123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477 |
- <template>
- <div class="smart-comparison">
- <div class="header">
- <home-header sub-title="自然资源大模型" />
- </div>
- <div class="content-box">
- <div class="top" v-if="false">
- <div
- v-for="(item, index) in fileList"
- :key="item"
- class="list-item"
- @click="toggleFile(item)"
- @mouseenter="handleMouseEnter(index)"
- @mouseleave="handleMouseLeave(index)"
- >
- <div class="file-item">{{ item.f_title }}</div>
- <div class="close-icon" v-if="hoveredIndex === index">
- <CloseCircleOutlined class="close-icon-font" @click="remove(item)" />
- </div>
- <div class="vs-font" v-if="index != fileList.length - 1">VS</div>
- </div>
- </div>
- <div class="content">
- <div class="left">
- <div class="upload-box">
- <div class="upload-input">
- <a-upload
- v-if="fileList1.length === 0"
- class="upload"
- action="/aisKnowledge/infra/file/upload"
- @change="(info)=>handleChange(info, 1)"
- :showUploadList="false"
- :data="{ type: 'temp' }"
- accept=".pdf"
- >
- <p class="upload_title">点击上传或拖入政策文档</p>
- <p class="upload_text">文档单个最大50MB;当前仅支持PDF格式 </p>
- </a-upload>
- <div v-else class="preview">
- <span class="icon"><img src="../../assets/images/pdf_icon.png" /></span>
- <div @click="switchPdfSource(1)">
- <span class="title">{{ fileList1[0]['fileName'] }}</span>
- <span class="size">{{ (fileList1[0]['size'] / 1024).toFixed(2) }}KB</span>
- </div>
- <span class="close" @click="deleteFileHandle(1)">x</span>
- </div>
- </div>
- <div class="upload-icon">VS</div>
- <div class="upload-input">
- <a-upload
- v-if="fileList2.length === 0"
- class="upload"
- action="/aisKnowledge/infra/file/upload"
- @change="(info)=>handleChange(info, 2)"
- :showUploadList="false"
- :data="{ type: 'temp' }"
- accept=".pdf"
- >
- <p class="upload_title">点击上传或拖入政策文档</p>
- <p class="upload_text">文档单个最大50MB;当前仅支持PDF格式 </p>
- </a-upload>
- <div v-else class="preview">
- <span class="icon"><img src="../../assets/images/pdf_icon.png" /></span>
- <div @click="switchPdfSource(2)">
- <span class="title">{{ fileList2[0]['fileName'] }}</span>
- <span class="size">{{ (fileList2[0]['size'] / 1024).toFixed(2) }}KB</span>
- </div>
- <span class="close" @click="deleteFileHandle(2)">x</span>
- </div>
- </div>
- </div>
- <div class="pdf">
- <PDFViewer :src="current.url" ref="ifRef" v-if="current.url"> </PDFViewer>
- </div>
- </div>
- <div class="affix_box">
- <div class="right" :class="{ zm: zoomFlag }">
- <AiAssistant :data="fileList" />
- </div>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script setup>
- /**
- * @description 智能对比
- */
- import HomeHeader from '@/views/home/components/HomeHeader.vue';
- import { ref, onMounted, watch, toRefs, nextTick } from 'vue';
- import { message } from 'ant-design-vue';
- import { CloseCircleOutlined } from '@ant-design/icons-vue';
- import PDFViewer from '@/components/pdf/PDFViewerSearch.vue';
- import AiAssistant from './components/aiAssistant.vue';
- const fileList = ref([]);
- import api from '@/utils/policy-api';
- import { useUserStore } from '@/stores/user/user';
- import PubsubService from '@/utils/PubsubService';
- const userStore = useUserStore();
- const { user } = userStore;
- const current = ref({});
- const index = ref(-1);
- const ifRef = ref(null);
- const zoomFlag = ref(false);
- // 控制鼠标移入的索引
- const hoveredIndex = ref(null);
- // 处理鼠标移入
- const handleMouseEnter = (index) => {
- hoveredIndex.value = index;
- };
- onMounted(() => {
- // 接收开关事件
- PubsubService.subscribe('change-doc', (t) => {
- nextTick(() => {
- ifRef.value.goSourceLocation(t.value, 2);
- });
- });
- PubsubService.subscribe('change-view', (t) => {
- zoomFlag.value = t.value;
- });
- index.value=-1;
- });
- const fileList1 = ref([])
- const fileList2 = ref([])
- const handleChange = (info, type) => {
- var name = info.file.name.split('.')[0];
- var fileName = info.file.name;
- const status = info.file.status;
- if (status === 'done') {
- message.success(`${info.file.name} 文件上传成功.`);
- const id = 'title-' + new Date().getTime();
- const url = 'https://ai.zrzyt.zj.gov.cn/aisKnowledge' + info.file.response.data;
- var item = {
- id: id,
- f_title: name,
- f_type: 'temp',
- file: info.file.originFileObj,
- size: info.file.size,
- fileName: fileName,
- url: url
- };
- if (type === 1) {
- fileList1.value = [item]
- }
- if (type === 2) {
- fileList2.value = [item]
- }
- fileList.value.push(item)
- current.value = item;
- if (fileList.value.length > 1) {
- // current.value = fileList.value[0];
- queryFilesName();
- }
- } else if (status === 'error') {
- message.error(`${info.file.name} file upload failed.`);
- }
- };
- const switchPdfSource = (type) => {
- if (type === 1) {
- current.value = fileList1.value[0];
- }else if (type === 2) {
- current.value = fileList2.value[0];
- }
- }
- const deleteFileHandle = (type) => {
- let file = null;
- if (type === 1) {
- file = fileList1.value[0]
- fileList1.value = []
- }
- if (type === 2) {
- file = fileList2.value[0]
- fileList2.value = []
- }
- for (let i = 0; i < fileList.value.length; i++){
- if(fileList.value[i]['id'] === file['id']) {
- fileList.value.splice(i, 1);
- break;
- }
- }
- if (fileList.value.length > 0) {
- current.value = fileList.value[0]
- } else if (fileList.value.length === 0) {
- current.value = {}
- }
- }
- const queryFilesName = () => {
- if (index.value < fileList.value.length) {
- index.value++;
- getFileName();
- }
- };
- const getFileName = () => {
- var item = fileList.value[index.value];
- initFileByUrl(item);
- queryFilesName();
- };
- const initFileByUrl = async (item) => {
- var fileName = item.fileName;
- var file = await fetchPdfFileStream(item.url, fileName);
- item.file = file;
- };
- const remove = (item) => {
- if (item.id == current.value.id) {
- current.value = null;
- }
- fileList.value = fileList.value.filter((citem) => citem.id != item.id);
- if (fileList.value && fileList.value.length > 0) {
- current.value = JSON.parse(JSON.stringify(fileList.value[0]));
- }
- };
- import axios from 'axios';
- //在线地址转文件
- const fetchPdfFileStream = (pdfUrl, name) => {
- return new Promise((resolve, reject) => {
- // const xhr = new XMLHttpRequest();
- // xhr.open('GET', pdfUrl);
- // xhr.responseType = 'blob';
- // var type = name.indexOf('pdf') > -1 ? 'application/pdf' : 'application/docx';
- // xhr.onload = function () {
- // if (xhr.status === 200) {
- // const blob = xhr.response;
- // const file = new File([blob], name, { type: type });
- // resolve(file); // 成功时,解析并返回File对象
- // } else {
- // resolve(null);
- // // reject(new Error('请求失败,状态码:' + xhr.status)); // 如果HTTP状态不是200,则拒绝Promise
- // }
- // };
- // xhr.onerror = function () {
- // reject(new Error('网络请求失败,请检查网络连接')); // 处理网络错误
- // };
- // xhr.send();
- var type = 'application/pdf';
- if (name.indexOf('pdf') > -1) {
- type = 'application/pdf';
- } else {
- type = 'application/docx';
- }
- axios
- .get(pdfUrl, { responseType: 'blob' })
- .then((response) => {
- const blob = new Blob([response.data], { type: type });
- const file = new File([blob], name, { type: type });
- resolve(file);
- // 接下来可以使用URL.createObjectURL(blob)创建一个可以用于<iframe>的URL
- })
- .catch((error) => {
- console.error('Error loading PDF:', error)
- reject(new Error('网络请求失败,请检查网络连接')); // 处理网络错误
- });
- });
- };
- // 处理鼠标移出
- const handleMouseLeave = () => {
- hoveredIndex.value = null;
- };
- </script>
- <style scoped lang="scss">
- .smart-comparison {
- width: 100%;
- height: 100%;
- >.content-box {
- height: calc(100% - 60px);
- display: flex;
- justify-content: center;
- flex-wrap: wrap;
- font-family: Alibaba PuHuiTi 2;
- position: relative;
- z-index: 1;
- .top {
- width: 1280px;
- height: auto;
- margin-top: 20px;
- margin-bottom: 20px;
- display: flex;
- // justify-content: space-between;
- justify-content: center;
- .list-item {
- width: auto;
- cursor: pointer;
- display: flex;
- position: relative;
- }
- .file-item {
- width: 345px;
- height: 106px;
- background: #ffffff;
- box-shadow: 0px 1px 8px 0px #e4e4e4;
- border-radius: 10px;
- border: 1px solid #3c8afb;
- padding: 20px;
- line-height: 30px;
- }
- .vs-font {
- width: auto;
- height: 106px;
- font-weight: bold;
- font-size: 24px;
- color: #2185f2;
- line-height: 106px;
- margin: 0px 47px;
- }
- .close-icon {
- position: absolute;
- top: 42px;
- left: 335px;
- .close-icon-font {
- color: #fff;
- background-color: #2185f2;
- border-radius: 50%;
- font-size: 20px;
- cursor: pointer;
- }
- }
- }
- .content {
- width: calc(100% - 300px);
- height: auto;
- display: flex;
- margin-top: 20px;
- margin-bottom: 20px;
- .left {
- min-height: calc(100vh - 270px);
- background: #ffffff;
- box-shadow: 0px 1px 8px 0px #e4e4e4;
- border-radius: 10px;
- width: calc(100% - 500px);
- >.upload-box {
- display: flex;
- align-items: center;
- margin-bottom: 20px;
- >.upload-icon {
- background: #4F7FFF;
- font-size: 26px;
- font-weight: bold;
- text-align: center;
- color: #fff;
- width: 60px;
- height: 60px;
- line-height: 60px;
- margin: 0px 20px;
- border-radius: 50%;
- }
- >.upload-input {
- background: #F8FCFF;
- border-radius: 6px 6px 6px 6px;
- border: 1px dashed #4B95E6;
- flex: 1;
- text-align: center;
- height: 82px;
- width: calc(50% - 50px);
- >.upload {
- cursor: pointer;
- }
- >.preview {
- text-align: left;
- padding: 15px;
- position: relative;
- cursor: pointer;
- >.icon {
- width: 50px;
- height: 50px;
- display: inline-block;
- vertical-align: top;
- margin-right: 10px;
- >img {
- width: 100%;
- height: 100%;
- }
- }
- >div {
- display: inline-block;
- width: calc(100% - 80px);
- >span {
- display: block;
- margin-bottom: 5px;
- &.title {
- color: #34383C;
- font-size: 16px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- &.size {
- color: #A5ADB9;
- font-size: 14px;
- }
- }
- }
- >.close {
- position: absolute;
- right: -8px;
- top: -8px;
- width: 20px;
- height: 20px;
- font-size: 14px;
- text-align: center;
- background: #A3BFDD;
- border-radius: 50%;
- color: #fff;
- cursor: pointer;
- }
- }
- .upload_title {
- color: #0F0F0F;
- text-align: center;
- font-size: 18px;
- margin-bottom: 0px;
- margin-top: 15px;
- }
- .upload_text {
- color: #727272;
- text-align: center;
- margin-bottom: 15px;
- }
- }
- }
- .pdf {
- width: 100%;
- height: 100%;
- }
- }
- .affix_box {
- position: fixed;
- right: 150px;
- top: 75px;
- bottom: 20px;
- }
- .right {
- width: 480px;
- margin-left: 20px;
- background: #ffffff;
- box-shadow: 0px 1px 8px 0px #e4e4e4;
- border-radius: 10px;
- position: relative;
- height: 100%;
- .title {
- font-weight: 600;
- font-size: 20px;
- color: #000;
- line-height: 50px;
- border-bottom: 1px solid #eaeaea;
- }
- .return-home {
- position: absolute;
- top: 620px;
- left: 0;
- height: 40px;
- width: 460px;
- background-color: #fff;
- box-shadow: 0px 1px 8px 0px #e4e4e4;
- border-radius: 10px;
- display: flex;
- justify-content: center;
- align-items: center;
- cursor: pointer;
- span {
- margin: 0 5px;
- font-size: 16px;
- }
- }
- .return-home:hover {
- color: #1677ff;
- }
- }
- .zm {
- width: 640px;
- }
- }
- }
- }
- </style>
|