文件同步管理

This commit is contained in:
wangxk 2025-05-08 18:56:57 +08:00
parent 8317b543cd
commit ff1e18aee9
5 changed files with 530 additions and 198 deletions

View File

@ -63,6 +63,13 @@ export function automaticFileBackup(params:any) {
params:params,
});
}
export function automaticFileBackupByIds(params:any) {
return request({
url: '/experimentalData/ts-files/automaticFileBackupByIds',
method: 'post',
params:params,
});
}
//获取url
export function obtainUrl(params:any) {
return request({
@ -95,3 +102,27 @@ export function compareMinio(params:any) {
params:params,
});
}
//文件差异-新增全部
export function compareLocalList(params:any) {
return request({
url: '/experimentalData/ts-files/compareLocalList',
method: 'post',
params:params,
});
}
//文件差异变更全部
export function compareMd5List(params:any) {
return request({
url: '/experimentalData/ts-files/compareMd5List',
method: 'post',
params:params,
});
}
//文件差异-缺失全部
export function compareMinioList(params:any) {
return request({
url: '/experimentalData/ts-files/compareMinioList',
method: 'post',
params:params,
});
}

View File

@ -1,139 +1,296 @@
<template>
<!-- 地图容器 -->
<div id="map" style="height: 800px; width: 100%"></div>
<div ref="mapContainer" class="map-container" :class="{ 'fullscreen': isFullscreen }">
<button class="fullscreen-btn" @click="toggleFullscreen">
{{ isFullscreen ? '退出全屏' : '全屏' }}
</button>
</div>
</template>
<script setup lang="ts">
import { onMounted, watch, nextTick, onUnmounted } from 'vue'
import L from 'leaflet'
import 'leaflet/dist/leaflet.css'
import { useUserStore } from '@/store/modules/user';
const userStore = useUserStore();
const url = userStore.mapUrl;
//
interface PointProp {
points?: Array<[number, number]>;
}
<script setup>
import { ref, onMounted, watch, defineEmits, onBeforeUnmount } from 'vue'
import * as d3 from 'd3'
import chinaData from './newJson.json'
//
const MAP_CONFIG = {
center: [39.9042, 116.4074] as [number, number], //
zoom: 4, //
minZoom: 0, //
maxZoom: 11, //
zoomControl: true //
}
// ==================== ====================
const DEFAULT_MAP_SIZE = { width: 800, height: 600 }
const PROJECTION_CENTER = [104, 37] //
const SCALE_FACTORS = { normal: 600, fullscreen: 1000 }
// 线
const POLYLINE_STYLE = {
color: 'blue', // 线
weight: 3, // 线
lineJoin: 'round' as const //
}
// props
const props = withDefaults(defineProps<PointProp>(), {
points: () => []
})
//
let map: L.Map | null = null
// 线
let polyline: L.Polyline | null = null
//
let markers: L.Marker[] = []
/**
* 初始化地图实例
*/
function initMap() {
map = L.map('map', MAP_CONFIG)
addTileLayer()
}
/**
* 添加离线瓦片图层
*/
function addTileLayer() {
L.tileLayer(url+'/{z}/{y}/{x}.jpg', {
attribution: 'Offline Map',
tileSize: 256,
noWrap: true
}).addTo(map!)
}
/**
* 清除所有轨迹元素
*/
function clearLayers() {
// 线
polyline?.remove()
//
markers.forEach(marker => marker.remove())
markers = []
}
/**
* 将坐标转换为Leaflet的LatLng对象
* @param point 原始坐标数组
* @returns Leaflet坐标对象
*/
const convertToLatLng = (point: [number, number]) => L.latLng(point[0], point[1])
/**
* 绘制轨迹线
* @param latlngs 坐标点数组
*/
function createPolyline(latlngs: L.LatLng[]) {
polyline = L.polyline(latlngs, POLYLINE_STYLE).addTo(map!)
//
// map?.fitBounds(polyline.getBounds())
}
/**
* 创建标记点
* @param latlngs 坐标点数组
* @returns 标记实例数组
*/
function createMarkers(latlngs: L.LatLng[]) {
return latlngs.map(latlng =>
L.marker(latlng).addTo(map!)
)
}
/**
* 主绘制函数
* @param points 原始坐标数组
*/
function drawTrajectory(points: Array<[number, number]>) {
if (!map) return
//
clearLayers()
//
if (points?.length > 0) {
const latlngs = points.map(convertToLatLng)
createPolyline(latlngs)
markers = createMarkers(latlngs)
// ==================== Props/Emits ====================
const props = defineProps({
coordinates: {
type: Array,
default: () => [
[116.405285, 39.904989], //
[121.472644, 31.231706] //
],
validator: value => value.every(coord =>
Array.isArray(coord) && coord.length === 2 &&
typeof coord[0] === 'number' && typeof coord[1] === 'number'
)
},
qvehuan: {
type: Boolean,
default: false
}
})
const emit = defineEmits(['qvehuan1'])
// ==================== ====================
const mapContainer = ref(null)
const isFullscreen = ref(false)
const isRouteInitialized = ref(false) // initqie
// ==================== D3 ====================
let svgInstance = null
let mapGroup = null
let markersGroup = null
let zoomBehavior = null
// ==================== ====================
/**
* 创建地理投影配置
* @returns {d3.GeoProjection} D3地理投影实例
*/
const createProjection = () => {
const { width, height } = getContainerSize()
return d3.geoMercator()
.center(PROJECTION_CENTER)
.scale(isFullscreen.value ? SCALE_FACTORS.fullscreen : SCALE_FACTORS.normal)
.translate([width / 2, height / 2])
}
//
onMounted(() => {
nextTick(() => {
initMap()
/**
* 初始化地图基础结构
*/
const initializeMap = () => {
//
if (svgInstance) svgInstance.remove()
const { width, height } = getContainerSize()
const projection = createProjection()
const pathGenerator = d3.geoPath().projection(projection)
// SVG
svgInstance = d3.select(mapContainer.value)
.append('svg')
.attr('width', width)
.attr('height', height)
//
const mainGroup = svgInstance.append('g')
mapGroup = mainGroup.append('g').attr('class', 'map-layer')
markersGroup = mainGroup.append('g').attr('class', 'markers-layer')
//
renderChinaMap(pathGenerator)
//
initializeZoomBehavior(mainGroup)
}
/**
* 渲染中国地图路径和文字
* @param {d3.GeoPath} path - 路径生成器
*/
const renderChinaMap = (path) => {
//
mapGroup.append('g')
.selectAll('path')
.data(chinaData.features)
.enter()
.append('path')
.attr('d', path)
.attr('fill', '#e7e7e7')
.attr('stroke', '#fff')
//
mapGroup.append('g')
.selectAll('text')
.data(chinaData.features)
.enter()
.append('text')
.attr('transform', d => `translate(${path.centroid(d)})`)
.text(d => d.properties.name || '')
.attr('text-anchor', 'middle')
.attr('dominant-baseline', 'central')
.style('font', '12px Arial')
.attr('fill', '#333')
.style('pointer-events', 'none')
}
/**
* 初始化缩放行为
* @param {d3.Selection} group - 需要应用缩放的分组
*/
const initializeZoomBehavior = (group) => {
zoomBehavior = d3.zoom()
.scaleExtent([0.2, 68])
.on('zoom', ({ transform }) => {
group.attr('transform', transform)
})
svgInstance.call(zoomBehavior)
}
// ==================== 线 ====================
/**
* 更新路线和标记点
*/
const updateRoute = () => {
if (!props.coordinates?.length) return
if (!mapGroup) initializeMap()
const projection = createProjection()
const pathGenerator = d3.geoPath().projection(projection)
//
if (isRouteInitialized.value) {
mapGroup.selectAll('.route-path').remove()
markersGroup.selectAll('*').remove()
isRouteInitialized.value = false
emit('qvehuan1', isRouteInitialized.value)
}
// 线
renderRoutePath(pathGenerator)
renderMarkers(projection)
}
/**
* 绘制路径动画
* @param {d3.GeoPath} path - 路径生成器
*/
const renderRoutePath = (path) => {
const routeData = {
type: "LineString",
coordinates: props.coordinates
}
mapGroup.append('path')
.datum(routeData)
.attr('class', 'route-path')
.attr('d', path)
.attr('fill', 'none')
.attr('stroke', '#f00')
.attr('stroke-width', 0.1)
.attr('stroke-dasharray', function() {
return this.getTotalLength()
})
.attr('stroke-dashoffset', function() {
return this.getTotalLength()
})
.transition()
.duration(2000)
.attr('stroke-dashoffset', 0)
}
/**
* 绘制位置标记点
* @param {d3.GeoProjection} projection - 地理投影实例
*/
const renderMarkers = (projection) => {
props.coordinates.forEach(coord => {
if (!isValidCoordinate(coord)) return
const [x, y] = projection(coord)
markersGroup.append('circle')
.attr('cx', x)
.attr('cy', y)
.attr('r', 0.3)
.attr('fill', '#ff4757')
.attr('stroke', 'white')
.attr('stroke-width', 0)
})
}
// ==================== ====================
const getContainerSize = () => ({
width: mapContainer.value?.clientWidth || DEFAULT_MAP_SIZE.width,
height: mapContainer.value?.clientHeight || DEFAULT_MAP_SIZE.height
})
//
onUnmounted(() => {
map?.remove()
map = null
const isValidCoordinate = (coord) =>
Array.isArray(coord) && coord.length === 2 &&
!isNaN(coord[0]) && !isNaN(coord[1])
// ==================== ====================
const handleWindowResize = () => {
if (!isFullscreen.value) return
initializeMap()
updateRoute()
}
const toggleFullscreen = () => {
isFullscreen.value = !isFullscreen.value
setTimeout(() => {
initializeMap()
updateRoute()
}, 100) // DOM
}
// ==================== ====================
onMounted(() => {
window.addEventListener('resize', handleWindowResize)
//
initializeMap() // [!code ++]
// coordinates线
if (props.coordinates?.length) { // [!code ++]
updateRoute() // [!code ++]
} // [!code ++]
})
// points
watch(() => props.points, (newPoints) => {
drawTrajectory(newPoints || [])
}, { deep: true, immediate: true })
</script>
onBeforeUnmount(() => {
window.removeEventListener('resize', handleWindowResize)
})
// ==================== ====================
watch(() => props.qvehuan, (newVal) => {
isRouteInitialized.value = newVal
updateRoute()
})
watch(() => props.coordinates, () => {
updateRoute()
}, { deep: true })
</script>
<style>
.map-container {
position: relative;
background-color: #f0f8ff;
margin: 20px;
overflow: hidden;
touch-action: none;
transition: all 0.3s ease;
width: 100%;
height: 100%;
}
.fullscreen {
position: fixed !important;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: 0 !important;
z-index: 1000;
}
.fullscreen-btn {
position: absolute;
top: 10px;
right: 25px;
z-index: 1001;
padding: 8px 16px;
background: rgba(0, 0, 0, 0.7);
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: opacity 0.2s;
}
.fullscreen-btn:hover {
opacity: 0.9;
}
</style>

View File

@ -89,16 +89,16 @@ function gettreedata() {
getNodesTree(treeForm.value).then((res: any) => {
treedata.value = res.data
treeloading.value = false
if( treedata.value[0]){
if (treedata.value[0]) {
pathid.value = treedata.value[0].id
nextTick(() => {
treeRef.value?.setCurrentKey(pathid.value);
});
getdata()
}else{
nextTick(() => {
treeRef.value?.setCurrentKey(pathid.value);
});
getdata()
} else {
tableData.value.length = 0
}
})
}
const pathid = ref()
@ -589,7 +589,23 @@ const title1 = ref('')
const isViewfile = ref(false)
const fileType = ref('')
function openPreview(row: any) {
if (getFileExtension(row.fileName) == 'pdf' || getFileExtension(row.fileName) == 'xlsx'|| getFileExtension(row.fileName) == 'xls' || getFileExtension(row.fileName) == 'docx' || getFileExtension(row.fileName) == 'doc' || getFileExtension(row.fileName) == 'bin') {
console.log(row)
// if(row.fileSize > '2'){
// ElMessageBox.confirm(
// '?',
// '',
// {
// confirmButtonText: '',
// cancelButtonText: '',
// type: 'warning',
// }
// )
// .then(() => {
// window.open(row.url);
// })
// return
// }
if (getFileExtension(row.fileName) == 'pdf' || getFileExtension(row.fileName) == 'xlsx' || getFileExtension(row.fileName) == 'xls' || getFileExtension(row.fileName) == 'docx' || getFileExtension(row.fileName) == 'doc' || getFileExtension(row.fileName) == 'bin') {
title1.value = row.fileName
ViewfileUrl.value = row.url
isViewfile.value = true
@ -669,7 +685,7 @@ const FILE_ICONS = {
txt: TextImg
};
//
const fileIcon = (row:any) => {
const fileIcon = (row: any) => {
const ext = row.fileName.split('.').pop()?.toLowerCase() || 'unknown';
return FILE_ICONS[ext as keyof typeof FILE_ICONS] || (row.type == 'ZIP' ? ZipImg : TextImg);
};
@ -754,21 +770,20 @@ const fileIcon = (row:any) => {
<el-table-column prop="fileName" label="预览" width="80" align="center">
<template #default="{ row }">
<div class="preview-icon">
<img :src="fileIcon(row)" alt="file icon" class="file-icon"
@click=" openPreview(row)">
<img :src="fileIcon(row)" alt="file icon" class="file-icon" @click=" openPreview(row)">
</div>
</template>
</el-table-column>
<el-table-column prop="uploader" width="80" label="上传人"></el-table-column>
<el-table-column prop="uploadTime" width="170" label="上传时间"></el-table-column>
<el-table-column label="操作" width="100" align="center">
<el-table-column label="操作" width="100" align="center">
<template #default="scope">
<span
style="display: flex;display: -webkit-flex;justify-content: space-between;-webkit-justify-content: space-between; ">
<!-- <img src="@/assets/project/chong.png" alt="" title="重命名" @click="editfile(scope.row, false)"
style="cursor: pointer;"> -->
<img src="@/assets/MenuIcon/lbcz_xg.png" alt="" @click="editfile(scope.row, true)" title="修改"
style="cursor: pointer;">
<img src="@/assets/MenuIcon/lbcz_xg.png" alt="" @click="editfile(scope.row, true)"
title="修改" style="cursor: pointer;">
<img src="@/assets/MenuIcon/lbcz_sc.png" alt="" @click="delfile(scope.row)" title="删除"
style="cursor: pointer;">
<img src="@/assets/MenuIcon/xia1.png" alt="" @click="xiafile(scope.row)" title="下载"
@ -807,23 +822,22 @@ const fileIcon = (row:any) => {
<el-button @click="openUploadFolderDialog" type="primary">上传文件夹</el-button> -->
<ZUpload />
</el-form-item>
<el-form-item v-else prop="fileName" label="文件名称:">
<el-form-item v-else prop="fileName" label="文件名称:">
<el-input v-model="fileObj.fileName" disabled />
</el-form-item>
<el-form-item v-if="judge" label="关键字:" prop="taskName">
<el-input v-model="fileObj.keywords" maxlength="200" show-word-limit />
</el-form-item>
<el-form-item v-if="judge" label="描述:">
<el-input v-model="fileObj.description" :rows="2" type="textarea" maxlength="400" show-word-limit />
</el-form-item>
<el-form-item>
<div style="width: 100%;display: flex;justify-content: end;">
<el-button type="primary" @click="submitfile">确定</el-button>
<el-button @click="fileClose">取消</el-button>
</div>
<el-input v-model="fileObj.description" :rows="2" type="textarea" maxlength="400"
show-word-limit />
</el-form-item>
</el-form>
</el-scrollbar>
<div style="width: 100%;display: flex;justify-content: end;">
<el-button type="primary" @click="submitfile">确定</el-button>
<el-button @click="fileClose">取消</el-button>
</div>
</el-dialog>
<!-- 组件预览 -->
@ -991,6 +1005,7 @@ const fileIcon = (row:any) => {
padding: 0px !important;
}
}
.preview-icon {
display: flex;
align-items: center;

View File

@ -1687,14 +1687,13 @@ function texexceltClose() {
<el-form-item v-if="judge" label="描述:">
<el-input v-model="fileObj.description" :rows="2" type="textarea" maxlength="400" show-word-limit />
</el-form-item>
<el-form-item>
<div style="width: 100%;display: flex;justify-content: end;">
</el-form>
</el-scrollbar>
<div style="width: 100%;display: flex;justify-content: end;">
<el-button type="primary" @click="submitfile">确定</el-button>
<el-button @click="fileClose">取消</el-button>
</div>
</el-form-item>
</el-form>
</el-scrollbar>
</el-dialog>
<el-dialog title="创建文件/文件夹" v-model="creat" width="30%" :before-close="creatClose" top="30px" draggable
destroy-on-close>
@ -1901,7 +1900,7 @@ function texexceltClose() {
</el-dialog>
<!-- 轨迹地图 -->
<el-dialog title="轨迹地图/图表" v-model="mapTrajectory" :before-close="mapClose" top="30px" draggable
<el-dialog title="轨迹地图/图表" v-model="mapTrajectory" :close-on-click-modal="false" :before-close="mapClose" top="30px" draggable
destroy-on-close>
<div style="margin:0px 0px 15px 0px ;">
<span>设定采样频率</span>
@ -1916,7 +1915,7 @@ function texexceltClose() {
<div @click="tabbas = '1'" :class="tabbas == '1' ? 'mapbox_border' : 'mapbox_border1'">载体运动轨迹</div>
<div @click="tabbas = '2'" :class="tabbas == '2' ? 'mapbox_border' : 'mapbox_border1'">高程变化动态图</div>
</div>
<div v-show="tabbas == '1'" style="width:100%;height:600px;overflow: hidden;margin-top: 20px;">
<div v-show="tabbas == '1'" style="width:800px;height:600px;overflow: hidden;margin-top: 20px;">
<MapChart :points="dynamicCoordinates" />
</div>
<div v-show="tabbas == '2'" style="width: 800px;height:600px;overflow: hidden;">
@ -1926,7 +1925,7 @@ function texexceltClose() {
</el-dialog>
<!-- 组件预览 -->
<!-- 视频播放器 -->
<el-dialog draggable class="zfile-video-dialog" :destroy-on-close="true" v-model="dialogVideoVisible">
<el-dialog draggable class="zfile-video-dialog" :destroy-on-close="true" v-model="dialogVideoVisible">
<video-player v-if="dialogVideoVisible" ref="videoPlayer" />
</el-dialog>
<!-- 文本编辑器 -->

View File

@ -9,7 +9,7 @@ import { ref, onMounted, nextTick, defineAsyncComponent, onBeforeUnmount } from
import { Search } from '@element-plus/icons-vue'
import { ElMessageBox, ElMessage } from "element-plus";
import { tstaskList, getTsNodesTree, tsFilesPage, deleteTsFilesByIds } from "@/api/datamanagement";
import { listLocalAndBackup, compare, compareLocal, compareMd5, compareMinio, uploadToBackup, downloadToLocal, deleteTsFilesById, automaticFileBackup, obtainUrl, listBackupTree, listLocalTree } from "@/api/fileSynchronization";
import { listLocalAndBackup, compare, compareLocalList,automaticFileBackupByIds, compareMd5List, compareMinioList, compareLocal, compareMd5, compareMinio, uploadToBackup, downloadToLocal, deleteTsFilesById, automaticFileBackup, obtainUrl, listBackupTree, listLocalTree } from "@/api/fileSynchronization";
import { debounce } from 'lodash-es';
import Page from '@/components/Pagination/page.vue';
//text
@ -68,10 +68,25 @@ function diffFile() {
});
tabs.value = 1
differential.value = true
diffSure()
diffChange()
diffMiss()
diffSure(false)
diffChange(false)
diffMiss(false)
}
function diffFile2() {
const seen = new Set();
comparearr.value = comparearr.value.filter(item => {
return seen.has(item.id) ? false : seen.add(item.id);
});
getchayi()
}
//
function gettreeTwo() {
getlocaltree()
getminiotree()
}
function backups() {
ElMessageBox.confirm(
'您确定要将文件/文件夹自动备份到备份空间吗?',
@ -85,16 +100,73 @@ function backups() {
.then(() => {
worktree.value = true
worktree1.value = true
automaticFileBackup({ nodeId: pathid.value, taskId: projectId.value }).then((res: any) => {
const seen = new Set();
comparearr.value = comparearr.value.filter(item => {
return seen.has(item.id) ? false : seen.add(item.id);
});
const ids = []
const params: any = {}
if (comparearr.value.length > 0) {
comparearr.value.forEach((item: any) => {
ids.push(item.id)
})
params.id = ids.join(',')
} else {
params.nodeId = pathid.value
params.taskId = projectId.value
}
if(ids.length > 0){
automaticFileBackupByIds(params).then((res: any) => {
if (res.code == 0) {
ElMessage.success(res.msg)
getlocaltree()
getminiotree()
}
})
}else{
automaticFileBackup(params).then((res: any) => {
if (res.code == 0) {
ElMessage.success(res.msg)
getlocaltree()
getminiotree()
}
})
}
})
}
////////////
function getchayi() {
const ids = []
const params: any = {}
if (comparearr.value.length > 0) {
comparearr.value.forEach((item: any) => {
ids.push(item.id)
})
params.id = ids.join(',')
} else {
params.nodeId = pathid.value
params.taskId = projectId.value
}
compareLocalList(params).then((res: any) => {
// debugger
localOnlyFiles.value = res.data
gettreeTwo()
})
compareMd5List(params).then((res: any) => {
md5MismatchedFiles.value = res.data
gettreeTwo()
})
compareMinioList(params).then((res: any) => {
minioOnlyFiles.value = res.data
gettreeTwo()
})
}
//
const comparearr: any = ref([])
const localOnlyFiles: any = ref([])
@ -107,7 +179,7 @@ const loading3 = ref(false)
const sureSize = ref(10)
const sureTotal = ref()
const sureCurrent = ref(1)
function diffSure() {
function diffSure(row: any) {
loading1.value = true
const ids = []
const params: any = {}
@ -134,7 +206,7 @@ function diffSure() {
const ChangeSize = ref(10)
const ChangeTotal = ref()
const ChangeCurrent = ref(1)
function diffChange() {
function diffChange(row: any) {
loading2.value = true
const ids = []
const params: any = {}
@ -155,13 +227,14 @@ function diffChange() {
ChangeSize.value = res.data.size
ChangeTotal.value = res.data.total
ChangeCurrent.value = res.data.current
})
}
//-
const MisseSize = ref(10)
const MissTotal = ref()
const MissCurrent = ref(1)
function diffMiss() {
function diffMiss(row: any) {
loading3.value = true
const ids = []
const params: any = {}
@ -182,6 +255,7 @@ function diffMiss() {
MisseSize.value = res.data.size
MissTotal.value = res.data.total
MissCurrent.value = res.data.current
})
}
//
@ -189,7 +263,6 @@ function diffMiss() {
function diffColor() {
// 1. 使Map
const createMap = (arr: any[]) => new Map(arr.map(item => [item.id, item]));
const localMap = createMap(localOnlyFiles.value);
const md5Map = createMap(md5MismatchedFiles.value);
const minioMap = createMap(minioOnlyFiles.value);
@ -303,8 +376,8 @@ const handleCheckChange = (
// 使
const updateCompare = debounce(() => {
//
comparearr.value = getclickdata(workall.value);
const comparearrval = getclickdata(workall.value);
comparearr.value = getclickdata(workall.value);
const comparearrval = getclickdata(workall.value);
//
const checkedKeys = comparearrval
.map(node => node.id)
@ -453,8 +526,8 @@ const backupsChange = (
const updateCompare = debounce(() => {
// comparearr.value.length = 0
comparearr.value = getclickdata(workall.value);
const comparearrval = getclickdata(workall.value);
comparearr.value = getclickdata(workall.value);
const comparearrval = getclickdata(workall.value);
//
const checkedKeys = comparearrval
.map(node => node.id)
@ -598,8 +671,8 @@ function tableBeifen(row: any) {
uploadToBackup({ parameterLists: params }).then((res: any) => {
if (res.code == '0') {
ElMessage.success("上传成功")
diffSure()
diffChange()
diffSure(false)
diffChange(false)
}
})
})
@ -630,8 +703,8 @@ function moretableBeifen() {
loading2.value = true
uploadToBackup({ parameterLists: beifenArr3 }).then((res: any) => {
if (res.code == '0') {
diffSure()
diffChange()
diffSure(false)
diffChange(false)
ElMessage.success("上传成功")
}
})
@ -662,8 +735,8 @@ function tablerestore(row: any) {
downloadToLocal({ parameterLists: params }).then((res: any) => {
if (res.code == '0') {
ElMessage.success("恢复成功")
diffChange()
diffMiss()
diffChange(false)
diffMiss(false)
}
})
})
@ -694,8 +767,8 @@ function moretablerestore() {
downloadToLocal({ parameterLists: restoreArr3 }).then((res: any) => {
if (res.code == '0') {
ElMessage.success("恢复成功")
diffChange()
diffMiss()
diffChange(false)
diffMiss(false)
}
})
@ -720,7 +793,7 @@ function delhuifu() {
deleteTsFilesByIds({ ids: ids.value.join(','), type: 'minio' }).then((res: any) => {
if (res.code == '0') {
ElMessage.success("删除成功")
diffMiss()
diffMiss(false)
}
})
@ -759,7 +832,7 @@ function bfclick(type: any) {
uploadToBackup({ parameterLists: beifenArr3 }).then((res: any) => {
if (res.code == '0') {
ElMessage.success("上传成功")
diffChange()
diffChange(false)
}
})
} else {
@ -771,7 +844,7 @@ function bfclick(type: any) {
downloadToLocal({ parameterLists: restoreArr3 }).then((res: any) => {
if (res.code == '0') {
ElMessage.success("恢复成功")
diffChange()
diffChange(false)
}
})
}
@ -966,12 +1039,28 @@ const tabs = ref(1)
</div>
</aside>
<section class="silderRight">
<div class="tree_button">
<el-button type="primary" :disabled="worktree && worktree1" @click="backups()">文件自动备份</el-button>
<el-button type="primary" :disabled="worktree && worktree1" @click="diffFile()">文件差异性对比</el-button>
<el-button type="primary" :disabled="worktree && worktree1"
@click="differential = true">查看本次差异性对比</el-button>
<div style="display: flex;justify-content: space-between;align-items: center;">
<div class="legend">
<div class="legend_box">
<div class="legend_color1"></div>
<div class="legend_text">工作空间新增文件</div>
</div>
<div class="legend_box">
<div class="legend_color2"></div>
<div class="legend_text">工作空间已删除文件</div>
</div>
<div class="legend_box">
<div class="legend_color3"></div>
<div class="legend_text">工作空间内容变动文件</div>
</div>
</div>
<div class="tree_button">
<el-button type="primary" :disabled="worktree && worktree1" @click="backups()">文件备份</el-button>
<el-button type="primary" :disabled="worktree && worktree1" @click="diffFile2()">差异检测</el-button>
<el-button type="primary" :disabled="worktree && worktree1" @click="diffFile()">差异批量处理</el-button>
</div>
</div>
<div class="tree_box">
<div class="tree_left">
<div class="tree_title">工作空间:</div>
@ -987,9 +1076,9 @@ const tabs = ref(1)
<span class="text">
{{ data.fileName }}({{ data.isFile == 'FOLDER' ? data.children.length :
data.fileSize + 'MB' }})
<span v-if="data.station != '0'">({{ data.station == '1' ? '新增' :
<!-- <span v-if="data.station != '0'">({{ data.station == '1' ? '新增' :
(data.station
== '2' ? '已变更' : '已删除') }})</span>
== '2' ? '已变更' : '已删除') }})</span> -->
</span>
</span>
</template>
@ -1022,9 +1111,9 @@ const tabs = ref(1)
<span class="text">{{ data.fileName }}({{ data.isFile == 'FOLDER' ?
data.children.length :
data.fileSize + 'MB' }})</span>
<span v-if="data.station != '0'">({{ data.station == '1' ? '新增' :
<!-- <span v-if="data.station != '0'">({{ data.station == '1' ? '新增' :
(data.station
== '2' ? '已变更' : '已删除') }})</span>
== '2' ? '已变更' : '已删除') }})</span> -->
</span>
</template>
</el-tree-v2>
@ -1042,12 +1131,12 @@ const tabs = ref(1)
</div>
</div>
<!-- 文件差异性对比 -->
<el-dialog title="文件差异性对比" v-model="differential" width="50%" :before-close="diffClose" top="30px"
<el-dialog title="差异批量处理" v-model="differential" width="50%" :before-close="diffClose" top="30px"
draggable destroy-on-close>
<div class="tabbs_all">
<div @click="tabs = 1" :class="tabs == 1 ? 'tabbs_box1' : 'tabbs_box'">新增内容</div>
<div @click="tabs = 2" :class="tabs == 2 ? 'tabbs_box1' : 'tabbs_box'">变更内容</div>
<div @click="tabs = 3" :class="tabs == 3 ? 'tabbs_box1' : 'tabbs_box'">缺失内容</div>
<div @click="tabs = 1" :class="tabs == 1 ? 'tabbs_box1' : 'tabbs_box'">新增文件</div>
<div @click="tabs = 2" :class="tabs == 2 ? 'tabbs_box1' : 'tabbs_box'">修改文件</div>
<div @click="tabs = 3" :class="tabs == 3 ? 'tabbs_box1' : 'tabbs_box'">删除文件</div>
</div>
<div>
<!-- <el-scrollbar height="400px"> -->
@ -1086,7 +1175,7 @@ const tabs = ref(1)
</el-table-column>
</el-table>
<Page :total="sureTotal" v-model:size="sureSize" v-model:current="sureCurrent"
@pagination="diffSure()">
@pagination="diffSure(false)">
</Page>
</div>
<div class="newContent" v-if="tabs == 2">
@ -1129,7 +1218,7 @@ const tabs = ref(1)
</el-table-column>
</el-table>
<Page :total="ChangeTotal" v-model:size="ChangeSize" v-model:current="ChangeCurrent"
@pagination="diffChange()">
@pagination="diffChange(false)">
</Page>
</div>
<div class="newContent" v-if="tabs == 3">
@ -1171,7 +1260,7 @@ const tabs = ref(1)
</el-table-column>
</el-table>
<Page :total="MissTotal" v-model:size="MisseSize" v-model:current="MissCurrent"
@pagination="diffMiss()">
@pagination="diffMiss(false)">
</Page>
</div>
<!-- </el-scrollbar> -->
@ -1306,7 +1395,7 @@ const tabs = ref(1)
.tree_left {
width: 49%;
height: calc(78vh);
height: calc(77vh);
.tree_title {
@ -1327,7 +1416,7 @@ const tabs = ref(1)
padding: 5px;
background-color: green;
color: #fff;
margin-bottom: 5px !important;
// margin-bottom: 5px !important;
}
.custom-tree-node2 {
@ -1468,4 +1557,45 @@ const tabs = ref(1)
border-bottom: 3px solid #409eff;
}
}
//
.legend {
width: 40%;
display: flex;
align-items: center;
justify-content: space-between;
background-color: #409eff;
padding: 5px 8px;
box-sizing: border-box;
border-radius: 4px;
color: #fff;
.legend_box {
display: flex;
align-items: center;
.legend_color1 {
width: 14px;
height: 14px;
background-color: green;
}
.legend_color2 {
width: 14px;
height: 14px;
background-color: red;
}
.legend_color3 {
width: 14px;
height: 14px;
background-color: yellow;
}
.legend_text {
font-size: 14px;
margin-left: 10px;
}
}
}
</style>