simple_table_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. package example
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "reflect"
  6. "testing"
  7. "github.com/tiechui1994/gopdf"
  8. "github.com/tiechui1994/gopdf/core"
  9. )
  10. type Template struct {
  11. Modelname string `json:"modelname"`
  12. MultiSelectList []string `json:"multiSelectList"`
  13. Value interface{} `json:"value"`
  14. ValueList interface{} `json:"valueList"`
  15. Modeltype string `json:"modeltype"`
  16. NeedPrint string `json:"needPrint"`
  17. TableObj struct {
  18. Columns []struct {
  19. ColumnsName string `json:"columnsName"`
  20. } `json:"columns"` // 列名称
  21. Rows []string `json:"rows"` // 行名称, 从第2行开算, 第一行是Header,没有
  22. } `json:"tableObj"`
  23. TbodyArray [][]struct {
  24. ColumnsType string `json:"columnsType"` // 当前TableCell类型
  25. ColumnsName string `json:"columnsName"` // 当前TableCell对应列的名称
  26. RowName string `json:"rowsName"` // 当前TableCell对于的行名称
  27. Content interface{} `json:"content"` // 内容
  28. SelectedOption string `json:"selectedOption"`
  29. } `json:"tbodyArray"`
  30. TableTotalArr []interface{} `json:"tableTotalArr"` // 合计
  31. }
  32. func handleTable(template Template) (rows, cols int, cells [][]string, hasRowName bool) {
  33. var (
  34. colNames = template.TableObj.Columns
  35. rowNames = template.TableObj.Rows
  36. body = template.TbodyArray
  37. )
  38. hasRowName = len(rowNames) != 0
  39. cols = len(colNames)
  40. rows = 1 // 头
  41. if hasRowName {
  42. cols += 1 // 第0行
  43. rows += len(rowNames) // 其余的的行
  44. } else {
  45. if isEmpty(body) {
  46. rows += 1 // 至少有一行
  47. } else {
  48. rows += len(body)
  49. }
  50. }
  51. if !isEmpty(template.TableTotalArr) {
  52. cells = make([][]string, rows+1)
  53. } else {
  54. cells = make([][]string, rows)
  55. }
  56. for i := range cells {
  57. cells[i] = make([]string, cols)
  58. }
  59. // header
  60. if hasRowName {
  61. cells[0][0] = ""
  62. }
  63. for i := range colNames {
  64. if hasRowName {
  65. cells[0][i+1] = colNames[i].ColumnsName
  66. } else {
  67. cells[0][i] = colNames[i].ColumnsName
  68. }
  69. }
  70. // 拥有rowname, 肯定有统计信息
  71. if hasRowName {
  72. // body内容: rows - 2 * cols - 1
  73. for i := 1; i < rows; i++ {
  74. cells[i][0] = body[i-1][0].RowName
  75. for j := 0; j < cols-1; j++ {
  76. if body[i-1][j].ColumnsType == "select" {
  77. cells[i][j+1] = body[i-1][j].SelectedOption
  78. continue
  79. }
  80. switch body[i-1][j].Content.(type) {
  81. case string:
  82. cells[i][j+1] = body[i-1][j].Content.(string)
  83. case float64:
  84. cells[i][j+1] = fmt.Sprintf("%0.2f", body[i-1][j].Content)
  85. }
  86. }
  87. }
  88. // 最后一行
  89. if !isEmpty(template.TableTotalArr) {
  90. cells[rows][0] = "合计"
  91. for j := 0; j < cols-1; j++ {
  92. switch template.TableTotalArr[j].(type) {
  93. case string:
  94. cells[rows][j+1] = template.TableTotalArr[j].(string)
  95. case float64:
  96. cells[rows][j+1] = fmt.Sprintf("%.2f", template.TableTotalArr[j].(float64))
  97. }
  98. }
  99. return rows + 1, cols, cells, hasRowName
  100. }
  101. return rows, cols, cells, hasRowName
  102. }
  103. // 没有rowname, 但是有内容
  104. if !hasRowName && !isEmpty(body) {
  105. for i := 1; i < rows; i++ {
  106. for j := 0; j < cols; j++ {
  107. if body[i-1][j].ColumnsType == "select" {
  108. cells[i][j] = body[i-1][j].SelectedOption
  109. continue
  110. }
  111. switch body[i-1][j].Content.(type) {
  112. case string:
  113. cells[i][j] = body[i-1][j].Content.(string)
  114. case float64:
  115. cells[i][j] = fmt.Sprintf("%0.2f", body[i-1][j].Content.(float64))
  116. }
  117. }
  118. }
  119. // 合计
  120. if !isEmpty(template.TableTotalArr) {
  121. for j := 0; j < cols; j++ {
  122. switch template.TableTotalArr[j].(type) {
  123. case string:
  124. cells[rows][j] = template.TableTotalArr[j].(string)
  125. case float64:
  126. cells[rows][j] = fmt.Sprintf("%.2f", template.TableTotalArr[j].(float64))
  127. }
  128. }
  129. return rows + 1, cols, cells, hasRowName
  130. }
  131. return rows, cols, cells, hasRowName
  132. } else {
  133. for j := 0; j < cols; j++ {
  134. cells[1][j] = ""
  135. }
  136. }
  137. return rows, cols, cells, hasRowName
  138. }
  139. func isEmpty(object interface{}) bool {
  140. if object == nil {
  141. return true
  142. }
  143. objValue := reflect.ValueOf(object)
  144. switch objValue.Kind() {
  145. // collection types are empty when they have no element
  146. case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
  147. return objValue.Len() == 0
  148. case reflect.Ptr:
  149. if objValue.IsNil() {
  150. return true
  151. }
  152. deref := objValue.Elem().Interface()
  153. return isEmpty(deref)
  154. // for all other types, compare against the zero value
  155. default:
  156. zero := reflect.Zero(objValue.Type())
  157. return reflect.DeepEqual(object, zero.Interface())
  158. }
  159. }
  160. func handleTemplateRow(template Template) (isTable bool, key, value string) {
  161. key = template.Modelname
  162. switch template.Modeltype {
  163. case "1", "2", "5", "9":
  164. if template.Value == nil {
  165. template.Value = ""
  166. }
  167. value = template.Value.(string)
  168. case "4":
  169. if template.Value == nil {
  170. template.Value = ""
  171. }
  172. var temp = &[]struct {
  173. SourceID string `json:"source_id"`
  174. FileName string `json:"file_name"`
  175. DownloadUrl string `json:"downloadUrl"`
  176. }{}
  177. err := json.Unmarshal([]byte(template.Value.(string)), temp)
  178. if err != nil {
  179. return false, key, ""
  180. }
  181. if isEmpty(temp) {
  182. value = ""
  183. return
  184. }
  185. for _, v := range *temp {
  186. value += fmt.Sprintf(" %s", v.FileName)
  187. }
  188. case "6":
  189. m, ok := template.ValueList.([]interface{})
  190. if ok == false {
  191. value = template.ValueList.(string)
  192. } else {
  193. var values string
  194. for _, v := range m {
  195. values += fmt.Sprintf(" %s", v)
  196. }
  197. value = values
  198. }
  199. case "7":
  200. key = ""
  201. case "8":
  202. }
  203. return template.Modeltype == "8", key, value
  204. }
  205. func SimpleTableReportExecutor(report *core.Report) {
  206. var (
  207. templates []Template
  208. unit = report.GetUnit()
  209. lineSpace = 0.01 * unit
  210. lineHight = 1.9 * unit
  211. )
  212. str := `[
  213. {"modelname":"所在公司","modeltype":"5","value":"中国航天科技九院"},
  214. {"modelname":"报销部门","modeltype":"1","value":"财务部"},
  215. {"modelname":"报销人","modeltype":"1","value":"钱伟长"},
  216. {"modelname":"职务","modeltype":"1","value":"技术总领导"},
  217. {"modelname":"项目名称","modeltype":"1","value":"航天科技人员培训"},
  218. {"modelname":"出差时间","modeltype":"2","value":"12.21"},
  219. {"modelname":"结束时间","modeltype":"2","value":"12.27"},
  220. {"modelname":"目的地","modeltype":"1","value":"青海金银滩"},
  221. {"modelname":"出差说明","modeltype":"2","value":"指导培训"},
  222. {"modelname":"实际出差时间和结束时间段","modeltype":"2"},
  223. {
  224. "modelname":"报销明细单",
  225. "modeltype":"8",
  226. "tableObj":{
  227. "columns":[
  228. {"columnsName":"出发时间","columnsType":"text"},
  229. {"columnsName":"出发地点","columnsType":"text"},
  230. {"columnsName":"到达时间","columnsType":"text"},
  231. {"columnsName":"到达地点","columnsType":"text"},
  232. {"columnsName":"交通工具","columnsType":"text"},
  233. {"columnsName":"事项","columnsType":"text"},
  234. {"columnsName":"交通费","columnsType":"number"},
  235. {"columnsName":"住宿费","columnsType":"number"},
  236. {"columnsName":"招待费","columnsType":"number"},
  237. {"columnsName":"补贴","columnsType":"number"},
  238. {"columnsName":"票据数","columnsType":"text"},
  239. {"columnsName":"票据序号","columnsType":"text"},
  240. {"columnsName":"备注","columnsType":"text"}
  241. ],
  242. "rows":[]
  243. },
  244. "tbodyArray":[],
  245. "tableTotalArr":["","","","","","","","","","","","",""]
  246. },
  247. {"modelname":"报销总额(小写)", "modeltype":"1","value":""},
  248. {"modelname":"报销总额(大写)","modeltype":"1","tableObj":{"columns":[],"rows":[]}},
  249. {"modelname":"超支金额","modeltype":"1","value":""},
  250. {"modelname":"应报金额","modeltype":"1","value":""},
  251. {
  252. "modelname":"调整金额",
  253. "modeltype":"8",
  254. "tableObj":{
  255. "columns":[
  256. {"columnsName":"交通费","columnsType":"text"},
  257. {"columnsName":"住宿费","columnsType":"text"},
  258. {"columnsName":"招待费","columnsType":"text"},
  259. {"columnsName":"补贴","columnsType":"text"}
  260. ],
  261. "rows":["调整","实报金额"]
  262. },
  263. "tbodyArray":[
  264. [
  265. {"columnsName":"交通费","rowsName":"调整"},
  266. {"columnsName":"住宿费","rowsName":"调整"},
  267. {"columnsName":"招待费","rowsName":"调整"},
  268. {"columnsName":"补贴","rowsName":"调整"}
  269. ],
  270. [
  271. {"columnsName":"交通费","rowsName":"实报金额"},
  272. {"columnsName":"住宿费","rowsName":"实报金额"},
  273. {"columnsName":"招待费","rowsName":"实报金额"},
  274. {"columnsName":"补贴","rowsName":"实报金额"}
  275. ]
  276. ],
  277. "tableTotalArr":["","","",""]
  278. },
  279. {"modelname":"备注","modeltype":"2", "value":""},
  280. {"modelname":"附件","modeltype":"4", "fileNameArr":[],"attachfileArr":[],"value":"[]"},
  281. {"modelname":"附单据","modeltype":"4","fileNameArr":[],"attachfileArr":[]}
  282. ]`
  283. json.Unmarshal([]byte(str), &templates)
  284. for _, template := range templates {
  285. isTable, key, value := handleTemplateRow(template)
  286. // key != "" 是过滤 Modeltype 为 "7"的情况
  287. if !isTable && key != "" {
  288. report.SetMargin(4*unit, 0)
  289. content := fmt.Sprintf("%s: %s", key, value)
  290. contentDiv := gopdf.NewDivWithWidth(80*unit, lineHight, lineSpace, report)
  291. contentDiv.SetFont(textFont).SetContent(content).GenerateAtomicCell()
  292. report.SetMargin(0, 1*unit)
  293. }
  294. // 处理表格
  295. if isTable {
  296. report.SetMargin(4*unit, 0)
  297. content := fmt.Sprintf("%s:", key)
  298. contentDiv := gopdf.NewDivWithWidth(80*unit, lineHight, lineSpace, report)
  299. contentDiv.SetFont(textFont).SetContent(content).GenerateAtomicCell()
  300. report.SetMargin(0, 0.5*unit)
  301. rows, cols, cells, hasRowName := handleTable(template)
  302. table := gopdf.NewTable(cols, rows, 100*unit, lineHight, report)
  303. for i := 0; i < rows; i++ {
  304. for j := 0; j < cols; j++ {
  305. cell := table.NewCell()
  306. element := gopdf.NewTextCell(table.GetColWidth(i, j), lineHight, lineSpace, report)
  307. element.SetFont(textFont)
  308. element.SetBorder(core.Scope{Left: 0.5 * unit, Top: 0.5 * unit})
  309. if i == 0 || j == 0 && hasRowName {
  310. element.HorizontalCentered()
  311. }
  312. element.SetContent(cells[i][j])
  313. cell.SetElement(element)
  314. }
  315. }
  316. table.GenerateAtomicCell()
  317. report.SetMargin(0, 1*unit)
  318. }
  319. }
  320. }
  321. func SimpleTableReport() {
  322. r := core.CreateReport()
  323. font1 := core.FontMap{
  324. FontName: FONT_MY,
  325. FileName: "ttf//microsoft.ttf",
  326. }
  327. font2 := core.FontMap{
  328. FontName: FONT_MD,
  329. FileName: "ttf//mplus-1p-bold.ttf",
  330. }
  331. r.SetFonts([]*core.FontMap{&font1, &font2})
  332. r.SetPage("A4", "mm", "P")
  333. r.RegisterExecutor(core.Executor(SimpleTableReportExecutor), core.Detail)
  334. r.Execute("simple_table_test.pdf")
  335. r.SaveAtomicCellText("simple_table_test.txt")
  336. }
  337. func TestComplexTableReport(t *testing.T) {
  338. SimpleTableReport()
  339. }