feat(version): 添加字典数据支持到版本管理功能
This commit is contained in:
@@ -267,6 +267,17 @@ func (sysVersionApi *SysVersionApi) ExportVersion(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// 获取选中的字典数据
|
||||
var dictData []system.SysDictionary
|
||||
if len(req.DictIds) > 0 {
|
||||
dictData, err = sysVersionService.GetDictionariesByIds(ctx, req.DictIds)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取字典数据失败!", zap.Error(err))
|
||||
response.FailWithMessage("获取字典数据失败:"+err.Error(), c)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 处理菜单数据,构建递归的children结构
|
||||
processedMenus := buildMenuTree(menuData)
|
||||
|
||||
@@ -282,6 +293,34 @@ func (sysVersionApi *SysVersionApi) ExportVersion(c *gin.Context) {
|
||||
processedApis = append(processedApis, cleanApi)
|
||||
}
|
||||
|
||||
// 处理字典数据,清除ID和时间戳字段,包含字典详情
|
||||
processedDicts := make([]system.SysDictionary, 0, len(dictData))
|
||||
for _, dict := range dictData {
|
||||
cleanDict := system.SysDictionary{
|
||||
Name: dict.Name,
|
||||
Type: dict.Type,
|
||||
Status: dict.Status,
|
||||
Desc: dict.Desc,
|
||||
}
|
||||
|
||||
// 处理字典详情数据,清除ID和时间戳字段
|
||||
cleanDetails := make([]system.SysDictionaryDetail, 0, len(dict.SysDictionaryDetails))
|
||||
for _, detail := range dict.SysDictionaryDetails {
|
||||
cleanDetail := system.SysDictionaryDetail{
|
||||
Label: detail.Label,
|
||||
Value: detail.Value,
|
||||
Extend: detail.Extend,
|
||||
Status: detail.Status,
|
||||
Sort: detail.Sort,
|
||||
// 不复制 ID, CreatedAt, UpdatedAt, SysDictionaryID
|
||||
}
|
||||
cleanDetails = append(cleanDetails, cleanDetail)
|
||||
}
|
||||
cleanDict.SysDictionaryDetails = cleanDetails
|
||||
|
||||
processedDicts = append(processedDicts, cleanDict)
|
||||
}
|
||||
|
||||
// 构建导出数据
|
||||
exportData := systemRes.ExportVersionResponse{
|
||||
Version: systemReq.VersionInfo{
|
||||
@@ -290,8 +329,9 @@ func (sysVersionApi *SysVersionApi) ExportVersion(c *gin.Context) {
|
||||
Description: req.Description,
|
||||
ExportTime: time.Now().Format("2006-01-02 15:04:05"),
|
||||
},
|
||||
Menus: processedMenus,
|
||||
Apis: processedApis,
|
||||
Menus: processedMenus,
|
||||
Apis: processedApis,
|
||||
Dictionaries: processedDicts,
|
||||
}
|
||||
|
||||
// 转换为JSON
|
||||
@@ -418,6 +458,15 @@ func (sysVersionApi *SysVersionApi) ImportVersion(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// 导入字典数据
|
||||
if len(importData.ExportDictionary) > 0 {
|
||||
if err := sysVersionService.ImportDictionaries(importData.ExportDictionary); err != nil {
|
||||
global.GVA_LOG.Error("导入字典失败!", zap.Error(err))
|
||||
response.FailWithMessage("导入字典失败: "+err.Error(), c)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 创建导入记录
|
||||
jsonData, _ := json.Marshal(importData)
|
||||
version := system.SysVersion{
|
||||
|
||||
@@ -20,13 +20,15 @@ type ExportVersionRequest struct {
|
||||
Description string `json:"description"` // 版本描述
|
||||
MenuIds []uint `json:"menuIds"` // 选中的菜单ID列表
|
||||
ApiIds []uint `json:"apiIds"` // 选中的API ID列表
|
||||
DictIds []uint `json:"dictIds"` // 选中的字典ID列表
|
||||
}
|
||||
|
||||
// ImportVersionRequest 导入版本请求结构体
|
||||
type ImportVersionRequest struct {
|
||||
VersionInfo VersionInfo `json:"version" binding:"required"` // 版本信息
|
||||
ExportMenu []system.SysBaseMenu `json:"menus"` // 菜单数据,直接复用SysBaseMenu
|
||||
ExportApi []system.SysApi `json:"apis"` // API数据,直接复用SysApi
|
||||
VersionInfo VersionInfo `json:"version" binding:"required"` // 版本信息
|
||||
ExportMenu []system.SysBaseMenu `json:"menus"` // 菜单数据,直接复用SysBaseMenu
|
||||
ExportApi []system.SysApi `json:"apis"` // API数据,直接复用SysApi
|
||||
ExportDictionary []system.SysDictionary `json:"dictionaries"` // 字典数据,直接复用SysDictionary
|
||||
}
|
||||
|
||||
// VersionInfo 版本信息结构体
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
|
||||
// ExportVersionResponse 导出版本响应结构体
|
||||
type ExportVersionResponse struct {
|
||||
Version request.VersionInfo `json:"version"` // 版本信息
|
||||
Menus []system.SysBaseMenu `json:"menus"` // 菜单数据,直接复用SysBaseMenu
|
||||
Apis []system.SysApi `json:"apis"` // API数据,直接复用SysApi
|
||||
}
|
||||
Version request.VersionInfo `json:"version"` // 版本信息
|
||||
Menus []system.SysBaseMenu `json:"menus"` // 菜单数据,直接复用SysBaseMenu
|
||||
Apis []system.SysApi `json:"apis"` // API数据,直接复用SysApi
|
||||
Dictionaries []system.SysDictionary `json:"dictionaries"` // 字典数据,直接复用SysDictionary
|
||||
}
|
||||
|
||||
@@ -86,6 +86,12 @@ func (sysVersionService *SysVersionService) GetApisByIds(ctx context.Context, id
|
||||
return
|
||||
}
|
||||
|
||||
// GetDictionariesByIds 根据ID列表获取字典数据
|
||||
func (sysVersionService *SysVersionService) GetDictionariesByIds(ctx context.Context, ids []uint) (dictionaries []system.SysDictionary, err error) {
|
||||
err = global.GVA_DB.Where("id in ?", ids).Preload("SysDictionaryDetails").Find(&dictionaries).Error
|
||||
return
|
||||
}
|
||||
|
||||
// ImportMenus 导入菜单数据
|
||||
func (sysVersionService *SysVersionService) ImportMenus(ctx context.Context, menus []system.SysBaseMenu) error {
|
||||
return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
|
||||
@@ -194,3 +200,31 @@ func (sysVersionService *SysVersionService) ImportApis(apis []system.SysApi) err
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// ImportDictionaries 导入字典数据
|
||||
func (sysVersionService *SysVersionService) ImportDictionaries(dictionaries []system.SysDictionary) error {
|
||||
return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
|
||||
for _, dict := range dictionaries {
|
||||
// 检查字典是否已存在
|
||||
var existingDict system.SysDictionary
|
||||
if err := tx.Where("type = ?", dict.Type).First(&existingDict).Error; err == nil {
|
||||
// 字典已存在,跳过
|
||||
continue
|
||||
}
|
||||
|
||||
// 创建新字典
|
||||
newDict := system.SysDictionary{
|
||||
Name: dict.Name,
|
||||
Type: dict.Type,
|
||||
Status: dict.Status,
|
||||
Desc: dict.Desc,
|
||||
SysDictionaryDetails: dict.SysDictionaryDetails,
|
||||
}
|
||||
|
||||
if err := tx.Create(&newDict).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ func (i *initDictDetail) InitializeData(ctx context.Context) (context.Context, e
|
||||
}
|
||||
|
||||
dicts[2].SysDictionaryDetails = []sysModel.SysDictionaryDetail{
|
||||
{Label: "date", Status: &True},
|
||||
{Label: "date", Value: "0", Status: &True, Extend: "mysql", Sort: 0},
|
||||
{Label: "time", Value: "1", Status: &True, Extend: "mysql", Sort: 1},
|
||||
{Label: "year", Value: "2", Status: &True, Extend: "mysql", Sort: 2},
|
||||
{Label: "datetime", Value: "3", Status: &True, Extend: "mysql", Sort: 3},
|
||||
@@ -74,7 +74,7 @@ func (i *initDictDetail) InitializeData(ctx context.Context) (context.Context, e
|
||||
{Label: "timestamptz", Value: "6", Status: &True, Extend: "pgsql", Sort: 5},
|
||||
}
|
||||
dicts[3].SysDictionaryDetails = []sysModel.SysDictionaryDetail{
|
||||
{Label: "float", Status: &True},
|
||||
{Label: "float", Value: "0", Status: &True, Extend: "mysql", Sort: 0},
|
||||
{Label: "double", Value: "1", Status: &True, Extend: "mysql", Sort: 1},
|
||||
{Label: "decimal", Value: "2", Status: &True, Extend: "mysql", Sort: 2},
|
||||
{Label: "numeric", Value: "3", Status: &True, Extend: "pgsql", Sort: 3},
|
||||
@@ -82,7 +82,7 @@ func (i *initDictDetail) InitializeData(ctx context.Context) (context.Context, e
|
||||
}
|
||||
|
||||
dicts[4].SysDictionaryDetails = []sysModel.SysDictionaryDetail{
|
||||
{Label: "char", Status: &True},
|
||||
{Label: "char", Value: "0", Status: &True, Extend: "mysql", Sort: 0},
|
||||
{Label: "varchar", Value: "1", Status: &True, Extend: "mysql", Sort: 1},
|
||||
{Label: "tinyblob", Value: "2", Status: &True, Extend: "mysql", Sort: 2},
|
||||
{Label: "tinytext", Value: "3", Status: &True, Extend: "mysql", Sort: 3},
|
||||
|
||||
@@ -117,9 +117,9 @@
|
||||
<el-input v-model="exportForm.description" type="textarea" placeholder="请输入版本描述" />
|
||||
</el-form-item>
|
||||
<el-form-item label="发版信息">
|
||||
<div class="flex gap-5 w-full">
|
||||
<div class="flex gap-3 w-full">
|
||||
<!-- 菜单选择 -->
|
||||
<div class="flex flex-col border border-gray-300 rounded overflow-hidden h-full flex-1 w-1/2">
|
||||
<div class="flex flex-col border border-gray-300 rounded overflow-hidden h-full flex-1 w-1/3">
|
||||
<div class="flex justify-between items-center px-4 py-3 bg-gray-50 border-b border-gray-300">
|
||||
<span class="m-0 text-gray-800 text-base font-medium">选择菜单</span>
|
||||
</div>
|
||||
@@ -140,7 +140,7 @@
|
||||
</div>
|
||||
|
||||
<!-- API选择 -->
|
||||
<div class="flex flex-col border border-gray-300 rounded overflow-hidden h-full flex-1 w-1/2">
|
||||
<div class="flex flex-col border border-gray-300 rounded overflow-hidden h-full flex-1 w-1/3">
|
||||
<div class="flex justify-between items-center px-4 py-3 bg-gray-50 border-b border-gray-300">
|
||||
<span class="m-0 text-gray-800 text-base font-medium">选择API</span>
|
||||
</div>
|
||||
@@ -153,7 +153,7 @@
|
||||
<el-tree ref="apiTreeRef" :data="apiTreeData" :default-checked-keys="selectedApiIds"
|
||||
:props="apiTreeProps" default-expand-all highlight-current node-key="onlyId" show-checkbox
|
||||
:filter-node-method="filterApiNode" @check="onApiCheck" class="api-tree">
|
||||
<template #default="{ _, data }">
|
||||
<template #default="{ data }">
|
||||
<div class="flex items-center justify-between w-full pr-1">
|
||||
<span>{{ data.description }}</span>
|
||||
<el-tooltip :content="data.path">
|
||||
@@ -166,6 +166,32 @@
|
||||
</el-tree>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 字典选择 -->
|
||||
<div class="flex flex-col border border-gray-300 rounded overflow-hidden h-full flex-1 w-1/3">
|
||||
<div class="flex justify-between items-center px-4 py-3 bg-gray-50 border-b border-gray-300">
|
||||
<span class="m-0 text-gray-800 text-base font-medium">选择字典</span>
|
||||
</div>
|
||||
<div class="px-4 py-3 border-b border-gray-300 bg-gray-50">
|
||||
<el-input v-model="dictFilterText" placeholder="输入关键字进行过滤" clearable size="small" />
|
||||
</div>
|
||||
<div class="flex-1 p-2 min-h-[300px] max-h-[400px] overflow-y-auto">
|
||||
<el-tree ref="dictTreeRef" :data="dictTreeData" :default-checked-keys="selectedDictIds"
|
||||
:props="dictTreeProps" default-expand-all highlight-current node-key="ID" show-checkbox
|
||||
:filter-node-method="filterDictNode" @check="onDictCheck" class="dict-tree">
|
||||
<template #default="{ data }">
|
||||
<div class="flex items-center justify-between w-full pr-1">
|
||||
<span>{{ data.name || data.label }}</span>
|
||||
<el-tooltip :content="data.desc || (data.value ? `值: ${data.value}` : '')">
|
||||
<span class="text-gray-500 text-xs ml-2">
|
||||
{{ data.type || (data.value ? `值: ${data.value}` : '') }}
|
||||
</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
</el-tree>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -212,8 +238,8 @@
|
||||
</el-form-item>
|
||||
<el-form-item label="预览内容" v-if="importPreviewData">
|
||||
<div class="flex flex-col flex-1 gap-4 border border-gray-300 rounded p-4 bg-gray-50">
|
||||
<div class="flex gap-5 w-full">
|
||||
<div class="border border-gray-300 rounded overflow-hidden flex-1 w-1/2">
|
||||
<div class="flex gap-3 w-full">
|
||||
<div class="border border-gray-300 rounded overflow-hidden flex-1 w-1/3">
|
||||
<div class="flex flex-col border border-gray-300 rounded overflow-hidden h-full">
|
||||
<div class="flex justify-between items-center px-4 py-3 bg-gray-50 border-b border-gray-300">
|
||||
<h3 class="m-0 text-gray-800 text-base font-medium">菜单 ({{ getTotalMenuCount() }}项)</h3>
|
||||
@@ -238,7 +264,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border border-gray-300 rounded overflow-hidden flex-1 w-1/2">
|
||||
<div class="border border-gray-300 rounded overflow-hidden flex-1 w-1/3">
|
||||
<div class="flex flex-col border border-gray-300 rounded overflow-hidden h-full">
|
||||
<div class="flex justify-between items-center px-4 py-3 bg-gray-50 border-b border-gray-300">
|
||||
<h3 class="m-0 text-gray-800 text-base font-medium">API ({{ importPreviewData.apis?.length || 0 }}项)</h3>
|
||||
@@ -263,6 +289,33 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border border-gray-300 rounded overflow-hidden flex-1 w-1/3">
|
||||
<div class="flex flex-col border border-gray-300 rounded overflow-hidden h-full">
|
||||
<div class="flex justify-between items-center px-4 py-3 bg-gray-50 border-b border-gray-300">
|
||||
<h3 class="m-0 text-gray-800 text-base font-medium">字典 ({{ importPreviewData.dictionaries?.length || 0 }}项)</h3>
|
||||
</div>
|
||||
<div class="flex-1 p-2 min-h-[300px] max-h-[400px] overflow-y-auto">
|
||||
<el-tree
|
||||
:data="previewDictTreeData"
|
||||
:props="dictTreeProps"
|
||||
node-key="ID"
|
||||
:expand-on-click-node="false"
|
||||
:check-on-click-node="false"
|
||||
:show-checkbox="false"
|
||||
default-expand-all
|
||||
>
|
||||
<template #default="{ data }">
|
||||
<div class="flex-1 flex items-center justify-between text-sm pr-2">
|
||||
<span>{{ data.name || data.label }}</span>
|
||||
<span class="text-gray-500 text-xs ml-2">
|
||||
{{ data.type || (data.value ? `值: ${data.value}` : '') }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-tree>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
@@ -286,14 +339,13 @@ import {
|
||||
// 导入菜单和API相关接口
|
||||
import { getMenuList } from '@/api/menu'
|
||||
import { getApiList } from '@/api/api'
|
||||
import { getSysDictionaryList } from '@/api/sysDictionary'
|
||||
|
||||
// 全量引入格式化工具 请按需保留
|
||||
import { getDictFunc, formatDate, filterDict } from '@/utils/format'
|
||||
import { formatDate } from '@/utils/format'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { UploadFilled } from '@element-plus/icons-vue'
|
||||
import { ref, reactive, watch } from 'vue'
|
||||
// 引入按钮权限标识
|
||||
import { useBtnAuth } from '@/utils/btnAuth'
|
||||
import { ref, watch } from 'vue'
|
||||
import { useAppStore } from "@/pinia"
|
||||
|
||||
defineOptions({
|
||||
@@ -313,21 +365,26 @@ const exportForm = ref({
|
||||
versionCode: '',
|
||||
description: '',
|
||||
menuIds: [],
|
||||
apiIds: []
|
||||
apiIds: [],
|
||||
dictIds: []
|
||||
})
|
||||
|
||||
// 树形结构相关数据
|
||||
const menuTreeData = ref([])
|
||||
const apiTreeData = ref([])
|
||||
const dictTreeData = ref([])
|
||||
const selectedMenuIds = ref([])
|
||||
const selectedApiIds = ref([])
|
||||
const selectedDictIds = ref([])
|
||||
const menuFilterText = ref('')
|
||||
const apiFilterTextName = ref('')
|
||||
const apiFilterTextPath = ref('')
|
||||
const dictFilterText = ref('')
|
||||
|
||||
// 树形组件引用
|
||||
const menuTreeRef = ref(null)
|
||||
const apiTreeRef = ref(null)
|
||||
const dictTreeRef = ref(null)
|
||||
|
||||
// 树形属性配置
|
||||
const menuTreeProps = ref({
|
||||
@@ -342,6 +399,21 @@ const apiTreeProps = ref({
|
||||
label: 'description'
|
||||
})
|
||||
|
||||
const dictTreeProps = ref({
|
||||
children: 'sysDictionaryDetails',
|
||||
label: function (data) {
|
||||
// 如果是字典主项,显示字典名称
|
||||
if (data.name) {
|
||||
return data.name
|
||||
}
|
||||
// 如果是字典详情项,显示标签
|
||||
if (data.label) {
|
||||
return data.label
|
||||
}
|
||||
return '未知项'
|
||||
}
|
||||
})
|
||||
|
||||
// 导入相关数据
|
||||
const importDialogVisible = ref(false)
|
||||
const importLoading = ref(false)
|
||||
@@ -350,36 +422,10 @@ const importPreviewData = ref(null)
|
||||
const uploadRef = ref(null)
|
||||
const previewMenuTreeData = ref([])
|
||||
const previewApiTreeData = ref([])
|
||||
const previewDictTreeData = ref([])
|
||||
|
||||
|
||||
|
||||
// 验证规则
|
||||
const rule = reactive({
|
||||
versionName: [{
|
||||
required: true,
|
||||
message: '请输入版本名称',
|
||||
trigger: ['input', 'blur'],
|
||||
},
|
||||
{
|
||||
whitespace: true,
|
||||
message: '不能只输入空格',
|
||||
trigger: ['input', 'blur'],
|
||||
}
|
||||
],
|
||||
versionCode: [{
|
||||
required: true,
|
||||
message: '请输入版本号',
|
||||
trigger: ['input', 'blur'],
|
||||
},
|
||||
{
|
||||
whitespace: true,
|
||||
message: '不能只输入空格',
|
||||
trigger: ['input', 'blur'],
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const elFormRef = ref()
|
||||
const elSearchFormRef = ref()
|
||||
|
||||
// =========== 表格控制部分 ===========
|
||||
@@ -549,6 +595,19 @@ const getMenuAndApiList = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 获取字典列表
|
||||
const getDictList = async () => {
|
||||
try {
|
||||
const dictRes = await getSysDictionaryList({ page: 1, pageSize: 9999 })
|
||||
if (dictRes.code === 0) {
|
||||
dictTreeData.value = dictRes.data || []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取字典数据失败:', error)
|
||||
ElMessage.error('获取字典数据失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 构建API树形结构
|
||||
const buildApiTree = (apis) => {
|
||||
const apiObj = {}
|
||||
@@ -595,6 +654,20 @@ const filterApiNode = (value, data) => {
|
||||
return matchesName && matchesPath
|
||||
}
|
||||
|
||||
const filterDictNode = (value, data) => {
|
||||
if (!value) return true
|
||||
const name = data.name || ''
|
||||
const type = data.type || ''
|
||||
const desc = data.desc || ''
|
||||
const label = data.label || ''
|
||||
const dataValue = data.value || ''
|
||||
return name.indexOf(value) !== -1 ||
|
||||
type.indexOf(value) !== -1 ||
|
||||
desc.indexOf(value) !== -1 ||
|
||||
label.indexOf(value) !== -1 ||
|
||||
dataValue.indexOf(value) !== -1
|
||||
}
|
||||
|
||||
const onMenuCheck = (data, checked) => {
|
||||
if (checked.checkedKeys) {
|
||||
selectedMenuIds.value = checked.checkedKeys
|
||||
@@ -607,6 +680,12 @@ const onApiCheck = (data, checked) => {
|
||||
}
|
||||
}
|
||||
|
||||
const onDictCheck = (data, checked) => {
|
||||
if (checked.checkedKeys) {
|
||||
selectedDictIds.value = checked.checkedKeys
|
||||
}
|
||||
}
|
||||
|
||||
// 监听过滤文本变化
|
||||
watch(menuFilterText, (val) => {
|
||||
if (menuTreeRef.value) {
|
||||
@@ -620,10 +699,17 @@ watch([apiFilterTextName, apiFilterTextPath], () => {
|
||||
}
|
||||
})
|
||||
|
||||
watch(dictFilterText, (val) => {
|
||||
if (dictTreeRef.value) {
|
||||
dictTreeRef.value.filter(val)
|
||||
}
|
||||
})
|
||||
|
||||
// 导出相关方法
|
||||
const openExportDialog = async () => {
|
||||
exportDialogVisible.value = true
|
||||
await getMenuAndApiList()
|
||||
await getDictList()
|
||||
}
|
||||
|
||||
const closeExportDialog = () => {
|
||||
@@ -633,13 +719,16 @@ const closeExportDialog = () => {
|
||||
versionCode: '',
|
||||
description: '',
|
||||
menuIds: [],
|
||||
apiIds: []
|
||||
apiIds: [],
|
||||
dictIds: []
|
||||
}
|
||||
selectedMenuIds.value = []
|
||||
selectedApiIds.value = []
|
||||
selectedDictIds.value = []
|
||||
menuFilterText.value = ''
|
||||
apiFilterTextName.value = ''
|
||||
apiFilterTextPath.value = ''
|
||||
dictFilterText.value = ''
|
||||
}
|
||||
|
||||
const handleExport = async () => {
|
||||
@@ -650,15 +739,18 @@ const handleExport = async () => {
|
||||
|
||||
exportLoading.value = true
|
||||
try {
|
||||
// 获取选中的菜单和API
|
||||
// 获取选中的菜单、API和字典
|
||||
const checkedMenus = menuTreeRef.value ? menuTreeRef.value.getCheckedNodes(false, true) : []
|
||||
const checkedApis = apiTreeRef.value ? apiTreeRef.value.getCheckedNodes(true) : []
|
||||
const checkedDicts = dictTreeRef.value ? dictTreeRef.value.getCheckedNodes(true) : []
|
||||
|
||||
const menuIds = checkedMenus.map(menu => menu.ID)
|
||||
const apiIds = checkedApis.map(api => api.ID)
|
||||
const dictIds = checkedDicts.map(dict => dict.ID)
|
||||
|
||||
exportForm.value.menuIds = menuIds
|
||||
exportForm.value.apiIds = apiIds
|
||||
exportForm.value.dictIds = dictIds
|
||||
|
||||
const res = await exportVersion(exportForm.value)
|
||||
if (res.code !== 0) {
|
||||
@@ -748,29 +840,14 @@ const getTotalMenuCount = () => {
|
||||
return countMenus(importPreviewData.value.menus)
|
||||
}
|
||||
|
||||
// 构建树形结构的辅助函数
|
||||
const buildTreeData = (data, parentId = 0) => {
|
||||
const tree = []
|
||||
// 处理parentId可能为字符串"0"或数字0的情况
|
||||
const targetParentId = parentId === 0 ? [0, "0"] : [parentId]
|
||||
const items = data.filter(item => targetParentId.includes(item.parentId))
|
||||
|
||||
items.forEach(item => {
|
||||
const children = buildTreeData(data, item.ID)
|
||||
if (children.length > 0) {
|
||||
item.children = children
|
||||
}
|
||||
tree.push(item)
|
||||
})
|
||||
|
||||
return tree
|
||||
}
|
||||
|
||||
|
||||
const handleJsonContentChange = () => {
|
||||
if (!importJsonContent.value.trim()) {
|
||||
importPreviewData.value = null
|
||||
previewMenuTreeData.value = []
|
||||
previewApiTreeData.value = []
|
||||
previewDictTreeData.value = []
|
||||
return
|
||||
}
|
||||
|
||||
@@ -780,7 +857,8 @@ const handleJsonContentChange = () => {
|
||||
// 构建预览数据
|
||||
importPreviewData.value = {
|
||||
menus: data.menus || [],
|
||||
apis: data.apis || []
|
||||
apis: data.apis || [],
|
||||
dictionaries: data.dictionaries || []
|
||||
}
|
||||
|
||||
// 直接使用菜单数据,因为它已经是树形结构(包含children字段)
|
||||
@@ -810,11 +888,19 @@ const handleJsonContentChange = () => {
|
||||
} else {
|
||||
previewApiTreeData.value = []
|
||||
}
|
||||
|
||||
// 处理字典数据
|
||||
if (data.dictionaries && data.dictionaries.length > 0) {
|
||||
previewDictTreeData.value = data.dictionaries
|
||||
} else {
|
||||
previewDictTreeData.value = []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('JSON解析失败:', error)
|
||||
importPreviewData.value = null
|
||||
previewMenuTreeData.value = []
|
||||
previewApiTreeData.value = []
|
||||
previewDictTreeData.value = []
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user