Commit 922f75be by ningjihai

项目管理

parent 49682210
...@@ -104,6 +104,77 @@ export function updateDataProject(data) { ...@@ -104,6 +104,77 @@ export function updateDataProject(data) {
data: data data: data
}) })
} }
export function showProxyInfo(data) {
return request({
url: '/core/encryptionconfig/showProxyInfo',
method: 'post',
data: data
})
}
export function saveProxyJarInfo(data) {
return request({
url: '/core/encryptionconfig/saveProxyJarInfo',
method: 'post',
data: data
})
}
export function getProjectTree(data) {
return request({
url: '/core/encryptionconfig/getProjectTree',
method: 'post',
data: data
})
}
export function getEncryptExcel(data) {
return request({
url: '/core/encryptionconfig/getEncryptExcel',
method: 'post',
data: data,
responseType: 'blob' //
})
}
export function checkEncryptExcel(data) {
return request({
url: '/core/encryptionconfig/checkEncryptExcel',
method: 'post',
data: data
})
}
export function exportToExcel(data) {
return request({
url: '/core/encryptionconfig/exportToExcel',
method: 'post',
data: data,
responseType: 'blob' //
})
}
export function tdatasourceQuery(data) {
return request({
url: '/core/tdatasource/query',
method: 'post',
data: data
})
}
export function queryShemasmodifysubsettask(data) {
return request({
url: '/core/modifysubsettask/queryShemas',
method: 'post',
data: data
})
}
export function rowsensitivelevelType(type,data) {
return request({
url: '/core/rowsensitivelevel/' + type,
method: 'post',
data: data
})
}
...@@ -11,8 +11,8 @@ ...@@ -11,8 +11,8 @@
<div class="section-content"> <div class="section-content">
<div class="readonly-input-group"> <div class="readonly-input-group">
<span class="input-label">加密网关平台:</span> <span class="input-label">加密网关平台:</span>
<el-input v-model="gatewayConfig.url" disabled class="input-field" /> <el-input v-model="gatewayConfig.url" class="input-field" />
<el-input v-model="gatewayConfig.port" disabled class="input-field port-input" /> <el-input v-model="gatewayConfig.port" class="input-field port-input" />
<el-button type="primary" icon="Download" @click="downloadGatewayPlugin">下载</el-button> <el-button type="primary" icon="Download" @click="downloadGatewayPlugin">下载</el-button>
</div> </div>
</div> </div>
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
<el-table-column label="操作" width="300" align="center"> <el-table-column label="操作" width="300" align="center">
<template #default="{ row, $index }"> <template #default="{ row, $index }">
<el-button type="danger" icon="Delete" @click="removeProjectConfig($index)">删除</el-button> <el-button type="danger" icon="Delete" @click="removeProjectConfig($index)">删除</el-button>
<el-button type="primary" icon="Download" @click="downloadProjectPlugin($index)">下载</el-button> <el-button type="primary" icon="Download" @click="downloadProjectPlugin(row,$index)">下载</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
...@@ -85,7 +85,11 @@ ...@@ -85,7 +85,11 @@
import { ref, watch, computed } from 'vue' import { ref, watch, computed } from 'vue'
import { Download, Plus, Delete } from '@element-plus/icons-vue' import { Download, Plus, Delete } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import {
saveProxyJarInfo
} from '@/api/project'
const route = useRoute()
const props = defineProps({ const props = defineProps({
visible: { visible: {
type: Boolean, type: Boolean,
...@@ -119,9 +123,11 @@ const fetchGatewayConfig = async () => { ...@@ -119,9 +123,11 @@ const fetchGatewayConfig = async () => {
// 模拟API调用,实际项目中替换为真实API // 模拟API调用,实际项目中替换为真实API
return new Promise(resolve => { return new Promise(resolve => {
setTimeout(() => { setTimeout(() => {
// let url = import.meta.env.VITE_APP_BASE_API
// const httpList = url.split(':')
resolve({ resolve({
url: 'https://172.19.1.166', url:'',
port: '9005' port:''
}) })
}, 300) }, 300)
}) })
...@@ -129,6 +135,7 @@ const fetchGatewayConfig = async () => { ...@@ -129,6 +135,7 @@ const fetchGatewayConfig = async () => {
// 添加项目配置 // 添加项目配置
const addProjectConfig = () => { const addProjectConfig = () => {
console.log('route',location.origin)
projectConfigs.value.push({ projectConfigs.value.push({
name: '', name: '',
url: '', url: '',
...@@ -143,19 +150,19 @@ const removeProjectConfig = (index) => { ...@@ -143,19 +150,19 @@ const removeProjectConfig = (index) => {
// 下载网关插件 // 下载网关插件
const downloadGatewayPlugin = () => { const downloadGatewayPlugin = () => {
ElMessage.success('开始下载加密网关插件') window.open(gatewayConfig.value.url + `/core/encryptionconfig/download?appProjectName='加密网关平台'&projectid=${props.projectId}&gatewayUrl=${gatewayConfig.value.url}&gatewayPort=${gatewayConfig.value.port}&appUrl=''&appPort=''`)
// 实际项目中实现下载逻辑 // 实际项目中实现下载逻辑
} }
// 下载项目插件 // 下载项目插件
const downloadProjectPlugin = (index) => { const downloadProjectPlugin = (item,index) => {
const project = projectConfigs.value[index] const project = projectConfigs.value[index]
if (!project.name || !project.url || !project.port) { if (!project.name || !project.url || !project.port) {
ElMessage.warning('请先填写完整的项目配置') ElMessage.warning('请先填写完整的项目配置')
return return
} }
ElMessage.success(`开始下载项目 ${project.name} 的插件`)
// 实际项目中实现下载逻辑 window.open(gatewayConfig.value.url + `/core/encryptionconfig/download?appProjectName=${item.name}&projectid=${props.projectId}&gatewayUrl=${gatewayConfig.value.url}&gatewayPort=${gatewayConfig.value.port}&appUrl=${item.url}&appPort=${item.port}`)
} }
// 确认操作 // 确认操作
...@@ -168,11 +175,22 @@ const handleConfirm = () => { ...@@ -168,11 +175,22 @@ const handleConfirm = () => {
} }
} }
emit('confirm', { saveProxyJarInfo('/core/encryptionconfig/saveProxyJarInfo', {
projectId: props.projectId, gatewayUrl: gatewayConfig.value.url,
projectConfigs: projectConfigs.value gatewayPort: gatewayConfig.value.port,
}) projectId: projectId,
dialogVisible.value = false apps: projectConfigs.value.map( item => {
return {
appUrl: item.url,
appProjectName: item.name,
appPort: item.port
}
})
}).then(res => {
ElMessage.success('存储成功!')
dialogVisible.value = false
})
} }
......
<template>
<el-dialog
v-model="dialogVisible"
title="导入"
width="500px"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<div class="import-dialog">
<el-upload
ref="uploadRef"
class="upload-container"
drag
:action="uploadAction"
:headers="headers"
:data="uploadData"
:before-upload="beforeUpload"
:on-success="handleSuccess"
:on-error="handleError"
:on-progress="handleProgress"
:file-list="fileList"
:limit="1"
:auto-upload="true"
:show-file-list="false"
accept=".xlsx,.xls"
>
<div class="upload-content">
<el-icon class="upload-icon"><UploadFilled /></el-icon>
<div class="upload-text">
<p class="upload-title">点击或拖动Excel文件到此处进行上传目录结构</p>
<p class="upload-tip">支持 .xlsx, .xls 格式文件</p>
</div>
</div>
</el-upload>
<!-- 上传进度显示 -->
<div v-if="uploading" class="upload-progress">
<el-progress
:percentage="uploadProgress"
:status="uploadProgress === 100 ? 'success' : ''"
:show-text="false"
/>
<p class="progress-text">上传中... {{ uploadProgress }}%</p>
</div>
</div>
</el-dialog>
</template>
<script setup>
import { ref, computed, watch } from 'vue'
import { getToken, removeToken } from '@/utils/auth'
import { ElMessage } from 'element-plus'
import { UploadFilled } from '@element-plus/icons-vue'
import useAppStore from '@/store/modules/app'
const appStore = useAppStore()
const props = defineProps({
visible: {
type: Boolean,
default: false
},
projectId: {
type: String,
required: true
}
})
const emit = defineEmits(['update:visible', 'success'])
// 控制弹窗显示
const dialogVisible = computed({
get: () => props.visible,
set: (value) => emit('update:visible', value)
})
const uploadRef = ref(null)
const fileList = ref([])
const uploading = ref(false)
const uploadProgress = ref(0)
// 获取token用于请求头
// const token = computed(() => appStore.token)
const headers = ref({ Token: getToken() })
// 上传参数
const uploadData = computed(() => ({
pid: props.projectId
}))
// 上传地址
const uploadAction = computed(() => import.meta.env.VITE_APP_BASE_API + '/core/encryption/excelFileUpLoad')
// 上传前验证
const beforeUpload = (file) => {
const isExcel = file.type === 'application/vnd.ms-excel' ||
file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
file.name.endsWith('.xlsx') ||
file.name.endsWith('.xls')
const isLt10M = file.size / 1024 / 1024 < 10
if (!isExcel) {
ElMessage.error('只能上传Excel文件!')
return false
}
if (!isLt10M) {
ElMessage.error('文件大小不能超过10MB!')
return false
}
// 开始上传
uploading.value = true
uploadProgress.value = 0
return true
}
// 上传成功处理
const handleSuccess = (response, file, fileList) => {
uploading.value = false
uploadProgress.value = 0
if (response && response.flag) {
ElMessage.success('导入成功!')
emit('success', response.data)
// 延迟关闭对话框,让用户看到成功提示
setTimeout(() => {
dialogVisible.value = false
}, 1500)
} else {
ElMessage.error(response?.msg || '导入失败')
uploading.value = false
}
}
// 上传错误处理
const handleError = (error, file, fileList) => {
uploading.value = false
uploadProgress.value = 0
console.error('上传错误:', error)
ElMessage.error('上传失败,请重试')
}
// 上传进度处理
const handleProgress = (event, file, fileList) => {
uploadProgress.value = Math.round(event.percent)
}
// 监听可见性变化,重置状态
watch(() => props.visible, (newVal) => {
if (!newVal) {
// 关闭时重置状态
fileList.value = []
uploading.value = false
uploadProgress.value = 0
} else {
// 打开时确保状态重置
fileList.value = []
uploading.value = false
uploadProgress.value = 0
}
})
// 监听上传完成或失败后自动关闭
watch(uploading, (newVal) => {
if (!newVal && uploadProgress.value === 100) {
// 上传完成,3秒后自动关闭
setTimeout(() => {
if (!uploading.value) {
dialogVisible.value = false
}
}, 3000)
}
})
</script>
<style scoped>
.import-dialog {
padding: 20px;
text-align: center;
}
.upload-container {
width: 100%;
margin-bottom: 20px;
}
.upload-content {
padding: 40px 20px;
text-align: center;
}
.upload-icon {
font-size: 64px;
color: #409EFF;
margin-bottom: 16px;
}
.upload-title {
font-size: 16px;
font-weight: 500;
color: #303133;
margin-bottom: 8px;
line-height: 1.5;
}
.upload-tip {
font-size: 14px;
color: #909399;
margin-top: 8px;
}
.upload-progress {
margin-top: 20px;
padding: 0 20px;
}
.progress-text {
font-size: 14px;
color: #606266;
margin-top: 8px;
text-align: center;
}
:deep(.el-upload-dragger) {
width: 100%;
height: 200px;
padding: 40px 20px;
border: 2px dashed #dcdfe6;
border-radius: 8px;
background-color: #f5f7fa;
transition: all 0.3s ease;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
:deep(.el-upload-dragger:hover) {
border-color: #409EFF;
background-color: #ecf5ff;
}
:deep(.el-dialog__header) {
padding: 20px 20px 10px;
margin-right: 0;
}
:deep(.el-dialog__headerbtn) {
display: none; /* 隐藏关闭按钮 */
}
:deep(.el-dialog__body) {
padding: 0;
}
:deep(.el-progress-bar) {
margin-top: 8px;
}
</style>
\ No newline at end of file
...@@ -165,13 +165,13 @@ ...@@ -165,13 +165,13 @@
<!-- 第四步:数据域选择 --> <!-- 第四步:数据域选择 -->
<div v-if="activeStep === 4"> <div v-if="activeStep === 4">
<div class="step-title">数据域选择</div> <div class="step-title">规则选择</div>
<div class="domain-container"> <div class="domain-container">
<!-- 左侧可选择数据域 --> <!-- 左侧可选择规则 -->
<div class="available-domains"> <div class="available-domains">
<div class="section-header"> <div class="section-header">
<div class="section-title">可选择数据域</div> <div class="section-title">可选择规则</div>
</div> </div>
<div class="domain-group" v-for="group in domainGroups" :key="group.id"> <div class="domain-group" v-for="group in domainGroups" :key="group.id">
...@@ -204,10 +204,10 @@ ...@@ -204,10 +204,10 @@
</div> </div>
<!-- 右侧已选择数据域 --> <!-- 已选择规则 -->
<div class="selected-domains"> <div class="selected-domains">
<div class="section-header"> <div class="section-header">
<div class="section-title">已选择数据域</div> <div class="section-title">已选择规则</div>
<div class="selection-info"> <div class="selection-info">
<span class="count">{{ selectedDomains.length }}</span> <span class="count">{{ selectedDomains.length }}</span>
<el-button type="text" @click="clearSelectedDomains">清空</el-button> <el-button type="text" @click="clearSelectedDomains">清空</el-button>
...@@ -768,12 +768,23 @@ const fetchAllSchemas = async (databases) => { ...@@ -768,12 +768,23 @@ const fetchAllSchemas = async (databases) => {
} }
// 处理数据域和规则数据
const processAreaAndRuleList = (areaAndRuleList) => { const processAreaAndRuleList = (areaAndRuleList) => {
if (!areaAndRuleList || !Array.isArray(areaAndRuleList)) return if (!areaAndRuleList || !Array.isArray(areaAndRuleList)) {
console.warn('areaAndRuleList为空或不是数组', areaAndRuleList)
selectedDomains.value = [] // 确保设置为空数组而不是null或undefined
return
}
// 获取所有数据域分组信息 // 获取所有数据域分组信息
getAllDataAreaAndRule().then(res => { getAllDataAreaAndRule().then(res => {
if (!res.data || !Array.isArray(res.data)) {
console.error('获取的数据域分组无效', res.data)
return
}
console.log('所有数据域分组:', res.data) console.log('所有数据域分组:', res.data)
console.log('接口返回的areaAndRuleList:', areaAndRuleList)
// 处理已选择的数据域 // 处理已选择的数据域
const selectedDomainIds = [] const selectedDomainIds = []
...@@ -781,13 +792,13 @@ const processAreaAndRuleList = (areaAndRuleList) => { ...@@ -781,13 +792,13 @@ const processAreaAndRuleList = (areaAndRuleList) => {
// 将接口返回的数据映射到 domainGroups // 将接口返回的数据映射到 domainGroups
domainGroups.value = res.data.map(group => { domainGroups.value = res.data.map(group => {
// 处理组内的每个规则 // 处理组内的每个规则
const processedList = group.list.map(domain => { const processedList = (group.list || []).map(domain => {
// 检查这个规则是否在已选择的列表中 // 检查这个规则是否在已选择的列表中
const isSelected = areaAndRuleList.some(item => const isSelected = areaAndRuleList.some(item =>
item.dataarea_id === group.dataarea_id && item.rule_id === domain.id item && item.dataarea_id === group.dataarea_id && item.rule_id === domain.id
) )
if (isSelected) { if (isSelected && domain.id) {
selectedDomainIds.push(domain.id) selectedDomainIds.push(domain.id)
} }
...@@ -798,7 +809,7 @@ const processAreaAndRuleList = (areaAndRuleList) => { ...@@ -798,7 +809,7 @@ const processAreaAndRuleList = (areaAndRuleList) => {
}) })
// 检查是否全选 // 检查是否全选
const groupDomainIds = processedList.map(d => d.id) const groupDomainIds = processedList.map(d => d.id).filter(Boolean)
const selectedInGroup = selectedDomainIds.filter(id => groupDomainIds.includes(id)) const selectedInGroup = selectedDomainIds.filter(id => groupDomainIds.includes(id))
group.selectedAll = selectedInGroup.length === groupDomainIds.length && groupDomainIds.length > 0 group.selectedAll = selectedInGroup.length === groupDomainIds.length && groupDomainIds.length > 0
...@@ -809,8 +820,16 @@ const processAreaAndRuleList = (areaAndRuleList) => { ...@@ -809,8 +820,16 @@ const processAreaAndRuleList = (areaAndRuleList) => {
}) })
// 设置已选择的数据域 // 设置已选择的数据域
selectedDomains.value = selectedDomainIds selectedDomains.value = selectedDomainIds.filter(Boolean) // 过滤掉可能的空值
console.log('已选择的数据域ID:', selectedDomains.value) console.log('已选择的数据域ID:', selectedDomains.value)
// 如果没有选择任何数据域,显示警告
if (selectedDomains.value.length === 0) {
console.warn('没有找到任何已选择的数据域,请检查数据映射逻辑')
}
}).catch(error => {
console.error('获取数据域分组失败:', error)
ElMessage.error('获取数据域分组失败')
}) })
} }
// 处理Schema数据 // 处理Schema数据
......
...@@ -4,6 +4,7 @@ import { ElMessage,ElMessageBox } from 'element-plus' ...@@ -4,6 +4,7 @@ import { ElMessage,ElMessageBox } from 'element-plus'
import QueryForm from './QueryForm.vue' import QueryForm from './QueryForm.vue'
import ProjectEditDialog from './ProjectEditDialog.vue' import ProjectEditDialog from './ProjectEditDialog.vue'
import DownloadPluginDialog from './DownloadPluginDialog.vue' import DownloadPluginDialog from './DownloadPluginDialog.vue'
import ImportProjectDialog from './ImportProjectDialog.vue'
import ExportDialog from './ExportDialog.vue' import ExportDialog from './ExportDialog.vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import {changeRoute} from '@/utils/switchRoute' import {changeRoute} from '@/utils/switchRoute'
...@@ -12,7 +13,8 @@ import { ...@@ -12,7 +13,8 @@ import {
checkProjectNum, checkProjectNum,
addDataProject, addDataProject,
deleteDataProject, deleteDataProject,
updateDataProject updateDataProject,
showProxyInfo
} from '@/api/project' } from '@/api/project'
import useAppStore from '@/store/modules/app' import useAppStore from '@/store/modules/app'
...@@ -198,7 +200,9 @@ const handleCommandProject = (command, project) => { ...@@ -198,7 +200,9 @@ const handleCommandProject = (command, project) => {
console.warn('未知命令:', command) console.warn('未知命令:', command)
} }
} }
// 添加导入相关变量
const importDialogVisible = ref(false)
const currentImportProjectId = ref('')
// 具体操作方法 // 具体操作方法
const handleEnterProject = (project) => { const handleEnterProject = (project) => {
console.log('进入项目:', project) console.log('进入项目:', project)
...@@ -254,8 +258,18 @@ const handleDeleteProject = (val) => { ...@@ -254,8 +258,18 @@ const handleDeleteProject = (val) => {
// 导入项目 // 导入项目
const handleImportProject = (project) => { const handleImportProject = (project) => {
ElMessage.info('导入功能待实现') currentImportProjectId.value = project.id
importDialogVisible.value = true
} }
const handleImportSuccess = (data) => {
// ElMessage.success('项目导入成功')
// 刷新项目列表
handleQuery()
}
// 导出项目 // 导出项目
const handleExportProject = (project) => { const handleExportProject = (project) => {
// ElMessage.success(`开始导出项目 "${project.proName}"`) // ElMessage.success(`开始导出项目 "${project.proName}"`)
...@@ -265,7 +279,24 @@ const handleExportProject = (project) => { ...@@ -265,7 +279,24 @@ const handleExportProject = (project) => {
const handleDownloadPlugin = (project) => { const handleDownloadPlugin = (project) => {
// ElMessage.success(`开始下载 "${project.proName}" 的插件`) // ElMessage.success(`开始下载 "${project.proName}" 的插件`)
currentProjectId.value = project.id // 假设项目对象中有id字段 currentProjectId.value = project.id // 假设项目对象中有id字段
downloadDialogVisible.value = true
showProxyInfo({
projectId:project.id
}).then(res=>{
if(res.flag){
downloadDialogVisible.value = true
}else{
ElMessage.info(res.msg)
}
}).catch(err=>{
ElMessage.info(res.msg)
})
console.log(123) console.log(123)
} }
// 处理确认操作 // 处理确认操作
...@@ -313,11 +344,14 @@ const handleSubmit = (formData) => { ...@@ -313,11 +344,14 @@ const handleSubmit = (formData) => {
loginUser:loginUser, loginUser:loginUser,
project:{ project:{
createtime:currentProject.value.createtime,
createuser:currentProject.value.createuser,
edition_id: '', edition_id: '',
note: formData.remark, note: formData.remark,
project: formData.name, project: formData.name,
id:formData.id, id:formData.id,
projectType: "normal", flag:null,
projectType: "normal"
}, },
schemalist:formData.schemas, schemalist:formData.schemas,
...@@ -353,7 +387,9 @@ const exportDialogVisible = ref(false) ...@@ -353,7 +387,9 @@ const exportDialogVisible = ref(false)
const currentExportProjectId = ref('') const currentExportProjectId = ref('')
// 打开导出弹窗 // 打开导出弹窗
const exportProjectName = ref('')
const openExportDialog = (project) => { const openExportDialog = (project) => {
exportProjectName.value = project.project
currentExportProjectId.value = project.id currentExportProjectId.value = project.id
exportDialogVisible.value = true exportDialogVisible.value = true
} }
...@@ -457,10 +493,17 @@ onMounted(()=>{ ...@@ -457,10 +493,17 @@ onMounted(()=>{
<ExportDialog <ExportDialog
v-model:visible="exportDialogVisible" v-model:visible="exportDialogVisible"
:exportProjectName="exportProjectName"
:project-id="currentExportProjectId" :project-id="currentExportProjectId"
@confirm="handleExportConfirm" @confirm="handleExportConfirm"
@backup="handleBackup" @backup="handleBackup"
/> />
<ImportProjectDialog
v-model:visible="importDialogVisible"
:project-id="currentImportProjectId"
@success="handleImportSuccess"
/>
</div> </div>
</template> </template>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论