master
lion 8 months ago
parent dfa7374765
commit bb4e672eec

@ -19,6 +19,7 @@
"@vue-office/docx": "^1.6.3",
"@vue-office/excel": "^1.7.14",
"@vue-office/pdf": "^2.0.10",
"@vue-office/pptx": "^1.0.1",
"@vue/composition-api": "^1.7.2",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^1.0.2",
@ -30,6 +31,7 @@
"element-ui": "2.15.13",
"file-saver": "^2.0.5",
"js-cookie": "2.2.0",
"jszip": "^3.10.1",
"less": "^3.13.1",
"less-loader": "^5.0.0",
"moment": "^2.29.2",

@ -0,0 +1,314 @@
<template>
<el-dialog class="common-dialog" :fullscreen='isfullscreen' :title="title" :modal="false" :visible.sync="isShow"
:width="width">
<div slot="title">
<span class="el-dialog__title">{{title}}</span>
<slot name="searchtype"></slot>
</div>
<div class="dialogConcent" :style="{height:wheight+'px'}">
<div class="btnwrap">
<el-checkbox @change="changeAll" v-model="allChecked"></el-checkbox>
<el-button type="primary" size="small" @click="downloadBtn" :loading="btnloading">
{{ btnloading ? '下载中...' : '批量下载' }}
</el-button>
</div>
<div class="filewrap">
<!-- 文件 -->
<div v-for="item in fileList" class="filewrap-item">
<div>
<i class="el-icon-document-copy" @click="toshowFile(item)"></i>
</div>
<div>
<el-checkbox @change="(e)=>{return changeCheck(e,item)}"
v-model="item.checked">{{item.original_name}}</el-checkbox>
</div>
</div>
<div v-for="item in imgList" class="filewrap-item">
<div class="filewrap-item-img">
<el-image style="width: 40px; height: 40px;margin-bottom:10px" :src="item.url"
:preview-src-list="imgPrewList"></el-image>
</div>
<div>
<el-checkbox @change="(e)=>{return changeCheck(e,item)}"
v-model="item.checked">{{item.original_name}}</el-checkbox>
</div>
</div>
</div>
</div>
<div slot="footer" class="dialog-footer">
<div>
<el-button size="small" @click="isShow = false">关闭</el-button>
</div>
<slot name="footerbtn"></slot>
</div>
<!-- 文件预览 -->
<viewFile ref="viewFile"></viewFile>
</el-dialog>
</template>
<script>
import viewFile from '@/components/viewFile/viewFile.vue'
import JSZip from "jszip";
import FileSaver from "file-saver";
export default {
components: {
viewFile
},
props: {
title: {
type: String,
default: "文件预览"
},
width: {
type: String,
default: "70%"
},
// files: {
// type: Array,
// default: () => {
// return []
// }
// },
type: {
type: String,
default: "showinfo"
},
},
data() {
return {
// diaShow: this.isShow,
isShow: false,
isfullscreen: false,
btnloading: false,
allChecked: false,
wheight: "400",
form: {
show: ''
},
files: [],
imgList: [],
imgPrewList: [],
fileList: [],
checkList: []
}
},
watch: {
isShow(val) {
if (val) {
this.files.map(item => {
item.checked = false
if (this.isImageUrl(item.url)) {
this.imgList.push(item)
this.imgPrewList.push(item.url)
} else {
this.fileList.push(item)
}
})
console.log("this.fileList", this.fileList)
} else {
this.imgList = []
this.imgPrewList = []
this.fileList = []
this.files = []
this.checkList = []
}
},
},
methods: {
isImageUrl(url) {
//
const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.tif', '.webp', '.svg'];
// URL 便
const lowerCaseUrl = url.toLowerCase();
// URL
return imageExtensions.some(ext => lowerCaseUrl.endsWith(ext));
},
changeAll(e) {
if (e) {
let arr = []
this.imgList.map(item => {
this.$set(item, 'checked', e)
arr.push(item)
})
this.fileList.map(item => {
this.$set(item, 'checked', e)
arr.push(item)
})
this.checkList = arr
} else {
this.checkList = []
this.imgList.map(item => {
this.$set(item, 'checked', e)
})
this.fileList.map(item => {
this.$set(item, 'checked', e)
})
}
console.log("checkListAll", this.checkList)
this.$forceUpdate()
},
changeCheck(e, item) {
console.log(e)
this.$set(item, 'checked', e)
const index = this.checkList.findIndex((c) => c.id === item.id);
if (e) {
if (index == -1) {
this.checkList.push(item);
}
} else {
if (index !== -1) {
this.checkList.splice(index, 1);
}
}
console.log("checkList", this.checkList)
this.$forceUpdate()
},
//
toshowFile(item) {
console.log(item)
//
if (item.url && this.base.containsVideoFormat(item.url)) {
this.$refs.viewFile.typeName = 'video'
this.$refs.viewFile.url = item.url
} else {
this.$refs.viewFile.typeName = 'file'
if (item.extension == 'doc' || item.extension == 'DOC') {
this.$refs.viewFile.url = item.view_url
} else {
this.$refs.viewFile.url = item.url
}
}
this.$refs.viewFile.diaShow = true
},
// downloadBtn<>
downloadBtn() {
console.log("13",this.checkList)
if (this.checkList.length < 1) {
this.$Message.warning('请选择要下载的文件')
return
}
var blogTitle = this.title; //
var zip = new JSZip();
var promises = [];
let cache = {};
this.btnloading = true
for (let item of this.checkList) {
// item.url
// item.name
if (item.url) {
const promise = this.getImgArrayBuffer(item.url).then((data) => {
// , ArrayBuffer(blob) + '.' + item.extension
zip.file(item.original_name, data, {
binary: true
}); //
cache[item.original_name] = data;
});
promises.push(promise);
} else {
// url
alert(`附件${item.original_name}地址错误,下载失败`);
}
}
Promise.all(promises).then(() => {
zip.generateAsync({
type: "blob"
}).then((content) => {
//
FileSaver.saveAs(content, blogTitle); // file-saver blogTitle:
this.btnloading = false
});
}).catch((res) => {
alert("文件压缩失败");
});
},
//url
getImgArrayBuffer(url) {
console.log("url", url)
return new Promise((resolve, reject) => {
//blob
let xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", url, true);
xmlhttp.responseType = "blob";
xmlhttp.onload = function() {
if (xmlhttp.status == 200) {
resolve(xmlhttp.response);
} else {
reject(xmlhttp.response);
}
};
xmlhttp.send();
});
},
}
}
</script>
<style scoped lang="scss">
::v-deep .show {
flex-basis: 100%;
}
.dialogConcent {
overflow-y: scroll;
}
.btnwrap{
margin:1%;
.el-button{
margin-left:20px;
}
}
.filewrap {
display: flex;
align-items: center;
flex-wrap: wrap;
&-item {
text-align: center;
font-size: 18px;
margin: 1%;
cursor: pointer;
color: #b3241d;
width: 18%;
height: 130px;
position: relative;
&-img{
font-size: 0;
}
::v-deep .el-checkbox {
display: flex;
// align-items: center;
white-space: normal;
justify-content: center;
.el-checkbox__inner{
margin-top:3px;
}
}
i {
font-size: 40px;
margin-bottom: 10px;
}
}
}
.iframeWeb {
text-align: center;
border: none;
display: block;
height: 100vh;
width: 100%;
}
</style>

@ -13,6 +13,7 @@
<vue-office-docx v-if="urlType==='docx'" :src="url" @rendered="renderingCompleted"></vue-office-docx>
<vue-office-pdf v-else-if="urlType==='pdf'" :src="url" @rendered="renderingCompleted"></vue-office-pdf>
<vue-office-excel v-else-if="urlType==='excel'" :src="url" @rendered="renderingCompleted"></vue-office-excel>
<vue-office-pptx v-else-if="urlType==='pptx'" :src="url" @rendered="renderingCompleted"></vue-office-pptx>
<img v-else-if="urlType==='image'" :src="url" style="width:100%"></img>
@ -39,13 +40,15 @@
<script>
import vueOfficeDocx from "@vue-office/docx"
import vueOfficeExcel from "@vue-office/excel"
import vueOfficePdf from "@vue-office/pdf"
import vueOfficePdf from "@vue-office/pdf"
import vueOfficePptx from "@vue-office/pptx"
import '@vue-office/docx/lib/index.css'
export default {
components: {
vueOfficeDocx,
vueOfficeExcel,
vueOfficePdf
vueOfficePdf,
vueOfficePptx
},
props: {
title: {
@ -54,7 +57,7 @@
},
width: {
type: String,
default: "60%"
default: "80%"
},
isShow: {
type: Boolean,
@ -95,6 +98,9 @@
this.urlType = 'pdf'
} else if (val.includes('xls') || val.includes('xlsx') || val.includes('XLS') || val.includes('XLSX')) {
this.urlType = 'excel'
} else if (val.includes('pptx') || val.includes('PPTX') ) {
this.urlType = 'pptx'
} else if (this.isImageUrl(val)) {
this.urlType = 'image'
} else {

@ -1,100 +0,0 @@
<template>
<el-dialog class="common-dialog" :fullscreen='isfullscreen' :title="title" :modal="false" top="10vh" :visible.sync="diaShow" @close="coloseDia"
:width="width">
<div slot="title">
<span class="el-dialog__title">{{title}}</span>
<slot name="searchtype"></slot>
</div>
<div class="dialogConcent" style="max-height: 65vh !important;min-height: 300px;overflow: scroll;">
<div v-if="typeName=='file'">
<iframe id="iframeWin" :src="url" frameborder="0" scrolling="auto" align="center" class="iframeWeb">
</iframe>
</div>
<div v-if="typeName=='video'" style="text-align: center;">
<video :src="url" controls></video>
</div>
</div>
<div slot="footer" class="dialog-footer">
<div>
<el-button size="small" @click="coloseDia"></el-button>
</div>
<slot name="footerbtn"></slot>
</div>
</el-dialog>
</template>
<script>
export default {
props: {
title: {
type: String,
default: "文件预览"
},
width: {
type: String,
default: "70%"
},
isShow: {
type: Boolean,
default: () => {
return false
}
},
type: {
type: String,
default: "showinfo"
},
},
data() {
return {
diaShow: this.isShow,
isfullscreen:false,
url:'',
typeName:'file',
baseUrl: `${process.env.VUE_APP_PREVIEW_API}?url=`,
wheight: "",
form:{
show:''
}
}
},
watch: {
isShow(val) {
this.diaShow = this.isShow;
},
},
methods: {
coloseDia() {
// this.url = ""
this.diaShow = false
this.url = ''
this.typeName = 'file'
this.$emit('update:isShow', false)
}
}
}
</script>
<style scoped>
/deep/ .show{
flex-basis: 100%;
}
.dialogConcent {
overflow-y: hidden;
}
.iframeWeb {
text-align: center;
border: none;
display: block;
height: 100vh;
width: 100%;
}
</style>

@ -0,0 +1,156 @@
<template>
<div>
<xy-dialog ref="dialog" :width="60" :is-show.sync="isShow" :type="'normal'" :title="form.title">
<template v-slot:default>
<div class="article">
<div class="article-title">{{form.title}}</div>
<div v-if="form.tag_ids">
<!-- <el-tag></el-tag> -->
</div>
<div class="article-time">
<div v-if="form.date">{{form.date}}</div>
<div v-if="form.catalog_name">
<el-tag>{{form.catalog_name}}</el-tag>
</div>
<div v-if="form.area_ids">
<template v-if="form.area_ids_details && form.area_ids_details.length>0">
<template v-for="(item,index) in form.area_ids_details">
<el-tag style="margin-right:5px">{{item.name}}</el-tag>
</template>
</template>
</div>
<div v-if="form.tag_ids">
<template v-if="form.area_ids_details && form.tag_ids_details.length>0">
<template v-for="(item,index) in form.tag_ids_details">
<el-tag style="margin-right:5px">{{item.name}}</el-tag>
</template>
</template>
</div>
</div>
<div class="article-files" v-if="form.files_details && form.files_details.length>0">
<div v-for="(item,index) in form.files_details">
附件{{index+1}}
<a :href="item.url" target="_blank">{{item.original_name}}</a>
<el-link target="_blank" style="margin:0 10px;" @click="toshowFile(item)" type="primary">
预览
</el-link>
</div>
</div>
<div class="article-html" v-if="form.content">
<div v-html="form.content"></div>
</div>
</div>
</template>
<template v-slot:footerContent>
<Button ghost type="primary" @click='isShow=false'>关闭</Button>
</template>
</xy-dialog>
<viewFile ref="viewFile"></viewFile>
</div>
</template>
<script>
import {
show
} from "@/api/system/baseForm.js"
import viewFile from '@/components/viewFile/viewFile.vue'
export default {
components: {
viewFile
},
data() {
return {
isShow: false,
id: '',
table_name: 'records',
form: {}
}
},
created() {
},
methods: {
getDetail() {
show({
id: this.id,
table_name: this.table_name,
json_data_fields: ['files', 'area_ids','tag_ids']
}).then(res => {
this.form = this.base.deepCopy(res)
console.log("this.form", this.form)
})
},
toshowFile(item) {
//
if(item.url && this.base.containsVideoFormat(item.url)){
this.$refs.viewFile.typeName = 'video'
this.$refs.viewFile.url = item.url
}else{
this.$refs.viewFile.typeName = 'file'
if(item.url.includes('doc')||item.url.includes('DOC')){
this.$refs.viewFile.url = item.view_url
}else{
this.$refs.viewFile.url = item.url
}
}
this.$refs.viewFile.diaShow = true
},
},
watch: {
isShow(newVal) {
if (newVal) {
this.getDetail()
} else {
this.id = ''
this.form = {}
}
},
}
}
</script>
<style scoped lang="scss">
.article {
&>div {
margin:10px 30px;
}
&-title {
font-size: 24px;
text-align: center;
font-weight: bold;
color: #000;
}
&-time {
display: flex;
justify-content: center;
font-size: 16px;
color: rgba(0, 0, 0, 0.6);
align-items: center;
&>div {
margin: 0 10px;
}
}
&-files {
color: blue;
cursor: pointer;
text-decoration: underline;
// text-indent: 2em;
}
&-html {
line-height: 1.5;
font-size: 20px;
::v-deep video{
display:block!important;
margin:0 auto!important;
}
}
}
</style>

@ -27,14 +27,18 @@
</template>
</div>
</div>
<div class="article-files" v-if="form.files_details && form.files_details.length>0">
<div v-for="(item,index) in form.files_details">
<div class="article-files" v-if="form.files_details && form.files_details.length>0">
<el-link target="_blank" style="margin:0 10px;" @click="toViewDownLoadFile(form.files_details)" type="primary">
共有{{form.files_details.length}}条附件点击查看
</el-link>
<!-- <div v-for="(item,index) in form.files_details">
附件{{index+1}}
<a :href="item.url" target="_blank">{{item.original_name}}</a>
<el-link target="_blank" style="margin:0 10px;" @click="toshowFile(item)" type="primary">
预览
</el-link>
</div>
</div> -->
</div>
<div class="article-html" v-if="form.content">
<div v-html="form.content"></div>
@ -45,7 +49,8 @@
<Button ghost type="primary" @click='isShow=false'>关闭</Button>
</template>
</xy-dialog>
<viewFile ref="viewFile"></viewFile>
<viewFile ref="viewFile"></viewFile>
<viewDownload ref="viewDownload" :title="form.title"></viewDownload>
</div>
</template>
@ -53,17 +58,19 @@
import {
show
} from "@/api/system/baseForm.js"
import viewFile from '@/components/viewFile/viewFile.vue'
import viewFile from '@/components/viewFile/viewFile.vue'
import viewDownload from '@/components/viewFile/viewDownload.vue'
export default {
components: {
viewFile
viewFile,
viewDownload
},
data() {
return {
isShow: false,
id: '',
table_name: 'records',
form: {}
form: {},
}
},
created() {
@ -96,7 +103,12 @@
}
}
this.$refs.viewFile.diaShow = true
},
},
//
toViewDownLoadFile(files){
this.$refs.viewDownload.files = files
this.$refs.viewDownload.isShow = true
}
},
watch: {
isShow(newVal) {

@ -25,7 +25,7 @@ module.exports = {
* Detail: https://cli.vuejs.org/config/#publicpath
*/
publicPath: process.env.ENV === 'staging' ? '/admin_test' : '/admin',
outputDir: '/Users/mac/Documents/朗业/2024/s-四世同堂-档案/sstt_dangan/public/admin',
outputDir: '/Users/mac/Documents/朗业/2024/s-四世同堂-档案/sstt_dangan/public/admin_test',
assetsDir: 'static',
css: {
loaderOptions: { // 向 CSS 相关的 loader 传递选项

Loading…
Cancel
Save