model.go 16 KB

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