parse.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. package survey
  2. import (
  3. "fmt"
  4. "github.com/golang-module/carbon"
  5. "github.com/samber/lo"
  6. "gogs.uu.mdfitnesscao.com/cuiguohai/sdk"
  7. )
  8. const (
  9. TYPE_INPUT = "input" // 单行文本题
  10. TYPE_RADIO = "radio" // 单选题
  11. TYPE_CHECKBOX = "checkbox" // 多选题
  12. TYPE_DATE = "date" // 日期选择题
  13. TYPE_GROUP = "group" // 组合题
  14. TYPE_MATRIX_CHECKBOX = "matrix_checkbox" // 矩阵多选题
  15. TYPE_LINK = "upload" // 链接题
  16. TYPE_SELECT = "select" // 链接题
  17. )
  18. const (
  19. DATE_TYPE_DATE = "dateType:date" // 日期类型:2022年01月01日
  20. DATE_TYPE_DATETIME = "dateType:datetime" // 日期类型:2022年01月01日 12:00:00
  21. DATE_TYPE_AGE = "dateType:age" // 日期类型:年龄值,向下取整
  22. DATE_TYPE_DAY = "dateType:day" // 日期类型:距离某个日期的天数
  23. DATE_TYPE_HOUR = "dateType:hour" // 日期类型:距离某个日期的小时数
  24. )
  25. /**
  26. * 获取题目的有效答案的数量
  27. *
  28. * 适用于:单选题,多选题,单行文本题,时间选择题
  29. *
  30. * 1. 单选题(QuRadio)
  31. * 您是否有疾病史?
  32. * yes => 是
  33. * no => 否
  34. *
  35. * 当用户选择了是或者否时:
  36. * getValidAnswerCount(QuRadio)
  37. * 返回值: 1
  38. *
  39. * 当用户跳过了该题:
  40. *
  41. * getValidAnswerCount(QuRadio)
  42. * 返回值: 0
  43. *
  44. * @param sdk.SurveyAnswer question 题目内容
  45. * @return int 有效答案的数量
  46. **/
  47. // 获取题目的有效答案的数量(不支持组合题)
  48. func GetValidAnswerCount(question sdk.SurveyAnswer) int {
  49. var total int = 0
  50. // 除了组合题,其他都支持
  51. switch question.Type {
  52. case TYPE_GROUP:
  53. for _, group := range question.GroupAnswers {
  54. for _, item := range group {
  55. total += GetValidAnswerCount(item)
  56. }
  57. }
  58. case TYPE_MATRIX_CHECKBOX:
  59. if len(question.MatrixAnswers) > 0 {
  60. total = len(question.MatrixAnswers)
  61. }
  62. case TYPE_CHECKBOX:
  63. if len(question.CheckboxAnswers) > 0 {
  64. total = len(question.CheckboxAnswers)
  65. }
  66. case TYPE_INPUT:
  67. if len(question.InputAnswers.Value) > 0 {
  68. total = len(question.InputAnswers.Value)
  69. }
  70. case TYPE_LINK:
  71. if len(question.LinkAnswers.Value) > 0 {
  72. total = len(question.LinkAnswers.Value)
  73. }
  74. default:
  75. if question.Answer.Value != "" {
  76. total = 1
  77. }
  78. }
  79. return total
  80. }
  81. /**
  82. * 获取矩阵题的有效答案
  83. *
  84. * 仅适用于:矩阵题
  85. *
  86. * 有矩阵题如下
  87. * |---------|高血压(g)|糖尿病(t)|癌症(a)|
  88. * |父亲(dad)| √ | √ | |
  89. * |母亲(mom)| √ | | √ |
  90. *
  91. * 当需要获取获取“父亲高血压”的答案时:
  92. * getValidAnswerForMatrix(Question, 'dad', 'g');
  93. * 返回值为: ['dad' => '父亲', 'g' => '高血压'] (数组)
  94. *
  95. **/
  96. // 获取矩阵题的有效答案
  97. func GetValidAnswerForMatrix(question sdk.SurveyAnswer, questionNo string, answerNo string) (*sdk.QuestionMatrixAnswerModel, error) {
  98. // 仅支持矩阵题
  99. if question.Type != TYPE_MATRIX_CHECKBOX {
  100. return nil, fmt.Errorf("不支持非矩阵题")
  101. }
  102. // 遍历矩阵题的答案
  103. for _, answer := range question.MatrixAnswers {
  104. // 如果X轴和Y轴的key都匹配,则返回true
  105. if answer.XKey == questionNo && answer.YKey == answerNo {
  106. return &answer, nil
  107. }
  108. }
  109. return nil, fmt.Errorf("没有符合要求的答案")
  110. }
  111. // 获取单选和多选题的有效答案KEY
  112. func GetValidAnswerKeysForRadioOrCheckbox(question sdk.SurveyAnswer) []string {
  113. var keys []string
  114. switch question.Type {
  115. case TYPE_CHECKBOX:
  116. for _, answer := range question.CheckboxAnswers {
  117. if answer.Key != "" {
  118. keys = append(keys, answer.Key)
  119. }
  120. }
  121. case TYPE_SELECT:
  122. for _, answer := range question.CheckboxAnswers {
  123. if answer.Key != "" {
  124. keys = append(keys, answer.Key)
  125. }
  126. }
  127. case TYPE_RADIO:
  128. if question.Answer.Value != "" && question.Answer.Key != "" {
  129. keys = append(keys, question.Answer.Key)
  130. }
  131. }
  132. return keys
  133. }
  134. // 获取单选和多选题的有效答案KEY
  135. func GetValidAnswerKeys(question sdk.SurveyAnswer) []string {
  136. var keys []string
  137. switch question.Type {
  138. case TYPE_CHECKBOX:
  139. for _, answer := range question.CheckboxAnswers {
  140. if answer.Key != "" {
  141. keys = append(keys, answer.Key)
  142. }
  143. }
  144. case TYPE_SELECT:
  145. for _, answer := range question.CheckboxAnswers {
  146. if answer.Key != "" {
  147. keys = append(keys, answer.Key)
  148. }
  149. }
  150. case TYPE_RADIO:
  151. if question.Answer.Value != "" && question.Answer.Key != "" {
  152. keys = append(keys, question.Answer.Key)
  153. }
  154. case TYPE_LINK:
  155. if len(question.LinkAnswers.Value) > 0 && question.LinkAnswers.Key != "" {
  156. keys = append(keys, question.LinkAnswers.Key)
  157. }
  158. case TYPE_INPUT:
  159. if len(question.InputAnswers.Value) > 0 && question.InputAnswers.Key != "" {
  160. keys = append(keys, question.InputAnswers.Key)
  161. }
  162. case TYPE_DATE:
  163. if len(question.InputAnswers.Value) > 0 && question.InputAnswers.Key != "" {
  164. keys = append(keys, question.InputAnswers.Key)
  165. }
  166. }
  167. return keys
  168. }
  169. func GetValidAnswerValues(question sdk.SurveyAnswer) []string {
  170. var values []string
  171. switch question.Type {
  172. case TYPE_CHECKBOX:
  173. for _, answer := range question.CheckboxAnswers {
  174. if answer.Value != "" {
  175. values = append(values, answer.Value)
  176. }
  177. }
  178. case TYPE_SELECT:
  179. for _, answer := range question.CheckboxAnswers {
  180. if answer.Value != "" {
  181. values = append(values, answer.Value)
  182. }
  183. }
  184. case TYPE_RADIO:
  185. if question.Answer.Value != "" && question.Answer.Key != "" {
  186. values = append(values, question.Answer.Value)
  187. }
  188. case TYPE_LINK:
  189. if len(question.LinkAnswers.Value) > 0 && question.LinkAnswers.Key != "" {
  190. for _, value := range question.LinkAnswers.Value {
  191. values = append(values, value.Url)
  192. }
  193. }
  194. case TYPE_INPUT:
  195. if len(question.InputAnswers.Value) > 0 && question.InputAnswers.Key != "" {
  196. values = append(values, question.InputAnswers.Value...)
  197. }
  198. case TYPE_DATE:
  199. if len(question.InputAnswers.Value) > 0 && question.InputAnswers.Key != "" {
  200. values = append(values, question.InputAnswers.Value...)
  201. }
  202. }
  203. return values
  204. }
  205. func GetValidAnswerKeyAndValues(question sdk.SurveyAnswer) []sdk.QuestionInputAnswerModel {
  206. var values []sdk.QuestionInputAnswerModel
  207. switch question.Type {
  208. case TYPE_CHECKBOX:
  209. for _, answer := range question.CheckboxAnswers {
  210. if answer.Value != "" {
  211. values = append(values, sdk.QuestionInputAnswerModel{
  212. Key: answer.Key,
  213. Value: []string{answer.Value},
  214. })
  215. }
  216. }
  217. case TYPE_SELECT:
  218. for _, answer := range question.CheckboxAnswers {
  219. if answer.Value != "" {
  220. values = append(values, sdk.QuestionInputAnswerModel{
  221. Key: answer.Key,
  222. Value: []string{answer.Value},
  223. })
  224. }
  225. }
  226. case TYPE_RADIO:
  227. if question.Answer.Value != "" && question.Answer.Key != "" {
  228. values = append(values, sdk.QuestionInputAnswerModel{
  229. Key: question.Answer.Key,
  230. Value: []string{question.Answer.Value},
  231. })
  232. }
  233. case TYPE_LINK:
  234. if len(question.LinkAnswers.Value) > 0 && question.LinkAnswers.Key != "" {
  235. linkValues := make([]string, 0)
  236. for _, value := range question.LinkAnswers.Value {
  237. linkValues = append(linkValues, value.Url)
  238. }
  239. values = append(values, sdk.QuestionInputAnswerModel{
  240. Key: question.LinkAnswers.Key,
  241. Value: linkValues,
  242. })
  243. }
  244. case TYPE_INPUT:
  245. if len(question.InputAnswers.Value) > 0 && question.InputAnswers.Key != "" {
  246. values = append(values, question.InputAnswers)
  247. }
  248. case TYPE_DATE:
  249. if len(question.InputAnswers.Value) > 0 && question.InputAnswers.Key != "" {
  250. values = append(values, question.InputAnswers)
  251. }
  252. }
  253. return values
  254. }
  255. // 获取组合题的有效答案Key和Value
  256. // question 问题答案实体
  257. // questionNo 组合题中单个问题的编号
  258. func GetValidAnswerKeyAndValuesForGroup(question sdk.SurveyAnswer, questionNo string) []sdk.QuestionInputAnswerModel {
  259. var values []sdk.QuestionInputAnswerModel
  260. switch question.Type {
  261. case TYPE_GROUP:
  262. for _, groupAnswer := range question.GroupAnswers {
  263. for _, answer := range groupAnswer {
  264. if answer.QuestionNo == questionNo {
  265. values = append(values, GetValidAnswerKeyAndValues(answer)...)
  266. }
  267. }
  268. }
  269. }
  270. return values
  271. }
  272. // 获取组合题的有效答案Value
  273. // question 问题答案实体
  274. // questionNo 组合题中单个问题的编号
  275. func GetValidAnswerValuesForGroup(question sdk.SurveyAnswer, questionNo string) []string {
  276. var values []string
  277. switch question.Type {
  278. case TYPE_GROUP:
  279. for _, groupAnswer := range question.GroupAnswers {
  280. for _, answer := range groupAnswer {
  281. if answer.QuestionNo == questionNo {
  282. values = append(values, GetValidAnswerValues(answer)...)
  283. }
  284. }
  285. }
  286. }
  287. return values
  288. }
  289. // 获取组合题的有效答案KEY
  290. // question 问题答案实体
  291. // questionNo 组合题中单个问题的编号
  292. func GetValidAnswerKeysForGroup(question sdk.SurveyAnswer, questionNo string) []string {
  293. var keys []string
  294. switch question.Type {
  295. case TYPE_GROUP:
  296. for _, groupAnswer := range question.GroupAnswers {
  297. for _, answer := range groupAnswer {
  298. if answer.QuestionNo == questionNo {
  299. keys = append(keys, GetValidAnswerKeys(answer)...)
  300. }
  301. }
  302. }
  303. }
  304. return keys
  305. }
  306. // 给定一个KEY获取单选和多选题的有效答案
  307. func GetValidAnswerForRadioOrCheckbox(question sdk.SurveyAnswer, answerKey string) (*sdk.QuestionAnswerModel, error) {
  308. switch question.Type {
  309. case TYPE_CHECKBOX:
  310. for _, answer := range question.CheckboxAnswers {
  311. if answer.Key == answerKey {
  312. return &answer, nil
  313. }
  314. }
  315. case TYPE_SELECT:
  316. for _, answer := range question.CheckboxAnswers {
  317. if answer.Key == answerKey {
  318. return &answer, nil
  319. }
  320. }
  321. case TYPE_RADIO:
  322. if question.Answer.Key == answerKey {
  323. return &question.Answer, nil
  324. }
  325. }
  326. return nil, fmt.Errorf("没有符合要求的答案")
  327. }
  328. // 判断单选或多选题的答案是否有效
  329. func CheckAnswerKeysIsValid(question sdk.SurveyAnswer, answerKeys []string) bool {
  330. // 获取有效答案的key
  331. validAnswerKeys := GetValidAnswerKeysForRadioOrCheckbox(question)
  332. // 判断两个字符串数组的交集
  333. intersectAnswers := lo.Intersect(validAnswerKeys, answerKeys)
  334. // 如果交集的数量和有效答案的数量相等,则表示答案有效
  335. return len(intersectAnswers) == len(answerKeys)
  336. }
  337. // 日期格式化
  338. func TranslateDate(date string, translateType string, baseDate string) string {
  339. if baseDate == "" {
  340. baseDate = carbon.Now().Format("Y-m-d")
  341. }
  342. switch translateType {
  343. case DATE_TYPE_AGE:
  344. // 年龄值,向下取整
  345. return fmt.Sprintf("%d", carbon.Parse(date).Age())
  346. case DATE_TYPE_DATE:
  347. // 日期类型:2022年01月01日
  348. return carbon.Parse(date).Format("Y/m/d")
  349. case DATE_TYPE_DATETIME:
  350. // 日期类型:2022年01月01日 12:00:00
  351. return carbon.Parse(date).Format("Y/m/d H:i:s")
  352. case DATE_TYPE_DAY:
  353. // 日期类型:距离某个日期的天数
  354. return fmt.Sprintf("%d", carbon.Parse(baseDate).DiffInDays(carbon.Parse(date)))
  355. case DATE_TYPE_HOUR:
  356. // 日期类型:距离某个日期的小时数
  357. return fmt.Sprintf("%d", carbon.Parse(baseDate).DiffInHours(carbon.Parse(date)))
  358. }
  359. return ""
  360. }