文件同步管理

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, params:params,
}); });
} }
export function automaticFileBackupByIds(params:any) {
return request({
url: '/experimentalData/ts-files/automaticFileBackupByIds',
method: 'post',
params:params,
});
}
//获取url //获取url
export function obtainUrl(params:any) { export function obtainUrl(params:any) {
return request({ return request({
@ -95,3 +102,27 @@ export function compareMinio(params:any) {
params:params, 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> <template>
<!-- 地图容器 --> <div ref="mapContainer" class="map-container" :class="{ 'fullscreen': isFullscreen }">
<div id="map" style="height: 800px; width: 100%"></div> <button class="fullscreen-btn" @click="toggleFullscreen">
{{ isFullscreen ? '退出全屏' : '全屏' }}
</button>
</div>
</template> </template>
<script setup lang="ts"> <script setup>
import { onMounted, watch, nextTick, onUnmounted } from 'vue' import { ref, onMounted, watch, defineEmits, onBeforeUnmount } from 'vue'
import L from 'leaflet' import * as d3 from 'd3'
import 'leaflet/dist/leaflet.css' import chinaData from './newJson.json'
import { useUserStore } from '@/store/modules/user';
const userStore = useUserStore();
const url = userStore.mapUrl;
//
interface PointProp {
points?: Array<[number, number]>;
}
// // ==================== ====================
const MAP_CONFIG = { const DEFAULT_MAP_SIZE = { width: 800, height: 600 }
center: [39.9042, 116.4074] as [number, number], // const PROJECTION_CENTER = [104, 37] //
zoom: 4, // const SCALE_FACTORS = { normal: 600, fullscreen: 1000 }
minZoom: 0, //
maxZoom: 11, //
zoomControl: true //
}
// 线 // ==================== Props/Emits ====================
const POLYLINE_STYLE = { const props = defineProps({
color: 'blue', // 线 coordinates: {
weight: 3, // 线 type: Array,
lineJoin: 'round' as const // default: () => [
} [116.405285, 39.904989], //
[121.472644, 31.231706] //
// props ],
const props = withDefaults(defineProps<PointProp>(), { validator: value => value.every(coord =>
points: () => [] Array.isArray(coord) && coord.length === 2 &&
}) typeof coord[0] === 'number' && typeof coord[1] === 'number'
//
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!)
) )
},
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])
} }
/** /**
* 主绘制函数 * 初始化地图基础结构
* @param points 原始坐标数组
*/ */
function drawTrajectory(points: Array<[number, number]>) { const initializeMap = () => {
if (!map) return //
if (svgInstance) svgInstance.remove()
// const { width, height } = getContainerSize()
clearLayers() const projection = createProjection()
const pathGenerator = d3.geoPath().projection(projection)
// // SVG
if (points?.length > 0) { svgInstance = d3.select(mapContainer.value)
const latlngs = points.map(convertToLatLng) .append('svg')
createPolyline(latlngs) .attr('width', width)
markers = createMarkers(latlngs) .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)
} }
// /**
onMounted(() => { * 渲染中国地图路径和文字
nextTick(() => { * @param {d3.GeoPath} path - 路径生成器
initMap() */
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
}) })
// const isValidCoordinate = (coord) =>
onUnmounted(() => { Array.isArray(coord) && coord.length === 2 &&
map?.remove() !isNaN(coord[0]) && !isNaN(coord[1])
map = null
// ==================== ====================
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 onBeforeUnmount(() => {
watch(() => props.points, (newPoints) => { window.removeEventListener('resize', handleWindowResize)
drawTrajectory(newPoints || []) })
}, { deep: true, immediate: true })
// ==================== ====================
watch(() => props.qvehuan, (newVal) => {
isRouteInitialized.value = newVal
updateRoute()
})
watch(() => props.coordinates, () => {
updateRoute()
}, { deep: true })
</script> </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,13 +89,13 @@ function gettreedata() {
getNodesTree(treeForm.value).then((res: any) => { getNodesTree(treeForm.value).then((res: any) => {
treedata.value = res.data treedata.value = res.data
treeloading.value = false treeloading.value = false
if( treedata.value[0]){ if (treedata.value[0]) {
pathid.value = treedata.value[0].id pathid.value = treedata.value[0].id
nextTick(() => { nextTick(() => {
treeRef.value?.setCurrentKey(pathid.value); treeRef.value?.setCurrentKey(pathid.value);
}); });
getdata() getdata()
}else{ } else {
tableData.value.length = 0 tableData.value.length = 0
} }
@ -589,7 +589,23 @@ const title1 = ref('')
const isViewfile = ref(false) const isViewfile = ref(false)
const fileType = ref('') const fileType = ref('')
function openPreview(row: any) { 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 title1.value = row.fileName
ViewfileUrl.value = row.url ViewfileUrl.value = row.url
isViewfile.value = true isViewfile.value = true
@ -669,7 +685,7 @@ const FILE_ICONS = {
txt: TextImg txt: TextImg
}; };
// //
const fileIcon = (row:any) => { const fileIcon = (row: any) => {
const ext = row.fileName.split('.').pop()?.toLowerCase() || 'unknown'; const ext = row.fileName.split('.').pop()?.toLowerCase() || 'unknown';
return FILE_ICONS[ext as keyof typeof FILE_ICONS] || (row.type == 'ZIP' ? ZipImg : TextImg); return FILE_ICONS[ext as keyof typeof FILE_ICONS] || (row.type == 'ZIP' ? ZipImg : TextImg);
}; };
@ -754,8 +770,7 @@ const fileIcon = (row:any) => {
<el-table-column prop="fileName" label="预览" width="80" align="center"> <el-table-column prop="fileName" label="预览" width="80" align="center">
<template #default="{ row }"> <template #default="{ row }">
<div class="preview-icon"> <div class="preview-icon">
<img :src="fileIcon(row)" alt="file icon" class="file-icon" <img :src="fileIcon(row)" alt="file icon" class="file-icon" @click=" openPreview(row)">
@click=" openPreview(row)">
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
@ -767,8 +782,8 @@ const fileIcon = (row:any) => {
style="display: flex;display: -webkit-flex;justify-content: space-between;-webkit-justify-content: space-between; "> 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)" <!-- <img src="@/assets/project/chong.png" alt="" title="重命名" @click="editfile(scope.row, false)"
style="cursor: pointer;"> --> style="cursor: pointer;"> -->
<img src="@/assets/MenuIcon/lbcz_xg.png" alt="" @click="editfile(scope.row, true)" title="修改" <img src="@/assets/MenuIcon/lbcz_xg.png" alt="" @click="editfile(scope.row, true)"
style="cursor: pointer;"> title="修改" style="cursor: pointer;">
<img src="@/assets/MenuIcon/lbcz_sc.png" alt="" @click="delfile(scope.row)" title="删除" <img src="@/assets/MenuIcon/lbcz_sc.png" alt="" @click="delfile(scope.row)" title="删除"
style="cursor: pointer;"> style="cursor: pointer;">
<img src="@/assets/MenuIcon/xia1.png" alt="" @click="xiafile(scope.row)" title="下载" <img src="@/assets/MenuIcon/xia1.png" alt="" @click="xiafile(scope.row)" title="下载"
@ -814,16 +829,15 @@ const fileIcon = (row:any) => {
<el-input v-model="fileObj.keywords" maxlength="200" show-word-limit /> <el-input v-model="fileObj.keywords" maxlength="200" show-word-limit />
</el-form-item> </el-form-item>
<el-form-item v-if="judge" label="描述:"> <el-form-item v-if="judge" label="描述:">
<el-input v-model="fileObj.description" :rows="2" type="textarea" maxlength="400" show-word-limit /> <el-input v-model="fileObj.description" :rows="2" type="textarea" maxlength="400"
show-word-limit />
</el-form-item> </el-form-item>
<el-form-item> </el-form>
</el-scrollbar>
<div style="width: 100%;display: flex;justify-content: end;"> <div style="width: 100%;display: flex;justify-content: end;">
<el-button type="primary" @click="submitfile">确定</el-button> <el-button type="primary" @click="submitfile">确定</el-button>
<el-button @click="fileClose">取消</el-button> <el-button @click="fileClose">取消</el-button>
</div> </div>
</el-form-item>
</el-form>
</el-scrollbar>
</el-dialog> </el-dialog>
<!-- 组件预览 --> <!-- 组件预览 -->
@ -991,6 +1005,7 @@ const fileIcon = (row:any) => {
padding: 0px !important; padding: 0px !important;
} }
} }
.preview-icon { .preview-icon {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@ -1687,14 +1687,13 @@ function texexceltClose() {
<el-form-item v-if="judge" label="描述:"> <el-form-item v-if="judge" label="描述:">
<el-input v-model="fileObj.description" :rows="2" type="textarea" maxlength="400" show-word-limit /> <el-input v-model="fileObj.description" :rows="2" type="textarea" maxlength="400" show-word-limit />
</el-form-item> </el-form-item>
<el-form-item>
</el-form>
</el-scrollbar>
<div style="width: 100%;display: flex;justify-content: end;"> <div style="width: 100%;display: flex;justify-content: end;">
<el-button type="primary" @click="submitfile">确定</el-button> <el-button type="primary" @click="submitfile">确定</el-button>
<el-button @click="fileClose">取消</el-button> <el-button @click="fileClose">取消</el-button>
</div> </div>
</el-form-item>
</el-form>
</el-scrollbar>
</el-dialog> </el-dialog>
<el-dialog title="创建文件/文件夹" v-model="creat" width="30%" :before-close="creatClose" top="30px" draggable <el-dialog title="创建文件/文件夹" v-model="creat" width="30%" :before-close="creatClose" top="30px" draggable
destroy-on-close> destroy-on-close>
@ -1901,7 +1900,7 @@ function texexceltClose() {
</el-dialog> </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> destroy-on-close>
<div style="margin:0px 0px 15px 0px ;"> <div style="margin:0px 0px 15px 0px ;">
<span>设定采样频率</span> <span>设定采样频率</span>
@ -1916,7 +1915,7 @@ function texexceltClose() {
<div @click="tabbas = '1'" :class="tabbas == '1' ? 'mapbox_border' : 'mapbox_border1'">载体运动轨迹</div> <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 @click="tabbas = '2'" :class="tabbas == '2' ? 'mapbox_border' : 'mapbox_border1'">高程变化动态图</div>
</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" /> <MapChart :points="dynamicCoordinates" />
</div> </div>
<div v-show="tabbas == '2'" style="width: 800px;height:600px;overflow: hidden;"> <div v-show="tabbas == '2'" style="width: 800px;height:600px;overflow: hidden;">

View File

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