mirror of
https://github.com/eyebluecn/tank-front
synced 2024-04-21 12:31:55 +00:00
Add image preview plugin.
This commit is contained in:
+3
-1
@@ -17,6 +17,7 @@
|
||||
"animate.css": "^3.5.2",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"bootstrap": "^3.3.7",
|
||||
"clipboard": "^2.0.4",
|
||||
"editor.md": "^1.5.0",
|
||||
"element-ui": "^2.0.2",
|
||||
"enquire.js": "^2.1.6",
|
||||
@@ -33,7 +34,8 @@
|
||||
"vue-resource": "^1.3.4",
|
||||
"vue-router": "^3.0.1",
|
||||
"vuex": "^3.0.1",
|
||||
"vuex-router-sync": "^5.0.0"
|
||||
"vuex-router-sync": "^5.0.0",
|
||||
"x-photoswipe": "^4.1.3-rc.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^7.1.2",
|
||||
|
||||
+2
-2
@@ -151,10 +151,10 @@
|
||||
|
||||
that.$emit('createDirectorySuccess', that.imageCache)
|
||||
|
||||
}, function (response) {
|
||||
}, function (errorMessage) {
|
||||
that.director.createMode = false
|
||||
that.editMode = false
|
||||
Message.error(response.data.msg)
|
||||
Message.error(errorMessage)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
@@ -61,17 +61,16 @@
|
||||
<div class="middle-part">
|
||||
|
||||
<span class="matter-name-edit" v-if="matter.editMode">
|
||||
|
||||
<input ref="editInput" class="form-control"
|
||||
:class="matter.uuid"
|
||||
v-model="matter.name"
|
||||
v-model="renameMatterName"
|
||||
placeholder="请输入名称"
|
||||
@blur="blurTrigger()"
|
||||
v-on:keyup.13="enterTrigger()"/>
|
||||
</span>
|
||||
<span class="matter-name" :class="{'alien':matter.alien}" v-else>
|
||||
{{matter.name}} <i class="fa fa-unlock" v-if="!matter.dir && !matter.privacy" title="公有文件,任何人可以访问"></i>
|
||||
</span>
|
||||
{{matter.name}} <i class="fa fa-unlock" v-if="!matter.dir && !matter.privacy" title="公有文件,任何人可以访问"></i>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -139,14 +138,17 @@
|
||||
import $ from 'jquery'
|
||||
import Director from './Director'
|
||||
import {Message, MessageBox, Notification} from 'element-ui'
|
||||
import {setInputSelection} from '../../../common/util/Utils'
|
||||
import {currentHost, setInputSelection} from '../../../common/util/Utils'
|
||||
import PhotoSwipeHelper from "../../../common/plugin/photoswipe/PhotoSwipeHelper";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
//正在向服务器提交rename的请求
|
||||
renamingLoading: false,
|
||||
showMore: false
|
||||
showMore: false,
|
||||
//正在重命名的临时字段
|
||||
renameMatterName: null
|
||||
}
|
||||
},
|
||||
components: {
|
||||
@@ -181,7 +183,8 @@
|
||||
if (this.matter.dir) {
|
||||
this.$emit('goToDirectory', that.matter.uuid)
|
||||
} else {
|
||||
this.download()
|
||||
PhotoSwipeHelper.showPhoto(that.matter.getDownloadUrl())
|
||||
//this.download()
|
||||
}
|
||||
|
||||
},
|
||||
@@ -220,12 +223,14 @@
|
||||
//告诉导演,自己正在编辑
|
||||
this.director.renameMode = true
|
||||
this.matter.editMode = true
|
||||
this.renameMatterName = this.matter.name
|
||||
|
||||
//稍作延迟,vue的组件才能加载出来
|
||||
setTimeout(function () {
|
||||
|
||||
let dotIndex = that.matter.name.lastIndexOf('.')
|
||||
if (dotIndex === -1) {
|
||||
setInputSelection(that.$refs.editInput, 0, that.matter.name.length)
|
||||
setInputSelection(that.$refs.editInput, 0, that.renameMatterName)
|
||||
} else {
|
||||
setInputSelection(that.$refs.editInput, 0, dotIndex)
|
||||
}
|
||||
@@ -239,17 +244,18 @@
|
||||
if (that.renamingLoading) {
|
||||
return
|
||||
}
|
||||
|
||||
that.renamingLoading = true
|
||||
this.matter.httpRename(function () {
|
||||
this.matter.httpRename(that.renameMatterName, function () {
|
||||
that.renamingLoading = false
|
||||
Message.info('重命名成功!')
|
||||
Message.success('重命名成功!')
|
||||
//告诉导演,自己编辑完毕
|
||||
that.director.renameMode = false
|
||||
that.matter.editMode = false
|
||||
|
||||
}, function (response) {
|
||||
}, function (errorMessage) {
|
||||
that.renamingLoading = false
|
||||
Message.error(response.data.msg)
|
||||
Message.error(errorMessage)
|
||||
//告诉导演,自己编辑完毕
|
||||
that.director.renameMode = false
|
||||
that.matter.editMode = false
|
||||
@@ -267,10 +273,10 @@
|
||||
|
||||
that.$emit('createDirectorySuccess', that.matter)
|
||||
|
||||
}, function (response) {
|
||||
}, function (errorMessage) {
|
||||
that.director.createMode = false
|
||||
that.editMode = false
|
||||
Message.error(response.data.msg)
|
||||
Message.error(errorMessage)
|
||||
})
|
||||
},
|
||||
blurTrigger() {
|
||||
@@ -291,14 +297,13 @@
|
||||
},
|
||||
clipboard() {
|
||||
|
||||
let $temp = $("<input>");
|
||||
$("body").append($temp);
|
||||
$temp.val(location.protocol + "//" + location.host + this.matter.getDownloadUrl()).select();
|
||||
document.execCommand("copy");
|
||||
$temp.remove();
|
||||
|
||||
Message.success('已复制!');
|
||||
|
||||
let textToCopy = currentHost() + this.matter.getDownloadUrl();
|
||||
this.$copyPlguin.copy(textToCopy, function () {
|
||||
Message.success({
|
||||
message: "复制成功!",
|
||||
center: true
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
@@ -7,6 +7,7 @@ import User from '../user/User'
|
||||
import UserInputSelection from '../../../backyard/user/widget/UserInputSelection'
|
||||
import Vue from "vue"
|
||||
import {FilterType} from "../base/FilterType";
|
||||
import {handleImageUrl} from "../../util/ImageUtil";
|
||||
|
||||
export default class Matter extends BaseEntity {
|
||||
|
||||
@@ -33,7 +34,6 @@ export default class Matter extends BaseEntity {
|
||||
this.privacy = true
|
||||
this.path = null
|
||||
|
||||
|
||||
/*
|
||||
这部分是辅助UI的字段信息
|
||||
*/
|
||||
@@ -54,6 +54,7 @@ export default class Matter extends BaseEntity {
|
||||
//实时上传速度 byte/s
|
||||
this.speed = 0
|
||||
|
||||
|
||||
}
|
||||
|
||||
getFilters() {
|
||||
@@ -96,7 +97,10 @@ export default class Matter extends BaseEntity {
|
||||
} else if (startWith(mimeType, 'text')) {
|
||||
return "/static/img/file/text.svg"
|
||||
} else if (startWith(mimeType, 'image')) {
|
||||
return "/static/img/file/image.svg"
|
||||
|
||||
//对于图片,使用其缩略图
|
||||
return handleImageUrl(this.getDownloadUrl(), false, 100, 100)
|
||||
|
||||
} else if (endWith(this.name, 'zip') || endWith(this.name, 'rar') || endWith(this.name, '7z') || endWith(this.name, 'tar') || endWith(this.name, 'tar') || endWith(this.name, 'gz')) {
|
||||
return "/static/img/file/archive.svg"
|
||||
} else {
|
||||
@@ -128,20 +132,25 @@ export default class Matter extends BaseEntity {
|
||||
}, errorCallback)
|
||||
}
|
||||
|
||||
httpRename(successCallback, errorCallback) {
|
||||
|
||||
httpRename(name, successCallback, errorCallback) {
|
||||
let that = this
|
||||
this.httpPost(Matter.URL_MATTER_RENAME, {'uuid': this.uuid, 'name': this.name}, function (response) {
|
||||
this.httpPost(Matter.URL_MATTER_RENAME, {'uuid': this.uuid, 'name': name}, function (response) {
|
||||
that.render(response.data.data)
|
||||
typeof successCallback === 'function' && successCallback(response)
|
||||
}, errorCallback)
|
||||
}
|
||||
|
||||
|
||||
httpChangePrivacy(privacy, successCallback, errorCallback) {
|
||||
let that = this
|
||||
this.httpPost(Matter.URL_CHANGE_PRIVACY, {'uuid': this.uuid, 'privacy': privacy}, function (response) {
|
||||
that.privacy = privacy
|
||||
Message.success(response.data.msg)
|
||||
typeof successCallback === 'function' && successCallback(response)
|
||||
if (typeof successCallback === "function") {
|
||||
successCallback(response)
|
||||
} else {
|
||||
Message.success(response.data.msg)
|
||||
}
|
||||
}, errorCallback)
|
||||
}
|
||||
|
||||
@@ -363,7 +372,7 @@ export default class Matter extends BaseEntity {
|
||||
}
|
||||
|
||||
getDownloadUrl() {
|
||||
return Vue.http.options.root + '/alien/download/' + this.uuid + '/' + this.name
|
||||
return '/api/alien/download/' + this.uuid + '/' + this.name
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<button ref="clipboardBtn"
|
||||
class="copy-plugin-clipboard-btn"
|
||||
data-clipboard-text="textToCopy"
|
||||
style="position: absolute;opacity:0;">
|
||||
{{textToCopy}}
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Clipboard from 'clipboard';
|
||||
import {safeCallback} from "../../util/Utils";
|
||||
|
||||
let nop = () => {
|
||||
};
|
||||
//这个组件主要用于提供dom元素。
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
textToCopy: "",
|
||||
clipboardBtn: null,
|
||||
successCallback: null,
|
||||
errorCallback: null
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
props: {},
|
||||
watch: {},
|
||||
methods: {
|
||||
copy(text, successCallback, errorCallback) {
|
||||
|
||||
let that = this;
|
||||
|
||||
this.successCallback = successCallback
|
||||
this.errorCallback = errorCallback
|
||||
|
||||
this.textToCopy = text;
|
||||
|
||||
//这里不用延迟设置,否则backyard会出错
|
||||
that.$refs.clipboardBtn.setAttribute("data-clipboard-text", text)
|
||||
that.$refs.clipboardBtn.click()
|
||||
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let that = this;
|
||||
this.clipboardBtn = new Clipboard(this.$refs.clipboardBtn);
|
||||
|
||||
this.clipboardBtn.on('success', function (e) {
|
||||
console.info('clipboard success');
|
||||
safeCallback(that.successCallback)()
|
||||
});
|
||||
|
||||
this.clipboardBtn.on('error', function (e) {
|
||||
console.error('clipboard error:', e);
|
||||
safeCallback(that.errorCallback)()
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,32 @@
|
||||
import CopyPlguinLayout from "./CopyPlguinLayout"
|
||||
|
||||
export default class CopyPlugin {
|
||||
|
||||
constructor() {
|
||||
this.$vm = null;
|
||||
}
|
||||
|
||||
install(Vue, options) {
|
||||
|
||||
const CopyPlguinComponent = Vue.extend(CopyPlguinLayout)
|
||||
if (!this.$vm) {
|
||||
this.$vm = new CopyPlguinComponent({
|
||||
el: document.createElement('div'),
|
||||
propsData: {}
|
||||
})
|
||||
document.body.appendChild(this.$vm.$el)
|
||||
}
|
||||
|
||||
Vue.$copyPlguin = this;
|
||||
|
||||
Vue.mixin({
|
||||
created: function () {
|
||||
this.$copyPlguin = Vue.$copyPlguin
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
copy(text, successCallback) {
|
||||
this.$vm.copy(text, successCallback);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
import PhotoSwipeLayout from "./PhotoSwipeLayout";
|
||||
import Vue from 'vue'
|
||||
import PhotoSwipe from 'x-photoswipe/dist/photoswipe'
|
||||
import PhotoSwipeUIDefault from 'x-photoswipe/dist/photoswipe-ui-default'
|
||||
//PhotoSwipe的样式
|
||||
import "x-photoswipe/dist/photoswipe.css";
|
||||
import "x-photoswipe/dist/default-skin/default-skin.css";
|
||||
|
||||
/**
|
||||
*
|
||||
* 图片预览控件,主要提供给H5端使用。
|
||||
*/
|
||||
export default class PhotoSwipeHelper {
|
||||
|
||||
constructor() {
|
||||
|
||||
//核心
|
||||
this.photoSwipe = null;
|
||||
|
||||
//小本本记住,动态创建Vue组件。
|
||||
let ComponentClass = Vue.extend(PhotoSwipeLayout)
|
||||
this.vueInstance = new ComponentClass()
|
||||
|
||||
this.init()
|
||||
}
|
||||
|
||||
//初始化工作一口气做完
|
||||
init() {
|
||||
//挂载组件,非常重要。否则$el就不会出现。
|
||||
this.vueInstance.$mount()
|
||||
document.body.appendChild(this.vueInstance.$el)
|
||||
}
|
||||
|
||||
|
||||
//展示一张图片
|
||||
showSinglePhoto(url, width = 0, height = 0) {
|
||||
|
||||
let that = this;
|
||||
let items = [{
|
||||
src: url,
|
||||
w: width,
|
||||
h: height
|
||||
}];
|
||||
|
||||
let options = {
|
||||
//不需要历史纪录
|
||||
history: false,
|
||||
//不需要全屏按钮
|
||||
fullscreenEl: false,
|
||||
//不需要分享按钮
|
||||
shareEl: false,
|
||||
//点击不要让控制按钮消失
|
||||
tapToToggleControls: false,
|
||||
//当前从第0张展示。
|
||||
index: 0
|
||||
};
|
||||
this.photoSwipe = new PhotoSwipe(this.vueInstance.$el, PhotoSwipeUIDefault, items, options);
|
||||
|
||||
this.photoSwipe.listen('gettingData', function (index, item) {
|
||||
if (!item.w || !item.h || item.w < 1 || item.h < 1) {
|
||||
const img = new Image()
|
||||
img.onload = function () {
|
||||
item.w = this.width
|
||||
item.h = this.height
|
||||
that.photoSwipe.updateSize(true)
|
||||
}
|
||||
img.src = item.src
|
||||
}
|
||||
})
|
||||
this.photoSwipe.init();
|
||||
|
||||
this.photoSwipe.listen('close', () => {
|
||||
console.log("photoSwipe事件:close")
|
||||
})
|
||||
this.photoSwipe.listen('afterChange', (a, b) => {
|
||||
console.log("photoSwipe事件:afterChange")
|
||||
})
|
||||
}
|
||||
|
||||
//展示一系列图片
|
||||
showMultiPhoto(urls = [], index = 0) {
|
||||
|
||||
let that = this;
|
||||
let items = [];
|
||||
urls.forEach((url) => {
|
||||
items.push({
|
||||
src: url,
|
||||
w: 0,
|
||||
h: 0
|
||||
})
|
||||
})
|
||||
|
||||
let options = {
|
||||
//不需要历史纪录
|
||||
history: false,
|
||||
//不需要全屏按钮
|
||||
fullscreenEl: false,
|
||||
//不需要分享按钮
|
||||
shareEl: false,
|
||||
//点击不要让控制按钮消失
|
||||
tapToToggleControls: false,
|
||||
//当前从第0张展示。
|
||||
index: index
|
||||
};
|
||||
this.photoSwipe = new PhotoSwipe(this.vueInstance.$el, PhotoSwipeUIDefault, items, options);
|
||||
|
||||
this.photoSwipe.listen('gettingData', function (index, item) {
|
||||
if (!item.w || !item.h || item.w < 1 || item.h < 1) {
|
||||
const img = new Image()
|
||||
img.onload = function () {
|
||||
item.w = this.width
|
||||
item.h = this.height
|
||||
that.photoSwipe.updateSize(true)
|
||||
}
|
||||
img.src = item.src
|
||||
}
|
||||
})
|
||||
this.photoSwipe.init();
|
||||
|
||||
this.photoSwipe.listen('close', () => {
|
||||
//photoSwipe事件:close
|
||||
})
|
||||
this.photoSwipe.listen('afterChange', (a, b) => {
|
||||
//photoSwipe事件:afterChange
|
||||
})
|
||||
}
|
||||
|
||||
//单例,为了只有一个实例
|
||||
static singleton = null;
|
||||
|
||||
//使用懒加载
|
||||
static getSingleton() {
|
||||
if (!PhotoSwipeHelper.singleton) {
|
||||
PhotoSwipeHelper.singleton = new PhotoSwipeHelper();
|
||||
}
|
||||
return PhotoSwipeHelper.singleton;
|
||||
}
|
||||
|
||||
//展示一张图片。
|
||||
static showPhoto(url) {
|
||||
PhotoSwipeHelper.getSingleton().showSinglePhoto(url);
|
||||
}
|
||||
|
||||
|
||||
//展示一系列图片
|
||||
static showPhotos(urls, index = 0) {
|
||||
PhotoSwipeHelper.getSingleton().showMultiPhoto(urls, index);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<!-- Root element of PhotoSwipe. Must have class pswp. -->
|
||||
<div ref="root1" class="pswp vux-previewer" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<!-- Background of PhotoSwipe.
|
||||
It's a separate element as animating opacity is faster than rgba(). -->
|
||||
<div class="pswp__bg"></div>
|
||||
<!-- Slides wrapper with overflow:hidden. -->
|
||||
<div class="pswp__scroll-wrap">
|
||||
<!-- Container that holds slides.
|
||||
PhotoSwipe keeps only 3 of them in the DOM to save memory.
|
||||
Don't modify these 3 pswp__item elements, data is added later on. -->
|
||||
<div class="pswp__container">
|
||||
<div class="pswp__item"></div>
|
||||
<div class="pswp__item"></div>
|
||||
<div class="pswp__item"></div>
|
||||
</div>
|
||||
<!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
|
||||
<div class="pswp__ui pswp__ui--hidden">
|
||||
<div class="pswp__top-bar">
|
||||
<!-- Controls are self-explanatory. Order can be changed. -->
|
||||
<div class="pswp__counter"></div>
|
||||
<button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
|
||||
<button class="pswp__button pswp__button--share" title="Share"></button>
|
||||
<button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
|
||||
<button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>
|
||||
<!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
|
||||
<!-- element will get class pswp__preloader--active when preloader is running -->
|
||||
<div class="pswp__preloader">
|
||||
<div class="pswp__preloader__icn">
|
||||
<div class="pswp__preloader__cut">
|
||||
<div class="pswp__preloader__donut"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
|
||||
<div class="pswp__share-tooltip"></div>
|
||||
</div>
|
||||
<button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)"></button>
|
||||
<button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)"></button>
|
||||
<div class="pswp__caption">
|
||||
<div class="pswp__caption__center"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
//这个组件主要用于提供dom元素。
|
||||
export default {
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {},
|
||||
props: {},
|
||||
|
||||
watch: {},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
@@ -27,7 +27,7 @@ export function handleImageUrl(url = null, origin = false, width = 200, height =
|
||||
if (origin) {
|
||||
return url;
|
||||
} else {
|
||||
return url + "?imageProcess=resize&imageResizeM=fill&imageResizeW=" + width + "&imageResizeH=" + height
|
||||
return url + "?ir=fill_" + width + "_" + height
|
||||
}
|
||||
} else {
|
||||
if (NumberUtil.fractionEqual(1, 1, width, height)) {
|
||||
|
||||
@@ -15,8 +15,6 @@ const state = {
|
||||
},
|
||||
debug: true,
|
||||
|
||||
host: '/api',
|
||||
|
||||
//当前版本信息。
|
||||
version: {
|
||||
identifier: 'cn.eyeblue.tank',
|
||||
|
||||
+5
-1
@@ -4,6 +4,9 @@ import "babel-polyfill";
|
||||
//custom directive.
|
||||
import "./common/directive/directive"
|
||||
|
||||
//自定义文本框插件
|
||||
import CopyPlugin from "./common/plugin/copy/CopyPlugin";
|
||||
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
import store from './common/vuex'
|
||||
@@ -25,9 +28,10 @@ Vue.store = store;
|
||||
Vue.router = router;
|
||||
sync(store, router)
|
||||
Vue.use(VueResource)
|
||||
Vue.http.options.root = store.state.host;
|
||||
Vue.use(NProgress)
|
||||
|
||||
//使用自定义插件
|
||||
Vue.use(new CopyPlugin())
|
||||
|
||||
// register global utility filters.
|
||||
Object.keys(filters).forEach(key => {
|
||||
|
||||
Reference in New Issue
Block a user