excel_to_lucky_sheet.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. package excel
  2. import (
  3. "encoding/json"
  4. "eta/eta_mobile/utils"
  5. "fmt"
  6. "github.com/shopspring/decimal"
  7. "github.com/xuri/excelize/v2"
  8. "sync"
  9. "time"
  10. )
  11. // ConvToLuckySheet 普通的excel转luckySheet数据
  12. func ConvToLuckySheet(filePath string) (err error) {
  13. defer func() {
  14. if err != nil {
  15. fmt.Println(err)
  16. }
  17. }()
  18. f, err := excelize.OpenFile(filePath)
  19. if err != nil {
  20. fmt.Println(err)
  21. return
  22. }
  23. sheetDataList := make([]SimpleLuckySheetData, 0)
  24. // 获取所有sheet
  25. sheetList := f.GetSheetList()
  26. fmt.Println("读取完成后", time.Now().Format(utils.FormatDateTime))
  27. for sheetIndex, sheetName := range sheetList {
  28. sheetData, tmpErr := getLuckySheetData(f, sheetIndex, sheetName)
  29. if tmpErr != nil {
  30. err = tmpErr
  31. return
  32. }
  33. sheetDataList = append(sheetDataList, sheetData)
  34. }
  35. byteS, err := json.Marshal(sheetDataList)
  36. if err != nil {
  37. return
  38. }
  39. utils.FileLog.Info(string(byteS))
  40. return
  41. }
  42. // SimpleLuckySheetData sheet表格数据
  43. type SimpleLuckySheetData struct {
  44. Name string `json:"name" description:"工作表名称"`
  45. Index int `json:"index" description:"工作表索引"`
  46. //Row int `json:"row" description:"行数"`
  47. //Column int `json:"column" description:"列数"`
  48. CellData []SimpleLuckySheetCellData `json:"celldata" description:"单元格数据"`
  49. Config SimpleLuckySheetDataConfig `json:"config" description:""`
  50. CalcChain []CalcChain `json:"calcChain" description:"公式链"`
  51. //Status int64 `json:"status" description:"激活状态"`
  52. }
  53. type CalcChain struct {
  54. Col int64 `json:"c"` //列数
  55. Row int64 `json:"r"` //行数
  56. Index int `json:"index"` //工作表id
  57. Func []interface{} `json:"func"` //公式信息,包含公式计算结果和公式字符串
  58. Color string `json:"color"` //"w":采用深度优先算法 "b":普通计算
  59. //Parent interface{} `json:"parent"`
  60. //Chidren struct {
  61. //} `json:"chidren"`
  62. Times int `json:"times"`
  63. }
  64. // SimpleLuckySheetDataConfig sheet表单的配置
  65. type SimpleLuckySheetDataConfig struct {
  66. BorderInfo []LuckySheetDataConfigBorderInfo `json:"borderInfo" description:"边框"`
  67. Colhidden map[string]int64 `json:"colhidden" description:"隐藏列,示例值:\"colhidden\":{\"30\":0,\"31\":0}"`
  68. //CustomHeight struct {
  69. // Zero int64 `json:"0"`
  70. //} `json:"customHeight" description:""`
  71. //CustomWidth struct {
  72. // Two int64 `json:"2" description:""`
  73. //} `json:"customWidth" description:""`
  74. Merge map[string]LuckySheetDataConfigMerge `json:"merge" description:"合并单元格"`
  75. //Rowlen map[string]float64 `json:"rowlen" description:"每个单元格的行高"`
  76. Columnlen map[string]float64 `json:"columnlen" description:"每个单元格的列宽"`
  77. }
  78. // SimpleLuckySheetCellData 单个单元格数据
  79. type SimpleLuckySheetCellData struct {
  80. Col int64 `json:"c" description:"列"`
  81. Row int64 `json:"r" description:"行"`
  82. //Value SimpleLuckySheetDataValue `json:"v" description:"单元格内值的数据"`
  83. Value interface{} `json:"v" description:"单元格内值的数据"`
  84. }
  85. // SimpleLuckySheetDataValue 单元格内值的数据
  86. type SimpleLuckySheetDataValue struct {
  87. CellType LuckySheetDataCellType `json:"ct" description:"单元格值格式:文本、时间等 "`
  88. Value interface{} `json:"v" description:"原始值"`
  89. //Monitor string `json:"m" description:"显示值"`
  90. //Fontsize int `description:"字体大小,14"`
  91. //TextBeak int `description:"文本换行, 0 截断、1溢出、2 自动换行"`
  92. //Tb interface{} `json:"tb" description:"文本换行, 0 截断、1溢出、2 自动换行"`
  93. //Ps LuckySheetDataCellComment `json:"ps" description:"批注"`
  94. Function string `json:"f" description:"公式"`
  95. //MergeCell LuckySheetDataConfigMerge `json:"mc" description:"合并单元格信息"`
  96. }
  97. func getLuckySheetData(f *excelize.File, sheetIndex int, sheetName string) (sheetData SimpleLuckySheetData, err error) {
  98. cellData := make([]SimpleLuckySheetCellData, 0) // excel数据
  99. mergeData := make(map[string]LuckySheetDataConfigMerge) //合并单元格数据
  100. calcChainList := make([]CalcChain, 0) //公式链信息
  101. sheetData = SimpleLuckySheetData{
  102. Name: sheetName,
  103. Index: sheetIndex,
  104. //Row: 0,
  105. //Column: 0,
  106. CellData: cellData,
  107. Config: SimpleLuckySheetDataConfig{},
  108. }
  109. fmt.Println("开始读取sheet数据:", time.Now().Format(utils.FormatDateTime))
  110. rows, tmpErr := f.GetRows(sheetName)
  111. if tmpErr != nil {
  112. err = tmpErr
  113. return
  114. }
  115. fmt.Println("读取完sheet数据:", time.Now().Format(utils.FormatDateTime))
  116. lenRow := len(rows)
  117. fmt.Println("总共:", lenRow, "条数据")
  118. if lenRow <= 0 {
  119. return
  120. }
  121. //sheetData.Row = len(rows)
  122. //sheetData.Column = len(Column)
  123. // 最大单元格数
  124. maxColumnIndex := 0
  125. wg := sync.WaitGroup{}
  126. wg.Add(1)
  127. // 协程处理合并单元格
  128. go func() {
  129. defer func() {
  130. wg.Done()
  131. }()
  132. mergeCellList, err := f.GetMergeCells(sheetName)
  133. if err != nil {
  134. return
  135. }
  136. for _, v := range mergeCellList {
  137. // 左上角单元格位置
  138. cStartIndex, rStartIndex, tmpErr := excelize.CellNameToCoordinates(v.GetStartAxis())
  139. if tmpErr != nil {
  140. err = tmpErr
  141. return
  142. }
  143. // 右下角单元格位置
  144. cEndIndex, rEndIndex, tmpErr := excelize.CellNameToCoordinates(v.GetEndAxis())
  145. if tmpErr != nil {
  146. err = tmpErr
  147. return
  148. }
  149. //fmt.Println(v.GetEndAxis())
  150. tmpLuckySheetDataConfigMerge := LuckySheetDataConfigMerge{
  151. Row: rStartIndex - 1,
  152. Column: cStartIndex - 1,
  153. Rs: rEndIndex - rStartIndex + 1,
  154. Cs: cEndIndex - cStartIndex + 1,
  155. }
  156. mergeData[fmt.Sprint(rStartIndex-1, "_", cStartIndex-1)] = tmpLuckySheetDataConfigMerge
  157. }
  158. sheetData.Config.Merge = mergeData
  159. }()
  160. colWidthMap := make(map[string]float64)
  161. // 每次分割就是5000条
  162. splitNum := 500
  163. splitLen := lenRow / splitNum
  164. residue := lenRow % splitNum
  165. if residue > 0 {
  166. splitLen += 1
  167. }
  168. for i := 0; i < splitLen; i++ {
  169. wg.Add(1)
  170. startRow := i * splitNum
  171. endRow := (i + 1) * splitNum
  172. if i == splitLen-1 && residue > 0 {
  173. endRow = lenRow
  174. }
  175. go func(currStartRow, currEndRow int) {
  176. defer func() {
  177. wg.Done()
  178. }()
  179. for rIndex := currStartRow; rIndex < currEndRow; rIndex++ {
  180. row := rows[rIndex]
  181. for cIndex, colCell := range row {
  182. if rIndex == 0 {
  183. //colName, tmpErr := excelize.ColumnNumberToName(cIndex + 1)
  184. //if tmpErr != nil {
  185. // err = tmpErr
  186. // return
  187. //}
  188. //colWidth, tmpErr := f.GetColWidth(sheetName, colName)
  189. //if tmpErr != nil {
  190. // err = tmpErr
  191. // return
  192. //}
  193. //colWidthMap[fmt.Sprint(cIndex)] = emuToPx(colWidth)
  194. }
  195. if maxColumnIndex < cIndex {
  196. maxColumnIndex = cIndex
  197. }
  198. cellName, tmpErr := excelize.CoordinatesToCellName(cIndex+1, rIndex+1)
  199. if tmpErr != nil {
  200. err = tmpErr
  201. return
  202. }
  203. //cellType, tmpErr := f.GetCellType(sheetName, cellName)
  204. //if tmpErr != nil {
  205. // err = tmpErr
  206. // return
  207. //}
  208. cellFormula, tmpErr := f.GetCellFormula(sheetName, cellName)
  209. if tmpErr != nil {
  210. err = tmpErr
  211. return
  212. }
  213. //fmt.Println(cellName, ": ", "类型:", cellType, ",公式:", cellFormula, ",值", colCell, "\t")
  214. var colCellIntfac interface{}
  215. cellTypeT := "g"
  216. //colCell = utils.Tof
  217. tmpDec, tmpErr := decimal.NewFromString(colCell)
  218. if tmpErr != nil {
  219. colCellIntfac = colCell
  220. } else {
  221. colCellIntfac, _ = tmpDec.Float64()
  222. cellTypeT = "n"
  223. }
  224. if cellFormula != `` {
  225. cellFormula = `=` + cellFormula
  226. calcChainList = append(calcChainList, CalcChain{
  227. Col: int64(cIndex),
  228. Row: int64(rIndex),
  229. Index: sheetIndex,
  230. Func: []interface{}{true, colCell, cellFormula},
  231. Color: "w",
  232. Times: 0,
  233. })
  234. }
  235. //CellType LuckySheetDataCellType `json:"ct" description:"单元格值格式:文本、时间等 "`
  236. //Value interface{} `json:"v" description:"原始值"`
  237. ////Monitor string `json:"m" description:"显示值"`
  238. ////Fontsize int `description:"字体大小,14"`
  239. ////TextBeak int `description:"文本换行, 0 截断、1溢出、2 自动换行"`
  240. ////Tb interface{} `json:"tb" description:"文本换行, 0 截断、1溢出、2 自动换行"`
  241. ////Ps LuckySheetDataCellComment `json:"ps" description:"批注"`
  242. //Function string `json:"f" description:"公式"`
  243. valueMap := make(map[string]interface{})
  244. valueMap["ct"] = LuckySheetDataCellType{
  245. Fa: "General",
  246. T: cellTypeT,
  247. }
  248. valueMap["v"] = colCellIntfac
  249. if cellFormula != `` {
  250. valueMap["f"] = cellFormula
  251. }
  252. cellData = append(cellData, SimpleLuckySheetCellData{
  253. Col: int64(cIndex),
  254. Row: int64(rIndex),
  255. Value: valueMap,
  256. })
  257. }
  258. }
  259. }(startRow, endRow)
  260. }
  261. wg.Wait()
  262. fmt.Println("解析完sheet数据:", time.Now().Format(utils.FormatDateTime))
  263. //for rIndex, row := range rows {
  264. // for cIndex, colCell := range row {
  265. // if rIndex == 0 {
  266. // //colName, tmpErr := excelize.ColumnNumberToName(cIndex + 1)
  267. // //if tmpErr != nil {
  268. // // err = tmpErr
  269. // // return
  270. // //}
  271. // //colWidth, tmpErr := f.GetColWidth(sheetName, colName)
  272. // //if tmpErr != nil {
  273. // // err = tmpErr
  274. // // return
  275. // //}
  276. // //colWidthMap[fmt.Sprint(cIndex)] = emuToPx(colWidth)
  277. // }
  278. // if maxColumnIndex < cIndex {
  279. // maxColumnIndex = cIndex
  280. // }
  281. // cellName, tmpErr := excelize.CoordinatesToCellName(cIndex+1, rIndex+1)
  282. // if tmpErr != nil {
  283. // err = tmpErr
  284. // return
  285. // }
  286. // //cellType, tmpErr := f.GetCellType(sheetName, cellName)
  287. // //if tmpErr != nil {
  288. // // err = tmpErr
  289. // // return
  290. // //}
  291. // cellFormula, tmpErr := f.GetCellFormula(sheetName, cellName)
  292. // if tmpErr != nil {
  293. // err = tmpErr
  294. // return
  295. // }
  296. //
  297. // //fmt.Println(cellName, ": ", "类型:", cellType, ",公式:", cellFormula, ",值", colCell, "\t")
  298. //
  299. // var colCellIntfac interface{}
  300. // cellTypeT := "g"
  301. // //colCell = utils.Tof
  302. // tmpDec, tmpErr := decimal.NewFromString(colCell)
  303. // if tmpErr != nil {
  304. // colCellIntfac = colCell
  305. // } else {
  306. // colCellIntfac, _ = tmpDec.Float64()
  307. // cellTypeT = "n"
  308. // }
  309. //
  310. // if cellFormula != `` {
  311. // cellFormula = `=` + cellFormula
  312. //
  313. // calcChainList = append(calcChainList, CalcChain{
  314. // Col: int64(cIndex),
  315. // Row: int64(rIndex),
  316. // Index: sheetIndex,
  317. // Func: []interface{}{true, colCell, cellFormula},
  318. // Color: "w",
  319. // Times: 0,
  320. // })
  321. // }
  322. //
  323. // cellData = append(cellData, SimpleLuckySheetCellData{
  324. // Col: int64(cIndex),
  325. // Row: int64(rIndex),
  326. // Value: SimpleLuckySheetDataValue{
  327. // CellType: LuckySheetDataCellType{
  328. // Fa: "General",
  329. // T: cellTypeT,
  330. // },
  331. // Value: colCellIntfac,
  332. // Monitor: colCell,
  333. // Function: cellFormula,
  334. // //MergeCell: LuckySheetDataConfigMerge{},
  335. // },
  336. // })
  337. // }
  338. //}
  339. sheetData.Config.Columnlen = colWidthMap
  340. sheetData.CellData = cellData
  341. sheetData.CalcChain = calcChainList
  342. //sheetData.Column = maxColumnIndex + 1
  343. return
  344. }
  345. // emuToPx 计量单位emu转px
  346. func emuToPx(num float64) float64 {
  347. return num * 15
  348. }