hsun 11 місяців тому
батько
коміт
c498c99250

+ 8 - 0
controllers/speech_recognition/speech_recognition.go

@@ -183,10 +183,17 @@ func (this *SpeechRecognitionController) Convert() {
 			return
 		}
 	}
+	sortMax, e := services.GetSpeechMenuMaxSort(req.MenuId)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取语音识别目录下最大排序失败, Err: " + e.Error()
+		return
+	}
 
 	speeches := make([]*speech_recognition.SpeechRecognition, 0)
 	nowTime := time.Now().Local()
 	for _, v := range req.Files {
+		sortMax += 1
 		t := new(speech_recognition.SpeechRecognition)
 		t.FileName = v.FileName
 		t.ResourceUrl = v.ResourceUrl
@@ -196,6 +203,7 @@ func (this *SpeechRecognitionController) Convert() {
 		t.SysUserId = sysUser.AdminId
 		t.SysUserName = sysUser.RealName
 		t.State = speech_recognition.SpeechRecognitionStateWait
+		t.Sort = sortMax
 		t.CreateTime = nowTime
 		t.ModifyTime = nowTime
 		// CreateMulti拿不到主键, 此处用循环新增获取

+ 17 - 5
controllers/speech_recognition/speech_recognition_menu.go

@@ -5,6 +5,7 @@ import (
 	"eta/eta_api/controllers"
 	"eta/eta_api/models"
 	"eta/eta_api/models/speech_recognition"
+	"eta/eta_api/services"
 	"eta/eta_api/utils"
 	"fmt"
 	"sort"
@@ -69,7 +70,7 @@ func (this *SpeechRecognitionMenuController) Add() {
 		}
 	}
 
-	// 获取目录层级
+	// 获取目录层级和同级最大排序
 	level := 1
 	rootId := 0
 	{
@@ -84,17 +85,23 @@ func (this *SpeechRecognitionMenuController) Add() {
 			rootId = parentMenu.RootId
 		}
 	}
+	sortMax, e := services.GetSpeechMenuMaxSort(req.ParentId)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取语音识别目录下最大排序失败, Err: " + e.Error()
+		return
+	}
 
 	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
 	menuOb.UniqueCode = utils.MD5(fmt.Sprintf("%s_%s", menuOb.TableName(), timestamp))
 	menuOb.MenuName = req.MenuName
 	menuOb.ParentId = req.ParentId
 	menuOb.Level = level
+	menuOb.Sort = sortMax + 1
 	menuOb.RootId = rootId
 	menuOb.CreateTime = time.Now().Local()
 	menuOb.ModifyTime = time.Now().Local()
-	e := menuOb.Create()
-	if e != nil {
+	if e = menuOb.Create(); e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "新增目录失败, Err: " + e.Error()
 		return
@@ -421,7 +428,7 @@ func (this *SpeechRecognitionMenuController) Tree() {
 // @Description 移动目录/语音识别
 // @Param	request	body speech_recognition.SpeechRecognitionMenuMoveReq true "type json string"
 // @Success 200 string "操作成功"
-// @router /move [post]
+// @router /menu/move [post]
 func (this *SpeechRecognitionMenuController) Move() {
 	br := new(models.BaseResponse).Init()
 	defer func() {
@@ -449,7 +456,12 @@ func (this *SpeechRecognitionMenuController) Move() {
 		return
 	}
 
-	// TODO:移动
+	e, _ := services.MoveSpeechMenu(req)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "移动目录/语音识别失败, Err: " + e.Error()
+		return
+	}
 
 	br.Ret = 200
 	br.Success = true

+ 8 - 0
controllers/speech_recognition/speech_recognition_tag.go

@@ -5,6 +5,7 @@ import (
 	"eta/eta_api/controllers"
 	"eta/eta_api/models"
 	"eta/eta_api/models/speech_recognition"
+	"eta/eta_api/services"
 	"eta/eta_api/utils"
 	"fmt"
 	"strconv"
@@ -71,11 +72,18 @@ func (this *SpeechRecognitionTagController) Add() {
 			return
 		}
 	}
+	sortMax, e := services.GetSpeechTagMenuMaxSort(req.MenuId)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取标签目录下最大排序失败, Err: " + e.Error()
+		return
+	}
 
 	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
 	tagOb.UniqueCode = utils.MD5(fmt.Sprintf("%s_%s", tagOb.TableName(), timestamp))
 	tagOb.TagName = req.TagName
 	tagOb.MenuId = req.MenuId
+	tagOb.Sort = sortMax + 1
 	tagOb.CreateTime = time.Now().Local()
 	tagOb.ModifyTime = time.Now().Local()
 	if e := tagOb.Create(); e != nil {

+ 29 - 8
controllers/speech_recognition/speech_recognition_tag_menu.go

@@ -71,7 +71,7 @@ func (this *SpeechRecognitionTagMenuController) Add() {
 		}
 	}
 
-	// 获取目录层级
+	// 获取目录层级和同级最大排序
 	level := 1
 	rootId := 0
 	{
@@ -86,17 +86,23 @@ func (this *SpeechRecognitionTagMenuController) Add() {
 			rootId = parentMenu.RootId
 		}
 	}
+	sortMax, e := services.GetSpeechTagMenuMaxSort(req.ParentId)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取标签目录下最大排序失败, Err: " + e.Error()
+		return
+	}
 
 	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
 	menuOb.UniqueCode = utils.MD5(fmt.Sprintf("%s_%s", menuOb.TableName(), timestamp))
 	menuOb.MenuName = req.MenuName
 	menuOb.ParentId = req.ParentId
 	menuOb.Level = level
+	menuOb.Sort = sortMax + 1
 	menuOb.RootId = rootId
 	menuOb.CreateTime = time.Now().Local()
 	menuOb.ModifyTime = time.Now().Local()
-	e := menuOb.Create()
-	if e != nil {
+	if e = menuOb.Create(); e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "新增目录失败, Err: " + e.Error()
 		return
@@ -302,7 +308,7 @@ func (this *SpeechRecognitionTagMenuController) Tree() {
 		br.Ret = 408
 		return
 	}
-	// 前端采用懒加载, 所以只查询目录及当前目录下的语音识别
+	// 前端采用懒加载, 所以只查询目录及当前目录下的标签
 	parentId, _ := this.GetInt("ParentId")
 
 	// 获取所有目录
@@ -461,12 +467,12 @@ func (this *SpeechRecognitionTagMenuController) List() {
 	br.Msg = "获取成功"
 }
 
-// TODO:Move
+// Move
 // @Title 移动标签/目录
 // @Description 移动标签/目录
-// @Param	request	body speech_recognition.SpeechRecognitionTagRemoveReq true "type json string"
+// @Param	request	body speech_recognition.SpeechRecognitionTagMenuMoveReq true "type json string"
 // @Success 200 string "操作成功"
-// @router /tag/move [post]
+// @router /tag/menu/move [post]
 func (this *SpeechRecognitionTagMenuController) Move() {
 	br := new(models.BaseResponse).Init()
 	defer func() {
@@ -483,8 +489,23 @@ func (this *SpeechRecognitionTagMenuController) Move() {
 		br.Ret = 408
 		return
 	}
+	var req speech_recognition.SpeechRecognitionTagMenuMoveReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+	if req.MenuId <= 0 && req.TagId <= 0 {
+		br.Msg = "请选择目录或标签"
+		return
+	}
 
-	// TODO:移动标签/目录
+	e, _ := services.MoveSpeechTagMenu(req)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "移动目录/标签失败, Err: " + e.Error()
+		return
+	}
 
 	br.Ret = 200
 	br.Success = true

+ 29 - 0
models/speech_recognition/speech_recognition.go

@@ -443,3 +443,32 @@ type SpeechRecognitionContentExportReq struct {
 	ExportType          int  `description:"导出类型:1-txt;2-doc;3-pdf"`
 	Timestamp           bool `description:"是否显示时间戳"`
 }
+
+// UpdateSortByMenuId 根据分类ID更新排序
+func (m *SpeechRecognition) UpdateSortByMenuId(menuId, nowSort int, prevSpeechId int, updateSort string) (err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`UPDATE %s SET %s = %s WHERE %s = ? `, m.TableName(), SpeechRecognitionCols.Sort, updateSort, SpeechRecognitionCols.MenuId)
+	if prevSpeechId > 0 {
+		sql += fmt.Sprintf(` AND (%s > ? OR (%s > %d AND %s = %d))`, SpeechRecognitionCols.Sort, SpeechRecognitionCols.SpeechRecognitionId, prevSpeechId, SpeechRecognitionCols.Sort, nowSort)
+	} else {
+		sql += fmt.Sprintf(` AND %s > ?`, SpeechRecognitionCols.Sort)
+	}
+	_, err = o.Raw(sql, menuId, nowSort).Exec()
+	return
+}
+
+// GetMaxSortByMenuId 获取分类下最大Sort
+func (m *SpeechRecognition) GetMaxSortByMenuId(menuId int) (sort int, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT MAX(sort) AS sort FROM %s WHERE %s = ?`, m.TableName(), SpeechRecognitionCols.MenuId)
+	err = o.Raw(sql, menuId).QueryRow(&sort)
+	return
+}
+
+// GetFirstByMenuId 获取目录下排序第一的数据
+func (m *SpeechRecognition) GetFirstByMenuId(menuId int) (item *SpeechRecognition, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? ORDER BY %s ASC, %s ASC LIMIT 1`, m.TableName(), SpeechRecognitionCols.MenuId, SpeechRecognitionCols.Sort, SpeechRecognitionCols.SpeechRecognitionId)
+	err = o.Raw(sql, menuId).QueryRow(&item)
+	return
+}

+ 41 - 0
models/speech_recognition/speech_recognition_menu.go

@@ -195,3 +195,44 @@ type SpeechRecognitionMenuMoveReq struct {
 	PrevSpeechId int `description:"上一个语音识别ID"`
 	NextSpeechId int `description:"下一个语音识别ID"`
 }
+
+// UpdateSortByParentId 根据父级ID更新排序
+func (m *SpeechRecognitionMenu) UpdateSortByParentId(parentId, menuId, nowSort int, updateSort string) (err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`UPDATE %s SET %s = %s WHERE %s = ? AND %s > ?`, m.TableName(), SpeechRecognitionMenuCols.Sort, updateSort, SpeechRecognitionMenuCols.ParentId, SpeechRecognitionMenuCols.Sort)
+	if menuId > 0 {
+		sql += fmt.Sprintf(` OR (%s > %d AND %s = %d)`, SpeechRecognitionMenuCols.SpeechRecognitionMenuId, menuId, SpeechRecognitionMenuCols.Sort, nowSort)
+	}
+	_, err = o.Raw(sql, parentId, nowSort).Exec()
+	return
+}
+
+// GetMaxSortByParentId 获取父级分类下最大Sort
+func (m *SpeechRecognitionMenu) GetMaxSortByParentId(parentId int) (sort int, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT MAX(sort) AS sort FROM %s WHERE %s = ?`, m.TableName(), SpeechRecognitionMenuCols.ParentId)
+	err = o.Raw(sql, parentId).QueryRow(&sort)
+	return
+}
+
+// GetFirstByParentId 获取父级目录下排序第一的目录
+func (m *SpeechRecognitionMenu) GetFirstByParentId(parentId int) (item *SpeechRecognitionMenu, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? ORDER BY %s ASC, %s ASC LIMIT 1`, m.TableName(), SpeechRecognitionMenuCols.ParentId, SpeechRecognitionMenuCols.Sort, SpeechRecognitionMenuCols.SpeechRecognitionMenuId)
+	err = o.Raw(sql, parentId).QueryRow(&item)
+	return
+}
+
+// UpdateChildByParentMenuId 通过父级目录ID更新子目录
+func (m *SpeechRecognitionMenu) UpdateChildByParentMenuId(menuIds []int, rootId int, levelStep int) (err error) {
+	if len(menuIds) == 0 {
+		return
+	}
+	o := orm.NewOrm()
+	var pars []interface{}
+	pars = append(pars, rootId, levelStep)
+	pars = append(pars, menuIds)
+	sql := fmt.Sprintf(`UPDATE %s SET %s = ?, %s = %s + ? WHERE %s IN (%s)`, m.TableName(), SpeechRecognitionMenuCols.RootId, SpeechRecognitionMenuCols.Level, SpeechRecognitionMenuCols.Level, SpeechRecognitionMenuCols.SpeechRecognitionMenuId, utils.GetOrmInReplace(len(menuIds)))
+	_, err = o.Raw(sql, pars).Exec()
+	return
+}

+ 29 - 0
models/speech_recognition/speech_recognition_tag.go

@@ -184,3 +184,32 @@ type SpeechRecognitionTagEditReq struct {
 type SpeechRecognitionTagRemoveReq struct {
 	TagId int `description:"标签ID"`
 }
+
+// UpdateSortByMenuId 根据分类ID更新排序
+func (m *SpeechRecognitionTag) UpdateSortByMenuId(menuId, nowSort int, prevTagId int, updateSort string) (err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`UPDATE %s SET %s = %s WHERE %s = ? `, m.TableName(), SpeechRecognitionTagCols.Sort, updateSort, SpeechRecognitionTagCols.MenuId)
+	if prevTagId > 0 {
+		sql += fmt.Sprintf(` AND (%s > ? OR (%s > %d AND %s = %d))`, SpeechRecognitionTagCols.Sort, SpeechRecognitionTagCols.SpeechRecognitionTagId, prevTagId, SpeechRecognitionTagCols.Sort, nowSort)
+	} else {
+		sql += fmt.Sprintf(` AND %s > ?`, SpeechRecognitionTagCols.Sort)
+	}
+	_, err = o.Raw(sql, menuId, nowSort).Exec()
+	return
+}
+
+// GetMaxSortByMenuId 获取分类下最大Sort
+func (m *SpeechRecognitionTag) GetMaxSortByMenuId(menuId int) (sort int, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT MAX(sort) AS sort FROM %s WHERE %s = ?`, m.TableName(), SpeechRecognitionTagCols.MenuId)
+	err = o.Raw(sql, menuId).QueryRow(&sort)
+	return
+}
+
+// GetFirstByMenuId 获取目录下排序第一的数据
+func (m *SpeechRecognitionTag) GetFirstByMenuId(menuId int) (item *SpeechRecognitionTag, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? ORDER BY %s ASC, %s ASC LIMIT 1`, m.TableName(), SpeechRecognitionTagCols.MenuId, SpeechRecognitionTagCols.Sort, SpeechRecognitionTagCols.SpeechRecognitionTagId)
+	err = o.Raw(sql, menuId).QueryRow(&item)
+	return
+}

+ 41 - 0
models/speech_recognition/speech_recognition_tag_menu.go

@@ -206,3 +206,44 @@ type SpeechRecognitionTagMenuMoveReq struct {
 	PrevTagId    int `description:"上一个标签ID"`
 	NextTagId    int `description:"下一个标签ID"`
 }
+
+// UpdateSortByParentId 根据父级ID更新排序
+func (m *SpeechRecognitionTagMenu) UpdateSortByParentId(parentId, menuId, nowSort int, updateSort string) (err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`UPDATE %s SET %s = %s WHERE %s = ? AND %s > ?`, m.TableName(), SpeechRecognitionTagMenuCols.Sort, updateSort, SpeechRecognitionTagMenuCols.ParentId, SpeechRecognitionTagMenuCols.Sort)
+	if menuId > 0 {
+		sql += fmt.Sprintf(` OR (%s > %d AND %s = %d)`, SpeechRecognitionTagMenuCols.SpeechRecognitionTagMenuId, menuId, SpeechRecognitionTagMenuCols.Sort, nowSort)
+	}
+	_, err = o.Raw(sql, parentId, nowSort).Exec()
+	return
+}
+
+// GetMaxSortByParentId 获取父级分类下最大Sort
+func (m *SpeechRecognitionTagMenu) GetMaxSortByParentId(parentId int) (sort int, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT MAX(sort) AS sort FROM %s WHERE %s = ?`, m.TableName(), SpeechRecognitionTagMenuCols.ParentId)
+	err = o.Raw(sql, parentId).QueryRow(&sort)
+	return
+}
+
+// GetFirstByParentId 获取父级目录下排序第一的目录
+func (m *SpeechRecognitionTagMenu) GetFirstByParentId(parentId int) (item *SpeechRecognitionTagMenu, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? ORDER BY %s ASC, %s ASC LIMIT 1`, m.TableName(), SpeechRecognitionTagMenuCols.ParentId, SpeechRecognitionTagMenuCols.Sort, SpeechRecognitionTagMenuCols.SpeechRecognitionTagMenuId)
+	err = o.Raw(sql, parentId).QueryRow(&item)
+	return
+}
+
+// UpdateChildByParentMenuId 通过父级目录ID更新子目录
+func (m *SpeechRecognitionTagMenu) UpdateChildByParentMenuId(menuIds []int, rootId int, levelStep int) (err error) {
+	if len(menuIds) == 0 {
+		return
+	}
+	o := orm.NewOrm()
+	var pars []interface{}
+	pars = append(pars, rootId, levelStep)
+	pars = append(pars, menuIds)
+	sql := fmt.Sprintf(`UPDATE %s SET %s = ?, %s = %s + ? WHERE %s IN (%s)`, m.TableName(), SpeechRecognitionTagMenuCols.RootId, SpeechRecognitionTagMenuCols.Level, SpeechRecognitionTagMenuCols.Level, SpeechRecognitionTagMenuCols.SpeechRecognitionTagMenuId, utils.GetOrmInReplace(len(menuIds)))
+	_, err = o.Raw(sql, pars).Exec()
+	return
+}

+ 16 - 16
routers/commentsRouter.go

@@ -6147,8 +6147,8 @@ func init() {
 
     beego.GlobalControllerRouter["eta/eta_api/controllers/speech_recognition:SpeechRecognitionMenuController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/speech_recognition:SpeechRecognitionMenuController"],
         beego.ControllerComments{
-            Method: "Remove",
-            Router: `/menu/remove`,
+            Method: "Move",
+            Router: `/menu/move`,
             AllowHTTPMethods: []string{"post"},
             MethodParams: param.Make(),
             Filters: nil,
@@ -6156,18 +6156,18 @@ func init() {
 
     beego.GlobalControllerRouter["eta/eta_api/controllers/speech_recognition:SpeechRecognitionMenuController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/speech_recognition:SpeechRecognitionMenuController"],
         beego.ControllerComments{
-            Method: "Tree",
-            Router: `/menu/tree`,
-            AllowHTTPMethods: []string{"get"},
+            Method: "Remove",
+            Router: `/menu/remove`,
+            AllowHTTPMethods: []string{"post"},
             MethodParams: param.Make(),
             Filters: nil,
             Params: nil})
 
     beego.GlobalControllerRouter["eta/eta_api/controllers/speech_recognition:SpeechRecognitionMenuController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/speech_recognition:SpeechRecognitionMenuController"],
         beego.ControllerComments{
-            Method: "Move",
-            Router: `/move`,
-            AllowHTTPMethods: []string{"post"},
+            Method: "Tree",
+            Router: `/menu/tree`,
+            AllowHTTPMethods: []string{"get"},
             MethodParams: param.Make(),
             Filters: nil,
             Params: nil})
@@ -6237,8 +6237,8 @@ func init() {
 
     beego.GlobalControllerRouter["eta/eta_api/controllers/speech_recognition:SpeechRecognitionTagMenuController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/speech_recognition:SpeechRecognitionTagMenuController"],
         beego.ControllerComments{
-            Method: "Remove",
-            Router: `/tag/menu/remove`,
+            Method: "Move",
+            Router: `/tag/menu/move`,
             AllowHTTPMethods: []string{"post"},
             MethodParams: param.Make(),
             Filters: nil,
@@ -6246,18 +6246,18 @@ func init() {
 
     beego.GlobalControllerRouter["eta/eta_api/controllers/speech_recognition:SpeechRecognitionTagMenuController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/speech_recognition:SpeechRecognitionTagMenuController"],
         beego.ControllerComments{
-            Method: "Tree",
-            Router: `/tag/menu/tree`,
-            AllowHTTPMethods: []string{"get"},
+            Method: "Remove",
+            Router: `/tag/menu/remove`,
+            AllowHTTPMethods: []string{"post"},
             MethodParams: param.Make(),
             Filters: nil,
             Params: nil})
 
     beego.GlobalControllerRouter["eta/eta_api/controllers/speech_recognition:SpeechRecognitionTagMenuController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/speech_recognition:SpeechRecognitionTagMenuController"],
         beego.ControllerComments{
-            Method: "Move",
-            Router: `/tag/move`,
-            AllowHTTPMethods: []string{"post"},
+            Method: "Tree",
+            Router: `/tag/menu/tree`,
+            AllowHTTPMethods: []string{"get"},
             MethodParams: param.Make(),
             Filters: nil,
             Params: nil})

+ 1003 - 0
services/speech_recognition.go

@@ -5,6 +5,7 @@ import (
 	"baliance.com/gooxml/measurement"
 	"baliance.com/gooxml/schema/soo/wml"
 	"bufio"
+	"errors"
 	"eta/eta_api/models"
 	"eta/eta_api/models/speech_recognition"
 	"eta/eta_api/services/alarm_msg"
@@ -230,3 +231,1005 @@ func SpeechRecognitionContentExport(exportType int, exportTimestamp bool, fileNa
 	result = filePath
 	return
 }
+
+// ------------------ 移动目录/语音识别(有空的话后面可以优化一下,以后这种菜单混合移动的情况不会少,CV起来怪麻烦的) ------------------ //
+
+// MoveSpeechMenu 移动语音识别目录/识别文件
+func MoveSpeechMenu(req speech_recognition.SpeechRecognitionMenuMoveReq) (err error, errMsg string) {
+	menuId := req.MenuId
+	parentMenuId := req.ParentMenuId
+	prevMenuId := req.PrevMenuId
+	nextMenuId := req.NextMenuId
+
+	speechId := req.SpeechId
+	prevSpeechId := req.PrevSpeechId
+	nextSpeechId := req.NextSpeechId
+
+	//首先确定移动的对象是目录还是语音识别
+	//判断上一个节点是目录还是语音识别
+	//判断下一个节点是目录还是语音识别
+	//同时更新目录目录下的目录sort和语音识别sort
+	//更新当前移动的目录或者语音识别sort
+
+	menuOb := new(speech_recognition.SpeechRecognitionMenu)
+	speechOb := new(speech_recognition.SpeechRecognition)
+
+	var parentSpeechMenu *speech_recognition.SpeechRecognitionMenu
+	if parentMenuId > 0 {
+		t, e := menuOb.GetItemById(parentMenuId)
+		if e != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取上级目录信息失败,Err:" + err.Error())
+			return
+		}
+		parentSpeechMenu = t
+	}
+
+	//如果有传入 上一个兄弟节点目录id
+	var (
+		speechMenu *speech_recognition.SpeechRecognitionMenu
+		prevMenu   *speech_recognition.SpeechRecognitionMenu
+		nextMenu   *speech_recognition.SpeechRecognitionMenu
+
+		speechItem *speech_recognition.SpeechRecognition
+		prevSpeech *speech_recognition.SpeechRecognition
+		nextSpeech *speech_recognition.SpeechRecognition
+		prevSort   int
+		nextSort   int
+	)
+
+	// 移动对象为目录
+	if speechId == 0 {
+		speechMenu, err = menuOb.GetItemById(menuId)
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				errMsg = "当前目录不存在"
+				err = errors.New("获取目录信息失败,Err:" + err.Error())
+				return
+			}
+			errMsg = "移动失败"
+			err = errors.New("获取目录信息失败,Err:" + err.Error())
+			return
+		}
+		if parentMenuId > 0 && parentSpeechMenu.Level == 3 {
+			errMsg = "最高只支持添加3级目录"
+			err = errors.New(errMsg)
+			return
+		}
+
+		// 如果是移动目录, 那么校验一下父级目录下是否有重名目录
+		{
+			cond := fmt.Sprintf(` AND %s = ? AND %s = ? AND %s <> ?`, speech_recognition.SpeechRecognitionMenuCols.MenuName, speech_recognition.SpeechRecognitionMenuCols.ParentId, speech_recognition.SpeechRecognitionMenuCols.SpeechRecognitionMenuId)
+			pars := make([]interface{}, 0)
+			pars = append(pars, parentMenuId, speechMenu.MenuName, menuId)
+			exists, e := menuOb.GetItemByCondition(cond, pars, "")
+			if e != nil && e.Error() != utils.ErrNoRow() {
+				errMsg = "移动失败"
+				err = fmt.Errorf("获取父级目录下的同名目录失败, Err: %s", e.Error())
+				return
+			}
+			if exists != nil {
+				errMsg = "移动失败,目录名称已存在"
+				return
+			}
+		}
+	} else {
+		speechItem, err = speechOb.GetItemById(speechId)
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				errMsg = "当前语音识别不存在"
+				err = errors.New("获取目录信息失败,Err:" + err.Error())
+				return
+			}
+			errMsg = "移动失败"
+			err = errors.New("获取目录信息失败,Err:" + err.Error())
+			return
+		}
+		if parentMenuId == 0 {
+			errMsg = "移动失败,语音识别必须挂在目录下"
+			err = errors.New(errMsg)
+			return
+		}
+	}
+
+	if prevMenuId > 0 {
+		prevMenu, err = menuOb.GetItemById(prevMenuId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取上一个兄弟节点目录信息失败,Err:" + err.Error())
+			return
+		}
+		prevSort = prevMenu.Sort
+	} else if prevSpeechId > 0 {
+		prevSpeech, err = speechOb.GetItemById(prevSpeechId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取上一个兄弟节点信息失败,Err:" + err.Error())
+			return
+		}
+		prevSort = prevSpeech.Sort
+	}
+
+	// 下一个兄弟节点
+	if nextMenuId > 0 {
+		nextMenu, err = menuOb.GetItemById(nextMenuId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取下一个兄弟节点目录信息失败,Err:" + err.Error())
+			return
+		}
+		nextSort = nextMenu.Sort
+	} else if nextSpeechId > 0 {
+		nextSpeech, err = speechOb.GetItemById(nextSpeechId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取下一个兄弟节点目录信息失败,Err:" + err.Error())
+			return
+		}
+		nextSort = nextSpeech.Sort
+	}
+
+	err, errMsg = moveSpeechMenu(parentSpeechMenu, speechMenu, prevMenu, nextMenu, speechItem, prevSpeech, nextSpeech, parentMenuId, prevSort, nextSort)
+	return
+}
+
+func moveSpeechMenu(parentSpeechMenu, speechMenu, prevMenu, nextMenu *speech_recognition.SpeechRecognitionMenu, speechItem, prevSpeech, nextSpeech *speech_recognition.SpeechRecognition, parentMenuId int, prevSort, nextSort int) (err error, errMsg string) {
+	updateCol := make([]string, 0)
+
+	menuOb := new(speech_recognition.SpeechRecognitionMenu)
+	speechOb := new(speech_recognition.SpeechRecognition)
+
+	// 移动对象为目录, 判断目录是否存在
+	if speechMenu != nil {
+		oldParentId := speechMenu.ParentId
+		oldLevel := speechMenu.Level
+		var menuIds []int
+		if oldParentId != parentMenuId {
+			//更新子目录对应的level
+			childList, e, m := GetChildSpeechMenuByMenuId(speechMenu.SpeechRecognitionMenuId)
+			if e != nil {
+				errMsg = "移动失败"
+				err = errors.New("查询子目录失败,Err:" + e.Error() + m)
+				return
+			}
+
+			if len(childList) > 0 {
+				for _, v := range childList {
+					if v.SpeechRecognitionMenuId == speechMenu.SpeechRecognitionMenuId {
+						continue
+					}
+					menuIds = append(menuIds, v.SpeechRecognitionMenuId)
+				}
+			}
+		}
+		//判断上级id是否一致,如果不一致的话,那么需要移动该目录层级
+		if speechMenu.ParentId != parentMenuId && parentMenuId != 0 {
+			if speechMenu.Level != parentSpeechMenu.Level+1 { //禁止层级调整
+				errMsg = "移动失败"
+				err = errors.New("不支持目录层级变更")
+				return
+			}
+			speechMenu.ParentId = parentSpeechMenu.SpeechRecognitionMenuId
+			speechMenu.RootId = parentSpeechMenu.RootId
+			speechMenu.Level = parentSpeechMenu.Level + 1
+			speechMenu.ModifyTime = time.Now()
+			updateCol = append(updateCol, "ParentId", "RootId", "Level", "ModifyTime")
+		} else if speechMenu.ParentId != parentMenuId && parentMenuId == 0 {
+			errMsg = "移动失败"
+			err = errors.New("不支持目录层级变更")
+			return
+		}
+
+		if prevSort > 0 {
+			//如果是移动在两个兄弟节点之间
+			if nextSort > 0 {
+				//下一个兄弟节点
+				//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
+				if prevSort == nextSort || prevSort == speechMenu.Sort {
+					//变更兄弟节点的排序
+					updateSortStr := `sort + 2`
+
+					//变更目录
+					if prevMenu != nil {
+						_ = menuOb.UpdateSortByParentId(parentMenuId, prevMenu.SpeechRecognitionMenuId, prevMenu.Sort, updateSortStr)
+					} else {
+						_ = menuOb.UpdateSortByParentId(parentMenuId, 0, prevSort, updateSortStr)
+					}
+
+					//变更语音识别
+					if prevSpeech != nil {
+						//变更兄弟节点的排序
+						_ = speechOb.UpdateSortByMenuId(parentMenuId, prevSort, prevSpeech.SpeechRecognitionId, updateSortStr)
+					} else {
+						_ = speechOb.UpdateSortByMenuId(parentMenuId, prevSort, 0, updateSortStr)
+					}
+				} else {
+					//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
+					if nextSort-prevSort == 1 {
+						//变更兄弟节点的排序
+						updateSortStr := `sort + 1`
+
+						//变更目录
+						if prevMenu != nil {
+							_ = menuOb.UpdateSortByParentId(parentMenuId, prevMenu.SpeechRecognitionMenuId, prevSort, updateSortStr)
+						} else {
+							_ = menuOb.UpdateSortByParentId(parentMenuId, 0, prevSort, updateSortStr)
+						}
+
+						//变更语音识别
+						if prevSpeech != nil {
+							//变更兄弟节点的排序
+							_ = speechOb.UpdateSortByMenuId(parentMenuId, prevSort, prevSpeech.SpeechRecognitionId, updateSortStr)
+						} else {
+							_ = speechOb.UpdateSortByMenuId(parentMenuId, prevSort, 0, updateSortStr)
+						}
+
+					}
+				}
+			}
+
+			speechMenu.Sort = prevSort + 1
+			speechMenu.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		} else if prevMenu == nil && nextMenu == nil && prevSpeech == nil && nextSpeech == nil && parentMenuId > 0 {
+			//处理只拖动到目录里,默认放到目录底部的情况
+			var maxSort int
+			maxSort, err = GetSpeechMenuMaxSort(parentMenuId)
+			if err != nil {
+				errMsg = "移动失败"
+				err = errors.New("查询组内排序信息失败,Err:" + err.Error())
+				return
+			}
+			speechMenu.Sort = maxSort + 1 //那就是排在组内最后一位
+			speechMenu.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		} else {
+			// 拖动到父级目录的第一位
+			firstMenu, tmpErr := menuOb.GetFirstByParentId(parentMenuId)
+			if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+				errMsg = "移动失败"
+				err = errors.New("获取获取当前父级目录下的排序第一条的目录信息失败,Err:" + tmpErr.Error())
+				return
+			}
+
+			//如果该目录下存在其他目录,且第一个其他目录的排序等于0,那么需要调整排序
+			if firstMenu != nil && firstMenu.Sort == 0 {
+				updateSortStr := ` sort + 1 `
+				_ = menuOb.UpdateSortByParentId(parentMenuId, firstMenu.SpeechRecognitionMenuId-1, 0, updateSortStr)
+				//该目录下的所有语音识别也需要+1
+				_ = speechOb.UpdateSortByMenuId(parentMenuId, 0, 0, updateSortStr)
+			} else {
+				//如果该目录下存在语音识别,且第一个语音识别的排序等于0,那么需要调整排序
+				firstSpeech, tErr := speechOb.GetFirstByMenuId(parentMenuId)
+				if tErr != nil && tErr.Error() != utils.ErrNoRow() {
+					errMsg = "移动失败"
+					err = errors.New("获取获取当前父级目录下的排序第一条的目录信息失败,Err:" + tErr.Error())
+					return
+				}
+
+				//如果该目录下存在其他目录,且第一个其他目录的排序等于0,那么需要调整排序
+				if firstSpeech != nil && firstSpeech.Sort == 0 {
+					updateSortStr := ` sort + 1 `
+					_ = speechOb.UpdateSortByMenuId(parentMenuId, 0, firstSpeech.SpeechRecognitionId-1, updateSortStr)
+					_ = menuOb.UpdateSortByParentId(parentMenuId, 0, 0, updateSortStr)
+				}
+			}
+
+			speechMenu.Sort = 0 //那就是排在第一位
+			speechMenu.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		}
+
+		//更新
+		if len(updateCol) > 0 {
+			err = speechMenu.Update(updateCol)
+			if err != nil {
+				errMsg = "移动失败"
+				err = errors.New("修改失败,Err:" + err.Error())
+				return
+			}
+			//更新对应目录的root_id和层级
+			if oldParentId != parentMenuId {
+				if len(menuIds) > 0 {
+					levelStep := speechMenu.Level - oldLevel
+					err = menuOb.UpdateChildByParentMenuId(menuIds, speechMenu.RootId, levelStep)
+					if err != nil {
+						errMsg = "移动失败"
+						err = errors.New("更新子目录失败,Err:" + err.Error())
+						return
+					}
+				}
+			}
+		}
+	} else {
+		if speechItem == nil {
+			errMsg = "当前语音识别不存在"
+			err = errors.New(errMsg)
+			return
+		}
+		//如果改变了目录,那么移动该语音识别数据
+		if speechItem.MenuId != parentMenuId {
+			speechItem.MenuId = parentMenuId
+			speechItem.ModifyTime = time.Now()
+			updateCol = append(updateCol, speech_recognition.SpeechRecognitionCols.MenuId, speech_recognition.SpeechRecognitionCols.ModifyTime)
+		}
+		if prevSort > 0 {
+			//如果是移动在两个兄弟节点之间
+			if nextSort > 0 {
+				//下一个兄弟节点
+				//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
+				if prevSort == nextSort || prevSort == speechItem.Sort {
+					//变更兄弟节点的排序
+					updateSortStr := `sort + 2`
+
+					//变更目录
+					if prevMenu != nil {
+						_ = menuOb.UpdateSortByParentId(parentMenuId, prevMenu.SpeechRecognitionMenuId, prevMenu.Sort, updateSortStr)
+					} else {
+						_ = menuOb.UpdateSortByParentId(parentMenuId, 0, prevSort, updateSortStr)
+					}
+
+					//变更语音识别
+					if prevSpeech != nil {
+						//变更兄弟节点的排序
+						_ = speechOb.UpdateSortByMenuId(parentMenuId, prevSort, prevSpeech.SpeechRecognitionId, updateSortStr)
+					} else {
+						_ = speechOb.UpdateSortByMenuId(parentMenuId, prevSort, 0, updateSortStr)
+					}
+				} else {
+					//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
+					if nextSort-prevSort == 1 {
+						//变更兄弟节点的排序
+						updateSortStr := `sort + 1`
+						//变更目录
+						if prevMenu != nil {
+							_ = menuOb.UpdateSortByParentId(parentMenuId, prevMenu.SpeechRecognitionMenuId, prevSort, updateSortStr)
+						} else {
+							_ = menuOb.UpdateSortByParentId(parentMenuId, 0, prevSort, updateSortStr)
+						}
+
+						//变更语音识别
+						if prevSpeech != nil {
+							//变更兄弟节点的排序
+							_ = speechOb.UpdateSortByMenuId(parentMenuId, prevSort, prevSpeech.SpeechRecognitionId, updateSortStr)
+						} else {
+							_ = speechOb.UpdateSortByMenuId(parentMenuId, prevSort, 0, updateSortStr)
+						}
+					}
+				}
+			}
+
+			speechItem.Sort = prevSort + 1
+			speechItem.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		} else if prevMenu == nil && nextMenu == nil && prevSpeech == nil && nextSpeech == nil && parentMenuId > 0 {
+			//处理只拖动到目录里,默认放到目录底部的情况
+			var maxSort int
+			maxSort, err = GetSpeechMenuMaxSort(parentMenuId)
+			if err != nil {
+				errMsg = "移动失败"
+				err = errors.New("查询组内排序信息失败,Err:" + err.Error())
+				return
+			}
+			speechItem.Sort = maxSort + 1 //那就是排在组内最后一位
+			speechItem.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		} else {
+			// 拖动到父级目录的第一位
+			firstMenu, tmpErr := menuOb.GetFirstByParentId(parentMenuId)
+			if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+				errMsg = "移动失败"
+				err = errors.New("获取获取当前父级目录下的排序第一条的目录信息失败,Err:" + tmpErr.Error())
+				return
+			}
+
+			//如果该目录下存在其他目录,且第一个其他目录的排序等于0,那么需要调整排序
+			if firstMenu != nil && firstMenu.Sort == 0 {
+				updateSortStr := ` sort + 1 `
+				_ = menuOb.UpdateSortByParentId(parentMenuId, firstMenu.SpeechRecognitionMenuId-1, 0, updateSortStr)
+				//该目录下的所有语音识别也需要+1
+				_ = speechOb.UpdateSortByMenuId(parentMenuId, 0, 0, updateSortStr)
+			} else {
+				//如果该目录下存在语音识别,且第一个语音识别的排序等于0,那么需要调整排序
+				firstSpeech, tErr := speechOb.GetFirstByMenuId(parentMenuId)
+				if tErr != nil && tErr.Error() != utils.ErrNoRow() {
+					errMsg = "移动失败"
+					err = errors.New("获取获取当前父级目录下的排序第一条的目录信息失败,Err:" + tErr.Error())
+					return
+				}
+
+				//如果该目录下存在其他目录,且第一个其他目录的排序等于0,那么需要调整排序
+				if firstSpeech != nil && firstSpeech.Sort == 0 {
+					updateSortStr := ` sort + 1 `
+					_ = speechOb.UpdateSortByMenuId(parentMenuId, 0, firstSpeech.SpeechRecognitionId-1, updateSortStr)
+					_ = menuOb.UpdateSortByParentId(parentMenuId, 0, 0, updateSortStr)
+				}
+			}
+
+			speechItem.Sort = 0 //那就是排在第一位
+			speechItem.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		}
+
+		//更新
+		if len(updateCol) > 0 {
+			err = speechItem.Update(updateCol)
+			if err != nil {
+				errMsg = "移动失败"
+				err = errors.New("修改失败,Err:" + err.Error())
+				return
+			}
+		}
+	}
+	return
+}
+
+func GetChildSpeechMenuByMenuId(menuId int) (targetList []*speech_recognition.SpeechRecognitionMenu, err error, errMsg string) {
+	menuOb := new(speech_recognition.SpeechRecognitionMenu)
+	//判断是否是挂在顶级目录下
+	speechMenu, err := menuOb.GetItemById(menuId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			errMsg = "当前目录不存在"
+			err = errors.New(errMsg)
+			return
+		}
+		errMsg = "获取失败"
+		err = errors.New("获取目录信息失败,Err:" + err.Error())
+		return
+	}
+
+	cond := fmt.Sprintf(" AND %s = ?", speech_recognition.SpeechRecognitionMenuCols.RootId)
+	pars := make([]interface{}, 0)
+	pars = append(pars, speechMenu.RootId)
+	order := fmt.Sprintf("%s ASC, %s ASC, %s ASC", speech_recognition.SpeechRecognitionMenuCols.Level, speech_recognition.SpeechRecognitionMenuCols.Sort, speech_recognition.SpeechRecognitionMenuCols.SpeechRecognitionMenuId)
+	tmpList, err := speechMenu.GetItemsByCondition(cond, pars, []string{}, order)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		errMsg = "获取失败"
+		err = errors.New("获取数据失败,Err:" + err.Error())
+		return
+	}
+	idMap := make(map[int]struct{})
+	if len(tmpList) > 0 {
+		for _, v := range tmpList {
+			if v.SpeechRecognitionMenuId == speechMenu.SpeechRecognitionMenuId {
+				idMap[v.SpeechRecognitionMenuId] = struct{}{}
+			}
+		}
+		for _, v := range tmpList {
+			if _, ok := idMap[v.ParentId]; ok {
+				idMap[v.SpeechRecognitionMenuId] = struct{}{}
+			}
+		}
+		for _, v := range tmpList {
+			if _, ok := idMap[v.SpeechRecognitionMenuId]; ok {
+				targetList = append(targetList, v)
+			}
+		}
+	}
+	return
+}
+
+// GetSpeechMenuMaxSort 获取同级下最大的排序
+func GetSpeechMenuMaxSort(parentId int) (maxSort int, err error) {
+	menuOb := new(speech_recognition.SpeechRecognitionMenu)
+	speechOb := new(speech_recognition.SpeechRecognition)
+
+	//获取该层级下最大的排序数
+	menuMax, err := menuOb.GetMaxSortByParentId(parentId)
+	if err != nil {
+		return
+	}
+	maxSort = menuMax
+	speechMax, err := speechOb.GetMaxSortByMenuId(parentId)
+	if err != nil {
+		return
+	}
+	if maxSort < speechMax {
+		maxSort = speechMax
+	}
+	return
+}
+
+// ------------------ 移动目录/语音识别 ------------------ //
+
+// ------------------ 移动标签目录/标签 ------------------ //
+
+// MoveSpeechTagMenu 移动标签目录/标签
+func MoveSpeechTagMenu(req speech_recognition.SpeechRecognitionTagMenuMoveReq) (err error, errMsg string) {
+	menuId := req.MenuId
+	parentMenuId := req.ParentMenuId
+	prevMenuId := req.PrevMenuId
+	nextMenuId := req.NextMenuId
+
+	tagId := req.TagId
+	prevTagId := req.PrevTagId
+	nextTagId := req.NextTagId
+
+	//首先确定移动的对象是目录还是标签
+	//判断上一个节点是目录还是标签
+	//判断下一个节点是目录还是标签
+	//同时更新目录目录下的目录sort和标签sort
+	//更新当前移动的目录或者标签sort
+
+	menuOb := new(speech_recognition.SpeechRecognitionTagMenu)
+	tagOb := new(speech_recognition.SpeechRecognitionTag)
+
+	var parentTagMenu *speech_recognition.SpeechRecognitionTagMenu
+	if parentMenuId > 0 {
+		t, e := menuOb.GetItemById(parentMenuId)
+		if e != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取上级目录信息失败,Err:" + err.Error())
+			return
+		}
+		parentTagMenu = t
+	}
+
+	//如果有传入 上一个兄弟节点目录id
+	var (
+		tagMenu  *speech_recognition.SpeechRecognitionTagMenu
+		prevMenu *speech_recognition.SpeechRecognitionTagMenu
+		nextMenu *speech_recognition.SpeechRecognitionTagMenu
+
+		tagItem  *speech_recognition.SpeechRecognitionTag
+		prevTag  *speech_recognition.SpeechRecognitionTag
+		nextTag  *speech_recognition.SpeechRecognitionTag
+		prevSort int
+		nextSort int
+	)
+
+	// 移动对象为目录
+	if tagId == 0 {
+		tagMenu, err = menuOb.GetItemById(menuId)
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				errMsg = "当前目录不存在"
+				err = errors.New("获取目录信息失败,Err:" + err.Error())
+				return
+			}
+			errMsg = "移动失败"
+			err = errors.New("获取目录信息失败,Err:" + err.Error())
+			return
+		}
+		if parentMenuId > 0 && parentTagMenu.Level == 3 {
+			errMsg = "最高只支持添加3级目录"
+			err = errors.New(errMsg)
+			return
+		}
+
+		// 如果是移动目录, 那么校验一下父级目录下是否有重名目录
+		{
+			cond := fmt.Sprintf(` AND %s = ? AND %s = ? AND %s <> ?`, speech_recognition.SpeechRecognitionTagMenuCols.MenuName, speech_recognition.SpeechRecognitionTagMenuCols.ParentId, speech_recognition.SpeechRecognitionTagMenuCols.SpeechRecognitionTagMenuId)
+			pars := make([]interface{}, 0)
+			pars = append(pars, parentMenuId, tagMenu.MenuName, menuId)
+			exists, e := menuOb.GetItemByCondition(cond, pars, "")
+			if e != nil && e.Error() != utils.ErrNoRow() {
+				errMsg = "移动失败"
+				err = fmt.Errorf("获取父级目录下的同名目录失败, Err: %s", e.Error())
+				return
+			}
+			if exists != nil {
+				errMsg = "移动失败,目录名称已存在"
+				return
+			}
+		}
+	} else {
+		tagItem, err = tagOb.GetItemById(tagId)
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				errMsg = "当前标签不存在"
+				err = errors.New("获取目录信息失败,Err:" + err.Error())
+				return
+			}
+			errMsg = "移动失败"
+			err = errors.New("获取目录信息失败,Err:" + err.Error())
+			return
+		}
+		if parentMenuId == 0 {
+			errMsg = "移动失败,标签必须挂在目录下"
+			err = errors.New(errMsg)
+			return
+		}
+	}
+
+	if prevMenuId > 0 {
+		prevMenu, err = menuOb.GetItemById(prevMenuId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取上一个兄弟节点目录信息失败,Err:" + err.Error())
+			return
+		}
+		prevSort = prevMenu.Sort
+	} else if prevTagId > 0 {
+		prevTag, err = tagOb.GetItemById(prevTagId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取上一个兄弟节点信息失败,Err:" + err.Error())
+			return
+		}
+		prevSort = prevTag.Sort
+	}
+
+	// 下一个兄弟节点
+	if nextMenuId > 0 {
+		nextMenu, err = menuOb.GetItemById(nextMenuId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取下一个兄弟节点目录信息失败,Err:" + err.Error())
+			return
+		}
+		nextSort = nextMenu.Sort
+	} else if nextTagId > 0 {
+		nextTag, err = tagOb.GetItemById(nextTagId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取下一个兄弟节点目录信息失败,Err:" + err.Error())
+			return
+		}
+		nextSort = nextTag.Sort
+	}
+
+	err, errMsg = moveSpeechTagMenu(parentTagMenu, tagMenu, prevMenu, nextMenu, tagItem, prevTag, nextTag, parentMenuId, prevSort, nextSort)
+	return
+}
+
+func moveSpeechTagMenu(parentTagMenu, tagMenu, prevMenu, nextMenu *speech_recognition.SpeechRecognitionTagMenu, tagItem, prevTag, nextTag *speech_recognition.SpeechRecognitionTag, parentMenuId int, prevSort, nextSort int) (err error, errMsg string) {
+	updateCol := make([]string, 0)
+
+	menuOb := new(speech_recognition.SpeechRecognitionTagMenu)
+	tagOb := new(speech_recognition.SpeechRecognitionTag)
+
+	// 移动对象为目录, 判断目录是否存在
+	if tagMenu != nil {
+		oldParentId := tagMenu.ParentId
+		oldLevel := tagMenu.Level
+		var menuIds []int
+		if oldParentId != parentMenuId {
+			//更新子目录对应的level
+			childList, e, m := GetChildSpeechTagMenuByMenuId(tagMenu.SpeechRecognitionTagMenuId)
+			if e != nil {
+				errMsg = "移动失败"
+				err = errors.New("查询子目录失败,Err:" + e.Error() + m)
+				return
+			}
+
+			if len(childList) > 0 {
+				for _, v := range childList {
+					if v.SpeechRecognitionTagMenuId == tagMenu.SpeechRecognitionTagMenuId {
+						continue
+					}
+					menuIds = append(menuIds, v.SpeechRecognitionTagMenuId)
+				}
+			}
+		}
+		//判断上级id是否一致,如果不一致的话,那么需要移动该目录层级
+		if tagMenu.ParentId != parentMenuId && parentMenuId != 0 {
+			if tagMenu.Level != parentTagMenu.Level+1 { //禁止层级调整
+				errMsg = "移动失败"
+				err = errors.New("不支持目录层级变更")
+				return
+			}
+			tagMenu.ParentId = parentTagMenu.SpeechRecognitionTagMenuId
+			tagMenu.RootId = parentTagMenu.RootId
+			tagMenu.Level = parentTagMenu.Level + 1
+			tagMenu.ModifyTime = time.Now()
+			updateCol = append(updateCol, "ParentId", "RootId", "Level", "ModifyTime")
+		} else if tagMenu.ParentId != parentMenuId && parentMenuId == 0 {
+			errMsg = "移动失败"
+			err = errors.New("不支持目录层级变更")
+			return
+		}
+
+		if prevSort > 0 {
+			//如果是移动在两个兄弟节点之间
+			if nextSort > 0 {
+				//下一个兄弟节点
+				//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
+				if prevSort == nextSort || prevSort == tagMenu.Sort {
+					//变更兄弟节点的排序
+					updateSortStr := `sort + 2`
+
+					//变更目录
+					if prevMenu != nil {
+						_ = menuOb.UpdateSortByParentId(parentMenuId, prevMenu.SpeechRecognitionTagMenuId, prevMenu.Sort, updateSortStr)
+					} else {
+						_ = menuOb.UpdateSortByParentId(parentMenuId, 0, prevSort, updateSortStr)
+					}
+
+					//变更标签
+					if prevTag != nil {
+						//变更兄弟节点的排序
+						_ = tagOb.UpdateSortByMenuId(parentMenuId, prevSort, prevTag.SpeechRecognitionTagId, updateSortStr)
+					} else {
+						_ = tagOb.UpdateSortByMenuId(parentMenuId, prevSort, 0, updateSortStr)
+					}
+				} else {
+					//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
+					if nextSort-prevSort == 1 {
+						//变更兄弟节点的排序
+						updateSortStr := `sort + 1`
+
+						//变更目录
+						if prevMenu != nil {
+							_ = menuOb.UpdateSortByParentId(parentMenuId, prevMenu.SpeechRecognitionTagMenuId, prevSort, updateSortStr)
+						} else {
+							_ = menuOb.UpdateSortByParentId(parentMenuId, 0, prevSort, updateSortStr)
+						}
+
+						//变更标签
+						if prevTag != nil {
+							//变更兄弟节点的排序
+							_ = tagOb.UpdateSortByMenuId(parentMenuId, prevSort, prevTag.SpeechRecognitionTagId, updateSortStr)
+						} else {
+							_ = tagOb.UpdateSortByMenuId(parentMenuId, prevSort, 0, updateSortStr)
+						}
+
+					}
+				}
+			}
+
+			tagMenu.Sort = prevSort + 1
+			tagMenu.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		} else if prevMenu == nil && nextMenu == nil && prevTag == nil && nextTag == nil && parentMenuId > 0 {
+			//处理只拖动到目录里,默认放到目录底部的情况
+			var maxSort int
+			maxSort, err = GetSpeechTagMenuMaxSort(parentMenuId)
+			if err != nil {
+				errMsg = "移动失败"
+				err = errors.New("查询组内排序信息失败,Err:" + err.Error())
+				return
+			}
+			tagMenu.Sort = maxSort + 1 //那就是排在组内最后一位
+			tagMenu.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		} else {
+			// 拖动到父级目录的第一位
+			firstTagMenu, tmpErr := menuOb.GetFirstByParentId(parentMenuId)
+			if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+				errMsg = "移动失败"
+				err = errors.New("获取获取当前父级目录下的排序第一条的目录信息失败,Err:" + tmpErr.Error())
+				return
+			}
+
+			//如果该目录下存在其他目录,且第一个其他目录的排序等于0,那么需要调整排序
+			if firstTagMenu != nil && firstTagMenu.Sort == 0 {
+				updateSortStr := ` sort + 1 `
+				_ = menuOb.UpdateSortByParentId(parentMenuId, firstTagMenu.SpeechRecognitionTagMenuId-1, 0, updateSortStr)
+				//该目录下的所有标签也需要+1
+				_ = tagOb.UpdateSortByMenuId(parentMenuId, 0, 0, updateSortStr)
+			} else {
+				//如果该目录下存在标签,且第一个标签的排序等于0,那么需要调整排序
+				firstTag, tErr := tagOb.GetFirstByMenuId(parentMenuId)
+				if tErr != nil && tErr.Error() != utils.ErrNoRow() {
+					errMsg = "移动失败"
+					err = errors.New("获取获取当前父级目录下的排序第一条的目录信息失败,Err:" + tErr.Error())
+					return
+				}
+
+				//如果该目录下存在其他目录,且第一个其他目录的排序等于0,那么需要调整排序
+				if firstTag != nil && firstTag.Sort == 0 {
+					updateSortStr := ` sort + 1 `
+					_ = tagOb.UpdateSortByMenuId(parentMenuId, 0, firstTag.SpeechRecognitionTagId-1, updateSortStr)
+					_ = menuOb.UpdateSortByParentId(parentMenuId, 0, 0, updateSortStr)
+				}
+			}
+
+			tagMenu.Sort = 0 //那就是排在第一位
+			tagMenu.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		}
+
+		//更新
+		if len(updateCol) > 0 {
+			err = tagMenu.Update(updateCol)
+			if err != nil {
+				errMsg = "移动失败"
+				err = errors.New("修改失败,Err:" + err.Error())
+				return
+			}
+			//更新对应目录的root_id和层级
+			if oldParentId != parentMenuId {
+				if len(menuIds) > 0 {
+					levelStep := tagMenu.Level - oldLevel
+					err = menuOb.UpdateChildByParentMenuId(menuIds, tagMenu.RootId, levelStep)
+					if err != nil {
+						errMsg = "移动失败"
+						err = errors.New("更新子目录失败,Err:" + err.Error())
+						return
+					}
+				}
+			}
+		}
+	} else {
+		if tagItem == nil {
+			errMsg = "当前标签不存在"
+			err = errors.New(errMsg)
+			return
+		}
+		//如果改变了目录,那么移动该标签数据
+		if tagItem.MenuId != parentMenuId {
+			tagItem.MenuId = parentMenuId
+			tagItem.ModifyTime = time.Now()
+			updateCol = append(updateCol, speech_recognition.SpeechRecognitionTagCols.MenuId, speech_recognition.SpeechRecognitionTagCols.ModifyTime)
+		}
+		if prevSort > 0 {
+			//如果是移动在两个兄弟节点之间
+			if nextSort > 0 {
+				//下一个兄弟节点
+				//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
+				if prevSort == nextSort || prevSort == tagItem.Sort {
+					//变更兄弟节点的排序
+					updateSortStr := `sort + 2`
+
+					//变更目录
+					if prevMenu != nil {
+						_ = menuOb.UpdateSortByParentId(parentMenuId, prevMenu.SpeechRecognitionTagMenuId, prevMenu.Sort, updateSortStr)
+					} else {
+						_ = menuOb.UpdateSortByParentId(parentMenuId, 0, prevSort, updateSortStr)
+					}
+
+					//变更标签
+					if prevTag != nil {
+						//变更兄弟节点的排序
+						_ = tagOb.UpdateSortByMenuId(parentMenuId, prevSort, prevTag.SpeechRecognitionTagId, updateSortStr)
+					} else {
+						_ = tagOb.UpdateSortByMenuId(parentMenuId, prevSort, 0, updateSortStr)
+					}
+				} else {
+					//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
+					if nextSort-prevSort == 1 {
+						//变更兄弟节点的排序
+						updateSortStr := `sort + 1`
+						//变更目录
+						if prevMenu != nil {
+							_ = menuOb.UpdateSortByParentId(parentMenuId, prevMenu.SpeechRecognitionTagMenuId, prevSort, updateSortStr)
+						} else {
+							_ = menuOb.UpdateSortByParentId(parentMenuId, 0, prevSort, updateSortStr)
+						}
+
+						//变更标签
+						if prevTag != nil {
+							//变更兄弟节点的排序
+							_ = tagOb.UpdateSortByMenuId(parentMenuId, prevSort, prevTag.SpeechRecognitionTagId, updateSortStr)
+						} else {
+							_ = tagOb.UpdateSortByMenuId(parentMenuId, prevSort, 0, updateSortStr)
+						}
+					}
+				}
+			}
+
+			tagItem.Sort = prevSort + 1
+			tagItem.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		} else if prevMenu == nil && nextMenu == nil && prevTag == nil && nextTag == nil && parentMenuId > 0 {
+			//处理只拖动到目录里,默认放到目录底部的情况
+			var maxSort int
+			maxSort, err = GetSpeechTagMenuMaxSort(parentMenuId)
+			if err != nil {
+				errMsg = "移动失败"
+				err = errors.New("查询组内排序信息失败,Err:" + err.Error())
+				return
+			}
+			tagItem.Sort = maxSort + 1 //那就是排在组内最后一位
+			tagItem.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		} else {
+			// 拖动到父级目录的第一位
+			firstTagMenu, tmpErr := menuOb.GetFirstByParentId(parentMenuId)
+			if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+				errMsg = "移动失败"
+				err = errors.New("获取获取当前父级目录下的排序第一条的目录信息失败,Err:" + tmpErr.Error())
+				return
+			}
+
+			//如果该目录下存在其他目录,且第一个其他目录的排序等于0,那么需要调整排序
+			if firstTagMenu != nil && firstTagMenu.Sort == 0 {
+				updateSortStr := ` sort + 1 `
+				_ = menuOb.UpdateSortByParentId(parentMenuId, firstTagMenu.SpeechRecognitionTagMenuId-1, 0, updateSortStr)
+				//该目录下的所有标签也需要+1
+				_ = tagOb.UpdateSortByMenuId(parentMenuId, 0, 0, updateSortStr)
+			} else {
+				//如果该目录下存在标签,且第一个标签的排序等于0,那么需要调整排序
+				firstTag, tErr := tagOb.GetFirstByMenuId(parentMenuId)
+				if tErr != nil && tErr.Error() != utils.ErrNoRow() {
+					errMsg = "移动失败"
+					err = errors.New("获取获取当前父级目录下的排序第一条的目录信息失败,Err:" + tErr.Error())
+					return
+				}
+
+				//如果该目录下存在其他目录,且第一个其他目录的排序等于0,那么需要调整排序
+				if firstTag != nil && firstTag.Sort == 0 {
+					updateSortStr := ` sort + 1 `
+					_ = tagOb.UpdateSortByMenuId(parentMenuId, 0, firstTag.SpeechRecognitionTagId-1, updateSortStr)
+					_ = menuOb.UpdateSortByParentId(parentMenuId, 0, 0, updateSortStr)
+				}
+			}
+
+			tagItem.Sort = 0 //那就是排在第一位
+			tagItem.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		}
+
+		//更新
+		if len(updateCol) > 0 {
+			err = tagItem.Update(updateCol)
+			if err != nil {
+				errMsg = "移动失败"
+				err = errors.New("修改失败,Err:" + err.Error())
+				return
+			}
+		}
+	}
+	return
+}
+
+func GetChildSpeechTagMenuByMenuId(menuId int) (targetList []*speech_recognition.SpeechRecognitionTagMenu, err error, errMsg string) {
+	menuOb := new(speech_recognition.SpeechRecognitionTagMenu)
+	//判断是否是挂在顶级目录下
+	tagMenu, err := menuOb.GetItemById(menuId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			errMsg = "当前目录不存在"
+			err = errors.New(errMsg)
+			return
+		}
+		errMsg = "获取失败"
+		err = errors.New("获取目录信息失败,Err:" + err.Error())
+		return
+	}
+
+	cond := fmt.Sprintf(" AND %s = ?", speech_recognition.SpeechRecognitionTagMenuCols.RootId)
+	pars := make([]interface{}, 0)
+	pars = append(pars, tagMenu.RootId)
+	order := fmt.Sprintf("%s ASC, %s ASC, %s ASC", speech_recognition.SpeechRecognitionTagMenuCols.Level, speech_recognition.SpeechRecognitionTagMenuCols.Sort, speech_recognition.SpeechRecognitionTagMenuCols.SpeechRecognitionTagMenuId)
+	tmpList, err := tagMenu.GetItemsByCondition(cond, pars, []string{}, order)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		errMsg = "获取失败"
+		err = errors.New("获取数据失败,Err:" + err.Error())
+		return
+	}
+	idMap := make(map[int]struct{})
+	if len(tmpList) > 0 {
+		for _, v := range tmpList {
+			if v.SpeechRecognitionTagMenuId == tagMenu.SpeechRecognitionTagMenuId {
+				idMap[v.SpeechRecognitionTagMenuId] = struct{}{}
+			}
+		}
+		for _, v := range tmpList {
+			if _, ok := idMap[v.ParentId]; ok {
+				idMap[v.SpeechRecognitionTagMenuId] = struct{}{}
+			}
+		}
+		for _, v := range tmpList {
+			if _, ok := idMap[v.SpeechRecognitionTagMenuId]; ok {
+				targetList = append(targetList, v)
+			}
+		}
+	}
+	return
+}
+
+// GetSpeechTagMenuMaxSort 获取同级下最大的排序
+func GetSpeechTagMenuMaxSort(parentId int) (maxSort int, err error) {
+	menuOb := new(speech_recognition.SpeechRecognitionTagMenu)
+	tagOb := new(speech_recognition.SpeechRecognitionTag)
+
+	//获取该层级下最大的排序数
+	menuMax, err := menuOb.GetMaxSortByParentId(parentId)
+	if err != nil {
+		return
+	}
+	maxSort = menuMax
+	speechMax, err := tagOb.GetMaxSortByMenuId(parentId)
+	if err != nil {
+		return
+	}
+	if maxSort < speechMax {
+		maxSort = speechMax
+	}
+	return
+}
+
+// ------------------ 移动标签目录/标签 ------------------ //