wujingjing
2025-04-02 5fb58c10b2bb44b3f2d3bdab4d7a6619271e2bbf
src/components/chat/user/index.vue
@@ -10,7 +10,8 @@
                     <div
                        v-for="(item, index) in msg.attachList"
                        :key="index"
                        class="flex items-center gap-2 bg-[#e9e9e9] px-2 py-3 rounded-lg w-[220px] relative group"
                        class="flex items-center gap-2 bg-[#e9e9e9] px-2 py-3 rounded-lg w-[220px] relative group cursor-pointer"
                        @click="openAttachPreview(item)"
                     >
                        <template v-if="item.type === 'file'">
                           <el-image
@@ -27,7 +28,26 @@
                              <div v-if="item.model.type" class="text-info text-sm over-ellipsis w-full">
                                 {{ `${item.model.type ?? ''},${item.model.size ?? ''}` }}
                              </div>
                              <el-tooltip effect="dark" content="下载" placement="top">
                                 <span
                                    class="group-hover:visible invisible ywifont ywicon-download2 absolute right-2 cursor-pointer"
                                    @click.stop="downloadAttach(item)"
                                 ></span>
                              </el-tooltip>
                           </div>
                        </template>
                        <template v-if="item.type === 'metric'">
                           <div class="ywifont !text-[24px] flex-0" :class="[`ywicon-${item.icon}`, item.iconClass]"></div>
                           <div class="flex flex-col gap-0.5 w-full flex-auto">
                              <div class="font-bold over-ellipsis w-full">{{ item.title }}</div>
                              <div class="text-info text-sm over-ellipsis w-full">{{ `指标,${item.model.values?.length} 条记录` }}</div>
                           </div>
                           <el-tooltip effect="dark" content="引用" placement="top">
                              <span
                                 class="group-hover:visible invisible ywifont ywicon-quote absolute right-2 cursor-pointer"
                                 @click.stop="quoteAttach(item)"
                              ></span>
                           </el-tooltip>
                        </template>
                        <template v-if="item.type === 'table'">
                           <div class="ywifont !text-[24px] flex-0" :class="[`ywicon-${item.icon}`, item.iconClass]"></div>
@@ -35,6 +55,12 @@
                              <div class="font-bold over-ellipsis w-full">{{ item.title }}</div>
                              <div class="text-info text-sm over-ellipsis w-full">{{ `业务表格,${item.model.values?.length} 条记录` }}</div>
                           </div>
                           <el-tooltip effect="dark" content="引用" placement="top">
                              <span
                                 class="group-hover:visible invisible ywifont ywicon-quote absolute right-2 cursor-pointer"
                                 @click.stop="quoteAttach(item)"
                              ></span>
                           </el-tooltip>
                        </template>
                     </div>
                  </div>
@@ -42,6 +68,10 @@
            </div>
         </div>
      </div>
      <BusinessTablePreview :data="attachPreviewData" v-model="attachPreviewIsShow" />
      <MetricValuesPreview v-model="metricPreviewIsShow" :data="metricPreviewData" />
      <!-- #endregion -->
      <div class="flex px-4 rounded-lg relative flex-row-reverse items-center" :key="`${msg.historyId}_${msg.role}`">
@@ -103,10 +133,17 @@
</template>
<script setup lang="ts" name="UserMsg">
import { useClipboard } from '@vueuse/core';
import { ElMessage } from 'element-plus';
import { AnswerState, answerTypeMapCom, roleImageMap, type ChatMessage } from '../model/types';
import { isSharePage } from '/@/stores/chatRoom';
import { onClickOutside, useClipboard } from '@vueuse/core';
import { onActivated, ref } from 'vue';
import BusinessTablePreview from '../components/playBar/businessTablePreview/index.vue';
import { Attach } from '../components/playBar/hook/useAttach';
import MetricValuesPreview from '../components/playBar/metricValues/MetricValuesPreview.vue';
import emitter from '/@/utils/mitt';
import { downloadFileByPost } from '/@/api/file';
const emit = defineEmits<{
   (event: 'copyMsg', msgObj: ChatMessage): void;
@@ -135,5 +172,61 @@
const shareClick = (msg) => {
   emit('shareClick', msg);
};
//#region ====================== 指标附件预览 ======================
const metricPreviewIsShow = ref(false);
const metricPreviewData = ref<Attach>();
//#endregion
//#region ====================== 附件预览 ======================
const attachPreviewIsShow = ref(false);
const attachPreviewData = ref<Attach>();
const openAttachPreview = (item: Attach) => {
   if (item.type === 'file') {
      openFileContent(item);
   } else if (item.type === 'table') {
      attachPreviewIsShow.value = true;
      attachPreviewData.value = item;
   } else if (item.type === 'metric') {
      metricPreviewIsShow.value = true;
      metricPreviewData.value = item;
   }
};
//#endregion
//#region ====================== 附件引用 ======================
const quoteAttach = (item: Attach) => {
   emitter.emit('quoteAttach', item);
};
//#endregion
//#region ====================== 查看文件文本内容 ======================
const openFileContent = (item: Attach) => {
   emitter.emit('setFileContent', {
      title: item.title,
      content: item.model?.file_content ?? '',
   });
};
//#endregion
//#region ====================== 附件下载 ======================
const downloadAttach = async (item: Attach) => {
   const fileId = item.model?.file_id;
   if (!fileId) return;
   const res = await downloadFileByPost({
      file_id: fileId,
   });
   const url = window.URL.createObjectURL(res as any);
   const link = document.createElement('a');
   link.href = url;
   link.download = item.title || 'download'; // Use item title or fallback name
   document.body.appendChild(link);
   link.click();
   document.body.removeChild(link);
   window.URL.revokeObjectURL(url);
};
//#endregion
</script>
<style scoped lang="scss"></style>