|
|
|
@ -6,25 +6,31 @@ |
|
|
|
<!-- 选择服务器 --> |
|
|
|
<select class="selbox" name="fsip" ref="fsip" @change="changeSer"> |
|
|
|
<option value="0">请选择源服务器</option> |
|
|
|
<option v-for="item in uslist" :value="item.addr+':'+item.port">{{ item.addr+':'+item.port }}</option> |
|
|
|
<option v-for="item in uslist" :value="item.addr + ':' + item.port">{{ item.addr + ':' + item.port }} |
|
|
|
</option> |
|
|
|
</select> |
|
|
|
<input name="path" class="inputbox" type="text" placeholder="/" autocomplete="off" v-model="fspath"> |
|
|
|
<button @click="getFlist">Go</button> |
|
|
|
<button @click="goParent">🔙</button> |
|
|
|
</div> |
|
|
|
<div class="sflist"> |
|
|
|
<ul > |
|
|
|
<li v-for="item in fsclist" :key="item"> |
|
|
|
<ul> |
|
|
|
<li v-for="item in fsclist" :key="item" @contextmenu.prevent="showMenu" @click="hideMenu"> |
|
|
|
<input type="checkbox" :value="item.path" class="sfchkbox" /> |
|
|
|
<a class="haschild" @click="goIntoDir(item.path,1)" v-if="item.isdir">{{item.path}}</a> |
|
|
|
<span v-else>{{item.path}}</span> |
|
|
|
<a class="haschild" @click="goIntoDir(item.path, 1)" v-if="item.isdir">{{ item.path }}</a> |
|
|
|
<span v-else>{{ item.path }}</span> |
|
|
|
<!-- |
|
|
|
<div class="sflfunc"> |
|
|
|
<a>发送</a> |
|
|
|
</div> --> |
|
|
|
</li> |
|
|
|
</ul> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="tips" > |
|
|
|
<span v-if="fsclist.length > 0"> 服务器:{{this.$refs.fsip.value}} 路径:{{fspath}} ,文件数量:{{ fsclist.length }}</span> |
|
|
|
<span v-else>当前服务器:{{fsip}}</span> |
|
|
|
|
|
|
|
<div class="tips"> |
|
|
|
<span v-if="fsclist.length > 0"> 服务器:{{ this.$refs.fsip.value }} 路径:{{ fspath }} ,文件数量:{{ fsclist.length |
|
|
|
}}</span> |
|
|
|
<span v-else>当前服务器:{{ fsip }}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<!-- 第二个服务器的文件列表 --> |
|
|
|
@ -33,32 +39,45 @@ |
|
|
|
<!-- 选择服务器 --> |
|
|
|
<select class="selbox" name="ssip" ref="ssip"> |
|
|
|
<option value="0">请选择源服务器</option> |
|
|
|
<option v-for="item in uslist" :value="item.addr+':'+item.port">{{ item.addr+':'+item.port }}</option> |
|
|
|
<option v-for="item in uslist" :value="item.addr + ':' + item.port">{{ item.addr + ':' + item.port }} |
|
|
|
</option> |
|
|
|
</select> |
|
|
|
<input name="path" class="inputbox" type="text" placeholder="/" autocomplete="off" v-model="sspath"> |
|
|
|
<button @click="getSflist">GO</button> |
|
|
|
<button @click="goParent">🔙</button> |
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<div class="sflist"> |
|
|
|
<ul > |
|
|
|
<ul> |
|
|
|
<li v-for="item in ssclist" :key="item"> |
|
|
|
<a class="haschild" @click="goIntoDir(item.path,2)" v-if="item.isdir">{{item.path}}</a> |
|
|
|
<span v-else>{{item.path}}</span> |
|
|
|
<a class="haschild" @click="goIntoDir(item.path, 2)" v-if="item.isdir">{{ item.path }}</a> |
|
|
|
<span v-else>{{ item.path }}</span> |
|
|
|
</li> |
|
|
|
</ul> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="tips" > |
|
|
|
<span v-if="ssclist.length > 0">当前路径:{{sspath}} ,文件数量:{{ ssclist.length }}</span> |
|
|
|
<span v-else>当前服务器:{{ssip}}</span> |
|
|
|
|
|
|
|
<div class="tips"> |
|
|
|
<span v-if="ssclist.length > 0">当前路径:{{ sspath }} ,文件数量:{{ ssclist.length }}</span> |
|
|
|
<span v-else>当前服务器:{{ ssip }}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 右键菜单 --> |
|
|
|
<div class="sftrans" v-if="isMenuVisible" @contextmenu.prevent :style="{ top: menuTop + 'px', left: menuLeft + 'px' }"> |
|
|
|
<ul class="sfbcon"> |
|
|
|
<li><span href="javascript:void(0)" @click="handleMenuAction('upload')">同步文件</span></li> |
|
|
|
<li><span href="javascript:void(0)" @click="handleMenuAction('download')">压缩下载</span></li> |
|
|
|
<li class="divider"></li> |
|
|
|
<li><span href="javascript:void(0)" @click="handleMenuAction('delete')">删除文件</span></li> |
|
|
|
</ul> |
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
</div> |
|
|
|
</template> |
|
|
|
|
|
|
|
<script> |
|
|
|
import { GetFileList,SerlistInUsing } from '@/api/scinfo' |
|
|
|
import { GetFileList, SerlistInUsing } from '@/api/scinfo' |
|
|
|
|
|
|
|
export default { |
|
|
|
name: 'Sfilecompare', |
|
|
|
@ -68,19 +87,35 @@ export default { |
|
|
|
ssip: '', |
|
|
|
fsclist: {}, // 第一台文件列表 |
|
|
|
ssclist: {}, // 第二台文件列表 |
|
|
|
uslist:[], //使用中的服务器 |
|
|
|
fspath:'/', // 第一个服务器的路径 |
|
|
|
sspath:'/', // 第二个服务器的路径 |
|
|
|
uslist: [], //使用中的服务器 |
|
|
|
fspath: '/', // 第一个服务器的路径 |
|
|
|
sspath: '/', // 第二个服务器的路径 |
|
|
|
|
|
|
|
isMenuVisible: true, // 菜单是否可见 |
|
|
|
menuTop: 0, // 菜单顶部位置 |
|
|
|
menuLeft: 0, // 菜单左侧位置 |
|
|
|
} |
|
|
|
}, |
|
|
|
mounted() { |
|
|
|
// 点击文档其他区域隐藏菜单 |
|
|
|
document.addEventListener('click', (event) => { |
|
|
|
//避免快速点击时的冲突 |
|
|
|
if(this.isMenuVisible){ |
|
|
|
this.hideMenu() |
|
|
|
} |
|
|
|
}) |
|
|
|
// 使用中的服务器 |
|
|
|
SerlistInUsing().then(res => { |
|
|
|
this.uslist = res.data; |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
}, |
|
|
|
beforeMount() { |
|
|
|
// 移除事件监听 |
|
|
|
document.removeEventListener('click', this.hideMenu); |
|
|
|
}, |
|
|
|
methods: { |
|
|
|
|
|
|
|
// 获取第一个服务器的文件列表 |
|
|
|
getFlist() { |
|
|
|
// 获取第一个服务器 |
|
|
|
@ -89,7 +124,7 @@ export default { |
|
|
|
let sport = sstr[1] |
|
|
|
let scip = btoa(sstr[0]) |
|
|
|
// 获取文件列表 |
|
|
|
GetFileList({srcip: scip,path: this.fspath,sport: sport}).then(res => { |
|
|
|
GetFileList({ srcip: scip, path: this.fspath, sport: sport }).then(res => { |
|
|
|
this.fsclist = res.data.list |
|
|
|
}) |
|
|
|
}, |
|
|
|
@ -100,74 +135,67 @@ export default { |
|
|
|
let sport = sstr[1] |
|
|
|
let scip = btoa(sstr[0]) |
|
|
|
// 获取文件列表 |
|
|
|
GetFileList({srcip: scip,path: this.sspath,sport: sport}).then(res => { |
|
|
|
GetFileList({ srcip: scip, path: this.sspath, sport: sport }).then(res => { |
|
|
|
this.ssclist = res.data.list |
|
|
|
}) |
|
|
|
}, |
|
|
|
// 进入子目录 |
|
|
|
goIntoDir(path,nflag){ |
|
|
|
goIntoDir(path, nflag) { |
|
|
|
// 根据nflag 来判断 |
|
|
|
let npath,sel |
|
|
|
if(nflag==1){ |
|
|
|
sel=this.$refs.fsip.value |
|
|
|
// if(this.fspath == path){ |
|
|
|
// this.fspath = '/' |
|
|
|
// } |
|
|
|
let npath, sel |
|
|
|
if (nflag == 1) { |
|
|
|
sel = this.$refs.fsip.value |
|
|
|
// 拼装url |
|
|
|
if(this.fspath == '/'){ |
|
|
|
if (this.fspath == '/') { |
|
|
|
npath = '/' + path |
|
|
|
}else{ |
|
|
|
} else { |
|
|
|
npath = this.fspath + '/' + path |
|
|
|
} |
|
|
|
// npath = this.fspath== '/' ? "/"+path : this.fspath + path |
|
|
|
} |
|
|
|
if(nflag==2){ |
|
|
|
if (nflag == 2) { |
|
|
|
sel = this.$refs.ssip.value |
|
|
|
|
|
|
|
if(this.sspath == path){ |
|
|
|
if (this.sspath == path) { |
|
|
|
this.sspath = '/' |
|
|
|
} |
|
|
|
if(this.sspath=='/'){ |
|
|
|
if (this.sspath == '/') { |
|
|
|
npath = '/' + path |
|
|
|
}else{ |
|
|
|
} else { |
|
|
|
npath = this.sspath + '/' + path |
|
|
|
} |
|
|
|
// npath = this.sspath + path+"/" |
|
|
|
// npath = this.sspath == '/' ? "/"+path : this.fspath + path |
|
|
|
} |
|
|
|
let rrarr = this.preIp(sel) |
|
|
|
// ip转为base64 |
|
|
|
let ip = btoa(rrarr[0]) |
|
|
|
console.log(npath) |
|
|
|
this.queryFlist(ip,rrarr[1],npath,nflag) |
|
|
|
this.queryFlist(ip, rrarr[1], npath, nflag) |
|
|
|
}, |
|
|
|
// 查询内容 |
|
|
|
// nflag 1 第一个服务器 2 第二个服务器 |
|
|
|
async queryFlist(ip,port,npath,nflag){ |
|
|
|
async queryFlist(ip, port, npath, nflag) { |
|
|
|
let rlist = [] |
|
|
|
await GetFileList({ |
|
|
|
srcip: ip,path: npath, sport: port |
|
|
|
srcip: ip, path: npath, sport: port |
|
|
|
}).then(res => { |
|
|
|
var vlist = res.data.list |
|
|
|
if(vlist){ |
|
|
|
// 绑定数据 |
|
|
|
if(nflag == 1){ |
|
|
|
this.fspath = npath |
|
|
|
this.fsclist = vlist |
|
|
|
} |
|
|
|
if(nflag == 2){ |
|
|
|
this.sspath = npath |
|
|
|
this.ssclist = vlist |
|
|
|
if (vlist) { |
|
|
|
// 绑定数据 |
|
|
|
if (nflag == 1) { |
|
|
|
this.fspath = npath |
|
|
|
this.fsclist = vlist |
|
|
|
} |
|
|
|
if (nflag == 2) { |
|
|
|
this.sspath = npath |
|
|
|
this.ssclist = vlist |
|
|
|
} |
|
|
|
} else { |
|
|
|
npath = "/" |
|
|
|
} |
|
|
|
}else{ |
|
|
|
npath="/" |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
}) |
|
|
|
return rlist; |
|
|
|
}, |
|
|
|
// 拆分组装ip |
|
|
|
preIp(ssip){ |
|
|
|
preIp(ssip) { |
|
|
|
// 返回数组 |
|
|
|
let iparr = [] |
|
|
|
let sstr = ssip.split(":") |
|
|
|
@ -176,7 +204,7 @@ export default { |
|
|
|
return iparr |
|
|
|
}, |
|
|
|
// 选择服务器 |
|
|
|
changeSer(){ |
|
|
|
changeSer() { |
|
|
|
// 清空路径 |
|
|
|
this.fspath = '/' |
|
|
|
this.sspath = '/' |
|
|
|
@ -184,9 +212,9 @@ export default { |
|
|
|
|
|
|
|
// 上一级目录 |
|
|
|
// 移除最后一个文件 |
|
|
|
goParent(){ |
|
|
|
goParent() { |
|
|
|
// 第一个服务器 |
|
|
|
if(this.fspath != '/'){ |
|
|
|
if (this.fspath != '/') { |
|
|
|
let npath = this.fspath.split('/') |
|
|
|
// 弹出最后一个元素 |
|
|
|
npath.pop() |
|
|
|
@ -195,15 +223,53 @@ export default { |
|
|
|
this.getFlist() |
|
|
|
} |
|
|
|
// 第二个服务器 |
|
|
|
if(this.sspath != '/'){ |
|
|
|
if (this.sspath != '/') { |
|
|
|
let npath = this.sspath.split('/') |
|
|
|
npath.pop() |
|
|
|
this.sspath = npath.join('/') |
|
|
|
// 调用方法 |
|
|
|
this.getSflist() |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
// 右键菜单内容 |
|
|
|
showMenu(event) { |
|
|
|
console.log(event) |
|
|
|
// 计算菜单位置(基于点击坐标) |
|
|
|
this.menuTop = event.clientY; |
|
|
|
this.menuLeft = event.clientX; |
|
|
|
|
|
|
|
// 确保菜单不会超出视口 |
|
|
|
this.adjustMenuPosition(); |
|
|
|
|
|
|
|
// 显示菜单 |
|
|
|
this.isMenuVisible = true; |
|
|
|
}, |
|
|
|
// 隐藏右键菜单 |
|
|
|
hideMenu() { |
|
|
|
this.isMenuVisible = false; |
|
|
|
}, |
|
|
|
// 调整菜单位置,避免超出视口 |
|
|
|
adjustMenuPosition() { |
|
|
|
const menuWidth = 200; // 菜单宽度(px) |
|
|
|
const menuHeight = 160; // 菜单高度(px) |
|
|
|
|
|
|
|
// 右侧超出视口时向左调整 |
|
|
|
if (this.menuLeft + menuWidth > window.innerWidth) { |
|
|
|
this.menuLeft = window.innerWidth - menuWidth; |
|
|
|
} |
|
|
|
|
|
|
|
// 底部超出视口时向上调整 |
|
|
|
if (this.menuTop + menuHeight > window.innerHeight) { |
|
|
|
this.menuTop = window.innerHeight - menuHeight; |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 处理菜单操作 |
|
|
|
handleMenuAction(action) { |
|
|
|
console.log(`执行操作: ${action}`); |
|
|
|
// 这里可以添加具体的业务逻辑 |
|
|
|
this.hideMenu(); // 执行完操作后隐藏菜单 |
|
|
|
}, |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
@ -219,69 +285,81 @@ export default { |
|
|
|
background-color: #fff; |
|
|
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); |
|
|
|
border-radius: 12px 12px 0 0; |
|
|
|
position: relative; |
|
|
|
} |
|
|
|
.sfcon{ |
|
|
|
|
|
|
|
.sfcon { |
|
|
|
padding: 20px; |
|
|
|
float: left; |
|
|
|
width: 100%; |
|
|
|
min-height: 560px; |
|
|
|
} |
|
|
|
.sfcon:first-child{ |
|
|
|
|
|
|
|
.sfcon:first-child { |
|
|
|
margin-bottom: 22px; |
|
|
|
box-shadow: 1px 7px 10px 3px rgba(0, 0, 0, 0.1); |
|
|
|
} |
|
|
|
.sfcon:nth-child(2){ |
|
|
|
|
|
|
|
.sfcon:nth-child(2) { |
|
|
|
margin-top: 22px; |
|
|
|
} |
|
|
|
.sfcon:nth-child(2) .sflist{ |
|
|
|
|
|
|
|
.sfcon:nth-child(2) .sflist { |
|
|
|
background-color: #f1ebeb; |
|
|
|
} |
|
|
|
.sfind{ |
|
|
|
|
|
|
|
.sfind { |
|
|
|
width: 100%; |
|
|
|
/* height: 40px; */ |
|
|
|
line-height: 40px; |
|
|
|
padding: 12px; |
|
|
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); |
|
|
|
} |
|
|
|
.sfind .selbox{ |
|
|
|
|
|
|
|
.sfind .selbox { |
|
|
|
height: 40px; |
|
|
|
border-top: none; |
|
|
|
border-left:none; |
|
|
|
border-left: none; |
|
|
|
border-right: none; |
|
|
|
|
|
|
|
outline: none; |
|
|
|
padding: 0 12px; |
|
|
|
} |
|
|
|
.sfind .inputbox{ |
|
|
|
|
|
|
|
.sfind .inputbox { |
|
|
|
height: 40px; |
|
|
|
line-height: 40px; |
|
|
|
padding: 12px; |
|
|
|
border-top: none; |
|
|
|
border-left:none; |
|
|
|
border-left: none; |
|
|
|
border-right: none; |
|
|
|
margin-left: 12px; |
|
|
|
outline: none; |
|
|
|
width: 460px; |
|
|
|
} |
|
|
|
.sfind button{ |
|
|
|
|
|
|
|
.sfind button { |
|
|
|
width: 70px; |
|
|
|
height: 40px; |
|
|
|
margin-left: 12px; |
|
|
|
background-color: #f5f5f5; |
|
|
|
border: none; |
|
|
|
} |
|
|
|
.sfcon .sflist{ |
|
|
|
|
|
|
|
.sfcon .sflist { |
|
|
|
min-height: 460px; |
|
|
|
overflow-y: auto; |
|
|
|
background-color: #f5f5f5; |
|
|
|
} |
|
|
|
.sfcon .sflist ul{ |
|
|
|
|
|
|
|
.sfcon .sflist ul { |
|
|
|
margin-top: 20px; |
|
|
|
display: block; |
|
|
|
width: 100%; |
|
|
|
min-height: 500px; |
|
|
|
} |
|
|
|
.sfcon .sflist ul li{ |
|
|
|
|
|
|
|
.sfcon .sflist ul li { |
|
|
|
list-style: none; |
|
|
|
width: 100%; |
|
|
|
float: left; |
|
|
|
@ -290,17 +368,64 @@ export default { |
|
|
|
border-bottom: 1px dashed #ccc; |
|
|
|
} |
|
|
|
|
|
|
|
.sfcon .sflist ul li .sfchkbox{ |
|
|
|
.sfcon .sflist ul li:hover { |
|
|
|
background-color: #dad8d8; |
|
|
|
} |
|
|
|
|
|
|
|
.sfcon .sflist ul li .sflfunc { |
|
|
|
/* display: none; */ |
|
|
|
float: right; |
|
|
|
width: 360px; |
|
|
|
margin-right: 20px; |
|
|
|
} |
|
|
|
|
|
|
|
.sfcon .sflist ul li .sfchkbox { |
|
|
|
margin-right: 12px; |
|
|
|
} |
|
|
|
|
|
|
|
.sfcon .sflist .haschild{ |
|
|
|
.sfcon .sflist .haschild { |
|
|
|
cursor: pointer; |
|
|
|
} |
|
|
|
|
|
|
|
.sfcon .sflist .tips{ |
|
|
|
.sfcon .sflist .tips { |
|
|
|
width: 100%; |
|
|
|
float: left; |
|
|
|
margin-top: 12px; |
|
|
|
} |
|
|
|
|
|
|
|
/* 传输功能区 */ |
|
|
|
.sftrans { |
|
|
|
position: fixed; |
|
|
|
width: 200px; |
|
|
|
height: 120px; |
|
|
|
z-index: 99; |
|
|
|
background-color: #f5f5f5; |
|
|
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); |
|
|
|
} |
|
|
|
|
|
|
|
.sftrans .sfbcon { |
|
|
|
color: #333; |
|
|
|
margin-left: auto; |
|
|
|
margin-right: auto; |
|
|
|
background-color: #fff; |
|
|
|
padding:10px; |
|
|
|
} |
|
|
|
.sftrans .sfbcon li{ |
|
|
|
list-style: none; |
|
|
|
height: 30px; |
|
|
|
line-height: 30px; |
|
|
|
} |
|
|
|
.sftrans .sfbcon li:hover{ |
|
|
|
background-color: #00bd7e; |
|
|
|
color: #fff; |
|
|
|
cursor: default; |
|
|
|
} |
|
|
|
.sftrans .sfbcon li span{ |
|
|
|
padding-left: 12px; |
|
|
|
} |
|
|
|
.sftrans .sfbcon li.divider{ |
|
|
|
height: 1px; |
|
|
|
background-color: #00bd7e; |
|
|
|
margin: 10px 0; |
|
|
|
} |
|
|
|
</style> |