Files
gfast/app/service/common/com_model_service/model.go
T
2020-09-16 15:46:11 +08:00

625 lines
16 KiB
Go

package com_model_service
import (
"encoding/json"
"gfast/app/model/admin/model_fields"
"gfast/app/model/admin/model_info"
"gfast/app/model/admin/sys_dict_type"
"gfast/library/utils"
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/database/gdb"
"github.com/gogf/gf/encoding/gjson"
"github.com/gogf/gf/errors/gerror"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
"github.com/gogf/gf/os/gtime"
"github.com/gogf/gf/text/gstr"
"github.com/gogf/gf/util/gconv"
)
//通过模型ID获取模型字段规则
func GetModelRuleByModelId(r *ghttp.Request, modelId int64, masterId int64) (rules []*model_fields.FieldRule, err error) {
//1.获取模型信息
modelInfo, err := model_info.GetByID(modelId)
if err != nil {
return
}
//获取模型字段信息
args := &model_fields.SelectPageReq{
ModelId: modelId,
}
//2.字段信息
modelFields, err := model_fields.SelectListAll(args)
if err != nil {
return
}
//3.获取字段数据
//表前缀
dbPrefix := g.DB().GetPrefix()
var fieldData gdb.Record
if masterId != 0 {
fieldData, err = g.DB().Table(dbPrefix+modelInfo.ModelName).Where(modelInfo.ModelPk, masterId).FindOne()
if err != nil {
g.Log().Error(err)
err = gerror.New("获取模型字段数据失败")
return
}
}
//获取可编辑字段
fieldEdit := garray.NewStrArrayFrom(gstr.Split(modelInfo.ModelEdit, ","))
for _, field := range modelFields {
rule := &model_fields.FieldRule{
FOptions: g.List{},
FAttr: g.Map{},
FProps: g.Map{},
FValidate: make([]model_fields.Validate, 0),
}
fAttr := g.Map{}
//主键跳过不在表单显示
if field.FieldName == modelInfo.ModelPk {
continue
}
//过滤不可编辑字段
if !fieldEditAble(field.FieldName, fieldEdit) {
continue
}
//字段规则
fieldRules := garray.NewStrArrayFrom(gstr.Split(field.FieldRules, ","))
//隐藏字段处理
if fieldRules.Contains("hidden") {
continue
}
rule.FField = field.FieldName
rule.FTitle = field.FieldTitle
rule.FValue = field.FieldDefault
//必填验证
if fieldRules.Contains("required") {
validate := model_fields.Validate{
VType: "string",
VRequired: true,
VMessage: rule.FTitle + "不能为空",
VTrigger: "blur",
}
rule.FValidate = append(rule.FValidate, validate)
}
//只读规则
if fieldRules.Contains("fAttr") {
fAttr["readonly"] = true
}
switch field.FieldType {
case "baidu_map":
case "text":
rule.FType = "input"
if fieldData != nil {
rule.FValue = fieldData[field.FieldName]
}
case "number", "large_number", "currency":
rule.FType = "inputNumber"
//非负
if fieldRules.Contains("unsigned") {
validate := model_fields.Validate{
VType: "number",
VRequired: true,
VMin: 0,
VMessage: rule.FTitle + "不能为负数",
}
rule.FValidate = append(rule.FValidate, validate)
}
if fieldData != nil {
rule.FValue = fieldData[field.FieldName]
}
case "datetime":
rule.FType = "DatePicker"
rule.FProps = g.Map{
"type": "datetime",
"format": "yyyy-MM-dd HH:mm:ss",
"placeholder": "请选择" + field.FieldTitle,
}
if fieldData != nil {
rule.FValue = utils.TimeStampToDateTime(gconv.Int64(fieldData[field.FieldName]))
} else if field.FieldDefault == "" {
rule.FValue = gtime.Now().Format("Y-m-d H:i:s")
}
case "date":
rule.FType = "DatePicker"
rule.FProps = g.Map{
"format": "yyyy-MM-dd",
"placeholder": "请选择" + field.FieldTitle,
}
if fieldData != nil {
rule.FValue = utils.TimeStampToDate(gconv.Int64(fieldData[field.FieldName]))
} else if field.FieldDefault == "" {
rule.FValue = gtime.Now().Format("Y-m-d")
}
case "switch":
rule.FType = "switch"
rule.FProps = g.Map{
"activeValue": "1",
"inactiveValue": "0",
}
if fieldData != nil {
rule.FValue = fieldData[field.FieldName]
}
case "bigtext":
rule.FType = "input"
rule.FProps = g.Map{
"type": "textarea",
"placeholder": "请输入" + field.FieldTitle,
"rows": 5,
}
if fieldData != nil {
rule.FValue = fieldData[field.FieldName]
}
case "richtext":
rule.FType = "Editor"
if fieldData != nil {
rule.FValue = fieldData[field.FieldName]
}
case "selectnumber", "selecttext":
rule.FType = "select"
rule.FOptions, err = fieldOptionConv(field.FieldData)
if err != nil {
return
}
for k, _ := range rule.FValidate {
rule.FValidate[k].VTrigger = "change"
}
if fieldData != nil {
rule.FValue = gconv.String(fieldData[field.FieldName])
}
case "checkbox":
rule.FType = "checkbox"
if fieldData != nil {
rule.FValue = gstr.Split(gconv.String(fieldData[field.FieldName]), ",")
} else {
if field.FieldDefault != "" {
rule.FValue = gstr.Split(field.FieldDefault, ",")
} else {
rule.FValue = g.Slice{}
}
}
rule.FOptions, err = fieldOptionConv(field.FieldData)
if err != nil {
return
}
for k, _ := range rule.FValidate {
rule.FValidate[k].VType = "array"
rule.FValidate[k].VTrigger = "change"
}
case "file", "files":
rule.FType = "upFile"
if fieldData != nil {
type fileMap map[string]interface{}
var filesSlice []fileMap
filesByte := gconv.Bytes(fieldData[field.FieldName])
if len(filesByte) > 0 {
err = json.Unmarshal(filesByte, &filesSlice)
if err != nil {
g.Log().Error(err)
err = gerror.New("获取附件信息失败")
return
}
}
for k, fm := range filesSlice {
filesSlice[k]["url"], err = utils.GetRealFilesUrl(r, gconv.String(fm["url"]))
if err != nil {
return
}
}
rule.FValue = filesSlice
} else {
if field.FieldDefault != "" {
rule.FValue = gjson.New(field.FieldDefault)
} else {
rule.FValue = g.Slice{}
}
}
limit := 1
multiple := false
if field.FieldType == "files" {
limit = 6
multiple = true
}
rule.FProps = g.Map{
"type": "select",
"uploadType": "file",
"action": "/system/upload/upFile",
"name": "file",
"multiple": multiple,
"limit": limit,
}
case "imagefile", "images":
rule.FType = "upload"
limit := 1
multiple := false
if field.FieldType == "images" {
limit = 6
multiple = true
if fieldData != nil {
imgStr := gconv.String(fieldData[field.FieldName])
if imgStr != "" {
imgs := gstr.Split(imgStr, ",")
for k, img := range imgs {
imgs[k], err = utils.GetRealFilesUrl(r, img)
if err != nil {
return
}
}
rule.FValue = imgs
} else {
rule.FValue = g.Slice{}
}
} else {
if field.FieldDefault != "" {
rule.FValue = gstr.Split(field.FieldDefault, ",")
} else {
rule.FValue = g.Slice{}
}
}
} else {
if fieldData != nil {
imgStr := gconv.String(fieldData[field.FieldName])
if imgStr != "" {
rule.FValue, err = utils.GetRealFilesUrl(r, imgStr)
if err != nil {
return
}
} else {
rule.FValue = ""
}
} else {
if field.FieldDefault != "" {
rule.FValue = field.FieldDefault
} else {
rule.FValue = ""
}
}
}
rule.FProps = g.Map{
"type": "select",
"uploadType": "image",
"action": "/system/upload/upImg",
"name": "file",
"multiple": multiple,
"accept": "image/*",
"limit": limit,
}
case "DepartmentSelector":
rule.FType = "DepartmentSelector"
if fieldData != nil {
rule.FValue = gstr.Split(gconv.String(fieldData[field.FieldName]), ",")
} else {
if field.FieldDefault != "" {
rule.FValue = gstr.Split(field.FieldDefault, ",")
} else {
rule.FValue = g.Slice{}
}
}
rule.FProps = g.Map{
"dataListApi": "/api/v1/govWork/options/getDepartmentSelector",
}
default:
err = gerror.New("未知字段" + field.FieldName + ",类型:" + field.FieldType)
return
}
rule.FAttr = fAttr
rules = append(rules, rule)
}
return
}
//保存模型字段数据
//modelId 模型ID
//data 字段数据
//masterId 主表主键ID
func HandlePostData(modelId int64, data g.Map, masterId int64, tx *gdb.TX, isUpdate bool) (err error) {
//表前缀
dbPrefix := g.DB().GetPrefix()
//1.获取模型信息
modelInfo, err := model_info.GetByID(modelId)
if err != nil {
return
}
//获取模型字段信息
//字段信息
args := &model_fields.SelectPageReq{
ModelId: modelId,
}
modelFields, err := model_fields.SelectListAll(args)
if err != nil {
return
}
//获取可编辑字段
fieldEdit := garray.NewStrArrayFrom(gstr.Split(modelInfo.ModelEdit, ","))
insertData := g.Map{}
for _, field := range modelFields {
//主键
if field.FieldName == modelInfo.ModelPk {
insertData[field.FieldName] = masterId
}
//过滤不可编辑字段
if !fieldEditAble(field.FieldName, fieldEdit) {
continue
}
//字段规则
fieldRules := garray.NewStrArrayFrom(gstr.Split(field.FieldRules, ","))
switch field.FieldType {
case "images":
//图片上传
picArr := gconv.SliceStr(data[field.FieldName])
for k, a := range picArr {
picArr[k], err = utils.GetFilesPath(a)
g.Log().Error(picArr)
if err != nil {
return
}
}
insertData[field.FieldName] = gstr.Join(picArr, ",")
case "files", "file":
//文件上传
fileArr := gconv.SliceMap(data[field.FieldName])
for k, fa := range fileArr {
fileArr[k]["url"], err = utils.GetFilesPath(gconv.String(fa["url"]))
if err != nil {
return
}
}
insertData[field.FieldName] = gconv.String(fileArr)
case "imagefile":
//单图上传
if _, ok := data[field.FieldName].(string); !ok {
err = gerror.New("单图片上传字段必须是一个字符串")
return
}
imgStr := gconv.String(data[field.FieldName])
if imgStr != "" {
imgStr, err = utils.GetFilesPath(imgStr)
if err != nil {
return
}
}
insertData[field.FieldName] = imgStr
case "baidu_map", "text", "bigtext", "switch", "richtext":
insertData[field.FieldName] = data[field.FieldName]
case "number", "large_number":
insertData[field.FieldName] = gconv.Int64(data[field.FieldName])
case "currency":
insertData[field.FieldName] = currencyLong(data[field.FieldName])
case "datetime", "date":
insertData[field.FieldName] = utils.StrToTimestamp(gconv.String(data[field.FieldName]))
case "selectnumber":
insertData[field.FieldName] = gconv.Int64(data[field.FieldName])
var b bool
//验证字段数据
b, err = fieldOptionValid(field.FieldData, insertData[field.FieldName])
if err != nil {
return
}
if fieldRules.Contains("required") && !b {
err = gerror.New(field.FieldTitle + "数据无效")
return
}
case "selecttext":
insertData[field.FieldName] = gstr.Trim(gconv.String(data[field.FieldName]))
var b bool
//验证字段数据
b, err = fieldOptionValid(field.FieldData, insertData[field.FieldName])
if err != nil {
return
}
if fieldRules.Contains("required") && !b {
err = gerror.New(field.FieldTitle + "数据无效")
return
}
case "checkbox":
checkboxData := data[field.FieldName]
var b bool
//验证字段数据
b, err = fieldOptionValid(field.FieldData, checkboxData)
if err != nil {
return
}
if fieldRules.Contains("required") && !b {
err = gerror.New(field.FieldTitle + "数据无效")
return
}
sliceData := gconv.SliceAny(checkboxData)
dataArr := garray.NewFrom(sliceData)
insertData[field.FieldName] = dataArr.Join(",")
case "DepartmentSelector":
data := gconv.SliceStr(data[field.FieldName])
insertData[field.FieldName] = gstr.Join(data, ",")
default:
err = gerror.New("未知字段:" + field.FieldTitle + field.FieldType)
return
}
//处理特殊规则-必须
if fieldRules.Contains("required") {
if val, ok := insertData[field.FieldName].(string); ok && val == "" {
err = gerror.New(field.FieldTitle + "不能为空")
return
}
}
//唯一验证
if fieldRules.Contains("unique") {
var one gdb.Record
one, err = g.DB().Table(dbPrefix+modelInfo.ModelName).Where(field.FieldName, insertData[field.FieldName]).FindOne()
if err != nil {
g.Log().Error(one)
err = gerror.New("判断字段" + field.FieldTitle + "唯一性失败")
return
}
if one != nil {
if !isUpdate || (isUpdate && gconv.Int64(one[modelInfo.ModelPk]) != gconv.Int64(insertData[modelInfo.ModelPk])) {
err = gerror.New(field.FieldTitle + "已存在")
return
}
}
}
}
//保存模型字段数据
_, err = tx.Table(dbPrefix + modelInfo.ModelName).Replace(insertData)
if err != nil {
g.Log().Error(err)
err = gerror.New("报错模型数据失败")
return
}
return nil
}
//删除模型字段数据
func DeleteModelFieldData(modelId int64, masterId int64, tx *gdb.TX) (err error) {
//表前缀
dbPrefix := g.DB().GetPrefix()
//1.获取模型信息
modelInfo, err := model_info.GetByID(modelId)
if err != nil {
return
}
//删除操作
_, err = g.DB().Table(dbPrefix+modelInfo.ModelName).TX(tx).Where(modelInfo.ModelPk, masterId).Delete()
if err != nil {
g.Log().Error(err)
err = gerror.New("删除模型数据失败")
return
}
return
}
//字段选项数据解析
func fieldOptionConv(fieldData string) (data g.List, err error) {
//直接查库操作
if gstr.Pos(fieldData, "|") > -1 {
dataInfo := garray.NewStrArrayFrom(gstr.Split(fieldData, "|"))
var (
table, fieldK, fieldV, sort, where string
)
var has bool = true
if has {
table, has = dataInfo.Get(0)
}
if has {
fieldK, has = dataInfo.Get(1)
}
if has {
fieldV, has = dataInfo.Get(2)
}
if !has {
err = gerror.New("数据规则格式不正确,请检查模型字段设置")
}
model := g.DB().Table(table).Fields(fieldK + "," + fieldV)
sort, has = dataInfo.Get(3)
if has {
model = model.Order(sort)
}
where, has = dataInfo.Get(4)
if has {
model = model.Where(where)
}
var res gdb.Result
res, err = model.FindAll()
if err != nil {
g.Log().Error(err)
err = gerror.New("获取模型数据选项失败")
return
}
for _, r := range res {
data = append(data, g.Map{
"value": r[fieldK],
"label": r[fieldV],
"disable": false,
})
}
} else if gstr.Pos(fieldData, ":") == 0 { //从字典库查询
dictType := gstr.SubStr(fieldData, 1)
var dict g.Map
dict, err = sys_dict_type.GetDictWithDataByType(dictType, "", "")
if err != nil {
return
}
values := gconv.SliceMap(dict["values"])
for _, val := range values {
data = append(data, g.Map{
"value": val["key"],
"label": val["value"],
"disable": false,
})
}
} else { //硬编码
dataSlice := gstr.Split(fieldData, ",")
for _, val := range dataSlice {
keyVal := gstr.Split(val, ":")
if len(keyVal) != 2 {
err = gerror.New("数据规则格式不正确,请检查模型字段设置")
return
}
data = append(data, g.Map{
"value": keyVal[0],
"label": keyVal[1],
"disable": false,
})
}
}
return
}
//判断字段是否可编辑
func fieldEditAble(fieldName string, fieldEdits *garray.StrArray) bool {
if fieldEdits.Len() == 0 {
return false
}
return fieldEdits.ContainsI(fieldName)
}
//货币转化为分
func currencyLong(currency interface{}) int64 {
strArr := gstr.Split(gconv.String(currency), ".")
switch len(strArr) {
case 1:
return gconv.Int64(strArr[0]) * 100
case 2:
if len(strArr[1]) == 1 {
strArr[1] += "0"
} else if len(strArr[1]) > 2 {
strArr[1] = gstr.SubStr(strArr[1], 0, 2)
}
return gconv.Int64(strArr[0])*100 + gconv.Int64(strArr[1])
}
return 0
}
//检测字段选项是否有效
func fieldOptionValid(fieldData string, value interface{}) (bool, error) {
data, err := fieldOptionConv(fieldData)
if err != nil {
return false, err
}
valueArr := garray.New()
switch value.(type) {
case g.Slice:
valueArr = garray.NewFrom(value.(g.Slice))
default:
valueArr.Append(value)
}
//去重
valueArr = valueArr.Unique()
if valueArr.Len() != 0 {
r := false //检查提交数据是否在选项数据中
valueArr.Iterator(func(k int, v interface{}) bool {
r = false
for _, d := range data {
if gstr.Equal(gconv.String(v), gconv.String(d["value"])) {
r = true
continue
}
}
return r
})
return r, nil
}
return true, nil
}