Files
quark-go/pkg/app/admin/component/form/fields/checkbox/checkbox.go
2023-12-26 10:46:42 +08:00

813 lines
23 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package checkbox
import (
"encoding/json"
"strings"
"github.com/quarkcloudio/quark-go/v2/pkg/app/admin/component/component"
"github.com/quarkcloudio/quark-go/v2/pkg/app/admin/component/form/fields/when"
"github.com/quarkcloudio/quark-go/v2/pkg/app/admin/component/form/rule"
"github.com/quarkcloudio/quark-go/v2/pkg/app/admin/component/table"
"github.com/quarkcloudio/quark-go/v2/pkg/utils/convert"
"github.com/quarkcloudio/quark-go/v2/pkg/utils/hex"
)
type Option struct {
Label string `json:"label"`
Value interface{} `json:"value"`
Disabled bool `json:"disabled,omitempty"`
}
type Component struct {
ComponentKey string `json:"componentkey"` // 组件标识
Component string `json:"component"` // 组件名称
RowProps map[string]interface{} `json:"rowProps,omitempty"` // 开启 grid 模式时传递给 Row, 仅在ProFormGroup, ProFormList, ProFormFieldSet 中有效,默认:{ gutter: 8 }
ColProps map[string]interface{} `json:"colProps,omitempty"` // 开启 grid 模式时传递给 Col默认{ xs: 24 }
Secondary bool `json:"secondary,omitempty"` // 是否是次要控件,只针对 LightFilter 下有效
Colon bool `json:"colon,omitempty"` // 配合 label 属性使用,表示是否显示 label 后面的冒号
Extra string `json:"extra,omitempty"` // 额外的提示信息,和 help 类似,当需要错误信息和提示文案同时出现时,可以使用这个。
HasFeedback bool `json:"hasFeedback,omitempty"` // 配合 validateStatus 属性使用,展示校验状态图标,建议只配合 Input 组件使用
Help string `json:"help,omitempty"` // 提示信息,如不设置,则会根据校验规则自动生成
Hidden bool `json:"hidden,omitempty"` // 是否隐藏字段(依然会收集和校验字段)
InitialValue interface{} `json:"initialValue,omitempty"` // 设置子元素默认值,如果与 Form 的 initialValues 冲突则以 Form 为准
Label string `json:"label,omitempty"` // label 标签的文本
LabelAlign string `json:"labelAlign,omitempty"` // 标签文本对齐方式
LabelCol interface{} `json:"labelCol,omitempty"` // label 标签布局,同 <Col> 组件,设置 span offset 值,如 {span: 3, offset: 12} 或 sm: {span: 3, offset: 12}。你可以通过 Form 的 labelCol 进行统一设置,不会作用于嵌套 Item。当和 Form 同时设置时,以 Item 为准
Name string `json:"name,omitempty"` // 字段名,支持数组
NoStyle bool `json:"noStyle,omitempty"` // 为 true 时不带样式,作为纯字段控件使用
Required bool `json:"required,omitempty"` // 必填样式设置。如不设置,则会根据校验规则自动生成
Tooltip string `json:"tooltip,omitempty"` // 会在 label 旁增加一个 icon悬浮后展示配置的信息
ValuePropName string `json:"valuePropName,omitempty"` // 子节点的值的属性,如 Switch 的是 'checked'。该属性为 getValueProps 的封装,自定义 getValueProps 后会失效
WrapperCol interface{} `json:"wrapperCol,omitempty"` // 需要为输入控件设置布局样式时,使用该属性,用法同 labelCol。你可以通过 Form 的 wrapperCol 进行统一设置,不会作用于嵌套 Item。当和 Form 同时设置时,以 Item 为准
Column *table.Column `json:"-"` // 列表页、详情页中列属性
Align string `json:"-"` // 设置列的对齐方式,left | right | center只在列表页、详情页中有效
Fixed interface{} `json:"-"` // IE 下无效)列是否固定,可选 true (等效于 left) left rightr只在列表页中有效
Editable bool `json:"-"` // 表格列是否可编辑,只在列表页中有效
Ellipsis bool `json:"-"` // 是否自动缩略,只在列表页、详情页中有效
Copyable bool `json:"-"` // 是否支持复制,只在列表页、详情页中有效
Filters interface{} `json:"-"` // 表头的筛选菜单项,当值为 true 时,自动使用 valueEnum 生成,只在列表页中有效
Order int `json:"-"` // 查询表单中的权重,权重大排序靠前,只在列表页中有效
Sorter interface{} `json:"-"` // 可排序列,只在列表页中有效
Span int `json:"-"` // 包含列的数量,只在详情页中有效
ColumnWidth int `json:"-"` // 设置列宽,只在列表页中有效
Api string `json:"api,omitempty"` // 获取数据接口
Ignore bool `json:"ignore"` // 是否忽略保存到数据库,默认为 false
Rules []*rule.Rule `json:"-"` // 全局校验规则
CreationRules []*rule.Rule `json:"-"` // 创建页校验规则
UpdateRules []*rule.Rule `json:"-"` // 编辑页校验规则
FrontendRules []*rule.Rule `json:"frontendRules"` // 前端校验规则,设置字段的校验逻辑
When *when.Component `json:"when"` //
WhenItem []*when.Item `json:"-"` //
ShowOnIndex bool `json:"-"` // 在列表页展示
ShowOnDetail bool `json:"-"` // 在详情页展示
ShowOnCreation bool `json:"-"` // 在创建页面展示
ShowOnUpdate bool `json:"-"` // 在编辑页面展示
ShowOnExport bool `json:"-"` // 在导出的Excel上展示
ShowOnImport bool `json:"-"` // 在导入Excel上展示
Callback interface{} `json:"-"` // 回调函数
DefaultValue interface{} `json:"defaultValue,omitempty"` // 默认选中的选项
Disabled bool `json:"disabled,omitempty"` // 整组失效
Value interface{} `json:"value,omitempty"` // 指定选中项,string[] | number[]
Options []*Option `json:"options,omitempty"` // 可选项数据源
}
// 初始化组件
func New() *Component {
return (&Component{}).Init()
}
// 初始化
func (p *Component) Init() *Component {
p.Component = "checkboxField"
p.Colon = true
p.LabelAlign = "right"
p.ShowOnIndex = true
p.ShowOnDetail = true
p.ShowOnCreation = true
p.ShowOnUpdate = true
p.ShowOnExport = true
p.ShowOnImport = true
p.Column = (&table.Column{}).Init()
p.SetKey(component.DEFAULT_KEY, component.DEFAULT_CRYPT)
return p
}
// 设置Key
func (p *Component) SetKey(key string, crypt bool) *Component {
p.ComponentKey = hex.Make(key, crypt)
return p
}
// 会在 label 旁增加一个 icon悬浮后展示配置的信息
func (p *Component) SetTooltip(tooltip string) *Component {
p.Tooltip = tooltip
return p
}
// 开启 grid 模式时传递给 Row, 仅在ProFormGroup, ProFormList, ProFormFieldSet 中有效,默认:{ gutter: 8 }
func (p *Component) SetRowProps(rowProps map[string]interface{}) *Component {
p.RowProps = rowProps
return p
}
// 开启 grid 模式时传递给 Col默认{ xs: 24 }
func (p *Component) SetColProps(colProps map[string]interface{}) *Component {
p.ColProps = colProps
return p
}
// 是否是次要控件,只针对 LightFilter 下有效
func (p *Component) SetSecondary(secondary bool) *Component {
p.Secondary = secondary
return p
}
// 配合 label 属性使用,表示是否显示 label 后面的冒号
func (p *Component) SetColon(colon bool) *Component {
p.Colon = colon
return p
}
// 额外的提示信息,和 help 类似,当需要错误信息和提示文案同时出现时,可以使用这个。
func (p *Component) SetExtra(extra string) *Component {
p.Extra = extra
return p
}
// 配合 validateStatus 属性使用,展示校验状态图标,建议只配合 Input 组件使用
func (p *Component) SetHasFeedback(hasFeedback bool) *Component {
p.HasFeedback = hasFeedback
return p
}
// 配合 help 属性使用,展示校验状态图标,建议只配合 Input 组件使用
func (p *Component) SetHelp(help string) *Component {
p.Help = help
return p
}
// 为 true 时不带样式,作为纯字段控件使用
func (p *Component) SetNoStyle() *Component {
p.NoStyle = true
return p
}
// label 标签的文本
func (p *Component) SetLabel(label string) *Component {
p.Label = label
return p
}
// 标签文本对齐方式
func (p *Component) SetLabelAlign(align string) *Component {
p.LabelAlign = align
return p
}
// label 标签布局,同 <Col> 组件,设置 span offset 值,如 {span: 3, offset: 12} 或 sm: {span: 3, offset: 12}。
// 你可以通过 Form 的 labelCol 进行统一设置。当和 Form 同时设置时,以 Item 为准
func (p *Component) SetLabelCol(col interface{}) *Component {
p.LabelCol = col
return p
}
// 字段名,支持数组
func (p *Component) SetName(name string) *Component {
p.Name = name
return p
}
// 字段名转标签,只支持英文
func (p *Component) SetNameAsLabel() *Component {
p.Label = strings.Title(p.Name)
return p
}
// 是否必填,如不设置,则会根据校验规则自动生成
func (p *Component) SetRequired() *Component {
p.Required = true
return p
}
// 生成前端验证规则
func (p *Component) BuildFrontendRules(path string) interface{} {
var (
frontendRules []*rule.Rule
rules []*rule.Rule
creationRules []*rule.Rule
updateRules []*rule.Rule
)
uri := strings.Split(path, "/")
isCreating := (uri[len(uri)-1] == "create") || (uri[len(uri)-1] == "store")
isEditing := (uri[len(uri)-1] == "edit") || (uri[len(uri)-1] == "update")
if len(p.Rules) > 0 {
rules = rule.ConvertToFrontendRules(p.Rules)
}
if isCreating && len(p.CreationRules) > 0 {
creationRules = rule.ConvertToFrontendRules(p.CreationRules)
}
if isEditing && len(p.UpdateRules) > 0 {
updateRules = rule.ConvertToFrontendRules(p.UpdateRules)
}
if len(rules) > 0 {
frontendRules = append(frontendRules, rules...)
}
if len(creationRules) > 0 {
frontendRules = append(frontendRules, creationRules...)
}
if len(updateRules) > 0 {
frontendRules = append(frontendRules, updateRules...)
}
p.FrontendRules = frontendRules
return p
}
// 校验规则,设置字段的校验逻辑
//
// []*rule.Rule{
// rule.Required(true, "用户名必须填写"),
// rule.Min(6, "用户名不能少于6个字符"),
// rule.Max(20, "用户名不能超过20个字符"),
// }
func (p *Component) SetRules(rules []*rule.Rule) *Component {
for k, v := range rules {
rules[k] = v.SetName(p.Name)
}
p.Rules = rules
return p
}
// 校验规则,只在创建表单提交时生效
//
// []*rule.Rule{
// rule.Unique("admins", "username", "用户名已存在"),
// }
func (p *Component) SetCreationRules(rules []*rule.Rule) *Component {
for k, v := range rules {
rules[k] = v.SetName(p.Name)
}
p.CreationRules = rules
return p
}
// 校验规则,只在更新表单提交时生效
//
// []*rule.Rule{
// rule.Unique("admins", "username", "{id}", "用户名已存在"),
// }
func (p *Component) SetUpdateRules(rules []*rule.Rule) *Component {
for k, v := range rules {
rules[k] = v.SetName(p.Name)
}
p.UpdateRules = rules
return p
}
// 获取全局验证规则
func (p *Component) GetRules() []*rule.Rule {
return p.Rules
}
// 获取创建表单验证规则
func (p *Component) GetCreationRules() []*rule.Rule {
return p.CreationRules
}
// 获取更新表单验证规则
func (p *Component) GetUpdateRules() []*rule.Rule {
return p.UpdateRules
}
// 子节点的值的属性,如 Switch 的是 "checked"
func (p *Component) SetValuePropName(valuePropName string) *Component {
p.ValuePropName = valuePropName
return p
}
// 需要为输入控件设置布局样式时,使用该属性,用法同 labelCol。
// 你可以通过 Form 的 wrapperCol 进行统一设置。当和 Form 同时设置时,以 Item 为准。
func (p *Component) SetWrapperCol(col interface{}) *Component {
p.WrapperCol = col
return p
}
// 列表页、详情页中列属性
func (p *Component) SetColumn(f func(column *table.Column) *table.Column) *Component {
p.Column = f(p.Column)
return p
}
// 设置列的对齐方式,left | right | center只在列表页、详情页中有效
func (p *Component) SetAlign(align string) *Component {
p.Align = align
return p
}
// IE 下无效)列是否固定,可选 true (等效于 left) left rightr只在列表页中有效
func (p *Component) SetFixed(fixed interface{}) *Component {
p.Fixed = fixed
return p
}
// 表格列是否可编辑,只在列表页中有效
func (p *Component) SetEditable(editable bool) *Component {
p.Editable = editable
return p
}
// 是否自动缩略,只在列表页、详情页中有效
func (p *Component) SetEllipsis(ellipsis bool) *Component {
p.Ellipsis = ellipsis
return p
}
// 是否支持复制,只在列表页、详情页中有效
func (p *Component) SetCopyable(copyable bool) *Component {
p.Copyable = copyable
return p
}
// 表头的筛选菜单项,当值为 true 时,自动使用 valueEnum 生成,只在列表页中有效
func (p *Component) SetFilters(filters interface{}) *Component {
getFilters, ok := filters.(map[string]string)
if ok {
tmpFilters := []map[string]string{}
for k, v := range getFilters {
tmpFilters = append(tmpFilters, map[string]string{
"text": v,
"value": k,
})
}
p.Filters = tmpFilters
} else {
p.Filters = filters
}
return p
}
// 查询表单中的权重,权重大排序靠前,只在列表页中有效
func (p *Component) SetOrder(order int) *Component {
p.Order = order
return p
}
// 可排序列,只在列表页中有效
func (p *Component) SetSorter(sorter bool) *Component {
p.Sorter = sorter
return p
}
// 包含列的数量,只在详情页中有效
func (p *Component) SetSpan(span int) *Component {
p.Span = span
return p
}
// 设置列宽,只在列表页中有效
func (p *Component) SetColumnWidth(width int) *Component {
p.ColumnWidth = width
return p
}
// 设置保存值。
func (p *Component) SetValue(value interface{}) *Component {
p.Value = value
return p
}
// 设置默认值。
func (p *Component) SetDefault(value interface{}) *Component {
p.DefaultValue = value
return p
}
// 是否禁用状态,默认为 false
func (p *Component) SetDisabled(disabled bool) *Component {
p.Disabled = disabled
return p
}
// 是否忽略保存到数据库,默认为 false
func (p *Component) SetIgnore(ignore bool) *Component {
p.Ignore = ignore
return p
}
// 设置When组件数据
//
// SetWhen(1, func () interface{} {
// return []interface{}{
// field.Text("name", "姓名"),
// }
// })
//
// SetWhen(">", 1, func () interface{} {
// return []interface{}{
// field.Text("name", "姓名"),
// }
// })
func (p *Component) SetWhen(value ...any) *Component {
w := when.New()
i := when.NewItem()
var operator string
var option any
if len(value) == 2 {
operator = "="
option = value[0]
callback := value[1].(func() interface{})
i.Body = callback()
}
if len(value) == 3 {
operator = value[0].(string)
option = value[1]
callback := value[2].(func() interface{})
i.Body = callback()
}
getOption := convert.AnyToString(option)
switch operator {
case "=":
i.Condition = "<%=String(" + p.Name + ") === '" + getOption + "' %>"
break
case ">":
i.Condition = "<%=String(" + p.Name + ") > '" + getOption + "' %>"
break
case "<":
i.Condition = "<%=String(" + p.Name + ") < '" + getOption + "' %>"
break
case "<=":
i.Condition = "<%=String(" + p.Name + ") <= '" + getOption + "' %>"
break
case ">=":
i.Condition = "<%=String(" + p.Name + ") => '" + getOption + "' %>"
break
case "has":
i.Condition = "<%=(String(" + p.Name + ").indexOf('" + getOption + "') !=-1) %>"
break
case "in":
jsonStr, _ := json.Marshal(option)
i.Condition = "<%=(" + string(jsonStr) + ".indexOf(" + p.Name + ") !=-1) %>"
break
default:
i.Condition = "<%=String(" + p.Name + ") === '" + getOption + "' %>"
break
}
i.ConditionName = p.Name
i.ConditionOperator = operator
i.Option = option
p.WhenItem = append(p.WhenItem, i)
p.When = w.SetItems(p.WhenItem)
return p
}
// 获取When组件数据
func (p *Component) GetWhen() *when.Component {
return p.When
}
// Specify that the element should be hidden from the index view.
func (p *Component) HideFromIndex(callback bool) *Component {
p.ShowOnIndex = !callback
return p
}
// Specify that the element should be hidden from the detail view.
func (p *Component) HideFromDetail(callback bool) *Component {
p.ShowOnDetail = !callback
return p
}
// Specify that the element should be hidden from the creation view.
func (p *Component) HideWhenCreating(callback bool) *Component {
p.ShowOnCreation = !callback
return p
}
// Specify that the element should be hidden from the update view.
func (p *Component) HideWhenUpdating(callback bool) *Component {
p.ShowOnUpdate = !callback
return p
}
// Specify that the element should be hidden from the export file.
func (p *Component) HideWhenExporting(callback bool) *Component {
p.ShowOnExport = !callback
return p
}
// Specify that the element should be hidden from the import file.
func (p *Component) HideWhenImporting(callback bool) *Component {
p.ShowOnImport = !callback
return p
}
// Specify that the element should be hidden from the index view.
func (p *Component) OnIndexShowing(callback bool) *Component {
p.ShowOnIndex = callback
return p
}
// Specify that the element should be hidden from the detail view.
func (p *Component) OnDetailShowing(callback bool) *Component {
p.ShowOnDetail = callback
return p
}
// Specify that the element should be hidden from the creation view.
func (p *Component) ShowOnCreating(callback bool) *Component {
p.ShowOnCreation = callback
return p
}
// Specify that the element should be hidden from the update view.
func (p *Component) ShowOnUpdating(callback bool) *Component {
p.ShowOnUpdate = callback
return p
}
// Specify that the element should be hidden from the export file.
func (p *Component) ShowOnExporting(callback bool) *Component {
p.ShowOnExport = callback
return p
}
// Specify that the element should be hidden from the import file.
func (p *Component) ShowOnImporting(callback bool) *Component {
p.ShowOnImport = callback
return p
}
// Specify that the element should only be shown on the index view.
func (p *Component) OnlyOnIndex() *Component {
p.ShowOnIndex = true
p.ShowOnDetail = false
p.ShowOnCreation = false
p.ShowOnUpdate = false
p.ShowOnExport = false
p.ShowOnImport = false
return p
}
// Specify that the element should only be shown on the detail view.
func (p *Component) OnlyOnDetail() *Component {
p.ShowOnIndex = false
p.ShowOnDetail = true
p.ShowOnCreation = false
p.ShowOnUpdate = false
p.ShowOnExport = false
p.ShowOnImport = false
return p
}
// Specify that the element should only be shown on forms.
func (p *Component) OnlyOnForms() *Component {
p.ShowOnIndex = false
p.ShowOnDetail = false
p.ShowOnCreation = true
p.ShowOnUpdate = true
p.ShowOnExport = false
p.ShowOnImport = false
return p
}
// Specify that the element should only be shown on export file.
func (p *Component) OnlyOnExport() *Component {
p.ShowOnIndex = false
p.ShowOnDetail = false
p.ShowOnCreation = false
p.ShowOnUpdate = false
p.ShowOnExport = true
p.ShowOnImport = false
return p
}
// Specify that the element should only be shown on import file.
func (p *Component) OnlyOnImport() *Component {
p.ShowOnIndex = false
p.ShowOnDetail = false
p.ShowOnCreation = false
p.ShowOnUpdate = false
p.ShowOnExport = false
p.ShowOnImport = true
return p
}
// Specify that the element should be hidden from forms.
func (p *Component) ExceptOnForms() *Component {
p.ShowOnIndex = true
p.ShowOnDetail = true
p.ShowOnCreation = false
p.ShowOnUpdate = false
p.ShowOnExport = true
p.ShowOnImport = true
return p
}
// Check for showing when updating.
func (p *Component) IsShownOnUpdate() bool {
return p.ShowOnUpdate
}
// Check showing on index.
func (p *Component) IsShownOnIndex() bool {
return p.ShowOnIndex
}
// Check showing on detail.
func (p *Component) IsShownOnDetail() bool {
return p.ShowOnDetail
}
// Check for showing when creating.
func (p *Component) IsShownOnCreation() bool {
return p.ShowOnCreation
}
// Check for showing when exporting.
func (p *Component) IsShownOnExport() bool {
return p.ShowOnExport
}
// Check for showing when importing.
func (p *Component) IsShownOnImport() bool {
return p.ShowOnImport
}
// 当前可选项
func (p *Component) GetOptions() []*Option {
return p.Options
}
// 设置回调函数
func (p *Component) SetCallback(closure func() interface{}) *Component {
if closure != nil {
p.Callback = closure
}
return p
}
// 获取回调函数
func (p *Component) GetCallback() interface{} {
return p.Callback
}
// 设置属性,示例:[]*checkbox.Option{{Value: 1, Label: "中国"}, {Value: 2, Label: "美国"}, {Value: 3, Label: "日本"}}
func (p *Component) SetOptions(options []*Option) *Component {
p.Options = options
return p
}
// 获取数据接口
func (p *Component) SetApi(api string) *Component {
p.Api = api
return p
}
// 当前列值的枚举 valueEnum
func (p *Component) GetValueEnum() interface{} {
data := map[interface{}]interface{}{}
for _, v := range p.Options {
data[v.Value] = v.Label
}
return data
}
// 根据value值获取Option的Label
func (p *Component) GetOptionLabel(value interface{}) string {
var (
labels []string
values []interface{}
labelString string
)
if value, ok := value.(string); ok {
if strings.Contains(value, "[") || strings.Contains(value, "{") {
json.Unmarshal([]byte(value), &values)
}
}
if len(values) > 0 {
for _, option := range p.Options {
for _, v := range values {
if v == option.Value {
labels = append(labels, option.Label)
}
}
}
} else {
for _, option := range p.Options {
if value == option.Value {
labels = append(labels, option.Label)
}
}
}
for _, v := range labels {
labelString = labelString + "," + v
}
labelString = strings.Trim(labelString, ",")
return labelString
}
// 根据label值获取Option的Value
func (p *Component) GetOptionValue(label string) interface{} {
var values []interface{}
var value interface{}
var labels []string
getLabels := strings.Split(label, ",")
if len(getLabels) > 1 {
labels = getLabels
}
getLabels = strings.Split(label, "")
if len(getLabels) > 1 {
labels = getLabels
}
if len(labels) > 1 {
for _, v := range p.Options {
for _, getLabel := range labels {
if v.Label == getLabel {
values = append(values, v.Value)
}
}
}
} else {
for _, v := range p.Options {
if v.Label == label {
value = v.Value
}
}
}
if len(values) > 0 {
return values
}
return value
}
// 获取Option的Labels
func (p *Component) GetOptionLabels() string {
var labelString string
for _, option := range p.Options {
labelString = labelString + "," + option.Label
}
return strings.Trim(labelString, ",")
}