zoie 3 місяців тому
батько
коміт
62d42a4c94

+ 1 - 1
conf/app.conf

@@ -33,7 +33,7 @@ Redis_password = ""
 Redis_dbNum = "2"
 
 FilterExcludeURL = "/Percentage/SyncVerify"
-FilterOnlyLoginCheckURL =
+FilterOnlyLoginCheckURL = "/validationTool/transfer"
 
 # 消息通知前端页面跳转url
 ContractApprovalUrl = "/contract"

+ 62 - 14
controllers/Stock.go

@@ -668,21 +668,32 @@ func (c *StockController) StockIn_Add() {
 	T_date := c.GetString("T_date")
 	T_product := c.GetString("T_product")
 	T_remark := c.GetString("T_remark")
+	T_project := c.GetString("T_project")
+	T_return_user := c.GetString("T_return_user")
 	date, is := lib.DateStrToTime(T_date)
 	if !is {
 		c.Data["json"] = lib.JSONS{Code: 202, Msg: "日期格式错误!"}
 		c.ServeJSON()
 		return
 	}
+
+	if T_type == 2 && len(T_project) == 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "退库时,项目不能为空!"}
+		c.ServeJSON()
+		return
+	}
+
 	NatsServer.AddUserLogs(c.User.T_uuid, "仓库管理", "入库", T_product)
 
 	var_ := Stock.StockIn{
-		T_number:   T_number,
-		T_depot_id: T_depot_id,
-		T_type:     T_type,
-		T_date:     T_date,
-		T_remark:   T_remark,
-		T_submit:   c.User.T_uuid,
+		T_number:      T_number,
+		T_depot_id:    T_depot_id,
+		T_type:        T_type,
+		T_date:        T_date,
+		T_remark:      T_remark,
+		T_submit:      c.User.T_uuid,
+		T_project:     T_project,
+		T_return_user: T_return_user,
 	}
 
 	StockInProductDao := Stock.NewStockInProduct(o)
@@ -722,6 +733,7 @@ func (c *StockController) StockIn_Add() {
 		}
 		if len(T_relation_sn) > 0 {
 			snList := strings.Split(strings.Trim(T_relation_sn, ","), ",")
+			num = len(snList)
 			for _, sn := range snList {
 				mqtt := Stock.Read_MqttUser(sn)
 
@@ -874,6 +886,8 @@ func (c *StockController) StockIn_Edit() {
 	T_date := c.GetString("T_date")
 	T_product := c.GetString("T_product")
 	T_remark := c.GetString("T_remark")
+	T_project := c.GetString("T_project")
+	T_return_user := c.GetString("T_return_user")
 	date, is := lib.DateStrToTime(T_date)
 	if !is {
 		c.Data["json"] = lib.JSONS{Code: 202, Msg: "日期格式错误!"}
@@ -931,10 +945,14 @@ func (c *StockController) StockIn_Edit() {
 		product_id, _ := strconv.Atoi(strings.Split(v, "-")[0])
 		num, _ := strconv.Atoi(strings.Split(v, "-")[1])
 		T_relation_sn := strings.Split(v, "-")[2]
+		snList := lib.SplitString(T_relation_sn, ",")
+		if len(snList) > 0 {
+			num = len(snList)
+		}
 		stockProduct := dto.StockProduct{
 			T_product_id:  product_id,
 			T_num:         num,
-			T_relation_sn: lib.SplitString(T_relation_sn, ","),
+			T_relation_sn: snList,
 		}
 		newProductList = append(newProductList, stockProduct)
 		productNewMap[product_id] = stockProduct
@@ -1197,8 +1215,14 @@ func (c *StockController) StockIn_Edit() {
 	if len(T_date) > 0 {
 		stockIn.T_date = T_date
 	}
+	if len(T_project) > 0 {
+		stockIn.T_project = T_project
+	}
+	if len(T_return_user) > 0 {
+		stockIn.T_return_user = T_return_user
+	}
 
-	err = StockInDao.Update_StockIn(stockIn, "T_remark", "T_date")
+	err = StockInDao.Update_StockIn(stockIn, "T_remark", "T_date", "T_project", "T_return_user")
 	if err != nil {
 		o.Rollback()
 		c.Data["json"] = lib.JSONS{Code: 203, Msg: "修改入库失败"}
@@ -1908,6 +1932,23 @@ func (c *StockController) StockOut_Get() {
 	return
 }
 
+func (c *StockController) StockOut_generate_number() {
+	StockOutDao := Stock.NewStockOut(orm.NewOrm())
+	rand_x := 0
+	T_number := ""
+	for true {
+		T_number = "CK-" + lib.GetRandstring(8, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", int64(rand_x))
+		_, err := StockOutDao.Read_StockOut_ByT_number(T_number)
+		if err != nil && err.Error() == orm.ErrNoRows.Error() {
+			break
+		}
+		rand_x += 1
+	}
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: T_number}
+	c.ServeJSON()
+	return
+}
+
 func (c *StockController) StockOut_Add() {
 
 	rand_x := 0
@@ -2014,7 +2055,8 @@ func (c *StockController) StockOut_Add() {
 		}
 		// 2、更新设备状态为已出库
 		if len(T_relation_sn) > 0 {
-			snList := strings.Split(T_relation_sn, ",")
+			snList := lib.SplitString(T_relation_sn, ",")
+			num = len(snList)
 			for _, sn := range snList {
 				mqtt := Stock.Read_MqttUser(sn)
 				device := Stock.Device{
@@ -2259,10 +2301,14 @@ func (c *StockController) StockOut_Edit() {
 		product_id, _ := strconv.Atoi(strings.Split(v, "-")[0])
 		num, _ := strconv.Atoi(strings.Split(v, "-")[1])
 		T_relation_sn := strings.Split(v, "-")[2]
+		snList := lib.SplitString(T_relation_sn, ",")
+		if len(snList) > 0 {
+			num = len(snList)
+		}
 		stockProduct := dto.StockProduct{
 			T_product_id:  product_id,
 			T_num:         num,
-			T_relation_sn: lib.SplitString(T_relation_sn, ","),
+			T_relation_sn: snList,
 		}
 		newProductList = append(newProductList, stockProduct)
 		productNewMap[product_id] = stockProduct
@@ -3163,7 +3209,6 @@ func generateMonthList(startMonth time.Time, t_type string) []string {
 		endMonth = endMonth.AddDate(0, 1, 0)
 	}
 	for month := startMonth; month.Before(endMonth); month = month.AddDate(0, 1, 0) {
-		fmt.Println("=========================", month.Format("2006-01"))
 		months = append(months, month.Format("2006-01"))
 	}
 	return months
@@ -3701,6 +3746,7 @@ func (c *StockController) StockOut_Audit() {
 	//T_depot_id, _ := c.GetInt("T_depot_id")
 	T_audit, _ := c.GetInt("T_audit")                       // 审核 2财务通过 3财务不通过 4总经理通过 5总经理不通过 6已出库
 	T_approval_opinion := c.GetString("T_approval_opinion") // 审批意见
+	T_approval_img := c.GetString("T_approval_img")         // 审批意见
 	T_type := c.GetString("T_type")                         // 类型 Finance  Manager
 
 	o := orm.NewOrm()
@@ -3718,8 +3764,10 @@ func (c *StockController) StockOut_Audit() {
 	StockOut.T_state = T_audit
 	if T_type == Stock.StockOutTypeFinance {
 		StockOut.T_finance_approval_opinion = T_approval_opinion
+		StockOut.T_finance_approval_img = T_approval_img
 	} else {
 		StockOut.T_manager_approval_opinion = T_approval_opinion
+		StockOut.T_manager_approval_img = T_approval_img
 	}
 
 	if T_audit == Stock.StockOutAuditFinanceUnPass || T_audit == Stock.StockOutAuditManagerUnPass {
@@ -3736,7 +3784,7 @@ func (c *StockController) StockOut_Audit() {
 		}
 	}
 
-	err = StockOutDao.Update_StockOut(StockOut, "T_state", "T_finance_approval_opinion", "T_manager_approval_opinion")
+	err = StockOutDao.Update_StockOut(StockOut, "T_state", "T_finance_approval_opinion", "T_manager_approval_opinion", "T_finance_approval_img", "T_manager_approval_img")
 	if err != nil {
 		o.Rollback()
 		c.Data["json"] = lib.JSONS{Code: 203, Msg: "出库审批失败"}
@@ -3805,9 +3853,9 @@ func (c *StockController) StockOut_Warehouse() {
 		}
 
 		snList := strings.Split(T_relation_sn, ",")
-		if num != len(snList) {
+		if product.T_relation_sn == 1 && num != len(snList) {
 			o.Rollback()
-			c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("%sSN数量与出库数量不一致,请核查!", product.T_name)}
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("%s SN数量与出库数量不一致,请核查!", product.T_name)}
 			c.ServeJSON()
 			return
 		}

+ 277 - 206
controllers/Validation.go

@@ -3,6 +3,7 @@ package controllers
 import (
 	"ERP_storage/Nats/NatsServer"
 	"ERP_storage/conf"
+	"ERP_storage/dto"
 	"ERP_storage/logs"
 	"ERP_storage/models/Account"
 	"ERP_storage/models/Basic"
@@ -943,67 +944,39 @@ func (c *ValidationController) Operation_Excel() {
 	c.Ctx.Output.Download(filePath, fileName)
 }
 
-// 设备转移请求结构体
-type TransferValidationToolRequest struct {
-	T_sn          []string `json:"T_sn"`
-	CurrentUser   string `json:"CurrentUser"`
-	TargetUser    string `json:"TargetUser"`
-	TransferRemark string `json:"TransferRemark"` // 转移备注
-}
-
-// 设备转移结果结构体
-type TransferResult struct {
-	T_sn         string `json:"T_sn"`
-	Success      bool   `json:"success"`
-	Message      string `json:"message"`
-	Status       string `json:"status"`
-}
-
 // 检查所有转移结果是否都失败
-func allFailed(results []TransferResult) bool {
+func allSuccess(results []dto.TransferResult) bool {
 	for _, r := range results {
-		if r.Success {
+		if !r.Success {
 			return false
 		}
 	}
 	return true
 }
 
-// 检查是否有任何转移结果成功
-func anySuccess(results []TransferResult) bool {
-	for _, r := range results {
-		if r.Success {
-			return true
-		}
-	}
-	return false
-}
-
 // 设备转移请求
-func (c *ValidationController) TransferValidationTool() {
-	var request TransferValidationToolRequest
-	err := json.Unmarshal(c.Ctx.Input.RequestBody, &request)
-	if err != nil {
-		c.Data["json"] = lib.JSONS{Code: 1201, Msg: "json 序列化失败!", Data: nil}
+func (c *ValidationController) Transfer() {
+
+	request := dto.TransferValidationToolReq{}
+
+	if err := c.ParseForm(&request); err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "参数错误"}
 		c.ServeJSON()
 		return
 	}
-
-	// 验证参数
-	if len(request.T_sn) <= 0 {
-		c.Data["json"] = lib.JSONS{Code: 1201, Msg: "T_sn不能为空!", Data: nil}
+	if err := json.Unmarshal([]byte(request.T_sn), &request.T_sn_List); err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "sn 参数错误"}
 		c.ServeJSON()
 		return
 	}
-
-	if len(request.TargetUser) <= 0 {
-		c.Data["json"] = lib.JSONS{Code: 1201, Msg: "目标借出用户不能为空!", Data: nil}
+	if err := Validate(&request); err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
 		c.ServeJSON()
 		return
 	}
 
-	if request.CurrentUser == request.TargetUser {
-		c.Data["json"] = lib.JSONS{Code: 1201, Msg: "目标用户不能与当前用户相同!", Data: nil}
+	if c.User.T_name == request.AcceptedUser {
+		c.Data["json"] = lib.JSONS{Code: 1201, Msg: "调用人不能与接收人相同!", Data: nil}
 		c.ServeJSON()
 		return
 	}
@@ -1014,11 +987,11 @@ func (c *ValidationController) TransferValidationTool() {
 	valiRecord := validationtool.NewValidationToolRecord(o)
 	BatchNumber := time.Now().Format("2006-01-02 15:04:05")
 
-	var results []TransferResult
+	var results []dto.TransferResult
 
 	// 遍历所有SN进行检查和更新
-	for _, sn := range request.T_sn {
-		result := TransferResult{T_sn: sn, Success: false, Status: "failed"}
+	for _, sn := range request.T_sn_List {
+		result := dto.TransferResult{T_sn: sn, Success: false, Status: "failed"}
 
 		validation, err2 := vali.ReadValidationBytSn(sn)
 		if err2 != nil {
@@ -1031,15 +1004,15 @@ func (c *ValidationController) TransferValidationTool() {
 			continue
 		}
 
-		// 检查设备当前状态是否为已出库
-		if validation.T_state != validationtool.ValidationToolStateStockOut {
+		// 检查设备当前状态是否为已出库或已损坏状态
+		if validation.T_state != validationtool.ValidationToolStateStockOut && validation.T_state != validationtool.ValidationToolStateStockDamage {
 			result.Message = fmt.Sprintf("当前sn:%v 未出库,无法进行转移", sn)
 			results = append(results, result)
 			continue
 		}
 
 		// 检查当前借出用户是否匹配
-		if validation.LendUser != request.CurrentUser {
+		if validation.LendUser != c.User.T_name {
 			result.Message = fmt.Sprintf("当前sn:%v 的借出用户与请求不符", sn)
 			results = append(results, result)
 			continue
@@ -1047,34 +1020,27 @@ func (c *ValidationController) TransferValidationTool() {
 
 		// 检查设备是否已经在转移中
 		if validation.T_state == validationtool.ValidationToolStateTransferring {
-			result.Message = fmt.Sprintf("当前sn:%v 正在转移中,请等待对方确认或取消当前转移", sn)
+			result.Message = fmt.Sprintf("当前sn:%v 正在转移中,请等待对方确认或取消当前转移[%s->%s]", sn, c.User.T_name, request.AcceptedUser)
 			results = append(results, result)
 			continue
 		}
 
-		// 修改设备状态和备注,记录转移信息
-		originalRemark := validation.T_remark
-		transferInfo := fmt.Sprintf("[转移请求] 从 %s 转移至 %s", request.CurrentUser, request.TargetUser)
-		if len(request.TransferRemark) > 0 {
-			transferInfo += fmt.Sprintf(",备注:%s", request.TransferRemark)
-		}
-		if len(originalRemark) > 0 {
-			validation.T_remark = originalRemark + "\n" + transferInfo
-		} else {
-			validation.T_remark = transferInfo
-		}
-
 		// 设置转移中的状态
 		validation.T_state = validationtool.ValidationToolStateTransferring
-		
-		cols := []string{"T_remark", "T_state"}
-		err = vali.UpdateValidationTool(validation, cols...)
+		validation.T_remark = request.Remark
+		cols := []string{"T_remark", "T_state", "T_remark"}
+		err := vali.UpdateValidationTool(validation, cols...)
 		if err != nil {
 			result.Message = fmt.Sprintf("更新设备sn:%v 状态失败", sn)
 			results = append(results, result)
 			continue
 		}
-		
+
+		var separator string
+		if len(request.Remark) > 0 {
+			separator = " "
+		}
+		validation.T_remark = request.Remark + fmt.Sprintf("%s正在转移[%s->%s]", separator, c.User.T_name, request.AcceptedUser)
 		_, err = valiRecord.ADD(validation, BatchNumber)
 		if err != nil {
 			result.Message = fmt.Sprintf("保存sn:%v 历史记录失败", sn)
@@ -1082,92 +1048,69 @@ func (c *ValidationController) TransferValidationTool() {
 			continue
 		}
 		result.Success = true
-		result.Status = "pending"
+		result.Status = validationtool.TransferPending
 		result.Message = fmt.Sprintf("sn:%v 转移请求已发送", sn)
 		results = append(results, result)
 
 	}
 
-	if anySuccess(results) {
-		// 创建转移记录到新表
-		snListJSON, err := json.Marshal(request.T_sn)
-		if err != nil {
-			o.Rollback()
-			c.Data["json"] = lib.JSONS{Code: 1201, Msg: "T_sn列表序列化失败!", Data: nil}
-			c.ServeJSON()
-			return
-		}
-		transferRecord := validationtool.ValidationToolTransfer{
-			T_sn:     string(snListJSON),
-			FromUser: request.CurrentUser,
-			ToUser:   request.TargetUser,
-			Status:   "pending",
-			Remark:   request.TransferRemark,
-		}
+	// 任意一个不成功都回滚
+	if !allSuccess(results) {
+		o.Rollback() // 如果没有一个成功,则回滚所有操作
+		c.Data["json"] = lib.JSONS{Code: 1201, Msg: "转移失败!", Data: results}
+		c.ServeJSON()
+		return
+	}
 
-		transferTool := validationtool.NewValidationToolTransfer(o)
-		_, err = transferTool.Add(&transferRecord)
-		if err != nil {
-			o.Rollback()
-			c.Data["json"] = lib.JSONS{Code: 1201, Msg: "创建转移记录失败!", Data: nil}
-			c.ServeJSON()
-			return
-		}
+	transferRecord := validationtool.ValidationToolTransfer{
+		TransferSn:      request.T_sn,
+		TransferUser:    c.User.T_name,
+		TransferUserUid: c.User.T_uuid,
+		AcceptedUser:    request.AcceptedUser,
+		AcceptedUserUid: request.AcceptedUserUid,
+		Status:          validationtool.TransferPending,
+		TransferRemark:  request.Remark,
+	}
 
-		err = o.Commit() // 提交事务
-		if err != nil {
-			o.Rollback() // 回滚事务
-			c.Data["json"] = lib.JSONS{Code: 1201, Msg: "提交事务失败!", Data: nil}
-			c.ServeJSON()
-			return
-		}
+	transferTool := validationtool.NewValidationToolTransfer(o)
+	_, err := transferTool.Add(&transferRecord)
+	if err != nil {
+		o.Rollback()
+		c.Data["json"] = lib.JSONS{Code: 1201, Msg: "创建转移记录失败!", Data: nil}
+		c.ServeJSON()
+		return
+	}
 
-		NatsServer.AddUserLogs(c.User.T_uuid, "验证工具", "转移请求", request.T_sn)
-		c.Data["json"] = lib.JSONS{Code: 200, Msg: "批量转移请求处理完成", Data: results}
+	err = o.Commit() // 提交事务
+	if err != nil {
+		o.Rollback() // 回滚事务
+		c.Data["json"] = lib.JSONS{Code: 1201, Msg: "提交事务失败!", Data: nil}
 		c.ServeJSON()
 		return
 	}
 
-	o.Rollback() // 如果没有一个成功,则回滚所有操作
-	c.Data["json"] = lib.JSONS{Code: 1201, Msg: "所有SN转移失败", Data: results}
+	NatsServer.AddUserLogs(c.User.T_uuid, "验证工具", "发起转移", request.T_sn)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "发起转移成功", Data: results}
 	c.ServeJSON()
 	return
 }
 
-// 确认接收设备请求结构体
-type ConfirmTransferValidationTool struct {
-	T_sn         []string `json:"T_sn"`
-	ConfirmUser  string `json:"ConfirmUser"`  // 确认接收的用户
-	// 添加设备信息字段用于比对
-	DeviceInfo   map[string]interface{} `json:"DeviceInfo"` // 设备信息用于比对
-}
-
-// 设备一致性比对结果结构体
-type DeviceComparisonResult struct {
-	Field       string `json:"field"`
-	Expected    string `json:"expected"`
-	Actual      string `json:"actual"`
-}
-
 // 确认接收设备
-func (c *ValidationController) ConfirmTransferValidationTool() {
-	var request ConfirmTransferValidationTool
-	err := json.Unmarshal(c.Ctx.Input.RequestBody, &request)
-	if err != nil {
-		c.Data["json"] = lib.JSONS{Code: 1201, Msg: "json 序列化失败!", Data: nil}
-		c.ServeJSON()
-		return
-	}
+func (c *ValidationController) ConfirmAccepted() {
+	var request dto.ConfirmTransferValidationToolReq
 
-	// 验证参数
-	if len(request.T_sn) <= 0 {
-		c.Data["json"] = lib.JSONS{Code: 1201, Msg: "T_sn不能为空!", Data: nil}
+	if err := c.ParseForm(&request); err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "参数错误"}
 		c.ServeJSON()
 		return
 	}
-
-	if len(request.ConfirmUser) <= 0 {
-		c.Data["json"] = lib.JSONS{Code: 1201, Msg: "确认用户不能为空!", Data: nil}
+	//if err := json.Unmarshal([]byte(request.T_sn), &request.T_sn_List); err != nil {
+	//	c.Data["json"] = lib.JSONS{Code: 202, Msg: "sn 参数错误"}
+	//	c.ServeJSON()
+	//	return
+	//}
+	if err := Validate(&request); err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
 		c.ServeJSON()
 		return
 	}
@@ -1177,113 +1120,195 @@ func (c *ValidationController) ConfirmTransferValidationTool() {
 	vali := validationtool.NewValidationTool(o)
 	valiRecord := validationtool.NewValidationToolRecord(o)
 	BatchNumber := time.Now().Format("2006-01-02 15:04:05")
+	transfer := validationtool.NewValidationToolTransfer(o)
+
+	// 查询待处理的转移记录
+	transferRecord, err := transfer.GetPendingTransferById(request.TransferId)
+	if err != nil {
+		o.Rollback()
+		c.Data["json"] = lib.JSONS{Code: 1201, Msg: fmt.Sprintf("当前sn:%v 没有待确认的转移请求", request.T_sn), Data: nil}
+		c.ServeJSON()
+		return
+	}
 
-	// 查询设备信息
-	validation, err2 := vali.ReadValidationBytSn(request.T_sn)
-	if err2 != nil {
+	// 检查确认用户是否为目标用户
+	if transferRecord.AcceptedUser != c.User.T_name {
 		o.Rollback()
-		if err2.Error() == orm.ErrNoRows.Error() {
-			c.Data["json"] = lib.JSONS{Code: 1201, Msg: fmt.Sprintf("当前sn:%v 未入库", request.T_sn), Data: nil}
+		c.Data["json"] = lib.JSONS{Code: 1201, Msg: "您不是当前调用单的目标接收用户", Data: nil}
+		c.ServeJSON()
+		return
+	}
+	transferRecord_R := validationtool.ValidationToolTransferTo_R(transferRecord)
+	// 遍历所有SN进行检查和更新
+	for _, sn := range transferRecord_R.TransferSn {
+
+		// 查询设备信息
+		validation, err2 := vali.ReadValidationBytSn(sn)
+		if err2 != nil {
+			o.Rollback()
+			if err2.Error() == orm.ErrNoRows.Error() {
+				c.Data["json"] = lib.JSONS{Code: 1201, Msg: fmt.Sprintf("当前sn:%v 未入库", sn), Data: nil}
+				c.ServeJSON()
+				return
+			} else {
+				c.Data["json"] = lib.JSONS{Code: 1201, Msg: fmt.Sprintf("查询sn:%v 失败", sn), Data: nil}
+				c.ServeJSON()
+				return
+			}
+		}
+
+		// 检查设备是否在转移中
+		if validation.T_state != validationtool.ValidationToolStateTransferring {
+			o.Rollback()
+			c.Data["json"] = lib.JSONS{Code: 1201, Msg: fmt.Sprintf("当前sn:%v 不在转移状态", sn), Data: nil}
 			c.ServeJSON()
 			return
-		} else {
-			c.Data["json"] = lib.JSONS{Code: 1201, Msg: fmt.Sprintf("查询sn:%v 失败", request.T_sn), Data: nil}
+		}
+
+		// 更新借出用户
+		validation.LendUser = c.User.T_name
+		// 将状态改回已出库
+		validation.T_state = validationtool.ValidationToolStateStockOut
+		validation.T_project = request.Project
+		validation.T_remark = request.Remark
+
+		cols := []string{"LendUser", "T_project", "T_state", "T_remark"}
+		err = vali.UpdateValidationTool(validation, cols...)
+		if err != nil {
+			o.Rollback()
+			c.Data["json"] = lib.JSONS{Code: 1201, Msg: "修改失败!", Data: nil}
+			c.ServeJSON()
+			return
+		}
+
+		var separator string
+		if len(request.Remark) > 0 {
+			separator = " "
+		}
+		validation.T_remark = request.Remark + fmt.Sprintf("%s确认已接收[%s->%s]", separator, transferRecord.TransferUser, c.User.T_name)
+		validation.T_state = validationtool.ValidationToolStateAccepted
+		_, err = valiRecord.ADD(validation, BatchNumber)
+		if err != nil {
+			o.Rollback() // 回滚事务
+			c.Data["json"] = lib.JSONS{Code: 1201, Msg: "保存历史记录失败!", Data: nil}
 			c.ServeJSON()
 			return
 		}
 	}
 
-	// 检查设备是否在转移中
-	if validation.T_state != validationtool.ValidationToolStateTransferring {
+	transferRecord.Status = validationtool.TransferCompleted
+	transferRecord.AcceptedNumber = request.Number
+	transferRecord.AcceptedRemark = request.Remark
+	transferRecord.AcceptedTime = time.Now()
+	transferTool := validationtool.NewValidationToolTransfer(o)
+	err = transferTool.Update(transferRecord, "Status", "AcceptedRemark", "AcceptedNumber", "AcceptedTime")
+	if err != nil {
 		o.Rollback()
-		c.Data["json"] = lib.JSONS{Code: 1201, Msg: fmt.Sprintf("当前sn:%v 不在转移状态", request.T_sn), Data: nil}
+		c.Data["json"] = lib.JSONS{Code: 1201, Msg: "更新转移记录失败!", Data: nil}
 		c.ServeJSON()
 		return
 	}
 
-	// 查询待处理的转移记录
+	err = o.Commit() // 提交事务
+	if err != nil {
+		o.Rollback() // 回滚事务
+		c.Data["json"] = lib.JSONS{Code: 1201, Msg: "提交事务失败!", Data: nil}
+		c.ServeJSON()
+		return
+	}
+
+	NatsServer.AddUserLogs(c.User.T_uuid, "验证工具", "确认转移", request.TransferId)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "设备转移确认成功!", Data: request.TransferId}
+	c.ServeJSON()
+	return
+}
+
+// 取消调用
+func (c *ValidationController) CancelTransfer() {
+	TransferId, _ := c.GetInt("TransferId")
+
+	o := orm.NewOrm()
+	o.Begin()
+	vali := validationtool.NewValidationTool(o)
+	valiRecord := validationtool.NewValidationToolRecord(o)
+	BatchNumber := time.Now().Format("2006-01-02 15:04:05")
 	transfer := validationtool.NewValidationToolTransfer(o)
-	transferRecord, err := transfer.GetPendingTransferBySn(request.T_sn)
+
+	// 查询待处理的转移记录
+	transferRecord, err := transfer.GetPendingTransferById(TransferId)
 	if err != nil {
 		o.Rollback()
-		c.Data["json"] = lib.JSONS{Code: 1201, Msg: fmt.Sprintf("当前sn:%v 没有待确认的转移请求", request.T_sn), Data: nil}
+		c.Data["json"] = lib.JSONS{Code: 1201, Msg: "查询调用记录失败", Data: nil}
 		c.ServeJSON()
 		return
 	}
 
 	// 检查确认用户是否为目标用户
-	if transferRecord.ToUser != request.ConfirmUser {
+	if transferRecord.TransferUser != c.User.T_name {
 		o.Rollback()
-		c.Data["json"] = lib.JSONS{Code: 1201, Msg: fmt.Sprintf("您不是当前sn:%v 的目标接收用户", request.T_sn), Data: nil}
+		c.Data["json"] = lib.JSONS{Code: 1201, Msg: "您不是当前转移单的发起用户", Data: nil}
 		c.ServeJSON()
 		return
 	}
+	transferRecord_R := validationtool.ValidationToolTransferTo_R(transferRecord)
+	// 遍历所有SN进行检查和更新
+	for _, sn := range transferRecord_R.TransferSn {
 
-	// 设备一致性比对
-	var comparisonResults []DeviceComparisonResult
-
-	// 如果提供了设备信息进行比对
-	if request.DeviceInfo != nil {
-		// 比对T_iccid
-		if iccid, ok := request.DeviceInfo["T_iccid"].(string); ok && iccid != validation.T_iccid {
-			comparisonResults = append(comparisonResults, DeviceComparisonResult{
-				Field:    "T_iccid",
-				Expected: validation.T_iccid,
-				Actual:   iccid,
-			})
+		// 查询设备信息
+		validation, err2 := vali.ReadValidationBytSn(sn)
+		if err2 != nil {
+			o.Rollback()
+			if err2.Error() == orm.ErrNoRows.Error() {
+				c.Data["json"] = lib.JSONS{Code: 1201, Msg: fmt.Sprintf("当前sn:%v 未入库", sn), Data: nil}
+				c.ServeJSON()
+				return
+			} else {
+				c.Data["json"] = lib.JSONS{Code: 1201, Msg: fmt.Sprintf("查询sn:%v 失败", sn), Data: nil}
+				c.ServeJSON()
+				return
+			}
 		}
 
-		// 比对T_imei
-		if imei, ok := request.DeviceInfo["T_imei"].(string); ok && imei != validation.T_imei {
-			comparisonResults = append(comparisonResults, DeviceComparisonResult{
-				Field:    "T_imei",
-				Expected: validation.T_imei,
-				Actual:   imei,
-			})
+		// 检查设备是否在转移中
+		if validation.T_state != validationtool.ValidationToolStateTransferring {
+			o.Rollback()
+			c.Data["json"] = lib.JSONS{Code: 1201, Msg: fmt.Sprintf("当前sn:%v 不在转移状态", sn), Data: nil}
+			c.ServeJSON()
+			return
 		}
 
-		// 比对T_class
-		if class, ok := request.DeviceInfo["T_class"]; ok {
-			classStr := fmt.Sprintf("%v", class)
-			if classStr != fmt.Sprintf("%v", validation.T_class) {
-				comparisonResults = append(comparisonResults, DeviceComparisonResult{
-					Field:    "T_class",
-					Expected: fmt.Sprintf("%v", validation.T_class),
-					Actual:   classStr,
-				})
-			}
-		}
+		// 更新借出用户
+		validation.LendUser = c.User.T_name
+		// 将状态改回已出库
+		validation.T_state = validationtool.ValidationToolStateStockOut
 
-		// 如果比对结果不一致,返回不一致信息
-		if len(comparisonResults) > 0 {
+		cols := []string{"LendUser", "T_state"}
+		err = vali.UpdateValidationTool(validation, cols...)
+		if err != nil {
 			o.Rollback()
-			c.Data["json"] = lib.JSONS{Code: 1201, Msg: "设备信息比对不一致", Data: comparisonResults}
+			c.Data["json"] = lib.JSONS{Code: 1201, Msg: "修改失败!", Data: nil}
 			c.ServeJSON()
 			return
 		}
-	}
 
-	// 更新借出用户
-	validation.LendUser = request.ConfirmUser
-	// 将状态改回已出库
-	validation.T_state = validationtool.ValidationToolStateStockOut
-	// 在备注中记录转移确认信息
-	confirmInfo := fmt.Sprintf("[转移完成] %s 确认接收", request.ConfirmUser)
-	validation.T_remark += "\n" + confirmInfo
-
-	cols := []string{"LendUser", "T_remark", "T_state"}
-	err = vali.UpdateValidationTool(validation, cols...)
-	if err != nil {
-		o.Rollback()
-		c.Data["json"] = lib.JSONS{Code: 1201, Msg: "修改失败!", Data: nil}
-		c.ServeJSON()
-		return
+		validation.T_remark = "取消转移"
+		validation.T_state = validationtool.ValidationToolStateCancelTransfer
+		_, err = valiRecord.ADD(validation, BatchNumber)
+		if err != nil {
+			o.Rollback() // 回滚事务
+			c.Data["json"] = lib.JSONS{Code: 1201, Msg: "保存历史记录失败!", Data: nil}
+			c.ServeJSON()
+			return
+		}
 	}
 
-	_, err = valiRecord.ADD(validation, BatchNumber)
+	transferRecord.Status = validationtool.TransferCanceled
+	transferTool := validationtool.NewValidationToolTransfer(o)
+	err = transferTool.Update(transferRecord, "Status")
 	if err != nil {
-		o.Rollback() // 回滚事务
-		c.Data["json"] = lib.JSONS{Code: 1201, Msg: "保存历史记录失败!", Data: nil}
+		o.Rollback()
+		c.Data["json"] = lib.JSONS{Code: 1201, Msg: "更新转移记录失败!", Data: nil}
 		c.ServeJSON()
 		return
 	}
@@ -1296,19 +1321,65 @@ func (c *ValidationController) ConfirmTransferValidationTool() {
 		return
 	}
 
-	NatsServer.AddUserLogs(c.User.T_uuid, "验证工具", "确认转移", []string{request.T_sn})
+	NatsServer.AddUserLogs(c.User.T_uuid, "验证工具", "取消转移", TransferId)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "设备取消转移成功!", Data: TransferId}
+	c.ServeJSON()
+	return
+}
 
-	// 返回转移结果
-	result := TransferResult{
-		T_sn:    request.T_sn,
-		Success: true,
-		Message: "设备转移确认成功!",
-		Status:  "completed",
+// GetTransferRecords 获取转移人的转移记录
+// @router /transfer/records [get]
+func (c *ValidationController) TransferRecords_List() {
+	// 分页参数 初始化
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
 	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+	status := c.GetString("status")
+	// 查询转移记录
+	o := orm.NewOrm()
+	vali := validationtool.NewValidationToolTransfer(o)
+	R_List, R_cnt := vali.GetTransferRecordsByUser(c.User.T_uuid, status, page, page_z)
+	var r_jsons lib.R_JSONS
+	r_jsons.Num = R_cnt
+	r_jsons.Data = R_List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(math.Ceil(float64(R_cnt) / float64(page_z)))
 
-	c.Data["json"] = lib.JSONS{Code: 200, Msg: "设备转移确认成功!", Data: result}
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
 	c.ServeJSON()
 	return
 }
 
-// ... existing code ...
+// GetPendingRecords 获取接收人的待接收记录
+// @router /transfer/pending [get]
+func (c *ValidationController) AcceptedRecords_List() {
+	// 分页参数 初始化
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+	status := c.GetString("status")
+	// 查询待接收记录
+	o := orm.NewOrm()
+	vali := validationtool.NewValidationToolTransfer(o)
+	R_List, R_cnt := vali.GetAcceptedRecordsByUser(c.User.T_uuid, status, page, page_z)
+	var r_jsons lib.R_JSONS
+	r_jsons.Num = R_cnt
+	r_jsons.Data = R_List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(math.Ceil(float64(R_cnt) / float64(page_z)))
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}

+ 28 - 0
dto/validationtool.go

@@ -0,0 +1,28 @@
+package dto
+
+// 设备转移请求结构体
+type TransferValidationToolReq struct {
+	T_sn            string `form:"T_sn" vd:"len($)>0;msg:'sn不能为空'"`
+	AcceptedUser    string `form:"AcceptedUser" vd:"len($)>0;msg:'接收人不能为空'"`
+	AcceptedUserUid string `form:"AcceptedUserUid"`
+	Remark          string `form:"Remark"` // 转移备注
+	T_sn_List       []string
+}
+
+// 设备转移结果结构体
+type TransferResult struct {
+	T_sn    string
+	Success bool
+	Message string
+	Status  string
+}
+
+// 确认接收设备请求结构体
+type ConfirmTransferValidationToolReq struct {
+	TransferId int    `form:"TransferId" vd:"$>0;msg:'id不能为空'"`
+	T_sn       string `form:"T_sn"`                                 // 如果后期接收sn需要传入再做处理
+	Project    string `form:"Project" vd:"len($)>0;msg:'出库项目不能为空'"` // 备注
+	Remark     string `form:"Remark"`                               // 接收备注
+	Number     int    `form:"Number"`                               // 接收数量
+	T_sn_List  []string
+}

+ 1 - 1
go.mod

@@ -14,7 +14,7 @@ require (
 	github.com/smartystreets/goconvey v1.8.1
 	github.com/vmihailenco/msgpack/v5 v5.3.5
 	github.com/xuri/excelize/v2 v2.9.0
-	gogs.baozhida.cn/zoie/ERP_libs v0.0.0-20250421082929-038047d473e1
+	gogs.baozhida.cn/zoie/ERP_libs v0.0.0-20250901061433-cb5c3676aa11
 	gorm.io/driver/mysql v1.5.7
 	gorm.io/gorm v1.25.11
 )

+ 2 - 0
go.sum

@@ -362,6 +362,8 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 gogs.baozhida.cn/zoie/ERP_libs v0.0.0-20250421082929-038047d473e1 h1:Tc4YfrvTkAXhHK2JyTn4kbmyHUH+evXF7M7FYEjZXno=
 gogs.baozhida.cn/zoie/ERP_libs v0.0.0-20250421082929-038047d473e1/go.mod h1:wS/rgL1FkdfMsCwKpwG04dZtG4SOFcBADi4lxHN7UeM=
+gogs.baozhida.cn/zoie/ERP_libs v0.0.0-20250901061433-cb5c3676aa11 h1:aMuM32qXdOojinJW9w9rm0tSopDvD5eecI14YXnwMdA=
+gogs.baozhida.cn/zoie/ERP_libs v0.0.0-20250901061433-cb5c3676aa11/go.mod h1:wS/rgL1FkdfMsCwKpwG04dZtG4SOFcBADi4lxHN7UeM=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=

+ 1 - 1
models/Basic/Product.go

@@ -266,7 +266,7 @@ func Read_ProductModel_List(T_name string) (lists orm2.ParamsList) {
 func Read_ProductName_List(T_name string, T_class int) (lists orm2.ParamsList) {
 	o := orm.NewOrm()
 	var pl_lists orm2.ParamsList
-	sql := "SELECT DISTINCT t_name FROM product WHERE t_class > 0 AND t_name like '%" + T_name + "%'"
+	sql := "SELECT DISTINCT t_name FROM product WHERE t_class > 0 AND t__state > 0 AND t_name like '%" + T_name + "%'"
 	if T_class > 0 {
 		sql += " AND T_class = " + strconv.Itoa(T_class)
 	}

+ 42 - 29
models/Stock/StockIn.go

@@ -17,15 +17,17 @@ import (
 
 // 入库
 type StockIn struct {
-	Id         int       `orm:"column(ID);size(11);auto;pk"`
-	T_number   string    `orm:"size(256);null"`                                        // 入库单号
-	T_type     int       `orm:"size(256);;default(1)"`                                 // 入库类型 1-入库 2-退库
-	T_depot_id int       `orm:"size(20);null"`                                         // 仓库id
-	T_date     string    `orm:"size(256);null"`                                        // 业务日期
-	T_submit   string    `orm:"size(256);null"`                                        // 经办人
-	T_remark   string    `orm:"type(text);null"`                                       // 备注
-	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
-	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
+	Id            int       `orm:"column(ID);size(11);auto;pk"`
+	T_number      string    `orm:"size(256);null"`                                        // 入库单号
+	T_type        int       `orm:"size(256);;default(1)"`                                 // 入库类型 1-入库 2-退库
+	T_depot_id    int       `orm:"size(20);null"`                                         // 仓库id
+	T_date        string    `orm:"size(256);null"`                                        // 业务日期
+	T_submit      string    `orm:"size(256);null"`                                        // 经办人
+	T_remark      string    `orm:"type(text);null"`                                       // 备注
+	T_project     string    `orm:"type(text);null"`                                       // 退库项目
+	T_return_user string    `orm:"type(text);null"`                                       // 退库人
+	CreateTime    time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+	UpdateTime    time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
 }
 
 func (t *StockIn) TableName() string {
@@ -46,28 +48,34 @@ func init() {
 }
 
 type StockIn_R struct {
-	Id            int
-	T_number      string
-	T_type        int
-	T_depot_id    int
-	T_depot_name  string
-	T_date        string
-	T_submit      string
-	T_submit_name string
-	T_remark      string
+	Id                 int
+	T_number           string
+	T_type             int
+	T_depot_id         int
+	T_depot_name       string
+	T_date             string
+	T_submit           string
+	T_submit_name      string
+	T_remark           string
+	T_project          string
+	T_return_user      string
+	T_return_user_name string
 }
 
 type StockIn_Detail struct {
-	Id            int
-	T_number      string
-	T_type        int
-	T_depot_id    int
-	T_depot_name  string
-	T_date        string
-	T_submit      string
-	T_submit_name string
-	T_remark      string
-	T_Product     []StockInProduct_R
+	Id                 int
+	T_number           string
+	T_type             int
+	T_depot_id         int
+	T_depot_name       string
+	T_date             string
+	T_submit           string
+	T_submit_name      string
+	T_remark           string
+	T_project          string
+	T_return_user      string
+	T_return_user_name string
+	T_Product          []StockInProduct_R
 }
 
 func StockInToStockIn_R(t StockIn) (r StockIn_R) {
@@ -80,6 +88,9 @@ func StockInToStockIn_R(t StockIn) (r StockIn_R) {
 	r.T_submit = t.T_submit
 	r.T_submit_name = Account.Read_User_T_name_Get(t.T_submit)
 	r.T_remark = t.T_remark
+	r.T_project = t.T_project
+	r.T_return_user = t.T_return_user
+	r.T_return_user_name = Account.Read_User_T_name_Get(t.T_return_user)
 	return r
 }
 
@@ -94,7 +105,9 @@ func StockInToStockIn_Detail(t StockIn, productList []StockInProduct_R) (r Stock
 	r.T_submit_name = Account.Read_User_T_name_Get(t.T_submit)
 	r.T_remark = t.T_remark
 	r.T_Product = productList
-
+	r.T_project = t.T_project
+	r.T_return_user = t.T_return_user
+	r.T_return_user_name = Account.Read_User_T_name_Get(t.T_return_user)
 	return r
 }
 

+ 7 - 5
models/Stock/StockOut.go

@@ -84,6 +84,8 @@ type StockOut struct {
 	T_state                    int    `orm:"size(2);column(t_state);default(6)"` // 0 删除 1待审核  2财务通过 3财务不通过 4总经理通过 5总经理不通过 6已出库
 	T_finance_approval_opinion string `orm:"size(256);null"`                     // 财务审批意见
 	T_manager_approval_opinion string `orm:"size(256);null"`                     // 总经理审批意见
+	T_finance_approval_img     string `orm:"size(256);null"`                     // 财务审批意见
+	T_manager_approval_img     string `orm:"size(256);null"`                     // 总经理审批意见
 
 	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
 	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
@@ -322,7 +324,7 @@ func (dao *StockOutDaoImpl) Read_StockOut_Audit_List(T_uuid, T_name, T_type stri
 	cond := orm.NewCondition()
 
 	if T_type == StockOutTypeApply {
-		cond = cond.And("T_submit", T_uuid)
+		cond = cond.And("T_receive", T_uuid)
 	}
 
 	if T_type == StockOutTypeFinance {
@@ -334,10 +336,10 @@ func (dao *StockOutDaoImpl) Read_StockOut_Audit_List(T_uuid, T_name, T_type stri
 			OrCond(cond1.And("T_state", StockOutWaitAudit).And("T_payment_method__in", []string{StockOutPaymentMethodC, StockOutPaymentMethodD})))
 	}
 
-	if T_type == StockOutTypeWarehouse {
-		cond = cond.AndCond(cond.And("T_state", StockOutAuditManagerPass).
-			OrCond(cond1.And("T_state", StockOutAlreadyOut).And("T_warehouse", T_uuid)))
-	}
+	//if T_type == StockOutTypeWarehouse {
+	//	cond = cond.AndCond(cond.And("T_state", StockOutAuditManagerPass).
+	//		OrCond(cond1.And("T_state", StockOutAlreadyOut)))
+	//}
 
 	if T_depot_id > 0 {
 		cond = cond.And("T_depot_id", T_depot_id)

+ 12 - 6
models/validationtool/validation.go

@@ -17,15 +17,21 @@ const (
 	ValidationToolStateStockRepair
 	ValidationToolStateStockScrap
 	ValidationToolStateStockDamage
+	ValidationToolStateTransferring
+	ValidationToolStateCancelTransfer
+	ValidationToolStateAccepted
 )
 
 var (
 	ValidationToolStateMap = map[int]string{
-		ValidationToolStateStockOut:    "已出库",
-		ValidationToolStateStockIn:     "未出库",
-		ValidationToolStateStockRepair: "维修中",
-		ValidationToolStateStockScrap:  "已报废",
-		ValidationToolStateStockDamage: "已损坏",
+		ValidationToolStateStockOut:       "已出库",
+		ValidationToolStateStockIn:        "未出库",
+		ValidationToolStateStockRepair:    "维修中",
+		ValidationToolStateStockScrap:     "已报废",
+		ValidationToolStateStockDamage:    "已损坏",
+		ValidationToolStateTransferring:   "转移中",
+		ValidationToolStateCancelTransfer: "取消转移",
+		ValidationToolStateAccepted:       "已接收",
 	}
 )
 
@@ -237,7 +243,7 @@ func (dao *ValidationImpl) Validation_stat(LendUser, T_project string, page, pag
 
 	sql = sql + sqlWhere
 
-	sql += " GROUP BY lend_user,t_project ORDER BY lend_user"
+	sql += " GROUP BY lend_user,t_project,t_state ORDER BY lend_user"
 
 	var maps_z []orm2.ParamsList
 	// 获取总条数

+ 217 - 0
models/validationtool/validationTransfer.go

@@ -0,0 +1,217 @@
+package validationtool
+
+import (
+	"ERP_storage/logs"
+	"encoding/json"
+	"fmt"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	"gogs.baozhida.cn/zoie/ERP_libs/lib"
+	"time"
+)
+
+const (
+	TransferPending   = "pending"   // 待确认
+	TransferCompleted = "completed" // 已完成
+	TransferCanceled  = "canceled"  // 已取消
+
+)
+
+// 验证工具转移记录
+type ValidationToolTransfer struct {
+	Id              int       `orm:"column(id);size(11);auto;pk"`
+	TransferSn      string    `orm:"type(text);null"`                                       // 设备sn列表(JSON字符串)
+	TransferUser    string    `orm:"size(256);null"`                                        // 转移人
+	AcceptedUser    string    `orm:"size(256);null"`                                        // 接收人
+	TransferUserUid string    `orm:"size(256);null"`                                        // 转移人uuid
+	AcceptedUserUid string    `orm:"size(256);null"`                                        // 接收人uuid
+	Status          string    `orm:"size(20);null"`                                         // 状态:pending-待确认,completed-已完成,canceled-已取消
+	AcceptedNumber  int       `orm:"size(11);null"`                                         // 接收数量
+	TransferRemark  string    `orm:"type(text);null"`                                       // 转移备注
+	AcceptedRemark  string    `orm:"type(text);null"`                                       // 接收备注
+	CreateTime      time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` // 创建时间
+	UpdateTime      time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     // 更新时间
+	AcceptedSn      string    `orm:"type(text);null"`                                       // 实际接收的SN列表(JSON字符串)
+	AcceptedTime    time.Time `orm:"column(accepted_time);type(timestamp);null"`            // 创建时间
+
+}
+
+func (t *ValidationToolTransfer) TableName() string {
+	return "validation_tool_transfer"
+}
+
+type ValidationToolTransfer_R struct {
+	Id             int
+	TransferSn     []string
+	AcceptedSn     []string
+	TransferUser   string
+	AcceptedUser   string
+	Status         string
+	TransferRemark string
+	AcceptedRemark string
+	CreateTime     string
+	AcceptedTime   string
+	AcceptedNumber int
+	TransferNumber int
+}
+
+func ValidationToolTransferTo_R(v ValidationToolTransfer) (r ValidationToolTransfer_R) {
+	r.Id = v.Id
+	var TransferSn, AcceptedSn []string
+	err := json.Unmarshal([]byte(v.TransferSn), &TransferSn)
+	fmt.Println(err)
+	r.TransferSn = TransferSn
+	_ = json.Unmarshal([]byte(v.AcceptedSn), &AcceptedSn)
+	r.AcceptedSn = AcceptedSn
+	r.TransferUser = v.TransferUser
+	r.AcceptedUser = v.AcceptedUser
+	r.TransferNumber = len(r.TransferSn)
+	r.AcceptedNumber = v.AcceptedNumber
+	r.Status = v.Status
+	r.TransferRemark = v.TransferRemark
+	r.AcceptedRemark = v.AcceptedRemark
+	r.CreateTime = v.CreateTime.Format("2006-01-02 15:04")
+	if v.AcceptedTime.IsZero() {
+		r.AcceptedTime = "-"
+	} else {
+		r.AcceptedTime = v.AcceptedTime.Format("2006-01-02 15:04")
+
+	}
+	return
+}
+
+// 获取单条转移记录
+func (dao *ValidationToolTransferImpl) GetTransferRecordByID(id int) (transfer ValidationToolTransfer, err error) {
+	transfer.Id = id
+	err = dao.orm.Read(&transfer)
+	return
+}
+
+// 确认转移,更新状态和接收的SN列表
+func (dao *ValidationToolTransferImpl) ConfirmTransfer(id int, acceptedSNsJSON string) (err error) {
+	transfer := ValidationToolTransfer{Id: id}
+	if err = dao.orm.Read(&transfer); err == nil {
+		transfer.Status = "completed"
+		transfer.AcceptedSn = acceptedSNsJSON
+		_, err = dao.orm.Update(&transfer, "Status", "AcceptedSn", "UpdateTime")
+	}
+	return err
+}
+
+type ValidationToolTransferImpl struct {
+	orm orm.Ormer
+}
+
+func NewValidationToolTransfer(orm orm.Ormer) *ValidationToolTransferImpl {
+	return &ValidationToolTransferImpl{orm: orm}
+}
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(ValidationToolTransfer))
+}
+
+// 添加转移记录
+func (dao *ValidationToolTransferImpl) Add(transfer *ValidationToolTransfer) (id int64, err error) {
+	id, err = dao.orm.Insert(transfer)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+	return id, err
+}
+
+func (dao *ValidationToolTransferImpl) Update(r ValidationToolTransfer, cols ...string) (err error) {
+	_, err = dao.orm.Update(&r, cols...)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+	return err
+}
+
+// 获取接收人的待接收记录
+func (dao *ValidationToolTransferImpl) GetTransferRecordsByUser(userUUID, status string, page, page_z int) (list []ValidationToolTransfer_R, cnt int64) {
+
+	qs := dao.orm.QueryTable(new(ValidationToolTransfer))
+
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+
+	// 过滤
+	cond := orm.NewCondition()
+	cond = cond.And("TransferUserUid", userUUID)
+
+	if len(status) > 0 {
+
+		cond = cond.And("Status", status)
+	}
+
+	// 查询
+	var records []ValidationToolTransfer
+	_, err := qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond)).OrderBy("-Id").All(&records)
+
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return
+	}
+
+	cnt, err = qs.SetCond((*orm2.Condition)(cond)).Count()
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return
+	}
+
+	for _, m := range records {
+		list = append(list, ValidationToolTransferTo_R(m))
+	}
+	return list, cnt
+}
+func (dao *ValidationToolTransferImpl) GetAcceptedRecordsByUser(userUUID, status string, page, page_z int) (list []ValidationToolTransfer_R, cnt int64) {
+
+	qs := dao.orm.QueryTable(new(ValidationToolTransfer))
+
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+
+	// 过滤
+	cond := orm.NewCondition()
+	cond = cond.And("AcceptedUserUid", userUUID).AndNot("Status", TransferCanceled)
+
+	if len(status) > 0 {
+		cond = cond.And("Status", status)
+	}
+
+	// 查询
+	var records []ValidationToolTransfer
+	_, err := qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond)).OrderBy("-Id").All(&records)
+
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return
+	}
+
+	cnt, err = qs.SetCond((*orm2.Condition)(cond)).Count()
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return
+	}
+
+	for _, m := range records {
+		list = append(list, ValidationToolTransferTo_R(m))
+	}
+	return list, cnt
+}
+
+// 根据设备SN获取未完成的转移记录
+func (dao *ValidationToolTransferImpl) GetPendingTransferById(TransferId int) (transfer ValidationToolTransfer, err error) {
+	sql := "SELECT * FROM validation_tool_transfer WHERE id = ? AND status = 'pending' ORDER BY create_time DESC LIMIT 1"
+	err = dao.orm.Raw(sql, TransferId).QueryRow(&transfer)
+	return transfer, err
+}

+ 5 - 2
routers/vaildationTool.go

@@ -24,8 +24,11 @@ func init() {
 		beego.NSRouter("/recordList", &controllers.ValidationController{}, "*:Record_List"),                    // 读取文件
 		beego.NSRouter("/operationList", &controllers.ValidationController{}, "*:Operation_List"),              // 操作记录列表
 		beego.NSRouter("/exportOperationExcel", &controllers.ValidationController{}, "*:Operation_Excel"),      // 操作记录列表
-		beego.NSRouter("/transfer", &controllers.ValidationController{}, "*:TransferValidationTool"),          // 设备转移请求
-		beego.NSRouter("/confirmTransfer", &controllers.ValidationController{}, "*:ConfirmTransferValidationTool"), // 确认接收设备
+		beego.NSRouter("/transfer", &controllers.ValidationController{}, "*:Transfer"),                         // 设备转移请求
+		beego.NSRouter("/confirmAccepted", &controllers.ValidationController{}, "*:ConfirmAccepted"),           // 确认接收设备
+		beego.NSRouter("/CancelTransfer", &controllers.ValidationController{}, "*:CancelTransfer"),             // 取消转移
+		beego.NSRouter("/transferRecordsList", &controllers.ValidationController{}, "*:TransferRecords_List"),  // 我转移的
+		beego.NSRouter("/acceptedRecordsList", &controllers.ValidationController{}, "*:AcceptedRecords_List"),  // 我接受的
 	)
 	beego.AddNamespace(validationTool)
 }

+ 21 - 0
tests/default_test.go

@@ -1,6 +1,7 @@
 package main
 
 import (
+	"encoding/json"
 	"fmt"
 	"testing"
 	"time"
@@ -20,3 +21,23 @@ func generateMonthList(startMonth time.Time) []string {
 	}
 	return months
 }
+
+func TestJson(t *testing.T) {
+	jsonStr := "[\"2025152150736858\",\"2025151362687552\",\"2025151858776242\"]"
+
+	// 定义一个字符串切片用于存储解析后的数据
+	var strSlice []string
+
+	// 解析JSON字符串到切片
+	err := json.Unmarshal([]byte(jsonStr), &strSlice)
+	if err != nil {
+		fmt.Printf("解析JSON错误: %v\n", err)
+		return
+	}
+
+	// 打印解析后的切片
+	fmt.Println("解析后的切片:")
+	for i, s := range strSlice {
+		fmt.Printf("  元素%d: %s\n", i+1, s)
+	}
+}