Skip to content

Commit a1f18e1

Browse files
author
piexlMax(奇淼
committed
feat: 增加字典的json导出和导入
1 parent c028ea3 commit a1f18e1

File tree

7 files changed

+477
-5
lines changed

7 files changed

+477
-5
lines changed

server/api/v1/system/sys_dictionary.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,57 @@ func (s *DictionaryApi) GetSysDictionaryList(c *gin.Context) {
135135
}
136136
response.OkWithDetailed(list, "获取成功", c)
137137
}
138+
139+
// ExportSysDictionary
140+
// @Tags SysDictionary
141+
// @Summary 导出字典JSON(包含字典详情)
142+
// @Security ApiKeyAuth
143+
// @accept application/json
144+
// @Produce application/json
145+
// @Param data query system.SysDictionary true "字典ID"
146+
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "导出字典JSON"
147+
// @Router /sysDictionary/exportSysDictionary [get]
148+
func (s *DictionaryApi) ExportSysDictionary(c *gin.Context) {
149+
var dictionary system.SysDictionary
150+
err := c.ShouldBindQuery(&dictionary)
151+
if err != nil {
152+
response.FailWithMessage(err.Error(), c)
153+
return
154+
}
155+
if dictionary.ID == 0 {
156+
response.FailWithMessage("字典ID不能为空", c)
157+
return
158+
}
159+
exportData, err := dictionaryService.ExportSysDictionary(dictionary.ID)
160+
if err != nil {
161+
global.GVA_LOG.Error("导出失败!", zap.Error(err))
162+
response.FailWithMessage("导出失败", c)
163+
return
164+
}
165+
response.OkWithDetailed(exportData, "导出成功", c)
166+
}
167+
168+
// ImportSysDictionary
169+
// @Tags SysDictionary
170+
// @Summary 导入字典JSON(包含字典详情)
171+
// @Security ApiKeyAuth
172+
// @accept application/json
173+
// @Produce application/json
174+
// @Param data body map[string]interface{} true "字典JSON数据"
175+
// @Success 200 {object} response.Response{msg=string} "导入字典"
176+
// @Router /sysDictionary/importSysDictionary [post]
177+
func (s *DictionaryApi) ImportSysDictionary(c *gin.Context) {
178+
var importData map[string]interface{}
179+
err := c.ShouldBindJSON(&importData)
180+
if err != nil {
181+
response.FailWithMessage(err.Error(), c)
182+
return
183+
}
184+
err = dictionaryService.ImportSysDictionary(importData)
185+
if err != nil {
186+
global.GVA_LOG.Error("导入失败!", zap.Error(err))
187+
response.FailWithMessage("导入失败: "+err.Error(), c)
188+
return
189+
}
190+
response.OkWithMessage("导入成功", c)
191+
}

server/router/system/sys_dictionary.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ func (s *DictionaryRouter) InitSysDictionaryRouter(Router *gin.RouterGroup) {
1414
sysDictionaryRouter.POST("createSysDictionary", dictionaryApi.CreateSysDictionary) // 新建SysDictionary
1515
sysDictionaryRouter.DELETE("deleteSysDictionary", dictionaryApi.DeleteSysDictionary) // 删除SysDictionary
1616
sysDictionaryRouter.PUT("updateSysDictionary", dictionaryApi.UpdateSysDictionary) // 更新SysDictionary
17+
sysDictionaryRouter.POST("importSysDictionary", dictionaryApi.ImportSysDictionary) // 导入SysDictionary
18+
sysDictionaryRouter.GET("exportSysDictionary", dictionaryApi.ExportSysDictionary) // 导出SysDictionary
1719
}
1820
{
1921
sysDictionaryRouterWithoutRecord.GET("findSysDictionary", dictionaryApi.FindSysDictionary) // 根据ID获取SysDictionary

server/service/system/sys_dictionary.go

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,166 @@ func (dictionaryService *DictionaryService) checkCircularReference(currentID uin
152152

153153
return nil
154154
}
155+
156+
//@author: [yourname]
157+
//@function: ExportSysDictionary
158+
//@description: 导出字典JSON(包含字典详情)
159+
//@param: id uint
160+
//@return: exportData map[string]interface{}, err error
161+
162+
func (dictionaryService *DictionaryService) ExportSysDictionary(id uint) (exportData map[string]interface{}, err error) {
163+
var dictionary system.SysDictionary
164+
// 查询字典及其所有详情
165+
err = global.GVA_DB.Where("id = ?", id).Preload("SysDictionaryDetails", func(db *gorm.DB) *gorm.DB {
166+
return db.Order("sort")
167+
}).First(&dictionary).Error
168+
if err != nil {
169+
return nil, err
170+
}
171+
172+
// 构造导出数据
173+
exportData = map[string]interface{}{
174+
"name": dictionary.Name,
175+
"type": dictionary.Type,
176+
"status": dictionary.Status,
177+
"desc": dictionary.Desc,
178+
"details": dictionary.SysDictionaryDetails,
179+
}
180+
181+
return exportData, nil
182+
}
183+
184+
//@author: [yourname]
185+
//@function: ImportSysDictionary
186+
//@description: 导入字典JSON(包含字典详情)
187+
//@param: importData map[string]interface{}
188+
//@return: err error
189+
190+
func (dictionaryService *DictionaryService) ImportSysDictionary(importData map[string]interface{}) error {
191+
// 解析基本字典信息
192+
name, ok := importData["name"].(string)
193+
if !ok || name == "" {
194+
return errors.New("字典名称不能为空")
195+
}
196+
197+
dictType, ok := importData["type"].(string)
198+
if !ok || dictType == "" {
199+
return errors.New("字典类型不能为空")
200+
}
201+
202+
// 检查字典类型是否已存在
203+
if !errors.Is(global.GVA_DB.First(&system.SysDictionary{}, "type = ?", dictType).Error, gorm.ErrRecordNotFound) {
204+
return errors.New("存在相同的type,不允许导入")
205+
}
206+
207+
// 创建字典
208+
dictionary := system.SysDictionary{
209+
Name: name,
210+
Type: dictType,
211+
}
212+
213+
// 处理status字段
214+
if status, ok := importData["status"].(bool); ok {
215+
dictionary.Status = &status
216+
}
217+
218+
// 处理desc字段
219+
if desc, ok := importData["desc"].(string); ok {
220+
dictionary.Desc = desc
221+
}
222+
223+
// 开启事务
224+
return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
225+
// 创建字典
226+
if err := tx.Create(&dictionary).Error; err != nil {
227+
return err
228+
}
229+
230+
// 处理字典详情
231+
if details, ok := importData["details"].([]interface{}); ok && len(details) > 0 {
232+
// 创建一个映射来跟踪旧ID到新ID的对应关系
233+
idMap := make(map[uint]uint)
234+
235+
// 第一遍:创建所有详情记录(不设置parent_id)
236+
for _, detail := range details {
237+
detailMap, ok := detail.(map[string]interface{})
238+
if !ok {
239+
continue
240+
}
241+
242+
label, _ := detailMap["label"].(string)
243+
value, _ := detailMap["value"].(string)
244+
245+
if label == "" || value == "" {
246+
continue
247+
}
248+
249+
detailRecord := system.SysDictionaryDetail{
250+
Label: label,
251+
Value: value,
252+
SysDictionaryID: int(dictionary.ID),
253+
}
254+
255+
// 处理extend字段
256+
if extend, ok := detailMap["extend"].(string); ok {
257+
detailRecord.Extend = extend
258+
}
259+
260+
// 处理status字段
261+
if status, ok := detailMap["status"].(bool); ok {
262+
detailRecord.Status = &status
263+
}
264+
265+
// 处理sort字段
266+
if sort, ok := detailMap["sort"].(float64); ok {
267+
detailRecord.Sort = int(sort)
268+
}
269+
270+
// 创建详情记录
271+
if err := tx.Create(&detailRecord).Error; err != nil {
272+
return err
273+
}
274+
275+
// 记录ID映射(如果有原始ID)
276+
if oldID, ok := detailMap["ID"].(float64); ok {
277+
idMap[uint(oldID)] = detailRecord.ID
278+
}
279+
}
280+
281+
// 第二遍:更新parent_id关系
282+
for i, detail := range details {
283+
detailMap, ok := detail.(map[string]interface{})
284+
if !ok {
285+
continue
286+
}
287+
288+
// 如果有parentID,更新它
289+
if oldParentID, ok := detailMap["parentID"].(float64); ok && oldParentID > 0 {
290+
if newParentID, exists := idMap[uint(oldParentID)]; exists {
291+
// 获取新创建的记录ID(按顺序)
292+
if oldID, ok := detailMap["ID"].(float64); ok {
293+
if newID, exists := idMap[uint(oldID)]; exists {
294+
if err := tx.Model(&system.SysDictionaryDetail{}).Where("id = ?", newID).Update("parent_id", newParentID).Error; err != nil {
295+
return err
296+
}
297+
}
298+
} else {
299+
// 如果没有ID,使用索引来查找
300+
var allDetails []system.SysDictionaryDetail
301+
if err := tx.Where("sys_dictionary_id = ?", dictionary.ID).Order("id").Find(&allDetails).Error; err != nil {
302+
return err
303+
}
304+
if i < len(allDetails) {
305+
if err := tx.Model(&system.SysDictionaryDetail{}).Where("id = ?", allDetails[i].ID).Update("parent_id", newParentID).Error; err != nil {
306+
return err
307+
}
308+
}
309+
}
310+
}
311+
}
312+
}
313+
}
314+
315+
return nil
316+
})
317+
}

server/source/system/api.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ func (i *initApi) InitializeData(ctx context.Context) (context.Context, error) {
149149
{ApiGroup: "系统字典", Method: "PUT", Path: "/sysDictionary/updateSysDictionary", Description: "更新字典"},
150150
{ApiGroup: "系统字典", Method: "GET", Path: "/sysDictionary/findSysDictionary", Description: "根据ID获取字典(建议选择)"},
151151
{ApiGroup: "系统字典", Method: "GET", Path: "/sysDictionary/getSysDictionaryList", Description: "获取字典列表"},
152+
{ApiGroup: "系统字典", Method: "POST", Path: "/sysDictionary/importSysDictionary", Description: "导入字典JSON"},
153+
{ApiGroup: "系统字典", Method: "GET", Path: "/sysDictionary/exportSysDictionary", Description: "导出字典JSON"},
152154

153155
{ApiGroup: "操作记录", Method: "POST", Path: "/sysOperationRecord/createSysOperationRecord", Description: "新增操作记录"},
154156
{ApiGroup: "操作记录", Method: "GET", Path: "/sysOperationRecord/findSysOperationRecord", Description: "根据ID获取操作记录"},

server/source/system/casbin.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ func (i *initCasbin) InitializeData(ctx context.Context) (context.Context, error
149149
{Ptype: "p", V0: "888", V1: "/sysDictionary/getSysDictionaryList", V2: "GET"},
150150
{Ptype: "p", V0: "888", V1: "/sysDictionary/createSysDictionary", V2: "POST"},
151151
{Ptype: "p", V0: "888", V1: "/sysDictionary/deleteSysDictionary", V2: "DELETE"},
152+
{Ptype: "p", V0: "888", V1: "/sysDictionary/importSysDictionary", V2: "POST"},
153+
{Ptype: "p", V0: "888", V1: "/sysDictionary/exportSysDictionary", V2: "GET"},
152154

153155
{Ptype: "p", V0: "888", V1: "/sysOperationRecord/findSysOperationRecord", V2: "GET"},
154156
{Ptype: "p", V0: "888", V1: "/sysOperationRecord/updateSysOperationRecord", V2: "PUT"},

web/src/api/sysDictionary.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,35 @@ export const getSysDictionaryList = (params) => {
7878
params
7979
})
8080
}
81+
82+
// @Tags SysDictionary
83+
// @Summary 导出字典JSON(包含字典详情)
84+
// @Security ApiKeyAuth
85+
// @accept application/json
86+
// @Produce application/json
87+
// @Param data query model.SysDictionary true "字典ID"
88+
// @Success 200 {string} string "{"success":true,"data":{},"msg":"导出成功"}"
89+
// @Router /sysDictionary/exportSysDictionary [get]
90+
export const exportSysDictionary = (params) => {
91+
return service({
92+
url: '/sysDictionary/exportSysDictionary',
93+
method: 'get',
94+
params
95+
})
96+
}
97+
98+
// @Tags SysDictionary
99+
// @Summary 导入字典JSON(包含字典详情)
100+
// @Security ApiKeyAuth
101+
// @accept application/json
102+
// @Produce application/json
103+
// @Param data body object true "字典JSON数据"
104+
// @Success 200 {string} string "{"success":true,"data":{},"msg":"导入成功"}"
105+
// @Router /sysDictionary/importSysDictionary [post]
106+
export const importSysDictionary = (data) => {
107+
return service({
108+
url: '/sysDictionary/importSysDictionary',
109+
method: 'post',
110+
data
111+
})
112+
}

0 commit comments

Comments
 (0)