档案管理3

This commit is contained in:
xiao-fajia 2024-08-29 19:18:18 +08:00
parent ecbb4851ef
commit 5aa3e8b2e3
7 changed files with 362 additions and 20 deletions

View File

@ -52,11 +52,12 @@
"dayjs": "^1.11.12",
"echarts": "5.4.0",
"element-ui": "2.15.12",
"file-saver": "2.0.5",
"file-saver": "^2.0.5",
"fuse.js": "6.6.2",
"highlight.js": "9.18.5",
"js-beautify": "1.13.0",
"jsencrypt": "3.3.1",
"jszip": "^3.10.1",
"min-dash": "3.5.2",
"nprogress": "0.2.0",
"qrcode.vue": "^1.7.0",

View File

@ -98,8 +98,13 @@ export default {
return this.isShowTip && (this.fileType || this.fileSize);
},
},
mounted(){
//
this.initFiles()
},
watch: {
value(val) {
if (val) {
let temp = 1;
const list = Array.isArray(val)? val : this.value.split(",");
@ -116,6 +121,26 @@ export default {
},
},
methods: {
/**
* 手动加载文件列表为了解决本组件value值变化可能会出现监听不到的情况
*/
initFiles(){
if(this.fileList.length==0){
//
if (!this.value){
return;
}
let temp = 1;
const list = Array.isArray(this.value)? this.value : this.value.split(",");
this.fileList = list.map((item) => {
if (typeof item === "string") {
item = { name: item, url: item };
}
item.uid = item.uid || new Date().getTime() + temp++;
return item;
});
}
},
handleBeforeUpload(file) {
if (this.fileType.length) {
const name = file.name.split(".");

29
src/utils/downloadZIP.js Normal file
View File

@ -0,0 +1,29 @@
import JSZip from 'jszip'
import { saveAs } from 'file-saver'
export async function downloadFilesAsZip(fileObject) {
const zip = new JSZip()
for (const item of fileObject.files) {
try {
const response = await fetch(item.url)
if (!response.ok) {
throw new Error(`下载失败 ${item.url}: ${response.status}`)
}
const blob = await response.blob()
// 提取文件名,假设文件路径中最后一部分为文件名
const fileName = item.name
zip.file(fileName, blob)
} catch (error) {
console.error(`下载失败 ${item.url}:`, error)
}
}
// 生成压缩文件
try {
const content = await zip.generateAsync({ type: 'blob' });
// 保存压缩文件
saveAs(content, fileObject.zipName);
} catch (error) {
console.error('生成ZIP错误', error);
}
}

View File

@ -34,6 +34,7 @@
:filter-node-method="filterNode"
@node-click="handleNodeClick"
highlight-current
:default-checked-keys="[chooseData.id]"
>
<template v-slot="{ node, data }">
<!-- 自定义节点内容 -->
@ -47,8 +48,8 @@
<!-- 具体表格 -->
<div class="right">
<!-- 搜索栏 -->
<el-empty style="margin-top: 10%" v-if="!chooseData" description="请先选择目录"></el-empty>
<div v-else>
<el-empty style="margin-top: 10%" v-show="!chooseData" description="请先选择目录"></el-empty>
<div v-show="!!chooseData">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch"
label-width="90px"
>
@ -75,11 +76,11 @@
>新增
</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getTabList"></right-toolbar>
</el-row>
<!-- 表格 -->
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" :row-class-name="getRowClass">
<el-table-column label="序号" align="center" width="80">
<template scope="scope">
<span>{{ scope.$index + 1 }}</span>
@ -103,13 +104,13 @@
<el-button v-if="chooseData.isDeleted" size="mini" type="text" icon="el-icon-delete" @click="handleItemDelete(scope.row)"
>删除
</el-button>
<el-dropdown>
<el-dropdown @command="(command) => handleCommand(command, scope.$index, scope.row)">
<el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="handleStaffChange" size="mini" type="text" icon="el-icon-search"
<el-dropdown-item command="showItem" size="mini" type="text" icon="el-icon-search"
>查看详情
</el-dropdown-item>
<el-dropdown-item command="handleStaffChangeData" size="mini" type="text" icon="el-icon-download"
<el-dropdown-item v-if="chooseData.isDownload" command="downloadItem" size="mini" type="text" icon="el-icon-download"
>下载
</el-dropdown-item>
</el-dropdown-menu>
@ -130,6 +131,7 @@
<ArchivesCatalogForm ref="formRef" @success="getList"/>
<ArchivesForm ref="archivesFormRef" @success="getTabList" />
<ArchivesShowForm ref="archivesShowFormRef" @success="getTabList" />
</div>
</template>
@ -139,12 +141,15 @@ import { getArchivesCatalogList, removeArchivesRoleAndDict } from '@/api/company
import {queryArchivesPage, removeArchivesById} from '@/api/company/archives/archives'
import ArchivesCatalogForm from '@/views/knowledge/views/archives/form/ArchivesCatalogForm'
import ArchivesForm from '@/views/knowledge/views/archives/form/ArchivesForm'
import {downloadFilesAsZip} from '@/utils/downloadZIP'
import ArchivesShowForm from '@/views/knowledge/views/archives/form/ArchivesShowForm'
export default {
name: 'ArchivesTable',
components: {
ArchivesCatalogForm,
ArchivesForm
ArchivesForm,
ArchivesShowForm
},
props: {
activeTab: {
@ -217,9 +222,13 @@ export default {
} finally {
this.treeLoading = false
}
if (this.chooseData){
await this.$tab.refreshPage(this.$route)
}
},
//
handleNodeClick(e) {
this.loading = true
this.chooseData = e
this.chooseDataId = e.dataId
this.queryParams.dataId = e.dataId
@ -270,9 +279,11 @@ export default {
},
/** 获取表格数据 */
async getTabList(){
this.loading = true
const res = await queryArchivesPage(this.queryParams)
this.list = res.data.records
this.total = res.data.total
this.loading = false
},
openTableFrom(row){
const data = {
@ -291,6 +302,51 @@ export default {
await this.getTabList()
this.$modal.msgSuccess('删除成功')
}catch {}
},
// ZIP
async downloadItem(row){
const fileObject = {
zipName: row.archivesName,
files: row.archivesUrls.split(",").map(item => {
return {
name: item.split("|")[1],
url: item.split("|")[0],
uid: item.split("|")[2],
status: item.split("|")[3]
}
})
}
await downloadFilesAsZip(fileObject)
},
handleCommand(command, index, row){
switch (command){
case 'showItem':
row = {
...row,
activeTab: this.activeTab
}
this.$refs["archivesShowFormRef"].open(row)
break
case 'downloadItem':
this.downloadItem(row)
break
default:
break
}
},
//
getRowClass(row, rowIndex){
if (this.activeTab !== 'contract_type'){
return '';
}
const diffTime = new Date(row.row.expireTime) - new Date()
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
if (diffDays < 0 || diffDays <= 30){
return 'one-month-row';
}else if (diffDays <= 90){
return 'three-months-row';
}
return ''
}
}
}
@ -335,4 +391,12 @@ div {
::v-deep .el-tree-node__expand-icon.is-leaf {
display: none;
}
::v-deep .el-table .one-month-row td{
background-color: #ffcccc !important; /* 红色背景 */
}
::v-deep .el-table .three-months-row td{
background-color: #ffffcc !important; /* 黄色背景 */
}
</style>

View File

@ -89,6 +89,26 @@
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="1">
<el-col :span="24">
<el-form-item label="下载权限" prop="downloadRoleIds">
<el-select
style="width: 100%"
filterable
clearable
v-model="formData.downloadRoleIds" multiple placeholder="请选择有下载权限的角色"
>
<el-option
v-for="(item, index) in roleList"
:key="index"
:label="item.name"
:value="item.id"
>
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm" :disabled="formLoading"> </el-button>
@ -118,6 +138,7 @@ export default {
updateRoleIds: null,
createRoleIds: null,
deleteRoleIds: null,
downloadRoleIds: null,
dictLabel: null,
},
formRules:{
@ -125,6 +146,7 @@ export default {
updateRoleIds: [{required: true, message: "修改权限不能为空", trigger: "blur"}],
deleteRoleIds: [{required: true, message: "删除权限不能为空", trigger: "blur"}],
createRoleIds: [{required: true, message: "新增权限不能为空", trigger: "blur"}],
downloadRoleIds: [{required: true, message: "下载权限不能为空", trigger: "blur"}],
dictLabel: [{required: true, message: "档案名称不能为空", trigger: "blur"}],
},
roleList: [],
@ -139,10 +161,11 @@ export default {
if (data.dataId) {
this.formData = {
...data,
queryRoleIds: data.queryRoleIds.split(",").map(item => parseInt(item)),
createRoleIds: data.createRoleIds.split(",").map(item => parseInt(item)),
updateRoleIds: data.updateRoleIds.split(",").map(item => parseInt(item)),
deleteRoleIds: data.deleteRoleIds.split(",").map(item => parseInt(item))
queryRoleIds: data.queryRoleIds ? data.queryRoleIds.split(",").map(item => parseInt(item)) : null,
createRoleIds: data.createRoleIds ? data.createRoleIds.split(",").map(item => parseInt(item)) : null,
updateRoleIds: data.updateRoleIds ? data.updateRoleIds.split(",").map(item => parseInt(item)) : null,
deleteRoleIds: data.deleteRoleIds ? data.deleteRoleIds.split(",").map(item => parseInt(item)) : null,
downloadRoleIds: data.downloadRoleIds ? data.downloadRoleIds.split(",").map(item => parseInt(item)) : null
}
}
await this.listRoles()
@ -165,6 +188,7 @@ export default {
updateRoleIds: this.formData.updateRoleIds.join(","),
deleteRoleIds: this.formData.deleteRoleIds.join(","),
createRoleIds: this.formData.createRoleIds.join(","),
downloadRoleIds: this.formData.deleteRoleIds.join(","),
}
//
if (data.dataId) {
@ -192,6 +216,7 @@ export default {
updateRoleIds: null,
createRoleIds: null,
deleteRoleIds: null,
downloadRoleIds: null,
dictLabel: null,
}
this.resetForm('formRef')

View File

@ -62,7 +62,7 @@
</el-radio-group>
</el-form-item>
<el-form-item label="文件上传" prop="archivesUrls">
<FileUpload v-model="formData.archivesUrls" :limit="50" />
<FileUpload ref="fileUpload" v-model="formData.archivesUrls" :limit="50" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input type="textarea" v-model="formData.remark" maxlength="200"
@ -125,8 +125,7 @@ export default {
this.formData = {
...data,
}
this.formData.archivesUrls = this.buildUrls()
console.log(this.formData.archivesUrls)
this.formData.archivesUrls = this.buildUrls(data.archivesUrls)
}
this.dialogTitle = data.id ? '修改档案' : '新增档案'
this.activeTab = data.activeTab
@ -139,7 +138,7 @@ export default {
await this.$refs['formRef'].validate()
try {
this.formLoading = true
this.formData.archivesUrls = this.buildUrls()
this.formData.archivesUrls = this.buildUrls(undefined)
this.formData.archivesCode = createHashCodeByStr(this.formData.archivesName)
const data = this.formData
//
@ -160,9 +159,9 @@ export default {
}
},
//
buildUrls(){
if (typeof this.formData.archivesUrls === 'string'){
return this.formData.archivesUrls.split(",").map(item => {
buildUrls(data){
if (data){
return data.split(",").map(item => {
return {
name: item.split("|")[1],
url: item.split("|")[0],

View File

@ -0,0 +1,199 @@
<template>
<div class="app-container">
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="80%" v-dialogDrag append-to-body>
<el-form ref="formRef" :model="formData" v-loading="formLoading" label-width="145px">
<!-- 档案信息 -->
<el-card class="box-card">
<!-- 卡片头 -->
<div slot="header" class="clearfix">
<i class="el-icon-plus"/>
<span>档案信息</span>
</div>
<!-- 卡片内容 -->
<div>
<el-row :gutter="2">
<el-col :span="12">
<el-form-item label="档案名称" prop="archivesName">
<el-input disabled v-model="formData.archivesName" placeholder="请输入档案名称"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="档案存放位置" prop="archivesPhysicsUrl">
<el-input disabled v-model="formData.archivesPhysicsUrl" placeholder="请输入档案存放位置"/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="2" v-if="activeTab === 'contract_type'">
<el-col :span="12">
<el-form-item label="签订日期" prop="signTime">
<el-date-picker disabled clearable v-model="formData.signTime" type="date" value-format="yyyy-MM-dd"
placeholder="选择签订日期"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="到期日期" prop="expireTime">
<el-date-picker disabled clearable v-model="formData.expireTime" type="date" value-format="yyyy-MM-dd"
placeholder="到期日期"
/>
</el-form-item>
</el-col>
</el-row>
</div>
</el-card>
<!-- 档案内容 -->
<el-card class="box-card">
<!-- 卡片头 -->
<div slot="header" class="clearfix">
<i class="el-icon-plus"/>
<span>档案内容</span>
</div>
<!-- 卡片内容 -->
<div class="card-content" style="display: flex; flex-direction: column; align-items: center;">
<div v-for="(file, index) in formData.files" :key="index" class="file-item">
<!-- 文件名 -->
<div class="file-name" v-if="file.fileType !== 'file'">{{ file.fileName }}</div>
<!-- 根据文件类型渲染不同的内容 -->
<div v-if="file.fileType === 'image'" class="image-preview">
<el-image
style="max-width: 100%; max-height: 100%"
:src="file.fileUrl"
:preview-src-list="file.fileUrl">
</el-image>
</div>
<div v-else-if="file.fileType === 'video'" class="video-preview">
<video :src="file.fileUrl" controls style="max-width: 100%; max-height: 100%;"></video>
</div>
<div v-else-if="file.fileType === 'audio'" class="audio-preview">
<audio :src="file.fileUrl" controls style="max-width: 100%; max-height: 300px;"></audio>
</div>
<div v-else class="file-link">
<a :href="file.fileUrl" target="_blank">{{ file.fileName }}</a>
</div>
<hr/>
</div>
</div>
</el-card>
</el-form>
</el-dialog>
</div>
</template>
<script>
export default {
name: 'ArchivesShow',
data() {
return {
dialogTitle: null,
dialogVisible: false,
// 12
formLoading: false,
//
formData: {
files: [
{
fileName: null,
fileType: null,
fileUrl: null
}
]
},
activeTab: null,
//
fileTypeMap: {
//
jpg: 'image',
jpeg: 'image',
png: 'image',
gif: 'image',
bmp: 'image',
tif: 'image',
tiff: 'image',
svg: 'image',
webp: 'image',
//
mp4: 'video',
avi: 'video',
mkv: 'video',
mov: 'video',
flv: 'video',
wmv: 'video',
mpg: 'video',
mpeg: 'video',
m4v: 'video',
//
mp3: 'audio',
wav: 'audio',
aac: 'audio',
flac: 'audio',
ogg: 'audio',
m4a: 'audio',
//
default: 'file'
}
}
},
methods: {
/** 打开弹窗 */
async open(data) {
this.formData = {
...data,
files: this.buildFiles(data.archivesUrls)
}
this.activeTab = data.activeTab
this.dialogTitle = '查看档案'
this.dialogVisible = true
},
buildFiles(data) {
return data.split(',').map(item => {
return {
fileName: item.split('|')[1],
fileUrl: item.split('|')[0],
fileType: this.fileTypeMap[item.split('|')[1].split('.').pop().toLowerCase()] || this.fileTypeMap.default
}
})
}
}
}
</script>
<style scoped>
.box-card {
margin-bottom: 10px;
}
.card-content {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}
.file-item {
margin-bottom: 20px;
width: 100%;
text-align: center;
}
.file-name {
font-size: 16px;
margin-bottom: 10px;
color: #333;
}
.image-preview img,
.video-preview video,
.audio-preview audio {
max-width: 100%;
max-height: 300px;
}
.file-link {
text-align: center;
}
</style>