13 changed files with 387 additions and 4273 deletions
-
27src/api/system/documentArchives.js
-
10src/assets/styles/mixin.scss
-
925src/views/archivesMIOD/miodLibrary/index copy.vue
-
320src/views/archivesMIOD/miodLibrary/index.vue
-
1100src/views/archivesMIOD/miodLibrary/module/detail.json
-
80src/views/archivesMIOD/miodLibrary/module/detail.vue
-
136src/views/archivesMIOD/miodLibrary/module/pdfDialog.vue
-
360src/views/archivesMIOD/miodLibrary/module/pdfViewer.vue
-
610src/views/archivesMIOD/miodLibrary/module/pdfViewer2.vue
-
293src/views/archivesMIOD/miodLibrary/module/pdfViewer3.vue
-
146src/views/archivesMIOD/miodLibrary/module/pdfViewer4.vue
-
642src/views/archivesMIOD/miodLibrary/showFiled.json
-
11src/views/system/borrowerManage/index.vue
@ -1,925 +0,0 @@ |
|||
<template> |
|||
<div class="app-container"> |
|||
<!-- 门类列表 --> |
|||
<div class="container-main"> |
|||
<div class="elect-cont-left"> |
|||
<TreeList ref="treeList" @nodeClick="handleNodeClick" /> |
|||
</div> |
|||
<div v-if="selectedDocument.isType!==1" class="elect-cont-right"> |
|||
<!--工具栏--> |
|||
<div class="head-container" :style="isRecycle?'display:flex;justify-content: space-between; align-items: center;':'' "> |
|||
<div class="head-search" :style="isRecycle?'margin: 0;':''"> |
|||
<!-- 搜索 --> |
|||
<el-input v-model="query.search" clearable size="small" placeholder="输入题名搜索" prefix-icon="el-icon-search" style="width: 200px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> |
|||
<rrOperation /> |
|||
<el-button class="filter-item filter-refresh" size="mini" type="warning" icon="el-icon-refresh-left" @click="resetQuery">重置</el-button> |
|||
</div> |
|||
<crudOperation v-if="!isRecycle" :permission="permission"> |
|||
<template v-slot:left> |
|||
<!-- 新增 --> |
|||
<el-button size="mini" @click="handleForm('add')"><i class="iconfont icon-xinzeng" />新增</el-button> |
|||
<!-- 修改 --> |
|||
<el-button size="mini" :disabled="crud.selections.length !== 1" @click="handleForm('edit')"><i class="iconfont icon-bianji" />编辑</el-button> |
|||
<!-- 删除btn 多选 --> |
|||
<el-button size="mini" :loading="crud.delAllLoading" :disabled="crud.selections.length === 0" @click="toDelete(crud.selections)"><i class="iconfont icon-shanchu" />删除</el-button> |
|||
<el-button :loading="crud.downloadLoading" size="mini" :disabled="crud.selections.length === 0" @click="doExport(crud.selections)"> |
|||
<i class="iconfont icon-daochu" /> |
|||
导出 |
|||
</el-button> |
|||
</template> |
|||
<template v-slot:rightButtonGroup> |
|||
<div> |
|||
<el-button size="mini" :disabled="crud.selections.length === 0" @click="doPrint(crud.selections)"><i class="iconfont icon-dayin" />打印处理单</el-button> |
|||
</div> |
|||
</template> |
|||
</crudOperation> |
|||
<div v-if="isRecycle"> |
|||
<el-button size="mini" type="success" @click="toRecover(crud.selections)"><i class="iconfont icon-huifu" />恢复</el-button> |
|||
<el-button size="mini" type="success" @click="toCompletelyDelete(crud.selections)"><i class="iconfont icon-shanchu" />彻底删除</el-button> |
|||
</div> |
|||
</div> |
|||
<!--表格渲染--> |
|||
<div class="container-right"> |
|||
<span class="right-top-line" /> |
|||
<span class="left-bottom-line" /> |
|||
<el-table |
|||
ref="table" |
|||
v-loading="crud.loading" |
|||
class="archives-table" |
|||
:data="crud.data" |
|||
style="width: 100%;" |
|||
@row-click="clickRowHandler" |
|||
@select="crud.selectChange" |
|||
@select-all="crud.selectAllChange" |
|||
@selection-change="crud.selectionChangeHandler" |
|||
@cell-dblclick="tableDoubleClick" |
|||
> |
|||
<el-table-column type="selection" align="center" width="55" /> |
|||
<el-table-column v-for="field in tableDisplayFields" :key="field.id" :label="field.fieldCnName" :align="field.displayformatType" :width="field.displayLength" show-overflow-tooltip> |
|||
<template slot="header"> |
|||
<el-tooltip |
|||
class="item" |
|||
effect="dark" |
|||
:content="field.fieldCnName" |
|||
placement="top-start" |
|||
> |
|||
<span>{{ field.fieldCnName }}</span> |
|||
</el-tooltip> |
|||
</template> |
|||
<template slot-scope="scope"> |
|||
<!-- 仅针对read_type字段添加特殊处理 --> |
|||
<span |
|||
v-if="field.fieldName === 'read_type'" |
|||
:class="{ |
|||
'row-state row-packing': scope.row.read_type === '未传阅', |
|||
'row-state row-warehousing state-active': scope.row.read_type === '传阅中', |
|||
'row-state row-binding state-active': scope.row.read_type === '已完成', |
|||
}" |
|||
> |
|||
{{ scope.row[field.fieldName] }} |
|||
</span> |
|||
<span v-else>{{ scope.row[field.fieldName] }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<!--分页组件--> |
|||
<pagination v-if="crud.data.length !== 0" /> |
|||
</div> |
|||
<detail ref="archivesInfo" :selected-document="selectedDocument" /> |
|||
|
|||
<!--新增 / 编辑 表单组件--> |
|||
<el-dialog class="preview-dialog" :modal-append-to-body="false" :close-on-click-modal="false" append-to-body :before-close="closeDialog" :visible="formVisible" :title="formTitle"> |
|||
<span class="dialog-right-top" /> |
|||
<span class="dialog-left-bottom" /> |
|||
<div class="setting-dialog"> |
|||
<PreviewForm |
|||
ref="previewForm" |
|||
:form-preview-data.sync="formPreviewData" |
|||
:selected-category="selectedCategory" |
|||
:parents-id="parentsId" |
|||
:arc-id="arcId" |
|||
:is-des-form-type="isDesFormType" |
|||
:is-disabled="isDisabled" |
|||
:selected-document="selectedDocument" |
|||
:is-has-code="isHasCode" |
|||
@close-dialog="closeDialog" |
|||
@formLoadingShow="formLoadingShow" |
|||
@refreshTree="refreshTreeList" |
|||
/> |
|||
<div slot="footer" class="dialog-footer" style="margin-top: 20px !important;"> |
|||
<el-button type="text" @click="closeDialog">取消</el-button> |
|||
<el-button :loading="archivesBtnLoading" type="primary" @click="handlerArchivesSubmit">保存</el-button> |
|||
<!-- @click="handlerArchivesSubmit" --> |
|||
<el-button :loading="bindSaveLoading" type="primary">保存并绑定标签</el-button> |
|||
</div> |
|||
</div> |
|||
</el-dialog> |
|||
<!--表单组件--> |
|||
<el-dialog class="tip-dialog" :close-on-click-modal="false" :modal-append-to-body="false" append-to-body title="提示" :visible.sync="printVisible"> |
|||
<div class="setting-dialog"> |
|||
<div class="tip-content"> |
|||
<p class="tipMsg">此操作将打印所选公文库数据</p> |
|||
</div> |
|||
<el-radio-group v-model="printType" style="padding-left: 36px;"> |
|||
<el-radio :label="0">套打</el-radio> |
|||
<el-radio :label="1">彩打</el-radio> |
|||
</el-radio-group> |
|||
<div slot="footer" class="dialog-footer"> |
|||
<el-button @click.native="printVisible = false">取消</el-button> |
|||
<el-button type="primary" @click.native="handlePrint">确定</el-button> |
|||
</div> |
|||
</div> |
|||
</el-dialog> |
|||
<!-- v-show="isHidden" --> |
|||
<div id="print" ref="printId" class="print-container"> |
|||
<!-- 收文处理单表格 --> |
|||
<table class="official-table" width="100%" cellpadding="1" cellspacing="0"> |
|||
<!-- 列宽定义 --> |
|||
<col width="32*"> |
|||
<col width="70*"> |
|||
<col width="42*"> |
|||
<col width="56*"> |
|||
<col width="27*"> |
|||
<col width="29*"> |
|||
|
|||
<!-- 表头 --> |
|||
<tbody> |
|||
<tr> |
|||
<td colspan="6" class="header-cell"> |
|||
<p class="header-text" style="font-size: 30px;">武汉市交通运输局收文处理单</p> |
|||
</td> |
|||
</tr> |
|||
</tbody> |
|||
|
|||
<!-- 收文信息行 --> |
|||
<tbody> |
|||
<tr> |
|||
<td class="label-cell">收文号</td> |
|||
<td class="content-cell">{{ formData.receiveNo }}</td> |
|||
<td class="label-cell">收文日期</td> |
|||
<td class="content-cell">{{ formData.receiveDate }}</td> |
|||
<td class="label-cell">缓急</td> |
|||
<td class="content-cell">{{ formData.urgency }}</td> |
|||
</tr> |
|||
</tbody> |
|||
|
|||
<!-- 来文信息行 --> |
|||
<tbody> |
|||
<tr> |
|||
<td class="label-cell">来文单位</td> |
|||
<td class="content-cell">{{ formData.senderUnit }}</td> |
|||
<td class="label-cell">来文字号</td> |
|||
<td class="content-cell">{{ formData.senderNo }}</td> |
|||
<td class="label-cell">密级</td> |
|||
<td class="content-cell">{{ formData.secrecyLevel }}</td> |
|||
</tr> |
|||
</tbody> |
|||
|
|||
<!-- 提示行 --> |
|||
<tbody> |
|||
<tr> |
|||
<td class="label-cell">提示</td> |
|||
<td colspan="5" class="content-cell content-left">{{ formData.tip }}</td> |
|||
</tr> |
|||
</tbody> |
|||
|
|||
<!-- 文件标题行 --> |
|||
<tbody> |
|||
<tr> |
|||
<td class="label-cell">文件标题</td> |
|||
<td colspan="5" class="content-cell content-left">{{ formData.fileTitle }}</td> |
|||
</tr> |
|||
</tbody> |
|||
|
|||
<!-- 拟办意见行 --> |
|||
<tbody> |
|||
<tr> |
|||
<td class="label-cell">拟办意见</td> |
|||
<td colspan="5" class="content-cell content-left">{{ formData.recommendation }}</td> |
|||
</tr> |
|||
</tbody> |
|||
|
|||
<!-- 领导批示行 --> |
|||
<tbody> |
|||
<tr> |
|||
<td class="label-cell">领导批示</td> |
|||
<td colspan="5" class="content-cell content-left">{{ formData.leaderApproval }}</td> |
|||
</tr> |
|||
</tbody> |
|||
|
|||
<!-- 部门阅办行 --> |
|||
<tbody> |
|||
<tr> |
|||
<td class="label-cell">部门阅办</td> |
|||
<td colspan="5" class="content-cell content-center">{{ formData.departmentOpinion }}</td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import CRUD, { presenter, header } from '@crud/crud' |
|||
import { miodLibraryCrud } from './mixins/index' |
|||
import crudDocumentArchives, { FetchDelArchives, FetchCompleteDelArchives, FetchRestoreArchives } from '@/api/system/documentArchives' |
|||
import rrOperation from '@crud/RR.operation' |
|||
import crudOperation from '@crud/CRUD.operation' |
|||
import pagination from '@crud/Pagination' |
|||
import TreeList from './treeList' |
|||
import PreviewForm from '@/views/components/category/PreviewForm' |
|||
import detail from './module/detail' |
|||
import { exportFile } from '@/utils/index' |
|||
import qs from 'qs' |
|||
import { mapGetters } from 'vuex' |
|||
|
|||
import html2canvas from 'html2canvas' |
|||
import printJS from 'print-js' |
|||
|
|||
export default { |
|||
name: 'MiodLibrary', |
|||
components: { TreeList, PreviewForm, detail, rrOperation, crudOperation, pagination }, |
|||
cruds() { |
|||
return [ |
|||
CRUD({ |
|||
title: '收发文', url: 'api/documentArchives/initPreDocument', |
|||
crudMethod: { ...crudDocumentArchives }, |
|||
optShow: { |
|||
add: false, |
|||
edit: false, |
|||
del: false, |
|||
download: false, |
|||
group: false, |
|||
reset: false |
|||
}, |
|||
queryOnPresenterCreated: false |
|||
}) |
|||
] |
|||
}, |
|||
provide() { |
|||
return { |
|||
parentsData: this |
|||
} |
|||
}, |
|||
mixins: [presenter(), header(), miodLibraryCrud], |
|||
props: { |
|||
isRecycle: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
isdel: { |
|||
type: Boolean, |
|||
default: false |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
archivesBtnLoading: false, |
|||
bindSaveLoading: false, |
|||
permission: { |
|||
add: ['admin', 'prearchiveLibrary:add'], |
|||
edit: ['admin', 'prearchiveLibrary:edit'], |
|||
del: ['admin', 'prearchiveLibrary:del'], |
|||
sort: ['admin', 'prearchiveLibrary:sort'] |
|||
}, |
|||
tableDisplayFields: [], // table-list-title字段 |
|||
arrySort: [], |
|||
selectedDocument: {}, |
|||
form: {}, |
|||
formVisible: false, |
|||
formTitle: '新增文件', |
|||
formPreviewData: [], |
|||
selectedCategory: null, |
|||
parentsId: null, |
|||
arcId: null, |
|||
isDesFormType: 'miodLibrary', |
|||
isDisabled: false, |
|||
isHasCode: false, |
|||
printVisible: false, |
|||
printType: 0, |
|||
isHidden: false, |
|||
formData: { |
|||
receiveNo: '武交收〔2025〕12号', |
|||
receiveDate: '2025年05月20日', |
|||
urgency: '急件', |
|||
senderUnit: '湖北省交通运输厅', |
|||
senderNo: '鄂交发〔2025〕35号', |
|||
secrecyLevel: '普通', |
|||
tip: '请办公室尽快协调相关部门阅办', |
|||
fileTitle: '关于加强交通运输安全生产管理的通知', |
|||
recommendation: '建议转交运输科牵头办理,5个工作日内反馈意见', |
|||
leaderApproval: '同意拟办意见,张XX 2025.05.20', |
|||
departmentOpinion: '已阅,将于2025.05.25前反馈' |
|||
}, |
|||
printTitle: '' |
|||
} |
|||
}, |
|||
computed: { |
|||
...mapGetters([ |
|||
'baseApi' |
|||
]) |
|||
}, |
|||
watch: { |
|||
isdel: function(newValue, oldValue) { |
|||
}, |
|||
isRecycle: function(newValue, oldValue) { |
|||
} |
|||
}, |
|||
created() { |
|||
}, |
|||
methods: { |
|||
refreshTreeList() { |
|||
this.$refs.treeList.refreshData() |
|||
}, |
|||
resetQuery() { |
|||
if (this.selectedDocument.isType === 3) { |
|||
this.crud.query.docDepartment = this.selectedDocument.label |
|||
this.crud.query.archiveYear = null |
|||
this.crud.query.search = null |
|||
} else if (this.selectedDocument.isType === 4) { |
|||
this.crud.query.docDepartment = null |
|||
this.crud.query.archiveYear = this.selectedDocument.label |
|||
this.crud.query.search = null |
|||
} else { |
|||
this.crud.query.search = null |
|||
this.crud.query.docDepartment = null |
|||
this.crud.query.archiveYear = null |
|||
} |
|||
this.crud.toQuery() |
|||
}, |
|||
[CRUD.HOOK.beforeRefresh]() { |
|||
if (this.selectedDocument.isType === 2) { |
|||
this.crud.query.documentId = this.selectedDocument.id |
|||
} else { |
|||
this.crud.query.documentId = this.selectedDocument.documentId |
|||
} |
|||
this.crud.query.isdel = this.isdel |
|||
// this.crud.query.ignore = false |
|||
this.crud.query.fondsAffiliation = this.selectedDocument.fondsId |
|||
this.crud.query.sort = this.arrySort |
|||
}, |
|||
formLoadingShow(loadingType) { |
|||
this.archivesBtnLoading = loadingType |
|||
}, |
|||
handleNodeClick(data) { |
|||
if (data.isType !== 1) { |
|||
this.selectedDocument = data |
|||
let documentId = null |
|||
if (data.isType === 2) { |
|||
documentId = data.id |
|||
} else { |
|||
documentId = data.documentId |
|||
} |
|||
this.getInitDocumentsViewTable(documentId) |
|||
} |
|||
}, |
|||
// table字段项 |
|||
getInitDocumentsViewTable(documentId) { |
|||
crudDocumentArchives.FetchInitDocumentsViewTable({ documentId: documentId }).then(data => { |
|||
if (data) { |
|||
this.arrySort = [] |
|||
this.tableDisplayFields = data |
|||
const orderSortArry = this.tableDisplayFields.filter(item => item.queue).sort((a, b) => a.queue - b.queue) |
|||
orderSortArry.forEach(item => { |
|||
if (item.displayOrderBy) { |
|||
this.arrySort.push(item.fieldName + ',' + item.displayOrderBy) |
|||
} |
|||
}) |
|||
this.$nextTick(() => { |
|||
if (this.selectedDocument.isType === 3) { |
|||
this.crud.query.docDepartment = this.selectedDocument.label |
|||
this.crud.query.archiveYear = null |
|||
} else if (this.selectedDocument.isType === 4) { |
|||
this.crud.query.docDepartment = null |
|||
this.crud.query.archiveYear = this.selectedDocument.label |
|||
} else { |
|||
this.crud.query.search = null |
|||
this.crud.query.docDepartment = null |
|||
this.crud.query.archiveYear = null |
|||
} |
|||
this.crud.toQuery() |
|||
}) |
|||
} |
|||
}) |
|||
}, |
|||
handleForm(type) { |
|||
const { selectedDocument, crud } = this |
|||
|
|||
if (!selectedDocument) { |
|||
console.warn('selectedDocument 未定义,无法继续操作') |
|||
return |
|||
} |
|||
|
|||
this.selectedCategory = selectedDocument |
|||
this.isDesFormType = 'miodLibrary' |
|||
|
|||
let documentId |
|||
if (selectedDocument.isType === 2) { |
|||
documentId = selectedDocument.id |
|||
} else { |
|||
documentId = selectedDocument.documentId |
|||
} |
|||
|
|||
const params = { documentId } |
|||
|
|||
if (type === 'add') { |
|||
this.formTitle = '新增文件' |
|||
params.archivesId = null |
|||
} else if (type === 'edit') { |
|||
this.formTitle = '编辑文件' |
|||
const { id: archivesId } = crud.selections[0] |
|||
this.arcId = archivesId |
|||
params.archivesId = archivesId |
|||
} |
|||
|
|||
this.getFormInfo(params, type) |
|||
}, |
|||
|
|||
getFormInfo(params, type) { |
|||
crudDocumentArchives.FetchDoeditDocument(params).then(data => { |
|||
console.log('data', data) |
|||
const showFiledAll = data.showFiled.filter(item => item.isSequence).sort((a, b) => a.isSequence - b.isSequence) |
|||
this.$nextTick(() => { |
|||
this.formPreviewData = showFiledAll |
|||
this.formVisible = true |
|||
this.$nextTick(() => { |
|||
this.$refs.previewForm.fileOriginal = null |
|||
this.$refs.previewForm.fileJsonString = null |
|||
if (type === 'edit') { |
|||
this.$refs.previewForm.archivesType = 'edit' |
|||
this.$refs.previewForm.addOrUpdateForm = data.echo |
|||
if (data.fileecho) { |
|||
const fileecho = [] |
|||
fileecho.push(data.fileecho) |
|||
this.$refs.previewForm.fileOriginal = fileecho[0].file_name |
|||
this.$refs.previewForm.fileJsonString = JSON.stringify(fileecho) |
|||
} else { |
|||
this.$refs.previewForm.fileOriginal = '' |
|||
this.$refs.previewForm.fileJsonString = '' |
|||
} |
|||
} else { |
|||
this.$refs.previewForm.archivesType = 'add' |
|||
} |
|||
}) |
|||
}) |
|||
}) |
|||
}, |
|||
handlerArchivesSubmit() { |
|||
let documentId |
|||
if (this.selectedDocument.isType === 2) { |
|||
documentId = this.selectedDocument.id |
|||
} else { |
|||
documentId = this.selectedDocument.documentId |
|||
} |
|||
this.$refs.previewForm.submitForm('addOrUpdateForm', documentId) |
|||
}, |
|||
clickRowHandler(row) { |
|||
this.$refs.table.clearSelection() |
|||
this.$refs.table.toggleRowSelection(row) |
|||
}, |
|||
// 双击查看详情 |
|||
tableDoubleClick(row) { |
|||
console.log('tableDoubleClick', row) |
|||
this.$refs.archivesInfo.archivesInfoVisible = true |
|||
this.$refs.archivesInfo.archivesTabIndex = 0 |
|||
this.$refs.archivesInfo.parentInfo = row |
|||
this.$refs.archivesInfo.getDetial(row.id) |
|||
}, |
|||
// 删除 |
|||
toDelete(datas) { |
|||
this.$confirm('此操作将删除当前所选公文库数据' + '<span>你是否还要继续?</span>', '提示', { |
|||
confirmButtonText: '继续', |
|||
cancelButtonText: '取消', |
|||
type: 'warning', |
|||
dangerouslyUseHTMLString: true |
|||
}).then(() => { |
|||
this.crud.delAllLoading = true |
|||
const ids = [] |
|||
datas.forEach(val => { |
|||
ids.push(val.id) |
|||
}) |
|||
let documentId |
|||
if (this.selectedDocument.isType === 2) { |
|||
documentId = this.selectedDocument.id |
|||
} else { |
|||
documentId = this.selectedDocument.documentId |
|||
} |
|||
|
|||
const params = { |
|||
'documentId': documentId, |
|||
'archivesIds': ids |
|||
} |
|||
|
|||
FetchDelArchives(params).then((res) => { |
|||
console.log('res', res) |
|||
if (res.code !== 500) { |
|||
this.crud.notify('删除成功', CRUD.NOTIFICATION_TYPE.SUCCESS) |
|||
this.crud.refresh() |
|||
} else { |
|||
this.crud.notify('删除失败', CRUD.NOTIFICATION_TYPE.ERROR) |
|||
} |
|||
this.crud.delAllLoading = false |
|||
}).catch(err => { |
|||
this.crud.delAllLoading = false |
|||
console.log(err) |
|||
}) |
|||
}).catch(() => { |
|||
}) |
|||
}, |
|||
// 导出 |
|||
doExport(datas) { |
|||
this.crud.downloadLoading = true |
|||
this.$confirm('此操作将导出所选数据' + '<span>你是否还要继续?</span>', '提示', { |
|||
confirmButtonText: '继续', |
|||
cancelButtonText: '取消', |
|||
type: 'warning', |
|||
dangerouslyUseHTMLString: true |
|||
}).then(() => { |
|||
const ids = [] |
|||
datas.forEach(val => { |
|||
ids.push(val.id) |
|||
}) |
|||
let documentId |
|||
if (this.selectedDocument.isType === 2) { |
|||
documentId = this.selectedDocument.id |
|||
} else { |
|||
documentId = this.selectedDocument.documentId |
|||
} |
|||
const params = { |
|||
'documentId': documentId, |
|||
'ids': ids |
|||
} |
|||
exportFile(this.baseApi + '/api/documentArchives/downloadDocumentArchives?' + qs.stringify(params, { indices: false })) |
|||
this.crud.downloadLoading = false |
|||
}).catch(() => { |
|||
this.crud.downloadLoading = false |
|||
}) |
|||
}, |
|||
doPrint(datas) { |
|||
this.printVisible = true |
|||
}, |
|||
handlePrint() { |
|||
this.printVisible = false |
|||
this.isHidden = true |
|||
if (this.isHidden) { |
|||
const timer = setTimeout(() => { |
|||
this.printFn() |
|||
this.isHidden = false |
|||
clearTimeout(timer) |
|||
}, 100) |
|||
} |
|||
}, |
|||
printFn() { |
|||
// printJS({ |
|||
// printable: 'print', |
|||
// type: 'html', |
|||
// style: `page { |
|||
// size: A4; |
|||
// margin: 2cm; |
|||
// } |
|||
// /* 基础样式 */ |
|||
// .print-container { |
|||
// font-family: "宋体", sans-serif; |
|||
// margin: 20px; |
|||
// } |
|||
|
|||
// /* 标题样式 */ |
|||
// .print-title { |
|||
// font-size: 22pt; |
|||
// font-family: "华文中宋"; |
|||
// color: #ff0000; |
|||
// margin: 20px 0; |
|||
// } |
|||
|
|||
// /* 表格样式 */ |
|||
// .official-table { |
|||
// border-collapse: collapse; |
|||
// width: 100%; |
|||
// } |
|||
|
|||
// .label-cell, .content-cell { |
|||
// border: 1px solid #ff0000; |
|||
// padding: 8px; |
|||
// } |
|||
|
|||
// .label-cell { |
|||
// background: #ffffff; |
|||
// text-align: center; |
|||
// font-size: 12pt; |
|||
// color: #ff0000; |
|||
// vertical-align: middle; |
|||
// } |
|||
|
|||
// .content-cell { |
|||
// background: #ffffff; |
|||
// font-size: 12pt; |
|||
// vertical-align: top; |
|||
// } |
|||
|
|||
// .content-left { |
|||
// text-align: left; |
|||
// } |
|||
|
|||
// .content-center { |
|||
// text-align: center; |
|||
// } |
|||
|
|||
// .header-cell { |
|||
// border: none; |
|||
// padding: 20px 0; |
|||
// text-align: center; |
|||
// } |
|||
|
|||
// .header-text { |
|||
// font-family: "华文中宋"; |
|||
// font-size: 10pt; |
|||
// color: #ff0000; |
|||
// margin: 0; |
|||
// } |
|||
// ` // 去除页眉页脚 |
|||
// }) |
|||
const printContent = this.$refs.printId |
|||
// 获取dom 宽度 高度 |
|||
const width = printContent.clientWidth |
|||
const height = printContent.clientHeight |
|||
console.log('height', height) |
|||
// 创建一个canvas节点 |
|||
const canvas = document.createElement('canvas') |
|||
|
|||
const scale = 1 // 定义任意放大倍数,支持小数;越大,图片清晰度越高,生成图片越慢。 |
|||
canvas.width = width * scale // 定义canvas 宽度 * 缩放 |
|||
canvas.height = height * scale // 定义canvas高度 *缩放 |
|||
canvas.style.width = width * scale + 'px' |
|||
canvas.style.height = height * scale + 'px' |
|||
canvas.getContext('2d').scale(scale, scale) // 获取context,设置scale |
|||
|
|||
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop // 获取滚动轴滚动的长度 |
|||
const scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft // 获取水平滚动轴的长度 |
|||
|
|||
html2canvas(printContent, { |
|||
canvas, |
|||
backgroundColor: null, |
|||
useCORS: true, |
|||
windowHeight: document.body.scrollHeight, |
|||
scrollX: -scrollLeft, // 解决水平偏移问题,防止打印的内容不全 |
|||
scrollY: -scrollTop |
|||
}).then((canvas) => { |
|||
const url = canvas.toDataURL('image/png') |
|||
printJS({ |
|||
printable: url, |
|||
type: 'image', |
|||
documentTitle: '', // 标题 |
|||
style: '@page{size:auto;margin: 0cm 1cm 0cm 1cm;}' // 去除页眉页脚 |
|||
}) |
|||
}).catch(err => { |
|||
console.error(err) |
|||
}) |
|||
}, |
|||
// 回收站 - 恢复 |
|||
toRecover(datas) { |
|||
if (datas.length === 0) { |
|||
this.$message({ message: '您还未勾选需要操作的条目,请先确认!', offset: 8 }) |
|||
return false |
|||
} |
|||
this.$confirm('此恢复将会把所选条目及其子集一并恢复' + '<span>你是否还要继续?</span>', '提示', { |
|||
confirmButtonText: '继续', |
|||
cancelButtonText: '取消', |
|||
type: 'warning', |
|||
dangerouslyUseHTMLString: true |
|||
}).then(() => { |
|||
const archivesIds = [] |
|||
datas.forEach(val => { |
|||
archivesIds.push(val.id) |
|||
}) |
|||
|
|||
let documentId |
|||
if (this.selectedDocument.isType === 2) { |
|||
documentId = this.selectedDocument.id |
|||
} else { |
|||
documentId = this.selectedDocument.documentId |
|||
} |
|||
const params = { |
|||
'documentId': documentId, |
|||
'archivesIds': archivesIds |
|||
} |
|||
console.log('params', params) |
|||
FetchRestoreArchives(params).then((res) => { |
|||
console.log('res', res) |
|||
if (res.code !== 500) { |
|||
if (res.includes('成功')) { |
|||
this.$message({ message: res, type: 'success', offset: 8 }) |
|||
this.crud.refresh() |
|||
this.refreshTreeList() |
|||
} else { |
|||
this.$message({ message: res, type: 'error', offset: 8 }) |
|||
} |
|||
} else { |
|||
this.$message({ message: '恢复所选档案失败', type: 'error', offset: 8 }) |
|||
} |
|||
}).catch(err => { |
|||
console.log(err) |
|||
}) |
|||
}).catch(() => { |
|||
}) |
|||
}, |
|||
// 回收站 - 彻底删除 |
|||
toCompletelyDelete(datas) { |
|||
if (datas.length === 0) { |
|||
this.$message({ message: '您还未勾选需要操作的条目,请先确认!', offset: 8 }) |
|||
return false |
|||
} |
|||
this.$confirm('此删除将把会所选条目与其子集彻底删除' + '<span>你是否还要继续?</span>', '提示', { |
|||
confirmButtonText: '继续', |
|||
cancelButtonText: '取消', |
|||
type: 'warning', |
|||
dangerouslyUseHTMLString: true |
|||
}).then(() => { |
|||
const archivesIds = [] |
|||
datas.forEach(val => { |
|||
archivesIds.push(val.id) |
|||
}) |
|||
let documentId |
|||
if (this.selectedDocument.isType === 2) { |
|||
documentId = this.selectedDocument.id |
|||
} else { |
|||
documentId = this.selectedDocument.documentId |
|||
} |
|||
const params = { |
|||
'documentId': documentId, |
|||
'archivesIds': archivesIds |
|||
} |
|||
console.log('params', params) |
|||
FetchCompleteDelArchives(params).then((res) => { |
|||
if (res.code !== 500) { |
|||
this.$message({ message: res, type: 'success', offset: 8 }) |
|||
this.crud.refresh() |
|||
this.refreshTreeList() |
|||
} else { |
|||
this.$message({ message: '删除所选档案失败', type: 'error', offset: 8 }) |
|||
} |
|||
}).catch(err => { |
|||
console.log(err) |
|||
}) |
|||
}).catch(() => { |
|||
}) |
|||
}, |
|||
closeDialog() { |
|||
this.formVisible = false |
|||
this.$refs.previewForm.miodDeptsTags = [] |
|||
this.$refs.previewForm.miodDeptsSelections = [] |
|||
this.$refs.previewForm.deptsValid = false |
|||
if (this.$refs.previewForm.$refs['addOrUpdateForm']) { |
|||
this.$refs.previewForm.$refs['addOrUpdateForm'].clearValidate() |
|||
this.$refs.previewForm.$refs['addOrUpdateForm'].resetFields() |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
<style> |
|||
@media print { |
|||
html,body{ |
|||
height: inherit; |
|||
} |
|||
.print-container { |
|||
position: absolute; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
} |
|||
@page { |
|||
size: A4; |
|||
margin: 2cm; |
|||
} |
|||
} |
|||
</style> |
|||
<style lang='scss' scoped> |
|||
@import "~@/assets/styles/collect-reorganizi.scss"; |
|||
@mixin management-fixed-style{ |
|||
[data-theme="dark"] & { |
|||
background-color: #031435 !important; |
|||
-webkit-box-shadow: -5px 5px 10px 1px rgba(15,164,222,.16); |
|||
box-shadow: -5px 5px 10px 1px rgba(15,164,222,.16); |
|||
} |
|||
[data-theme="light"] & { |
|||
background-color: #fff; |
|||
} |
|||
} |
|||
.el-table { |
|||
::v-deep .el-table__fixed-right { |
|||
@include management-fixed-style; |
|||
} |
|||
} |
|||
.preview-dialog .el-dialog .preview-content { |
|||
height: calc(100vh - 264px) !important; |
|||
|
|||
} |
|||
.elect-cont-right .container-right { |
|||
min-height: calc(100vh - 284px); |
|||
} |
|||
.dialog-footer .el-button.el-button--primary, |
|||
.el-message-box__btns .el-button.el-button--primary{ |
|||
width: auto; |
|||
height: auto; |
|||
line-height:normal; |
|||
padding: 6px 20px; |
|||
} |
|||
|
|||
.tip-dialog{ |
|||
::v-deep .el-dialog{ |
|||
width: 504px; |
|||
.setting-dialog{ |
|||
padding: 10px 10px 0 10px; |
|||
} |
|||
.tip-content{ |
|||
padding-left: 34px; |
|||
font-size: 14px; |
|||
line-height: 24px; |
|||
color: #0C0E1E; |
|||
background: url("~@/assets/images/icon/tip-icon.png") no-repeat left top; |
|||
background-size: 24px 24px; |
|||
padding-bottom: 20px; |
|||
span{ |
|||
font-size: 12px; |
|||
color: #ED4A41; |
|||
} |
|||
} |
|||
} |
|||
.dialog-footer{ |
|||
margin-top: 27px; |
|||
} |
|||
} |
|||
.intoExamine{ |
|||
position: fixed; |
|||
left: 50%; |
|||
top: 50%; |
|||
transform: translate(-50%,-50%); |
|||
z-index: 99; |
|||
} |
|||
/* 基础样式 */ |
|||
.print-container { |
|||
position: fixed; |
|||
left: 50%; |
|||
top: 50%; |
|||
transform: translate(-50%,-50%); |
|||
z-index: 99; |
|||
} |
|||
|
|||
/* 标题样式 */ |
|||
.print-title { |
|||
font-size: 22pt; |
|||
font-family: "华文中宋"; |
|||
color: #ff0000; |
|||
margin: 20px 0; |
|||
} |
|||
|
|||
/* 表格样式 */ |
|||
.official-table { |
|||
border-collapse: collapse; |
|||
width: 100%; |
|||
} |
|||
|
|||
.label-cell, .content-cell { |
|||
border: 1px solid #ff0000; |
|||
padding: 8px; |
|||
} |
|||
|
|||
.label-cell { |
|||
background: #ffffff; |
|||
text-align: center; |
|||
font-size: 12pt; |
|||
color: #ff0000; |
|||
vertical-align: middle; |
|||
} |
|||
|
|||
.content-cell { |
|||
background: #ffffff; |
|||
font-size: 12pt; |
|||
vertical-align: top; |
|||
} |
|||
|
|||
.content-left { |
|||
text-align: left; |
|||
} |
|||
|
|||
.content-center { |
|||
text-align: center; |
|||
} |
|||
|
|||
.header-cell { |
|||
border: none; |
|||
padding: 20px 0; |
|||
text-align: center; |
|||
} |
|||
|
|||
.header-text { |
|||
font-family: "华文中宋"; |
|||
font-size: 22pt; |
|||
color: #ff0000; |
|||
margin: 0; |
|||
} |
|||
</style> |
1100
src/views/archivesMIOD/miodLibrary/module/detail.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,136 @@ |
|||
<template> |
|||
<el-dialog |
|||
:visible.sync="dialogVisible" |
|||
:close-on-click-modal="false" |
|||
:modal-append-to-body="false" |
|||
append-to-body |
|||
title="查看打印公文" |
|||
width="80%" |
|||
:before-close="handleClose" |
|||
> |
|||
<div class="setting-dialog"> |
|||
<div |
|||
v-if="loading" |
|||
v-loading="loading" |
|||
element-loading-text="正在加载公文文档,请稍候..." |
|||
element-loading-spinner="el-icon-loading" |
|||
class="global-loading" |
|||
> |
|||
<!-- <p>正在加载文档,请稍候...</p> --> |
|||
</div> |
|||
|
|||
<PdfViewer |
|||
v-else-if="pdfSources.length > 0" |
|||
ref="pdfViewerRef" |
|||
:pdf-sources="pdfSources" |
|||
frame-height="70vh" |
|||
@pdfPrinted="onPdfPrinted" |
|||
/> |
|||
|
|||
<div v-else class="empty-state"> |
|||
<img style="display: block; width: 100px;" src="~@/assets/images/errRecord.png" alt=""> |
|||
<span>没有可打印的公文文档</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<div slot="footer" class="dialog-footer"> |
|||
<el-button @click="dialogVisible = false">关闭</el-button> |
|||
<el-button |
|||
v-if="pdfSources.length > 0" |
|||
type="primary" |
|||
style="width: auto; padding: 0 6px;" |
|||
@click="printPdf" |
|||
> |
|||
<i class="iconfont icon-dayin" />打印文档 |
|||
</el-button> |
|||
</div> |
|||
</el-dialog> |
|||
</template> |
|||
|
|||
<script> |
|||
import { FetchHandleDocument } from '@/api/system/documentArchives' |
|||
import PdfViewer from './pdfViewer.vue' |
|||
|
|||
export default { |
|||
components: { PdfViewer }, |
|||
data() { |
|||
return { |
|||
dialogVisible: false, |
|||
pdfSources: [], |
|||
loading: false, |
|||
selectedDocumentId: null |
|||
} |
|||
}, |
|||
methods: { |
|||
/** |
|||
* 打开对话框并加载PDF |
|||
*/ |
|||
async openDialog(params) { |
|||
this.dialogVisible = true |
|||
await this.loadPdfData(params) |
|||
}, |
|||
/** |
|||
* 加载PDF数据 |
|||
*/ |
|||
async loadPdfData(params) { |
|||
this.loading = true |
|||
this.pdfSources = [] |
|||
try { |
|||
const res = await FetchHandleDocument(params) |
|||
// 处理Base64格式的响应 |
|||
this.pdfSources = res.map(item => { |
|||
return item.startsWith('data:application/pdf;base64,') |
|||
? item |
|||
: `data:application/pdf;base64,${item}` |
|||
}) |
|||
} catch (error) { |
|||
this.$message.error(`加载文档失败: ${error.message}`) |
|||
console.error('获取PDF失败:', error) |
|||
} finally { |
|||
this.loading = false |
|||
} |
|||
}, |
|||
/** |
|||
* 关闭对话框 |
|||
*/ |
|||
handleClose() { |
|||
this.pdfSources = [] // 清空数据 |
|||
this.dialogVisible = false |
|||
}, |
|||
/** |
|||
* 调用打印功能 |
|||
*/ |
|||
printPdf() { |
|||
this.$refs.pdfViewerRef.handlePrint() |
|||
}, |
|||
/** |
|||
* 打印完成回调(可选) |
|||
*/ |
|||
onPdfPrinted() { |
|||
console.log('PDF打印已触发') |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.global-loading { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
height: 70vh; |
|||
} |
|||
|
|||
.empty-state { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
height: 70vh; |
|||
color: #000; |
|||
} |
|||
.dialog-footer{ |
|||
margin-top: 0 !important; |
|||
} |
|||
</style> |
@ -1,290 +1,174 @@ |
|||
<template> |
|||
<div class="pdf-viewer-container"> |
|||
<!-- 加载状态 --> |
|||
<div v-if="loading" class="loading-overlay"> |
|||
<div class="loading-spinner"> |
|||
<i class="fa fa-spinner fa-spin fa-3x" /> |
|||
<p>{{ loadingMessage }}</p> |
|||
</div> |
|||
<div v-if="loading" class="loading-indicator"> |
|||
<i class="fa fa-spinner fa-spin fa-3x" /> |
|||
<p>正在合并PDF...</p> |
|||
</div> |
|||
|
|||
<!-- 错误提示 --> |
|||
<div v-else-if="error" class="error-message"> |
|||
<i class="fa fa-exclamation-triangle" /> |
|||
<p>{{ error }}</p> |
|||
</div> |
|||
|
|||
<!-- PDF 容器 --> |
|||
<div v-else class="pdf-container"> |
|||
<div class="pdf-controls"> |
|||
<button class="print-button" @click="printPdf"> |
|||
<i class="fa fa-print" /> 打印 PDF |
|||
</button> |
|||
<button class="download-button" @click="downloadPdf"> |
|||
<i class="fa fa-download" /> 下载 PDF |
|||
</button> |
|||
<div class="page-controls"> |
|||
<button :disabled="currentPage <= 1" class="page-button" @click="goToPrevPage"> |
|||
<i class="fa fa-chevron-left" /> |
|||
</button> |
|||
<span class="page-info"> |
|||
第 {{ currentPage }} 页,共 {{ totalPages }} 页 |
|||
</span> |
|||
<button :disabled="currentPage >= totalPages" class="page-button" @click="goToNextPage"> |
|||
<i class="fa fa-chevron-right" /> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<div ref="pdfViewer" class="pdf-viewer" /> |
|||
<div v-else class="pdf-render-area"> |
|||
<iframe |
|||
ref="pdfFrame" |
|||
:src="pdfUrl" |
|||
class="pdf-frame" |
|||
title="合并后的PDF" |
|||
:style="{ width:'100%', height: frameHeight }" |
|||
/> |
|||
<!-- 打印按钮 --> |
|||
<!-- <button v-if="pdfUrl" class="print-btn" @click="handlePrint">打印文档</button> --> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
// import pdfjsLib from 'pdfjs-dist/webpack' |
|||
// import 'pdfjs-dist/web/pdf_viewer.css' |
|||
|
|||
// 中文语言包支持 |
|||
// import { getDocument, GlobalWorkerOptions } from 'pdfjs-dist' |
|||
|
|||
import * as PDFJS from 'pdfdist-mergeofd/build/pdf' |
|||
// import { degrees, PDFDocument, rgb, StandardFonts } from 'pdf-lib' |
|||
// import { TextLayerBuilder, EventBus } from 'pdfdist-mergeofd/web/pdf_viewer' |
|||
import 'pdfdist-mergeofd/web/pdf_viewer.css' |
|||
PDFJS.GlobalWorkerOptions.workerSrc = require('pdfdist-mergeofd/build/pdf.worker.entry.js') |
|||
// import { saveByteArray } from '@/utils/index' |
|||
// import { getInitWatermark } from '@/api/system/waterMask' |
|||
// import { FetchGetFilingsealFormat, FetchGetFilingsealFormatDtails } from '@/api/system/category/category' |
|||
// import fontkit from '@pdf-lib/fontkit' |
|||
|
|||
// 设置 PDF.js worker 路径 |
|||
// GlobalWorkerOptions.workerSrc = '//cdnjs.cloudflare.com/ajax/libs/pdf.js/3.4.120/pdf.worker.min.js' |
|||
import { PDFDocument } from 'pdf-lib' // 引入PDF合并库 |
|||
|
|||
export default { |
|||
name: 'PdfViewer', |
|||
props: { |
|||
// 支持 URL 或 Blob 格式 |
|||
pdfSource: { |
|||
type: [String, Blob], |
|||
pdfSources: { |
|||
type: Array, // 接收二进制流数组 |
|||
required: true |
|||
}, |
|||
// 后端请求配置(当 pdfSource 为 URL 时使用) |
|||
requestOptions: { |
|||
type: Object, |
|||
default: () => ({ |
|||
method: 'GET', |
|||
headers: {} |
|||
}) |
|||
frameHeight: { |
|||
type: String, |
|||
default: '800px' |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
pdfDoc: null, |
|||
currentPage: 1, |
|||
totalPages: 0, |
|||
scale: 1.0, |
|||
pdfUrl: null, |
|||
loading: true, |
|||
loadingMessage: '正在准备 PDF...', |
|||
error: null, |
|||
pdfBlob: null // 存储 PDF Blob 对象 |
|||
error: null |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.loadPdf() |
|||
this.initPdf() |
|||
}, |
|||
beforeDestroy() { |
|||
// 清理临时资源 |
|||
if (this.pdfUrl?.startsWith('blob:')) { |
|||
URL.revokeObjectURL(this.pdfUrl) |
|||
} |
|||
}, |
|||
methods: { |
|||
async loadPdf() { |
|||
try { |
|||
let pdfData |
|||
|
|||
// 处理不同类型的数据源 |
|||
if (typeof this.pdfSource === 'string') { |
|||
// 如果是 URL,发起请求获取数据流 |
|||
this.loadingMessage = '正在下载 PDF...' |
|||
const response = await fetch(this.pdfSource, this.requestOptions) |
|||
|
|||
if (!response.ok) { |
|||
throw new Error(`HTTP错误,状态码:${response.status}`) |
|||
} |
|||
|
|||
pdfData = await response.arrayBuffer() |
|||
this.pdfBlob = new Blob([pdfData], { type: 'application/pdf' }) |
|||
} else if (this.pdfSource instanceof Blob) { |
|||
// 如果是 Blob 直接处理 |
|||
this.loadingMessage = '正在处理 PDF...' |
|||
pdfData = await this.blobToArrayBuffer(this.pdfSource) |
|||
this.pdfBlob = this.pdfSource |
|||
} else { |
|||
throw new Error('不支持的 PDF 数据源类型') |
|||
} |
|||
|
|||
// 加载 PDF 文件 |
|||
const loadingTask = PDFJS.getDocument({ |
|||
data: pdfData, |
|||
cMapUrl: '//cdnjs.cloudflare.com/ajax/libs/pdf.js/3.4.120/cmaps/', |
|||
cMapPacked: true |
|||
}) |
|||
|
|||
// 监听加载进度 |
|||
loadingTask.onProgress = (progressData) => { |
|||
const percent = Math.round((progressData.loaded / progressData.total) * 100) |
|||
this.loadingMessage = `正在加载 PDF: ${percent}%` |
|||
} |
|||
|
|||
// 获取 PDF 文档对象 |
|||
this.pdfDoc = await loadingTask.promise |
|||
this.totalPages = this.pdfDoc.numPages |
|||
|
|||
// 渲染第一页 |
|||
this.renderPage(this.currentPage) |
|||
this.loading = false |
|||
} catch (err) { |
|||
console.error('加载 PDF 失败:', err) |
|||
this.error = `无法加载 PDF 文件: ${err.message}` |
|||
this.loading = false |
|||
/** |
|||
* 将Base64字符串转换为ArrayBuffer |
|||
* @param {string} base64 - Base64编码的字符串 |
|||
* @returns {ArrayBuffer} 二进制数据 |
|||
*/ |
|||
base64ToArrayBuffer(base64) { |
|||
// 移除可能存在的前缀 |
|||
const base64WithoutPrefix = base64.replace(/^data:application\/pdf;base64,/, '') |
|||
|
|||
const binaryString = atob(base64WithoutPrefix) |
|||
const len = binaryString.length |
|||
const bytes = new Uint8Array(len) |
|||
|
|||
for (let i = 0; i < len; i++) { |
|||
bytes[i] = binaryString.charCodeAt(i) |
|||
} |
|||
}, |
|||
|
|||
// Blob 转 ArrayBuffer |
|||
blobToArrayBuffer(blob) { |
|||
return new Promise((resolve, reject) => { |
|||
const reader = new FileReader() |
|||
reader.onload = () => resolve(reader.result) |
|||
reader.onerror = reject |
|||
reader.readAsArrayBuffer(blob) |
|||
}) |
|||
return bytes.buffer |
|||
}, |
|||
|
|||
async renderPage(num) { |
|||
try { |
|||
const page = await this.pdfDoc.getPage(num) |
|||
|
|||
// 获取渲染上下文 |
|||
const viewport = page.getViewport({ scale: this.scale }) |
|||
const canvas = document.createElement('canvas') |
|||
const context = canvas.getContext('2d') |
|||
|
|||
// 设置 canvas 尺寸 |
|||
canvas.height = viewport.height |
|||
canvas.width = viewport.width |
|||
canvas.className = 'pdf-page' |
|||
|
|||
// 清空容器并添加新的 canvas |
|||
const viewer = this.$refs.pdfViewer |
|||
viewer.innerHTML = '' |
|||
viewer.appendChild(canvas) |
|||
|
|||
// 渲染 PDF 页面 |
|||
const renderContext = { |
|||
canvasContext: context, |
|||
viewport: viewport |
|||
} |
|||
|
|||
await page.render(renderContext).promise |
|||
} catch (err) { |
|||
console.error('渲染 PDF 页面失败:', err) |
|||
this.error = '无法渲染 PDF 页面。' |
|||
} |
|||
}, |
|||
|
|||
goToPrevPage() { |
|||
if (this.currentPage > 1) { |
|||
this.currentPage-- |
|||
this.renderPage(this.currentPage) |
|||
} |
|||
/** |
|||
* 验证是否为PDF文件流(保持原有方法不变) |
|||
*/ |
|||
isValidPdfBuffer(buffer) { |
|||
const uint8Array = new Uint8Array(buffer) |
|||
const pdfHeader = new TextDecoder().decode(uint8Array.slice(0, 4)) |
|||
return pdfHeader === '%PDF' |
|||
}, |
|||
|
|||
goToNextPage() { |
|||
if (this.currentPage < this.totalPages) { |
|||
this.currentPage++ |
|||
this.renderPage(this.currentPage) |
|||
} |
|||
}, |
|||
|
|||
async printPdf() { |
|||
// 在组件中使用 |
|||
async initPdf() { |
|||
try { |
|||
// 打印前确保 PDF 已加载 |
|||
if (!this.pdfDoc) return |
|||
|
|||
this.loading = true |
|||
this.loadingMessage = '正在准备打印...' |
|||
|
|||
// 创建临时打印容器 |
|||
const printContainer = document.createElement('div') |
|||
printContainer.className = 'pdf-print-container' |
|||
printContainer.style.display = 'none' |
|||
document.body.appendChild(printContainer) |
|||
|
|||
// 逐页渲染到打印容器 |
|||
for (let i = 1; i <= this.totalPages; i++) { |
|||
const page = await this.pdfDoc.getPage(i) |
|||
const viewport = page.getViewport({ scale: 1.5 }) // 使用较高的缩放比例以获得更好的打印质量 |
|||
|
|||
const canvas = document.createElement('canvas') |
|||
const context = canvas.getContext('2d') |
|||
|
|||
canvas.height = viewport.height |
|||
canvas.width = viewport.width |
|||
canvas.className = 'pdf-print-page' |
|||
canvas.style.pageBreakAfter = 'always' |
|||
if (i === this.totalPages) { |
|||
canvas.style.pageBreakAfter = 'avoid' |
|||
} |
|||
|
|||
printContainer.appendChild(canvas) |
|||
|
|||
const renderContext = { |
|||
canvasContext: context, |
|||
viewport: viewport |
|||
} |
|||
// 将Base64字符串转换为ArrayBuffer |
|||
const binaryStreams = this.pdfSources.map(base64 => { |
|||
return this.base64ToArrayBuffer(base64) |
|||
}) |
|||
|
|||
await page.render(renderContext).promise |
|||
// 验证PDF格式 |
|||
const validStreams = binaryStreams.filter(stream => { |
|||
return this.isValidPdfBuffer(stream) |
|||
}) |
|||
|
|||
// 更新加载进度 |
|||
const percent = Math.round((i / this.totalPages) * 100) |
|||
this.loadingMessage = `正在准备打印: ${percent}%` |
|||
if (validStreams.length === 0) { |
|||
throw new Error('没有有效的PDF文件') |
|||
} |
|||
|
|||
// 保存当前视图 |
|||
const currentScroll = window.scrollY |
|||
|
|||
// 打印 |
|||
window.print() |
|||
|
|||
// 清理 |
|||
setTimeout(() => { |
|||
document.body.removeChild(printContainer) |
|||
this.loading = false |
|||
window.scrollTo(0, currentScroll) |
|||
}, 1000) |
|||
// 合并PDF |
|||
const mergedPdfBlob = await this.mergePdfStreams(validStreams) |
|||
this.pdfUrl = URL.createObjectURL(mergedPdfBlob) |
|||
} catch (err) { |
|||
console.error('打印 PDF 失败:', err) |
|||
this.error = '打印 PDF 时出错。' |
|||
this.error = `PDF加载失败:${err.message}` |
|||
} finally { |
|||
this.loading = false |
|||
} |
|||
}, |
|||
|
|||
downloadPdf() { |
|||
if (!this.pdfBlob) { |
|||
this.error = '无法下载 PDF,数据不可用。' |
|||
return |
|||
/** |
|||
* 合并多个PDF二进制流 |
|||
* @param {Array<ArrayBuffer>} streams - 二进制流数组 |
|||
* @returns {Blob} 合并后的PDF Blob对象 |
|||
*/ |
|||
async mergePdfStreams(streams) { |
|||
const mergedPdf = await PDFDocument.create() |
|||
|
|||
for (const stream of streams) { |
|||
try { |
|||
// 加载单个PDF |
|||
const pdfDoc = await PDFDocument.load(stream) |
|||
|
|||
// 复制所有页面(新版API:使用copyPages返回数组) |
|||
const copiedPages = await mergedPdf.copyPages(pdfDoc, pdfDoc.getPageIndices()) |
|||
|
|||
// 添加到合并文档 |
|||
copiedPages.forEach(page => mergedPdf.addPage(page)) |
|||
} catch (error) { |
|||
console.error('合并PDF失败:', error) |
|||
throw new Error('PDF合并过程中出现错误') |
|||
} |
|||
} |
|||
|
|||
// 创建下载链接 |
|||
const url = URL.createObjectURL(this.pdfBlob) |
|||
const link = document.createElement('a') |
|||
link.href = url |
|||
link.download = 'document.pdf' |
|||
link.click() |
|||
|
|||
// 释放 URL 对象 |
|||
setTimeout(() => URL.revokeObjectURL(url), 100) |
|||
// 生成合并后的PDF |
|||
const pdfBytes = await mergedPdf.save() |
|||
return new Blob([pdfBytes], { type: 'application/pdf' }) |
|||
}, |
|||
/** |
|||
* 触发打印 |
|||
*/ |
|||
handlePrint() { |
|||
this.$refs.pdfFrame.contentWindow.print() // 调用iframe的打印功能 |
|||
this.$emit('pdfPrinted') // 通知父组件打印已触发 |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
/* 样式部分保持不变... */ |
|||
.pdf-viewer-container { |
|||
position: relative; |
|||
width: 100%; |
|||
min-height: 500px; |
|||
} |
|||
|
|||
.pdf-render-area { |
|||
position: relative; |
|||
} |
|||
|
|||
.print-btn { |
|||
position: absolute; |
|||
top: 10px; |
|||
right: 10px; |
|||
padding: 6px 12px; |
|||
background-color: #42b983; |
|||
color: white; |
|||
border: none; |
|||
border-radius: 4px; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
</style> |
@ -1,610 +0,0 @@ |
|||
<template> |
|||
<div class="pdf-overlay-container"> |
|||
<div class="toolbar"> |
|||
<button class="btn" @click="loadPdf"> |
|||
<i class="fa fa-file-pdf-o" /> 加载PDF |
|||
</button> |
|||
<button class="btn" @click="addTextField"> |
|||
<i class="fa fa-font" /> 添加文本 |
|||
</button> |
|||
<button class="btn" @click="saveTemplate"> |
|||
<i class="fa fa-save" /> 保存模板 |
|||
</button> |
|||
<button class="btn" @click="loadTemplate"> |
|||
<i class="fa fa-folder-open-o" /> 加载模板 |
|||
</button> |
|||
<button class="btn" @click="exportPdf"> |
|||
<i class="fa fa-download" /> 导出PDF |
|||
</button> |
|||
<button class="btn" @click="printPdf"> |
|||
<i class="fa fa-print" /> 打印 |
|||
</button> |
|||
<div class="scale-controls"> |
|||
<button class="btn" @click="decreaseScale"> |
|||
<i class="fa fa-search-minus" /> |
|||
</button> |
|||
<span>{{ scale.toFixed(1) }}x</span> |
|||
<button class="btn" @click="increaseScale"> |
|||
<i class="fa fa-search-plus" /> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="pdf-container"> |
|||
<div ref="pdfViewer" class="pdf-viewer"> |
|||
<canvas ref="pdfCanvas" /> |
|||
</div> |
|||
|
|||
<div |
|||
ref="overlayContainer" |
|||
class="overlay-container" |
|||
@mousedown="startDrag" |
|||
@mousemove="onDrag" |
|||
@mouseup="stopDrag" |
|||
@mouseleave="stopDrag" |
|||
> |
|||
<div |
|||
v-for="(field, index) in formFields" |
|||
:key="index" |
|||
:style="getFieldStyle(field)" |
|||
class="form-field" |
|||
@click="selectField(index)" |
|||
@dblclick="editField(index)" |
|||
> |
|||
{{ field.content || '点击编辑' }} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div v-if="selectedFieldIndex !== -1" class="properties-panel"> |
|||
<h3>字段属性</h3> |
|||
<div class="property-row"> |
|||
<label>内容:</label> |
|||
<input v-model="formFields[selectedFieldIndex].content" type="text"> |
|||
</div> |
|||
<div class="property-row"> |
|||
<label>字体大小:</label> |
|||
<input v-model.number="formFields[selectedFieldIndex].fontSize" type="number"> |
|||
</div> |
|||
<div class="property-row"> |
|||
<label>颜色:</label> |
|||
<input v-model="formFields[selectedFieldIndex].color" type="color"> |
|||
</div> |
|||
<div class="property-row"> |
|||
<label>位置:</label> |
|||
<span>X: {{ formFields[selectedFieldIndex].x.toFixed(0) }}</span> |
|||
<span>Y: {{ formFields[selectedFieldIndex].y.toFixed(0) }}</span> |
|||
</div> |
|||
<button class="btn danger" @click="deleteSelectedField"> |
|||
<i class="fa fa-trash" /> 删除字段 |
|||
</button> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
|
|||
import html2canvas from 'html2canvas' |
|||
|
|||
import * as PDFJS from 'pdfdist-mergeofd/build/pdf' |
|||
// import { degrees, PDFDocument, rgb, StandardFonts } from 'pdf-lib' |
|||
// import { TextLayerBuilder, EventBus } from 'pdfdist-mergeofd/web/pdf_viewer' |
|||
import 'pdfdist-mergeofd/web/pdf_viewer.css' |
|||
PDFJS.GlobalWorkerOptions.workerSrc = require('pdfdist-mergeofd/build/pdf.worker.entry.js') |
|||
// import { saveByteArray } from '@/utils/index' |
|||
// import fontkit from '@pdf-lib/fontkit' |
|||
import jsPDF from 'jspdf' |
|||
|
|||
export default { |
|||
name: 'PdfOverlay', |
|||
data() { |
|||
return { |
|||
pdfDoc: null, |
|||
currentPage: 1, |
|||
totalPages: 0, |
|||
scale: 1.0, |
|||
formFields: [], |
|||
draggingFieldIndex: -1, |
|||
lastX: 0, |
|||
lastY: 0, |
|||
selectedFieldIndex: -1, |
|||
templateData: null, |
|||
pdfPath: '', |
|||
isDraggingCanvas: false, |
|||
canvasDragStart: { x: 0, y: 0 }, |
|||
canvasOffset: { x: 0, y: 0 } |
|||
} |
|||
}, |
|||
computed: { |
|||
pdfViewerStyle() { |
|||
return { |
|||
transform: `translate(${this.canvasOffset.x}px, ${this.canvasOffset.y}px) scale(${this.scale})`, |
|||
transformOrigin: '0 0', |
|||
position: 'relative', |
|||
overflow: 'auto' |
|||
} |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.$refs.pdfViewer.addEventListener('wheel', this.zoomOnScroll) |
|||
this.$refs.pdfViewer.addEventListener('mousedown', this.startCanvasDrag) |
|||
window.addEventListener('mousemove', this.onCanvasDrag) |
|||
window.addEventListener('mouseup', this.stopCanvasDrag) |
|||
}, |
|||
beforeDestroy() { |
|||
this.$refs.pdfViewer.removeEventListener('wheel', this.zoomOnScroll) |
|||
this.$refs.pdfViewer.removeEventListener('mousedown', this.startCanvasDrag) |
|||
window.removeEventListener('mousemove', this.onCanvasDrag) |
|||
window.removeEventListener('mouseup', this.stopCanvasDrag) |
|||
}, |
|||
methods: { |
|||
// 修改后的printPdf方法 |
|||
async printPdf() { |
|||
if (!this.pdfDoc) { |
|||
alert('请先加载PDF') |
|||
return |
|||
} |
|||
|
|||
try { |
|||
// 临时显示所有字段以便打印 |
|||
const originalStyles = this.formFields.map(field => ({ |
|||
...field, |
|||
style: { ...field.style } |
|||
})) |
|||
|
|||
// 确保所有字段可见 |
|||
this.formFields.forEach(field => { |
|||
field.style = { |
|||
...field.style, |
|||
display: 'block', |
|||
opacity: 1 |
|||
} |
|||
}) |
|||
|
|||
// 强制更新DOM |
|||
await this.$nextTick() |
|||
|
|||
// 使用html2canvas捕获PDF和覆盖层 |
|||
const pdfContainer = this.$refs.pdfViewer |
|||
const canvas = await html2canvas(pdfContainer, { |
|||
scale: 2, |
|||
useCORS: true, |
|||
logging: false |
|||
}) |
|||
|
|||
// 恢复原始样式 |
|||
this.formFields = originalStyles |
|||
|
|||
// 将canvas转换为Blob |
|||
const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/png')) |
|||
const imgUrl = URL.createObjectURL(blob) |
|||
|
|||
// 创建打印窗口 |
|||
const printWindow = window.open('', '_blank', 'width=1000,height=800') |
|||
const doc = printWindow.document |
|||
|
|||
// 写入基本HTML结构 |
|||
doc.write(`<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<title>打印PDF</title> |
|||
<style> |
|||
@media print { |
|||
body * { visibility: hidden; } |
|||
#print-area, #print-area * { visibility: visible; } |
|||
#print-area { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } |
|||
} |
|||
body { margin: 0; padding: 0; } |
|||
#print-area { display: flex; justify-content: center; align-items: center; padding: 20px; } |
|||
#print-image { max-width: 100%; max-height: 100%; } |
|||
.controls { position: fixed; bottom: 20px; left: 0; width: 100%; text-align: center; } |
|||
button { padding: 10px 20px; margin: 0 10px; } |
|||
</style> |
|||
</head> |
|||
<body> |
|||
<div id="print-area"></div> |
|||
<div class="controls"></div> |
|||
</body> |
|||
</html>`) |
|||
|
|||
// 使用DOM API添加内容 |
|||
const printArea = doc.getElementById('print-area') |
|||
const img = doc.createElement('img') |
|||
img.src = imgUrl |
|||
img.id = 'print-image' |
|||
img.style.maxWidth = '100%' |
|||
img.style.maxHeight = '100%' |
|||
printArea.appendChild(img) |
|||
|
|||
// 添加控制按钮 |
|||
const controls = doc.querySelector('.controls') |
|||
|
|||
const printBtn = doc.createElement('button') |
|||
printBtn.textContent = '打印' |
|||
printBtn.onclick = () => printWindow.print() |
|||
controls.appendChild(printBtn) |
|||
|
|||
const closeBtn = doc.createElement('button') |
|||
closeBtn.textContent = '关闭' |
|||
closeBtn.onclick = () => { |
|||
URL.revokeObjectURL(imgUrl) |
|||
printWindow.close() |
|||
} |
|||
controls.appendChild(closeBtn) |
|||
|
|||
// 窗口关闭时释放对象URL |
|||
printWindow.addEventListener('unload', () => { |
|||
URL.revokeObjectURL(imgUrl) |
|||
}) |
|||
} catch (error) { |
|||
console.error('打印失败:', error) |
|||
alert('打印失败,请重试') |
|||
} |
|||
}, |
|||
async loadPdf() { |
|||
const fileInput = document.createElement('input') |
|||
fileInput.type = 'file' |
|||
fileInput.accept = '.pdf' |
|||
fileInput.onchange = async(e) => { |
|||
const file = e.target.files[0] |
|||
if (!file) return |
|||
|
|||
const fileReader = new FileReader() |
|||
fileReader.onload = async(event) => { |
|||
try { |
|||
const arrayBuffer = event.target.result |
|||
this.pdfDoc = await PDFJS.getDocument(arrayBuffer).promise |
|||
this.totalPages = this.pdfDoc.numPages |
|||
this.currentPage = 1 |
|||
this.pdfPath = URL.createObjectURL(file) |
|||
await this.renderPage() |
|||
} catch (error) { |
|||
console.error('加载PDF失败:', error) |
|||
alert('加载PDF失败,请确保文件格式正确') |
|||
} |
|||
} |
|||
fileReader.readAsArrayBuffer(file) |
|||
} |
|||
fileInput.click() |
|||
}, |
|||
async renderPage() { |
|||
if (!this.pdfDoc) return |
|||
|
|||
const page = await this.pdfDoc.getPage(this.currentPage) |
|||
const viewport = page.getViewport({ scale: 1.0 }) |
|||
|
|||
const canvas = this.$refs.pdfCanvas |
|||
const context = canvas.getContext('2d') |
|||
|
|||
// 设置canvas尺寸 |
|||
canvas.height = viewport.height |
|||
canvas.width = viewport.width |
|||
|
|||
// 渲染PDF页面 |
|||
const renderContext = { |
|||
canvasContext: context, |
|||
viewport: viewport |
|||
} |
|||
|
|||
const renderTask = page.render(renderContext) |
|||
await renderTask.promise |
|||
|
|||
// 调整覆盖层大小 |
|||
const overlayContainer = this.$refs.overlayContainer |
|||
overlayContainer.style.height = `${viewport.height}px` |
|||
overlayContainer.style.width = `${viewport.width}px` |
|||
}, |
|||
addTextField() { |
|||
this.formFields.push({ |
|||
x: 50, |
|||
y: 50, |
|||
width: 150, |
|||
height: 30, |
|||
fontSize: 14, |
|||
content: '输入文本', |
|||
color: '#000000', |
|||
textAlign: 'left' |
|||
}) |
|||
}, |
|||
getFieldStyle(field) { |
|||
return { |
|||
position: 'absolute', |
|||
left: `${field.x}px`, |
|||
top: `${field.y}px`, |
|||
width: `${field.width}px`, |
|||
height: `${field.height}px`, |
|||
fontSize: `${field.fontSize}px`, |
|||
color: field.color, |
|||
border: this.selectedFieldIndex === this.formFields.indexOf(field) ? '1px dashed #3b82f6' : 'none', |
|||
padding: '4px', |
|||
boxSizing: 'border-box', |
|||
overflow: 'hidden', |
|||
whiteSpace: 'nowrap', |
|||
textOverflow: 'ellipsis', |
|||
cursor: 'move', |
|||
textAlign: field.textAlign, |
|||
backgroundColor: 'rgba(255, 255, 255, 0.7)', |
|||
borderRadius: '2px', |
|||
userSelect: 'none' |
|||
} |
|||
}, |
|||
startDrag(e) { |
|||
if (!e.target.classList.contains('form-field')) return |
|||
|
|||
const fieldIndex = this.formFields.findIndex(field => |
|||
e.target.textContent.trim() === (field.content || '点击编辑').trim() |
|||
) |
|||
|
|||
if (fieldIndex === -1) return |
|||
|
|||
this.draggingFieldIndex = fieldIndex |
|||
this.lastX = e.clientX |
|||
this.lastY = e.clientY |
|||
this.selectField(fieldIndex) |
|||
|
|||
e.stopPropagation() |
|||
}, |
|||
onDrag(e) { |
|||
if (this.draggingFieldIndex === -1) return |
|||
|
|||
const dx = e.clientX - this.lastX |
|||
const dy = e.clientY - this.lastY |
|||
|
|||
this.formFields[this.draggingFieldIndex].x += dx |
|||
this.formFields[this.draggingFieldIndex].y += dy |
|||
|
|||
this.lastX = e.clientX |
|||
this.lastY = e.clientY |
|||
}, |
|||
stopDrag() { |
|||
this.draggingFieldIndex = -1 |
|||
}, |
|||
selectField(index) { |
|||
this.selectedFieldIndex = index |
|||
}, |
|||
editField(index) { |
|||
const field = this.formFields[index] |
|||
const content = prompt('编辑文本内容:', field.content || '') |
|||
if (content !== null) { |
|||
this.formFields[index].content = content |
|||
} |
|||
}, |
|||
saveTemplate() { |
|||
const template = { |
|||
formFields: this.formFields, |
|||
currentPage: this.currentPage |
|||
} |
|||
|
|||
const templateJson = JSON.stringify(template) |
|||
const blob = new Blob([templateJson], { type: 'application/json' }) |
|||
const url = URL.createObjectURL(blob) |
|||
|
|||
const a = document.createElement('a') |
|||
a.href = url |
|||
a.download = 'pdf_template.json' |
|||
a.click() |
|||
|
|||
URL.revokeObjectURL(url) |
|||
}, |
|||
loadTemplate() { |
|||
const fileInput = document.createElement('input') |
|||
fileInput.type = 'file' |
|||
fileInput.accept = '.json' |
|||
fileInput.onchange = (e) => { |
|||
const file = e.target.files[0] |
|||
if (!file) return |
|||
|
|||
const reader = new FileReader() |
|||
reader.onload = (event) => { |
|||
try { |
|||
const template = JSON.parse(event.target.result) |
|||
this.formFields = template.formFields || [] |
|||
this.currentPage = template.currentPage || 1 |
|||
this.renderPage() |
|||
} catch (error) { |
|||
console.error('加载模板失败:', error) |
|||
alert('加载模板失败,请确保文件格式正确') |
|||
} |
|||
} |
|||
reader.readAsText(file) |
|||
} |
|||
fileInput.click() |
|||
}, |
|||
async exportPdf() { |
|||
if (!this.pdfDoc) { |
|||
alert('请先加载PDF') |
|||
return |
|||
} |
|||
|
|||
try { |
|||
// 创建一个新的jsPDF实例 |
|||
const Pdf = new jsPDF({ |
|||
orientation: 'portrait', |
|||
unit: 'px', |
|||
format: [this.$refs.pdfCanvas.width, this.$refs.pdfCanvas.height] |
|||
}) |
|||
|
|||
// 将原始PDF转换为图像 |
|||
const pdfImage = await this.convertCanvasToImage(this.$refs.pdfCanvas) |
|||
|
|||
// 添加原始PDF图像 |
|||
Pdf.addImage(pdfImage, 'PNG', 0, 0, this.$refs.pdfCanvas.width, this.$refs.pdfCanvas.height) |
|||
|
|||
// 添加表单字段 |
|||
this.formFields.forEach(field => { |
|||
Pdf.setFontSize(field.fontSize) |
|||
Pdf.setTextColor(field.color) |
|||
|
|||
// 根据文本对齐方式设置位置 |
|||
let x = field.x |
|||
if (field.textAlign === 'center') { |
|||
x += field.width / 2 |
|||
} else if (field.textAlign === 'right') { |
|||
x += field.width |
|||
} |
|||
|
|||
Pdf.text(field.content || '', x, field.y + field.fontSize) |
|||
}) |
|||
|
|||
// 保存PDF |
|||
Pdf.save('document_with_overlay.pdf') |
|||
} catch (error) { |
|||
console.error('导出PDF失败:', error) |
|||
alert('导出PDF失败,请重试') |
|||
} |
|||
}, |
|||
convertCanvasToImage(canvas) { |
|||
return new Promise((resolve) => { |
|||
const image = new Image() |
|||
image.onload = () => resolve(image) |
|||
image.src = canvas.toDataURL('image/png') |
|||
}) |
|||
}, |
|||
increaseScale() { |
|||
this.scale = Math.min(this.scale + 0.1, 3.0) |
|||
}, |
|||
decreaseScale() { |
|||
this.scale = Math.max(this.scale - 0.1, 0.5) |
|||
}, |
|||
zoomOnScroll(e) { |
|||
e.preventDefault() |
|||
|
|||
if (e.ctrlKey) { |
|||
const delta = e.deltaY > 0 ? -0.1 : 0.1 |
|||
this.scale = Math.max(0.5, Math.min(this.scale + delta, 3.0)) |
|||
} |
|||
}, |
|||
startCanvasDrag(e) { |
|||
if (e.target === this.$refs.pdfViewer) { |
|||
this.isDraggingCanvas = true |
|||
this.canvasDragStart.x = e.clientX - this.canvasOffset.x |
|||
this.canvasDragStart.y = e.clientY - this.canvasOffset.y |
|||
e.preventDefault() |
|||
} |
|||
}, |
|||
onCanvasDrag(e) { |
|||
if (this.isDraggingCanvas) { |
|||
this.canvasOffset.x = e.clientX - this.canvasDragStart.x |
|||
this.canvasOffset.y = e.clientY - this.canvasDragStart.y |
|||
} |
|||
}, |
|||
stopCanvasDrag() { |
|||
this.isDraggingCanvas = false |
|||
}, |
|||
deleteSelectedField() { |
|||
if (this.selectedFieldIndex !== -1) { |
|||
this.formFields.splice(this.selectedFieldIndex, 1) |
|||
this.selectedFieldIndex = -1 |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.pdf-overlay-container { |
|||
display: flex; |
|||
flex-direction: column; |
|||
height: 100vh; |
|||
overflow: hidden; |
|||
font-family: Arial, sans-serif; |
|||
} |
|||
|
|||
.toolbar { |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 10px; |
|||
background-color: #f8fafc; |
|||
border-bottom: 1px solid #e2e8f0; |
|||
gap: 10px; |
|||
} |
|||
|
|||
.btn { |
|||
display: inline-flex; |
|||
align-items: center; |
|||
gap: 5px; |
|||
padding: 6px 12px; |
|||
background-color: #3b82f6; |
|||
color: white; |
|||
border: none; |
|||
border-radius: 4px; |
|||
cursor: pointer; |
|||
transition: background-color 0.2s; |
|||
} |
|||
|
|||
.btn:hover { |
|||
background-color: #2563eb; |
|||
} |
|||
|
|||
.btn.danger { |
|||
background-color: #ef4444; |
|||
} |
|||
|
|||
.btn.danger:hover { |
|||
background-color: #dc2626; |
|||
} |
|||
|
|||
.scale-controls { |
|||
display: flex; |
|||
align-items: center; |
|||
margin-left: auto; |
|||
gap: 5px; |
|||
} |
|||
|
|||
.pdf-container { |
|||
flex: 1; |
|||
display: flex; |
|||
position: relative; |
|||
overflow: auto; |
|||
} |
|||
|
|||
.pdf-viewer { |
|||
position: relative; |
|||
margin: 20px auto; |
|||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); |
|||
} |
|||
|
|||
.overlay-container { |
|||
position: absolute; |
|||
top: 0; |
|||
left: 0; |
|||
pointer-events: none; |
|||
} |
|||
|
|||
.form-field { |
|||
pointer-events: all; |
|||
user-select: none; |
|||
transition: border-color 0.2s; |
|||
} |
|||
|
|||
.properties-panel { |
|||
position: absolute; |
|||
right: 10px; |
|||
top: 10px; |
|||
width: 250px; |
|||
background-color: white; |
|||
border: 1px solid #e2e8f0; |
|||
border-radius: 6px; |
|||
padding: 10px; |
|||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); |
|||
z-index: 3; |
|||
} |
|||
|
|||
.property-row { |
|||
display: flex; |
|||
align-items: center; |
|||
margin-bottom: 10px; |
|||
} |
|||
|
|||
.property-row label { |
|||
width: 80px; |
|||
margin-right: 10px; |
|||
} |
|||
|
|||
.property-row input { |
|||
flex: 1; |
|||
padding: 4px; |
|||
border: 1px solid #e2e8f0; |
|||
border-radius: 4px; |
|||
} |
|||
</style> |
@ -1,293 +0,0 @@ |
|||
|
|||
// FormPreview.vue |
|||
<template> |
|||
<div class="app-container"> |
|||
<div v-loading="loading" class="cardWhite" element-loading-text="加载中..."> |
|||
<div class="topArea"> |
|||
<div class="backBox"> |
|||
<!-- <i class="el-icon-back" @click="goBack"></i> --> |
|||
</div> |
|||
|
|||
<el-alert :title="myTitle" type="warning" :closable="false" /> |
|||
</div> |
|||
|
|||
<div class="previewBox"> |
|||
<div v-for="pdf in pdfsArray" :key="pdf.id"> |
|||
<iframe |
|||
ref="myPrint" |
|||
:src="pdf.mypdf" |
|||
class="myPrint" |
|||
width="100%" |
|||
height="1500px" |
|||
/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import axios from 'axios' |
|||
import { getToken } from '@/utils/auth' |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
myTitle: '', |
|||
|
|||
pdfsArray: [], |
|||
allData: [], |
|||
loading: false |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.loading = true |
|||
this.getFile() |
|||
}, |
|||
|
|||
methods: { |
|||
goBack() { |
|||
this.$router.go(-1) |
|||
}, |
|||
|
|||
// 重置标题 |
|||
resetTitle() { |
|||
const arr = this.allData.map(k => { |
|||
return k.formName |
|||
}) |
|||
|
|||
const newArr = this.getArrCountInfo(arr) |
|||
// console.log("统计", arr, newArr); |
|||
let str = '' |
|||
for (var i of newArr) { |
|||
str = str + '《' + i.formName + '》' + i.count + '份;' |
|||
} |
|||
|
|||
if (str.charAt(str.length - 1) === ';') { |
|||
str = str.slice(0, str.length - 1) |
|||
} |
|||
|
|||
this.myTitle = '您当前预览的表单是' + str |
|||
}, |
|||
|
|||
// 数组元素去重 |
|||
uniqueArr(arr) { |
|||
var x = new Set(arr) |
|||
return [...x] |
|||
}, |
|||
|
|||
// 获取重复元素个数,输出info1 |
|||
getWordCnt(arr) { |
|||
return arr.reduce(function(prev, next) { |
|||
prev[next] = prev[next] + 1 || 1 |
|||
return prev |
|||
}, {}) |
|||
}, |
|||
|
|||
// 获取重复元素个数,输出info2 |
|||
getArrCountInfo(arr) { |
|||
var info2 = [] |
|||
const that = this |
|||
that.uniqueArr(arr).forEach(function(item) { |
|||
var countInfo = {} |
|||
countInfo.formName = item |
|||
|
|||
countInfo.count = that.getWordCnt(arr)[item] |
|||
info2.push(countInfo) |
|||
}) |
|||
return info2 |
|||
}, |
|||
|
|||
// 获取文件流 |
|||
async getFile() { |
|||
const arr = JSON.parse(sessionStorage.getItem('FormPreviewArray')) |
|||
|
|||
const pdfArr = [] |
|||
|
|||
for (var i = 0; i < arr.length; i++) { |
|||
const item = arr[i] |
|||
|
|||
axios({ |
|||
url: |
|||
`${window.g.API_URL}/resourceManage/export/v4/dlform/pdf/` + |
|||
item.id, |
|||
method: 'get', |
|||
params: { |
|||
// fileUrl: this.$route.query.fileUrl |
|||
}, |
|||
headers: { |
|||
Authorization: getToken() |
|||
}, |
|||
responseType: 'arraybuffer' |
|||
}) |
|||
.then(res => { |
|||
// console.log("文件流获取成功", res); |
|||
|
|||
pdfArr.push({ |
|||
formName: item.formName, |
|||
pdf: res.data |
|||
}) |
|||
}) |
|||
.catch(err => { |
|||
console.log('文件流获取失败', err) |
|||
this.$message.error('获取文件信息失败,请稍后重试', 6000) |
|||
}) |
|||
.finally(() => { |
|||
// console.log("asd", i, arr.length); |
|||
if (i === arr.length) { |
|||
// console.log("文件流集合", pdfArr); |
|||
|
|||
this.pdfPreview(pdfArr) |
|||
} |
|||
}) |
|||
|
|||
// }); |
|||
} |
|||
}, |
|||
|
|||
pdfPreview(binaryData) { |
|||
// data是一个ArrayBuffer格式,也是一个buffer流的数据 |
|||
// console.log("pdf流", binaryData); |
|||
const newArr = [] |
|||
|
|||
// 获取blob链接 |
|||
|
|||
for (var i = 0; i < binaryData.length; i++) { |
|||
const k = binaryData[i] |
|||
|
|||
const pdfUrl = window.URL.createObjectURL( |
|||
new Blob([k.pdf], { type: 'application/pdf' }) |
|||
) |
|||
// console.log("pdfUrl", pdfUrl); |
|||
|
|||
newArr.push({ |
|||
formName: k.formName, |
|||
mypdf: pdfUrl |
|||
}) |
|||
|
|||
if (i === binaryData.length - 1) { |
|||
// console.log("newArr---", newArr); |
|||
setTimeout(() => { |
|||
this.resetTitle() |
|||
}, 10) |
|||
this.pdfsArray = newArr |
|||
|
|||
this.allData = newArr |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.app-container { |
|||
height: 100%; |
|||
|
|||
margin-top: -16px; |
|||
position: relative; |
|||
overflow-y: hidden; |
|||
z-index: 99999 !important; |
|||
|
|||
.cardWhite { |
|||
display: flex; |
|||
flex-direction: column; |
|||
|
|||
// background: gray; |
|||
|
|||
.topArea { |
|||
display: flex; |
|||
position: relative; |
|||
margin-bottom: 20px; |
|||
// border: 1px solid red; |
|||
|
|||
width: 80%; |
|||
height: 40px; |
|||
z-index: 99999 !important; |
|||
// background: gray; |
|||
|
|||
position: fixed; |
|||
top: 4rem; |
|||
left: 15.625rem; |
|||
|
|||
.backBox { |
|||
margin-right: 4.5rem; |
|||
position: relative; |
|||
i { |
|||
cursor: pointer; |
|||
font-size: 20px; |
|||
color: #fff; |
|||
|
|||
position: absolute; |
|||
left: 20px; |
|||
top: 10px; |
|||
} |
|||
} |
|||
|
|||
.el-button { |
|||
margin-right: 1rem; |
|||
} |
|||
|
|||
.titleBox { |
|||
text-align: center; |
|||
background: #fff; |
|||
color: #000000; |
|||
position: absolute; |
|||
top: 0; |
|||
left: 50%; |
|||
width: auto; |
|||
} |
|||
} |
|||
|
|||
.previewBox { |
|||
// border: 1px solid blue; |
|||
|
|||
max-height: 1000px; |
|||
|
|||
overflow-y: auto; |
|||
|
|||
padding-top: 38px; |
|||
|
|||
::v-deep div { |
|||
margin-bottom: 20px; |
|||
.myPrint { |
|||
.vue-office-pdf-wrapper { |
|||
// font-size: 14px !important; |
|||
canvas { |
|||
// height: 100% !important; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
//打印样式 |
|||
@media print { |
|||
body { |
|||
//设置一下边框,可以显示内容的范围,用于测试 |
|||
|
|||
//添加height:auto;才能打印多页,否则只能打印一页 |
|||
height: auto; |
|||
|
|||
// border: 1px solid red; |
|||
margin: 0; |
|||
} |
|||
|
|||
header, |
|||
footer { |
|||
//隐藏页眉页脚,不然会多打印出首尾两页 |
|||
display: none; |
|||
} |
|||
|
|||
@page { |
|||
// overflow: visible; |
|||
// /* 纵向 */ |
|||
// size: portrait; |
|||
size: auto; |
|||
margin: 0mm 10mm; |
|||
} |
|||
} |
|||
</style> |
|||
|
@ -1,146 +0,0 @@ |
|||
<template> |
|||
<div class="main"> |
|||
<div style="padding: 20px"> |
|||
<a-form layout="inline" style="color: black; margin-bottom: 22px"> |
|||
<a-row :gutter="48"> |
|||
<a-col> |
|||
<a-form-item label="运单号" style="margin-right: 30px"> |
|||
<a-input v-model="queryParam.waybillNo" placeholder="请输入运单号" allow-clear size="large" /> |
|||
</a-form-item> |
|||
<sava-button class="button" @click="doSearch">查询</sava-button> |
|||
</a-col> |
|||
</a-row> |
|||
</a-form> |
|||
<a-table |
|||
ref="table" |
|||
:columns="columns" |
|||
:data-source="loadData" |
|||
:loading="loading" |
|||
:row-key="(record) => record.id" |
|||
:pagination="pagination" |
|||
style="margin-top: 10px" |
|||
@change="handleTableChange" |
|||
> |
|||
<span slot="action" slot-scope="text, record"> |
|||
<!-- <a @click="handleEdit(record)" style="color: #2b79c2">编辑</a> --> |
|||
<a style="color: #2b79c2; margin-left: 10px" @click="viewDetail(record)">查看</a> |
|||
<a style="color: #2b79c2; margin-left: 10px" @click="printBill(record)">打印</a> |
|||
</span> |
|||
</a-table> |
|||
|
|||
<a-modal :visible="previewVisibleForAll" :footer="null" :width="800" @cancel="handleCancelAll"> |
|||
<div style="overflow-y: auto; overflow-x: hidden"> |
|||
<a-button shape="round" icon="file-pdf" size="small" @click="handlePrint(printData)">打印</a-button> |
|||
<div id="printFrom"> |
|||
<pdf ref="pdf" :src="previewFileSrc" /> |
|||
</div> |
|||
</div> |
|||
</a-modal> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
// 两个库引入 |
|||
import pdf from 'vue-pdf' |
|||
import printJS from 'print-js' |
|||
// 接口 |
|||
// import { reqWayBillList, reqBillReport } from '@/api/DigitalWayBill/DigitalWayBill' |
|||
|
|||
export default { |
|||
components: { |
|||
pdf |
|||
}, |
|||
data() { |
|||
return { |
|||
queryParam: { |
|||
waybillNo: '' |
|||
}, |
|||
columns: [ |
|||
], |
|||
loadData: [], |
|||
loading: false, |
|||
pagination: {}, |
|||
mdl: null, |
|||
enterpriseInfo: [], |
|||
inspectorInfo: [], |
|||
fenceParam: {}, |
|||
pdfUrl: '', // 你的 PDF 文件 URL |
|||
progress: 0, |
|||
printData: { |
|||
printable: 'printFrom', |
|||
header: '', |
|||
ignore: ['no-print'] |
|||
}, |
|||
previewVisibleForAll: false, |
|||
pageTotal: null, |
|||
previewFileSrc: '' |
|||
} |
|||
}, |
|||
created() { |
|||
this.doSearch() |
|||
}, |
|||
|
|||
methods: { |
|||
doSearch() { |
|||
this.loading = true |
|||
reqWayBillList(this.queryParam).then((res) => { |
|||
console.log('way bill list', res) |
|||
this.loadData = res.records |
|||
this.loading = false |
|||
}) |
|||
}, |
|||
handleTableChange(pagination) { |
|||
const pager = { ...this.pagination1 } |
|||
pager.current = pagination.current |
|||
this.pagination1 = pager |
|||
this.queryParam1.pageIndex = pagination.current |
|||
this.doSearch() |
|||
}, |
|||
|
|||
viewDetail(record) { |
|||
console.log('click view') |
|||
this.mdl = { ...record } |
|||
// 将获取的信息传递到新页面 |
|||
this.$router.push({ |
|||
path: '/bill/detail', |
|||
query: { |
|||
data: JSON.stringify(this.mdl) |
|||
} |
|||
}) |
|||
}, |
|||
printBill(record) { |
|||
this.$message.success('生成文档需要一些时间, 请稍候...', 10) |
|||
reqBillReport(record.waybillNo) |
|||
.then((res) => { |
|||
console.log('pdf url', res) |
|||
this.previewFileSrc = res |
|||
this.previewVisibleForAll = true |
|||
}) |
|||
.catch((err) => { |
|||
this.$message.error(`获取文档失败: ${err}`) |
|||
}) |
|||
}, |
|||
handlePrint(params) { |
|||
printJS({ |
|||
printable: params.printable, // 'printFrom', // 标签元素id |
|||
type: params.type || 'html', |
|||
header: params.header, // '表单', |
|||
targetStyles: ['*'], |
|||
style: '@page {margin:0 10mm};', // 可选-打印时去掉眉页眉尾 |
|||
ignoreElements: params.ignore || [], // ['no-print'] |
|||
properties: params.properties || null |
|||
}) |
|||
}, |
|||
printPdf() { |
|||
this.$refs.pdf.print() |
|||
// window.print() |
|||
}, |
|||
handleCancel() { |
|||
this.previewVisible = false |
|||
}, |
|||
handleCancelAll() { |
|||
this.previewVisibleForAll = false |
|||
} |
|||
} |
|||
} |
|||
</script> |
@ -1,642 +0,0 @@ |
|||
[ |
|||
{ |
|||
"createBy": "admin", |
|||
"updateBy": null, |
|||
"createTime": 1698300921000, |
|||
"updateTime": 1740364841000, |
|||
"id": "7DB71E6ADE901F69A7C5EB", |
|||
"categoryId": "AE8B188F0C0314F9BE31B8", |
|||
"mateData": 1, |
|||
"dictionaryId": null, |
|||
"fieldName": "fonds_no", |
|||
"fieldCnName": "编号", |
|||
"isDefaultValue": "", |
|||
"isInputClass": "select", |
|||
"isDataType": 1, |
|||
"isDataTypeDetails": "varchar", |
|||
"isColumnLength": 10, |
|||
"isColumnType": 2, |
|||
"isSequence": 1, |
|||
"isType": 2, |
|||
"isSystem": true, |
|||
"isLine": false, |
|||
"isInput": true, |
|||
"isRequired": false, |
|||
"isAutomatic": false, |
|||
"isAdd": null, |
|||
"isSearch": null, |
|||
"isInherit": null, |
|||
"isFilling": false, |
|||
"fillingDigit": null, |
|||
"isRepeat": null, |
|||
"isDisplay": true, |
|||
"displayOrder": 11, |
|||
"displayOrderBy": null, |
|||
"isDisplayformat": true, |
|||
"displayformatType": "center", |
|||
"editLength": 196, |
|||
"displayLength": 100, |
|||
"queue": null |
|||
}, |
|||
{ |
|||
"createBy": "admin", |
|||
"updateBy": null, |
|||
"createTime": 1699953035000, |
|||
"updateTime": 1705557128000, |
|||
"id": "BA2120965DB8DB63163771", |
|||
"categoryId": "AE8B188F0C0314F9BE31B8", |
|||
"mateData": null, |
|||
"dictionaryId": null, |
|||
"fieldName": "archival_category_code", |
|||
"fieldCnName": "题名", |
|||
"isDefaultValue": null, |
|||
"isInputClass": "text", |
|||
"isDataType": 1, |
|||
"isDataTypeDetails": "varchar", |
|||
"isColumnLength": 50, |
|||
"isColumnType": 1, |
|||
"isSequence": 2, |
|||
"isType": 2, |
|||
"isSystem": false, |
|||
"isLine": false, |
|||
"isInput": true, |
|||
"isRequired": false, |
|||
"isAutomatic": false, |
|||
"isAdd": null, |
|||
"isSearch": null, |
|||
"isInherit": null, |
|||
"isFilling": false, |
|||
"fillingDigit": null, |
|||
"isRepeat": null, |
|||
"isDisplay": false, |
|||
"displayOrder": 2, |
|||
"displayOrderBy": null, |
|||
"isDisplayformat": true, |
|||
"displayformatType": null, |
|||
"editLength": 196, |
|||
"displayLength": null, |
|||
"queue": null |
|||
}, |
|||
{ |
|||
"createBy": "admin", |
|||
"updateBy": null, |
|||
"createTime": 1698300921000, |
|||
"updateTime": 1740365090000, |
|||
"id": "A792C6C4D2186B345F35BA", |
|||
"categoryId": "AE8B188F0C0314F9BE31B8", |
|||
"mateData": 2, |
|||
"dictionaryId": null, |
|||
"fieldName": "archive_ctg_no", |
|||
"fieldCnName": "分类号", |
|||
"isDefaultValue": "", |
|||
"isInputClass": "popover", |
|||
"isDataType": 1, |
|||
"isDataTypeDetails": "varchar", |
|||
"isColumnLength": 20, |
|||
"isColumnType": 2, |
|||
"isSequence": 3, |
|||
"isType": 2, |
|||
"isSystem": true, |
|||
"isLine": false, |
|||
"isInput": true, |
|||
"isRequired": true, |
|||
"isAutomatic": false, |
|||
"isAdd": null, |
|||
"isSearch": null, |
|||
"isInherit": null, |
|||
"isFilling": false, |
|||
"fillingDigit": null, |
|||
"isRepeat": null, |
|||
"isDisplay": true, |
|||
"displayOrder": 1, |
|||
"displayOrderBy": "asc", |
|||
"isDisplayformat": true, |
|||
"displayformatType": "left", |
|||
"editLength": 196, |
|||
"displayLength": 120, |
|||
"queue": 1 |
|||
}, |
|||
{ |
|||
"createBy": "admin", |
|||
"updateBy": null, |
|||
"createTime": 1698300921000, |
|||
"updateTime": 1740365090000, |
|||
"id": "866CDF65ACE37BF12DF28B", |
|||
"categoryId": "AE8B188F0C0314F9BE31B8", |
|||
"mateData": 3, |
|||
"fieldName": "retention", |
|||
"fieldCnName": "来文单位", |
|||
"isDefaultValue": "", |
|||
"isInputClass": "text", |
|||
"isDataType": 1, |
|||
"isDataTypeDetails": "varchar", |
|||
"isColumnLength": 10, |
|||
"isColumnType": 2, |
|||
"isSequence": 5, |
|||
"isType": 2, |
|||
"isSystem": true, |
|||
"isLine": false, |
|||
"isInput": true, |
|||
"isRequired": false, |
|||
"isAutomatic": false, |
|||
"isAdd": null, |
|||
"isSearch": null, |
|||
"isInherit": null, |
|||
"isFilling": false, |
|||
"fillingDigit": null, |
|||
"isRepeat": null, |
|||
"isDisplay": true, |
|||
"displayOrder": 4, |
|||
"displayOrderBy": "asc", |
|||
"isDisplayformat": true, |
|||
"displayformatType": "center", |
|||
"editLength": 196, |
|||
"displayLength": 100, |
|||
"queue": 3 |
|||
}, |
|||
{ |
|||
"createBy": "admin", |
|||
"updateBy": null, |
|||
"createTime": 1698300921000, |
|||
"updateTime": 1699944406000, |
|||
"id": "2F8806C4DE32D68A371F2B", |
|||
"categoryId": "AE8B188F0C0314F9BE31B8", |
|||
"mateData": null, |
|||
"dictionaryId": null, |
|||
"fieldName": "created_date", |
|||
"fieldCnName": "来文日期", |
|||
"isDefaultValue": "", |
|||
"isInputClass": "date", |
|||
"isDataType": 1, |
|||
"isDataTypeDetails": "varchar", |
|||
"isColumnLength": 20, |
|||
"isColumnType": 2, |
|||
"isSequence": 17, |
|||
"isType": 2, |
|||
"isSystem": true, |
|||
"isLine": false, |
|||
"isInput": true, |
|||
"isRequired": false, |
|||
"isAutomatic": false, |
|||
"isAdd": null, |
|||
"isSearch": null, |
|||
"isInherit": null, |
|||
"isFilling": false, |
|||
"fillingDigit": null, |
|||
"isRepeat": null, |
|||
"isDisplay": null, |
|||
"displayOrder": null, |
|||
"displayOrderBy": null, |
|||
"isDisplayformat": null, |
|||
"displayformatType": null, |
|||
"editLength": 196, |
|||
"displayLength": null, |
|||
"queue": null |
|||
}, |
|||
{ |
|||
"createBy": "admin", |
|||
"updateBy": null, |
|||
"createTime": 1698300921000, |
|||
"updateTime": 1740365090000, |
|||
"id": "2CFFB4C17E2EC5F8E2FC78", |
|||
"categoryId": "AE8B188F0C0314F9BE31B8", |
|||
"mateData": null, |
|||
"dictionaryId": null, |
|||
"fieldName": "archive_year", |
|||
"fieldCnName": "年度", |
|||
"isDefaultValue": "", |
|||
"isInputClass": "text", |
|||
"isDataType": 1, |
|||
"isDataTypeDetails": "varchar", |
|||
"isColumnLength": 4, |
|||
"isColumnType": 2, |
|||
"isSequence": 4, |
|||
"isType": 2, |
|||
"isSystem": true, |
|||
"isLine": null, |
|||
"isInput": true, |
|||
"isRequired": null, |
|||
"isAutomatic": null, |
|||
"isAdd": null, |
|||
"isSearch": null, |
|||
"isInherit": null, |
|||
"isFilling": null, |
|||
"fillingDigit": null, |
|||
"isRepeat": null, |
|||
"isDisplay": true, |
|||
"displayOrder": 2, |
|||
"displayOrderBy": "desc", |
|||
"isDisplayformat": true, |
|||
"displayformatType": "center", |
|||
"editLength": 196, |
|||
"displayLength": 60, |
|||
"queue": 2 |
|||
}, |
|||
|
|||
{ |
|||
"createBy": "admin", |
|||
"updateBy": null, |
|||
"createTime": 1698300921000, |
|||
"updateTime": 1742953368000, |
|||
"id": "FED70276CCCDFAA4E8EC9F", |
|||
"categoryId": "AE8B188F0C0314F9BE31B8", |
|||
"mateData": null, |
|||
"dictionaryId": null, |
|||
"fieldName": "item_no", |
|||
"fieldCnName": "份数", |
|||
"isDefaultValue": "", |
|||
"isInputClass": "number", |
|||
"isDataType": 1, |
|||
"isDataTypeDetails": "varchar", |
|||
"isColumnLength": 10, |
|||
"isColumnType": 2, |
|||
"isSequence": 6, |
|||
"isType": 2, |
|||
"isSystem": true, |
|||
"isLine": false, |
|||
"isInput": true, |
|||
"isRequired": false, |
|||
"isAutomatic": false, |
|||
"isAdd": null, |
|||
"isSearch": null, |
|||
"isInherit": null, |
|||
"isFilling": true, |
|||
"fillingDigit": 4, |
|||
"isRepeat": null, |
|||
"isDisplay": true, |
|||
"displayOrder": 4, |
|||
"displayOrderBy": "asc", |
|||
"isDisplayformat": true, |
|||
"displayformatType": "center", |
|||
"editLength": 196, |
|||
"displayLength": 60, |
|||
"queue": 4 |
|||
}, |
|||
{ |
|||
"createBy": "admin", |
|||
"updateBy": null, |
|||
"createTime": 1698300921000, |
|||
"updateTime": 1740364841000, |
|||
"id": "AAFB0EDA47F922D31CFB56", |
|||
"categoryId": "AE8B188F0C0314F9BE31B8", |
|||
"mateData": null, |
|||
"dictionaryId": null, |
|||
"fieldName": "archive_no", |
|||
"fieldCnName": "文号", |
|||
"isDefaultValue": "", |
|||
"isInputClass": "text", |
|||
"isDataType": 1, |
|||
"isDataTypeDetails": "varchar", |
|||
"isColumnLength": 100, |
|||
"isColumnType": 2, |
|||
"isSequence": 7, |
|||
"isType": 2, |
|||
"isSystem": true, |
|||
"isLine": false, |
|||
"isInput": true, |
|||
"isRequired": false, |
|||
"isAutomatic": true, |
|||
"isAdd": null, |
|||
"isSearch": null, |
|||
"isInherit": null, |
|||
"isFilling": false, |
|||
"fillingDigit": null, |
|||
"isRepeat": null, |
|||
"isDisplay": true, |
|||
"displayOrder": 5, |
|||
"displayOrderBy": null, |
|||
"isDisplayformat": null, |
|||
"displayformatType": "left", |
|||
"editLength": 196, |
|||
"displayLength": 60, |
|||
"queue": null |
|||
}, |
|||
{ |
|||
"createBy": "admin", |
|||
"updateBy": null, |
|||
"createTime": 1698300921000, |
|||
"updateTime": 1740364841000, |
|||
"id": "14BE0DD4DE48878716567A", |
|||
"categoryId": "AE8B188F0C0314F9BE31B8", |
|||
"mateData": 3, |
|||
"dictionaryId": { |
|||
"id": "4028e3c389cee5920189cf0af3d30000", |
|||
"dictionaryName": "密级", |
|||
"dictionaryCode": "security_class", |
|||
"dictionaryParents": null, |
|||
"dictionaryOrder": 1, |
|||
"dictionaryRemarks": "", |
|||
"childDictionarys": null |
|||
}, |
|||
"fieldName": "security_class", |
|||
"fieldCnName": "密级", |
|||
"isDefaultValue": "", |
|||
"isInputClass": "select", |
|||
"isDataType": 1, |
|||
"isDataTypeDetails": "varchar", |
|||
"isColumnLength": 10, |
|||
"isColumnType": 2, |
|||
"isSequence": 12, |
|||
"isType": 2, |
|||
"isSystem": true, |
|||
"isLine": false, |
|||
"isInput": true, |
|||
"isRequired": false, |
|||
"isAutomatic": false, |
|||
"isAdd": null, |
|||
"isSearch": null, |
|||
"isInherit": null, |
|||
"isFilling": false, |
|||
"fillingDigit": null, |
|||
"isRepeat": null, |
|||
"isDisplay": true, |
|||
"displayOrder": 12, |
|||
"displayOrderBy": null, |
|||
"isDisplayformat": false, |
|||
"displayformatType": "center", |
|||
"editLength": 196, |
|||
"displayLength": 100, |
|||
"queue": null |
|||
}, |
|||
{ |
|||
"createBy": "admin", |
|||
"updateBy": null, |
|||
"createTime": 1698300921000, |
|||
"updateTime": 1740364841000, |
|||
"id": "843B66EAD9578E10348EA0", |
|||
"categoryId": "AE8B188F0C0314F9BE31B8", |
|||
"mateData": 3, |
|||
"dictionaryId": { |
|||
"id": "4028e3c38b419d81018b41a1c35d0000", |
|||
"dictionaryName": "紧急程度", |
|||
"dictionaryCode": "emergency_degree", |
|||
"dictionaryParents": null, |
|||
"dictionaryOrder": 5, |
|||
"dictionaryRemarks": null, |
|||
"childDictionarys": null |
|||
}, |
|||
"fieldName": "emergency_degree", |
|||
"fieldCnName": "紧急程度", |
|||
"isDefaultValue": "", |
|||
"isInputClass": "select", |
|||
"isDataType": 1, |
|||
"isDataTypeDetails": "varchar", |
|||
"isColumnLength": 10, |
|||
"isColumnType": 2, |
|||
"isSequence": 16, |
|||
"isType": 2, |
|||
"isSystem": true, |
|||
"isLine": false, |
|||
"isInput": true, |
|||
"isRequired": false, |
|||
"isAutomatic": false, |
|||
"isAdd": null, |
|||
"isSearch": null, |
|||
"isInherit": null, |
|||
"isFilling": false, |
|||
"fillingDigit": null, |
|||
"isRepeat": null, |
|||
"isDisplay": true, |
|||
"displayOrder": 8, |
|||
"displayOrderBy": null, |
|||
"isDisplayformat": null, |
|||
"displayformatType": "center", |
|||
"editLength": 196, |
|||
"displayLength": 100, |
|||
"queue": null |
|||
}, |
|||
{ |
|||
"createBy": "admin", |
|||
"updateBy": null, |
|||
"createTime": 1698300921000, |
|||
"updateTime": 1699944406000, |
|||
"id": "72F1F8FAD8DA348E096A11", |
|||
"categoryId": "AE8B188F0C0314F9BE31B8", |
|||
"mateData": null, |
|||
"dictionaryId": null, |
|||
"fieldName": "main_department", |
|||
"fieldCnName": "需传阅领导", |
|||
"isDefaultValue": "", |
|||
"isInputClass": "text", |
|||
"isDataType": 1, |
|||
"isDataTypeDetails": "varchar", |
|||
"isColumnLength": 100, |
|||
"isColumnType": 2, |
|||
"isSequence": 20, |
|||
"isType": 2, |
|||
"isSystem": true, |
|||
"isLine": null, |
|||
"isInput": true, |
|||
"isRequired": null, |
|||
"isAutomatic": null, |
|||
"isAdd": null, |
|||
"isSearch": null, |
|||
"isInherit": null, |
|||
"isFilling": null, |
|||
"fillingDigit": null, |
|||
"isRepeat": null, |
|||
"isDisplay": null, |
|||
"displayOrder": null, |
|||
"displayOrderBy": null, |
|||
"isDisplayformat": null, |
|||
"displayformatType": null, |
|||
"editLength": 196, |
|||
"displayLength": null, |
|||
"queue": null |
|||
}, |
|||
{ |
|||
"createBy": "admin", |
|||
"updateBy": null, |
|||
"createTime": 1698300921000, |
|||
"updateTime": 1699944406000, |
|||
"id": "F607C97A8B6E6C2C5CCA7A", |
|||
"categoryId": "AE8B188F0C0314F9BE31B8", |
|||
"mateData": null, |
|||
"dictionaryId": null, |
|||
"fieldName": "copy_department", |
|||
"fieldCnName": "需传阅部门", |
|||
"isDefaultValue": "", |
|||
"isInputClass": "text", |
|||
"isDataType": 1, |
|||
"isDataTypeDetails": "varchar", |
|||
"isColumnLength": 100, |
|||
"isColumnType": 2, |
|||
"isSequence": 21, |
|||
"isType": 2, |
|||
"isSystem": true, |
|||
"isLine": null, |
|||
"isInput": true, |
|||
"isRequired": null, |
|||
"isAutomatic": null, |
|||
"isAdd": null, |
|||
"isSearch": null, |
|||
"isInherit": null, |
|||
"isFilling": null, |
|||
"fillingDigit": null, |
|||
"isRepeat": null, |
|||
"isDisplay": null, |
|||
"displayOrder": null, |
|||
"displayOrderBy": null, |
|||
"isDisplayformat": null, |
|||
"displayformatType": null, |
|||
"editLength": 196, |
|||
"displayLength": null, |
|||
"queue": null |
|||
}, |
|||
{ |
|||
"createBy": "admin", |
|||
"updateBy": null, |
|||
"createTime": 1698300921000, |
|||
"updateTime": 1699944406000, |
|||
"id": "5A4BF9C96B09A26D60B581", |
|||
"categoryId": "AE8B188F0C0314F9BE31B8", |
|||
"mateData": null, |
|||
"dictionaryId": null, |
|||
"fieldName": "printing_department", |
|||
"fieldCnName": "传阅所在位置", |
|||
"isDefaultValue": "", |
|||
"isInputClass": "text", |
|||
"isDataType": 1, |
|||
"isDataTypeDetails": "varchar", |
|||
"isColumnLength": 100, |
|||
"isColumnType": 2, |
|||
"isSequence": 22, |
|||
"isType": 2, |
|||
"isSystem": true, |
|||
"isLine": null, |
|||
"isInput": true, |
|||
"isRequired": null, |
|||
"isAutomatic": null, |
|||
"isAdd": null, |
|||
"isSearch": null, |
|||
"isInherit": null, |
|||
"isFilling": null, |
|||
"fillingDigit": null, |
|||
"isRepeat": null, |
|||
"isDisplay": null, |
|||
"displayOrder": null, |
|||
"displayOrderBy": null, |
|||
"isDisplayformat": null, |
|||
"displayformatType": null, |
|||
"editLength": 196, |
|||
"displayLength": null, |
|||
"queue": null |
|||
}, |
|||
{ |
|||
"createBy": "admin", |
|||
"updateBy": null, |
|||
"createTime": 1698300921000, |
|||
"updateTime": 1699945287000, |
|||
"id": "D6440B7306E547759C3B69", |
|||
"categoryId": "AE8B188F0C0314F9BE31B8", |
|||
"mateData": null, |
|||
"dictionaryId": null, |
|||
"fieldName": "microfilm", |
|||
"fieldCnName": "原文号", |
|||
"isDefaultValue": "", |
|||
"isInputClass": "text", |
|||
"isDataType": 1, |
|||
"isDataTypeDetails": "varchar", |
|||
"isColumnLength": 20, |
|||
"isColumnType": 2, |
|||
"isSequence": 25, |
|||
"isType": 2, |
|||
"isSystem": true, |
|||
"isLine": null, |
|||
"isInput": true, |
|||
"isRequired": null, |
|||
"isAutomatic": null, |
|||
"isAdd": null, |
|||
"isSearch": null, |
|||
"isInherit": null, |
|||
"isFilling": null, |
|||
"fillingDigit": null, |
|||
"isRepeat": null, |
|||
"isDisplay": null, |
|||
"displayOrder": null, |
|||
"displayOrderBy": null, |
|||
"isDisplayformat": null, |
|||
"displayformatType": null, |
|||
"editLength": 196, |
|||
"displayLength": null, |
|||
"queue": null |
|||
}, |
|||
{ |
|||
"createBy": "admin", |
|||
"updateBy": null, |
|||
"createTime": 1698300921000, |
|||
"updateTime": 1699945287000, |
|||
"id": "2DFF954EE08C8B2DEA2777", |
|||
"categoryId": "AE8B188F0C0314F9BE31B8", |
|||
"mateData": null, |
|||
"dictionaryId": null, |
|||
"fieldName": "annotation", |
|||
"fieldCnName": "备注", |
|||
"isDefaultValue": "", |
|||
"isInputClass": "textarea", |
|||
"isDataType": 1, |
|||
"isDataTypeDetails": "varchar", |
|||
"isColumnLength": 1000, |
|||
"isColumnType": 2, |
|||
"isSequence": 27, |
|||
"isType": 2, |
|||
"isSystem": true, |
|||
"isLine": true, |
|||
"isInput": true, |
|||
"isRequired": false, |
|||
"isAutomatic": false, |
|||
"isAdd": null, |
|||
"isSearch": null, |
|||
"isInherit": null, |
|||
"isFilling": false, |
|||
"fillingDigit": null, |
|||
"isRepeat": null, |
|||
"isDisplay": null, |
|||
"displayOrder": null, |
|||
"displayOrderBy": null, |
|||
"isDisplayformat": null, |
|||
"displayformatType": null, |
|||
"editLength": 536, |
|||
"displayLength": null, |
|||
"queue": null |
|||
}, |
|||
{ |
|||
"createBy": null, |
|||
"updateBy": null, |
|||
"createTime": null, |
|||
"updateTime": null, |
|||
"id": null, |
|||
"categoryId": null, |
|||
"mateData": null, |
|||
"dictionaryId": null, |
|||
"fieldName": "is_entity", |
|||
"fieldCnName": "是否存在实体", |
|||
"isDefaultValue": null, |
|||
"isInputClass": null, |
|||
"isDataType": null, |
|||
"isDataTypeDetails": null, |
|||
"isColumnLength": null, |
|||
"isColumnType": null, |
|||
"isSequence": null, |
|||
"isType": null, |
|||
"isSystem": null, |
|||
"isLine": null, |
|||
"isInput": null, |
|||
"isRequired": null, |
|||
"isAutomatic": null, |
|||
"isAdd": null, |
|||
"isSearch": null, |
|||
"isInherit": null, |
|||
"isFilling": null, |
|||
"fillingDigit": null, |
|||
"isRepeat": null, |
|||
"isDisplay": null, |
|||
"displayOrder": null, |
|||
"displayOrderBy": null, |
|||
"isDisplayformat": null, |
|||
"displayformatType": null, |
|||
"editLength": null, |
|||
"displayLength": null, |
|||
"queue": null |
|||
} |
|||
] |
Write
Preview
Loading…
Cancel
Save
Reference in new issue