model.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. package com_model_service
  2. import (
  3. "encoding/json"
  4. "gfast/app/model/admin/model_fields"
  5. "gfast/app/model/admin/model_info"
  6. "gfast/app/model/admin/sys_dict_type"
  7. "gfast/library/utils"
  8. "github.com/gogf/gf/container/garray"
  9. "github.com/gogf/gf/database/gdb"
  10. "github.com/gogf/gf/encoding/gjson"
  11. "github.com/gogf/gf/errors/gerror"
  12. "github.com/gogf/gf/frame/g"
  13. "github.com/gogf/gf/net/ghttp"
  14. "github.com/gogf/gf/os/gtime"
  15. "github.com/gogf/gf/text/gstr"
  16. "github.com/gogf/gf/util/gconv"
  17. )
  18. //通过模型ID获取模型字段规则
  19. func GetModelRuleByModelId(r *ghttp.Request, modelId int64, masterId int64) (rules []*model_fields.FieldRule, err error) {
  20. //1.获取模型信息
  21. modelInfo, err := model_info.GetByID(modelId)
  22. if err != nil {
  23. return
  24. }
  25. //获取模型字段信息
  26. args := &model_fields.SelectPageReq{
  27. ModelId: modelId,
  28. }
  29. //2.字段信息
  30. modelFields, err := model_fields.SelectListAll(args)
  31. if err != nil {
  32. return
  33. }
  34. //3.获取字段数据
  35. //表前缀
  36. dbPrefix := g.DB().GetPrefix()
  37. var fieldData gdb.Record
  38. if masterId != 0 {
  39. fieldData, err = g.DB().Table(dbPrefix+modelInfo.ModelName).Where(modelInfo.ModelPk, masterId).FindOne()
  40. if err != nil {
  41. g.Log().Error(err)
  42. err = gerror.New("获取模型字段数据失败")
  43. return
  44. }
  45. }
  46. //获取可编辑字段
  47. fieldEdit := garray.NewStrArrayFrom(gstr.Split(modelInfo.ModelEdit, ","))
  48. for _, field := range modelFields {
  49. rule := &model_fields.FieldRule{
  50. FOptions: g.List{},
  51. FAttr: g.Map{},
  52. FProps: g.Map{},
  53. FValidate: make([]model_fields.Validate, 0),
  54. }
  55. fAttr := g.Map{}
  56. //主键跳过不在表单显示
  57. if field.FieldName == modelInfo.ModelPk {
  58. continue
  59. }
  60. //过滤不可编辑字段
  61. if !fieldEditAble(field.FieldName, fieldEdit) {
  62. continue
  63. }
  64. //字段规则
  65. fieldRules := garray.NewStrArrayFrom(gstr.Split(field.FieldRules, ","))
  66. //隐藏字段处理
  67. if fieldRules.Contains("hidden") {
  68. continue
  69. }
  70. rule.FField = field.FieldName
  71. rule.FTitle = field.FieldTitle
  72. rule.FValue = field.FieldDefault
  73. //必填验证
  74. if fieldRules.Contains("required") {
  75. validate := model_fields.Validate{
  76. VType: "string",
  77. VRequired: true,
  78. VMessage: rule.FTitle + "不能为空",
  79. VTrigger: "blur",
  80. }
  81. rule.FValidate = append(rule.FValidate, validate)
  82. }
  83. //只读规则
  84. if fieldRules.Contains("fAttr") {
  85. fAttr["readonly"] = true
  86. }
  87. switch field.FieldType {
  88. case "baidu_map":
  89. case "text":
  90. rule.FType = "input"
  91. if fieldData != nil {
  92. rule.FValue = fieldData[field.FieldName]
  93. }
  94. case "number", "large_number", "currency":
  95. rule.FType = "inputNumber"
  96. //非负
  97. if fieldRules.Contains("unsigned") {
  98. validate := model_fields.Validate{
  99. VType: "number",
  100. VRequired: true,
  101. VMin: 0,
  102. VMessage: rule.FTitle + "不能为负数",
  103. }
  104. rule.FValidate = append(rule.FValidate, validate)
  105. }
  106. if fieldData != nil {
  107. rule.FValue = fieldData[field.FieldName]
  108. }
  109. case "datetime":
  110. rule.FType = "DatePicker"
  111. rule.FProps = g.Map{
  112. "type": "datetime",
  113. "format": "yyyy-MM-dd HH:mm:ss",
  114. "placeholder": "请选择" + field.FieldTitle,
  115. }
  116. if fieldData != nil {
  117. rule.FValue = utils.TimeStampToDateTime(gconv.Int64(fieldData[field.FieldName]))
  118. } else if field.FieldDefault == "" {
  119. rule.FValue = gtime.Now().Format("Y-m-d H:i:s")
  120. }
  121. case "date":
  122. rule.FType = "DatePicker"
  123. rule.FProps = g.Map{
  124. "format": "yyyy-MM-dd",
  125. "placeholder": "请选择" + field.FieldTitle,
  126. }
  127. if fieldData != nil {
  128. rule.FValue = utils.TimeStampToDate(gconv.Int64(fieldData[field.FieldName]))
  129. } else if field.FieldDefault == "" {
  130. rule.FValue = gtime.Now().Format("Y-m-d")
  131. }
  132. case "switch":
  133. rule.FType = "switch"
  134. rule.FProps = g.Map{
  135. "activeValue": "1",
  136. "inactiveValue": "0",
  137. }
  138. if fieldData != nil {
  139. rule.FValue = fieldData[field.FieldName]
  140. }
  141. case "bigtext":
  142. rule.FType = "input"
  143. rule.FProps = g.Map{
  144. "type": "textarea",
  145. "placeholder": "请输入" + field.FieldTitle,
  146. "rows": 5,
  147. }
  148. if fieldData != nil {
  149. rule.FValue = fieldData[field.FieldName]
  150. }
  151. case "richtext":
  152. rule.FType = "Editor"
  153. if fieldData != nil {
  154. rule.FValue = fieldData[field.FieldName]
  155. }
  156. case "selectnumber", "selecttext":
  157. rule.FType = "select"
  158. rule.FOptions, err = fieldOptionConv(field.FieldData)
  159. if err != nil {
  160. return
  161. }
  162. for k, _ := range rule.FValidate {
  163. rule.FValidate[k].VTrigger = "change"
  164. }
  165. if fieldData != nil {
  166. rule.FValue = gconv.String(fieldData[field.FieldName])
  167. }
  168. case "checkbox":
  169. rule.FType = "checkbox"
  170. if fieldData != nil {
  171. rule.FValue = gstr.Split(gconv.String(fieldData[field.FieldName]), ",")
  172. } else {
  173. if field.FieldDefault != "" {
  174. rule.FValue = gstr.Split(field.FieldDefault, ",")
  175. } else {
  176. rule.FValue = g.Slice{}
  177. }
  178. }
  179. rule.FOptions, err = fieldOptionConv(field.FieldData)
  180. if err != nil {
  181. return
  182. }
  183. for k, _ := range rule.FValidate {
  184. rule.FValidate[k].VType = "array"
  185. rule.FValidate[k].VTrigger = "change"
  186. }
  187. case "file", "files":
  188. rule.FType = "upFile"
  189. if fieldData != nil {
  190. type fileMap map[string]interface{}
  191. var filesSlice []fileMap
  192. filesByte := gconv.Bytes(fieldData[field.FieldName])
  193. if len(filesByte) > 0 {
  194. err = json.Unmarshal(filesByte, &filesSlice)
  195. if err != nil {
  196. g.Log().Error(err)
  197. err = gerror.New("获取附件信息失败")
  198. return
  199. }
  200. }
  201. for k, fm := range filesSlice {
  202. filesSlice[k]["url"], err = utils.GetRealFilesUrl(r, gconv.String(fm["url"]))
  203. if err != nil {
  204. return
  205. }
  206. }
  207. rule.FValue = filesSlice
  208. } else {
  209. if field.FieldDefault != "" {
  210. rule.FValue = gjson.New(field.FieldDefault)
  211. } else {
  212. rule.FValue = g.Slice{}
  213. }
  214. }
  215. limit := 1
  216. multiple := false
  217. if field.FieldType == "files" {
  218. limit = 6
  219. multiple = true
  220. }
  221. rule.FProps = g.Map{
  222. "type": "select",
  223. "uploadType": "file",
  224. "action": "/system/upload/upFile",
  225. "name": "file",
  226. "multiple": multiple,
  227. "limit": limit,
  228. }
  229. case "imagefile", "images":
  230. rule.FType = "upload"
  231. limit := 1
  232. multiple := false
  233. if field.FieldType == "images" {
  234. limit = 6
  235. multiple = true
  236. if fieldData != nil {
  237. imgStr := gconv.String(fieldData[field.FieldName])
  238. if imgStr != "" {
  239. imgs := gstr.Split(imgStr, ",")
  240. for k, img := range imgs {
  241. imgs[k], err = utils.GetRealFilesUrl(r, img)
  242. if err != nil {
  243. return
  244. }
  245. }
  246. rule.FValue = imgs
  247. } else {
  248. rule.FValue = g.Slice{}
  249. }
  250. } else {
  251. if field.FieldDefault != "" {
  252. rule.FValue = gstr.Split(field.FieldDefault, ",")
  253. } else {
  254. rule.FValue = g.Slice{}
  255. }
  256. }
  257. } else {
  258. if fieldData != nil {
  259. imgStr := gconv.String(fieldData[field.FieldName])
  260. if imgStr != "" {
  261. rule.FValue, err = utils.GetRealFilesUrl(r, imgStr)
  262. if err != nil {
  263. return
  264. }
  265. } else {
  266. rule.FValue = ""
  267. }
  268. } else {
  269. if field.FieldDefault != "" {
  270. rule.FValue = field.FieldDefault
  271. } else {
  272. rule.FValue = ""
  273. }
  274. }
  275. }
  276. rule.FProps = g.Map{
  277. "type": "select",
  278. "uploadType": "image",
  279. "action": "/system/upload/upImg",
  280. "name": "file",
  281. "multiple": multiple,
  282. "accept": "image/*",
  283. "limit": limit,
  284. }
  285. case "DepartmentSelector":
  286. rule.FType = "DepartmentSelector"
  287. if fieldData != nil {
  288. rule.FValue = gstr.Split(gconv.String(fieldData[field.FieldName]), ",")
  289. } else {
  290. if field.FieldDefault != "" {
  291. rule.FValue = gstr.Split(field.FieldDefault, ",")
  292. } else {
  293. rule.FValue = g.Slice{}
  294. }
  295. }
  296. rule.FProps = g.Map{
  297. "dataListApi": "/api/v1/govWork/options/getDepartmentSelector",
  298. }
  299. default:
  300. err = gerror.New("未知字段" + field.FieldName + ",类型:" + field.FieldType)
  301. return
  302. }
  303. rule.FAttr = fAttr
  304. rules = append(rules, rule)
  305. }
  306. return
  307. }
  308. //保存模型字段数据
  309. //modelId 模型ID
  310. //data 字段数据
  311. //masterId 主表主键ID
  312. func HandlePostData(modelId int64, data g.Map, masterId int64, tx *gdb.TX, isUpdate bool) (err error) {
  313. //表前缀
  314. dbPrefix := g.DB().GetPrefix()
  315. //1.获取模型信息
  316. modelInfo, err := model_info.GetByID(modelId)
  317. if err != nil {
  318. return
  319. }
  320. //获取模型字段信息
  321. //字段信息
  322. args := &model_fields.SelectPageReq{
  323. ModelId: modelId,
  324. }
  325. modelFields, err := model_fields.SelectListAll(args)
  326. if err != nil {
  327. return
  328. }
  329. //获取可编辑字段
  330. fieldEdit := garray.NewStrArrayFrom(gstr.Split(modelInfo.ModelEdit, ","))
  331. insertData := g.Map{}
  332. for _, field := range modelFields {
  333. //主键
  334. if field.FieldName == modelInfo.ModelPk {
  335. insertData[field.FieldName] = masterId
  336. }
  337. //过滤不可编辑字段
  338. if !fieldEditAble(field.FieldName, fieldEdit) {
  339. continue
  340. }
  341. //字段规则
  342. fieldRules := garray.NewStrArrayFrom(gstr.Split(field.FieldRules, ","))
  343. switch field.FieldType {
  344. case "images":
  345. //图片上传
  346. picArr := gconv.SliceStr(data[field.FieldName])
  347. for k, a := range picArr {
  348. picArr[k], err = utils.GetFilesPath(a)
  349. g.Log().Error(picArr)
  350. if err != nil {
  351. return
  352. }
  353. }
  354. insertData[field.FieldName] = gstr.Join(picArr, ",")
  355. case "files", "file":
  356. //文件上传
  357. fileArr := gconv.SliceMap(data[field.FieldName])
  358. for k, fa := range fileArr {
  359. fileArr[k]["url"], err = utils.GetFilesPath(gconv.String(fa["url"]))
  360. if err != nil {
  361. return
  362. }
  363. }
  364. insertData[field.FieldName] = gconv.String(fileArr)
  365. case "imagefile":
  366. //单图上传
  367. if _, ok := data[field.FieldName].(string); !ok {
  368. err = gerror.New("单图片上传字段必须是一个字符串")
  369. return
  370. }
  371. imgStr := gconv.String(data[field.FieldName])
  372. if imgStr != "" {
  373. imgStr, err = utils.GetFilesPath(imgStr)
  374. if err != nil {
  375. return
  376. }
  377. }
  378. insertData[field.FieldName] = imgStr
  379. case "baidu_map", "text", "bigtext", "switch", "richtext":
  380. insertData[field.FieldName] = data[field.FieldName]
  381. case "number", "large_number":
  382. insertData[field.FieldName] = gconv.Int64(data[field.FieldName])
  383. case "currency":
  384. insertData[field.FieldName] = currencyLong(data[field.FieldName])
  385. case "datetime", "date":
  386. insertData[field.FieldName] = utils.StrToTimestamp(gconv.String(data[field.FieldName]))
  387. case "selectnumber":
  388. insertData[field.FieldName] = gconv.Int64(data[field.FieldName])
  389. var b bool
  390. //验证字段数据
  391. b, err = fieldOptionValid(field.FieldData, insertData[field.FieldName])
  392. if err != nil {
  393. return
  394. }
  395. if fieldRules.Contains("required") && !b {
  396. err = gerror.New(field.FieldTitle + "数据无效")
  397. return
  398. }
  399. case "selecttext":
  400. insertData[field.FieldName] = gstr.Trim(gconv.String(data[field.FieldName]))
  401. var b bool
  402. //验证字段数据
  403. b, err = fieldOptionValid(field.FieldData, insertData[field.FieldName])
  404. if err != nil {
  405. return
  406. }
  407. if fieldRules.Contains("required") && !b {
  408. err = gerror.New(field.FieldTitle + "数据无效")
  409. return
  410. }
  411. case "checkbox":
  412. checkboxData := data[field.FieldName]
  413. var b bool
  414. //验证字段数据
  415. b, err = fieldOptionValid(field.FieldData, checkboxData)
  416. if err != nil {
  417. return
  418. }
  419. if fieldRules.Contains("required") && !b {
  420. err = gerror.New(field.FieldTitle + "数据无效")
  421. return
  422. }
  423. sliceData := gconv.SliceAny(checkboxData)
  424. dataArr := garray.NewFrom(sliceData)
  425. insertData[field.FieldName] = dataArr.Join(",")
  426. case "DepartmentSelector":
  427. data := gconv.SliceStr(data[field.FieldName])
  428. insertData[field.FieldName] = gstr.Join(data, ",")
  429. default:
  430. err = gerror.New("未知字段:" + field.FieldTitle + field.FieldType)
  431. return
  432. }
  433. //处理特殊规则-必须
  434. if fieldRules.Contains("required") {
  435. if val, ok := insertData[field.FieldName].(string); ok && val == "" {
  436. err = gerror.New(field.FieldTitle + "不能为空")
  437. return
  438. }
  439. }
  440. //唯一验证
  441. if fieldRules.Contains("unique") {
  442. var one gdb.Record
  443. one, err = g.DB().Table(dbPrefix+modelInfo.ModelName).Where(field.FieldName, insertData[field.FieldName]).FindOne()
  444. if err != nil {
  445. g.Log().Error(one)
  446. err = gerror.New("判断字段" + field.FieldTitle + "唯一性失败")
  447. return
  448. }
  449. if one != nil {
  450. if !isUpdate || (isUpdate && gconv.Int64(one[modelInfo.ModelPk]) != gconv.Int64(insertData[modelInfo.ModelPk])) {
  451. err = gerror.New(field.FieldTitle + "已存在")
  452. return
  453. }
  454. }
  455. }
  456. }
  457. //保存模型字段数据
  458. _, err = tx.Table(dbPrefix + modelInfo.ModelName).Replace(insertData)
  459. if err != nil {
  460. g.Log().Error(err)
  461. err = gerror.New("报错模型数据失败")
  462. return
  463. }
  464. return nil
  465. }
  466. //删除模型字段数据
  467. func DeleteModelFieldData(modelId int64, masterId int64, tx *gdb.TX) (err error) {
  468. //表前缀
  469. dbPrefix := g.DB().GetPrefix()
  470. //1.获取模型信息
  471. modelInfo, err := model_info.GetByID(modelId)
  472. if err != nil {
  473. return
  474. }
  475. //删除操作
  476. _, err = g.DB().Table(dbPrefix+modelInfo.ModelName).TX(tx).Where(modelInfo.ModelPk, masterId).Delete()
  477. if err != nil {
  478. g.Log().Error(err)
  479. err = gerror.New("删除模型数据失败")
  480. return
  481. }
  482. return
  483. }
  484. //字段选项数据解析
  485. func fieldOptionConv(fieldData string) (data g.List, err error) {
  486. //直接查库操作
  487. if gstr.Pos(fieldData, "|") > -1 {
  488. dataInfo := garray.NewStrArrayFrom(gstr.Split(fieldData, "|"))
  489. var (
  490. table, fieldK, fieldV, sort, where string
  491. )
  492. var has bool = true
  493. if has {
  494. table, has = dataInfo.Get(0)
  495. }
  496. if has {
  497. fieldK, has = dataInfo.Get(1)
  498. }
  499. if has {
  500. fieldV, has = dataInfo.Get(2)
  501. }
  502. if !has {
  503. err = gerror.New("数据规则格式不正确,请检查模型字段设置")
  504. }
  505. model := g.DB().Table(table).Fields(fieldK + "," + fieldV)
  506. sort, has = dataInfo.Get(3)
  507. if has {
  508. model = model.Order(sort)
  509. }
  510. where, has = dataInfo.Get(4)
  511. if has {
  512. model = model.Where(where)
  513. }
  514. var res gdb.Result
  515. res, err = model.FindAll()
  516. if err != nil {
  517. g.Log().Error(err)
  518. err = gerror.New("获取模型数据选项失败")
  519. return
  520. }
  521. for _, r := range res {
  522. data = append(data, g.Map{
  523. "value": r[fieldK],
  524. "label": r[fieldV],
  525. "disable": false,
  526. })
  527. }
  528. } else if gstr.Pos(fieldData, ":") == 0 { //从字典库查询
  529. dictType := gstr.SubStr(fieldData, 1)
  530. var dict g.Map
  531. dict, err = sys_dict_type.GetDictWithDataByType(dictType, "", "")
  532. if err != nil {
  533. return
  534. }
  535. values := gconv.SliceMap(dict["values"])
  536. for _, val := range values {
  537. data = append(data, g.Map{
  538. "value": val["key"],
  539. "label": val["value"],
  540. "disable": false,
  541. })
  542. }
  543. } else { //硬编码
  544. dataSlice := gstr.Split(fieldData, ",")
  545. for _, val := range dataSlice {
  546. keyVal := gstr.Split(val, ":")
  547. if len(keyVal) != 2 {
  548. err = gerror.New("数据规则格式不正确,请检查模型字段设置")
  549. return
  550. }
  551. data = append(data, g.Map{
  552. "value": keyVal[0],
  553. "label": keyVal[1],
  554. "disable": false,
  555. })
  556. }
  557. }
  558. return
  559. }
  560. //判断字段是否可编辑
  561. func fieldEditAble(fieldName string, fieldEdits *garray.StrArray) bool {
  562. if fieldEdits.Len() == 0 {
  563. return false
  564. }
  565. return fieldEdits.ContainsI(fieldName)
  566. }
  567. //货币转化为分
  568. func currencyLong(currency interface{}) int64 {
  569. strArr := gstr.Split(gconv.String(currency), ".")
  570. switch len(strArr) {
  571. case 1:
  572. return gconv.Int64(strArr[0]) * 100
  573. case 2:
  574. if len(strArr[1]) == 1 {
  575. strArr[1] += "0"
  576. } else if len(strArr[1]) > 2 {
  577. strArr[1] = gstr.SubStr(strArr[1], 0, 2)
  578. }
  579. return gconv.Int64(strArr[0])*100 + gconv.Int64(strArr[1])
  580. }
  581. return 0
  582. }
  583. //检测字段选项是否有效
  584. func fieldOptionValid(fieldData string, value interface{}) (bool, error) {
  585. data, err := fieldOptionConv(fieldData)
  586. if err != nil {
  587. return false, err
  588. }
  589. valueArr := garray.New()
  590. switch value.(type) {
  591. case g.Slice:
  592. valueArr = garray.NewFrom(value.(g.Slice))
  593. default:
  594. valueArr.Append(value)
  595. }
  596. //去重
  597. valueArr = valueArr.Unique()
  598. if valueArr.Len() != 0 {
  599. r := false //检查提交数据是否在选项数据中
  600. valueArr.Iterator(func(k int, v interface{}) bool {
  601. r = false
  602. for _, d := range data {
  603. if gstr.Equal(gconv.String(v), gconv.String(d["value"])) {
  604. r = true
  605. continue
  606. }
  607. }
  608. return r
  609. })
  610. return r, nil
  611. }
  612. return true, nil
  613. }