iview UI或者element UI 实现回车键盘登入系统
- 绑定事件用 @keyup.enter.native="方法名"
<Form-item label="密码" prop="password">
<Input type="password" v-model="formLogin.password"
@keyup.enter.native="handleLogin('formLogin')">
<Icon type="ios-locked-outline" slot="prepend"></Icon>
</Input>
</Form-item>
<script>
import store from '../../store';
export default {
data () {
return {
loading:false,
formLogin: {
username: '',
password: ''
},
ruleLogin: {
username: [
{ required: true, message: '请填写用户名', trigger: 'blur' }
],
password: [
{ required: true, message: '请填写密码', trigger: 'blur' },
{ type: 'string', min: 4, message: '密码长度不能小于6位', trigger: 'blur' }
]
},
}
},
created:function(){
},
methods: {
handleLogin(name) {
this.$refs[name].validate((valid) => {
if (valid) {
this.loading = true;
this.$store.dispatch('Login', this.formLogin).then(response => {
this.loading = false;
this.$router.push({ path: '/space/person' })
},(response)=>{
this.loading = false;
this.$Message.error(response.data.message);
}).catch(err => {
this.loading = false;
});
} else {
this.loading = false;
this.$Message.error('表单验证失败!');
}
})
},
handleReset(name) {
this.loading = false;
this.$refs[name].resetFields();
},
}
}
</script>
- 记住密码功能(利用cookie)
data() {
return {
loading: false,
formLogin: {
username: "",
password: ""
},
checked:true,
ruleLogin: {
username: [{ required: true, message: "请填写用户名", trigger: "blur" }],
password: [
{ required: true, message: "请填写密码", trigger: "blur" },
{ type: "string", min: 4, message: "密码长度不能小于6位", trigger: "blur" }
]
}
};
},
methods: {
handleLogin(name) {
this.$refs[name].validate(valid => {
if (valid) {
this.loading = true;
this.$store
.dispatch("Login", this.formLogin)
.then(
response => {
this.loading = false;
this.$router.push({ path: "/space/person" });
if(this.checked) {
Cookies.set("username", this.formLogin.username, {
expires: 7
})
Cookies.set("password", this.formLogin.password, {
expires: 7
})
}else{
Cookies.remove("username");
Cookies.remove("password");
}
},
response => {
this.loading = false;
this.$Message.error(response.data.message);
}
)
.catch(err => {
this.loading = false;
});
} else {
this.loading = false;
this.$Message.error("表单验证失败!");
}
});
},
handleReset(name) {
this.loading = false;
this.$refs[name].resetFields();
},
},
mounted(){
let username = Cookies.get("username")
let password = Cookies.get("password")
this.formLogin = {
username: username,
password: password
};
}
vue2.0用jsx语法
- 第一步下载:
npm install\
babel-plugin-syntax-jsx\
babel-plugin-transform-vue-jsx\
babel-helper-vue-jsx-merge-props\
babel-preset-es2015\
--save-dev
- 第二步在.babelrc添加配置项
{
"presets": ["es2015"],
"plugins": ["transform-vue-jsx"]
}
完整的配置如下:
{
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-2",
"es2015"
],
"plugins": [
"transform-runtime",
"transform-vue-jsx"
],
"env": {
"test": {
"presets": ["env", "stage-2"],
"plugins": ["istanbul"]
}
}
}
- 具体用法 :在vue render涵数中渲染
render:(h,params)=>{
let iconType = params.row.isFile==true ? 'document' : 'folder';
let id = params.row.id;
let name = params.row.name;
let isFile = params.row.isFile;
return(
<div onClick={()=>this.showDetail(id,isFile)} style={{cursor:'pointer'}}>
<Icon type={iconType} style={{ fontSize:'16px'}}></Icon>
<span domPropsInnerHTML={name} style={{ marginLeft:'5px',cursor:'pointer'}} onClick=
{(e)=>this.handleResource(id,isFile,e)}></span>
</div>
)
}
iview 中动态引用Dropdown组件无法绑定事件
- 只能用onOn-click={(name,id)=>this.changeSelected(name,resourceId)}
- 例如:
return (
<div style={{ textAlign: 'left' }}>
<span style={{ color: '#ccc', display:'inline-block', width:'120px' }}>{fromInfo}</span>
{
canShare ?
<Button type="text" onClick={()=>this.getShare(isFile,resourceId,resourceName)}>
<Icon size='16' type="android-share-alt"></Icon>
</Button>
:
<Button type="text" disabled>
<Icon size='16' type="android-share-alt"></Icon>
</Button>
}
<a href={resourceURL} style={{ marginRight:'13px'}}><Icon size='16' type="android-download"></Icon></a>
<Dropdown placement="bottom-start" onOn-click={(name,id)=>this.changeSelected(name,resourceId)}>
<Icon type="more"></Icon>
<Dropdown.Menu slot="list">
<Dropdown.Item name='copy'>Copy</Dropdown.Item>
<Dropdown.Item name='move'>Move</Dropdown.Item>
{canDelete ? <Dropdown.Item name='delete' >Delete</Dropdown.Item> : ""}
</Dropdown.Menu>
</Dropdown>
</div>
);
ivew 中实现 无限层插件
数据格式
//准备数据
let testData = {
"department": [
{
"departmentName": "测试1",
"departmentDesc": "盛达康网络",
"parentId": "",
"id": "594a28fb1c8652a01f0301"
},
{
"departmentName": "测试-一级子级",
"parentId": "594a28fb1c8652a01f0301",
"id": "594a3910202469941"
},
{
"departmentName": "测试-二级子级",
"parentId": "594a3910202469941",
"id": "594a391020246994asasd1"
},
{
"departmentName": "盛达康",
"departmentDesc": "盛达康网络",
"parentId": "",
"id": "594a28fb1c8652a01f030126"
},
{
"departmentName": "开发",
"parentId": "594a28fb1c8652a01f030126",
"id": "594a3910202469941c349d7c"
},
{
"departmentName": "运营",
"parentId": "594a28fb1c8652a01f030126",
"id": "594a4509202469941c349d7f"
},
]
}
<template>
<Tree :data="baseData" show-checkbox ></Tree>
</template>
<script>
export default {
data () {
return {
baseData: []
}
},
methods:{
getTree(){
//准备数据
let testData = null;
ResourceAPI.getTree(this.moveId).then((response) => {
let resp = response.data;
if (resp.success == true) {
testData = resp.data;
var data = testData.department
let treedata = []
//查找最顶层
let len = data.length
for(let j=0;j<len;j++){
data[j].expand = false;
data[j].title = data[j].departmentName
if(data[j].parentId == ""){
treedata.push({
"expand":false,
"title":data[j].departmentName,
"id":data[j].id
})
}
}
//找到跟最高层id相关的子子孙孙,并给子孙添加lev
var treedataLevs =[]
for(let h=0,ls=treedata.length;h<ls;h++){
treedataLevs.push({
treedataLev:sonsTree(data,treedata[h].id)
})
}
for(let p=0,lq=treedataLevs.length;p<lq;p++){
var treedataLev = treedataLevs[p].treedataLev
//找到最高层的lev
var maxLev = 0
for(let i=0,lt=treedataLev.length;i<lt;i++){
if(parseInt(treedataLev[i].lev) > maxLev){
maxLev = parseInt(treedataLev[i].lev)
}else{
maxLev = maxLev
}
}
//比较当前层和上一层的数据,然后做处理
var needLev = maxLev
var maxLevTree = []
var maxLevTreePrev = []
for(let m=0;m<maxLev;m++){
maxLevTree = getLevArr(treedataLev,needLev)
maxLevTreePrev = getLevArr(treedataLev,needLev-1)
for(var j=0,lp=maxLevTreePrev.length;j<lp;j++){
maxLevTreePrev[j].children = new Array()
for(var i=0,lm=maxLevTree;i<lm.length;i++){
if(maxLevTree[i].parentId == maxLevTreePrev[j].id){
maxLevTreePrev[j].children.push(maxLevTree[i])
}
}
}
needLev--
}
treedata[p].children = maxLevTreePrev
}
this.baseData = treedata
//找出同一级的数据
function getLevArr(arr,lev){
var newarr = []
for(let i=0,la=arr.length;i<la;i++){
//这里对arr 的children 做处理
arr.children = new Array()
if(parseInt(arr[i].lev) == lev){
newarr.push(arr[i])
}
}
return newarr
}
//给每个数据添加一个lev
function sonsTree(arr,id){
var temp = [],lev=0;
var forFn = function(arr, id,lev){
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
if (item.parentId==id) {
item.lev=lev;
temp.push(item);
forFn(arr,item.id,lev+1);
}
}
};
forFn(arr, id,lev);
return temp;
}
}
}).catch(error => {
});
},
created:function(){
this.getTree()
}
}
</script>
iview中用递归完成tree的请求
<template>
<Tree :data="baseData" show-checkbox @on-select-change='movecheck' ></Tree>
</template>
<script>
import ResourceAPI from 'api/resource';
export default {
data () {
return {
baseData: [],
self_id:0,
}
},
methods: {
getTree(){
ResourceAPI.getTree().then((response) => {
let resp = response.data;
this.baseData=response.data.data;
if (resp.success == true) {
let datass = resp.data;
this.generateFolderTree(datass);
}
}).catch(error => {
});
},
// 回调函数
generateFolderTree(datasource){
datasource.forEach((item,index)=>{
item.expand = true;
item.id = item.id;
// item.disabled=true;
item.checked=false;
item.title = item.name;
if(item.children.length>0) {
this.generateFolderTree(item.children);
}
})
return datasource;
},
movecheck(selfID){
this.self_id= selfID[0].id;
//把self_id父组件
this.$emit('get_move_id',this.self_id);
}
},
created(){
this.getTree();
}
}
</script>
vue自动完成搜索功能的数据请求处理
- 参考博客:(http://www.cnblogs.com/fhen/p/6781144.html)
- 在现在的互联网世界里,自动完成的搜索功能是一个很常见的功能。比如百度、搜狗、360搜索 ...
功能描述一下大概是这个样子的:有一个搜索框,用户在里面输入要查询的条件,系统会“智能”判断用户输完了,然后自动根据条件去搜索相关的数据返回给用户。
网上这个自动完成的插件很多,实现自动完成功能也不复杂,特别是像vue、angularjs、react这类可以实现双向绑定的库出现以后,实现就更方便了。本文不讲自动完成功能的实现,而是介绍自动完成功能后续数据的请求该如何考虑,主要要处理下面两个问题。
问题1:自动完成搜索触发频率如何控制?
问什么要控制自动完成搜索的触发频率呢?大家都知道,自动完成触发基本上都是键盘响应事件,在文本框中输入一个文本就触发一次,这个太频繁了。比如我要输入的搜索条件是abcdefg,输入a触发一次,接着输入b再触发一次,接着输入c又触发一次...,等到我把这几个字母全部输完就触发了7次,假设请求逻辑没有限制的话,这就会发生7次数据请求,而实际上只有第7次的结果才是我想要的,其它6次数据请求完全是浪费资源。在用户需求上来说,用户真正希望的是搜索框能自动识别到用户的abcdefg这一串字符全部输入完了,然后再触发请求数据。对于一些变态的输入,比如按住某一个建不放,还不知道要触发多少次。
所以控制自动完成搜索的触发频率还是很有必要的。当然,搜索框能完全智能的知道用户所想然后去触发,在目前来说还是做不到的。
我这里使用控制空闲时间的间隔的方式来限制自动完成搜索的触发频率。使用lodash库中的debounce方法。
问题2:数据还在请求中时再次触发请求,上次的请求如何取消?
为什么要取消上次的请求你?举个例了,我输入了查询条件"xxx",数据请求发送了,我们暂且把它称为请求1。因为某些原因(比如说网络不好,这个条件的数据量大等等),请求1响应很慢,我们在请求1还没用拿到数据的时候又输入查询条件"yyy"发送了请求2,没想到这个请求2数据响应特别快,一下子就得到了数据data,我们准备把data展示出来,这时候请求1的数据回来了,data会被覆盖掉,也就是说这时候我们用"yyy"的条件查询得到了"xxx"条件的查询结果。这个结果其实是超出用户期望的。所以在发送新的请求之前,如果上次的请求还没有结束,我们就需要取消掉它。
我这里使用axios的CancelToken来取消请求。
- serach组件的调用
<SearchComponent
tip='请输入搜索内容'
search-url='search/'
:headers-token="searchHeaders"
:space-type="space"
:search-type="getSelectValue"
@outputResult="handleSearchResult" />
</SearchComponent>
- serach组件的引用
<script>
import SearchComponent from 'views/public/search.vue';
export default{
components:{
SearchComponent,
},
methods:{
handleSearchResult(item){
console.log(item.name+"选中的名称");
},
}
}
</script>
- serach组件
<template>
<div style="width: 100%">
<Input icon="ios-search" v-model="keyWord" :placeholder="tip" class="searchInput" @on-change="search(requestUrl,keyWord,resultset,headersToken,spaceType,searchType)" @on-blur="inputKeyWord"></Input>
<div :class="{resultsetContainer:true, resultsetHide:hideResultset}">
<div v-for="result in resultset" @click='selectResult(result)' class="result">{{result.value}}</div>
</div>
</div>
</template>
<script>
//
import _ from 'lodash'; //引入lodash
import axios from 'axios' //引入axios
//请求canceltoken列表
let sources = [];
export default{
props:{
tip:{
type:String
},
searchUrl:{
type:String
},
headersToken:{
type:Object
},
spaceType:{
type:String
},
searchType:{
type:String
}
},
data(){
let mockResultset = [
{id:1, value:'name1'},
{id:2, value:'name2'},
{id:3, value:'name3'},
];
let selectedResult = {
id:0,
value:''
}
return {
// requestUrl
requestUrl:process.env.BASE_API+this.searchUrl,
// search value
keyWord:'',
// result
hideResultset:true,
selectedResult:selectedResult,
resultset:mockResultset,
value1: '',
data1: []
}
},
watch:{
resultset:function(newValue, oldValue){
if(newValue.length > 0){
this.hideResultset = false;
}
else{
this.hideResultset = true;
}
},
},
methods:{
handleSearch1 (value) {
this.data1 = !value ? [] : [
value,
value + value,
value + value + value
];
},
// 搜索功能
// 使用_.debounce控制搜索的触发频率, 500ms后执行
// 准备搜索
search:_.debounce((url,keyword,resultset,headersToken,spaceType,searchType)=>{
// 没有就不搜索
if(keyword==""){
resultset.length=0;
}
else{
// 删除已经结束的请求
_.remove(sources, (n)=>{
return n.source === null;
})
// 取消还未结束的请求
sources.forEach(function (item) {
if (item !== null && item.source !== null && item.status === 1) {
item.status = 0;
}
});
//创建新的请求cancelToken,并设置状态请求中
var sc = {
source: axios.CancelToken.source(),
status: 1 //状态1:请求中,0:取消中
};
//这个对象加入数组中
sources.push(sc);
//开始搜索数据
url = url+"?space="+spaceType+"&type="+searchType+"&name="+keyword;
axios.get( url, {
cancelToken: sc.source.token,
headers:headersToken
}).then((res)=> {
//请求成功
sc.source = null; //置空请求canceltoken
res = res.data;
if(res.success == true){
resultset.length = 0;
res.data.results.forEach((item)=>{
resultset.push({
id:item.id,
value:item.name
});
});
}
}).catch((err)=>{
//请求失败
sc.source = null; //置空请求canceltoken
});
}
},500),
// 当失去对搜索框的焦点
inputKeyWord(){
if(this.keyWord==""){
this.hideResultset = true;
this.resultset.length = 0;
}
else{
let item = {id:0, value:this.keyWord};
this.$emit("outputResult", this.keyWord);
}
// this.hideResultset = true;
},
// 选择筛选出的节点
selectResult(item){
this.keyWord = item.value;
this.selectedResult = item;
this.$emit("outputResult", item);
this.hideResultset = true;
}
},
}
</script>
<style scoped>
.searchInput{
border-radius:0px;
}
.resultsetHide{
display:none;
}
.resultsetContainer{
border:1px solid #dddee1;
border-top:none;
height:100px;
overflow: auto;
/*box-shadow: 2px 2px 1px #888888;*/
}
.result{
padding:2px 5px;
}
.result:hover{
background-color:#f8f8f9;
}
</style>
兄弟组件之间的通信
-
1、兄弟之间传递数据需要借助于事件车,通过事件车的方式传递数据
-
2、创建一个Vue的实例,让各个兄弟共用同一个事件机制。
-
3、传递数据方,通过一个事件触发bus.$emit(方法名,传递的数据)。
-
4、接收数据方,通过mounted(){}触发bus.$on(方法名,function(接收数据的参数){用该组件的数据接收传递过来的数据}),此时函数中的this已经发生了改变,可以使用箭头函数。
例如:1:新建rest.js
import Vue from 'vue'
export default new Vue
- 2:组件 a
<template>
<Modal v-model="opened" title="更新文件夹" :closable="false" @on-cancel="cancel">
<Form ref="fAccount" :model="folder" :label-width="80">
<Form-item label="文件夹名:" prop="foldername">
<Input v-model="folderName" type="text"></Input>
</Form-item>
</Form>
<div slot="footer">
<Button type="ghost" @click="cancel" style="margin-left: 8px">取消</Button>
<Button type="primary" @click="updatefolder" :loading="loading">更新</Button>
</div>
</Modal>
</template>
<script>
import ResourceAPI from 'api/resource';
//引入rest.js
import RestVue from "../../rest"
export default{
props:{
opened:{
type:Boolean,
default:false
},
folderId:{
type:Number,
default:0
},
folderName:{
type:String
}
},
data(){
return {
loading:false,
folder:{
foldername:'',
}
}
},
methods: {
updatefolder() {
if(this.folderName != ''){
this.loading = true;
ResourceAPI.folders_update(this.folderId,this.folderName)
.then((response)=> {
this.loading = false;
if(response.data.success==true){
this.$Message.info('文件夹更新成功!');
this.$emit('updateFolder');
//发送给的方法
RestVue.$emit('updateFolderFlag', this.folderName)
this.$emit('closedModal');
}
else{
this.$Message.error(response.data.message);
}
})
.catch(error => {
this.loading = false;
});
}else{
this.$Message.error("文件夹名称不能为空!");
}
},
cancel() {
this.$refs['fAccount'].resetFields();
this.$emit('closedModal');
}
},
}
</script>
3:组件b
<template>
<div>
<Card style="width:350px">
<p slot="title">
<Icon :type="icon"></Icon>
{{this.resource.name}}
</p>
<a href="#" slot="extra" @click.prevent="close">
<Icon type="close" color="#ccc" ></Icon>
</a>
<Form ref='fResource' :model="resource" label-position='left' :label-width="70">
<Row>
<Col span='12'>
<Form-item label="作者:">
<label>{{resource.author}}</label>
</Form-item>
</Col>
<Col span='12'>
<Form-item label="大小:">
<label>{{resource.size}}</label>
</Form-item>
</Col>
<Col span='12'>
<Form-item label="创建时间:">
<label >{{resource.create_time}}</label>
</Form-item>
</Col>
<Col span='12'>
<Form-item label="更新时间:">
<label>{{resource.update_time}}</label>
</Form-item>
</Col>
</Row>
<Form-item v-if="isFile" label="标签:">
<template v-if="canManageTag===true">
<Tag v-for="item in resource.tags" :key="item.id" :name="item.name" color="blue" closable @on-close="deleteTag(item.name)">{{ item.name }}</Tag>
</template>
<template v-else>
<Tag v-for="item in resource.tags" :key="item.id" :name="item.name" color="blue" > {{ item.name }}</Tag>
</template>
<Button v-if="canManageTag===true" icon="ios-plus-empty" type="dashed" size="small" @click="addingTag=true">设置并添加标签</Button>
</Form-item>
</Form>
</Card>
<TagsComponent
:opened="addingTag"
:file-id="resourceId"
@addedTag="addedTag"
@closedModal="closedModal"
>
</TagsComponent>
</div>
</template>
<script>
import ResourceAPI from 'api/resource';
import TagAPI from 'api/tag';
import CapacityAPI from 'utils/capacity'
import TagsComponent from './tags.vue';
import RestVue from "../../rest"
export default {
components:{
TagsComponent
},
props:{
isFile:{
type:Boolean,
default:true
},
resourceId:{
type:Number,
default:0
},
},
data(){
return {
icon:'',
resource:{
id:0,
name:'',
author:'',
size:0,
tags:[],
create_time:'',
update_time:'',
description:''
},
// tag
addingTag:false,
// 权限设置
canManageTag:false
}
},
created:function(){
switch(this.$route.meta.space){
case "public":
// this.canManageTag = this.$store.getters.permission.public['108'];
this.canManageTag = true;
break;
case "group":
// this.canManageTag = this.$store.getters.permission.group['108'];
this.canManageTag = true;
break;
case "private":
this.canManageTag = true;
break;
}
},
watch:{
resourceId:function(value,oldValue) {
// 更新 ICON
this.icon = this.isFile == true ? 'document' : 'folder';
// 更新资源信息
this.getResouce()
}
},
methods:{
//获取单标签信息
getResouce(){
ResourceAPI.singleTage(this.resourceId).then(response=>{
let resp = response.data;
if(resp.success==true){
let resouceObject = resp.data;
this.resource.id = resouceObject.id;
this.resource.name = resouceObject.name;
this.resource.author = resouceObject.uploader.username;
this.resource.create_time = resouceObject.create_time;
this.resource.update_time = resouceObject.update_time;
let size = CapacityAPI.bytesToSize(resouceObject.size);
let isFile = resouceObject.is_file;
if(isFile == false){
size="- -";
this.resource.size = size
}else{
this.resource.size = size
}
this.resource.tags = [];
let tags = resouceObject.tag_set;
tags.forEach((item, index)=>{
this.resource.tags.push({
id:item.id,
name:item.name
});
});
}
});
},
addedTag(){
// 添加标签完成后,更新标签信息
this.getResouce();
},
deleteTag(tagName){
this.$Modal.confirm({
title:'警告',
content: `确定要删除标签【${tagName}】吗?`,
okText:'删除',
cancelText:'取消',
loading:this.loading,
onOk:()=>{
TagAPI.del(this.resourceId, tagName).then(response=>{
let resp = response.data;
if(resp.success==true){
this.$Message.info("删除标签成功!");
// 更新标签信息
this.getResouce();
}else{
this.$Message.error(resp.message);
}
}).catch(error=>{
});
},
onCancel:()=>{
}
});
},
close(){
this.$emit('closedDetail');
},
closedModal(){
this.addingTag = false;
},
getFolderName(){
//接收方法
RestVue.$on("updateFolderFlag", (message) => {
if(message != ''){
this.getResouce();
}
})
}
},
created(){
this.getFolderName()
}
}
</script>
<style scoped>
.ivu-form .ivu-form-item-label{
color:#ccc;
}
</style>
ztree实现树的结构(移除自己的节点)
<template>
<Modal v-model="opened" title="移动文件" :closable="false" @on-cancel="cancel">
<Form ref="fMove" :label-width="80">
<Form-item prop="name">
<!--<Tree :data="baseData" show-checkbox @on-select-change='movecheck' ></Tree>-->
<ul id="treeMove" class="ztree" style="margin-top:0; width:160px; height:auto;"></ul>
</Form-item>
</Form>
<div slot="footer">
<Button type="ghost" @click="cancel" style="margin-left: 8px">取消</Button>
<Button type="primary" @click="movefile" :loading="loading">移动</Button>
</div>
</Modal>
</template>
<script>
import ResourceAPI from 'api/resource';
export default{
props: {
opened: {
type: Boolean,
default: false
},
isFile: {
type: Boolean,
default: false
},
moveId: {
type: Number,
defalut: 0
},
folderId: {
type:Number,
defalut: 0
},
serachValue:{
type:Boolean,
defalut:false
}
},
data(){
return {
loading: false,
load:null,
self_id: 0,
baseData: [],
settingMove : {
check: {
enable: true,
chkStyle: "radio",
radioType: "all"
},
view: {
dblClickExpand: this.dblClickExpand
},
data: {
simpleData: {
enable: true
}
},
callback: {
onClick: this.onClickNode,
onCheck: this.onCheck
}
},
zNodes:[],
selfArray:[]
}
},
watch: {
opened: function (value, oldValue) {
if (value == true) {
this.getTree();
}
}
},
methods: {
movefile(){
if(this.self_id == this.moveId){
this.$Message.error("文件夹不能移动到本身文件夹中!");
return;
}
if (this.isFile == true) {
this.loading = true
this.load = this.$Message.loading({
content: 'Loading...',
duration: 0
});
ResourceAPI.file_move(this.self_id, this.moveId).then((response, reject) => {
this.loading = false;
if (response.data.success == true) {
this.$Notice.success({
title: '移动文件成功!',
duration:2.5
});
this.load = this.$Message.destroy();
this.loading = false
this.folderId == 0 ?this.$emit("refreshTable"):this.$emit("moveFolder")
this.serachValue == true?this.$emit("refreshSearch"):this.serachValue = false
this.$emit('closedModal');
}
else {
this.$Notice.error({
title: response.data.message,
duration:2.5
});
this.load = setTimeout(() => {
this.$Message.destroy();
this.loading = false
},500)
}
}).catch(error => {
this.loading = false;
});
} else {
this.load = this.$Message.loading({
content: 'Loading...',
duration: 0
});
this.loading = true
ResourceAPI.folder_move(this.self_id, this.moveId).then((response, reject) => {
if (response.data.success == true) {
this.$Notice.success({
title: '移动文件夹成功!',
duration:2.5
});
this.load = this.$Message.destroy();
this.loading = false;
this.folderId == 0 ?this.$emit("refreshTable"):this.$emit("moveFolder")
this.$emit('closedModal');
}
else {
this.$Notice.error({
title: response.data.message,
duration:2.5
});
this.load = setTimeout(() => {
this.$Message.destroy();
this.loading = false
},500)
}
}).catch(error => {
this.loading = false;
});
}
},
getTree(){
//准备数据
ResourceAPI.getTree(this.moveId).then((response) => {
let resp = response.data;
if (resp.success == true) {
let nodes = resp.data.department
let nodesArray = [{id:"", pId:"", name:"root", open:true}]
//调用去除自己的方法
this.removeShelf(this.moveId, nodes)
//利用差集来去除
let self_array = new Set(this.selfArray);
let node_array = new Set(nodes)
let new_node = new Set([...node_array].filter(x => !self_array.has(x)));
let new_node_array = Array.from(new_node);
new_node_array.forEach((item, index, array) =>{
nodesArray.push({
"name":item.departmentName,
"id":item.id,
"pId":item.parentId,
"open":true
})
})
this.zNodes= nodesArray
$.fn.zTree.init($("#treeMove"), this.settingMove, this.zNodes);
// this.$emit("refreshTable")
}
}).catch(error => {
});
},
onClickNode(e, treeId, treeNode){
var zTree = $.fn.zTree.getZTreeObj("treeMove");
zTree.checkNode(treeNode, !treeNode.checked, null, true);
return false;
},
onCheck(e, treeId, treeNode){
let _this = this;
var zTree = $.fn.zTree.getZTreeObj("treeMove"),
nodes = zTree.getCheckedNodes(true);
for (var i = 0, l = nodes.length; i < l; i++) {
// console.log(nodes[0].id);
_this.self_id = nodes[0].id
}
},
//根文件的显示
dblClickExpand(treeId, treeNode){
return treeNode.level > 0;
},
//去除选择自己的节点
removeShelf(id, array){
for (var i = 0; i < array.length; i++) {
var _array = array[i];
if(_array.parentId == id){
this.selfArray.push(_array)
this.removeShelf(_array.id, array)
}
if(_array.id == id){
if(this.selfArray.indexOf(_array) ==-1){
this.selfArray.push(_array)
}
}
}
},
cancel(){
this.$emit('closedModal');
},
},
}
</script>
- 批量选择移除自己的节点
<template>
<Modal v-model="opened" title="批量移动文件" :closable="false" @on-cancel="cancel">
<Form ref="fMove" :label-width="80">
<Form-item prop="name">
<!--<Tree :data="baseData" show-checkbox @on-select-change='movecheck' ></Tree>-->
<ul id="treeBatchMove" class="ztree" style="margin-top:0; width:160px; height:auto;"></ul>
</Form-item>
</Form>
<div slot="footer">
<Button type="ghost" @click="cancel" style="margin-left: 8px">取消</Button>
<Button type="primary" @click="movefile" :loading="loading">移动</Button>
</div>
</Modal>
</template>
<script>
import ResourceAPI from 'api/resource';
export default{
props: {
opened: {
type: Boolean,
default: false
},
isFile: {
type: Boolean,
default: false
},
listId:{
type:Array
},
folderId: {
type:Number,
defalut: 0
},
serachValue:{
type:Boolean,
defalut:false
}
},
data(){
return {
loading: false,
load:null,
self_id: 0,
baseData: [],
settingMove : {
check: {
enable: true,
chkStyle: "radio",
radioType: "all"
},
view: {
dblClickExpand: this.dblClickExpand
},
data: {
simpleData: {
enable: true
}
},
callback: {
onClick: this.onClickNode,
onCheck: this.onCheck
}
},
zNodes:[],
selfArray:[]
}
},
watch: {
opened: function (value, oldValue) {
if (value == true) {
this.getTree();
}
}
},
methods: {
movefile(){
if(this.self_id == this.moveId){
this.$Message.error("文件夹不能移动到本身文件夹中!");
return;
}
if (this.isFile == true) {
this.loading = true
this.load = this.$Message.loading({
content: 'Loading...',
duration: 0
});
ResourceAPI.file_move(this.self_id, this.moveId).then((response, reject) => {
this.loading = false;
if (response.data.success == true) {
this.$Notice.success({
title: '移动文件成功!',
duration:2.5
});
this.load = this.$Message.destroy();
this.loading = false
this.folderId == 0 ?this.$emit("refreshTable"):this.$emit("moveFolder")
this.serachValue == true?this.$emit("refreshSearch"):this.serachValue = false
this.$emit('closedModal');
}
else {
this.$Notice.error({
title: response.data.message,
duration:2.5
});
this.load = setTimeout(() => {
this.$Message.destroy();
this.loading = false
},500)
}
}).catch(error => {
this.loading = false;
});
} else {
this.load = this.$Message.loading({
content: 'Loading...',
duration: 0
});
this.loading = true
ResourceAPI.folder_move(this.self_id, this.moveId).then((response, reject) => {
if (response.data.success == true) {
this.$Notice.success({
title: '移动文件夹成功!',
duration:2.5
});
this.load = this.$Message.destroy();
this.loading = false;
this.folderId == 0 ?this.$emit("refreshTable"):this.$emit("moveFolder")
this.$emit('closedModal');
}
else {
this.$Notice.error({
title: response.data.message,
duration:2.5
});
this.load = setTimeout(() => {
this.$Message.destroy();
this.loading = false
},500)
}
}).catch(error => {
this.loading = false;
});
}
},
getTree(){
//准备数据
ResourceAPI.getTree(this.listId[0]).then((response) => {
let resp = response.data;
if (resp.success == true) {
let nodes = resp.data.department
let nodesArray = [{id:"", pId:"", name:"root", open:true}]
//调用去除自己的方法
this.removeShelf(this.listId, nodes)
//利用差集来去除
let self_array = new Set(this.selfArray);
let node_array = new Set(nodes)
let new_node = new Set([...node_array].filter(x => !self_array.has(x)));
let new_node_array = Array.from(new_node);
new_node_array.forEach((item, index, array) =>{
nodesArray.push({
"name":item.departmentName,
"id":item.id,
"pId":item.parentId,
"open":true
})
})
this.zNodes= nodesArray
$.fn.zTree.init($("#treeBatchMove"), this.settingMove, this.zNodes);
// this.$emit("refreshTable")
}
}).catch(error => {
});
},
onClickNode(e, treeId, treeNode){
var zTree = $.fn.zTree.getZTreeObj("treeBatchMove");
zTree.checkNode(treeNode, !treeNode.checked, null, true);
return false;
},
onCheck(e, treeId, treeNode){
let _this = this;
var zTree = $.fn.zTree.getZTreeObj("treeBatchMove"),
nodes = zTree.getCheckedNodes(true);
for (var i = 0, l = nodes.length; i < l; i++) {
// console.log(nodes[0].id);
_this.self_id = nodes[0].id
}
},
//根文件的显示
dblClickExpand(treeId, treeNode){
return treeNode.level > 0;
},
//去除选择自己的节点
removeShelf(id_list, array){
for (var i = 0; i < array.length; i++) {
var _array = array[i];
if(id_list.indexOf(_array.parentId) != -1){
this.selfArray.push(_array)
this.removeShelf([_array.id], array)
}
if(id_list.indexOf(_array.id) != -1){
if(this.selfArray.indexOf(_array) ==-1){
this.selfArray.push(_array)
}
}
}
},
cancel(){
this.$emit('closedModal');
},
},
}
</script>
vue-router 配置404页面(遇到的问题点)
- 后端已经配置了history 模式,404页面不生效,原因是:404页面的路径一定要放到最后
import Vue from 'vue'
import Router from 'vue-router'
const _import = require('./_import_' + process.env.NODE_ENV);
// in development env not use Lazy Loading,because Lazy Loading large page will cause webpack hot update too slow.so only in production use Lazy Loading
/* layout */
import Layout from '../views/layout/Layout';
/* login */
const Login = _import('login/index');
// const authRedirect = _import('login/authredirect');
/* finder */
const Finder = _import('finder/index');
/*groupHome 群主空间页面*/
const GroupHome = _import('groupHome/index')
/* profile */
const Profile = _import('profile/index');
/* Account & Group */
const Account = _import('account/index');
const Group = _import('group/index');
/* shared */
const Shared = _import('shared/index')
/*otherShared*/
const OtherShared = _import('otherShared/index')
/* Log */
const Log = _import('log/index');
//储存管理
const Buffer = _import('buffer/index')
/*回收站组件*/
const AccountRecycle = _import('accountRecycle/index');
const GroupRecycle = _import('groupRecycle/index');
const FileRecycle = _import('fileRecycle/index');
//404页面
const Err404 = _import('errorPage/404');
Vue.use(Router)
/**
* icon : the icon show in the sidebar
* hidden : if hidden:true will not show in the sidebar
* redirect : if redirect:noredirect will not redirct in the levelbar
* noDropdown : if noDropdown:true will not has submenu
* meta : { role: ['admin'] } will control the page role
**/
export const constantRouterMap = [
{ path: '/login', name: 'login', component: Login, hidden: true},
// { path: '/authredirect', component: authRedirect, hidden: true },
// { path: '/401', component: Err401, hidden: true },
{
path: '/',
redirect: '/space/person/',
hidden: true
},
{
path: '/space/person',
component: Layout,
name: '我的空间',
hiddenChildren:true,
icon: 'person',
children: [
{ path: '/', component: Finder, meta: { space: 'private', space2: 'person', activatedPath: '/space/person' }}
]
},
{
path: '/space/person/:folderId',
component: Layout,
name: '我的空间',
hidden: true,
hiddenChildren:true,
children: [
{ path: '/', component: Finder, meta: { space: 'private', space2: 'person', activatedPath: '/space/person' }}
]
},
{
path: '/space/group',
component: Layout,
name: '群组空间',
icon: 'person-stalker',
hiddenChildren:true,
children: [
{ path: '/', component: GroupHome, meta: { space: 'group', space2: 'group', activatedPath: '/space/group' }}
]
},
{
path: '/space/group/:folderId',
component: Layout,
name: '群组空间',
hidden: true,
hiddenChildren:true,
children: [
{ path: '/', component: GroupHome, meta: { space: 'group', space2: 'group', activatedPath: '/space/group' }}
]
},
{
path: '/space/shared',
component: Layout,
name: '我分享的文件',
hiddenChildren:true,
icon:'android-share-alt',
children: [
{ path: '/', component:Shared, meta: { space: 'SHARED', space2: 'user', activatedPath: '/space/shared' }}
]
},
{
path: '/space/shared/:folderId',
component: Layout,
name: '我分享的文件',
hidden: true,
hiddenChildren:true,
children: [
{ path: '/', component: Shared, meta: { space: 'SHARED', space2: 'user', activatedPath: '/space/shared' }}
]
},
{
path: '/space/ohtershared',
component: Layout,
name: '分享给我的文件',
icon:'android-share-alt',
hiddenChildren:true,
children: [
{ path: '/', component: OtherShared, meta: { space: 'OTHERSHARED', space2: 'othershared', activatedPath: '/space/ohtershared' }}
]
},
{
path: '/space/ohtershared/:folderId',
component: Layout,
name: '分享给我的文件',
hidden: true,
hiddenChildren:true,
children: [
{ path: '/', component: OtherShared, meta: { space: 'OTHERSHARED', space2: 'othershared', activatedPath: '/space/ohtershared' }}
]
},
{
path: '/space/public',
component: Layout,
name: '公共空间',
icon:'ios-list-outline',
hiddenChildren:true,
children: [
{ path: '/', component: Finder, meta: { space: 'public', space2: 'public', activatedPath: '/space/public' }}
]
},
{
path: '/space/public/:folderId',
component: Layout,
name: '公共空间',
hidden: true,
hiddenChildren:true,
children: [
{ path: '/', component: Finder, meta: { space: 'public', space2: 'public', activatedPath: '/space/public' }}
]
},
]
export default new Router({
mode:'history', //后端支持可开
scrollBehavior: () => ({ y: 0 }),
routes: constantRouterMap
})
export const asyncRouterMap = [
{
path: '/system',
component: Layout,
redirect: '/account',
name: '系统管理',
icon: 'android-settings',
hiddenChildren:false,
meta: { role: ['admin','group_admin','user'], activatedPath: '/system' },
children: [
{ path: '/account', component: Account, name: '用户管理', icon: 'person', meta: { role: ['admin', 'group_admin'], activatedPath: '/account' }},
{ path: '/group', component: Group, name: '群组管理', icon: 'person-stalker', meta: { role: ['admin', 'group_admin'], activatedPath: '/group' }},
// { path: '/storage', component: Buffer, name: '存储管理', icon: 'social-buffer', meta: { role: ['admin','group_admin'], activatedPath: '/storage' }},
{ path: '/log', component: Log, name: '日志管理', icon: 'chatbubble-working', meta: { role: ['admin','group_admin','user'], activatedPath: '/log' }},
]
},
{
path: '/recycle',
component: Layout,
redirect: '/account',
name: '回收站',
icon: 'trash-a',
hiddenChildren:false,
meta: { role: ['admin','group_admin','user'], activatedPath: '/recycle' },
children: [
{ path: '/account/recycle', component: AccountRecycle, icon: 'person', name: '用户回收', meta: { role: ['admin','group_admin'], activatedPath: '/account/recycle' }},
{ path: '/group/recycle', component: GroupRecycle, icon: 'person-stalker', name: '群组回收', meta: { role: ['admin','group_admin'], activatedPath: '/group/recycle' }},
{ path: '/file/recycle', component: FileRecycle, icon: 'document', name: '文件回收', meta: { role: ['admin','group_admin','user'], activatedPath: '/file/recycle' }},
]
},
//配置404路由一定要放在最后页面
{
path: '*',
name: 'error_404',
meta: {
title: '404-页面不存在'
},
component: Err404, hidden: true
},
//{ path: '*', redirect: '/errorPage', hidden: true }
];
- 404 组件
- 404样式
@keyframes error404animation {
0% {
transform: rotateZ(0deg);
}
20% {
transform: rotateZ(-60deg);
}
40% {
transform: rotateZ(-10deg);
}
60% {
transform: rotateZ(50deg);
}
80% {
transform: rotateZ(-20deg);
}
100% {
transform: rotateZ(0deg);
}
}
.error404{
&-body-con{
width: 700px;
height: 500px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
&-title{
text-align: center;
font-size: 240px;
font-weight: 700;
color: #2d8cf0;
height: 260px;
line-height: 260px;
margin-top: 40px;
span{
display: inline-block;
color: #19be6b;
font-size: 230px;
animation: error404animation 3s ease 0s infinite alternate;
}
}
&-message{
display: block;
text-align: center;
font-size: 30px;
font-weight: 500;
letter-spacing: 12px;
color: #dddde2;
}
}
&-btn-con{
text-align: center;
padding: 20px 0;
margin-bottom: 40px;
}
}
<style lang="less">
@import './404.less';
</style>
<template>
<div class="error404">
<div class="error404-body-con">
<Card>
<div class="error404-body-con-title">4<span><Icon type="ios-navigate-outline"></Icon></span>4</div>
<p class="error404-body-con-message">YOU LOOK LOST</p>
<div class="error404-btn-con">
<Button @click="goHome" type="error" size="large" style="width: 200px;" >返回首页</Button>
<Button @click="backPage" size="large" style="width: 200px;margin-left: 40px;" type="primary">返回上一页</Button>
</div>
</Card>
</div>
</div>
</template>
<script>
export default {
name: 'Error404',
methods: {
backPage () {
this.$router.go(-2);
},
goHome () {
this.$router.push({ path: "/space/person" });
}
}
};
</script>
授索功能的完善(自己封装的组件)
rest.js
import Vue from 'vue'
export default new Vue
- serarch 组件
<template>
<span>
<Input @keyup.enter.native="handleFilter(searchUrl,pagerSize,pagerIndex,spaceType,searchType,headersToken)"
@on-change="handleFilter(searchUrl,pagerSize,pagerIndex,spaceType,searchType,headersToken)"
v-model='inputValue'
@on-blur="inputKeyWord"
placeholder="请输入..." style="width: 20%">
</Input>
<Button type="primary" @click="handleFilter(searchUrl,pagerSize,pagerIndex,spaceType,searchType,headersToken)" >
<Icon type="ios-search"></Icon>
搜索
</Button>
</span>
</template>
<script>
//探索添加500ms以后请求
import _ from 'lodash'; //引入lodash
import axios from 'axios'//引入axios
import RestVue from "../../rest"
//请求canceltoken列表
let sources = [];
export default {
props:{
searchUrl:{
type:String
},
headersToken:{
type:Object
},
spaceType:{
type:String
},
searchType:{
type:String
},
pagerSize:{
type:Number,
},
pagerIndex:{
type:Number,
}
},
data(){
return{
inputValue:'',
}
},
methods:{
//搜索结果
handleFilter(searchUrl,pagerSize,pagerIndex,spaceType,searchType,headersToken){
this.$emit('showIsBatchBth',this.inputValue)
if(this.inputValue == ''){
return;
}else{
this.searchInputValue(searchUrl,pagerSize,pagerIndex,spaceType,searchType,headersToken)
}
},
// 搜索功能
// 使用_.debounce控制搜索的触发频率, 500ms后执行
// 准备搜索
searchInputValue:_.debounce(
function (requestUrl,pagerSize,pagerIndex,spaceType,searchType,headersToken) {
let that = this;
// 删除已经结束的请求
_.remove(sources, (n)=>{
return n.source === null;
})
// 取消还未结束的请求
sources.forEach(function (item) {
if (item !== null && item.source !== null && item.status === 1) {
item.status = 0;
}
});
//创建新的请求cancelToken,并设置状态请求中
var sc = {
source: axios.CancelToken.source(),
status: 1 //状态1:请求中,0:取消中
};
//这个对象加入数组中
sources.push(sc);
//开始搜索数据
//开始搜索数据
var url = requestUrl+"?pageSize="+pagerSize+"&page_index="+pagerIndex+"&space="+spaceType+"&type="+searchType+"&name="+that.inputValue;
axios.get( url, {
cancelToken: sc.source.token,
headers:headersToken
}).then((response)=> {
if(response.data.success == true){
sc.source = null;
}
this.$emit("searchResVlaue", response);
}).catch((err)=>{
//请求失败
sc.source = null; //置空请求canceltoken
});
},
1000),
//失去焦点
inputKeyWord(){
if(this.inputValue == ""){
this.$emit("openSearchSearch", false);
this.$emit("showTableopenSearch", true);
}
},
},
mounted(){
RestVue.$on("pagerIndexFun", (message) => {
this.handleFilter(
this.searchUrl,
this.pagerSize,
message,
this.spaceType,
this.searchType,
this.headersToken
);
})
RestVue.$on("refreshResultSerach", (message) => {
if(message == true){
this.handleFilter(
this.searchUrl,
this.pagerSize,
this.pagerIndex,
this.spaceType,
this.searchType,
this.headersToken
);
}
})
}
}
</script>
<style>
</style>
- 引用组件
- html
html
<Search
:search-url='requestUrl'
:pager-size='pager.size'
:pager-index="pager.index"
:space-type="space"
:search-type="getSelectValue||'name'"
:headers-token="searchHeaders"
@searchResVlaue='searchResValue'
@showIsBatchBth='showIsBatchBth'
></Search>
- js
import Search from '@/components/search/search.vue'
import RestVue from "../../rest"
export default {
name: 'space',
components:{
UploadComponent,
CreateFolderComponent,
DetailComponent,
MoveComponent,
CopyComponent,
ShareCompoent,
UpdateFolder,
UpdateFile,
BatchShared,
BatchMove,
BatchCopy,
Search
},
data () {
let columns = null;
if(this.$store.getters.role=='user'&&this.$route.meta.space == "public"){
columns = [
{
title: '文件名',
width:'25%',
// sortable: true,
render:(h,params)=>{
let iconType = params.row.isFile==true ? 'document' : 'folder';
let id =params.row.id;
let name = params.row.name;
let isFile = params.row.isFile;
let namePoint = '';
if(name.length>20){
namePoint+=name.slice(0, 20)+'...'
}else{
namePoint+=name
}
return(
<div onClick={()=>this.showDetail(id,isFile)} style={{cursor:'pointer'}}>
<Icon type={iconType} style={{ fontSize:'16px'}}></Icon>
<span domPropsInnerHTML={namePoint} title={name} style={{ cursor:'pointer',padding:'10px'}} onClick={(e)=>this.handleResource(id,isFile,e)}></span>
</div>
)
}
},
{
title: ' ',
key: 'action',
width:'25%',
render:(h,params)=>{
let resourceId = params.row.id;
let resourceName = params.row.name;
let resourceURL =process.env.BASE_API+params.row.download_url;
let isFile = params.row.isFile;
let tags = params.row.tags;
let shareId = params.row.shardId
// 来源信息
let fromInfo = '';
if (params.row.from){
fromInfo = "源自:"+ params.row.from.name;
}
// 权限控制
let canDelete = false;
let canShare = false;
let share = true;
let sharePermisson = true;
switch(this.space){
case "public":
if(this.$store.getters.role=='admin'){
share = true;
canDelete = true;
canShare = false;
}else if(this.$store.getters.role=='group_admin'){
share = true;
canDelete = true;
canShare = false;
sharePermisson = true;
}else if(this.$store.getters.role=='user'){
share = false;
canDelete = false;
canShare = false;
sharePermisson = true;
}
break;
case "group":
if(this.$store.getters.role=='admin'){
share = true;
canDelete = true;
canShare = true;
}else if(this.$store.getters.role=='group_admin'){
share = true;
canDelete = true;
canShare = true;
}else if(this.$store.getters.role=='user'){
share = true;
canDelete = true;
canShare = true;
sharePermisson = true;
}
break;
case "private":
canDelete = true;
canShare = true;
break;
}
return (
<div style={{ textAlign: 'left' }}>
<span style={{ color: '#ccc', display:'inline-block', width:'120px' }}>{fromInfo}</span>
{
canShare ?
<Button type="text" onClick={()=>this.getShare(isFile,resourceId,resourceName)}>
<Icon size='16' type="android-share-alt"></Icon>
</Button>
:
''
}
{
sharePermisson ?<span onClick={()=>this.clkicDownload(isFile)}><a href={isFile== true?resourceURL:"javascript:void(0);"} style={{ marginRight:'23px',marginLeft:'13px'}}><Icon size='16' type="android-download"></Icon></a></span> :''
}
{ share ?
<Dropdown placement="bottom-start" style={{ padding:'10px'}} onOn-click={(name,id)=>this.changeSelected(name,resourceId,isFile,resourceName,tags)}>
<Icon type="more"></Icon>
<Dropdown.Menu slot="list">
<Dropdown.Item name='copy'><Icon type="ios-copy-outline"></Icon> 复制</Dropdown.Item>
<Dropdown.Item name='move'><Icon type="arrow-move"></Icon> 移动</Dropdown.Item>
<Dropdown.Item name='update'><Icon type="android-create"></Icon> 更新</Dropdown.Item>
{canDelete ? <Dropdown.Item name='delete' ><Icon type="ios-trash"></Icon> 删除</Dropdown.Item> : ""}
</Dropdown.Menu>
</Dropdown>
: ''
}
</div>
);
}
},
{
title: '大小',
key: 'size',
sortable: true,
align: 'center',
// width: "120px"
},
{
title: '修改日期',
key: 'update_time',
sortable: true,
align: 'center',
width: "20%"
},
]
}else{
columns = [
{
type: 'selection',
width: 32,
align: 'center'
},
{
title: '文件名',
width:'25%',
// sortable: true,
render:(h,params)=>{
let iconType = params.row.isFile==true ? 'document' : 'folder';
let id =params.row.id;
let name = params.row.name;
let isFile = params.row.isFile;
let namePoint = '';
if(name.length>20){
namePoint+=name.slice(0, 20)+'...'
}else{
namePoint+=name
}
return(
<div onClick={()=>this.showDetail(id,isFile)} style={{cursor:'pointer'}}>
<Icon type={iconType} style={{ fontSize:'16px'}}></Icon>
<span domPropsInnerHTML={namePoint} title={name} style={{ cursor:'pointer',padding:'10px'}} onClick={(e)=>this.handleResource(id,isFile,e)}></span>
</div>
)
}
},
{
title: ' ',
key: 'action',
width:'45%',
render:(h,params)=>{
let resourceId = params.row.id;
let resourceName = params.row.name;
let resourceURL =process.env.BASE_API+params.row.download_url;
let isFile = params.row.isFile;
let tags = params.row.tags;
let shareId = params.row.shardId
// 来源信息
let fromInfo = '';
if (params.row.from){
fromInfo = "源自:"+ params.row.from.name;
}
// 权限控制
let canDelete = false;
let canShare = false;
let share = true;
let sharePermisson = true;
switch(this.space){
case "public":
if(this.$store.getters.role=='admin'){
share = true;
canDelete = true;
canShare = false;
}else if(this.$store.getters.role=='group_admin'){
share = true;
canDelete = true;
canShare = false;
sharePermisson = true;
}else if(this.$store.getters.role=='user'){
share = false;
canDelete = false;
canShare = false;
sharePermisson = true;
}
break;
case "group":
if(this.$store.getters.role=='admin'){
share = true;
canDelete = true;
canShare = true;
}else if(this.$store.getters.role=='group_admin'){
share = true;
canDelete = true;
canShare = true;
}else if(this.$store.getters.role=='user'){
share = true;
canDelete = true;
canShare = true;
sharePermisson = true;
}
break;
case "private":
canDelete = true;
canShare = true;
break;
}
return (
<div style={{ textAlign: 'left' }}>
<span style={{ color: '#ccc', display:'inline-block', width:'120px' }}>{fromInfo}</span>
{
canShare ?
<Button type="text" onClick={()=>this.getShare(isFile,resourceId,resourceName)}>
<Icon size='16' type="android-share-alt"></Icon>
</Button>
:
''
}
{
sharePermisson ? <span onClick={()=>this.clkicDownload(isFile)}><a href={isFile== true?resourceURL:"javascript:void(0);"} style={{ marginRight:'23px',marginLeft:'13px'}}><Icon size='16' type="android-download"></Icon></a></span> :''
}
{ share ?
<Dropdown placement="bottom-start" style={{ padding:'10px'}} onOn-click={(name,id)=>this.changeSelected(name,resourceId,isFile,resourceName,tags)}>
<Icon type="more"></Icon>
<Dropdown.Menu slot="list">
<Dropdown.Item name='copy'><Icon type="ios-copy-outline"></Icon> 复制</Dropdown.Item>
<Dropdown.Item name='move'><Icon type="arrow-move"></Icon> 移动</Dropdown.Item>
<Dropdown.Item name='update'><Icon type="android-create"></Icon> 更新</Dropdown.Item>
{canDelete ? <Dropdown.Item name='delete' ><Icon type="ios-trash"></Icon> 删除</Dropdown.Item> : ""}
</Dropdown.Menu>
</Dropdown>
: ''
}
</div>
);
}
},
{
title: '大小',
key: 'size',
sortable: true,
align: 'center',
// width: "120px"
},
{
title: '修改日期',
key: 'update_time',
sortable: true,
align: 'center',
width: "20%"
},
]
}
let resultColumns = [
{
type: 'selection',
width: 32,
align: 'center'
},
{
title: '文件名',
width: "20%",
render:(h,params)=>{
let iconType = params.row.isFile==true ? 'document' : 'folder';
let id =params.row.id;
let name = params.row.name;
let isFile = params.row.isFile;
let search = true
return(
<div onClick={()=>this.showDetail(id,isFile)} style={{cursor:'pointer'}}>
<Icon type={iconType} style={{ fontSize:'16px'}}></Icon>
<span domPropsInnerHTML={name.slice(0, 14)} title={name} style={{cursor:'pointer',padding:'10px'}} onClick={(e)=>this.handleResource(id,isFile,e)}></span>
</div>
)
}
},
{
title: ' ',
key: 'action',
width:'30%',
render:(h,params)=>{
let resourceId = params.row.id;
let resourceName = params.row.name;
let resourceURL =process.env.BASE_API+params.row.download_url;
let isFile = params.row.isFile;
let tags = params.row.tags;
let shareId = params.row.shardId
// 来源信息
let fromInfo = '';
if (params.row.from){
fromInfo = "源自:"+ params.row.from.name;
}
// 权限控制
let canDelete = false;
let canShare = false;
let share = true;
let sharePermisson = true;
let search = true
switch(this.space){
case "public":
if(this.$store.getters.role=='admin'){
share = true;
canDelete = true;
canShare = false;
}else if(this.$store.getters.role=='group_admin'){
share = true;
canDelete = true;
canShare = false;
sharePermisson = true;
}else if(this.$store.getters.role=='user'){
share = false;
canDelete = false;
canShare = false;
sharePermisson = true;
}
break;
case "group":
if(this.$store.getters.role=='admin'){
share = true;
canDelete = true;
canShare = true;
}else if(this.$store.getters.role=='group_admin'){
share = true;
canDelete = true;
canShare = true;
}else if(this.$store.getters.role=='user'){
share = true;
canDelete = true;
canShare = true;
sharePermisson = true;
}
break;
case "private":
canDelete = true;
canShare = true;
break;
}
return (
<div style={{ textAlign: 'left' }}>
<span style={{ color: '#ccc', display:'inline-block', width:'120px' }}>{fromInfo}</span>
{
canShare ?
<Button type="text" onClick={()=>this.getShare(isFile,resourceId,resourceName)}>
<Icon size='16' type="android-share-alt"></Icon>
</Button>
:
''
}
{
sharePermisson ?<a href={isFile== true?resourceURL:"javascript:void(0);"} style={{ marginRight:'23px',marginLeft:'13px'}}><Icon size='16' type="android-download"></Icon></a>:''
}
{ share ?
<Dropdown placement="bottom-start" style={{ padding:'10px'}} onOn-click={(name,id)=>this.changeSelected(name,resourceId,isFile,resourceName,tags,search)}>
<Icon type="more"></Icon>
<Dropdown.Menu slot="list">
<Dropdown.Item name='copy'><Icon type="ios-copy-outline"></Icon> 复制</Dropdown.Item>
<Dropdown.Item name='move'><Icon type="arrow-move"></Icon> 移动</Dropdown.Item>
<Dropdown.Item name='update'><Icon type="android-create"></Icon> 更新</Dropdown.Item>
{canDelete ? <Dropdown.Item name='delete' ><Icon type="ios-trash"></Icon> 删除</Dropdown.Item> : ""}
</Dropdown.Menu>
</Dropdown>
: ''
}
</div>
);
}
},
{
title: '大小',
key: 'size',
sortable: true,
align: 'center',
// width: "50px"
},
{
title: '修改日期',
key: 'update_time',
sortable: true,
align: 'center',
// width: "100px"
},
{
title: '路径',
width: "20%",
render:(h,params)=>{
let directoryName = params.row.directoryName;
let directoryId = params.row.directoryId;
let directoryResultName = null;
let isFile = params.row.isFile;
if(directoryName == null){
directoryResultName = '';
}else{
directoryResultName = directoryName;
}
let clickPath = true
return(
<div style={{cursor:'pointer'}} onClick={()=>this.getFolder(directoryId, isFile,clickPath)} >
<span domPropsInnerHTML={ directoryName == null ? 'root'+directoryResultName : 'root '+' > '+directoryResultName} ></span>
</div>
)
}
},
];
let folder = {
id:0,
parentId:0,
name:'',
tree:[
{id:0, name:'root', path:this.$route.meta.activatedPath}
],
};
return {
//表格没有数据时展示内容
tabNoDataTitle:'载入中。。。',
//showUser
showUser:false,
// status
load: null,
uploadDisabled:false,
uploading:false,
creatingFolder:false,
hidingDetail:true,
shareFolder:false,
updateFolder:false,
updateFile:false,
copingFile:false,
movingFile:false,
openSearch:false,
showTable:true,
openGroup:false,
groupDisabled:false,
serachResult: false,
showAllShared:true,
//批量删除按钮是否要禁用
isBatchBth:true,
//是否批量分享
isBatchShared:false,
//是否清空
isRemoveBatch:false,
//普通用户是否显示批量操作
isShowBatch:false,
//是否批量移动
isBatchMove:false,
//是否批量移动
isBatchCopy:false,
// attributes
modifyIsFile:true,
modifyResourceId:0,
modifyResourceName:'',
space:this.$route.meta.space,
groupId: null,
folder:folder,
files:[],
// table
columns:columns ,
resultColumns:resultColumns,
pager:{ total:0, index:1, size:10},
pagerIndex:null,
resourceGrid:{table:24, detail:0},
//tag
tags:[],
//folderPath
folederObj:null,
//serarch token
searchHeaders:{
Authorization:"conspace " + this.$store.getters.token
},
requestUrl:process.env.BASE_API+'search/',
//群组数据
groups:[],
// search result
searchResult:{
id:0,name:''
},
selectText:'name',
searchValue:[
{
value: 'name',
label: '文件'
},
{
value: 'tag',
label: '标签'
}
],
getSelectValue:'',
serachResultValue:[],
serachAccount:0,
groupFlag:0,
folderFlag:null,
//选中某一个的值
selectedList:[],
//全选中以后获取的值
selectedAllList:[],
//去生数组
repeatArray:[],
//交集
selectIntersectionSet:[],
//记录群组标记
groupName:null,
}
},
mounted: function(){
// 获取当前的目录信息,如果没有folderID,则是根目录,则为0。
let folderExistIndex = Object.keys(this.$route.params).indexOf('folderId');
let folderId = folderExistIndex ==-1 ? 0 : parseInt(this.$route.params.folderId);
this.folder.id = folderId;
if (folderId!=0){
// 获取非根目录下的文件夹信息。
this.groupDisabled = true
this.getFolder(folderId);
}
else{
// 获取根目录下的资源。
this.getResource();
}
if(this.$store.getters.role=='user'){
this.showUser = true
}
if(this.space == "public"){
this.showAllShared = false
}
if(this.$store.getters.role=='user'&&this.space == "public"){
this.isShowBatch = false
}else{
this.isShowBatch = true
}
},
methods:{
//授索回来的值
searchResValue(response){
this.serachAccount = 0;
this.hidingDetail = true
this.resourceGrid.table = 24
let resp = response.data;
this.serachResultValue = [];
if(resp.success == true){
//批量删除按钮是不要打开
this.isBatchBth = true
resp.data.results.forEach((item, index, array) => {
let isFile = item.is_file;
let size = CapacityAPI.bytesToSize(item.size);
if(isFile == false){
size="- -";
}else{
size
}
let directoryName = null;
let directoryId = 0;
let tags = item.tag_set;
item.directory.forEach((self,index,array)=>{
if(index>0){
directoryName = array[index].name +" > "+ directoryName ;
}else{
directoryName = array[index].name;
directoryId = array[index].id;
}
})
this.serachResultValue.push({
id:item.id,
name:item.name,
size:size,
isFile:isFile,
from:item.group,
directoryName:directoryName,
directoryId:directoryId,
update_time:item.update_time,
download_url:item.download_url,
tags:tags,
directory:item.directory,
});
this.serachAccount = resp.data.count;
this.pager.total = resp.data.count;
})
}
},
//是否有授索值
showIsBatchBth(value){
if(value == ''){
this.isBatchBth = true;
this.openSearch = false;
this.showTable = true;
if(this.folder.id != 0){
this.refreshFolder()
}else {
this.refreshTable()
}
}else{
this.isBatchBth = true
this.openSearch = true
this.showTable = false
}
},
handleResource(targetID, isFile, event,obj){
if(isFile == true){
}
else{
// 阻止事件冒泡
event.cancelBubble = true;
// 跳转到下级目录
this.$router.push({ path: this.$route.meta.activatedPath+"/"+targetID })
}
},
getSearchValue(item){
this.getSelectValue = item;
},
getGroupValue(item){
if(this.folder.id != 0){
this.groupId = null;
}else{
this.groupId = item;
}
},
changePage(pageIndex){
this.pager.index = pageIndex;
this.getResource();
},
serachChangePage(pageIndex){
this.pagerIndex = pageIndex;
RestVue.$emit('pagerIndexFun', this.pagerIndex)
},
getFolder(folderId, isFile,clickPath){
if(clickPath == true){
this.$router.push({ path: this.$route.meta.activatedPath+"/"+folderId })
}
this.openSearch = false
this.showTable = true
ResourceAPI.get(folderId).then(response=>{
let resp = response.data;
if(resp.success==true){
// 绑定属性
let folderItem = resp.data;
this.folder.parentId = folderId;
folderItem.results.forEach((item, index, array) => {
this.folder.id = item.id;
this.folder.name = item.name;
})
// // 获取文件夹路径
this.getPathList(folderId, isFile);
// 获取目录下的资源。
// this.getResource();
this.handleResourceList(response);
this.openSearch = false;
this.inputValue = "";
}
});
},
getPathList(folderId, isFile){
ResourceAPI.singleTage(folderId).then(response=>{
let resp = response.data;
if(resp.success==true){
// this.folder.tree = [];
if(isFile) {
this.folder.tree = [];
this.folder.tree.unshift( {id:0, name:'root', path:this.$route.meta.activatedPath})
}
resp.data.directory.reverse().forEach((folerItme, index, array) =>{
this.folder.tree.push({
id:array[index].id,
name:array[index].name,
path:this.$route.meta.activatedPath+"/"+array[index].id
})
});
this.folder.tree.push({
id:resp.data.id,
name:resp.data.name,
path:null
})
this.groupName = resp.data.group
resp.data.group == null? this.groupId = null: this.groupId = resp.data.group.id
}
});
},
getResource(){
// 我的空间List
if(this.space=="private"){
let privateParams= {
page_index:this.pager.index,
pageSize:this.pager.size,
search:"private",
ordering:"id",
}
ResourceAPI.list(privateParams).then(response=>{
this.handleResourceList(response);
});
}
// 公共空间List
else if(this.space=="public"){
let publicParams= {
page_index:this.pager.index,
pageSize:this.pager.size,
search:"public",
ordering:"id"
}
ResourceAPI.list(publicParams).then(response=>{
this.handleResourceList(response);
});
}
},
handleResourceList(response){
this.files = []; // clear the file data
let resp = response.data;
// console.log(resp);
if(resp.success == true){
resp.data.results.forEach((item, index, array) => {
let size = CapacityAPI.bytesToSize(item.size);
let isFile = item.is_file;
if(isFile == false){
size="- -";
}else{
size
}
let tags = item.tag_set;
// Add the user into array
this.files.push({
id:item.id,
name:item.name,
size:size,
isFile:isFile,
from:item.group,
update_time:item.update_time,
download_url:item.download_url,
tags:tags,
directory:item.directory,
});
})
this.pager.total = resp.data.count;
}
},
refreshTable(){
this.getResource();
},
refreshFolder(){
let tamp_list = [];
tamp_list.push(this.folder.tree[0]);
this.folder.tree = tamp_list;
this.getFolder(this.folder.parentId);
},
refreshResultSerach(){
RestVue.$emit('refreshResultSerach', true)
},
changeSelected(name,id,isFile,resourceName,tags,search){
this.modifyResourceId=id;
if(name=='delete'&&isFile==true){
this.delteFile(id,resourceName,search);
}
else if(name=='delete'&&isFile==false){
this.delteFolders(id,resourceName,search);
}
else if(name=='update'&&isFile==true){
this.updateFiles(id,isFile,resourceName,tags,search);
}
else if(name=='update'&&isFile==false){
this.updateFolders(id,isFile,resourceName);
}
else if(name=='copy'&&isFile==true){
this.copingFile =true;
this.modifyIsFile = true;
this.serachResult = search
}
else if(name=='copy'&&isFile==false){
this.copingFile =true;
this.modifyIsFile = false;
}
else if(name=='move'&&isFile==true){
this.movingFile = true;
this.modifyIsFile = true;
this.serachResult = search
}
else if(name=='move'&&isFile==false){
this.movingFile = true;
this.modifyIsFile = false;
}
},
//删除文件
delteFile(id,resourceName,search){
this.$Modal.confirm({
title:'警告',
content: `确定要删除文件【${resourceName}】吗?`,
okText:'删除',
cancelText:'取消',
loading:this.loading,
onOk:()=>{
this.load = this.$Message.loading({
content: 'Loading...',
duration: 0
});
ResourceAPI.file_delete(id).then((response)=>{
if(response.status==204){
if( this.folder.id != 0){
this.refreshFolder();
}
else if(search == true){
this.refreshResultSerach()
this.refreshTable();
}
else{
this.refreshTable(); //更新列表
}
this.$Notice.success({
title: "删除文件成功!",
duration:2.5
});
this.$Message.destroy();
}
else{
this.$Notice.error({
title: response.data.message,
duration:2.5
});
this.load = setTimeout(() => {
this.$Message.destroy();
},500)
}
}).catch(error => {
});
},
onCancel:()=>{
this.$Message.destroy();
this.$Modal.remove()
}
});
},
//删除文件夹
delteFolders(id,resourceName){
this.$Modal.confirm({
title:'警告',
content: `确定要删除文件夹【${resourceName}】吗?`,
cancelText:'取消',
okText:'删除',
loading:this.loading,
onOk:()=>{
this.load = this.$Message.loading({
content: 'Loading...',
duration: 0
});
ResourceAPI.folders_delete(id).then((response)=>{
this.loading = false;
if(response.status==204){
this.$Notice.success({
title: "删除文件夹成功!",
duration:2.5
});
this.$Message.destroy();
if( this.folder.id != 0){
this.refreshFolder()
}else{
this.refreshTable(); //更新列表
}
}
else{
this.$Notice.error({
title: response.data.message,
duration:2.5
});
this.load = setTimeout(() => {
this.$Message.destroy();
},500)
}
}).catch(error => {
});
},
onCancel:()=>{
this.$Message.destroy();
this.$Modal.remove()
}
});
},
//选中单个事件的时候触发
selectedItem(item){
if(this.isRemoveBatch == true){
this.selectedList = []
}
item.length == 0?this.isBatchBth = true: this.isBatchBth = false
let tempArr = []
item.forEach((item,index,array) => {
tempArr.push(item.id)
this.selectedList.push(item.id)
this.repeatArray = Array.from(new Set( this.selectedList));
})
let Array1 = tempArr;
let Array2 = this.selectedList;
let a = new Set(Array1);
let b = new Set(Array2);
// 交集
let intersectionSet = new Set([...a].filter(x => b.has(x)));
this.selectIntersectionSet = Array.from(intersectionSet);
},
//批量删除
remvoeAllDelete(){
this.$Modal.confirm({
title:'警告',
content: `您确定要批量删除吗?`,
cancelText:'取消',
okText:'删除',
loading:this.loading,
onOk:()=>{
this.load = this.$Message.loading({
content: 'Loading...',
duration: 0
});
BatchAPI.delBatch(
this.$store.getters.id,
this.selectIntersectionSet
).then((response)=>{
this.loading = false;
if(response.status==204){
this.$Notice.success({
title: "批量删除成功!",
duration:2.5
});
this.isRemoveBatch = true
this.$Message.destroy();
this.isBatchBth = true
if( this.folder.id != 0){
this.refreshFolder()
} else if(this.openSearch == true){
this.refreshResultSerach()
}
else{
this.refreshTable(); //更新列表
}
}
else{
this.$Notice.error({
title: response.data.message,
duration:2.5
});
this.load = setTimeout(() => {
this.$Message.destroy();
},500)
}
}).catch(error => {
});
},
onCancel:()=>{
this.$Message.destroy();
this.$Modal.remove()
}
});
},
//更新文件
updateFiles(id,isFile,resourceName,tags,serach){
this.serachResult = serach
this.updateFile = true;
this.modifyResourceId = id;
this.modifyResourceName = resourceName;
this.tags = tags;
},
//更新文件夹
updateFolders(id,isFile,resourceName){
this.updateFolder = true;
this.modifyResourceId = id;
this.modifyResourceName = resourceName;
},
//分享
getShare(isFile,id,name){
this.shareFolder = true;
this.modifyIsFile = isFile;
this.modifyResourceId = id;
this.modifyResourceName = name;
},
//批量分享
batchShared(){
this.isBatchShared = true;
},
// 重至批量分享
restBatchShared(boolen){
this.isRemoveBatch = boolen
if(boolen == true){
this.isBatchBth = true
}
},
//批量移动
batchMove(){
this.isBatchMove = true;
},
//批量复制
batchCopy(){
this.isBatchCopy = true
},
//点击下载
clkicDownload(isFile){
if(isFile&&this.folder.id != 0){
this.refreshFolder()
this.isBatchBth = true;
}else{
this.refreshTable()
this.isBatchBth = true ;
}
},
// 关闭Modal
closedModal () {
this.uploading = false;
this.creatingFolder = false;
this.movingFile = false;
this.copingFile = false;
this.shareFolder = false;
this.updateFolder = false;
this.updateFile = false;
this.isBatchShared = false;
this.isBatchMove = false;
this.isBatchCopy = false;
},
showDetail(targetID,isFile){
this.hidingDetail = false;
this.modifyResourceId = targetID;
this.modifyIsFile = isFile;
this.resourceGrid.table = 17;
this.resourceGrid.detail = 7;
},
closedDetail(){
this.hidingDetail = true;
this.modifyIsFile = true;
this.modifyResourceId = 0;
this.modifyResourceName = '';
this.resourceGrid.table = 24;
this.resourceGrid.detail = 0;
},
isUploadDisabled(value){
this.uploadDisabled = value
}
},
}
iview upload组件的应用
<template>
<Modal v-model="opened" :closable="false" :mask-closable="false" @on-cancel="cancel">
<div slot="header">
<h3>上传文件</h3>
</div>
<Upload
ref="upload"
multiple
type="drag"
:data="uploadParams"
:before-upload="handleUploadBefore"
:on-progress="handleUploadProgress"
:on-remove="handleUploadRemove"
:on-success="handleUploadSuccess"
:on-error="handleUploadError"
:action="uploadURL">
<div style="padding: 20px 0">
<Icon type="ios-cloud-upload" size="52" style="color: #3399ff"></Icon>
<p>点击或将文件拖拽到这里上传</p>
</div>
</Upload>
<div slot="footer">
<Button type="ghost" @click="cancel" style="margin-left: 8px">取消</Button>
</div>
</Modal>
</template>
<script>
import ResourceAPI from 'api/resource';
export default {
props:{
opened:{
type:Boolean,
default:false
},
space:{
type:String, // ['PUB','GRO','PER']
default:''
},
groupId:{
type:Number,
default:0
},
folderId:{
type:Number,
default:0
}
},
data(){
return{
uploading:false,
uploadParams:{},
uploadURL:process.env.BASE_API+"file_upload/",
fileList:[],
}
},
watch:{
opened:function(value,oldValue){
if(value==true){
// 更改上传的额外信息
this.uploadParams={
type:this.space,
directory:this.folderId,
group:this.groupId,
}
}
}
},
methods:{
handleUploadBefore (file) {
this.fileList = this.$refs.upload.fileList;
// return false; // 返回 false则不让其上传。
},
handleUploadProgress(event, file, fileList) {
},
handleUploadRemove(file, fileList){
console.log("移除文件");
console.log(file);
},
handleUploadSuccess(response, file, fileList){
console.log("上传成功");
console.log(response);
console.log(file)
this.$emit('uploaded');
},
handleUploadError(error, file, fileList){
console.log("上传失败");
console.log(response);
console.log(file)
},
cancel(){
this.$refs.upload.fileList = [];
this.$emit('closedModal');
}
}
}
// <Button type="ghost" icon="ios-cloud-upload-outline">上传文件</Button>
</script>
vue-cli项目在IE中运行
问题
- ie11打开vue2.0项目空白,控制台报错 vuex requires a Promise polyfill in this browser;
解决方法
- npm install --save-dev babel-polyfill
- 在build文件下找到webpack.base.conf.js
- 如图:
- 大约在第10行位置替换
entry: {
// app: './src/main.js'
app: ['./node_modules/babel-polyfill/dist/polyfill.js','./src/main.js']
},
vue-cli项目https协议登录不进火狐浏览器
解决方法
- 例如:先输入https://192.xx.xx.xx:8000,添加例外,然后在输入 https://192.xx.xx.xx在添加例外
问题点input type='file'的时候,vue怎么读取
- input type='file' @change='importLicense($event)'
- 在methods里添加importLicense($event)方法,
importLicense($event){
//读取文件的值
let _this = this
let file = $event.target.files
for (var i = 0, f; f = file[i]; i++) {
let reader = new FileReader(file);
reader.onload = (function (file) {
return function (e) {
_this.license = reader.result
};
})(f);
//读取文件内容
reader.readAsText(f);
}
},
- 例如:
<template>
<Modal v-model="opened" title="许可证更新" :closable="false" @on-cancel="cancel" >
<Row>
<textarea v-model='license' rows="3" cols="20" style="resize: none; height: 150px;width:400px;" >
</textarea>
<Button type="primary" style="position: absolute;display: inline-block;top: 10px;right: 0px;">
<span>导入</span>
<input @change='importLicense($event)' style="position: absolute;height: 30px;right: 0;top: 0;opacity: 0; width: 90px;" name="file" type="file">
</Button>
</Row>
<div slot="footer">
<Button type="ghost" @click="cancel" style="margin-left: 8px;">取消</Button>
<Button type="primary" :loading='loading' @click='updateLicense' style="margin-left: 8px;">提交</Button>
</div>
</Modal>
</template>
<script>
import LicenseApi from '@/api/license'
export default {
name: "update",
props:{
opened:{
type:Boolean,
default:false,
},
license:{
type:String,
default:''
}
},
data(){
return{
licenses:'',
loading:false,
load:'',
}
},
methods:{
//导入license
importLicense($event){
//读取文件的值
let _this = this
let file = $event.target.files
for (var i = 0, f; f = file[i]; i++) {
let reader = new FileReader(file);
reader.onload = (function (file) {
return function (e) {
_this.license = reader.result
};
})(f);
//读取文件内容
reader.readAsText(f);
}
},
cancel () {
this.$emit('closedModal');
},
//更新license
updateLicense(){
if( this.license.split(" ").join("").length == 0){
this.$Notice.error({
title: '许可证不能为空!',
duration:2.5
});
}else{
this.loading = true
this.load = this.$Message.loading({
content: 'Loading...',
duration: 0
});
LicenseApi.update_license({license:this.license}).then(response=>{
let resp = response.data
if(resp.success == true){
this.$Notice.success({
title: '许可证修改成功!',
duration:2.5
});
this.loading = false
this.load = this.$Message.destroy();
this.$emit('closedModal');
this.$emit('refreshLicense');
}else{
this.$Notice.error({
title: '许可证修改失败!',
duration:2.5
});
this.loading = false
}
}).catch(err=>{
console.log(err);
})
}
}
},
mounted(){
}
}
</script>
<style scoped>
</style>
问题点:webuploader支持上传文件夹
- 修改webuploader插件
- 1.在大概4880行代码左右,在动态生成的input组件的下面,增加webkitdirectory属性 如图:
return Html5Runtime.register( 'FilePicker', {
init: function() {
var container = this.getRuntime().getContainer(),
me = this,
owner = me.owner,
opts = me.options,
label = this.label = $( document.createElement('label') ),
input = this.input = $( document.createElement('input') ),
arr, i, len, mouseHandler;
input.attr( 'type', 'file' );
input.attr( 'name', opts.name );
input.attr( 'webkitdirectory', '')
input.addClass('webuploader-element-invisible');
label.on( 'click', function() {
input.trigger('click');
});
修改以后
问题点:iview 和webuploader实现多文件上传和选择目录上传
- 复制一分webuploader.js 更改名:webuploaderFolder.js
- 更改webuploaderFolder
例如:修改的地方
origin = root.WebUploaderFolder;
root.WebUploaderFolder = makeExport();
root.WebUploaderFolder.noConflict = function() {
root.WebUploaderFolder = origin;
};
问题点webuploader只能获取文件的相对路径
- 通过file.source.source.webkitRelativePath拿到文件的相对路径
/**
* 文件刚加进来的时候
*/
_this.uploaderFolder.on( 'fileQueued', function( file ) {
file.source.source.webkitRelativePath
// _this.uploadFileQueued(file)
});
- 但是文件路径只能拿到上一层文件夹的路径
- 例如路径:["b/d/11.txt", "b/c/新建文本文档.txt", "b/c/e/f/g/11.txt"]
- 要求完整的路径是:["b/d", "b/c", "b/c/e/f/g", "b", "b/c/e", "b/c/e/f"]
webkitdirectory属性支持文件夹上传,但不是标准的元素
- 例如:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>上传file属性</title>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
</head>
<body>
<input id="dialog" type="file" webkitdirectory='' >
</body>
<script>
dialog.onchange = function(e) {
var files = this.files;
var table = [];
for (var i = 0; i < files.length; i++) {
var f = files[i];
table.push(f.webkitRelativePath)
}
let temp = []
let tempArray = []
let new_array = []
table.forEach((item,index,array)=>{
let file = item.substring(0,item.lastIndexOf('/'))
temp.push(file)
})
console.log(table)
temp.forEach((item,index,array)=> {
let list = item.split("/")
let list_len = list.length
let lens = Array.from({length:list_len}, (v,k) => k); //动态指定生成数组的大小
console.log(lens)
lens.forEach((self,index,array)=>{
let ele = list.slice(0,index+1).join("/")
// console.log(ele)
tempArray.push(ele)
// console.log(ele)
})
});
let tempPath = Array.from(new Set(tempArray));
console.log(tempPath) //["b/d", "b/c", "b/c/e/f/g", "b", "b/c/e", "b/c/e/f"]
};
</script>
</html>
问题点:webpuloader在批量上传时,切片的顺序和切片名称错乱问题
- 解决方法:修改webuploader插件,大约在6758位置,添加你的fordata.task_id后端约定好的字段等于你添加的fromdata属性
- 引用
<script src="/static/wepUpload/js/webuploaderFolder.js"></script>
上传按钮的传参
- html
<Dropdown @on-click='uploaderTypeOpen' style="margin-left: 5px">
<Button type="ghost">
上传
<Icon type="android-upload"></Icon>
</Button>
<DropdownMenu slot="list">
<DropdownItem name='file'>文件</DropdownItem>
<DropdownItem name='folder' divided>文件夹</DropdownItem>
</DropdownMenu>
</Dropdown>
- js
<script>
export default {
data () {
return{
uploaderFolder:null,
}
},
methods:{
//上传组件的打开
uploaderTypeOpen(name){
this.uploading = true
this.uploaderFolder = name
},
}
}
<script>
上传的组件封装
<template>
<Modal v-model="opened" :closable="false" :mask-closable="false" @on-cancel="cancel" >
<div slot="header">
<h5>上传文件</h5>
</div>
<div class="uploadContent">
<div id="uploadWarp" style=" padding: 20px 0;">
<Icon type="ios-cloud-upload" size="52" style="color: #3399ff"></Icon>
<p>点击或将文件拖拽到这里上传</p>
</div>
</div>
<Row style='padding-top: 15px;'>
<Col span='24'>
<Row type="flex" justify="start" style='padding-bottom: 15px;'>
<Col span='6'>
<span style='margin-bottom: 10px; font-weight: 900;'> 文件列表 </span>
</Col>
<Col span='10' offset="8" >
<div style='width: 230px;'>
<span style='position: absolute; left: -72px;top: 0;'>上传总进度:</span>
<Progress :percent="allFilePercentage" :status="active" ></Progress>
</div>
</Col>
</Row>
<Table :data='fileList' :no-data-text='tabNoDataTitle' size="small" :columns="columns" border height="260"></Table>
</Col>
</Row>
<div slot="footer">
<Button id="btn" size="small" :disabled="uploadDisabled" type="ghost" @click="cancel" style="margin-left: 8px">取消</Button>
<Button size="small" id="ctlBtn" span="5" offset="7" :disabled="uploadBtnDisabled" type="primary" :loading='uploading'>{{title}}</Button>
</div>
</Modal>
</template>
<style>
.uploadContent{
background: #fff;
border: 1px dashed #dddee1;
border-radius: 4px;
text-align: center;
cursor: pointer;
position: relative;
overflow: hidden;
transition: border-color .2s ease;
}
.uploadContent:hover {
border: 1px dashed dodgerblue;
}
</style>
<script>
import ResourceAPI from 'api/resource';
import { Icon, Button,Progress } from 'iview';
export default {
props:{
opened:{
type:Boolean,
default:false
},
foldered:{
type:String,
default:''
},
space:{
type:String, // ['PUB','GRO','PER']
default:''
},
groupId:{
type:Number,
default:0
},
folderId:{
type:Number,
default:0
},
openSearch:{
type:Boolean,
default:false
}
},
data(){
const columns = [
{ title: '文件名', key: "fileName",width:'20%',
render:(h,params)=>{
let fileName = params.row.fileName;
let namePoint = '';
if(fileName.length>15){
namePoint+=fileName.slice(0, 15)+'...'
}else{
namePoint+=fileName
}
return(
<div >
<span domPropsInnerHTML={namePoint} title={fileName}></span>
</div>
)
}
},
{ title: '大小', key: "fileSize"},
{ title: '进度',textAlign:'center', width:'30%',
render:(h,params)=>{
let filePercentage = params.row.filePercentage
return(
<div>
<Progress style={{ width:'150px'}} percent={ filePercentage} ></Progress>
</div>
)
},
},
{ title: '操作',width:'20%',
render:(h,params)=>{
let fileId = params.row.fileId
let fileName = params.row.fileName
// <Button title='开始上传' onClick={()=>this.startFile(fileId)} size="small" ><Icon type="close"></Icon> </Button>
// <Button title='停止上传' onClick={()=>this.stopFile(this.uploaderFile,fileId)} size="small" ><Icon type="close"></Icon> </Button>
return(
<div style={{ textAlign: 'center' }} >
<Button title='取消上传' onClick={()=>this.deleFile(fileId,fileName)} size="small" ><Icon type="close"></Icon> </Button>
</div>
)
},
},
];
return{
uploading:false,
uploadDisabled:false,
uploadBtnDisabled:false,
title:'开始上传',
uploadParams:{},
uploadHeaders:{
Authorization:"conspace " + this.$store.getters.token
},
uploadURLServer:process.env.BASE_API+"upload/fragment/",
uploadURLSend:process.env.BASE_API+"upload/fragment/success/",
fileList:[],
uploader:null,
uploaderFolder:null,
uploaderId:null,
netWork:false,
tabNoDataTitle:'暂无上传文件',
columns:columns,
uploaderFile:[],
allFilePercentage:0,
active:'active',
pathArray:[],
progressFile:0,
fileProgressId:0,
resultPathFile:[],
resultPathFileCopy:[],
sendFilePathArray:[],
fileFolderIdItem:{},
fileFolderId:0,
fileIndex:0,
fileEndIndex:0,
fileFolderEndIndex:0,
}
},
watch:{
opened:function(value,oldValue){
if(value==true){
// 更改上传的额外信息
if(this.foldered == 'file'){
//上传文件
this.initUpload()
}else{
//上传文件夹
this.initUploadFolder()
}
}
}
},
methods:{
// //开始上传
// startFile(fileId){
// this.uploader.upload(fileId)
// },
// //停止上传
// stopFile(file,fileId){
// file.forEach((item,index,array) => {
// if(fileId == item.id){
// this.uploader.stop(item);
// this.uploader.refresh()
// }else{
// return
// }
// })
// },
//删除文件
deleFile(fileId,fileName,){
this.fileList.forEach((item,indexFile,array)=>{
this.fileIndex = 0
this.uploaderFile.forEach((self,index,array) =>{
if(item.fileId ==self.id && item.fileId ==fileId){
if(this.foldered == 'file'){
this.uploader.cancelFile(self);
this.uploader.removeFile(self,true );
this.uploader.refresh()
this.fileList.splice(indexFile,1)
}else{
this.uploaderFolder.cancelFile(self);
this.uploaderFolder.removeFile(self,true );
this.uploaderFolder.refresh()
this.fileList.splice(indexFile,1)
}
}else{
return
}
})
if(item.fileId ==fileId){
if(this.fileList.length == 0 || this.fileList.length != 0){
this.allFilePercentage = 0
}
}
})
},
//上传文件初始化
initUpload () {
let _this = this;
let uploadURLSend = this.uploadURLSend;
let folderId = this.folderId == 0? '':this.folderId;
let groupId = this.groupId == 0? '':this.groupId;
let type = this.space;
_this.uploader = WebUploader.create({
server: _this.uploadURLServer,//上传路径
dnd:"#uploadWarp",//上传的位置
pick: {
id:"#uploadWarp",
multiple:true
},
duplicate:false,
prepareNextFile: true,
auto: false,
chunked: true,
chunkSize: 20 * 1024 * 1024,
fileNumLimit:100,
fileSingleSizeLimit: 100* 1024 * 1024*1024,// 限制在100G
chunkRetry: 2,
threads: 1,
compress: false,
resize: false,
// formData: {
// task_id: fileMd5
// }
});
/**
* 验证文件格式以及文件大小
*/
_this.uploader.on("error",function (type,handler){
if(type=="F_EXCEED_SIZE"){
_this.$Notice.error({
title: '文件大小不能超过100G',
duration:2.5
});
}else if (type === 'Q_EXCEED_NUM_LIMIT') {
_this.$Notice.error({
title: '文件上传已达到最大上限数',
duration:2.5
});
}
else {
_this.$Notice.error({
title: `上传出错!请检查后重新上传!错误代码${type}`,
duration:10
});
}
});
/**
* 文件刚加进来的时候
*/
_this.uploader.on( 'fileQueued', function( file ) {
_this.uploaderFile.push (file)
_this.fileList.push({
fileName:file.name,
fileId:file.id,
fileSize:WebUploader.Base.formatSize(file.size),
filePercentage:0,
})
});
/**
* 文件刚开始的时候上传的时候
*/
_this.uploader.on('uploadStart', (file) => {
// 在这里可以准备好formData的数据
_this.uploader.options.formData.task_id = file.id
// // _this.keyGenerator(file);
// task_id = _this.keyGenerator(file)
});
// 文件上传过程中创建进度条实时显示。
_this.uploader.on( 'uploadProgress', function( file, percentage ) {
if(_this.fileIndex < _this.fileList.length){
if(percentage < 1){
_this.fileList[_this.fileIndex].filePercentage = parseInt(percentage.toFixed(2) * 100)
}else{
_this.fileList[_this.fileIndex].filePercentage = parseInt(percentage.toFixed(2) * 100)
_this.fileIndex++
}
let fileCount = 0
_this.fileList.forEach((item,index,array)=>{
fileCount += item.filePercentage
})
_this.allFilePercentage = parseInt((fileCount / (_this.fileList.length * 100)).toFixed(2) * 100)
}
});
// 文件上传成功。
_this.uploader.on('uploadSuccess', function(file) {
var data = {
'task_id':file.id,
'ext': file.source['ext'],
'type': file.source['type'],
'name': file.source['name']
};
$.ajax({
type: "get",
url: uploadURLSend,
data: data,
success: function (data) {
let fileName = data.data.file_name
let fileId = data.data.file_id
if(data.success == true){
_this.uploadDisabled = true
_this.$Notice.success({
title: "文件:"+fileName+"上传成功!",
duration:2.5
});
_this.fileEndIndex++
if(_this.fileEndIndex == _this.fileList.length){
debugger
_this.$emit('closedModal');
_this.fileList = []
_this.allFilePercentage = 0
_this.fileIndex = 0
_this.uploadDisabled = false
_this.fileEndIndex=0;
_this.uploader.destroy()
_this.uploader.reset()
_this.uploader.refresh()
_this.$emit("refreshTable")
if(_this.folderId == 0 && _this.openSearch == false){
_this.$emit("refreshTable")
}
else if(_this.folderId != 0 && _this.openSearch == false){
_this.$emit("uploadedFolder")
}
else if(_this.openSearch == true){
_this.openSearch == true?_this.$emit("refreshSearch"):_this.openSearch = false
}
if(_this.netWork == true){
setTimeout(() => {
_this.$router.go(0)
},500)
}
}
// _this.$emit('closedModal');
uploadSend(fileName,fileId)
}
}
});
});
//文件上传报错
_this.uploader.on('uploadError', function(file) {
_this.uploadDisabled = false
_this.netWork = true
_this.uploadBtnDisabled = true
_this.$Message.destroy()
_this.$Notice.error({
title: '上传出错,请重新再传!',
duration:2.5
});
_this.uploading = false;
_this.title = '上传终止'
_this.uploader.destroy()
_this.uploader.reset()
});
//文件上传完成
_this.uploader.on('uploadComplete', function(file) {
});
//文件加载完成
_this.uploader.on('uploadFinished', function () {
//清空队列
_this.uploader.reset();
});
function uploadSend(fileName,fileId){
ResourceAPI.upload(fileName,String(groupId) || '',type,fileId,String(folderId) || '').then(response=>{
let resp = response.data
if(resp.success == true){
_this.$Message.destroy();
_this.uploadDisabled = false
_this.$Notice.success({
title: "文件:"+fileName+"校验成功!",
duration:2.5
});
_this.$emit('uploadDisabled', false)
_this.$emit('restUpload',true)
_this.uploading = false
// if(_this.folderId == 0 && _this.openSearch == false){
// _this.$emit("refreshTable")
// }
//
// else if(_this.folderId != 0 && _this.openSearch == false){
// _this.$emit("uploadedFolder")
// }else if(_this.openSearch == true){
// _this.openSearch == true?_this.$emit("refreshSearch"):_this.openSearch = false
// }
}else{
if(resp.code == 400){
_this.$Notice.error({
title: response.data.message.slice(7),
duration:2.5
});
}else{
_this.$Notice.error({
title: response.data.message.slice(7),
duration:2.5
});
}
_this.uploading = false
_this.uploadDisabled = false
_this.$emit('uploadDisabled', false)
_this.upload = setTimeout(() => {
_this.$Message.destroy();
},500)
// _this.$emit('closedModal');
}
});
}
},
//上传文件夹初始化
initUploadFolder () {
let _this = this;
_this.uploaderFolder = WebUploaderFolder.create({
server: this.uploadURLServer,//上传路径
dnd:"#uploadWarp",//上传的位置
pick: {
id:"#uploadWarp",
multiple:true
},
duplicate:false,//同一文件是否可重复选择
prepareNextFile: true,
auto: false,
chunked: true,
chunkSize: 20 * 1024 * 1024,
// fileNumLimit:100,
fileSingleSizeLimit: 100* 1024 * 1024*1024,// 限制在100G
chunkRetry: 2,
threads: 1,
compress: false,
resize: false,
// formData: {
// task_id: task_id
// }
});
// /**
// * 验证文件格式以及文件大小
// */
_this.uploaderFolder.on("error",function (type,handler){
_this.uploadError(type)
});
/**
* 文件刚加进来的时候
*/
_this.uploaderFolder.on( 'fileQueued', function( file ) {
_this.uploadFileQueued(file)
});
/**
* 文件刚开始的时候上传的时候
*/
_this.uploaderFolder.on('uploadStart', (file) => {
// 在这里可以准备好formData的数据
_this.uploaderFolder.options.formData.task_id = file.id;
// _this.task_id = _this.keyGenerator(file)
});
// 文件上传过程中创建进度条实时显示。
_this.uploaderFolder.on( 'uploadProgress', function( file, percentage ) {
if(_this.fileIndex < _this.fileList.length){
if(percentage < 1){
_this.fileList[_this.fileIndex].filePercentage = parseInt(percentage.toFixed(2) * 100)
}else{
_this.fileList[_this.fileIndex].filePercentage = parseInt(percentage.toFixed(2) * 100)
_this.fileIndex++
}
let fileCount = 0
_this.fileList.forEach((item,index,array)=>{
fileCount += item.filePercentage
})
_this.allFilePercentage = parseInt((fileCount / (_this.fileList.length * 100)).toFixed(2) * 100)
}
});
// 文件上传成功。
_this.uploaderFolder.on('uploadSuccess', function(file,respson) {
let pathFile =file.source.source.webkitRelativePath.substring(0,file.source.source.webkitRelativePath.lastIndexOf('/'))
let pathAllFile ="/"+pathFile
for (var path in _this.fileFolderIdItem){
if(pathAllFile == path){
_this.fileFolderId=_this.fileFolderIdItem[path]
_this.uploadSucess(file.id,file.source,_this.fileFolderId)
break
}
}
});
//文件上传报错
_this.uploaderFolder.on('uploadError', function(file) {
_this.uploadDisabled = false
_this.netWork = true
_this.uploadBtnDisabled = true
_this.$Message.destroy()
_this.$Notice.error({
title: '上传出错,请重新再传!',
duration:2.5
});
_this.uploading = false;
_this.title = '上传终止'
_this.uploaderFolder.destroy()
_this.uploaderFolder.reset()
});
//文件上传完成
_this.uploaderFolder.on('uploadComplete', function(file) {
});
//文件加载完成
_this.uploaderFolder.on('uploadFinished', function () {
//清空队列
_this.uploaderFolder.reset();
});
},
//添加多文件上传参数
keyGenerator(file) {
const currentTime = new Date().getTime();
const key = `${currentTime}.${file.name}`;
return key;
},
cancel(){
this.fileList = []
this.allFilePercentage = 0
this.sendFilePathArray = []
this.fileIndex = 0
this.uploadDisabled = false
if(this.foldered == 'file'){
this.uploader.destroy()
this.uploader.reset()
this.uploader.refresh()
}else{
this.uploaderFolder.destroy()
this.uploaderFolder.reset()
this.uploaderFolder.refresh()
}
if(this.netWork == true){
setTimeout(() => {
this.$router.go(0)
},500)
}
this.$emit('closedModal');
},
//点击上传文件
btnUpload(){
let _this = this
this.$Message.destroy();
$.ajax({
type: "post",
url: this.uploadURLServer,
success: function (data) {
if(data.code == 1010){
_this.uploadDisabled = false
_this.netWork = true
_this.uploadBtnDisabled = true
_this.$Message.destroy()
_this.$Notice.error({
// title: '',
desc:data.message,
duration:2.5
});
_this.uploading = false;
_this.title = '上传终止'
if(_this.foldered == "folder"){
_this.uploaderFolder.destroy()
_this.uploaderFolder.reset()
}else{
_this.uploader.destroy()
_this.uploader.reset()
}
}else{
if(_this.foldered == "folder"){
_this.sendFolderPath()
}else{
_this.uploader.upload();
}
}
}
});
if( this.fileList.length > 0){
this.uploadDisabled = true
this.$Message.loading({
content: '文件正在上传中。。。',
duration: 0
});
this.$emit('uploadDisabled', true)
this.uploading = true
}else {
this.uploadDisabled = false
}
},
//目录最终上传方法
sendFolderPath(){
if(this.fileList.length > 0){
this.resultPathFileCopy =[]
this.resultPathFile.forEach((item,index,array)=>{
//调用方法
let file_list_length = item.split("/")
this.getfolderPath(file_list_length,file_list_length.length)
})
this.sendFilePathArray = Array.from(new Set(this.resultPathFileCopy));
//获取创建的目录方法
ResourceAPI.create_folder(this.$store.getters.id,this.sendFilePathArray,String(this.groupId == 0? '':this.groupId) || '',this.space,String( this.folderId == 0? '':this.folderId) || '').then(response=>{
let resp = response.data
if(resp.success == true){
this.fileFolderIdItem=resp.data//
this.uploaderFolder.upload();
}else{
this.$Notice.error({
title: response.data.message.slice(7),
duration:2.5
});
}
});
}else{
return
}
},
//上传文件错误
uploadError(type){
/**
* 验证文件格式以及文件大小
*/
if(type=="F_EXCEED_SIZE"){
this.$Notice.error({
title: '文件大小不能超过100G',
duration:2.5
});
}else if (type === 'Q_EXCEED_NUM_LIMIT') {
this.$Notice.error({
title: '文件上传已达到最大上限数',
duration:2.5
});
}
else {
this.$Notice.error({
title: '上传出错!请检查后重新上传!错误代码${type}',
duration:2.5
});
}
},
//文件刚加载进来
uploadFileQueued(file){
/**
* 文件刚加进来的时候
*/
let pathFile = file.source.source.webkitRelativePath
let pathFileList = pathFile.substring(0,pathFile.lastIndexOf('/'))
this.pathArray.push(pathFileList)
this.resultPathFile = Array.from(new Set(this.pathArray));
this.uploaderFile.push (file)
this.fileList.push({
fileName:file.name,
fileId:file.id,
fileSize:WebUploaderFolder.Base.formatSize(file.size),
filePercentage:0,
filePath:pathFile,
fileSource:file.source,
taskId:this.keyGenerator(file)
})
},
//调用成功接口
uploadSucess(task_id,fileSocure,fileFolderId){
let _this = this
let data = {
'task_id': task_id,
'ext': fileSocure['ext'],
'type': fileSocure['type'],
'name': fileSocure['name'],
};
$.ajax({
type: "get",
url: this.uploadURLSend,
data: data,
success: function (data) {
let fileName = data.data.file_name
let fileId = data.data.file_id
if (data.success == true) {
_this.uploadDisabled = true
_this.$Notice.success({
title: "文件:" + fileName + "上传成功!",
duration: 2.5
});
_this.fileFolderEndIndex++;
if(_this.fileFolderEndIndex==_this.fileList.length){
_this.fileList = []
_this.allFilePercentage = 0
_this.sendFilePathArray = []
_this.fileIndex = 0
_this.uploadDisabled = false
_this.fileFolderEndIndex=0;
_this.uploaderFolder.destroy()
_this.uploaderFolder.reset()
_this.uploaderFolder.refresh()
if(_this.folderId == 0 && _this.openSearch == false){
_this.$emit("refreshTable")
}else if(_this.folderId != 0 && _this.openSearch == false){
_this.$emit("uploadedFolder")
}else if(_this.openSearch == true){
_this.openSearch == true?_this.$emit("refreshSearch"):_this.openSearch = false
}
if(_this.netWork == true){
setTimeout(() => {
_this.$router.go(0)
},500)
}
_this.$emit('closedModal');
}
_this.uploadSend(fileName, fileId, fileFolderId)
// _this.$emit('closedModal');
}
}
})
},
//向后端请求
uploadSend(fileName,fileId,fileFolderId){
ResourceAPI.upload(fileName,String(this.groupId) || '',this.space,fileId, String(fileFolderId)).then(response=>{
let resp = response.data
if(resp.success == true){
this.$Message.destroy();
this.uploadDisabled = false
this.$Notice.success({
title: "文件:"+fileName+"校验成功!",
duration:2.5
});
this.$emit('uploadDisabled', false)
this.$emit('restUpload',true)
this.uploading = false
}else{
if(resp.code == 400){
this.$Notice.error({
title: response.data.message.slice(7),
duration:2.5
});
}else{
this.$Notice.error({
title: response.data.message.slice(7),
duration:2.5
});
}
this.uploading = false
this.uploadDisabled = false
this.$emit('uploadDisabled', false)
this.upload = setTimeout(() => {
this.$Message.destroy();
},500)
// _this.$emit('closedModal');
}
});
},
//获取文件上一级目录结构
getfolderPath(list,length){
//动态生成数组
let result_length = Array.from({length:length}, (v,k) => k);
result_length.forEach((self,index,array)=>{
let list_val = list.slice(0,index+1).join("/")
this.resultPathFileCopy.push("/"+list_val)
})
},
}
}
</script>
问题点:上传的文件实现预览功能,.text,word,excel,ppt,jpg,等文件
后端将实现好的以text/html形式传给前端,前端怎么接收?
例如:
var $iframe =$('<iframe src="about:blank" frameborder=0 />');
$iframe.ready(function() {
var doc = $iframe[0].contentDocument;
var id="_frame_t";
$iframe.attr('width', '100%');
$iframe.attr('height', '100%');
$iframe.attr('id', id);
doc.write(
resp
);
doc.close();
});
$iframe.appendTo($("#content"));
封装一个组件
<template>
<Modal v-model="opened" title="预览" :closable="false" @on-cancel="cancel" width='60%' :mask-closable='false' >
<div class="layout" id='content' style='height: 600px;'>
</div>
<div slot="footer">
<Button type="ghost" @click="cancel" style="margin-left: 8px">确定</Button>
</div>
</Modal>
</template>
<script>
import ResourceAPI from 'api/resource';
export default{
props:{
opened:{
type:Boolean,
default:false,
},
proviewId: {
type: Number,
default: 0
},
},
watch:{
opened: function (value, oldValue) {
if (value == true) {
$("#content").html('')
this.getPreview()
}
}
},
data () {
return{
load: null,
}
},
computed:{},
methods:{
//获取版本的信息方法
getPreview(){
this.load = this.$Message.loading({
content: 'Loading...',
duration: 0
});
ResourceAPI.proview(this.proviewId).then(response=>{
let resp = response.data
var $iframe =$('<iframe src="about:blank" frameborder=0 />');
$iframe.ready(function() {
var doc = $iframe[0].contentDocument;
var id="_frame_t";
$iframe.attr('width', '100%');
$iframe.attr('height', '100%');
$iframe.attr('id', id);
doc.write(
resp
);
doc.close();
});
$iframe.appendTo($("#content"));
this.load = this.$Message.destroy()
}).catch()
},
cancel () {
this.$emit('closedModal');
},
},
mounted:function () {
}
}
</script>
<style scoped>
</style>
问题点预览图片可以打开上一页,下一页面旋转的
用到插件viewerjs,结合vue和iview
<template>
<Modal v-model="opened" title="预览" :closable="false" @on-cancel="cancel" width='30%' :mask-closable='false'>
<div class="" style='height: 250px;'>
<ul class="pictures" id="galley">
<li><img :src="viewer_url" :alt="img_name"></li>
</ul>
</div>
<div slot="footer">
<Button type="ghost" :disabled='img_diabled' @click="cancel" style="margin-left: 8px">确定</Button>
</div>
</Modal>
</template>
<script>
import ResourceAPI from 'api/resource';
export default{
props:{
opened:{
type:Boolean,
default:false,
},
proviewImgId: {
type: Number,
default: 0
},
proviewImgName:{
type:String,
}
},
watch:{
opened: function (value, oldValue) {
if (value == true) {
this.viewer_url = null
this.get_preview_img()
}
}
},
data () {
return{
load: null,
viewer:null,
viewer_url:null,
img_diabled:false,
img_name:null,
}
},
computed:{},
methods:{
//获取版本的信息方法
get_preview_img() {
this.viewer_url = null
this.load = this.$Message.loading({
content: 'Loading...',
duration: 0
});
this.img_diabled = true
ResourceAPI.proview(this.proviewImgId).then(response=>{
let resp = response.data
if(resp.success == true){
this.viewer_url = resp.data
this.img_name = this.proviewImgName
$('#galley').viewer();
this.load = this.$Message.destroy()
this.img_diabled = false
}else{
this.$Notice.error({
title: resp.message,
duration:2.5
});
this.load = this.$Message.destroy()
this.img_diabled = false
}
}).catch()
},
cancel () {
this.$emit('closedModal');
this.viewer_url = null
this.img_name = null
},
},
mounted:function () {
}
}
</script>
<style scoped>
.pictures {
width: 200px;
height: 200px;
position: absolute;
top: 90px;
left: 180px;
}
.pictures > li {
float: left;
/*width: 33.3%;*/
/*height: 33.3%;*/
width: 100%;
height: 100%;
margin: 0 -1px -1px 0;
border: 1px solid transparent;
overflow: hidden;
}
.pictures > li > img {
width: 100%;
height: 100%;
text-align: center;
cursor: -webkit-zoom-in;
cursor: zoom-in;
}
</style>
问题点:预览视频和音频
<template>
<Modal v-model="opened" title="预览" :closable="false" @on-cancel="cancel" :mask-closable='false'>
<div class="layout video-part" >
<video :src="viedo_url" controls="controls" id='medio'>
<!--<source :src="viedo_url" >-->
</video>
</div>
<div slot="footer">
<Button type="ghost" :disabled='video_disabled' @click="cancel" style="margin-left: 8px">确定</Button>
</div>
</Modal>
</template>
<script>
import ResourceAPI from 'api/resource';
export default{
props:{
opened:{
type:Boolean,
default:false,
},
proviewVideoID: {
type: Number,
default: 0
},
},
watch:{
opened: function (value, oldValue) {
if (value == true) {
this.get_video_url()
}
}
},
data () {
return{
load: null,
viedo_url: null,
video_disabled: false,
}
},
computed:{},
methods:{
//获取版本的信息方法
get_video_url() {
this.viedo_url = null
this.load = this.$Message.loading({
content: 'Loading...',
duration: 0
});
this.video_disabled = true
ResourceAPI.proview(this.proviewVideoID).then(response=>{
let resp = response.data
if(resp.success == true){
this.viedo_url = resp.data
this.load = this.$Message.destroy()
this.video_disabled = false
}else{
this.$Notice.error({
title: resp.message,
duration:2.5
});
this.load = this.$Message.destroy()
this.video_disabled = false
}
}).catch()
},
cancel () {
this.$emit('closedModal');
let Medio = document.getElementById("medio");
Medio.src = null
Medio.pause()
},
},
mounted:function () {
}
}
</script>
<style scoped>
.video-part{
width: 488px;
height:250px;
}
video{
width:100%;
height: 100%;
height:500px\0;/* ie 8/9/10/Opera - for ie8/ie10/Opera */
_height:500px; /* ie 6 - for ie6 */
object-fit: fill
}
</style>
# 音频
<template>
<Modal v-model="opened" title="预览" :closable="false" @on-cancel="cancel" :mask-closable='false'>
<div class="layout" style='height: 60px;'>
<audio :src='audio_url' controls="controls" id='audio'>
<!--<source src="../../../static/movie.mp4" type="audio/mpeg">-->
<!--<source src="../../../static/cat1.ogg" type="audio/ogg">-->
</audio>
</div>
<div slot="footer">
<Button type="ghost" :disabled='audio_disable' @click="cancel" style="margin-left: 8px">确定</Button>
</div>
</Modal>
</template>
<script>
import ResourceAPI from 'api/resource';
export default{
props:{
opened:{
type:Boolean,
default:false,
},
proviewAideoID: {
type: Number,
default: 0
},
},
watch:{
opened: function (value, oldValue) {
if (value == true) {
this.get_preview_audio()
}
}
},
data () {
return{
load: null,
audio_url: null,
audio_disable: false,
}
},
computed:{},
methods:{
//获取版本的信息方法
get_preview_audio() {
this.audio_url = null
this.load = this.$Message.loading({
content: 'Loading...',
duration: 0
});
this.audio_disable = true
ResourceAPI.proview(this.proviewAideoID).then(response=>{
let resp = response.data
if(resp.success == true){
this.audio_url = resp.data
this.load = this.$Message.destroy()
this.audio_disable = false
}else{
this.$Notice.error({
title: resp.message,
duration:2.5
});
this.load = this.$Message.destroy()
this.audio_disable = false
}
}).catch()
},
cancel () {
this.$emit('closedModal');
this.audio_url = null
document.getElementById("audio").src = null;
document.getElementById("audio").pause()
},
},
mounted:function () {
}
}
</script>
<style scoped>
audio{
margin-top: 0px;
width:100%;
height: 100%;
height:500px\0;/* ie 8/9/10/Opera - for ie8/ie10/Opera */
_height:500px; /* ie 6 - for ie6 */
object-fit: fill
}
</style>
问题点:vue axios 默认阻止cookie请求,导致添加验证码以后登不进去
- 解决方法
import axios from 'axios'
axios.defaults.withCredentials=true;//让ajax携带cookie