提交 ba3882c5 authored 作者: 龙菲's avatar 龙菲

增加审核管理

上级 afa6208a
...@@ -18,14 +18,16 @@ ...@@ -18,14 +18,16 @@
"core-js": "3.6.5", "core-js": "3.6.5",
"echarts": "^5.4.0", "echarts": "^5.4.0",
"el-tree-transfer": "^2.4.7", "el-tree-transfer": "^2.4.7",
"element-ui": "2.13.2", "element-ui": "^2.15.6",
"js-cookie": "2.2.0", "js-cookie": "2.2.0",
"normalize.css": "7.0.0", "normalize.css": "7.0.0",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"path-to-regexp": "2.4.0", "path-to-regexp": "2.4.0",
"vue": "2.6.10", "vue": "2.6.10",
"vue-awesome-swiper": "^3.1.3",
"vue-quill-editor": "^3.0.6", "vue-quill-editor": "^3.0.6",
"vue-router": "3.0.6", "vue-router": "3.0.6",
"vue-video-player": "^5.0.2",
"vuex": "3.1.0" "vuex": "3.1.0"
}, },
"devDependencies": { "devDependencies": {
......
...@@ -59,3 +59,12 @@ export function getCulturalRelicStatistic(params) { ...@@ -59,3 +59,12 @@ export function getCulturalRelicStatistic(params) {
}) })
} }
// 获取文物审核列表
export function getCrChecklist(data) {
return request({
url: '/bizCulturalRelic/checklistByPagePer',
method: 'post',
data
})
}
...@@ -57,4 +57,32 @@ export function getExhibitionStatistic(params) { ...@@ -57,4 +57,32 @@ export function getExhibitionStatistic(params) {
method: 'get', method: 'get',
params params
}) })
} }
\ No newline at end of file
// 获取展览审核列表
// export function getDisplayChecklist(data) {
// return request({
// url: '/bizExhibition/checklistByPagePer',
// method: 'post',
// data
// })
// }
// 查询审批结果
export function getDisplayCheckById(params) {
return request({
url: '/bizExhibition/getCheckById',
method: 'get',
params
})
}
// 查询审批结果
export function postCheck(data) {
return request({
url: '/bizCheck/check',
method: 'post',
data
})
}
<template> <template>
<div> <div class="reader-operations">
<div class="operations"> <span class="operations">
<span class="operation-item" v-if="like"> <span class="operation-item" v-if="like">
<svg-icon <!-- <svg-icon @click="handleLike" icon-class="like-s" :style="{
:icon-class="loveCountStatus ? 'mz-like-s' : 'mz-like'" fontSize: iconSize + 'px',
:style="{ color: loveCountStatus ? selectColor : '#61666d',
fontSize: iconSize + 'px', }"></svg-icon> -->
color: loveCountStatus ? selectColor : '#61666d', <span>{{
}" formatNum(loveCount) == 0 ? "点赞" : formatNum(loveCount)
></svg-icon> }}</span>
<span>{{ formatNum(loveCount)?formatNum(loveCount):'点赞' }}</span>
</span> </span>
<span class="operation-item" v-if="collect"> <span class="operation-item" v-if="collect">
<svg-icon <!-- <svg-icon icon-class="collect-s-2" :style="{
:icon-class="collectCountStatus ? 'collect-s' : 'collect'" fontSize: iconSize + 'px',
:style="{ color: collectCountStatus ? selectColor : '#61666d',
fontSize: iconSize + 'px', }"></svg-icon> -->
color: collectCountStatus ? selectColor : '#61666d', <span>{{
}" formatNum(collectCount) == 0 ? "收藏" : formatNum(collectCount)
></svg-icon> }}</span>
<span>{{ formatNum(collectCount) }}</span>
</span> </span>
<span v-if="share" class="operation-item"> <span v-if="share" class="operation-item">
<svg-icon <!-- <svg-icon icon-class="share2" :style="{
icon-class="mz-fx" fontSize: iconSize + 'px',
class="collect" }"></svg-icon> -->
:style="{
fontSize: iconSize + 'px',
color: selectColor,
}"
></svg-icon>
<span>分享</span> <span>分享</span>
</span> </span>
</div> </span>
</div> </div>
</template> </template>
<script> <script>
import { formatNum } from "@/utils/index"; import { mapGetters } from "vuex";
import { debounce, formatNum } from "@/utils/index";
export default { export default {
name: "ReaderOperations", name: "ReaderOperations",
props: { props: {
...@@ -92,11 +86,11 @@ export default { ...@@ -92,11 +86,11 @@ export default {
}, },
iconSize: { iconSize: {
type: [Number, String], type: [Number, String],
default:40, default: 28,
}, },
selectColor: { selectColor: {
type: String, type: String,
default: "#2069c4", default: "$themeColor",
}, },
}, },
data() { data() {
...@@ -106,7 +100,11 @@ export default { ...@@ -106,7 +100,11 @@ export default {
curLink: "", //当前地址栏的链接 curLink: "", //当前地址栏的链接
}; };
}, },
computed: {
...mapGetters(["token", "showLoginDialog"]),
},
methods: { methods: {
formatNum(num) { formatNum(num) {
return formatNum(num); return formatNum(num);
}, },
...@@ -115,47 +113,76 @@ export default { ...@@ -115,47 +113,76 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
$themeColor: #132c33;
.reader-operations {
width: 100%;
max-width: 300px;
}
.operations { .operations {
// margin-top: 22px; // margin-top: 22px;
width: 100%;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
.operation-item { .operation-item {
display: flex; display: flex;
align-items: center; align-items: center;
// margin-right: 32px; // margin-right: 32px;
cursor: pointer; cursor: pointer;
font-size: 14px;
} }
.svg-icon { .svg-icon {
margin-right: 10px; margin-right: 10px;
font-size: 36px; font-size: 24px;
color: #61666d; color: #61666d;
} }
.like { .like {
color: #831122; color: #831122;
} }
.collect { .collect {
color: #831122; color: #831122;
} }
} }
.el-button--text { .el-button--text {
color: #2069c4; color: $themeColor;
} }
.qrcode,
.copy { .copy {
display: flex; display: flex;
// justify-content: space-between;
align-items: center; align-items: center;
height: 180px;
} }
.qrcode { .qrcode {
.img-container { .img-container {
width: 200px; width: 200px;
height: 200px; height: 200px;
img { img {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
} }
} }
::v-deep .el-input-group__append {
padding: 0 40px;
}
::v-deep .dialog-footer {
.el-button {
border-radius: 0;
}
.el-button--primary {
border: none;
background-color: $themeColor;
}
}
</style> </style>
\ No newline at end of file
<template>
<div class="firstDiv">
<div class="centerDiv">
<div class="thumb-example">
<!-- 大轮播图 -->
<swiper
class="swiper gallery-top"
:options="swiperOptionTop"
ref="swiperTop"
>
<swiper-slide
class="slide-item"
v-for="(item, index) in imgList"
:key="index"
>
<img :src="$getFullUrl(item.pressUrl)" alt="" />
<div class="enlarge" @click="handelPreviewImages(imgList)">
<img src="@/assets/imgs/enlarge-s.png" alt="" />
</div>
</swiper-slide>
<div
class="swiper-button-next swiper-button-white"
slot="button-next"
></div>
<div
class="swiper-button-prev swiper-button-white"
slot="button-prev"
></div>
</swiper>
<!-- 小缩略图 -->
<swiper
class="swiper gallery-thumbs"
:options="swiperOptionThumbs"
ref="swiperThumbs"
>
<swiper-slide
class="slide-item"
v-for="(item, index) in imgList"
:key="index"
>
<img :src="$getFullUrl(item.pressUrl)" alt="" />
</swiper-slide>
</swiper>
</div>
</div>
<el-image-viewer
v-if="imgViewerVisible"
:on-close="closeImgViewer"
:url-list="previewList"
/>
</div>
</template>
<script>
import { swiper, swiperSlide } from "vue-awesome-swiper";
import "swiper/dist/css/swiper.css";
export default {
name: "SlideImage",
components: {
swiper,
swiperSlide,
"el-image-viewer": () =>
import("element-ui/packages/image/src/image-viewer"),
},
props: {
imgKey: {
type: String,
default: "pressUrl",
},
imgList: {
type: Array,
default: () => [],
},
},
data() {
return {
swiperOptionTop: {
loop: false,
loopedSlides: 8, // looped slides should be the same
spaceBetween: 10,
navigation: {
nextEl: ".swiper-button-next",
prevEl: ".swiper-button-prev",
},
},
swiperOptionThumbs: {
loop: false,
loopedSlides: 8, // looped slides should be the same
spaceBetween: 10,
centeredSlides: true,
slidesPerView: "auto",
touchRatio: 0.2,
slideToClickedSlide: true,
},
imgViewerVisible: false,
};
},
mounted() {
this.$nextTick(() => {
const swiperTop = this.$refs.swiperTop.swiper;
const swiperThumbs = this.$refs.swiperThumbs.swiper;
swiperTop.controller.control = swiperThumbs;
swiperThumbs.controller.control = swiperTop;
});
},
methods: {
handelPreviewImages(items) {
this.imgViewerVisible = true;
this.previewList = items.map((item) => this.$getFullUrl(item.url));
},
closeImgViewer() {
this.imgViewerVisible = false;
},
},
};
</script>
<style scoped lang="scss">
.firstDiv {
/* width: 1920px; */
/* height: 1080px; */
width: 100%;
height: 100%;
position: relative;
}
.centerDiv {
width: 100%;
height: 100%;
background-color: #f5f5f9;
/* width: 900px; */
/* height: 800px; */
/* position: absolute; */
/* left: 510px; */
/* top: 200px; */
}
.thumb-example {
height: 100%;
background-color: transparent;
}
.swiper-slide {
background-size: cover;
background-position: center;
}
.slide-item {
background: #f5f5f9;
position: relative;
img {
width: 100%;
height: 100%;
object-fit: contain;
}
}
.enlarge {
position: absolute;
bottom: 30px;
right: 30px;
display: flex;
z-index: 9;
background-color: #c1925b;
width: 40px;
height: 40px;
border-radius: 12px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
cursor: pointer;
img {
width: 24px;
height: 24px;
}
}
.gallery-top {
height: 80%;
width: 100%;
}
.gallery-thumbs {
height: 20%;
box-sizing: border-box;
padding: 10px 0;
}
.gallery-thumbs .swiper-slide {
width: 20%;
height: 100%;
opacity: 0.4;
}
.gallery-thumbs .swiper-slide-active {
opacity: 1;
}
</style>
\ No newline at end of file
<template>
<div class="card-slider">
<div class="swiper">
<swiper
class="swiper gallery-top"
:options="swiperOptionTop"
ref="swiperTop"
>
<swiper-slide
class="slide-item"
v-for="(item, index) in imgList"
:key="index"
>
<img :src="item.pressUrl" alt="" />
<!-- <div class="enlarge" @click="handelPreviewImages(imgList)">
<img src="@/assets/imgs/enlarge-s.png" alt="" />
</div> -->
</swiper-slide>
<div
class="swiper-button-next swiper-button-white"
slot="button-next"
></div>
<div
class="swiper-button-prev swiper-button-white"
slot="button-prev"
></div>
</swiper>
</div>
<!-- <el-image-viewer
v-if="imgViewerVisible"
:on-close="closeImgViewer"
:url-list="previewList"
/> -->
</div>
</template>
<script>
import { swiper, swiperSlide } from "vue-awesome-swiper";
import "swiper/dist/css/swiper.css";
export default {
name: "SlideImage",
components: {
swiper,
swiperSlide,
/* "el-image-viewer": () =>
import("element-ui/packages/image/src/image-viewer"), */
},
props: {
imgKey: {
type: String,
default: "pressUrl",
},
imgList: {
type: Array,
default: () => [],
},
},
data() {
return {
swiperOptionTop: {
loop: true,
loopedSlides: 8, // looped slides should be the same
spaceBetween: 10,
navigation: {
nextEl: ".swiper-button-next",
prevEl: ".swiper-button-prev",
},
},
imgViewerVisible: false,
};
},
/* mounted() {
this.$nextTick(() => {
const swiperTop = this.$refs.swiperTop.swiper;
const swiperThumbs = this.$refs.swiperThumbs.swiper;
swiperTop.controller.control = swiperThumbs;
swiperThumbs.controller.control = swiperTop;
});
}, */
methods: {
handelPreviewImages(items) {
this.imgViewerVisible = true;
this.previewList = items.map((item) => this.$getFullUrl(item.url));
},
closeImgViewer() {
this.imgViewerVisible = false;
},
},
};
</script>
<style lang="scss" scoped>
.card-slider {
width: 100%;
height: 100%;
.slide-item {
background: transparent;
position: relative;
img {
width: 100%;
height: 100%;
object-fit: contain;
}
}
}
</style>
<template>
<div class="slide-img-group">
<div class="list">
<swiper
class="swiper gallery-thumbs"
:options="swiperOptionThumbs"
ref="swiperThumbs"
>
<swiper-slide
class="slide-item"
v-for="(item, index) in imgList"
:key="index"
@click="handleClickItem(item)"
>
<!-- <img :src="item.pressUrl || item.faceImagePressUrl" alt="" /> -->
<div class="img-container" @click="handelPreviewImages(imgList)">
<slot name="img" :item="item"></slot>
</div>
<slot name="info" :item="item" />
<!-- <div
class="enlarge"
@click="handelPreviewImages(imgList)"
v-if="needEnlarge"
>
<img src="@/assets/imgs/enlarge-s.png" alt="" />
<span>查看大图</span>
</div> -->
</swiper-slide>
<div class="swiper-pagination" slot="pagination"></div>
<div class="swiper-button-next swiper-button-white" slot="button-next">
<i class="el-icon-arrow-right"></i>
</div>
<div class="swiper-button-prev swiper-button-white" slot="button-prev">
<i class="el-icon-arrow-left"></i>
</div>
<!--分页器。如果放置在swiper外面,需要自定义样式。-->
</swiper>
</div>
<el-image-viewer
v-if="imgViewerVisible"
:on-close="closeImgViewer"
:url-list="previewList"
/>
</div>
</template>
<script>
import { swiper, swiperSlide } from "vue-awesome-swiper";
import "swiper/dist/css/swiper.css";
export default {
name: "SlideImageGroup",
components: {
swiper,
swiperSlide,
"el-image-viewer": () =>
import("element-ui/packages/image/src/image-viewer"),
},
props: {
imgKey: {
type: String,
default: "pressUrl",
},
imgList: {
type: Array,
default: () => [],
},
needEnlarge: {
type: Boolean,
default: false,
},
},
data() {
return {
swiperOptionThumbs: {
loop: false,
loopedSlides: 8, // looped slides should be the same
spaceBetween: 10,
slidesPerView: 4,
navigation: {
nextEl: ".swiper-button-next",
prevEl: ".swiper-button-prev",
},
pagination: {
el: ".swiper-pagination",
clickable: true,
},
},
imgViewerVisible: false,
};
},
mounted() {},
methods: {
handelPreviewImages(items) {
this.imgViewerVisible = true;
this.previewList = items.map((item) => this.$getFullUrl(item.url));
},
closeImgViewer() {
this.imgViewerVisible = false;
},
handleClickItem(item) {
debugger;
this.$emit("handleClickItem", item);
},
},
};
</script>
<style scoped lang="scss">
$themeColor:#132c33;
.slide-img-group {
height: 100%;
}
.swiper-container {
// padding: 0 60px;
::v-deep .swiper-wrapper {
display: flex;
// justify-content: center;
}
}
.list,
.swiper,
.swiper-wrapper {
height: 100%;
}
.swiper-slide {
background-size: cover;
background-position: center;
}
.slide-item {
position: relative;
height: 100%;
display: flex;
flex-direction: column;
padding-bottom: 10px;
.img-container {
width: 100%;
// height: 100%;
background: #f5f5f9;
height: 200px;
cursor: pointer;
img {
width: 100%;
height: 100%;
object-fit: fill;
}
}
}
.swiper-button-next,
.swiper-button-prev {
background-image: none;
width: 60px;
height: 60px;
display: flex;
justify-content: center;
align-items: center;
color: $themeColor;
font-weight: bolder;
font-size: 28px;
transform: translateY(-20px);
}
.enlarge {
position: absolute;
bottom: 19px;
right: -7px;
display: flex;
z-index: 9;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
background: rgba($color: #000000, $alpha: 0.3);
cursor: pointer;
color: #fff;
font-size: 12px;
padding: 4px 8px;
img {
width: 12px;
height: 12px;
margin-right: 4px;
}
}
::v-deep .swiper-pagination-bullets{
bottom: 0;
}
</style>
\ No newline at end of file
...@@ -41,9 +41,12 @@ ...@@ -41,9 +41,12 @@
<template v-else-if="item.isStatus"> <template v-else-if="item.isStatus">
<slot name="status" :scope="scope.row"></slot> <slot name="status" :scope="scope.row"></slot>
</template> </template>
<template v-else-if="item.prop=='checkStatus'">
<slot name="checkStatus" :scope="scope.row"></slot>
</template>
<template v-else-if="item.prop == 'years'"> <template v-else-if="item.prop == 'years'">
<slot name="years" :scope="scope.row"></slot> <slot name="years" :scope="scope.row"></slot>
</template> </template>
<template v-else-if="item.prop == 'level'"> <template v-else-if="item.prop == 'level'">
<slot name="level" :scope="scope.row"></slot> <slot name="level" :scope="scope.row"></slot>
......
<template> <template>
<div class="images-list"> <div class="images-list">
<el-upload <el-upload :disabled="onlyRead" action="#" :on-remove="handleRemove" :on-exceed="handleExceed" :on-change="handleChange"
action="#" :file-list="fileList" :multiple="fileLimit > 1" :limit="fileLimit" :list-type="listType" :accept="fileAccept"
:on-remove="handleRemove" :auto-upload="false" ref="ManualUploader" :class="{ disabled: uploadDisabled }">
:on-exceed="handleExceed" <i v-if="listType === 'picture-card'" class="el-icon-plus" slot="trigger"></i>
:on-change="handleChange" <el-button v-else size="small" type="primary" >点击上传</el-button>
:file-list="fileList"
:multiple="fileLimit > 1"
:limit="fileLimit"
:list-type="listType"
:accept="fileAccept"
:auto-upload="false"
ref="ManualUploader"
:class="{ disabled: uploadDisabled }"
>
<i
v-if="listType === 'picture-card'"
class="el-icon-plus"
slot="trigger"
></i>
<el-button v-else size="small" type="primary">点击上传</el-button>
<div v-if="showTip" slot="tip" class="el-upload__tip"> <div v-if="showTip" slot="tip" class="el-upload__tip">
<div v-if="advice" style="color: #f56c6c">建议:{{ advice }}</div> <div v-if="advice" style="color: #f56c6c">建议:{{ advice }}</div>
...@@ -67,6 +52,10 @@ export default { ...@@ -67,6 +52,10 @@ export default {
advice: { advice: {
type: String, type: String,
}, },
onlyRead: {
type: Boolean,
default: false
}
}, },
data() { data() {
return { return {
...@@ -144,7 +133,7 @@ export default { ...@@ -144,7 +133,7 @@ export default {
} }
}); });
return newFileList; return newFileList;
}else{ } else {
return this.fileList; return this.fileList;
} }
}, },
...@@ -224,6 +213,7 @@ export default { ...@@ -224,6 +213,7 @@ export default {
.disabled .el-upload--picture-card { .disabled .el-upload--picture-card {
display: none !important; display: none !important;
} }
.el-upload-list__item { .el-upload-list__item {
transition: none !important; transition: none !important;
} }
......
<template>
<div class="m-video">
<video-player ref="videoPlayer" @play="autoIncrement" @timeupdate="onPlayerTimeupdate($event)"
@ready="playerReadied" :playsinline="true" :options="playerOptions">
</video-player>
</div>
</template>
<script>
export default {
props: {
src: {
type: String,
default: "",
},
},
computed: {
player() {
return this.$refs.videoPlayer.player
},
},
watch:{
src(newSrc){
console.log('newSrc',newSrc);
this.toggle(newSrc)
}
},
data() {
return {
playerOptions: {
playbackRates: [0.7, 1.0, 1.5, 2.0], // 播放速度
autoplay: false, // 如果true,浏览器准备好时开始回放。
muted: false, // 默认情况下将会消除任何音频。
loop: false, // 导致视频一结束就重新开始。
preload: "auto", // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
language: "zh-CN",
// aspectRatio: '16:9', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如'16:9'或'4:3')
fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
sources: [
{
// type: '',// 这里的种类支持很多种:基本视频格式、直播、流媒体等,具体可以参看git网址项目
type: "video/mp4",
src: this.src, // url地址
},
],
// poster: '../../static/images/test.jpg', // 你的封面地址
// width: document.documentElement.clientWidth, // 播放器宽度
notSupportedMessage: "此视频暂无法播放,请稍后再试", // 允许覆盖Video.js无法播放媒体源时显示的默认信息。
controlBar: {
timeDivider: true,
durationDisplay: true,
remainingTimeDisplay: false,
fullscreenToggle: true, // 全屏按钮
playbackRateMenuButton: true,
chaptersButton: {},
audioTrackButton: true,
descriptionsButton: true,
},
controls: true,
},
};
},
methods: {
// ------------- 当播放时 ---------------
autoIncrement(player) {
/* this.$emit('autoIncrement', player)
this.player = player */
// player.currentTime(this.playTime)
},
// ----------- 当前播放进度更新时 ---------
onPlayerTimeupdate(player) {
// console.log('当前时间', player)
// this.playTime = player.cache_.currentTime // 获取当前播放进度(时间)
},
onPlayerCanplay() {
let player = this.$refs.videoPlayer.player;
player.play();
},
playerReadied(player) { },
toggle(newSrc){
this.player.src(newSrc)
}
},
};
</script>
<style lang="scss" scoped>
.m-video {
height: 100%;
::v-deep .video-player {
height: 100%;
.video-js {
video {
// object-fit: fill;
}
&.vjs-fluid {
height: 100% !important;
padding-top: 0;
}
.vjs-big-play-button {
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.vjs-control-bar {
.vjs-icon-custombutton {
font-family: VideoJS;
font-weight: normal;
font-style: normal;
}
.vjs-icon-custombutton:before {
content: "\f108";
font-size: 1.8em;
line-height: 1.67;
}
}
}
}
}
</style>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1669855676059" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2024" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><path d="M810.96 872.17H219.11c-28.38 0-51.48-23.09-51.48-51.48V675.26c0-28.39 23.1-51.48 51.48-51.48h591.85c28.38 0 51.48 23.09 51.48 51.48v145.43c0 28.39-23.1 51.48-51.48 51.48z m-591.85-201.1c-2.27 0-4.19 1.92-4.19 4.19v145.43c0 2.23 1.96 4.19 4.19 4.19h591.85c2.23 0 4.19-1.96 4.19-4.19V675.26c0-2.27-1.92-4.19-4.19-4.19H219.11zM191.28 900.27h647.51v47.29H191.28zM515.04 533.28c-126.56 0-229.53-102.97-229.53-229.53S388.47 74.21 515.04 74.21s229.53 102.97 229.53 229.53S641.6 533.28 515.04 533.28z m0-411.78c-100.49 0-182.24 81.76-182.24 182.24s81.75 182.24 182.24 182.24 182.24-81.76 182.24-182.24S615.53 121.5 515.04 121.5z" p-id="2025"></path><path d="M348.378 650.824l11.836-194.958 47.195 2.865-11.836 194.959zM622.721 458.752l47.195-2.86 11.816 194.958-47.195 2.86z" p-id="2026"></path></svg>
\ No newline at end of file
...@@ -12,7 +12,7 @@ import Layout from '@/layout' ...@@ -12,7 +12,7 @@ import Layout from '@/layout'
// let e_new = { // let e_new = {
// path: e.path, // path: e.path,
// name: e.menuName, // name: e.menuName,
// component: resolve => e.component === Layout ? require([`@/layout`], resolve) : require([`@/views/${e.component}/index`], resolve) // component: resolve => e.component === 'Layout' ? require([`@/layout`], resolve) : require([`@/views/${e.component}/index`], resolve)
// } // }
// if (e.children) { // if (e.children) {
// const children = addRouter(e.children) // const children = addRouter(e.children)
...@@ -124,27 +124,27 @@ export function addRouter() { ...@@ -124,27 +124,27 @@ export function addRouter() {
path: 'approval', path: 'approval',
name: 'Approval', name: 'Approval',
component: () => import('@/views/approval/index'), component: () => import('@/views/approval/index'),
redirect: '/crApproval', // redirect: '/crApproval',
meta: { meta: {
title: '审批管理', title: '审批管理',
icon: 'approval' icon: 'approval'
}, },
children: [ children: [
{ // {
path: 'crApproval', // path: 'crApproval',
name: 'CrApproval', // name: 'CrApproval',
component: () => import('@/views/approval/culturalRelic.vue'), // component: () => import('@/views/approval/culturalRelic.vue'),
meta: { // meta: {
title: '文物', // title: '文物',
icon: 'culturalRelic' // icon: 'culturalRelic'
} // }
}, // },
{ {
path: 'displayApproval', path: 'displayApproval',
name: 'DisplayApproval', name: 'DisplayApproval',
component: () => import('@/views/approval/display.vue'), component: () => import('@/views/approval/display.vue'),
meta: { meta: {
title: '展览', title: '展览审批',
icon: 'display' icon: 'display'
} }
} }
......
...@@ -234,3 +234,17 @@ export function renderSize(value) { ...@@ -234,3 +234,17 @@ export function renderSize(value) {
size = size.toFixed(2);//保留的小数位数 size = size.toFixed(2);//保留的小数位数
return size + unitArr[index]; return size + unitArr[index];
} }
// 监听某元素是否在可视区,使用getBoundingClientRect
export const isElementInViewport2 = function (content) {
let scrollTop =
window.pageYOffset ||
document.documentElement.scrollTop ||
document.body.scrollTop;
let clientHeight =
document.documentElement.clientHeight || window.innerHeight;
if (content) {
return (content.offsetTop + content.offsetHeight > scrollTop &&
content.offsetTop < scrollTop + clientHeight)
}
};
<template>
<div>
<el-form :model="displayDetail" class="basic-info" ref="form">
<el-row :gutter="50">
<el-col :span="12">
<el-form-item label="展览标题" :label-width="formLabelWidth">
<el-input disabled v-model="displayDetail.title" autocomplete="off" placeholder="暂无数据"
clearable></el-input>
</el-form-item>
<el-form-item label="展览介绍" :label-width="formLabelWidth">
<div style="background-color: #F5F7FA;border:1px solid #E4E7ED;color: #C0C4CC;padding: 0 10px;border-radius: 4px;"
v-html="displayDetail.intro"></div>
</el-form-item>
<el-form-item label="展览单位" :label-width="formLabelWidth">
<el-cascader disabled style="width: 100%" v-model="displayDetail.deptId" :options="orgTreeData"
:props="optionProps" placeholder="暂无数据" clearable>
</el-cascader>
</el-form-item>
<el-form-item label="展览地区" :label-width="formLabelWidth">
<el-cascader disabled class="years item" style="width: 100%" v-model="displayDetail.regionCode"
:options="regionTree" :props="culturalRegionProps" placeholder="暂无数据" filterable clearable>
</el-cascader>
</el-form-item>
<el-form-item label="展览类型" :label-width="formLabelWidth">
<el-select disabled v-model="displayDetail.type" placeholder="暂无数据" style="width: 100%"
clearable>
<el-option v-for="(value, key) in dicts.displayType" :key="key" :label="value" :value="key">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="展览性质" :label-width="formLabelWidth" style="display: none">
<el-select disabled v-model="displayDetail.displayCharacter" placeholder="暂无数据"
style="width: 100%" clearable>
<el-option v-for="(value, key) in dicts.displayCharacter" :key="key" :label="value"
:value="key">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="模板主题" :label-width="formLabelWidth">
<el-select disabled v-model="displayDetail.themeType" placeholder="暂无数据" style="width: 100%"
clearable>
<el-option v-for="item in themeTypeOptions" :key="item.value" :label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="关键词" :label-width="formLabelWidth">
<el-input disabled v-model="displayDetail.keyword" autocomplete="off" placeholder="暂无数据"
clearable></el-input>
</el-form-item>
<el-form-item label="展览文物" :label-width="formLabelWidth">
<el-select disabled v-model="crIds" multiple filterable remote reserve-keyword
placeholder="暂无数据" style="width: 100%" clearable>
<el-option v-for="item in crList" :key="item.crId" :label="item.name" :value="item.crId">
</el-option>
</el-select>
<!-- <PageSelect
ref="PageSelect"
label="name"
value="crId"
:select.sync="value"
:url="pageSelectUrl"
filter-key="name"
/> -->
</el-form-item>
<el-form-item label="关联文献" :label-width="formLabelWidth">
<el-select disabled v-model="literatureValues" multiple filterable remote reserve-keyword
placeholder="暂无数据" style="width: 100%" ref="literatureSelect" clearable>
<el-option v-for="item in literatureList" :key="item.literatureId" :label="item.name"
:value="item.literatureId">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="关联虚拟展厅" :label-width="formLabelWidth">
<el-select disabled v-model="vrIds" multiple filterable remote reserve-keyword
placeholder="暂无数据" style="width: 100%" ref="virtualSelect" clearable>
<el-option v-for="item in vrList" :key="item.bvId" :label="item.name" :value="item.bvId">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="是否上架" :label-width="formLabelWidth">
<el-switch v-model="displayDetail.status" disabled> </el-switch>
</el-form-item>
<el-form-item label="备注" :label-width="formLabelWidth">
<el-input disabled type="textarea" placeholder="暂无数据" v-model="displayDetail.remark"
maxlength="100" show-word-limit clearable>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="展览封面" :label-width="formLabelWidth">
<div v-if="displayDetail.faceImagePressUrl" class="img-container">
<img :src="displayDetail.faceImagePressUrl" alt="">
</div>
<div v-else>
暂无封面
</div>
</el-form-item>
<el-form-item label="展览图片" :label-width="formLabelWidth">
<div class="images-group" v-if="displayDetail.imagesVo.length > 0">
<div class="img-container" v-for="(item, index) in displayDetail.imagesVo" :key="index">
<img :src="item.pressUrl" alt="">
</div>
</div>
<div v-else>
暂无展览图片
</div>
</el-form-item>
<el-form-item label="展览音频" :label-width="formLabelWidth">
<div class="images-group" v-if="displayDetail.imagesVo.length > 0">
<div class="img-container" v-for="(item, index) in displayDetail.imagesVo" :key="index">
</div>
</div>
<div v-else>
暂无展览音频
</div>
</el-form-item>
<el-form-item label="展览视频" :label-width="formLabelWidth">
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-form-item label="展览单元" :label-width="formLabelWidth">
<ExhibitionUnit :exhibitionUnits="displayDetail.exhibitionUnits" ref="exhibitionUnits" />
</el-form-item>
</el-row>
</el-form>
</div>
</template>
<script>
import { themeTypeOptions } from "@/views/display/contants";
import ManualUploader from "@/components/Uploader/ManualUploader.vue";
import ExhibitionUnit from "@/views/display/components/ExhibitionUnit.vue";
export default {
name: 'BaseInfo',
components: {
ExhibitionUnit,
ManualUploader
},
props: {
displayDetail: {
type: Object,
default: () => ({})
},
dicts: {
type: Object,
default: () => ({})
},
},
computed: {
themeTypeOptions() {
return themeTypeOptions;
},
},
watch: {
displayDetail(value) {
if (Object.key(value).length == 0) {
return
}
// // 回填媒体资源
// if (
// this.displayDetail.faceImageUrl ||
// this.displayDetail.faceImagePressUrl
// ) {
// this.faceImage = [
// {
// name: "",
// url: this.displayDetail.faceImageUrl || "",
// pressUrl:
// this.displayDetail.faceImagePressUrl ||
// this.displayDetail.faceImageUrl ||
// "",
// fileId: this.displayDetail.faceImage || "",
// },
// ];
// } else {
// this.faceImage = [];
// }
// this.images = this.displayDetail.imagesVo || [];
// this.videos = this.displayDetail.videosVo || [];
// this.audios = this.displayDetail.audiosVo || [];
// 回填状态
this.dialogForm.status = Boolean(Number(this.dialogForm.status));
// 回填文献
this.literatureValues = [];
if (
this.dialogForm.literatureVo &&
this.dialogForm.literatureVo.length > 0
) {
this.literatureList = this.dialogForm.literatureVo;
this.dialogForm.literatureVo.forEach((lt) => {
if (this.literatureValues) {
this.literatureValues.push(lt.literatureId);
}
});
}
// 回填文物
this.crIds = [];
if (
this.dialogForm.culturalRelicVo &&
this.dialogForm.culturalRelicVo.length > 0
) {
this.crList = this.dialogForm.culturalRelicVo;
this.dialogForm.culturalRelicVo.forEach((cr) => {
if (this.crIds) {
this.crIds.push(cr.crId);
}
});
}
// 回填虚拟展厅
this.vrIds = [];
if (
this.dialogForm.virtualVo &&
this.dialogForm.virtualVo.length > 0
) {
this.vrList = this.dialogForm.virtualVo;
this.dialogForm.virtualVo.forEach((vr) => {
if (this.vrIds) {
this.vrIds.push(vr.bvId);
}
});
}
}
},
data() {
return {
formLabelWidth: "100px",
orgTreeData: [],
regionTree: [],
optionProps: {
value: "id",
label: "name",
children: "children",
checkStrictly: true,
},
culturalRegionProps: {
value: "code",
label: "name",
children: "children",
checkStrictly: true,
},
faceImage: [],
images: [],
videos: [],
audios: [],
literatureList: [], //文献列表
literatureValues: [], //选中的文献列表
crList: [], //文物列表
crIds: [], //选中的文物列表
vrList: [], //虚拟展厅列表
vrIds: [],
}
},
async created() {
await this.$store.dispatch("dict/getDictList", [
"displayType",
"displayCharacter",
]);
this.$store.dispatch("org/getMuseumTreeData", false).then((res) => {
// this.orgTreeData = res[0].children; //去掉根节点的文旅厅
this.orgTreeData = res;
});
this.loadRegionTree();
},
methods: {
loadRegionTree() {
let parentId = "";
this.$store.dispatch("org/getSysRegionTreeData", parentId).then((res) => {
this.regionTree = res;
loopTree(this.regionTree);
function loopTree(arr) {
if (arr && arr.length > 0) {
arr.forEach((item) => {
if (item.children && item.children.length == 0) {
delete item.children;
} else {
loopTree(item.children);
}
});
}
}
});
},
}
}
</script>
<style lang="scss" scoped>
.img-container {
background-color: #fbfdff;
border: 1px dashed #c0ccda;
border-radius: 6px;
box-sizing: border-box;
width: 148px;
height: 148px;
cursor: pointer;
}
</style>
\ No newline at end of file
<template>
<el-dialog :visible.sync="dialogVisible" width="80%" style="height: 98%" :before-close="handleClose" top="5vh"
lock-scroll>
<div class="title" slot="title">
<div class="divider"></div>
<div class="label">{{ title }}</div>
</div>
<div class="dialog-content">
<el-descriptions class="margin-top" title="文物详情" :column="3" :size="size" border>
<template slot="extra">
<el-button type="primary" size="small">同意</el-button>
<el-button type="danger" size="small">驳回</el-button>
</template>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-user"></i>
文物名称
</template>
{{crDetail.name}}
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-mobile-phone"></i>
馆藏介绍
</template>
18100000000
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-mobile-phone"></i>
文物封面
</template>
18100000000
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-mobile-phone"></i>
文物图片
</template>
18100000000
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-mobile-phone"></i>
文物视频
</template>
18100000000
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-mobile-phone"></i>
文物音频
</template>
18100000000
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-mobile-phone"></i>
馆藏单位
</template>
18100000000
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-location-outline"></i>
文物类别
</template>
苏州市
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-tickets"></i>
文物质地
</template>
<el-tag size="small">学校</el-tag>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-office-building"></i>
文物年代
</template>
江苏省苏州市吴中区吴中大道 1188 号
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-office-building"></i>
文物级别
</template>
江苏省苏州市吴中区吴中大道 1188 号
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-office-building"></i>
文物数量
</template>
江苏省苏州市吴中区吴中大道 1188 号
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-office-building"></i>
关联文献
</template>
江苏省苏州市吴中区吴中大道 1188 号
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-office-building"></i>
主题词
</template>
江苏省苏州市吴中区吴中大道 1188 号
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-office-building"></i>
3durl链接
</template>
江苏省苏州市吴中区吴中大道 1188 号
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">
<i class="el-icon-office-building"></i>
备注
</template>
江苏省苏州市吴中区吴中大道 1188 号
</el-descriptions-item>
</el-descriptions>
<div class="dialog-footer">
<el-button type="primary" @click="handleClose">关闭</el-button>
</div>
</div>
</el-dialog>
</template>
<script>
import { mapGetters } from "vuex";
export default {
name: "PreviewDialog",
components: {
},
props: {
visible: {
type: Boolean,
default: false,
},
crDetail: {
type: Object,
default: () => ({}),
},
},
computed: {
...mapGetters(["dicts"]),
title() {
return "预览——" + this.crDetail.name;
},
},
watch: {
visible: {
handler: function (value) {
this.dialogVisible = value;
},
immediate: true,
deep: true,
},
},
data() {
return {
dialogVisible: false,
};
},
async mounted() {
await this.$store.dispatch("dict/getDictList", [
"displayType",
"displayCharacter",
]);
},
methods: {
handleClose(done) {
this.$emit("handleClose");
},
},
};
</script>
<style lang='scss' scoped>
.title {
display: flex;
margin-bottom: 16px;
.divider {
width: 8px;
border-left: 4px solid #409eff;
margin-right: 8px;
}
.label {
font-weight: bold;
}
}
.dialog-content {
padding: 0 32px;
display: flex;
flex-direction: column;
.relate {
flex: 1;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
margin-top: 40px;
}
}
.video-container {
background-color: #000;
display: flex;
justify-content: center;
}
.el-dialog__body {
padding: 0 20px 30px 20px;
}
</style>
\ No newline at end of file
<template>
<el-dialog :visible.sync="dialogVisible" width="80%" :before-close="handleClose" top="5vh" lock-scroll>
<div class="title" slot="title">
<div class="divider"></div>
<div class="label">{{ title }}</div>
</div>
<div class="dialog-content">
<el-tabs v-model="activeName">
<el-tab-pane label="基本信息" name="info">
<BaseInfo :displayDetail="displayDetail" :dicts="dicts" />
</el-tab-pane>
<el-tab-pane label="效果预览" name="page">
<div class="container" v-if="dicts">
<NormalStyle v-if="displayDetail.themeType == '1'" :displayDetail="displayDetail" :dicts="dicts" />
<ChStyle v-if="displayDetail.themeType == '2'" :displayDetail="displayDetail" :dicts="dicts" />
<RedStyle v-if="displayDetail.themeType == '3'" :displayDetail="displayDetail" :dicts="dicts" />
</div>
</el-tab-pane>
<el-tab-pane label="审批历史记录" name="history">
<div class="container">
<el-steps :active="displayDetail.historyChecks.length" align-center>
<el-step v-for="(item, index) in displayDetail.historyChecks" :title="getStepTitle(item)" :key="index"
:icon="getStepIcon(item)">
<div slot="description">
<div class="name">{{ item.createName }}</div>
<div class="time">{{ item.createTime }}</div>
<div class="desc">{{ item.remark }}</div>
</div>
</el-step>
</el-steps>
</div>
</el-tab-pane>
</el-tabs>
<div class="dialog-footer">
<el-button @click="handleClose" style="margin-right:6px">取消</el-button>
<el-popover placement="top-end" width="400" trigger="click">
<div>
<el-form :model="dialogForm">
<el-form-item label="驳回意见" prop="remark">
<el-input placeholder="驳回意见" v-model="dialogForm.remark" size="small">
<el-button type="primary" slot="append" @click.native="handleCheck(-2)">确定</el-button>
</el-input>
</el-form-item>
</el-form>
</div>
<el-button slot="reference" type="danger" icon="el-icon-close">驳回</el-button>
</el-popover>
<el-button style="margin-left:6px" type="primary" icon="el-icon-check"
@click.native="handleCheck(1)">同意</el-button>
</div>
</div>
</el-dialog>
</template>
<script>
import NormalStyle from "@/views/display/components/templates/NormalStyle.vue";
// import NormalStyle from "./components/NormalStyle.vue";
import ChStyle from "@/views/display/components/templates/ChStyle.vue";
import RedStyle from "@/views/display/components/templates/RedStyle.vue";
import BaseInfo from './BaseInfo'
import { mapGetters } from "vuex";
import { postCheck } from '@/api/display'
export default {
name: "PreviewDialog",
components: {
NormalStyle,
ChStyle,
RedStyle,
BaseInfo
},
props: {
visible: {
type: Boolean,
default: false,
},
displayDetail: {
type: Object,
default: () => ({}),
},
},
computed: {
...mapGetters(["dicts"]),
title() {
return "审批——" + this.displayDetail.title;
},
getStepTitle(item) {
return (item) => {
switch (item.checkStatus) {
case 0:
return '发起审核'
case 1:
return '审核通过'
case -2:
return '驳回'
}
}
},
getStepIcon(item) {
return (item) => {
switch (item.checkStatus) {
case 0:
return 'el-icon-s-check'
case 1:
return 'el-icon-s-claim'
case -2:
return 'el-icon-circle-close'
}
}
},
},
watch: {
visible: {
handler: function (value) {
this.dialogVisible = value;
},
immediate: true,
deep: true,
},
},
data() {
return {
dialogVisible: false,
dialogForm: {
remark: '',//驳回意见
},
activeName: 'info'
};
},
async mounted() {
await this.$store.dispatch("dict/getDictList", [
"displayType",
"displayCharacter",
]);
console.log('this.dicts',this.dicts);
},
methods: {
handleClose(done) {
this.$emit("handleClose");
},
handleCheck(checkStatus) {
console.log('checkStatus', checkStatus);
// postCheck()
}
},
};
</script>
<style lang='scss' scoped>
.title {
display: flex;
margin-bottom: 16px;
.divider {
width: 8px;
border-left: 4px solid #409eff;
margin-right: 8px;
}
.label {
font-weight: bold;
}
}
.dialog-content {
padding: 0 32px;
.container {
border: 1px dashed #409eff;
height: calc(64vh);
overflow: auto;
padding: 16px 0;
.desc {
color: #666 !important;
}
.name {
color: #333 !important;
}
.time {
color: #999 !important;
}
}
}
::v-deep .el-dialog__wrapper {
overflow: hidden !important;
}
::v-deep .el-step__title {
color: #333;
font-weight: bold;
}
// ::v-deep .el-dialog__body {
// position: relative;
// }
.dialog-footer {
display: flex;
justify-content: flex-end;
margin-top: 40px;
// position: absolute;
// width:100%;
bottom: 0;
position: sticky;
// height: 100px;
}
// ::v-deep .el-dialog__footer {
// position: sticky !important;
// }
.video-container {
background-color: #000;
display: flex;
justify-content: center;
}
.el-dialog__body {
padding: 0 20px 30px 20px;
}
</style>
\ No newline at end of file
export const title = [{ export const displayTabletitle = [{
prop: "title", prop: "title",
label: "标题", label: "标题",
columnAlign: 'center', columnAlign: 'center',
width: 120, width: 120,
showOverFlowToolTip: true, showOverFlowToolTip: true,
}, },
// {
// prop: "keyword",
// label: "关键词",
// columnAlign: 'center',
// showOverFlowToolTip: true,
// },
{ {
prop: "keyword", prop: "deptName",
label: "关键词", label: "展览单位",
columnAlign: 'center', columnAlign: 'center', showOverFlowToolTip: true,
showOverFlowToolTip: true,
}, },
{ {
prop: "type", prop: "type",
...@@ -19,7 +24,6 @@ export const title = [{ ...@@ -19,7 +24,6 @@ export const title = [{
showOverFlowToolTip: true, showOverFlowToolTip: true,
}, },
{ {
prop: "faceImageUrl", prop: "faceImageUrl",
label: "封面", label: "封面",
...@@ -28,19 +32,17 @@ export const title = [{ ...@@ -28,19 +32,17 @@ export const title = [{
width: 130 width: 130
}, },
{ {
prop: "remark", prop: "checkStatus",
label: "备注", label: "状态",
columnAlign: 'center', showOverFlowToolTip: true, columnAlign: 'center',
}, },
{ {
prop: "status", prop: "checkRemark",
label: "状态", label: "备注",
columnAlign: 'center', columnAlign: 'center',
isStatus: true showOverFlowToolTip: true,
}, },
] ]
export const operates = { export const operates = {
...@@ -52,10 +54,137 @@ export const operates = { ...@@ -52,10 +54,137 @@ export const operates = {
columnAlign: "center", columnAlign: "center",
} }
export const operations = [{ export const approvalOperations = [{
type: 'approval', type: 'approval',
title: '审批' title: '审批'
} }
] ]
export const viewOperations = [{
type: 'view',
title: '查看详情'
}
]
export const crTabletitle = [{
prop: "name",
label: "名称",
columnAlign: 'center',
showOverFlowToolTip: true,
},
// {
// prop: "level",
// label: "文物级别",
// columnAlign: 'center',
// },
// {
// prop: "detailSize",
// label: "尺寸",
// columnAlign: 'center',
// },
// {
// prop: "textureType",
// label: "质地",
// columnAlign: 'center',
// },
// {
// prop: "type",
// label: "类别",
// width: 100,
// columnAlign: 'center',
// isCulturalRelicType:true
// },
// {
// prop: "createId",
// label: "创建人",
// columnAlign: 'center',
// },
// {
// prop: "createTime",
// label: "创建时间",
// columnAlign: 'center',
// },
{
prop: "deptName",
label: "馆藏单位",
columnAlign: 'center',
showOverFlowToolTip: true,
},
{
prop: "regionName",
label: "所属地",
columnAlign: 'center',
showOverFlowToolTip: true,
},
// {
// prop: "intro",
// label: "馆藏介绍",
// columnAlign: 'center',
// showOverFlowToolTip: true,
// width: 120,
// },
{
prop: "themeWord",
label: "主题词",
columnAlign: 'center',
showOverFlowToolTip: true,
},
{
prop: "faceImageUrl",
label: "封面",
columnAlign: 'center',
isFaceImage: true,
},
{
prop: "status",
label: "上下架状态",
width: 100,
columnAlign: 'center',
isStatus: true
},
{
prop: "num",
label: "数量",
columnAlign: 'center',
},
{
prop: "sourceWay",
label: "来源方式",
columnAlign: 'center',
showOverFlowToolTip: true,
},
{
prop: "remark",
label: "备注",
columnAlign: 'center',
},
// directory 文件夹
// flag3d 是否有3d图片
// updateId 更新人
]
export const importOperates = {
operate: true,
label: "操作",
width: "220px",
minwidth: "220px",
titleAlign: "center",
columnAlign: "center",
}
export const importOperations = [{
type: 'delete',
title: '删除记录及文物'
},]
\ No newline at end of file
<template> <template>
<div class="app-container"> <div class="app-container">
<div class="top-bar"> <div class="top-bar">
<SearchBar :config="searchConfig" @search="search" @reset="reset" /> <SearchBar :config="searchConfig" @search="search" @reset="reset" />
<!-- <el-button <!-- <el-button
type="primary" type="primary"
@click.native="handleOperation({ type: 'add' })" @click.native="handleOperation({ type: 'add' })"
icon="el-icon-plus" icon="el-icon-plus"
>
发布</el-button
>
</div> -->
<!-- <el-button type="primary" @click.native="handleCopy">复制</el-button> -->
</div>
<TablePage
:data="list.records"
:tableTitle="tableTitle"
:operates="tableOperates"
> >
<template v-slot:status="data"> 发布</el-button
<el-popconfirm
:title="getStatusTitle(data.scope.status)"
@onConfirm="handleChangeStatus(data.scope)"
>
<el-switch
slot="reference"
:value="Boolean(Number(data.scope.status))"
></el-switch>
</el-popconfirm>
</template>
<template v-slot:displayType="data">
{{ dicts.displayType[data.scope.type] }}
</template>
<template v-slot:faceImageUrl="data">
<img
:src="
$getFullUrl(data.scope.faceImagePressUrl || data.scope.faceImageUrl)
"
alt="暂无图片"
v-if="
$getFullUrl(data.scope.faceImagePressUrl || data.scope.faceImageUrl)
"
style="cursor: pointer"
width="100px"
@click="handelPreviewImages(data.scope.faceImageUrl)"
/>
</template>
<template v-slot:operates="scope">
<TableOperation
:operations="tableOperations"
:rawData="scope.scope.row"
@handleOperation="handleOperation"
></TableOperation>
</template>
</TablePage>
<el-pagination
style="margin: 16px 0"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="Number(list.current)"
:page-sizes="[10, 20, 50, 100]"
:page-size="Number(list.size)"
layout="total, sizes, prev, pager, next, jumper"
:total="Number(list.total)"
class="pagination"
> >
</el-pagination> </div> -->
<InfoEditDialog
:visible="editDialogVisible"
:form="form"
:currentPageIds="currentPageIds"
@handleClose="handleClose"
@refresh="loadData"
@changeDisplay="reloadDisplay"
ref="InfoEditDialog"
/>
<PreviewDialog
v-if="Object.keys(curPreviewObj).length > 0"
:visible="previewDialogVisible"
:displayDetail="curPreviewObj"
@handleClose="handleClosePreviewDialog"
/>
<!-- <CopyDialog
:visible="copyDialogVisible"
@handleClose="handleCloseCopyDialog"
@handleCopySelect="handleCopySelect"
:list="list"
/> -->
<el-image-viewer
v-if="imgViewerVisible"
:on-close="closeImgViewer"
:url-list="imgList"
/>
</div> </div>
</template> <TablePage
:data="list.records"
<script> :tableTitle="tableTitle"
import TablePage from "@/components/Table/TablePage.vue"; :operates="tableOperates"
import TableOperation from "@/components/Table/TableOperation.vue"; >
import { title, operates, operations } from "./config"; <template v-slot:status="data">
import { <el-popconfirm
getListPer, :title="getStatusTitle(data.scope.status)"
deleteDisplay, @onConfirm="handleChangeStatus(data.scope)"
getDisplayById, >
editDisplay, <el-switch
} from "@/api/display"; slot="reference"
// import CopyDialog from "./components/CopyDialog"; :value="Boolean(Number(data.scope.status))"
import SearchBar from "@/components/SearchBar"; ></el-switch>
import { mapGetters } from "vuex"; </el-popconfirm>
import { getToken } from "@/utils/auth"; </template>
import { importZip } from "@/utils/file"; <template v-slot:displayType="data">
export default { {{ dicts.displayType[data.scope.type] }}
components: { </template>
TablePage, <template v-slot:faceImageUrl="data">
TableOperation, <img
SearchBar, :src="
"el-image-viewer": () => $getFullUrl(data.scope.faceImagePressUrl || data.scope.faceImageUrl)
import("element-ui/packages/image/src/image-viewer"), "
}, alt="暂无图片"
data() { v-if="
let that = this; $getFullUrl(data.scope.faceImagePressUrl || data.scope.faceImageUrl)
return { "
list: { style="cursor: pointer"
record: [], width="100px"
size: 10, @click="handelPreviewImages(data.scope.faceImageUrl)"
current: 1, />
total: 0, </template>
}, <template v-slot:operates="scope">
searchForm: { <TableOperation
name: "", :operations="tableOperations"
status: "", :rawData="scope.scope.row"
}, @handleOperation="handleOperation"
searchConfig: [ ></TableOperation>
{ </template>
prop: "title", </TablePage>
type: "input", <el-pagination
label: "展览名称", style="margin: 16px 0"
}, @size-change="handleSizeChange"
{ @current-change="handleCurrentChange"
prop: "status", :current-page="Number(list.current)"
type: "select", :page-sizes="[10, 20, 50, 100]"
label: "状态", :page-size="Number(list.size)"
selectOptions: [ layout="total, sizes, prev, pager, next, jumper"
{ :total="Number(list.total)"
label: "已上线", class="pagination"
value: "1", >
}, </el-pagination>
{ <PreviewCrDialog
label: "已下线", v-if="Object.keys(curPreviewObj).length > 0"
value: "0", :visible="previewDialogVisible"
}, :displayDetail="curPreviewObj"
], @handleClose="handleClosePreviewDialog"
}, />
], <!-- <CopyDialog
editDialogVisible: false, :visible="copyDialogVisible"
isAdd: true, @handleClose="handleCloseCopyDialog"
form: { @handleCopySelect="handleCopySelect"
title: "", //标题 :list="list"
type: "", // 类别(待定)--枚举值(社会、生活等) /> -->
displayCharacter: "1", //展览性质(精品展2、布展1、文物展3)--此处填写布展类别 <el-image-viewer
keyword: "", // 关键词 v-if="imgViewerVisible"
deptId: "", //展览单位id--暂填入用户自己的单位 :on-close="closeImgViewer"
regionCode: "", // 所在地域--暂填入用户自己的地区 :url-list="imgList"
intro: "", //展览介绍, />
themeType: "1", //模板主题--前端枚举 </div>
literature: "", //关联文献。id1,id2,id3--接口查询 </template>
remark: "", //备注
status: 1, //上下架状态(0-下架,1-上架) <script>
faceImage: "", // 封面(图片1张) import TablePage from "@/components/Table/TablePage.vue";
images: "", //展览图片 import TableOperation from "@/components/Table/TableOperation.vue";
videos: "", //展览视频 import PreviewCrDialog from './components/PreviewCrDialog.vue'
audios: "", //展览音频 import { crTabletitle, operates, operations } from "./config";
exhibitionUnits: [], //布展单元 import {
getListPer,
getDisplayById,
editDisplay,
} from "@/api/display";
import SearchBar from "@/components/SearchBar";
import { mapGetters } from "vuex";
import { getToken } from "@/utils/auth";
import { importZip } from "@/utils/file";
export default {
components: {
TablePage,
TableOperation,
SearchBar,
PreviewCrDialog,
"el-image-viewer": () =>
import("element-ui/packages/image/src/image-viewer"),
},
data() {
let that = this;
return {
list: {
record: [],
size: 10,
current: 1,
total: 0,
},
searchForm: {
name: "",
status: "",
},
searchConfig: [
{
prop: "title",
type: "input",
label: "文物名称",
}, },
loading: false, {
imgViewerVisible: false, prop: "status",
previewDialogVisible: false, type: "select",
copyDialogVisible: false, label: "状态",
previewVideos: [], selectOptions: [
displayTypes: {}, {
curPreviewObj: {}, //当前预览的对象 label: "已上线",
currentPageIds: [], //当前的id数组,用于给详情页切换用 value: "1",
importZipUrl: process.env.VUE_APP_BASE_API + "/bizImport/importZip", },
headers: { {
authorization: getToken(), label: "已下线",
value: "0",
},
],
}, },
multiUploadVisible: false, //控制批量上传弹窗显示 ],
importRecordVisible: false, //上传记录 editDialogVisible: false,
filesList: [], //上传当中的文件队列 isAdd: true,
uploadCount: 0, //处于上传中的文件数量,当等于fileList的时候就关闭弹窗,请求完毕一个就++ form: {
cancelUploadArr: [], //保存每个文件上传接口对应的取消请求的函数[fn,fn,fn...] title: "", //标题
isUpLoading: false, type: "", // 类别(待定)--枚举值(社会、生活等)
}; displayCharacter: "1", //展览性质(精品展2、布展1、文物展3)--此处填写布展类别
keyword: "", // 关键词
deptId: "", //展览单位id--暂填入用户自己的单位
regionCode: "", // 所在地域--暂填入用户自己的地区
intro: "", //展览介绍,
themeType: "1", //模板主题--前端枚举
literature: "", //关联文献。id1,id2,id3--接口查询
remark: "", //备注
status: 1, //上下架状态(0-下架,1-上架)
faceImage: "", // 封面(图片1张)
images: "", //展览图片
videos: "", //展览视频
audios: "", //展览音频
exhibitionUnits: [], //布展单元
},
loading: false,
imgViewerVisible: false,
previewDialogVisible: false,
curPreviewObj: {}, //当前预览的对象
currentPageIds: [], //当前的id数组,用于给详情页切换用
importZipUrl: process.env.VUE_APP_BASE_API + "/bizImport/importZip",
headers: {
authorization: getToken(),
},
multiUploadVisible: false, //控制批量上传弹窗显示
importRecordVisible: false, //上传记录
filesList: [], //上传当中的文件队列
uploadCount: 0, //处于上传中的文件数量,当等于fileList的时候就关闭弹窗,请求完毕一个就++
cancelUploadArr: [], //保存每个文件上传接口对应的取消请求的函数[fn,fn,fn...]
isUpLoading: false,
};
},
computed: {
...mapGetters(["dicts"]),
tableTitle() {
return crTabletitle;
}, },
computed: { tableOperates() {
...mapGetters(["dicts"]), return operates;
tableTitle() {
return title;
},
tableOperates() {
return operates;
},
tableOperations() {
return operations;
},
getStatusTitle(status) {
return (status) => {
if (Number(status)) {
return "是否确定要下架?";
} else {
return "是否确定要上架?";
}
};
},
}, },
tableOperations() {
async created() { return operations;
await this.$store.dispatch("dict/getDictList", ["displayType"]);
this.loadData();
}, },
getStatusTitle(status) {
//watch部分 return (status) => {
watch: { if (Number(status)) {
//监听弹窗变化 return "是否确定要下架?";
multiUploadVisible(val) {
//弹窗关闭记得清空,开启执行批量上传
if (val) {
for (let i = 0; i < this.filesList.length; i++) {
this.uploadSelf(this.filesList[i].file, i); //弹窗显示的时候,就根据文件队列的数量调用上传接口
}
} else { } else {
//弹窗关闭,还原数据到初始位置 return "是否确定要上架?";
this.filesList = [];
this.uploadCount = 0;
this.cancelUploadArr = [];
} }
}, };
}, },
methods: { },
async search(form) {
var params = { async created() {
page: 1, await this.$store.dispatch("dict/getDictList", ["displayType"]);
limit: this.list.size, this.loadData();
...form, },
};
if (params.status == "") { //watch部分
delete params.status; watch: {
} //监听弹窗变化
let res = await getListPer(params); multiUploadVisible(val) {
if (res.code == 0) { //弹窗关闭记得清空,开启执行批量上传
this.list = res.data; if (val) {
this.currentPageIds = this.list.records.map((item) => { for (let i = 0; i < this.filesList.length; i++) {
return item.exhibitionId; this.uploadSelf(this.filesList[i].file, i); //弹窗显示的时候,就根据文件队列的数量调用上传接口
});
}
},
reset() {
this.loadData();
},
// 加载表格数据
async loadData() {
var params = {
page: this.list.current,
limit: this.list.size,
};
let res = await getListPer(params);
if (res.code == 0) {
this.list = res.data;
this.currentPageIds = this.list.records.map((item) => {
return item.exhibitionId;
});
}
},
async handleOperation(value, row) {
switch (value.type) {
case "add":
this.editDialogVisible = true;
case "view":
if (row) {
this.previewDialogVisible = true;
let res = await getDisplayById({ exhibitionId: row.exhibitionId });
this.curPreviewObj = res.data;
}
break;
case "edit":
let editRes = await getDisplayById({
exhibitionId: row.exhibitionId,
});
this.form = editRes.data;
this.editDialogVisible = true;
break;
case "delete":
let deleteRes = await deleteDisplay([row.exhibitionId]);
if (deleteRes.code === 0) {
this.loadData();
this.$message.success("删除成功!");
}
break;
case "multiAdd":
// debugger
// this.multiUploadVisible = true;
// console.log("this.multiUploadVisible", this.multiUploadVisible);
break;
case "downloadTemplate":
this.handleDownloadTemplate();
break;
case "viewImportRecord":
this.importRecordVisible = true;
break;
}
},
//下载批量导入模板
handleDownloadTemplate() {
let a = document.createElement("a");
a.href = "./static/展览导入模板.zip";
a.download = "展览整量导入模板.zip";
a.style.display = "none";
document.body.appendChild(a);
a.click();
a.remove();
},
uploadSelf(file, index) {
let formData = new FormData();
formData.append("type", "biz_exhibition");
formData.append("zipFile", file);
importZip(
formData,
(progressEvent) => this.uploadUnderWayCallback(progressEvent, index),
(c) => this.cancelCallBack(c, index)
).then((res) => {
if (res.data.code == 0) {
this.$set(this.filesList[index], "status", "success");
this.$set(this.filesList[index], "desc", "上传成功");
this.$message.success("文件" + file.name + "上传成功!");
this.loadData()
} else {
this.$set(this.filesList[index], "status", "warning");
this.$set(this.filesList[index], "desc", "上传失败" + res.data.msg);
this.$message.error("上传失败:" + res.data.msg);
this.loadData();
}
});
},
// 文件上传进度回调
uploadUnderWayCallback(progressEvent, index) {
let completeVal =
(progressEvent.loaded / progressEvent.total) * 100 - 1 || 0; //处理成组件库进度组件需要的格式
this.$set(this.filesList[index], "percent", Math.floor(completeVal)); //直接改变数组某一项不是响应式的,因此我们需要用到这个api,将其响应式化,添加到数组中
},
// 文件取消回调
cancelCallBack(c, index) {
this.$set(this.cancelUploadArr, index, c); //添加取消队列中,关闭弹窗批量取消
this.uploadCount = 0;
},
handleMultiUploadClose() {
// 文件列表中如果Status为null,则代表有仍在上传中
let isUpLoading = false;
this.filesList.map((item) => {
if (item.status == null) {
isUpLoading = true;
return;
}
});
let title = isUpLoading ? "当前有上传任务,是否取消上传" : "确认关闭?";
let confirmButtonText = isUpLoading ? "关闭并取消上传" : "确定";
let cancelButtonText = isUpLoading ? "否" : "取消";
let that = this;
this.$confirm(title, "提示", {
confirmButtonText,
cancelButtonText,
type: "warning",
})
.then(() => {
// 点击取消上传
if (that.isUpLoading) {
this.handleCancelAllUpLoad();
this.$message.warning("已取消上传!");
}
this.multiUploadVisible = false; //最后关闭
})
.catch(() => {
console.log("用户取消操作");
});
},
handleMultiUploadCancel(index) {
if (this.cancelUploadArr[index]) {
this.cancelUploadArr[index](); //取消上传
this.cancelUploadArr.splice(index, 1); //从取消队列中删除
}
if (this.filesList[index]) {
this.filesList.splice(index, 1);
} }
this.$message.info("已取消上传!"); } else {
}, //弹窗关闭,还原数据到初始位置
handleCancelAllUpLoad() {
this.cancelUploadArr.forEach((cancelCallBack) => cancelCallBack()); //批量取消上传
},
handleSuccess(res) {
res.Success && this.$Message.success("上传成功"); //提示
// this.processModal = false; //成功后关闭弹窗
this.filesList = []; this.filesList = [];
}, this.uploadCount = 0;
this.cancelUploadArr = [];
async reloadDisplay(exhibitionId) { }
this.$refs.InfoEditDialog.submitLoading = true; },
this.$refs.InfoEditDialog.loadingText = "加载中..."; },
let editRes = await getDisplayById({ methods: {
exhibitionId, async search(form) {
}); var params = {
this.form = editRes.data; page: 1,
this.$refs.InfoEditDialog.submitLoading = false; limit: this.list.size,
}, ...form,
async handleChangeStatus(row) { };
const { status } = row; if (params.status == "") {
let newStatus = status === "0" ? "1" : "0"; delete params.status;
const params = { }
...row, let res = await getListPer(params);
status: newStatus, if (res.code == 0) {
}; this.list = res.data;
let res = await editDisplay(params); this.currentPageIds = this.list.records.map((item) => {
if (res.code == 0) { return item.exhibitionId;
this.loadData();
this.$message.success("修改成功!");
}
},
// 多选
handleSelectionChange(val) {
this.multipleSelection = val;
},
// 改变页容量
handleSizeChange(value) {
this.list.size = value;
this.loadData();
},
// 改变当前显示页
handleCurrentChange(value) {
this.list.current = value;
this.loadData();
},
// 搜索
onSubmitSearch() {
console.log("submit!");
},
// 关闭Dialog
handleClose() {
this.editDialogVisible = false;
this.form = {
status: 1,
faceImage: "", // 封面(图片1张)
images: "", //展览图片
videos: "", //展览视频
audios: "", //展览音频
exhibitionUnits: [], //布展单元
};
},
// 关闭预览图片
closeImgViewer() {
this.imgViewerVisible = false;
},
// 预览图片
handelPreviewImages(images) {
this.imgViewerVisible = true;
this.imgList = [images];
},
handleClosePreviewDialog() {
this.previewDialogVisible = false;
},
handleCopy() {
this.copyDialogVisible = true;
},
handleCloseCopyDialog() {
this.copyDialogVisible = false;
},
async handleCopySelect(value) {
const { exhibitionId } = value;
let res = await getDisplayById({ exhibitionId });
delete res.data.exhibitionId;
this.form = { ...res.data };
this.editDialogVisible = true;
console.log("this.form", this.form);
},
// // 文件个数超出
// handleExceed() {
// this.$message.error(`超出上传文件个数,请删除以后再上传!`);
// },
handleUpload(file) {
this.multiUploadVisible = true; //显示弹窗
this.filesList.push({
file,
name: file.name,
size: file.size,
status: null,
desc: null,
}); });
return false; //阻止自动上传 }
}, },
reset() {
handleSuccess(res) { this.loadData();
res.Success && this.$Message.success("上传成功"); //提示 },
// this.processModal = false; //成功后关闭弹窗
this.filesList = []; // 加载表格数据
}, async loadData() {
var params = {
handleImportRecordClose() { page: this.list.current,
this.importRecordVisible = false; limit: this.list.size,
}, };
let res = await getListPer(params);
handleMultiUploadClose() { if (res.code == 0) {
// 文件列表中如果Status为null,则代表有仍在上传中 this.list = res.data;
let isUpLoading = false; this.currentPageIds = this.list.records.map((item) => {
this.filesList.map((item) => { return item.exhibitionId;
if (item.status == null) {
isUpLoading = true;
return;
}
}); });
let title = isUpLoading ? "当前有上传任务,是否取消上传" : "确认关闭?"; }
let confirmButtonText = isUpLoading ? "关闭并取消上传" : "确定";
let cancelButtonText = isUpLoading ? "否" : "取消";
let that = this;
this.$confirm(title, "提示", {
confirmButtonText,
cancelButtonText,
type: "warning",
})
.then(() => {
// 点击取消上传
if (that.isUpLoading) {
this.handleCancelAllUpLoad();
this.$message.warning("已取消上传!");
}
this.multiUploadVisible = false; //最后关闭
})
.catch(() => {
console.log("用户取消操作");
});
},
handleMultiUploadCancel(index) {
if (this.cancelUploadArr[index]) {
this.cancelUploadArr[index](); //取消上传
this.cancelUploadArr.splice(index, 1); //从取消队列中删除
}
if (this.filesList[index]) {
this.filesList.splice(index, 1);
}
this.$message.info("已取消上传!");
},
handleCancelAllUpLoad() {
this.cancelUploadArr.forEach((cancelCallBack) => cancelCallBack()); //批量取消上传
},
}, },
};
</script> async handleOperation(value, row) {
console.log(value, row);
<style lang="scss" scoped> // debugger
.top-bar { switch (value.type) {
display: flex; case "approval":
justify-content: space-between; if (row) {
flex-direction: column; this.previewDialogVisible = true;
height: 68px; let res = await getDisplayById({ exhibitionId: row.exhibitionId });
} this.curPreviewObj = res.data;
}
.tools { break;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 14px;
.tools-item {
display: flex;
&:last-child {
justify-content: flex-end;
} }
},
// 多选
handleSelectionChange(val) {
this.multipleSelection = val;
},
// 改变页容量
handleSizeChange(value) {
this.list.size = value;
this.loadData();
},
// 改变当前显示页
handleCurrentChange(value) {
this.list.current = value;
this.loadData();
},
// 关闭Dialog
handleClose() {
this.editDialogVisible = false;
this.form = {
status: 1,
faceImage: "", // 封面(图片1张)
images: "", //展览图片
videos: "", //展览视频
audios: "", //展览音频
exhibitionUnits: [], //布展单元
};
},
// 关闭预览图片
closeImgViewer() {
this.imgViewerVisible = false;
},
// 预览图片
handelPreviewImages(images) {
this.imgViewerVisible = true;
this.imgList = [images];
},
handleClosePreviewDialog() {
this.previewDialogVisible = false;
} }
.upload-button { },
margin: 0 10px; };
</script>
<style lang="scss" scoped>
.top-bar {
display: flex;
justify-content: space-between;
flex-direction: column;
height: 68px;
}
.tools {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 14px;
.tools-item {
display: flex;
&:last-child {
justify-content: flex-end;
} }
} }
</style> .upload-button {
\ No newline at end of file margin: 0 10px;
}
}
</style>
\ No newline at end of file
<template> <template>
<div class="app-container"> <div class="app-container">
<div class="top-bar"> <div class="top-bar">
<SearchBar :config="searchConfig" @search="search" @reset="reset" /> <SearchBar :config="searchConfig" @search="search" @reset="reset" />
<!-- <el-button <!-- <el-button
type="primary" type="primary"
@click.native="handleOperation({ type: 'add' })" @click.native="handleOperation({ type: 'add' })"
icon="el-icon-plus" icon="el-icon-plus"
>
发布</el-button
>
</div> -->
<!-- <el-button type="primary" @click.native="handleCopy">复制</el-button> -->
</div>
<TablePage
:data="list.records"
:tableTitle="tableTitle"
:operates="tableOperates"
> >
<template v-slot:status="data"> 发布</el-button
<el-popconfirm
:title="getStatusTitle(data.scope.status)"
@onConfirm="handleChangeStatus(data.scope)"
>
<el-switch
slot="reference"
:value="Boolean(Number(data.scope.status))"
></el-switch>
</el-popconfirm>
</template>
<template v-slot:displayType="data">
{{ dicts.displayType[data.scope.type] }}
</template>
<template v-slot:faceImageUrl="data">
<img
:src="
$getFullUrl(data.scope.faceImagePressUrl || data.scope.faceImageUrl)
"
alt="暂无图片"
v-if="
$getFullUrl(data.scope.faceImagePressUrl || data.scope.faceImageUrl)
"
style="cursor: pointer"
width="100px"
@click="handelPreviewImages(data.scope.faceImageUrl)"
/>
</template>
<template v-slot:operates="scope">
<TableOperation
:operations="tableOperations"
:rawData="scope.scope.row"
@handleOperation="handleOperation"
></TableOperation>
</template>
</TablePage>
<el-pagination
style="margin: 16px 0"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="Number(list.current)"
:page-sizes="[10, 20, 50, 100]"
:page-size="Number(list.size)"
layout="total, sizes, prev, pager, next, jumper"
:total="Number(list.total)"
class="pagination"
> >
</el-pagination> </div> -->
<InfoEditDialog </div>
:visible="editDialogVisible" <el-tabs v-model="activeName" type="border-card" ref="tabs">
:form="form" <el-tab-pane :label="item.label" :name="item.name" v-for="(item, tabIndex) in tabs" :key="tabIndex">
:currentPageIds="currentPageIds" <TablePage :data="dataList[tabIndex].records" :tableTitle="tableTitle" :operates="tableOperates">
@handleClose="handleClose" <template v-slot:checkStatus="data">
@refresh="loadData" <!-- {{ data.scope.checkStatus }} -->
@changeDisplay="reloadDisplay" <el-tag type="primary" v-if="data.scope.checkStatus == 0">
ref="InfoEditDialog" 待审核
/> </el-tag>
<PreviewDialog <el-tag type="success" v-if="data.scope.checkStatus == 1">
v-if="Object.keys(curPreviewObj).length > 0" 已通过
:visible="previewDialogVisible" </el-tag>
:displayDetail="curPreviewObj" <el-tag type="danger" v-if="data.scope.checkStatus == -2">
@handleClose="handleClosePreviewDialog" 已驳回
/> </el-tag>
<!-- <CopyDialog </template>
:visible="copyDialogVisible" <template v-slot:displayType="data">
@handleClose="handleCloseCopyDialog" {{ dicts.displayType[data.scope.type] }}
@handleCopySelect="handleCopySelect" </template>
:list="list" <template v-slot:faceImageUrl="data">
/> --> <img :src="
$getFullUrl(data.scope.faceImagePressUrl || data.scope.faceImageUrl)
" alt="暂无图片" v-if="$getFullUrl(data.scope.faceImagePressUrl || data.scope.faceImageUrl)"
style="cursor: pointer" width="100px" @click="handelPreviewImages(data.scope.faceImageUrl)" />
</template>
<template v-slot:operates="scope">
<TableOperation :operations="tableOperations" :rawData="scope.scope.row" @handleOperation="handleOperation">
</TableOperation>
</template>
</TablePage>
<el-pagination style="margin: 16px 0" @size-change="handleSizeChange" @current-change="handleCurrentChange"
:current-page="Number(dataList[currentTabIndex].current)" :page-sizes="[10, 20, 50, 100]"
:page-size="Number(dataList[currentTabIndex].size)" layout="total, sizes, prev, pager, next, jumper"
:total="Number(dataList[currentTabIndex].total)" class="pagination">
</el-pagination>
</el-tab-pane>
</el-tabs>
<PreviewDisplayDialog v-if="Object.keys(curPreviewObj).length > 0" :visible="previewDialogVisible"
<el-image-viewer :displayDetail="curPreviewObj" @handleClose="handleClosePreviewDialog" />
v-if="imgViewerVisible"
:on-close="closeImgViewer" <el-image-viewer v-if="imgViewerVisible" :on-close="closeImgViewer" :url-list="imgList" />
:url-list="imgList" </div>
/> </template>
</div>
</template> <script>
import TablePage from "@/components/Table/TablePage.vue";
<script> import TableOperation from "@/components/Table/TableOperation.vue";
import TablePage from "@/components/Table/TablePage.vue"; import PreviewDisplayDialog from './components/PreviewDisplayDialog.vue'
import TableOperation from "@/components/Table/TableOperation.vue"; import { displayTabletitle, operates, approvalOperations, viewOperations } from "./config";
import { title, operates, operations } from "./config"; import {
import { getListPer,
getListPer, getDisplayCheckById,
deleteDisplay, } from "@/api/display";
getDisplayById, import SearchBar from "@/components/SearchBar";
editDisplay, import { mapGetters } from "vuex";
} from "@/api/display"; import { getToken } from "@/utils/auth";
// import CopyDialog from "./components/CopyDialog"; import { importZip } from "@/utils/file";
import SearchBar from "@/components/SearchBar"; import { thisTypeAnnotation } from "@babel/types";
import { mapGetters } from "vuex"; export default {
import { getToken } from "@/utils/auth"; components: {
import { importZip } from "@/utils/file"; TablePage,
export default { TableOperation,
components: { SearchBar,
TablePage, PreviewDisplayDialog,
TableOperation, "el-image-viewer": () =>
SearchBar, import("element-ui/packages/image/src/image-viewer"),
"el-image-viewer": () => },
import("element-ui/packages/image/src/image-viewer"), data() {
}, let that = this;
data() { return {
let that = this; dataList: [
return { {
list: {
record: [], record: [],
size: 10, size: 10,
current: 1, current: 1,
total: 0, total: 0,
}, },
searchForm: { {
name: "", record: [],
status: "", size: 10,
}, current: 1,
searchConfig: [ total: 0,
{
prop: "title",
type: "input",
label: "展览名称",
},
{
prop: "status",
type: "select",
label: "状态",
selectOptions: [
{
label: "已上线",
value: "1",
},
{
label: "已下线",
value: "0",
},
],
},
],
editDialogVisible: false,
isAdd: true,
form: {
title: "", //标题
type: "", // 类别(待定)--枚举值(社会、生活等)
displayCharacter: "1", //展览性质(精品展2、布展1、文物展3)--此处填写布展类别
keyword: "", // 关键词
deptId: "", //展览单位id--暂填入用户自己的单位
regionCode: "", // 所在地域--暂填入用户自己的地区
intro: "", //展览介绍,
themeType: "1", //模板主题--前端枚举
literature: "", //关联文献。id1,id2,id3--接口查询
remark: "", //备注
status: 1, //上下架状态(0-下架,1-上架)
faceImage: "", // 封面(图片1张)
images: "", //展览图片
videos: "", //展览视频
audios: "", //展览音频
exhibitionUnits: [], //布展单元
}, },
loading: false, {
imgViewerVisible: false, record: [],
previewDialogVisible: false, size: 10,
copyDialogVisible: false, current: 1,
previewVideos: [], total: 0,
displayTypes: {}, }
curPreviewObj: {}, //当前预览的对象 ],
currentPageIds: [], //当前的id数组,用于给详情页切换用 searchConfig: [
importZipUrl: process.env.VUE_APP_BASE_API + "/bizImport/importZip", {
headers: { prop: "title",
authorization: getToken(), type: "input",
label: "展览名称",
}, },
multiUploadVisible: false, //控制批量上传弹窗显示 ],
importRecordVisible: false, //上传记录 loading: false,
filesList: [], //上传当中的文件队列 imgViewerVisible: false,
uploadCount: 0, //处于上传中的文件数量,当等于fileList的时候就关闭弹窗,请求完毕一个就++ previewDialogVisible: false,
cancelUploadArr: [], //保存每个文件上传接口对应的取消请求的函数[fn,fn,fn...] curPreviewObj: {}, //当前预览的对象
isUpLoading: false, currentPageIds: [], //当前的id数组,用于给详情页切换用
}; tabs: [{
name: '0',
label: '待审核'
}, {
name: '1',
label: '已通过'
},
{
name: '-2',
label: '已驳回'
}
],
activeName: '0',
currentTabIndex: 0
};
},
computed: {
...mapGetters(["dicts"]),
tableTitle() {
return displayTabletitle;
}, },
computed: { tableOperates() {
...mapGetters(["dicts"]), return operates;
tableTitle() {
return title;
},
tableOperates() {
return operates;
},
tableOperations() {
return operations;
},
getStatusTitle(status) {
return (status) => {
if (Number(status)) {
return "是否确定要下架?";
} else {
return "是否确定要上架?";
}
};
},
}, },
tableOperations() {
async created() { if (this.activeName == '0') {
await this.$store.dispatch("dict/getDictList", ["displayType"]); return approvalOperations
} else {
return viewOperations
}
}
},
watch: {
activeName(value) {
this.currentTabIndex = Number(Math.abs(value)) //当前索引正好对应状态的绝对值
this.loadData()
}
},
async created() {
await this.$store.dispatch("dict/getDictList", ["displayType"]);
this.loadData();
},
methods: {
async search(form) {
var params = {
page: 1,
limit: this.dataList[this.currentTabIndex].size,
...form,
};
if (params.status == "") {
delete params.status;
}
let res = await getListPer(params);
if (res.code == 0) {
this.$set(this.dataList, this.currentTabIndex, res.data)
// this.dataList[this.currentTabIndex] = res.data
// this.currentPageIds = this.dataList[this.currentTabIndex].records.map((item) => {
// return item.exhibitionId;
// });
}
},
reset() {
this.loadData(); this.loadData();
}, },
//watch部分 // 加载表格数据
watch: { async loadData() {
//监听弹窗变化 var params = {
multiUploadVisible(val) { page: this.dataList[this.currentTabIndex].current,
//弹窗关闭记得清空,开启执行批量上传 limit: this.dataList[this.currentTabIndex].size,
if (val) { checkStatus: Number(this.activeName)
for (let i = 0; i < this.filesList.length; i++) { };
this.uploadSelf(this.filesList[i].file, i); //弹窗显示的时候,就根据文件队列的数量调用上传接口 let res = await getListPer(params);
} if (res.code == 0) {
} else { this.$set(this.dataList, this.currentTabIndex, res.data)
//弹窗关闭,还原数据到初始位置 // this.currentPageIds = this.dataList[this.currentTabIndex].records.map((item) => {
this.filesList = []; // return item.exhibitionId;
this.uploadCount = 0; // });
this.cancelUploadArr = []; }
}
},
}, },
methods: {
async search(form) { async handleOperation(value, row) {
var params = { console.log(value, row);
page: 1, // debugger
limit: this.list.size, if (value.type == 'approval' || value.type == 'view') {
...form, if (row) {
}; this.previewDialogVisible = true;
if (params.status == "") { let res = await getDisplayCheckById({ exhibitionId: row.exhibitionId });
delete params.status; this.curPreviewObj = res.data;
}
let res = await getListPer(params);
if (res.code == 0) {
this.list = res.data;
this.currentPageIds = this.list.records.map((item) => {
return item.exhibitionId;
});
}
},
reset() {
this.loadData();
},
// 加载表格数据
async loadData() {
var params = {
page: this.list.current,
limit: this.list.size,
};
let res = await getListPer(params);
if (res.code == 0) {
this.list = res.data;
this.currentPageIds = this.list.records.map((item) => {
return item.exhibitionId;
});
}
},
async handleOperation(value, row) {
switch (value.type) {
case "add":
this.editDialogVisible = true;
case "view":
if (row) {
this.previewDialogVisible = true;
let res = await getDisplayById({ exhibitionId: row.exhibitionId });
this.curPreviewObj = res.data;
}
break;
case "edit":
let editRes = await getDisplayById({
exhibitionId: row.exhibitionId,
});
this.form = editRes.data;
this.editDialogVisible = true;
break;
case "delete":
let deleteRes = await deleteDisplay([row.exhibitionId]);
if (deleteRes.code === 0) {
this.loadData();
this.$message.success("删除成功!");
}
break;
case "multiAdd":
// debugger
// this.multiUploadVisible = true;
// console.log("this.multiUploadVisible", this.multiUploadVisible);
break;
case "downloadTemplate":
this.handleDownloadTemplate();
break;
case "viewImportRecord":
this.importRecordVisible = true;
break;
}
},
//下载批量导入模板
handleDownloadTemplate() {
let a = document.createElement("a");
a.href = "./static/展览导入模板.zip";
a.download = "展览整量导入模板.zip";
a.style.display = "none";
document.body.appendChild(a);
a.click();
a.remove();
},
uploadSelf(file, index) {
let formData = new FormData();
formData.append("type", "biz_exhibition");
formData.append("zipFile", file);
importZip(
formData,
(progressEvent) => this.uploadUnderWayCallback(progressEvent, index),
(c) => this.cancelCallBack(c, index)
).then((res) => {
if (res.data.code == 0) {
this.$set(this.filesList[index], "status", "success");
this.$set(this.filesList[index], "desc", "上传成功");
this.$message.success("文件" + file.name + "上传成功!");
this.loadData()
} else {
this.$set(this.filesList[index], "status", "warning");
this.$set(this.filesList[index], "desc", "上传失败" + res.data.msg);
this.$message.error("上传失败:" + res.data.msg);
this.loadData();
}
});
},
// 文件上传进度回调
uploadUnderWayCallback(progressEvent, index) {
let completeVal =
(progressEvent.loaded / progressEvent.total) * 100 - 1 || 0; //处理成组件库进度组件需要的格式
this.$set(this.filesList[index], "percent", Math.floor(completeVal)); //直接改变数组某一项不是响应式的,因此我们需要用到这个api,将其响应式化,添加到数组中
},
// 文件取消回调
cancelCallBack(c, index) {
this.$set(this.cancelUploadArr, index, c); //添加取消队列中,关闭弹窗批量取消
this.uploadCount = 0;
},
handleMultiUploadClose() {
// 文件列表中如果Status为null,则代表有仍在上传中
let isUpLoading = false;
this.filesList.map((item) => {
if (item.status == null) {
isUpLoading = true;
return;
}
});
let title = isUpLoading ? "当前有上传任务,是否取消上传" : "确认关闭?";
let confirmButtonText = isUpLoading ? "关闭并取消上传" : "确定";
let cancelButtonText = isUpLoading ? "否" : "取消";
let that = this;
this.$confirm(title, "提示", {
confirmButtonText,
cancelButtonText,
type: "warning",
})
.then(() => {
// 点击取消上传
if (that.isUpLoading) {
this.handleCancelAllUpLoad();
this.$message.warning("已取消上传!");
}
this.multiUploadVisible = false; //最后关闭
})
.catch(() => {
console.log("用户取消操作");
});
},
handleMultiUploadCancel(index) {
if (this.cancelUploadArr[index]) {
this.cancelUploadArr[index](); //取消上传
this.cancelUploadArr.splice(index, 1); //从取消队列中删除
}
if (this.filesList[index]) {
this.filesList.splice(index, 1);
}
this.$message.info("已取消上传!");
},
handleCancelAllUpLoad() {
this.cancelUploadArr.forEach((cancelCallBack) => cancelCallBack()); //批量取消上传
},
handleSuccess(res) {
res.Success && this.$Message.success("上传成功"); //提示
// this.processModal = false; //成功后关闭弹窗
this.filesList = [];
},
async reloadDisplay(exhibitionId) {
this.$refs.InfoEditDialog.submitLoading = true;
this.$refs.InfoEditDialog.loadingText = "加载中...";
let editRes = await getDisplayById({
exhibitionId,
});
this.form = editRes.data;
this.$refs.InfoEditDialog.submitLoading = false;
},
async handleChangeStatus(row) {
const { status } = row;
let newStatus = status === "0" ? "1" : "0";
const params = {
...row,
status: newStatus,
};
let res = await editDisplay(params);
if (res.code == 0) {
this.loadData();
this.$message.success("修改成功!");
}
},
// 多选
handleSelectionChange(val) {
this.multipleSelection = val;
},
// 改变页容量
handleSizeChange(value) {
this.list.size = value;
this.loadData();
},
// 改变当前显示页
handleCurrentChange(value) {
this.list.current = value;
this.loadData();
},
// 搜索
onSubmitSearch() {
console.log("submit!");
},
// 关闭Dialog
handleClose() {
this.editDialogVisible = false;
this.form = {
status: 1,
faceImage: "", // 封面(图片1张)
images: "", //展览图片
videos: "", //展览视频
audios: "", //展览音频
exhibitionUnits: [], //布展单元
};
},
// 关闭预览图片
closeImgViewer() {
this.imgViewerVisible = false;
},
// 预览图片
handelPreviewImages(images) {
this.imgViewerVisible = true;
this.imgList = [images];
},
handleClosePreviewDialog() {
this.previewDialogVisible = false;
},
handleCopy() {
this.copyDialogVisible = true;
},
handleCloseCopyDialog() {
this.copyDialogVisible = false;
},
async handleCopySelect(value) {
const { exhibitionId } = value;
let res = await getDisplayById({ exhibitionId });
delete res.data.exhibitionId;
this.form = { ...res.data };
this.editDialogVisible = true;
console.log("this.form", this.form);
},
// // 文件个数超出
// handleExceed() {
// this.$message.error(`超出上传文件个数,请删除以后再上传!`);
// },
handleUpload(file) {
this.multiUploadVisible = true; //显示弹窗
this.filesList.push({
file,
name: file.name,
size: file.size,
status: null,
desc: null,
});
return false; //阻止自动上传
},
handleSuccess(res) {
res.Success && this.$Message.success("上传成功"); //提示
// this.processModal = false; //成功后关闭弹窗
this.filesList = [];
},
handleImportRecordClose() {
this.importRecordVisible = false;
},
handleMultiUploadClose() {
// 文件列表中如果Status为null,则代表有仍在上传中
let isUpLoading = false;
this.filesList.map((item) => {
if (item.status == null) {
isUpLoading = true;
return;
}
});
let title = isUpLoading ? "当前有上传任务,是否取消上传" : "确认关闭?";
let confirmButtonText = isUpLoading ? "关闭并取消上传" : "确定";
let cancelButtonText = isUpLoading ? "否" : "取消";
let that = this;
this.$confirm(title, "提示", {
confirmButtonText,
cancelButtonText,
type: "warning",
})
.then(() => {
// 点击取消上传
if (that.isUpLoading) {
this.handleCancelAllUpLoad();
this.$message.warning("已取消上传!");
}
this.multiUploadVisible = false; //最后关闭
})
.catch(() => {
console.log("用户取消操作");
});
},
handleMultiUploadCancel(index) {
if (this.cancelUploadArr[index]) {
this.cancelUploadArr[index](); //取消上传
this.cancelUploadArr.splice(index, 1); //从取消队列中删除
}
if (this.filesList[index]) {
this.filesList.splice(index, 1);
} }
this.$message.info("已取消上传!");
},
handleCancelAllUpLoad() {
this.cancelUploadArr.forEach((cancelCallBack) => cancelCallBack()); //批量取消上传
},
},
};
</script>
<style lang="scss" scoped>
.top-bar {
display: flex;
justify-content: space-between;
flex-direction: column;
height: 68px;
}
.tools {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 14px;
.tools-item {
display: flex;
&:last-child {
justify-content: flex-end;
} }
},
// 多选
handleSelectionChange(val) {
this.multipleSelection = val;
},
// 改变页容量
handleSizeChange(value) {
this.dataList[this.currentTabIndex].size = value;
this.loadData();
},
// 改变当前显示页
handleCurrentChange(value) {
this.dataList[this.currentTabIndex].current = value;
this.loadData();
},
// 关闭Dialog
handleClose() {
this.editDialogVisible = false;
this.form = {
status: 1,
faceImage: "", // 封面(图片1张)
images: "", //展览图片
videos: "", //展览视频
audios: "", //展览音频
exhibitionUnits: [], //布展单元
};
},
// 关闭预览图片
closeImgViewer() {
this.imgViewerVisible = false;
},
// 预览图片
handelPreviewImages(images) {
this.imgViewerVisible = true;
this.imgList = [images];
},
handleClosePreviewDialog() {
this.previewDialogVisible = false;
} }
.upload-button { },
margin: 0 10px; };
</script>
<style lang="scss" scoped>
.top-bar {
display: flex;
justify-content: space-between;
flex-direction: column;
height: 68px;
}
.tools {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 14px;
.tools-item {
display: flex;
&:last-child {
justify-content: flex-end;
} }
} }
</style> }
\ No newline at end of file </style>
\ No newline at end of file
<template>
<router-view />
</template>
<script>
export default {
}
</script>
<style>
</style>
\ No newline at end of file
...@@ -81,14 +81,14 @@ ...@@ -81,14 +81,14 @@
<svg-icon icon-class="keyword"></svg-icon> <svg-icon icon-class="keyword"></svg-icon>
关键词:</span 关键词:</span
> >
<span class="value">{{ displayDetail.keyword }}</span> <span class="value">{{ displayDetail.keyword || '暂无'}}</span>
</div> </div>
<div class="body-item"> <div class="body-item">
<span class="label"> <span class="label">
<svg-icon icon-class="zllx"></svg-icon>展览类型:</span <svg-icon icon-class="zllx"></svg-icon>展览类型:</span
> >
<span class="value">{{ <span class="value">{{
dicts.displayType[displayDetail.type] dicts.displayType[displayDetail.type] || '暂无'
}}</span> }}</span>
</div> </div>
<div class="body-item"> <div class="body-item">
...@@ -96,20 +96,20 @@ ...@@ -96,20 +96,20 @@
<svg-icon icon-class="zlxz"></svg-icon>展览性质:</span <svg-icon icon-class="zlxz"></svg-icon>展览性质:</span
> >
<span class="value">{{ <span class="value">{{
dicts.displayCharacter[displayDetail.displayCharacter] dicts.displayCharacter[displayDetail.displayCharacter]|| '暂无'
}}</span> }}</span>
</div> </div>
<div class="body-item"> <div class="body-item">
<span class="label" <span class="label"
><svg-icon icon-class="zldw"></svg-icon>展览单位:</span ><svg-icon icon-class="zldw"></svg-icon>展览单位:</span
> >
<span class="value">{{ displayDetail.deptName }}</span> <span class="value">{{ displayDetail.deptName|| '暂无' }}</span>
</div> </div>
<div class="body-item"> <div class="body-item">
<span class="label" <span class="label"
><svg-icon icon-class="zldq"></svg-icon>展览地区:</span ><svg-icon icon-class="zldq"></svg-icon>展览地区:</span
> >
<span class="value">{{ displayDetail.regionName }}</span> <span class="value">{{ displayDetail.regionName || '暂无'}}</span>
</div> </div>
</div> </div>
</el-col> </el-col>
...@@ -279,25 +279,6 @@ ...@@ -279,25 +279,6 @@
</div> </div>
</el-carousel-item> </el-carousel-item>
</el-carousel> </el-carousel>
<!-- <el-col
:span="24 / curUnit.imagesVo.length"
v-for="item in curUnit.imagesVo"
:key="item.euId"
class="margin-bottom-32 unit-content_images_container"
>
<img :src="$getFullUrl(item.pressUrl)" width="100%" />
<div
class="enlarge"
@click="handelPreviewImages(curUnit.imagesVo)"
>
<img src="@/assets/imgs/enlarge-s.png" alt="" />
</div>
<div class="unit-content_images_desc">
{{ item.name }}
</div>
</el-col> -->
</div> </div>
<div <div
class="unit-content_videos" class="unit-content_videos"
......
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
<el-row> <el-row>
<el-col class="item"> <el-col class="item">
<div class="label">关键词:</div> <div class="label">关键词:</div>
<div class="value">{{ displayDetail.keyword }}</div> <div class="value">{{ displayDetail.keyword ||'暂无' }}</div>
</el-col> </el-col>
<el-col class="item" v-if="dicts.displayType"> <el-col class="item" v-if="dicts.displayType">
<div class="label">展览类型:</div> <div class="label">展览类型:</div>
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col class="item" v-if="dicts.displayCharacter"> <el-col class="item" v-if="(dicts.displayCharacter && displayDetail.displayCharacter)">
<div class="label">展览性质:</div> <div class="label">展览性质:</div>
<div class="value"> <div class="value">
{{ {{
......
<template>
<div class="content">
<div class="wrapper">
<div class="inner">
<!-- 展览基本信息 -->
<div class="content-item display-detail_basic_info">
<div class="info-container">
<div v-if="displayDetail.imagesVo && displayDetail.imagesVo.length > 0" class="info-container-left">
<SlideImage :imgList="displayDetail.imagesVo" v-if="
displayDetail.imagesVo && displayDetail.imagesVo.length > 0
" />
<SlideImage :imgList="[{ pressUrl: displayDetail.faceImagePressUrl }]"
v-else-if="displayDetail.faceImagePressUrl" />
</div>
<div class="info-container-right">
<div class="info-title">
<span>{{ displayDetail.title }} </span>
<div class="view-count">
<svg-icon icon-class="view"></svg-icon>
<span>{{ displayDetail.browseCount }}</span>
</div>
</div>
<el-row :span="20">
<el-col :span="24" class="left">
<div class="basic-info">
<div class="body-item">
<span class="label">
<!-- <svg-icon icon-class="keyword"></svg-icon> -->
关键词:
</span>
<span class="value">{{
displayDetail.keyword || "暂无"
}}</span>
</div>
<div class="body-item">
<span class="label">
<!-- <svg-icon icon-class="zllx"></svg-icon> -->
展览类型:
</span>
<span class="value">{{
dicts.displayType[displayDetail.type] || "暂无"
}}</span>
</div>
<div class="body-item">
<span class="label">
<!-- <svg-icon icon-class="zlxz"></svg-icon> -->
展览性质:
</span>
<span class="value">{{
dicts.displayCharacter[
displayDetail.displayCharacter
] || "暂无"
}}</span>
<span>
{{ dicts }}
</span>
</div>
<div class="body-item">
<span class="label">
<!-- <svg-icon icon-class="zldw"></svg-icon> -->
展览单位:
</span>
<span class="value">{{
displayDetail.deptName || "暂无"
}}</span>
</div>
<div class="body-item">
<span class="label">
<!-- <svg-icon icon-class="zldq"></svg-icon> -->
展览地区:
</span>
<span class="value">{{
displayDetail.regionName || "暂无"
}}</span>
</div>
</div>
</el-col>
<el-col :span="24" class="right">
<div class="qrcode">
<!-- <img
src="@/assets/imgs/display/normal/test-qrcode.png"
alt=""
/> -->
</div>
<div class="tools">
<ReaderOperations :loveCount="displayDetail.loveCount"
:loveCountStatus="Boolean(displayDetail.loveCountStatus)"
:collectCount="displayDetail.collectCount" :collectCountStatus="
Boolean(displayDetail.collectCountStatus)
" :sourceId="displayDetail.exhibitionId" :title="displayDetail.title"
:sourceType="'biz_exhibition'" @reload="() => { }" />
</div>
</el-col>
</el-row>
</div>
</div>
<div class="audio" :style="{ animationPlayState: audioPlaying ? 'running' : 'paused' }"
@click="handleClickAudio" v-if="displayDetail.audiosVo && displayDetail.audiosVo.length > 0">
<img src="@/assets/imgs/display/normal/music.png" alt="" />
<!-- <svg-icon icon-class="music"></svg-icon> -->
<AudioPlayer style="display: none" :url="$getFullUrl(displayDetail.audiosVo[0].url)" ref="AudioPlayer" />
</div>
</div>
<div class="content-item display-detail_tabbar" id="tabbar" :class="{ isFixed: isFixed }">
<span v-for="(item, index) in tabbarData" :key="index">
<span @click="handleClickTabItem(item)" :class="[
'tab-item',
currentTab && currentTab.domId == item.domId ? 'active' : '',
]" v-html="item.name" v-if="
displayDetail[item.domId] &&
displayDetail[item.domId].length > 0
">
</span>
</span>
</div>
<!-- 展览简介 -->
<div class="content-item display-detail_intro" id="intro">
<div class="intro-title">
<!-- <svg-icon icon-class="jianjie"></svg-icon> -->
<!-- <i class="el-icon-tickets"></i> -->
<span>展览简介</span>
</div>
<div class="intro-content">
<div class="left-box">简介</div>
<div class="intro-content-container" v-html="displayDetail.intro"></div>
</div>
</div>
<div class="display-detail_virtual content-item" v-if="displayDetail.virtualVo.length > 0" id="virtualVo">
<div class="custom_title">
<div class="center">
<!-- <svg-icon icon-class="wenxian"></svg-icon> -->
<span class="title">虚拟展厅</span>
</div>
</div>
<div class="vr-content">
<div class="img-container" @click="handleToVR(item)" v-for="(item, index) in displayDetail.virtualVo"
:key="index">
<img :src="$getFullUrl(item.faceImagePressUrl)" alt="" />
<div class="modal">
<svg-icon icon-class="360"></svg-icon>
<div class="name">点击进入{{ item.name }}</div>
</div>
</div>
</div>
</div>
<!-- 展览视频 -->
<div id="videosVo" class="content-item videos"
v-if="displayDetail.videosVo && displayDetail.videosVo.length > 0">
<div class="video-title">
<!-- <i class="el-icon-video-camera"></i> -->
展览视频
</div>
<div class="video-names">
<swiper class="swiper video-swiper" :options="videoSwiperOption" ref="unitSwiper" v-if="currentVideo">
<swiper-slide :class="[
'slide-item',
item.fileId == currentVideo.fileId ? 'active' : '',
]" v-for="(item, index) in displayDetail.videosVo" :key="index"
@click.native="handleChangeCurrentVideo(item)">
{{ item.name.split(".")[0] }}
</swiper-slide>
</swiper>
<div class="swiper-button-prev video-swiper-button-prev" slot="button-prev">
<i class="el-icon-arrow-left"></i>
</div>
<div class="swiper-button-next video-swiper-button-next" slot="button-next">
<i class="el-icon-arrow-right"></i>
</div>
<!-- <div class="video-item" v-for="(item, index) in displayDetail.videosVo" :key="index"
@click="handleChangeCurrentVideo(item)">
<div :class="[
'name',
currentVideo && item.fileId == currentVideo.fileId
? 'active'
: '',
]">
{{ item.name.split(".")[0] }}
</div>
</div> -->
</div>
<video-player v-if="currentVideo && currentVideo.url" :src="$getFullUrl(currentVideo.url)" class="video-box">
</video-player>
</div>
<!--展览单元 -->
<div class="content-item display-detail_units" ref="units" v-if="displayDetail.exhibitionUnits.length > 0"
id="exhibitionUnits">
<div class="custom_title">
<div class="center">
<span class="title">展览单元</span>
</div>
</div>
<NormalStyleUnit :curUnit="curUnit" :exhibitionUnits="displayDetail.exhibitionUnits"
@handleClickUnit="handleClickUnit" @handelPreviewImages="handelPreviewImages" @handleToCr="handleToCr" />
</div>
<!--展览相关文物 -->
<div class="content-item display-detail_relateRc" ref="units" v-if="
displayDetail.culturalRelicVo &&
displayDetail.culturalRelicVo.length > 0
" id="culturalRelicVo">
<div class="cr-title">展览文物</div>
<SlideImageGroup :imgList="displayDetail.culturalRelicVo">
<template slot-scope="{ item }" slot="img">
<img :src="$getFullUrl(item.faceImagePressUrl)" alt="" style="
width: 100%;
height: 100%;
object-fit: fill;
cursor: pointer;
" />
</template>
<template slot-scope="{ item }" slot="info">
<div class="name">{{ item.name }}</div>
</template>
</SlideImageGroup>
</div>
<!-- 相关文献 -->
<div class="content-item display-detail_lts" v-if="
displayDetail.literatureVo && displayDetail.literatureVo.length > 0
" id="literatureVo">
<div class="custom_title">
<div class="center">
<!-- <svg-icon icon-class="wenxian"></svg-icon> -->
<span class="title">相关文献</span>
</div>
</div>
<div class="lts-content">
<div class="lt-item" v-for="(item, index) in displayDetail.literatureVo" :key="index"
@click="handleViewLt(item)">
<span class="lt-order">[{{ index + 1 }}]</span>
<span class="lt-authors" v-if="item.authors">{{ item.authors }}.</span>
<span class="lt-name" v-if="item.name">{{ item.name }}.</span>
<span class="lt-source" v-if="item.source">{{ item.source }}.</span>
<span class="lt-date" v-if="item.date">{{ item.date }}</span>
</div>
</div>
</div>
</div>
</div>
<el-image-viewer v-if="imgViewerVisible" :on-close="closeImgViewer" :url-list="imgList" />
</div>
</template>
<script>
import AudioPlayer from "@/components/AudioPlayer";
import ReaderOperations from "@/components/ReaderOperations";
import { previewFile } from "@/utils/file";
import SlideImage from "@/components/SlideImage";
import SlideImageGroup from "@/components/SlideImageGroup";
import { swiper, swiperSlide } from "vue-awesome-swiper";
import "swiper/dist/css/swiper.css";
import { isElementInViewport2 } from "@/utils/index";
import NormalStyleUnit from './NormalStyleUnit.vue'
import videoPlayer from "@/components/VideoPlayer";
export default {
name: "NormalStyle",
components: {
AudioPlayer,
ReaderOperations,
videoPlayer,
NormalStyleUnit,
SlideImage,
SlideImageGroup,
swiper,
swiperSlide,
"el-image-viewer": () =>
import("element-ui/packages/image/src/image-viewer"),
},
props: {
displayDetail: {
type: Object,
default: () => ({}),
},
dicts: {
type: Object,
default: () => ({}),
},
},
data() {
let vm = this;
return {
imgViewerVisible: false,
relateRelics: [],
audioPlaying: true,
curUnit: {},
dotImg: require("@/assets/imgs/display/normal/mz-dot.png"),
dotImgS: require("@/assets/imgs/display/normal/mz-dot-s.png"),
page: null,
currentVideo: null,
videoSwiperOption: {
loop: false,
loopedSlides: 8, // looped slides should be the same
spaceBetween: 10,
slidesPerView: 4,
navigation: {
nextEl: ".video-swiper-button-next",
prevEl: ".video-swiper-button-prev",
},
},
isFixed: false,
currentTab: null,
offsetTop: null,
tabbarData: [
{
name: "展览简介",
domId: "intro",
},
{
name: "虚拟展厅",
domId: "virtualVo",
},
{
name: "展览视频",
domId: "videosVo",
},
{
name: "展览单元",
domId: "exhibitionUnits",
},
{
name: "展览文物",
domId: "culturalRelicVo",
},
{
name: "相关文献",
domId: "literatureVo",
},
],
};
},
async mounted() {
this.loadDetail();
console.log('this.dicts',this.dicts.displayCharacter);
this.$nextTick(() => {
window.addEventListener("scroll", this.initHeight);
this.offsetTop = document.querySelector("#tabbar").offsetTop; //距离offsetParent的高度
this.tabbarData.map((item) => {
let dom = document.getElementById(item.domId);
if (dom) {
item.position = dom.offsetTop - 320; //100navbar 55tabbar
}
});
});
},
beforeRouteLeave(to, form, next) {
// 离开路由移除滚动事件
window.removeEventListener("scroll", this.initHeight);
next();
},
methods: {
async loadDetail() {
if (
this.displayDetail.exhibitionUnits &&
this.displayDetail.exhibitionUnits.length > 0
) {
this.curUnit = this.displayDetail.exhibitionUnits[0];
this.expandUnitInfo()
}
processUnit(this.displayDetail.exhibitionUnits);
if (
this.displayDetail.videosVo &&
this.displayDetail.videosVo.length > 0
) {
this.currentVideo = this.displayDetail.videosVo[0];
}
if (this.displayDetail.intro) {
this.currentTab = {
name: "展览简介",
domId: "intro",
};
}
function processUnit(list) {
for (let o of list || []) {
if (o.children) {
if (o.children.length == 0) {
o.children = null;
} else {
processUnit(o.children);
}
}
}
}
this.$nextTick(() => {
// this.replaceFaceImage();
if (
this.displayDetail.audiosVo &&
this.displayDetail.audiosVo.length > 0
) {
this.$message.info("正在播放当前文物讲解音频,点击旋转按钮可关闭");
this.$refs.AudioPlayer.play();
}
});
},
replaceFaceImage() {
var img = new Image(); //新建一个图片对象
let url; //最终显示的大图
if (this.displayDetail.faceImagePressUrl) {
url = this.$getFullUrl(this.displayDetail.faceImageUrl);
} else if (this.displayDetail.imagesVo.length > 0) {
url = this.$getFullUrl(this.displayDetail.imagesVo[0].url);
}
let faceImage = document.getElementById("faceImage");
img.src = url;
img.onload = function () {
faceImage.src = url;
};
},
//节流函数
throttle(fn, gapTime) {
let _this = this;
return function () {
let _nowTime = +new Date();
if (_nowTime - _this._lastTime > gapTime || !_this._lastTime) {
fn(...arguments); // 函数可以带参数
_this._lastTime = _nowTime;
}
};
},
// 预览关联文献
handleViewLt(item) {
if (item.files[0].url) {
previewFile(item.files[0].url, item.files[0].name);
} else {
this.$message.info('当前文献暂不支持在线浏览')
}
},
// 点击音频
handleClickAudio() {
this.audioPlaying = !this.audioPlaying;
if (this.audioPlaying) {
this.$refs["AudioPlayer"].play();
// console.log(this.$refs['audioContainer']);
} else {
this.$refs["AudioPlayer"].pause();
}
},
reload() {
this.$emit("reload");
},
handelPreviewImages(images) {
this.imgViewerVisible = true;
this.imgList = images.map((item) => this.$getFullUrl(item.url));
},
closeImgViewer() {
this.imgViewerVisible = false;
},
handleClickUnit(item) {
this.curUnit = item;
this.expandUnitInfo()
},
handleToCr(item) {
console.log(item);
// return;
const { crId } = item;
const newPage = this.$router.resolve({
path: "/culturalRelic/" + crId,
});
window.open(newPage.href, "_blank");
},
handleToVR(item) {
window.open(item.url);
},
handleChangeCurrentVideo(video) {
this.currentVideo = video;
},
handleClickTabItem(item) {
this.currentTab = item;
if (item.position) {
document.documentElement.scrollTop = item.position;
}
},
initHeight() {
let scrollTop =
window.pageYOffset ||
document.documentElement.scrollTop ||
document.body.scrollTop;
this.isFixed = scrollTop > this.offsetTop - 155 ? true : false; //100为navbar的高度,55为tabbar的高度
this.tabbarData.map((item) => {
let content = document.getElementById(item.domId);
if (content && isElementInViewport2(content)) {
this.currentTab = item;
}
});
},
expandUnitInfo() {
// 将每个单元下的所有数据变成key-value形式,方便遍历
let newUnits = {}
traveseUnits(this.curUnit)
this.$set(this.curUnit, 'expandUnitInfo', JSON.parse(JSON.stringify(newUnits)))
function traveseUnits(obj) {
newUnits[obj.title] = obj
if (obj.children && obj.children.length > 0) {
obj.children.map(item => {
traveseUnits(item)
})
}
}
}
},
};
</script>
<style lang="scss" >
// 自定义分页器样式
#page {
height: 30px;
display: flex;
justify-content: center;
}
.page-item {
cursor: pointer;
}
.display-detail_intro {
.intro-content {
p {
// font-family: $defaultFontFamily !important;
}
}
}
</style>
<style lang="scss" scoped>
// 中国风主题样式
/**公共样式开始 */
$titleFontFamily: SourceHanSerifCN-Bold;
$themeColor: #132c33;
.custom-title {
width: 50px;
background-color: #d72f3f;
min-height: 300px;
color: #fff;
font-size: 28px;
writing-mode: vertical-rl;
display: flex;
align-items: center;
justify-content: center;
box-shadow: rgb(215 47 63 / 30%) 4px 3px 8px 1px;
letter-spacing: 10px;
}
.content {
background-color: #f3f3f3;
min-height: 50vh;
}
.content-item {
width: 100%;
background-color: #fff;
}
.custom_title {
padding: 50px 0 40px 0;
.center {
padding: 0 40px;
display: flex;
align-items: center;
i {
margin-right: 10px;
font-size: 28px;
color: $themeColor;
}
.svg-icon {
font-size: 32px;
color: $themeColor;
margin-right: 10px;
}
.title {
font-size: 26px;
font-weight: 400;
color: $themeColor;
font-family: "SourceHanSerifCN-Bold";
}
}
}
.enlarge {
position: absolute;
bottom: 20px;
right: 40px;
display: flex;
z-index: 9;
background-color: #c1925b;
width: 40px;
height: 40px;
border-radius: 12px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
cursor: pointer;
img {
width: 24px;
height: 24px;
}
}
.isFixed {
position: fixed;
left: 0;
top: 100px;
z-index: 99;
}
/**公共样式结束 */
/**样式开始 */
.content {
width: 100%;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
/**轮播图 */
.display-detail_imgs {
height: 436px;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.wrapper {
width: 1200px;
// padding: 0 13%;
// width: 100%;
// width: 78%;
display: flex;
justify-content: center;
.inner {
width: 100%;
// box-shadow: 0px 1px 56px 4px rgba(0, 0, 0, 0.16);
background-color: #fff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 200px;
// position: relative;
margin: 0 70px;
padding-bottom: 56px;
/**基本信息 */
.display-detail_basic_info {
position: relative;
.info-container {
display: flex;
justify-content: space-between;
padding: 60px 36px;
height: 100%;
background-color: #fff;
.info-container-left {
min-height: 200px;
max-height: 460px;
margin-right: 50px;
flex: 1;
overflow: hidden;
.imagesVo-image-container {
// position: relative;
.img-container {
height: 100%;
width: 100%;
background-color: #f5f5f9;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
}
}
.info-container-right {
flex: 1;
min-height: 200px;
.info-title {
font-size: 24px;
font-weight: bold;
color: #444;
padding-bottom: 20px;
margin-bottom: 20px;
border-bottom: 2px solid #f2f2f2;
.view-count {
font-size: 14px;
margin-top: 10px;
color: #999;
font-weight: normal;
.svg-icon {
margin-right: 10px;
}
}
}
.basic-info {
.body-item {
display: flex;
align-items: center;
margin-bottom: 10px;
font-size: 18px;
.label {
display: flex;
align-items: center;
width: 120px;
// margin-right: 26px;
// margin-bottom: 10px;
font-weight: bold;
color: #999;
.svg-icon {
width: 24px;
height: 24px;
margin-right: 16px;
font-size: 16px;
}
}
.value {
color: #666;
// font-weight: bold;
}
}
}
.right {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.qrcode {
margin-bottom: 28px;
display: flex;
justify-content: center;
img {
width: 50%;
height: 100%;
}
}
.tools {
width: 100%;
.tools-item {
color: #858585;
flex: 1;
display: flex;
align-items: center;
cursor: pointer;
.svg-icon {
width: 22px;
height: 22px;
margin-right: 8px;
}
.like {
color: #831122;
}
.collect {
color: $themeColor;
}
}
}
}
}
}
.audio {
position: absolute;
right: -120px;
top: 34px;
cursor: pointer;
animation: audioRotate 8s linear infinite;
transform-origin: center center;
border: 2px solid $themeColor;
padding: 10px;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
background-color: #fff;
transition: all 0.5s ease;
&:hover {
box-shadow: 0 0 14px rgb(0 0 0 / 40%);
}
.svg-icon {
color: $themeColor;
font-size: 80px;
}
img {
width: 60px;
height: 60px;
}
}
}
.display-detail_tabbar {
background-color: #fff;
display: flex;
justify-content: center;
padding: 10px;
border-bottom: 1px solid #f2f2f2;
.tab-item {
height: 100%;
margin-right: 20px;
color: $themeColor;
font-size: 24px;
font-family: $titleFontFamily;
cursor: pointer;
position: relative;
&:hover {
color: $themeColor;
&::after {
display: inline-block;
}
}
&::after {
display: none;
}
}
.active {
color: $themeColor;
&::after {
display: inline-block;
}
}
.tab-item::after,
.active::after {
position: absolute;
content: "";
height: 4px;
width: 100%;
bottom: -10px;
left: 0;
background-color: $themeColor;
}
}
/**简介和视频 */
.display-detail_intro {
// background-image: url("@/assets/imgs/display/normal/bg.png");
// background-size: 1%;
padding: 40px;
.intro-title {
font-size: 26px;
font-weight: 400;
color: $themeColor;
font-family: "SourceHanSerifCN-Bold";
display: flex;
align-items: center;
margin-bottom: 32px;
i {
margin-right: 10px;
}
.svg-icon {
margin-right: 10px;
font-size: 36px;
}
}
.intro-content {
line-height: 28px;
display: flex;
}
.left-box {
width: 60px;
background-color: $themeColor;
min-height: 200px;
color: #fff;
font-size: 28px;
writing-mode: vertical-rl;
display: flex;
align-items: center;
justify-content: center;
letter-spacing: 10px;
font-family: SourceHanSerifCN-Bold;
}
.intro-content-container {
flex: 1;
text-indent: 34px;
padding: 16px 32px;
background-color: rgba($themeColor, 10%);
}
}
// 视频
.videos {
display: flex;
flex-direction: column;
margin-bottom: 40px;
.video-title {
display: flex;
// justify-content: center;
align-items: center;
font-size: 24px;
color: $themeColor;
padding: 0 40px;
margin-bottom: 32px;
font-family: SourceHanSerifCN-Bold;
i {
font-size: 28px;
margin-right: 10px;
}
}
.video-names {
display: flex;
justify-content: center;
margin-bottom: 30px;
position: relative;
.video-swiper-button-next,
.video-swiper-button-prev {
// background-color: rgba(0,0,0,0.2);
// border-radius: 50%;
background-image: none;
width: 60px;
height: 60px;
display: flex;
justify-content: center;
align-items: center;
color: $themeColor;
font-weight: bolder;
font-size: 28px;
transform: translateY(-6px);
}
.swiper-container {
width: 90%;
.slide-item {
padding: 8px;
border-radius: 4px;
color: $themeColor;
cursor: pointer;
text-overflow: ellipsis;
overflow: hidden;
width: 100%;
white-space: nowrap;
border: 1px solid $themeColor;
}
.active {
background: $themeColor;
color: #fff;
}
}
// .video-item {
// font-size: 18px;
// margin: 8px 30px;
// .name {
// color: #999;
// position: relative;
// cursor: pointer;
// &:hover {
// color: $themeColor;
// &::after {
// display: inline-block;
// }
// &::before {
// display: inline-block;
// }
// }
// }
// .active::after,
// .name::after {
// content: "";
// width: 50%;
// height: 1px;
// background-color: $themeColor;
// position: absolute;
// left: 0;
// bottom: -9px;
// left: 50%;
// transform: translateX(-50%);
// display: none;
// }
// .active::before,
// .name::before {
// content: "";
// width: 0;
// height: 0;
// border: 8px solid transparent;
// border-top-color: $themeColor;
// position: absolute;
// left: 50%;
// bottom: -25px;
// transform: translateX(-50%);
// display: none;
// }
// .active::after,
// .active::before {
// display: inline-block;
// }
// }
}
.video-box {
height: 600px;
padding: 0 40px;
.video-player {
height: 100%;
}
}
}
// 虚拟展
.display-detail_virtual {
margin-bottom: 56px;
.vr-content {
display: flex;
}
.img-container {
// width: 800px;
flex: 1;
height: 400px;
position: relative;
cursor: pointer;
overflow: hidden;
&:hover {
img {
transform: scale(1.1);
}
}
img {
width: 100%;
height: 400px;
transition: all ease 0.5s;
object-fit: cover;
}
.modal {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 400px;
background: rgba(0, 0, 0, 0.4);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
&:hover {
.name {
opacity: 1;
}
}
.svg-icon {
font-size: 110px;
color: #fff;
}
.name {
color: #fff;
font-size: 28px;
font-family: "SourceHanSerifCN-Bold";
opacity: 0;
transition: all ease 0.5s;
}
}
}
}
/**展览单元 */
.display-detail_units {
overflow-x: hidden;
}
// 关联文物
.display-detail_relateRc {
padding: 0 40px;
margin-bottom: 56px;
.cr-title {
display: flex;
align-items: center;
font-size: 26px;
color: $themeColor;
font-family: SourceHanSerifCN-Bold;
i {
font-size: 28px;
margin-right: 10px;
}
}
.el-col {
margin-bottom: 20px;
.img-container {
width: 100%;
height: 460px;
position: relative;
background-color: #f5f5f9;
margin-bottom: 10px;
height: 214px;
img {
width: 100%;
height: 100%;
object-fit: fill;
}
}
.cr-name-intro {
.cr-name {
// font-size: 38px;
font-weight: bold;
color: #333;
text-align: left;
margin-bottom: 40px;
text-indent: 4px;
}
}
}
}
/**关联文献 */
.display-detail_lts {
.lts-content {
padding: 0 40px 40px;
.lt-item {
border-bottom: 1px dashed #ccc;
padding-bottom: 9px;
&>span {
padding: 0 4px;
}
}
.lt-name {
color: $themeColor;
cursor: pointer;
}
}
}
}
}
}
::v-deep .el-tree .el-tree-node__expand-icon.expanded {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
//有子节点 且未展开
::v-deep .el-tree .el-icon-caret-right:before {
background: url("~@/assets/imgs/display/normal/tree-node.png") no-repeat 0 3px;
content: "";
display: block;
width: 16px;
height: 16px;
font-size: 16px;
background-size: 16px;
}
//有子节点 且已展开
::v-deep .el-tree .el-tree-node__expand-icon.expanded.el-icon-caret-right:before {
background: url("~@/assets/imgs/display/normal/tree-node-s.png") no-repeat 0 3px;
content: "";
display: block;
width: 16px;
height: 16px;
font-size: 16px;
background-size: 16px;
}
//没有子节点
::v-deep .el-tree .el-tree-node__expand-icon.is-leaf::before {
background: transparent;
content: "";
display: block;
width: 16px;
height: 16px;
font-size: 16px;
background-size: 16px;
}
// 修改tree icon
::v-deep .el-carousel__item--card {
width: 100%;
height: 100%;
transform: translateX(0) scale(1) !important;
}
::v-deep .el-carousel {
height: 100%;
}
::v-deep .el-carousel__container {
height: 100%;
}
::v-deep .el-tree {
background: transparent;
.el-tree-node__content {
height: 54px;
&:hover {
background-color: #fff;
color: $themeColor;
}
padding-left: 16px !important;
}
.is-current {
.el-tree-node__content {
background-color: #fff;
color: $themeColor;
}
}
}
@keyframes filmMoveLeft {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-1200px);
}
}
@keyframes filmMoveRight {
0% {
transform: translateX(0);
}
100% {
transform: translateX(1200px);
}
}
@keyframes audioRotate {
0% {
transform: rotateZ(0deg);
}
100% {
transform: rotateZ(360deg);
}
}
@-webkit-keyframes audioRotate {
0% {
transform: rotateZ(0deg);
}
100% {
transform: rotateZ(360deg);
}
}
.animation-play-paused {
animation-play-state: paused;
-webkit-animation-play-state: paused;
/* Safari 和 Chrome */
}
</style>
\ No newline at end of file
<template>
<div class="unit-container">
<div class="unit-content-menu">
<swiper class="swiper unit-swiper" :options="unitSwiperOption" ref="videoSwiper">
<swiper-slide :class="[
'slide-item',
item.euId == curUnit.euId ? 'active' : '',
]" v-for="(item, index) in exhibitionUnits" :key="index" @click.native="handleClickUnit(item)">
{{ item.title }}
</swiper-slide>
</swiper>
<div class="swiper-button-prev unit-swiper-button-prev" slot="button-prev">
<i class="el-icon-arrow-left"></i>
</div>
<div class="swiper-button-next unit-swiper-button-next" slot="button-next">
<i class="el-icon-arrow-right"></i>
</div>
</div>
<div class="unit-content">
<div class="unit-content-container" v-for="(unitValue, unitTitle) in curUnit.expandUnitInfo"
:key="unitTitle">
<div class="unit-content-title">
{{ unitTitle }}
</div>
<div class="text-indent unit-content_intro" v-if="curUnit.intro" v-html="unitValue.intro"></div>
<div class="unit-content_images" v-if="unitValue.imagesVo && unitValue.imagesVo.length > 0">
<div class="imgs-title">单元图片</div>
<div class="unit-imgs">
<SlideImageGroup :imgList="unitValue.imagesVo" :needEnlarge="true"
v-if="unitValue.imagesVo.length > 3">
<template slot-scope="{ item }" slot="img">
<img :src="$getFullUrl(item.pressUrl)" alt=""
style="width: 100%; height: 100%; object-fit: contain" />
</template>
</SlideImageGroup>
<el-row v-if="unitValue.imagesVo.length > 0 && unitValue.imagesVo.length < 4" :gutter="10">
<el-col v-for="(item, index) in unitValue.imagesVo" :key="index"
:span="24 / unitValue.imagesVo.length" style="height:300px">
<img :src="$getFullUrl(item.pressUrl)" alt=""
style="width: 100%; height: 100%; object-fit: contain;cursor: pointer;"
@click="handelPreviewImages(unitValue.imagesVo)" />
</el-col>
</el-row>
</div>
</div>
<div class="unit-content_crs" v-if="
unitValue.culturalRelics && unitValue.culturalRelics.length > 0
">
<div class="imgs-title">单元文物</div>
<SlideImageGroup :imgList="unitValue.culturalRelics">
<template slot-scope="{ item }" slot="img">
<img :src="$getFullUrl(item.faceImagePressUrl)" alt="" style="
width: 100%;
height: 100%;
object-fit: fill;
cursor: pointer;
" @click="handleToCr(item)" />
</template>
<template slot-scope="{ item }" slot="info">
<div class="name">{{ item.name }}</div>
</template>
</SlideImageGroup>
</div>
</div>
</div>
</div>
</template>
<script>
import { swiper, swiperSlide } from "vue-awesome-swiper";
import SlideImageGroup from "@/components/SlideImageGroup";
import "swiper/dist/css/swiper.css";
export default {
name: "NormalStyleUnit",
components: {
swiper,
swiperSlide,
SlideImageGroup,
},
props: {
curUnit: {
type: Object,
default: null
},
exhibitionUnits: {
type: Array,
default: null
}
},
data() {
return {
unitSwiperOption: {
loop: false,
loopedSlides: 8, // looped slides should be the same
spaceBetween: 10,
slidesPerView: 4,
navigation: {
nextEl: ".unit-swiper-button-next",
prevEl: ".unit-swiper-button-prev",
},
},
}
},
methods: {
handleClickUnit(item) {
this.$emit('handleClickUnit', item)
},
handelPreviewImages(images) {
this.$emit('handelPreviewImages', images)
},
handleToCr(item) {
this.$emit('handleToCr', item)
}
}
}
</script>
<style lang="scss">
.unit-content_intro {
p {
// color: red !important;
// font-family: $defaultFontFamily !important;
}
}
</style>
<style lang="scss" scoped>
$themeColor:#132c33;
.unit-container {
margin-bottom: 40px;
position: relative;
}
.unit-content-menu {
margin-right: 40px;
padding: 0 20px;
position: relative;
.swiper-container {
width: 90%;
.slide-item {
padding: 8px;
border-radius: 4px;
color: $themeColor;
cursor: pointer;
text-overflow: ellipsis;
overflow: hidden;
width: 100%;
white-space: nowrap;
border: 1px solid $themeColor;
}
.active {
background: $themeColor;
color: #fff;
}
}
}
.swiper-button-next,
.swiper-button-prev {
// background-color: rgba(0,0,0,0.2);
// border-radius: 50%;
background-image: none;
width: 60px;
height: 60px;
display: flex;
justify-content: center;
align-items: center;
color: $themeColor;
font-weight: bolder;
font-size: 28px;
transform: translateY(-6px);
}
.unit-content {
flex: 1;
padding: 60px 40px 0;
.unit-content-container {}
.unit-content-title {
font-size: 24px;
line-height: 2;
display: flex;
justify-content: center;
margin-top: 48px;
}
.unit-content_intro {
font-size: 16px;
font-weight: 400;
color: #444444;
line-height: 36px;
text-indent: 32px;
margin-bottom: 20px;
}
.unit-content_images {
position: relative;
.unit-content_images_container {
height: 100%;
display: flex;
flex-direction: column;
background-color: #f5f5f9;
.images_img {
flex: 1;
}
.desc {
display: flex;
justify-content: center;
height: 40px;
align-items: center;
}
}
}
//单元文物和单元图片公共样式
.imgs-title {
margin: 16px 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
font-family: SourceHanSerifCN-Bold;
i {
margin: 0 10px;
font-size: 18px;
}
}
.unit-imgs {
// height: 300px;
}
.unit-content_crs {
position: relative;
.el-row {
.el-col {
margin-bottom: 10px;
.img-container {
background-color: #f5f5f9;
height: 250px;
.images_img {
height: 100%;
width: 100%;
position: relative;
cursor: pointer;
}
}
}
}
.desc {
display: flex;
justify-content: center;
padding: 10px;
align-items: center;
color: #333;
font-size: 14px;
}
}
.buttons {
display: flex;
justify-content: flex-end;
.btn {
display: flex;
align-content: center;
padding: 8px 10px;
// border: 1px solid $themeColor;
color: #666;
cursor: pointer;
&:hover {
color: $themeColor;
}
.svg-icon {
font-size: 22px;
margin: 0 4px;
}
}
}
}
</style>
\ No newline at end of file
...@@ -76,10 +76,15 @@ export const title = [{ ...@@ -76,10 +76,15 @@ export const title = [{
}, },
{ {
prop: "status", prop: "status",
label: "状态", label: "是否上架",
columnAlign: 'center', columnAlign: 'center',
isStatus: true isStatus: true
}, },
{
prop: "checkStatus",
label: "审核状态",
columnAlign: 'center',
},
{ {
prop: "themeType", prop: "themeType",
label: "模板主题", label: "模板主题",
......
...@@ -14,145 +14,78 @@ ...@@ -14,145 +14,78 @@
</div> </div>
<div class="tools"> <div class="tools">
<div class="tools-item"> <div class="tools-item">
<el-button <el-button type="primary" @click.native="handleOperation({ type: 'downloadTemplate' })" icon="el-icon-download">
type="primary" 下载导入模板</el-button>
@click.native="handleOperation({ type: 'downloadTemplate' })"
icon="el-icon-download" <el-button type="primary" @click.native="handleOperation({ type: 'viewImportRecord' })" icon="el-icon-document">
> 查看导入记录</el-button>
下载导入模板</el-button
>
<el-button
type="primary"
@click.native="handleOperation({ type: 'viewImportRecord' })"
icon="el-icon-document"
>
查看导入记录</el-button
>
</div> </div>
<div class="tools-item"> <div class="tools-item">
<el-button <el-button type="primary" @click.native="handleOperation({ type: 'add' })" icon="el-icon-plus">
type="primary" 添加</el-button>
@click.native="handleOperation({ type: 'add' })" <el-upload class="upload-button" :action="importZipUrl" :headers="headers" accept=".zip" :show-file-list="false"
icon="el-icon-plus" :before-upload="handleUpload" :on-success="handleSuccess" multiple>
> <el-button type="success" @click.native="handleOperation({ type: 'multiAdd' })" icon="el-icon-upload">
添加</el-button 整量导入</el-button>
>
<el-upload
class="upload-button"
:action="importZipUrl"
:headers="headers"
accept=".zip"
:show-file-list="false"
:before-upload="handleUpload"
:on-success="handleSuccess"
multiple
>
<el-button
type="success"
@click.native="handleOperation({ type: 'multiAdd' })"
icon="el-icon-upload"
>
整量导入</el-button
>
</el-upload> </el-upload>
</div> </div>
</div> </div>
<TablePage <TablePage :data="list.records" :tableTitle="tableTitle" :operates="tableOperates">
:data="list.records"
:tableTitle="tableTitle"
:operates="tableOperates"
>
<template v-slot:status="data"> <template v-slot:status="data">
<el-popconfirm <el-popconfirm :title="getStatusTitle(data.scope.status)" @onConfirm="handleChangeStatus(data.scope)">
:title="getStatusTitle(data.scope.status)" <el-switch slot="reference" :value="Boolean(Number(data.scope.status))"></el-switch>
@onConfirm="handleChangeStatus(data.scope)"
>
<el-switch
slot="reference"
:value="Boolean(Number(data.scope.status))"
></el-switch>
</el-popconfirm> </el-popconfirm>
</template> </template>
<template v-slot:displayType="data"> <template v-slot:displayType="data">
{{ dicts.displayType[data.scope.type] }} {{ dicts.displayType[data.scope.type] }}
</template> </template>
<template v-slot:checkStatus="data">
<!-- {{ data.scope.checkStatus }} -->
<el-tag type="primary" v-if="data.scope.checkStatus == 0">
待审核
</el-tag>
<el-tag type="success" v-if="data.scope.checkStatus == 1">
已通过
</el-tag>
<el-tag type="danger" v-if="data.scope.checkStatus == -2">
已驳回
</el-tag>
</template>
<template v-slot:faceImageUrl="data"> <template v-slot:faceImageUrl="data">
<img <img :src="
:src=" $getFullUrl(data.scope.faceImagePressUrl || data.scope.faceImageUrl)
$getFullUrl(data.scope.faceImagePressUrl || data.scope.faceImageUrl) " alt="暂无图片" v-if="
" $getFullUrl(data.scope.faceImagePressUrl || data.scope.faceImageUrl)
alt="暂无图片" " style="cursor: pointer" width="100px" @click="handelPreviewImages(data.scope.faceImageUrl)" />
v-if="
$getFullUrl(data.scope.faceImagePressUrl || data.scope.faceImageUrl)
"
style="cursor: pointer"
width="100px"
@click="handelPreviewImages(data.scope.faceImageUrl)"
/>
</template> </template>
<template v-slot:themeType="data"> <template v-slot:themeType="data">
{{ themeTypeCode(data.scope.themeType) }} {{ themeTypeCode(data.scope.themeType) }}
</template> </template>
<template v-slot:operates="scope"> <template v-slot:operates="scope">
<TableOperation <TableOperation :operations="tableOperations" :rawData="scope.scope.row" @handleOperation="handleOperation">
:operations="tableOperations" </TableOperation>
:rawData="scope.scope.row"
@handleOperation="handleOperation"
></TableOperation>
</template> </template>
</TablePage> </TablePage>
<el-pagination <el-pagination style="margin: 16px 0" @size-change="handleSizeChange" @current-change="handleCurrentChange"
style="margin: 16px 0" :current-page="Number(list.current)" :page-sizes="[10, 20, 50, 100]" :page-size="Number(list.size)"
@size-change="handleSizeChange" layout="total, sizes, prev, pager, next, jumper" :total="Number(list.total)" class="pagination">
@current-change="handleCurrentChange"
:current-page="Number(list.current)"
:page-sizes="[10, 20, 50, 100]"
:page-size="Number(list.size)"
layout="total, sizes, prev, pager, next, jumper"
:total="Number(list.total)"
class="pagination"
>
</el-pagination> </el-pagination>
<InfoEditDialog <InfoEditDialog :visible="editDialogVisible" :form="form" :currentPageIds="currentPageIds"
:visible="editDialogVisible" @handleClose="handleClose" @refresh="loadData" @changeDisplay="reloadDisplay" ref="InfoEditDialog" />
:form="form" <PreviewDialog v-if="Object.keys(curPreviewObj).length > 0" :visible="previewDialogVisible"
:currentPageIds="currentPageIds" :displayDetail="curPreviewObj" @handleClose="handleClosePreviewDialog" />
@handleClose="handleClose"
@refresh="loadData"
@changeDisplay="reloadDisplay"
ref="InfoEditDialog"
/>
<PreviewDialog
v-if="Object.keys(curPreviewObj).length > 0"
:visible="previewDialogVisible"
:displayDetail="curPreviewObj"
@handleClose="handleClosePreviewDialog"
/>
<!-- <CopyDialog <!-- <CopyDialog
:visible="copyDialogVisible" :visible="copyDialogVisible"
@handleClose="handleCloseCopyDialog" @handleClose="handleCloseCopyDialog"
@handleCopySelect="handleCopySelect" @handleCopySelect="handleCopySelect"
:list="list" :list="list"
/> --> /> -->
<ImportRecordDialog <ImportRecordDialog :visible="importRecordVisible" @reload="loadData" @handleClose="handleImportRecordClose" />
:visible="importRecordVisible"
@reload="loadData" <UploadListDialog :visible="multiUploadVisible" :filesList="filesList" @handleClose="handleMultiUploadClose"
@handleClose="handleImportRecordClose" @handleCancel="handleMultiUploadCancel" />
/>
<el-image-viewer v-if="imgViewerVisible" :on-close="closeImgViewer" :url-list="imgList" />
<UploadListDialog
:visible="multiUploadVisible"
:filesList="filesList"
@handleClose="handleMultiUploadClose"
@handleCancel="handleMultiUploadCancel"
/>
<el-image-viewer
v-if="imgViewerVisible"
:on-close="closeImgViewer"
:url-list="imgList"
/>
</div> </div>
</template> </template>
...@@ -661,12 +594,15 @@ export default { ...@@ -661,12 +594,15 @@ export default {
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
margin-bottom: 14px; margin-bottom: 14px;
.tools-item { .tools-item {
display: flex; display: flex;
&:last-child { &:last-child {
justify-content: flex-end; justify-content: flex-end;
} }
} }
.upload-button { .upload-button {
margin: 0 10px; margin: 0 10px;
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论