提交 e9ecf9c1 authored 作者: kxjia's avatar kxjia

完善预览文件功能

上级 5d921ef0
......@@ -116,7 +116,7 @@
<template #extra>
<a-button style="margin-right: 8px" type="link" @click="closeFileDrawer">关闭</a-button>
</template>
<ShowFileContent ref="refShowFile" />
<FileViewer ref="refShowFile" />
</a-drawer>
</div>
</template>
......@@ -126,7 +126,7 @@
import { queryAllCheckItems } from '/@/views/newlib/components/api/AuditCheckMethodItem.api';
import { queryAllReports, batchAddOrUpdate } from '/@/views/newlib/components/api/AuditTaskReport.api';
import type { VxeColumnPropTypes, VxeTablePropTypes } from 'vxe-table';
// import ShowFileContent from './modal/ShowFileContent.vue';
import FileViewer from '/@/components/onlinePreview/FileViewer.vue';
const list = ref([]);
const emit = defineEmits(['callback']);
......
......@@ -10,8 +10,8 @@
<a-breadcrumb-item />
</a-breadcrumb>
<a-card v-show="curActiveKey == 1" bordered="false" style="width: 100%">
<div style="margin: 10px; height: 70vh; width: 100%; background: red">
<ShowFileContent ref="refShowFile" />
<div style="margin: 10px; height: 70vh; width: 100%;">
<FileViewer ref="refShowFile" />
</div>
</a-card>
<a-card title="" v-show="curActiveKey == 2" :bordered="false" style="width: 100%">
......@@ -37,7 +37,7 @@
import { ref, nextTick } from 'vue';
import { getAllCheckMethodByItem } from '/@/views/newlib/components/api/AuditCheckMethodItem.api';
import { queryAllChecks } from '/@/views/newlib/components/api/AuditCheckMethod.api';
// import ShowFileContent from './modal/ShowFileContent.vue';
import FileViewer from '/@/components/onlinePreview/FileViewer.vue';
const emit = defineEmits(['callback']);
const showDrawer = ref(false);
......
......@@ -92,7 +92,7 @@
</a-descriptions>
</a-drawer>
</div>
<ShowFileContentModal @register="registerShowFileContentModal" />
<FileViewerModal @register="registerShowFileContentModal" :useStaticPrefixForDocx="true" />
<Import ref="refImport" @callback="importCallback"></Import>
</template>
<script setup lang="ts">
......@@ -100,7 +100,7 @@
import { VxeGridProps, VXETable } from 'vxe-table';
import { defHttp } from '/@/utils/http/axios';
import { MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons-vue';
import ShowFileContentModal from '/@/views/newlib/components/modal/ShowFileContentModal.vue';
import FileViewerModal from '/@/components/onlinePreview/FileViewerModal.vue';
import { useModal } from '/@/components/Modal';
import Import from '../../common/components/import.vue'
......
......@@ -91,14 +91,14 @@
</a-descriptions>
</a-drawer>
</div>
<ShowFileContentModal @register="registerShowFileContentModal" />
<FileViewerModal @register="registerShowFileContentModal" :useStaticPrefixForDocx="true" />
</template>
<script setup lang="ts">
import { ref, reactive, nextTick } from 'vue';
import { VxeGridProps, VXETable } from 'vxe-table';
import { defHttp } from '/@/utils/http/axios';
import { MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons-vue';
import ShowFileContentModal from '/@/views/newlib/components/modal/ShowFileContentModal.vue';
import FileViewerModal from '/@/components/onlinePreview/FileViewerModal.vue';
import { useModal } from '/@/components/Modal';
const getProjectChecks = '/audit/auditProject/getProjectChecks';
......
......@@ -109,17 +109,16 @@
<template #extra>
<a-button type="link" size="small" @click="closeFileDrawer">关闭</a-button>
</template>
<ShowFileContent ref="refShowFile" />
<FileViewer ref="refShowFile" />
</a-drawer>
</div>
</template>
<script setup lang="ts">
import { ref, nextTick, reactive, defineAsyncComponent } from 'vue';
import { ref, nextTick, reactive } from 'vue';
import { getProjectItems } from '../AuditProjectItem.api';
import { queryAllReports, saveOrUpdate } from '/@/views/newlib/components/api/AuditTaskReport.api';
const ShowFileContent = defineAsyncComponent(() => import('/@/views/newlib/components/modal/ShowFileContent.vue'));
import FileViewer from '/@/components/onlinePreview/FileViewer.vue';
import { listCriteria, listConfig } from '../../criteria/AuditCriteria.api';
......
......@@ -129,7 +129,7 @@
<template #extra>
<a-button style="margin-right: 8px" type="link" @click="closeFileDrawer">关闭</a-button>
</template>
<ShowFileContent ref="refShowFile" />
<FileViewer ref="refShowFile" />
</a-drawer>
</div>
</template>
......@@ -139,7 +139,7 @@
import { getProjectItems } from '../AuditProjectItem.api';
import { queryAllReports, batchAddOrUpdate } from '/@//views/newlib/components/api/AuditTaskReport.api';
import type { VxeTablePropTypes } from 'vxe-table';
import ShowFileContent from '/@/views/newlib/components/modal/ShowFileContent.vue';
import FileViewer from '/@/components/onlinePreview/FileViewer.vue';
const list = ref([]);
const emit = defineEmits(['callback']);
......
<template>
<a-drawer
:title="fileTitle"
placement="left"
:width="drawerWidth"
:closable="true"
:visible="showDrawer"
@close="closeDrawer"
:mask="false"
>
<template #extra>
<a-space wrap>
<a-button type="link" v-show="isFullScreen" block @click="setDrawerFull">
<FullscreenOutlined />
</a-button>
<a-button type="link" v-show="!isFullScreen" block @click="setDrawerFull">
<FullscreenExitOutlined />
</a-button>
<a-button type="link" block @click="closeDrawer">
<CloseOutlined />
</a-button>
</a-space>
</template>
<i-frame v-if="fileTp == 'pdf'" :src="fileUrl" style="width: 100%;">
</i-frame>
</a-drawer>
</template>
<script lang="ts" setup>
import iFrame from '/@/components/iFrame/index.vue';
import { ref,h } from 'vue';
import { FullscreenOutlined,FullscreenExitOutlined,CloseOutlined} from '@ant-design/icons-vue';
import mammoth from 'mammoth';
import * as XLSX from 'xlsx';
const toggleCollapseLeft = ref(false);
const loading = ref(false);
const fileTp = ref('');
const fileTitle = ref('文件名称');
const showDrawer = ref(false);
const regDocFileList = ref();
const fileUrl = ref('');
const drawerWidth = ref("50%");
const isFullScreen = ref(false);
const emit = defineEmits(['register', 'success', 'goItem', 'toggleCollapse']);
function toggleCollapse() {
emit('toggleCollapse');
}
const curDocFile = ref({});
const docContent = ref<string>('');
const fetchDoc = async (docUrl) => {
try {
const response = await fetch(docUrl);
const arrayBuffer = await response.arrayBuffer();
const result = await mammoth.convertToHtml({ arrayBuffer });
docContent.value = result.value;
loading.value = false;
} catch (error) {
console.error('无法加载 DOC 文件:', error);
} finally {
loading.value = false;
}
};
const fetchText = async (docUrl) => {
try {
const response = await fetch(docUrl);
const arrayBuffer = await response.arrayBuffer();
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const decoder = new TextDecoder('utf-8'); // 根据需要选择编码
const text = decoder.decode(arrayBuffer);
docContent.value = text;
loading.value = false;
} catch (error) {
console.error('无法加载 Txt 文件:', error);
} finally {
loading.value = false;
}
};
const fetchExcel = async (docUrl) => {
try {
fetch(docUrl)
.then((response) => {
if (!response.ok) {
throw new Error('网络响应不是 OK');
}
return response.arrayBuffer();
})
.then((data) => {
const workbook = XLSX.read(data, { type: 'array' });
const firstSheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[firstSheetName];
const htmlString = XLSX.utils.sheet_to_html(worksheet);
docContent.value = htmlString;
loading.value = false;
})
.catch((error) => {
console.error('读取 Excel 文件时出错:', error);
});
loading.value = false;
} catch (error) {
console.error('无法加载 Excel 文件:', error);
} finally {
loading.value = false;
}
};
async function fetchXml(fileUrl) {
try {
const response = await fetch(fileUrl);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const xmlText = await response.text();
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlText, 'text/xml');
docContent.value = xmlText.toString();
docContent.value = createXmlTree(xmlDoc.documentElement);
loading.value = false;
} catch (error) {
console.error('Error fetching or parsing XML:', error);
} finally {
loading.value = false;
}
}
function createXmlTree(node) {
let html = `<div class="xml-node"><strong>${node.nodeName}</strong>`;
if (node.attributes && node.attributes.length > 0) {
html += ' [';
for (let i = 0; i < node.attributes.length; i++) {
const attr = node.attributes[i];
html += `${attr.name}="${attr.value}"`;
if (i < node.attributes.length - 1) {
html += ', ';
}
}
html += ']';
}
if (node.childNodes.length > 0) {
html += '<div class="xml-node">';
node.childNodes.forEach((childNode) => {
if (childNode.nodeType === Node.ELEMENT_NODE) {
// 仅处理元素节点
html += createXmlTree(childNode);
} else if (childNode.nodeType === Node.TEXT_NODE && childNode.nodeValue.trim()) {
html += `<div>文本: ${childNode.nodeValue.trim()}</div>`;
}
});
html += '</div>';
}
html += '</div>';
return html;
}
async function handleShowDrawer() {
showDrawer.value = true;
await regDocFileList.value.iniData();
}
function closeDrawer() {
showDrawer.value = false;
}
async function showCurFille(fileData) {
curDocFile.value = fileData;
let globOnlineViewUrl: string = import.meta.env.VITE_GLOB_ONLINE_VIEW_URL;
fileTp.value = fileData.fileTp;
fileUrl.value = globOnlineViewUrl + fileData.filePath;
fileTitle.value = '文件名:' + fileData.fileName;
loading.value = true;
try {
if (fileTp.value == 'docx') {
fileUrl.value = globOnlineViewUrl +"/sys/common/static/"+ fileData.filePath;
await fetchDoc(fileUrl.value);
} else if (fileTp.value == 'pdf') {
} else if (fileTp.value == 'txt') {
await fetchText(fileUrl.value);
} else if (fileTp.value == 'xml') {
await fetchXml(fileUrl.value);
} else if (fileTp.value == 'xlsx') {
fetchExcel(fileUrl.value);
} else if (fileTp.value == 'zip') {
} else {
await fetchText(fileUrl.value);
}
} catch (error) {
console.log(error);
} finally {
loading.value = false;
}
}
const files = ref({
1:{fileTp:"pdf",filePath:"/baosong/银行业保险业信息科技非现场监管报表(2024版).pdf",fileName:"银行业保险业信息科技非现场监管报表(2024版)"},
2:{fileTp:"pdf",filePath:"/baosong/银行业保险业信息科技非现场监管报表填报指南(2024版).pdf",fileName:"银行业保险业信息科技非现场监管报表填报指南(2024版).pdf"}
})
function setDocFile(tp) {
showCurFille(files.value[tp]);
showDrawer.value = true;
}
function setDrawerFull() {
isFullScreen.value = !isFullScreen.value;
drawerWidth.value = isFullScreen.value?"100%":"50%"
}
defineExpose({
setDocFile,
});
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
::v-deep .content table {
border: 1px solid;
width: 100%;
}
::v-deep .content tr {
border: 1px solid;
}
::v-deep .content td {
border: 1px solid;
}
.ant-card-body {
padding: 2px !important;
}
</style>
......@@ -10,7 +10,11 @@
</BasicTable>
<RecordDrawer ref="refRecordDrawer" @showFile="showFileContent"/>
<RecordDrawer2 ref="refRecordDrawer2" @showFile="showFileContent"/>
<FileContentView ref="refFileContentView"></FileContentView>
<FileViewerDrawer
ref="refFileContentView"
:useStaticPrefixForDocx="true"
:fixedFiles="fixedFiles"
/>
</div>
</template>
......@@ -22,7 +26,7 @@
import { columns, searchFormSchema } from '../task/BaosongTask.data';
import RecordDrawer from './components/RecordDrawer.vue';
import RecordDrawer2 from './components/RecordDrawer2.vue';
import FileContentView from '../components/FileContentView.vue';
import FileViewerDrawer from '/@/components/onlinePreview/FileViewerDrawer.vue';
import { useRouter } from 'vue-router';
const router = useRouter()
......@@ -34,6 +38,11 @@
const refRecordDrawer2 = ref()
const refFileContentView = ref()
const fixedFiles = ref({
1:{fileTp:"pdf",filePath:"/baosong/银行业保险业信息科技非现场监管报表(2024版).pdf",fileName:"银行业保险业信息科技非现场监管报表(2024版)"},
2:{fileTp:"pdf",filePath:"/baosong/银行业保险业信息科技非现场监管报表填报指南(2024版).pdf",fileName:"银行业保险业信息科技非现场监管报表填报指南(2024版).pdf"}
})
const { prefixCls, tableContext, } = useListPage({
tableProps: {
title: '任务表',
......
......@@ -101,7 +101,7 @@
<DocTreeModal @register="registerTreeModal" @success="handleSuccess" />
<DocFilesModal @register="registerModal" @success="handleSuccess" @edit-success="handleEditSuccess" />
<DocMutiFilesModal @register="registerMutiModal" @success="handleSuccess" />
<ShowFileModal @register="registerShowFileContentModal" />
<FileViewerModal @register="registerShowFileContentModal" :useStaticPrefixForDocx="true" />
<FileList ref="refFileList" />
<FileHistory ref="refFileHistory" />
</template>
......@@ -114,7 +114,7 @@
import DocFilesModal from './components/DocFilesModal.vue';
import DocMutiFilesModal from './components/DocMutiFilesModal.vue';
import DocTreeModal from './components/DocTreeModal.vue';
import ShowFileModal from '/@/views/newlib/components/modal/ShowFileContentModal.vue'
import FileViewerModal from '/@/components/onlinePreview/FileViewerModal.vue'
import { columns } from './DocFiles.data';
import { deleteOne, queryAllList } from './DocFiles.api';
import { getChildList } from './DocFilesDir.api';
......
......@@ -35,7 +35,7 @@
<a-button type="link" @click="closeDrawer" style="text-align: center; float: right">关闭</a-button>
</a-card>
</BasicDrawer>
<ShowFileContentModal @register="registerShowFileContentModal" />
<FileViewerModal @register="registerShowFileContentModal" />
</template>
<script lang="ts" setup>
import { ref, unref } from 'vue';
......@@ -44,9 +44,8 @@
import { useAppInject } from '/@/hooks/web/useAppInject';
import { defHttp } from '/@/utils/http/axios';
import { useModal } from '/@/components/Modal';
import { BasicDrawer, useDrawerInner } from '/src/components/Drawer';
import ShowFileContentModal from './ShowFileContentModal.vue';
import { replaceAll } from '/@/utils';
import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
import FileViewerModal from '/@/components/onlinePreview/FileViewerModal.vue';
const pwidth = ref();
const pageTitle = ref('');
......
<template>
<a-card
:bodyStyle="{ height: '90%', padding: '10px 0px', margin: '0px 10px' }"
style="overflow-y: auto; height: 100%; padding: 0px"
:bordered="false"
>
<template #title><span v-html="fileTitle"></span></template>
<!-- <template #extra><a href="#" @click="handleShowDrawer">选择文件</a></template> -->
<i-frame v-if="fileTp == 'pdf'||fileTp=='url'" :src="fileUrl" style="width: 100%; height: 100%" />
<div v-else style="height: 100%; overflow: auto" v-html="docContent" class="file-content"> </div>
</a-card>
<a-drawer
title=""
placement="left"
width="100%"
:closable="false"
:visible="showDrawer"
:get-container="false"
:wrap-style="{ position: 'absolute', border: '1px solid rgb(255,255,255,0)' }"
@close="closeDrawer"
>
<!-- <DocFileList ref="regDocFileList" @selectFileDoc="setDocFile" @closeDrawer="closeDrawer" /> -->
</a-drawer>
</template>
<script lang="ts" setup>
import iFrame from '/@/components/iFrame/index.vue';
import { ref } from 'vue';
// import DocFileList from './DocFileList.vue';
import { queryDocFileById } from './esStandLibQuery.api';
import mammoth from 'mammoth';
import * as XLSX from 'xlsx';
const loading = ref(false);
const fileTp = ref('');
const fileTitle = ref('文件名称');
const showDrawer = ref(false);
const regDocFileList = ref();
const fileUrl = ref('');
const emit = defineEmits(['register', 'success', 'goItem']);
const curDocFile = ref({});
const docContent = ref<string>('');
const fetchDoc = async (docUrl) => {
try {
const response = await fetch(docUrl);
const arrayBuffer = await response.arrayBuffer();
const result = await mammoth.convertToHtml({ arrayBuffer });
docContent.value = result.value;
loading.value = false;
} catch (error) {
console.error('无法加载 DOC 文件:', error);
} finally {
loading.value = false;
}
};
const fetchText = async (docUrl) => {
try {
const response = await fetch(docUrl);
const arrayBuffer = await response.arrayBuffer();
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const decoder = new TextDecoder('utf-8'); // 根据需要选择编码
const text = decoder.decode(arrayBuffer);
docContent.value = text;
loading.value = false;
} catch (error) {
console.error('无法加载 Txt 文件:', error);
} finally {
loading.value = false;
}
};
const fetchExcel = async (docUrl) => {
try {
fetch(docUrl)
.then((response) => {
if (!response.ok) {
throw new Error('网络响应不是 OK');
}
return response.arrayBuffer();
})
.then((data) => {
const workbook = XLSX.read(data, { type: 'array' });
const firstSheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[firstSheetName];
const htmlString = XLSX.utils.sheet_to_html(worksheet);
docContent.value = htmlString;
loading.value = false;
})
.catch((error) => {
console.error('读取 Excel 文件时出错:', error);
alert('加载 Excel 文件时出错: ' + error.message);
});
loading.value = false;
} catch (error) {
console.error('无法加载 Excel 文件:', error);
} finally {
loading.value = false;
}
};
async function fetchXml(fileUrl) {
try {
const response = await fetch(fileUrl);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const xmlText = await response.text();
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlText, 'text/xml');
docContent.value = xmlText.toString();
docContent.value = createXmlTree(xmlDoc.documentElement);
loading.value = false;
} catch (error) {
console.error('Error fetching or parsing XML:', error);
} finally {
loading.value = false;
}
}
function createXmlTree(node) {
let html = `<div class="xml-node"><strong>${node.nodeName}</strong>`;
if (node.attributes && node.attributes.length > 0) {
html += ' [';
for (let i = 0; i < node.attributes.length; i++) {
const attr = node.attributes[i];
html += `${attr.name}="${attr.value}"`;
if (i < node.attributes.length - 1) {
html += ', ';
}
}
html += ']';
}
if (node.childNodes.length > 0) {
html += '<div class="xml-node">';
node.childNodes.forEach((childNode) => {
if (childNode.nodeType === Node.ELEMENT_NODE) {
// 仅处理元素节点
html += createXmlTree(childNode);
} else if (childNode.nodeType === Node.TEXT_NODE && childNode.nodeValue.trim()) {
html += `<div>文本: ${childNode.nodeValue.trim()}</div>`;
}
});
html += '</div>';
}
html += '</div>';
return html;
}
async function handleShowDrawer() {
showDrawer.value = true;
await regDocFileList.value.iniData();
}
function closeDrawer() {
showDrawer.value = false;
}
async function showCurFille(fileData) {
curDocFile.value = fileData;
let globOnlineViewUrl: string = import.meta.env.VITE_GLOB_ONLINE_VIEW_URL;
const fpath = fileData.fpath;
if(isHttpOrHttps(fpath)) {
fileTp.value = "url"
fileUrl.value = fpath
fileTitle.value = '网址:' + fpath;
} else {
fileTp.value = await getFileTp(fpath);
fileUrl.value = globOnlineViewUrl + fileData.fpath;
fileTitle.value = '文件名:' + fileData.fpathHight;
}
loading.value = true;
try {
if (fileTp.value == 'docx') {
fileUrl.value = globOnlineViewUrl +"/sys/common/static/"+ fileData.filePath;
await fetchDoc(fileUrl.value);
} else if (fileTp.value == 'pdf') {
} else if (fileTp.value == 'txt') {
await fetchText(fileUrl.value);
} else if (fileTp.value == 'xml') {
await fetchXml(fileUrl.value);
} else if (fileTp.value == 'xlsx') {
fetchExcel(fileUrl.value);
} else if (fileTp.value == 'zip') {
} else {
await fetchText(fileUrl.value);
}
} catch (error) {
console.log(error);
} finally {
loading.value = false;
closeDrawer();
}
}
function getFileId() {
return curDocFile.value['fileId'] || curDocFile.value['id'];
}
function setDocFile(fileData) {
if (fileData && fileData.fpath) {
showCurFille(fileData);
curDocFile.value = fileData;
}
}
async function setDocFileById(fileId) {
if (fileId) {
curDocFile.value = await queryDocFileById({ id: fileId });
showCurFille(curDocFile.value);
}
}
async function getFileTp(strUrl) {
const p = strUrl.lastIndexOf('.'); // 将 lastIndex 改为 lastIndexOf
if (p === -1) return ''; // 如果没有找到文件扩展名,则返回空字符串
const fileTp = strUrl.substring(p + 1); // 获取最后一个点之后的子字符串
return fileTp;
}
function isHttpOrHttps(url) {
return url.startsWith('http://') || url.startsWith('https://');
}
defineExpose({
getFileId,
setDocFile,
setDocFileById,
});
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
::v-deep .content table {
border: 1px solid;
width: 100%;
}
::v-deep .content tr {
border: 1px solid;
}
::v-deep .content td {
border: 1px solid;
}
.ant-card-body {
padding: 2px !important;
}
</style>
<template>
<BasicModal v-bind="$attrs" @register="registerModal" title="文件内容查看" :centered="true" width="80%" :useWrapper="true" :footer="null">
<div style="background-color: #ececec; padding: 5px">
<div :style="{ overflow: 'hidden', height: '85vh' }">
<ShowFileCotent ref="refShowFileCotent" :loading="loading" />
</div>
</div>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, nextTick } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import ShowFileCotent from './ShowFileContent.vue';
const refShowFileCotent = ref();
const loading = ref(false);
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
setModalProps({ confirmLoading: false, showCancelBtn: !!data?.showFooter, showOkBtn: !!data?.showFooter });
refShowFileCotent.value.setDocFile(data?.record);
});
</script>
<style lang="less" scoped>
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
</style>
......@@ -137,7 +137,7 @@
<FileDetail @register="registerModalDetail" />
</div>
</div>
<ShowFileContentModal @register="registerShowFileContentModal" />
<FileViewerModal @register="registerShowFileContentModal" />
</template>
<script lang="ts" name="es-esSearchFile" setup>
import { Pagination, Tag } from 'ant-design-vue';
......@@ -150,7 +150,7 @@
import FileDetail from './FileDetail.vue';
import { usePermission } from '/@/hooks/web/usePermission';
import { isEmpty } from '/@/utils/is';
import ShowFileContentModal from './ShowFileContentModal.vue';
import FileViewerModal from '/@/components/onlinePreview/FileViewerModal.vue';
const { hasPermission } = usePermission();
......
......@@ -42,7 +42,7 @@
</BasicTable>
<!-- 表单区域 -->
<MetricStatReportModal @register="registerModal" @success="handleSuccess"></MetricStatReportModal>
<ShowFileContentModal @register="registerShowFileContentModal" />
<FileViewerModal @register="registerShowFileContentModal" />
</div>
</template>
......@@ -57,7 +57,7 @@
import {list, deleteOne, batchDelete, getImportUrl,getExportUrl,caluculatAllMetric} from './MetricStatReport.api';
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
import ShowFileContentModal from './components/ShowFileContentModal.vue';
import FileViewerModal from '/@/components/onlinePreview/FileViewerModal.vue';
const checkedKeys = ref<Array<string | number>>([]);
......
<template>
<a-card
:bodyStyle="{ height: '100%', padding: '0px 0px', margin: '0px 0px' }"
style="overflow-y: hidden; height: 100%; padding: 20px"
:bordered="true"
>
<template #title><span v-html="fileTitle"></span></template>
<i-frame v-if="fileTp == 'pdf'" :src="fileUrl" style="width: 100%; height: 100%" />
<div v-else style="height: 100%; overflow: auto" v-html="docContent" class="file-content"> </div>
</a-card>
</template>
<script lang="ts" setup>
import iFrame from '/@/components/iFrame/index.vue';
import { ref } from 'vue';
import mammoth from 'mammoth';
import * as XLSX from 'xlsx';
const toggleCollapseLeft = ref(false);
const loading = ref(false);
const fileTp = ref('');
const fileTitle = ref('文件名称');
const showDrawer = ref(false);
const regDocFileList = ref();
const fileUrl = ref('');
const emit = defineEmits(['register', 'success', 'goItem', 'toggleCollapse']);
function toggleCollapse() {
emit('toggleCollapse');
}
const curDocFile = ref({});
const docContent = ref<string>('');
const fetchDoc = async (docUrl) => {
try {
const response = await fetch(docUrl);
const arrayBuffer = await response.arrayBuffer();
const result = await mammoth.convertToHtml({ arrayBuffer });
docContent.value = result.value;
loading.value = false;
} catch (error) {
console.error('无法加载 DOC 文件:', error);
} finally {
loading.value = false;
}
};
const fetchText = async (docUrl) => {
try {
const response = await fetch(docUrl);
const arrayBuffer = await response.arrayBuffer();
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const decoder = new TextDecoder('utf-8'); // 根据需要选择编码
const text = decoder.decode(arrayBuffer);
docContent.value = text;
loading.value = false;
} catch (error) {
console.error('无法加载 Txt 文件:', error);
} finally {
loading.value = false;
}
};
const fetchExcel = async (docUrl) => {
try {
fetch(docUrl)
.then((response) => {
if (!response.ok) {
throw new Error('网络响应不是 OK');
}
return response.arrayBuffer();
})
.then((data) => {
const workbook = XLSX.read(data, { type: 'array' });
const firstSheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[firstSheetName];
const htmlString = XLSX.utils.sheet_to_html(worksheet);
docContent.value = htmlString;
loading.value = false;
})
.catch((error) => {
console.error('读取 Excel 文件时出错:', error);
});
loading.value = false;
} catch (error) {
console.error('无法加载 Excel 文件:', error);
} finally {
loading.value = false;
}
};
async function fetchXml(fileUrl) {
try {
const response = await fetch(fileUrl);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const xmlText = await response.text();
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlText, 'text/xml');
docContent.value = xmlText.toString();
docContent.value = createXmlTree(xmlDoc.documentElement);
loading.value = false;
} catch (error) {
console.error('Error fetching or parsing XML:', error);
} finally {
loading.value = false;
}
}
function createXmlTree(node) {
let html = `<div class="xml-node"><strong>${node.nodeName}</strong>`;
if (node.attributes && node.attributes.length > 0) {
html += ' [';
for (let i = 0; i < node.attributes.length; i++) {
const attr = node.attributes[i];
html += `${attr.name}="${attr.value}"`;
if (i < node.attributes.length - 1) {
html += ', ';
}
}
html += ']';
}
if (node.childNodes.length > 0) {
html += '<div class="xml-node">';
node.childNodes.forEach((childNode) => {
if (childNode.nodeType === Node.ELEMENT_NODE) {
// 仅处理元素节点
html += createXmlTree(childNode);
} else if (childNode.nodeType === Node.TEXT_NODE && childNode.nodeValue.trim()) {
html += `<div>文本: ${childNode.nodeValue.trim()}</div>`;
}
});
html += '</div>';
}
html += '</div>';
return html;
}
async function handleShowDrawer() {
showDrawer.value = true;
await regDocFileList.value.iniData();
}
function closeDrawer() {
showDrawer.value = false;
}
async function showCurFille(fileData) {
curDocFile.value = fileData;
const globOnlineViewUrl = import.meta.env.VITE_GLOB_ONLINE_VIEW_URL;
fileTp.value = fileData.fileTp;
fileUrl.value = globOnlineViewUrl + fileData.filePath;
fileTitle.value = '文件名:' + fileData.fileName;
loading.value = true;
try {
if (fileTp.value == 'docx') {
fileUrl.value = globOnlineViewUrl + fileData.filePath;
await fetchDoc(fileUrl.value);
} else if (fileTp.value == 'pdf') {
} else if (fileTp.value == 'txt') {
await fetchText(fileUrl.value);
} else if (fileTp.value == 'xml') {
await fetchXml(fileUrl.value);
} else if (fileTp.value == 'xlsx') {
fetchExcel(fileUrl.value);
} else if (fileTp.value == 'zip') {
} else {
await fetchText(fileUrl.value);
}
} catch (error) {
console.log(error);
} finally {
loading.value = false;
closeDrawer();
}
}
function setDocFile(fileData) {
if (fileData && fileData.filePath) {
showCurFille(fileData);
curDocFile.value = fileData;
}
}
defineExpose({
setDocFile,
});
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
::v-deep .content table {
border: 1px solid;
width: 100%;
}
::v-deep .content tr {
border: 1px solid;
}
::v-deep .content td {
border: 1px solid;
}
.ant-card-body {
padding: 2px !important;
}
:deep(.file-content) {
padding: 20px;
font-family: "Microsoft YaHei", SimSun, sans-serif;
line-height: 1.6;
color: #333;
/* 表格样式 */
table {
border-collapse: collapse;
width: 100%;
margin: 15px 0;
border: 1px solid #ddd;
th, td {
border: 1px solid #ddd;
padding: 8px 12px;
}
th {
background-color: #f2f2f2;
font-weight: bold;
}
}
/* 标题样式 */
h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
color: #222;
font-weight: bold;
}
h1 { font-size: 24px; }
h2 { font-size: 22px; }
h3 { font-size: 20px; }
h4 { font-size: 18px; }
h5 { font-size: 16px; }
h6 { font-size: 14px; }
/* 段落样式 */
p {
margin: 0 0 15px;
text-align: justify;
}
/* 列表样式 */
ul, ol {
margin: 15px 0;
padding-left: 30px;
}
li {
margin-bottom: 5px;
}
/* 图片样式 */
img {
max-width: 100%;
height: auto;
margin: 10px 0;
}
/* 代码块样式 */
pre {
background-color: #f5f5f5;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
margin: 15px 0;
}
/* 引用样式 */
blockquote {
border-left: 4px solid #ddd;
padding-left: 15px;
color: #666;
margin: 15px 0;
}
}
.ant-card-body {
padding: 2px !important;
}
</style>
<template>
<BasicModal v-bind="$attrs" @register="registerModal" title="文件内容查看" :centered="true" width="60%" :useWrapper="true" :footer="null">
<div style="background-color: #ececec; padding: 5px">
<div :style="{ overflow: 'hidden', height: '85vh' }">
<ShowFileCotent ref="refShowFileCotent" :loading="loading"/>
</div>
</div>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, nextTick } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import ShowFileCotent from './ShowFileContent.vue';
const refShowFileCotent = ref();
const loading = ref(false);
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
const { showFooter, record } = data || {};
const { filepath } = record || {};
setModalProps({
confirmLoading: false,
showCancelBtn: !!showFooter,
showOkBtn: !!showFooter,
});
if (filepath) {
let docObj = {
filePath:filepath,
fileTp:getFileExtension(filepath) || "docx",
fileName:filepath
}
refShowFileCotent.value.setDocFile(docObj);
}
});
function getFileExtension(filename) {
const index = filename.lastIndexOf('.');
if (index === -1) return '';
return filename.substring(index + 1);
}
</script>
<style lang="less" scoped>
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
</style>
......@@ -69,7 +69,7 @@
</a-descriptions>
</a-drawer>
</a-layout>
<ShowFileContentModal @register="registerShowFileContentModal" />
<FileViewerModal @register="registerShowFileContentModal" :useStaticPrefixForDocx="true" />
</template>
<script lang="ts" setup>
......@@ -79,7 +79,7 @@
import { useModal } from '/@/components/Modal';
import RuleListLeft from './components/RuleListLeft.vue';
import { getAllCheckMethodByItem } from './components/api/AuditCheckMethodItem.api';
import ShowFileContentModal from './components/modal/ShowFileContentModal.vue';
import FileViewerModal from '/@/components/onlinePreview/FileViewerModal.vue';
const [registerShowFileContentModal, { openModal: openFileContentModel }] = useModal();
const refRuleListLeft = ref();
......
......@@ -45,6 +45,7 @@
</a-layout-content>
</a-layout>
<UserList ref="refUserList" @callBack="onAllocTask"/>
<FileViewerModal @register="registerShowFileContentModal" :useStaticPrefixForDocx="true" />
</template>
<script lang="ts" setup>
......@@ -58,10 +59,17 @@
import { getAllCheckMethodFiles } from './components/api/AuditCheckMethodItem.api';
import UserList from './components/UserList.vue';
import TaskLeft from './components/TaskLeft.vue';
import FileViewerModal from '/@/components/onlinePreview/FileViewerModal.vue';
const [registerShowFileContentModal, { openModal: openFileContentModel }] = useModal();
function showFileContent(data) {
if (data) {
openFileContentModel(true, { record: data });
}
}
const refUserList = ref();
const tableRef = ref()
const loading = ref(false);
......@@ -75,18 +83,15 @@
fileId: string;
}
const srhFormData = reactive<FormDataVO>({
content: '',
fileId: '',
});
const fileFilterMethod: VxeColumnPropTypes.FilterMethod = ({ value, row }) => {
return row['fileId'] == value;
};
const nameFilterRender: VxeColumnPropTypes.FilterRender = {
name: 'VxeInput'
}
......
......@@ -88,7 +88,7 @@
<AuditActListModal @register="refAuditActListModal" @saveRel="handleSaveRel" />
<AuditSetLableModal @register="regAddLableModal" modalTitle="添加标签" @saveLabel="saveLabels" />
<MergeActModal @register="registerMergeActModal" @success="handleSuccess" />
<ShowFileContentModal @register="registerShowFileContentModal" />
<FileViewerModal @register="registerShowFileContentModal" :useStaticPrefixForDocx="true" />
<a-drawer
title="节点流程"
......@@ -129,7 +129,7 @@
import AuditSetLableModal from './modal/AuditSetLableModal.vue';
import AuditActListModal from './modal/AuditActListModal.vue';
import MergeActModal from './modal/MergeActModal.vue';
import ShowFileContentModal from './modal/ShowFileContentModal.vue';
import FileViewerModal from '/@/components/onlinePreview/FileViewerModal.vue';
import { useUserStoreWithOut } from '/@/store/modules/user';
import { saveOrUpdateByTp, deleteByTp, saveBatchLabels, saveBatchActRels, queryActByIds, queryLabelByCodes } from '../index.api';
......
......@@ -53,7 +53,7 @@
</template>
</vxe-modal> -->
</div>
<ShowFileContentModal @register="registerShowFileContentModal" />
<FileViewerModal @register="registerShowFileContentModal" :useStaticPrefixForDocx="true" />
<component :is="currentComponent" @register="registerModal" @success="handleSuccess" @callback="callback" />
</template>
......@@ -64,7 +64,7 @@
import { auditCols } from './data/AuditCommon2.data';
import { VXETable } from 'vxe-table';
import { useModal } from '/@/components/Modal';
import ShowFileContentModal from './modal/ShowFileContentModal.vue';
import FileViewerModal from '/@/components/onlinePreview/FileViewerModal.vue';
import AuditComplianeItemModal from './modal/AuditComplianeItemModal.vue';
import AuditInnerCtrlModal from './modal/AuditInnerCtrlModal.vue';
import AuditInnerOrderModal from './modal/AuditInnerOrderModal.vue';
......
......@@ -92,7 +92,7 @@
<template #extra>
<a-button style="margin-right: 8px" type="link" @click="closeFileDrawer">关闭</a-button>
</template>
<ShowFileContent ref="refShowFile"></ShowFileContent>
<FileViewer ref="refShowFile"></FileViewer>
</a-drawer>
</div>
</template>
......@@ -102,7 +102,7 @@
import { queryAllCheckItems } from './api/AuditCheckMethodItem.api';
import { queryAllReports,batchAddOrUpdate } from './api/AuditTaskReport.api';
import type { VxeColumnPropTypes,VxeTablePropTypes } from 'vxe-table'
import ShowFileContent from './modal/ShowFileContent.vue'
import FileViewer from '/@/components/onlinePreview/FileViewer.vue'
const list = ref([]);
const emit = defineEmits(['callback']);
......
......@@ -10,8 +10,8 @@
<a-breadcrumb-item></a-breadcrumb-item>
</a-breadcrumb>
<a-card v-show="curActiveKey==1" bordered="false" style="width:100%">
<div style="margin:10px;height:70vh;width:100%;background:red;">
<ShowFileContent ref="refShowFile"></ShowFileContent>
<div style="margin:10px;height:70vh;width:100%;">
<FileViewer ref="refShowFile"></FileViewer>
</div>
</a-card>
<a-card title="" v-show="curActiveKey==2" :bordered="false" style="width: 100%">
......@@ -39,7 +39,7 @@
import { ref,nextTick } from 'vue';
import { getAllCheckMethodByItem } from './api/AuditCheckMethodItem.api';
import { queryAllChecks } from './api/AuditCheckMethod.api';
import ShowFileContent from './modal/ShowFileContent.vue'
import FileViewer from '/@/components/onlinePreview/FileViewer.vue'
......
......@@ -35,7 +35,7 @@
</vxe-column>
</vxe-table>
</div>
<ShowFileContentModal @register="registerShowFileContentModal" />
<FileViewerModal @register="registerShowFileContentModal" :useStaticPrefixForDocx="true" />
</template>
<script lang="ts" setup>
......@@ -45,7 +45,7 @@
import { useModal } from '/@/components/Modal';
import XEUtils from 'xe-utils'
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
import ShowFileContentModal from './modal/ShowFileContentModal.vue';
import FileViewerModal from '/@/components/onlinePreview/FileViewerModal.vue';
interface RowVO {
fileName: string;
......
......@@ -103,7 +103,7 @@
<AuditProblemModal @register="registerProbModal" @success="handleSuccess" />
<AuditBestPracticeModal @register="registerPraModal" @success="handleSuccess" />
<AuditRiskEventModal @register="registerRiskModal" @success="handleSuccess" />
<ShowFileContentModal @register="registerShowFileContentModal" />
<FileViewerModal @register="registerShowFileContentModal" :useStaticPrefixForDocx="true" />
</template>
<script lang="ts" name="doc-docFiles" setup>
......@@ -118,7 +118,7 @@
import { getAllDataByFileId } from './AuditDoc.api';
import { Base64 } from 'js-base64';
import { FolderFilled, FileTextTwoTone, MenuOutlined, AppstoreOutlined, FileWordTwoTone, FilePdfTwoTone } from '@ant-design/icons-vue';
import ShowFileContentModal from '../modal/ShowFileContentModal.vue';
import FileViewerModal from '/@/components/onlinePreview/FileViewerModal.vue';
import AuditComplianeItemModal from '../modal/AuditComplianeItemModal.vue';
import AuditInnerCtrlModal from '../modal/AuditInnerCtrlModal.vue';
import AuditInnerOrderModal from '../modal/AuditInnerOrderModal.vue';
......
......@@ -5,7 +5,7 @@
<a-col :span="10">
<a-card :bordered="false">
<div :style="{ overflow: 'hidden', height: '75vh' }">
<ShowFileCotent ref="refShowFileCotent" />
<FileViewer ref="refShowFileCotent" />
</div>
</a-card>
</a-col>
......@@ -61,7 +61,7 @@
import { computed, ref, unref } from 'vue';
import { BasicForm, useForm } from '/@/components/Form/index';
import { BasicModal, useModalInner } from '/@/components/Modal';
import ShowFileCotent from './ShowFileContent.vue';
import FileViewer from '/@/components/onlinePreview/FileViewer.vue';
import { formSchema } from '../data/AuditBestPractice.data';
import { deleteOne, saveOrUpdate } from '../api/AuditBestPractice.api';
......
......@@ -13,7 +13,7 @@
<a-row :gutter="8">
<a-col :span="!isCollapsedLeft ? 8 : 4">
<div :style="{ overflow: 'hidden', height: '87vh' }">
<ShowFileCotent ref="refShowFileCotent" @toggle-collapse="toggleCollapseLeft" />
<FileViewer ref="refShowFileCotent" @toggle-collapse="toggleCollapseLeft" :showToggleCollapse="true" />
</div>
</a-col>
<a-col :span="isCollapsed ? (isCollapsedLeft ? 17 : 13) : isCollapsedLeft ? 13 : 9">
......@@ -88,7 +88,7 @@
import { batchDeleteNoTip } from '../api/AuditCheckMethodItem.api';
import { BasicForm, useForm } from '/@/components/Form/index';
import { BasicModal, useModalInner } from '/@/components/Modal';
import ShowFileCotent from './ShowFileContent.vue';
import FileViewer from '/@/components/onlinePreview/FileViewer.vue';
import AuditCheckpoint from './AuditCheckpoint.vue';
const refShowFileCotent = ref();
......
......@@ -4,7 +4,7 @@
<a-row :gutter="8">
<a-col :span="12">
<div :style="{ overflow: 'hidden', height: '85vh' }">
<ShowFileCotent ref="refShowFileCotent" />
<FileViewer ref="refShowFileCotent" />
</div>
</a-col>
<a-col :span="12">
......@@ -73,7 +73,7 @@
import { BasicModal, useModalInner } from '/@/components/Modal';
import { VXETable, VxeTableInstance, VxeToolbarInstance } from 'vxe-table';
import { allList, saveOrUpdate, saveOrUpdateSingle, deleteOne, batchDelete } from '../api/AuditFileContentCategories.api';
import ShowFileCotent from './ShowFileContent.vue';
import FileViewer from '/@/components/onlinePreview/FileViewer.vue';
const { createMessage } = useMessage();
// Emits声明
......
......@@ -25,7 +25,7 @@
</vxe-grid>
</div>
<ShowFileContentModal @register="registerShowFileContentModal" />
<FileViewerModal @register="registerShowFileContentModal" :useStaticPrefixForDocx="true" />
</template>
<script lang="ts" setup>
......@@ -33,7 +33,7 @@
import { useModal } from '/@/components/Modal';
import { getAllCheckMethodByItem } from '../api/AuditCheckMethodItem.api';
import ShowFileContentModal from './ShowFileContentModal.vue';
import FileViewerModal from '/@/components/onlinePreview/FileViewerModal.vue';
const [registerShowFileContentModal, { openModal: openFileContentModel }] = useModal();
......
......@@ -13,7 +13,7 @@
<a-row :gutter="8">
<a-col :span="!isCollapsedLeft ? 8 : 4">
<div :style="{ overflow: 'hidden', height: '87vh' }">
<ShowFileCotent ref="refShowFileCotent" @toggle-collapse="toggleCollapseLeft" />
<FileViewer ref="refShowFileCotent" @toggle-collapse="toggleCollapseLeft" :showToggleCollapse="true" />
</div>
</a-col>
<a-col :span="isCollapsed ? (isCollapsedLeft ? 17 : 13) : isCollapsedLeft ? 13 : 9">
......@@ -89,7 +89,7 @@
import { batchDeleteNoTip } from '../api/AuditInnerCheckmethodItem.api';
import { BasicForm, useForm } from '/@/components/Form/index';
import { BasicModal, useModalInner } from '/@/components/Modal';
import ShowFileCotent from './ShowFileContent.vue';
import FileViewer from '/@/components/onlinePreview/FileViewer.vue';
import AuditCheckpoint from './AuditCheckpoint.vue';
const refShowFileCotent = ref();
......
......@@ -13,7 +13,11 @@
<a-row :gutter="8">
<a-col :span="!isCollapsedLeft ? 8 : 4">
<div :style="{ overflow: 'hidden', height: '87vh' }">
<ShowFileCotent ref="refShowFileCotent" @toggle-collapse="toggleCollapseLeft" />
<FileViewer
ref="refShowFileCotent"
@toggle-collapse="toggleCollapseLeft"
:showToggleCollapse="true"
/>
</div>
</a-col>
<a-col :span="isCollapsed ? (isCollapsedLeft ? 17 : 13) : isCollapsedLeft ? 13 : 9">
......@@ -85,7 +89,7 @@
import { BasicForm, useForm } from '/@/components/Form/index';
import { columns, formSchema } from '../data/AuditProblem.data';
import { list, deleteOne, saveOrUpdate } from '../api/AuditProblem.api';
import ShowFileCotent from './ShowFileContent.vue';
import FileViewer from '/@/components/onlinePreview/FileViewer.vue';
// Emits声明
const emit = defineEmits(['register', 'success']);
......
......@@ -13,7 +13,11 @@
<a-row :gutter="8">
<a-col :span="!isCollapsedLeft ? 8 : 4">
<div :style="{ overflow: 'hidden', height: '87vh' }">
<ShowFileCotent ref="refShowFileCotent" @toggle-collapse="toggleCollapseLeft" />
<FileViewer
ref="refShowFileCotent"
@toggle-collapse="toggleCollapseLeft"
:showToggleCollapse="true"
/>
</div>
</a-col>
<a-col :span="isCollapsed ? (isCollapsedLeft ? 17 : 13) : isCollapsedLeft ? 13 : 9">
......@@ -75,7 +79,7 @@
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from '../data/AuditRiskEvent.data';
import { deleteOne, saveOrUpdate } from '../api/AuditRiskEvent.api';
import ShowFileCotent from './ShowFileContent.vue';
import FileViewer from '/@/components/onlinePreview/FileViewer.vue';
// Emits声明
const emit = defineEmits(['register', 'success']);
const isDetail = ref(false);
......
<template>
<a-card
:bodyStyle="{ height: '100%', padding: '0px 0px', margin: '0px 0px' }"
style="overflow-y: hidden; height: 100%; padding: 0px"
:bordered="true"
>
<template #title><span v-html="fileTitle"></span></template>
<template #extra>
<a href="#" @click="handleShowDrawer">选择文件</a>
<a href="#" style="margin-left: 20px" @click="toggleCollapse">{{ toggleCollapseLeft ? '展开>' : '<收起' }}</a>
</template>
<iFrame v-if="fileTp == 'pdf'" :src="fileUrl" style="width: 100%; height: 100%"></iFrame>
<div v-else style="height: 100%; overflow: auto" v-html="docContent" class="file-content"> </div>
</a-card>
<a-drawer
title=""
placement="left"
width="100%"
:closable="false"
:visible="showDrawer"
:get-container="false"
:wrap-style="{ position: 'absolute', border: '1px solid rgb(255,255,255,0)' }"
@close="closeDrawer"
>
<DocFileList ref="regDocFileList" @selectFileDoc="setDocFile" @closeDrawer="closeDrawer" />
</a-drawer>
</template>
<script lang="ts" setup>
import iFrame from '/@/components/iFrame/index.vue';
import { ref } from 'vue';
import DocFileList from './DocFileList.vue';
import { queryDocFileById } from '../../index.api';
import mammoth from 'mammoth';
import * as XLSX from 'xlsx';
const toggleCollapseLeft = ref(false);
const loading = ref(false);
const fileTp = ref('');
const fileTitle = ref('文件名称');
const showDrawer = ref(false);
const regDocFileList = ref();
const fileUrl = ref('');
const emit = defineEmits(['register', 'success', 'goItem', 'toggleCollapse']);
function toggleCollapse() {
emit('toggleCollapse');
}
const curDocFile = ref({});
const docContent = ref<string>('');
const fetchDoc = async (docUrl) => {
try {
const response = await fetch(docUrl);
const arrayBuffer = await response.arrayBuffer();
const result = await mammoth.convertToHtml({ arrayBuffer });
docContent.value = result.value;
loading.value = false;
} catch (error) {
console.error('无法加载 DOC 文件:', error);
} finally {
loading.value = false;
}
};
const fetchText = async (docUrl) => {
try {
const response = await fetch(docUrl);
const arrayBuffer = await response.arrayBuffer();
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const decoder = new TextDecoder('utf-8'); // 根据需要选择编码
const text = decoder.decode(arrayBuffer);
docContent.value = text;
loading.value = false;
} catch (error) {
console.error('无法加载 Txt 文件:', error);
} finally {
loading.value = false;
}
};
const fetchExcel = async (docUrl) => {
try {
fetch(docUrl)
.then((response) => {
if (!response.ok) {
throw new Error('网络响应不是 OK');
}
return response.arrayBuffer();
})
.then((data) => {
const workbook = XLSX.read(data, { type: 'array' });
const firstSheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[firstSheetName];
const htmlString = XLSX.utils.sheet_to_html(worksheet);
docContent.value = htmlString;
loading.value = false;
})
.catch((error) => {
console.error('读取 Excel 文件时出错:', error);
});
loading.value = false;
} catch (error) {
console.error('无法加载 Excel 文件:', error);
} finally {
loading.value = false;
}
};
async function fetchXml(fileUrl) {
try {
const response = await fetch(fileUrl);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const xmlText = await response.text();
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlText, 'text/xml');
docContent.value = xmlText.toString();
docContent.value = createXmlTree(xmlDoc.documentElement);
loading.value = false;
} catch (error) {
console.error('Error fetching or parsing XML:', error);
} finally {
loading.value = false;
}
}
function createXmlTree(node) {
let html = `<div class="xml-node"><strong>${node.nodeName}</strong>`;
if (node.attributes && node.attributes.length > 0) {
html += ' [';
for (let i = 0; i < node.attributes.length; i++) {
const attr = node.attributes[i];
html += `${attr.name}="${attr.value}"`;
if (i < node.attributes.length - 1) {
html += ', ';
}
}
html += ']';
}
if (node.childNodes.length > 0) {
html += '<div class="xml-node">';
node.childNodes.forEach((childNode) => {
if (childNode.nodeType === Node.ELEMENT_NODE) {
// 仅处理元素节点
html += createXmlTree(childNode);
} else if (childNode.nodeType === Node.TEXT_NODE && childNode.nodeValue.trim()) {
html += `<div>文本: ${childNode.nodeValue.trim()}</div>`;
}
});
html += '</div>';
}
html += '</div>';
return html;
}
async function handleShowDrawer() {
showDrawer.value = true;
await regDocFileList.value.iniData();
}
function closeDrawer() {
showDrawer.value = false;
}
async function showCurFille(fileData) {
curDocFile.value = fileData;
let globOnlineViewUrl: string = import.meta.env.VITE_GLOB_ONLINE_VIEW_URL;
fileTp.value = fileData.fileTp;
fileUrl.value = globOnlineViewUrl + fileData.filePath;
fileTitle.value = '文件名:' + fileData.fileName;
loading.value = true;
try {
if (fileTp.value == 'docx') {
fileUrl.value = globOnlineViewUrl +"/sys/common/static/"+ fileData.filePath;
await fetchDoc(fileUrl.value);
} else if (fileTp.value == 'pdf') {
fileUrl.value = globOnlineViewUrl + fileData.filePath;
} else if (fileTp.value == 'txt') {
await fetchText(fileUrl.value);
} else if (fileTp.value == 'xml') {
await fetchXml(fileUrl.value);
} else if (fileTp.value == 'xlsx') {
fetchExcel(fileUrl.value);
} else if (fileTp.value == 'zip') {
} else {
await fetchText(fileUrl.value);
}
} catch (error) {
console.log(error);
} finally {
loading.value = false;
closeDrawer();
}
}
function getFileId() {
return curDocFile.value['fileId'] || curDocFile.value['id'];
}
function setDocFile(fileData) {
if (fileData && fileData.filePath) {
showCurFille(fileData);
curDocFile.value = fileData;
}
}
async function setDocFileById(fileId) {
if (fileId) {
curDocFile.value = await queryDocFileById({ id: fileId });
showCurFille(curDocFile.value);
}
}
defineExpose({
getFileId,
setDocFile,
setDocFileById,
});
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
::v-deep .content table {
border: 1px solid;
width: 100%;
}
::v-deep .content tr {
border: 1px solid;
}
::v-deep .content td {
border: 1px solid;
}
.ant-card-body {
padding: 2px !important;
}
:deep(.file-content) {
padding: 20px;
font-family: "Microsoft YaHei", SimSun, sans-serif;
line-height: 1.6;
color: #333;
/* 表格样式 */
table {
border-collapse: collapse;
width: 100%;
margin: 15px 0;
border: 1px solid #ddd;
th, td {
border: 1px solid #ddd;
padding: 8px 12px;
}
th {
background-color: #f2f2f2;
font-weight: bold;
}
}
/* 标题样式 */
h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
color: #222;
font-weight: bold;
}
h1 { font-size: 24px; }
h2 { font-size: 22px; }
h3 { font-size: 20px; }
h4 { font-size: 18px; }
h5 { font-size: 16px; }
h6 { font-size: 14px; }
/* 段落样式 */
p {
margin: 0 0 15px;
text-align: justify;
}
/* 列表样式 */
ul, ol {
margin: 15px 0;
padding-left: 30px;
}
li {
margin-bottom: 5px;
}
/* 图片样式 */
img {
max-width: 100%;
height: auto;
margin: 10px 0;
}
/* 代码块样式 */
pre {
background-color: #f5f5f5;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
margin: 15px 0;
}
/* 引用样式 */
blockquote {
border-left: 4px solid #ddd;
padding-left: 15px;
color: #666;
margin: 15px 0;
}
}
.ant-card-body {
padding: 2px !important;
}
</style>
<template>
<BasicModal v-bind="$attrs" @register="registerModal" title="文件内容查看" :centered="true" width="80%" :useWrapper="true" :footer="null">
<div style="background-color: #ececec; padding: 5px">
<div :style="{ overflow: 'hidden', height: '85vh' }">
<ShowFileCotent ref="refShowFileCotent" :loading="loading"/>
</div>
</div>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, nextTick } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import ShowFileCotent from './ShowFileContent.vue';
const refShowFileCotent = ref();
const loading = ref(false);
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
const { showFooter, record } = data || {};
const { filePath, fileId } = record || {};
setModalProps({
confirmLoading: false,
showCancelBtn: !!showFooter,
showOkBtn: !!showFooter,
});
if (filePath) {
refShowFileCotent.value.setDocFile(record);
} else if (fileId) {
refShowFileCotent.value.setDocFileById(fileId);
}
});
</script>
<style lang="less" scoped>
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
</style>
......@@ -172,7 +172,7 @@
</vxe-grid>
</div>
</a-drawer>
<ShowFileContentModal @register="regShowFileContentModal" />
<FileViewerModal @register="regShowFileContentModal" :useStaticPrefixForDocx="true" />
<CheckItem ref="refCheckItem" />
<TaskReportIndex ref="refTaskReportIndex" />
</template>
......@@ -181,7 +181,7 @@
import { ref, reactive,nextTick } from 'vue';
import { queryAllDataReport } from './report.api';
import { auditCols,srhCond } from './ReportCommon.data';
import ShowFileContentModal from '../components/modal/ShowFileContentModal.vue';
import FileViewerModal from '/@/components/onlinePreview/FileViewerModal.vue';
import CheckItem from '../components/CheckItem.vue';
import TaskReportIndex from '../TaskReportIndex.vue';
......
......@@ -37,7 +37,7 @@
</a-card>
<ShowFileContentModal @register="regShowFileContentModal" />
<FileViewerModal @register="regShowFileContentModal" :useStaticPrefixForDocx="true" />
</div>
</template>
<script lang="ts" setup>
......@@ -48,7 +48,7 @@ import { VXETable } from 'vxe-table';
import { queryActRelates } from '../index.api';
import { auditCols,srhCond } from './ReportCommon.data';
import DocFileList from './DocFileList.vue';
import ShowFileContentModal from '../components/modal/ShowFileContentModal.vue';
import FileViewerModal from '/@/components/onlinePreview/FileViewerModal.vue';
import { useModal } from '/@/components/Modal';
const [regShowFileContentModal, { openModal }] = useModal();
......
......@@ -30,7 +30,7 @@
/>
</template> -->
</vxe-grid>
<ShowFileContentModal @register="regShowFileContentModal" />
<FileViewerModal @register="regShowFileContentModal" :useStaticPrefixForDocx="true" />
<a-drawer
title="已选择"
v-model:visible="isOpenDrawer"
......@@ -71,7 +71,7 @@
import { auditCols } from './ReportCommon.data';
import { VXETable } from 'vxe-table';
import { useModal } from '/@/components/Modal';
import ShowFileContentModal from '../components/modal/ShowFileContentModal.vue';
import FileViewerModal from '/@/components/onlinePreview/FileViewerModal.vue';
const [regShowFileContentModal, { openModal }] = useModal();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论