upload_file.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. package backend
  2. import (
  3. "context"
  4. "fmt"
  5. "kpt-pasture/config"
  6. "kpt-pasture/model"
  7. "kpt-pasture/util"
  8. "mime/multipart"
  9. "os"
  10. "path/filepath"
  11. "reflect"
  12. "strconv"
  13. "strings"
  14. "time"
  15. "gorm.io/gorm"
  16. pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
  17. "gitee.com/xuyiping_admin/pkg/xerr"
  18. )
  19. func (s *StoreEntry) Photos(ctx context.Context, files []*multipart.FileHeader) ([]string, error) {
  20. userModel, err := s.GetUserModel(ctx)
  21. if err != nil {
  22. return nil, err
  23. }
  24. workDir := fmt.Sprintf("%s", config.WorkDir)
  25. pathDir := fmt.Sprintf("/files/photos/%d/%s", userModel.AppPasture.Id, time.Now().Local().Format("20060102"))
  26. saveDir := filepath.Join(workDir, pathDir)
  27. if _, err = os.Stat(saveDir); os.IsNotExist(err) {
  28. if err = os.MkdirAll(saveDir, 0755); err != nil {
  29. return nil, xerr.Customf("创建目录失败: %s", err.Error())
  30. }
  31. }
  32. // 处理每个文件
  33. filePaths := make([]string, len(files))
  34. for i, file := range files {
  35. contentType := file.Header.Get("Content-Type")
  36. if contentType != "image/jpeg" && contentType != "image/png" && contentType != "image/gif" {
  37. return nil, xerr.Customf("图片格式错误: %s", file.Filename)
  38. }
  39. if file.Size > 1024*1024*5 {
  40. return nil, xerr.Customf("单个图片文件不能超过5MB")
  41. }
  42. ext := filepath.Ext(file.Filename)
  43. if ext == "" {
  44. switch contentType {
  45. case "image/jpeg":
  46. ext = ".jpg"
  47. case "image/png":
  48. ext = ".png"
  49. case "image/gif":
  50. ext = ".gif"
  51. default:
  52. ext = ".jpg" // 默认
  53. }
  54. }
  55. randomName := util.GenerateRandomNumberString(32)
  56. finalFilename := randomName + ext
  57. fPath := filepath.Join(saveDir, finalFilename)
  58. urlPath := filepath.Join(pathDir, finalFilename)
  59. if err = util.SaveUploadedFile(file, fPath); err != nil {
  60. return nil, xerr.Customf("保存文件失败: %s", err.Error())
  61. }
  62. filePaths[i] = urlPath
  63. }
  64. return filePaths, nil
  65. }
  66. func (s *StoreEntry) ImportExcel(ctx context.Context, data [][]string) error {
  67. // 获取当前用户信息
  68. userModel, err := s.GetUserModel(ctx)
  69. if err != nil {
  70. return err
  71. }
  72. penMap := s.PenMap2(ctx, userModel.AppPasture.Id)
  73. if userModel.AppPasture.Id <= 0 {
  74. return xerr.Custom("无效的牧场ID")
  75. }
  76. // 处理Excel数据
  77. //headers := data[0]
  78. eventEnterList := make([]*pasturePb.EventEnterRequest, 0)
  79. for _, row := range data[1:] {
  80. if len(row) <= 0 {
  81. continue
  82. }
  83. ts := &pasturePb.EventEnterRequest{
  84. OperationId: 33,
  85. OperationName: "kpt_admin",
  86. MessengerId: 33,
  87. MessengerName: "kpt_admin",
  88. }
  89. for j, d := range row {
  90. switch j {
  91. case 0:
  92. continue
  93. case 1:
  94. continue
  95. case 2:
  96. ts.EarNumber = d
  97. case 3:
  98. if pn, ok := penMap[d]; ok {
  99. ts.PenId = pn.Id
  100. ts.PenName = d
  101. }
  102. case 4:
  103. ts.Sex = pasturePb.Genders_Female
  104. if d == "公" {
  105. ts.Sex = pasturePb.Genders_Male
  106. }
  107. case 5:
  108. if d == "成母牛" {
  109. ts.CowType = pasturePb.CowType_Breeding_Calf
  110. } else if d == "犊牛" {
  111. ts.CowType = pasturePb.CowType_Lactating_Calf
  112. } else if d == "青年牛" {
  113. ts.CowType = pasturePb.CowType_Youth_Calf
  114. } else if d == "育成牛" {
  115. ts.CowType = pasturePb.CowType_Reserve_Calf
  116. }
  117. case 6:
  118. continue
  119. case 7:
  120. bat, _ := util.TimeParseLocal(model.LayoutTime2, d)
  121. if !bat.IsZero() {
  122. ts.BirthAt = int32(bat.Local().Unix())
  123. }
  124. case 8:
  125. lact, _ := strconv.Atoi(d)
  126. ts.Lact = int32(lact)
  127. case 9:
  128. eat, _ := util.TimeParseLocal(model.LayoutTime2, d)
  129. if !eat.IsZero() {
  130. ts.EnterAt = int32(eat.Local().Unix())
  131. }
  132. case 10:
  133. ts.FatherNumber = d
  134. case 11:
  135. ts.MotherNumber = d
  136. case 12:
  137. mat, _ := util.TimeParseLocal(model.LayoutTime2, d)
  138. if !mat.IsZero() {
  139. ts.MatingAt = int32(mat.Local().Unix())
  140. }
  141. case 13:
  142. continue
  143. case 14:
  144. continue
  145. case 15:
  146. mt, _ := strconv.Atoi(d)
  147. ts.MatingTimes = int32(mt)
  148. case 16:
  149. continue
  150. case 17:
  151. pat, _ := util.TimeParseLocal(model.LayoutTime2, d)
  152. if !pat.IsZero() {
  153. ts.PregnancyCheckAt = int32(pat.Local().Unix())
  154. }
  155. case 18:
  156. continue
  157. case 19:
  158. continue
  159. case 20:
  160. cat, _ := util.TimeParseLocal(model.LayoutTime2, d)
  161. if !cat.IsZero() {
  162. ts.CalvingAt = int32(cat.Local().Unix())
  163. }
  164. case 21:
  165. continue
  166. case 22:
  167. continue
  168. case 23:
  169. continue
  170. case 24:
  171. ts.CowKind = pasturePb.CowKind_AGSN
  172. }
  173. }
  174. eventEnterList = append(eventEnterList, ts)
  175. }
  176. if len(eventEnterList) <= 0 {
  177. return nil
  178. }
  179. pastureId := userModel.AppPasture.Id
  180. if pastureId != 4 {
  181. pastureId = 4
  182. }
  183. return s.ExecExcelData(ctx, pastureId, eventEnterList)
  184. }
  185. func (s *StoreEntry) ImportExcel2(ctx context.Context, data [][]string, excelHeader []string) error {
  186. // 获取当前用户信息
  187. userModel, err := s.GetUserModel(ctx)
  188. if err != nil {
  189. return err
  190. }
  191. penMap := s.PenMap2(ctx, userModel.AppPasture.Id)
  192. if userModel.AppPasture.Id <= 0 {
  193. return xerr.Custom("无效的牧场ID")
  194. }
  195. // 处理Excel数据
  196. //headers := data[0]
  197. eventEnterList := make([]*pasturePb.EventEnterRequest, 0)
  198. /*for _, row := range data[1:] {
  199. if len(row) <= 0 {
  200. continue
  201. }
  202. ts := &pasturePb.EventEnterRequest{
  203. OperationId: int32(userModel.SystemUser.Id),
  204. OperationName: userModel.SystemUser.Name,
  205. MessengerId: int32(userModel.SystemUser.Id),
  206. MessengerName: userModel.SystemUser.Name,
  207. }
  208. for j, d := range row {
  209. switch j {
  210. case 0:
  211. continue
  212. case 1:
  213. continue
  214. case 2:
  215. ts.EarNumber = d
  216. case 3:
  217. if pn, ok := penMap[d]; ok {
  218. ts.PenId = pn.Id
  219. ts.PenName = pn.Name
  220. }
  221. case 4:
  222. ts.Sex = pasturePb.Genders_Female
  223. if d == "公" {
  224. ts.Sex = pasturePb.Genders_Male
  225. }
  226. case 5:
  227. if d == "成母牛" {
  228. ts.CowType = pasturePb.CowType_Breeding_Calf
  229. } else if d == "犊牛" {
  230. ts.CowType = pasturePb.CowType_Lactating_Calf
  231. } else if d == "青年牛" {
  232. ts.CowType = pasturePb.CowType_Youth_Calf
  233. } else if d == "育成牛" {
  234. ts.CowType = pasturePb.CowType_Reserve_Calf
  235. }
  236. case 6:
  237. continue
  238. case 7:
  239. bat, _ := util.TimeParseLocal(model.LayoutTime2, d)
  240. if !bat.IsZero() {
  241. ts.BirthAt = int32(bat.Local().Unix())
  242. }
  243. case 8:
  244. lact, _ := strconv.Atoi(d)
  245. ts.Lact = int32(lact)
  246. case 9:
  247. eat, _ := util.TimeParseLocal(model.LayoutTime2, d)
  248. if !eat.IsZero() {
  249. ts.EnterAt = int32(eat.Local().Unix())
  250. }
  251. case 10:
  252. ts.FatherNumber = d
  253. case 11:
  254. ts.MotherNumber = d
  255. case 12:
  256. mat, _ := util.TimeParseLocal(model.LayoutTime2, d)
  257. if !mat.IsZero() {
  258. ts.MatingAt = int32(mat.Local().Unix())
  259. }
  260. case 13:
  261. continue
  262. case 14:
  263. continue
  264. case 15:
  265. mt, _ := strconv.Atoi(d)
  266. ts.MatingTimes = int32(mt)
  267. case 16:
  268. continue
  269. case 17:
  270. pat, _ := util.TimeParseLocal(model.LayoutTime2, d)
  271. if !pat.IsZero() {
  272. ts.PregnancyCheckAt = int32(pat.Local().Unix())
  273. }
  274. case 18:
  275. continue
  276. case 19:
  277. continue
  278. case 20:
  279. cat, _ := util.TimeParseLocal(model.LayoutTime2, d)
  280. if !cat.IsZero() {
  281. ts.CalvingAt = int32(cat.Local().Unix())
  282. }
  283. case 21:
  284. continue
  285. case 22:
  286. continue
  287. case 23:
  288. continue
  289. case 24:
  290. ts.CowKind = pasturePb.CowKind_AGSN
  291. }
  292. }
  293. eventEnterList = append(eventEnterList, ts)
  294. }*/
  295. // 遍历数据行(跳过表头)
  296. for _, row := range data[1:] {
  297. if len(row) == 0 {
  298. continue
  299. }
  300. ts := &pasturePb.EventEnterRequest{
  301. OperationId: int32(userModel.SystemUser.Id),
  302. OperationName: userModel.SystemUser.Name,
  303. MessengerId: int32(userModel.SystemUser.Id),
  304. MessengerName: userModel.SystemUser.Name,
  305. }
  306. // 使用反射动态匹配字段
  307. val := reflect.ValueOf(ts).Elem()
  308. typ := val.Type()
  309. for i := 0; i < val.NumField(); i++ {
  310. field := typ.Field(i)
  311. fieldVal := val.Field(i)
  312. // 获取字段的 excel 标签(如 excel:"耳标号")
  313. excelTag := strings.ReplaceAll(field.Tag.Get("json"), ",omitempty", "")
  314. if excelTag == "" {
  315. continue // 没有 excel 标签的字段跳过
  316. }
  317. // 查找 excelHeader 中匹配的列索引
  318. colIndex := -1
  319. for j, colName := range excelHeader {
  320. if colName == "" {
  321. continue // 跳过空列名
  322. }
  323. if colName == excelTag {
  324. colIndex = j
  325. break
  326. }
  327. }
  328. if colIndex == -1 || colIndex >= len(row) {
  329. continue // 列名不匹配或数据越界
  330. }
  331. cellValue := row[colIndex]
  332. if cellValue == "" {
  333. continue // 空值跳过
  334. }
  335. // 根据字段类型设置值
  336. switch fieldVal.Kind() {
  337. case reflect.String:
  338. fieldVal.SetString(cellValue)
  339. case reflect.Int32:
  340. if num, err := strconv.ParseInt(cellValue, 10, 32); err == nil {
  341. fieldVal.SetInt(num)
  342. }
  343. case reflect.Struct: // 处理枚举或时间类型
  344. switch field.Type {
  345. case reflect.TypeOf(pasturePb.Genders_Female):
  346. if cellValue == "公" {
  347. fieldVal.Set(reflect.ValueOf(pasturePb.Genders_Male))
  348. } else {
  349. fieldVal.Set(reflect.ValueOf(pasturePb.Genders_Female))
  350. }
  351. // 添加其他自定义类型的处理...
  352. }
  353. }
  354. }
  355. // 特殊处理 PenId 和 PenName(依赖 penMap)
  356. if ts.PenName != "" {
  357. if pen, ok := penMap[ts.PenName]; ok {
  358. ts.PenId = pen.Id
  359. }
  360. }
  361. eventEnterList = append(eventEnterList, ts)
  362. }
  363. if len(eventEnterList) <= 0 {
  364. return nil
  365. }
  366. return nil
  367. return s.ExecExcelData(ctx, userModel.AppPasture.Id, eventEnterList)
  368. }
  369. func (s *StoreEntry) ExecExcelData(ctx context.Context, pastureId int64, dataList []*pasturePb.EventEnterRequest) error {
  370. if len(dataList) <= 0 {
  371. return nil
  372. }
  373. return s.DB.Transaction(func(tx *gorm.DB) error {
  374. for _, data := range dataList {
  375. var count int64
  376. if err := tx.Model(new(model.Cow)).
  377. Where("pasture_id = ?", pastureId).
  378. Where("ear_number = ?", data.EarNumber).
  379. Count(&count).Error; err != nil {
  380. return err
  381. }
  382. if count > 0 {
  383. continue
  384. }
  385. if err := s.CreateEnter(ctx, data); err != nil {
  386. return err
  387. }
  388. }
  389. return nil
  390. })
  391. }