290 lines
6.9 KiB
Go
290 lines
6.9 KiB
Go
package controllers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// 本文件包含组织架构模块的请求参数解析工具。
|
|
// 前端存在 JSON、form-urlencoded 与 multipart/form-data 三种提交方式,
|
|
// 因此每个取值函数都先读 JSON body,再回退到表单参数。
|
|
|
|
func (c *BackendOrganizationController) parseJSONBody() map[string]interface{} {
|
|
body := map[string]interface{}{}
|
|
contentType := strings.ToLower(c.Ctx.Input.Header("Content-Type"))
|
|
if !strings.Contains(contentType, "json") {
|
|
return body
|
|
}
|
|
if len(c.Ctx.Input.RequestBody) == 0 {
|
|
return body
|
|
}
|
|
_ = json.Unmarshal(c.Ctx.Input.RequestBody, &body)
|
|
return body
|
|
}
|
|
|
|
// ensureFormParsed 在读取表单参数前确保请求体已被解析。
|
|
func (c *BackendOrganizationController) ensureFormParsed() {
|
|
if c.Ctx.Request.Form == nil && c.Ctx.Request.PostForm == nil && c.Ctx.Request.MultipartForm == nil {
|
|
_ = c.Ctx.Request.ParseMultipartForm(32 << 20)
|
|
}
|
|
}
|
|
|
|
func (c *BackendOrganizationController) getStringValue(body map[string]interface{}, keys ...string) (string, bool) {
|
|
for _, key := range keys {
|
|
if v, ok := body[key]; ok {
|
|
switch val := v.(type) {
|
|
case string:
|
|
return val, true
|
|
case float64:
|
|
return strconv.FormatFloat(val, 'f', -1, 64), true
|
|
case bool:
|
|
return strconv.FormatBool(val), true
|
|
case nil:
|
|
return "", true
|
|
}
|
|
}
|
|
c.ensureFormParsed()
|
|
if val := c.GetString(key); val != "" {
|
|
return val, true
|
|
}
|
|
}
|
|
return "", false
|
|
}
|
|
|
|
func (c *BackendOrganizationController) getIntValue(body map[string]interface{}, keys ...string) (int, bool) {
|
|
for _, key := range keys {
|
|
if v, ok := body[key]; ok {
|
|
switch val := v.(type) {
|
|
case float64:
|
|
return int(val), true
|
|
case int:
|
|
return val, true
|
|
case bool:
|
|
return boolInt(val), true
|
|
case string:
|
|
trimmed := strings.TrimSpace(val)
|
|
if trimmed == "" {
|
|
return 0, true
|
|
}
|
|
parsed, err := strconv.Atoi(trimmed)
|
|
return parsed, err == nil
|
|
}
|
|
}
|
|
c.ensureFormParsed()
|
|
if val := c.GetString(key); val != "" {
|
|
parsed, err := strconv.Atoi(strings.TrimSpace(val))
|
|
return parsed, err == nil
|
|
}
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
func (c *BackendOrganizationController) getUintValue(body map[string]interface{}, keys ...string) (uint, bool) {
|
|
v, ok := c.getIntValue(body, keys...)
|
|
if !ok || v < 0 {
|
|
return 0, ok && v >= 0
|
|
}
|
|
return uint(v), true
|
|
}
|
|
|
|
func (c *BackendOrganizationController) getUint64Value(body map[string]interface{}, keys ...string) (uint64, bool) {
|
|
for _, key := range keys {
|
|
if v, ok := body[key]; ok {
|
|
switch val := v.(type) {
|
|
case float64:
|
|
if val < 0 {
|
|
return 0, false
|
|
}
|
|
return uint64(val), true
|
|
case int:
|
|
if val < 0 {
|
|
return 0, false
|
|
}
|
|
return uint64(val), true
|
|
case nil:
|
|
return 0, true
|
|
case string:
|
|
trimmed := strings.TrimSpace(val)
|
|
if trimmed == "" {
|
|
return 0, true
|
|
}
|
|
parsed, err := strconv.ParseUint(trimmed, 10, 64)
|
|
return parsed, err == nil
|
|
}
|
|
}
|
|
c.ensureFormParsed()
|
|
if val := c.GetString(key); val != "" {
|
|
parsed, err := strconv.ParseUint(strings.TrimSpace(val), 10, 64)
|
|
return parsed, err == nil
|
|
}
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
func (c *BackendOrganizationController) getBoolValue(body map[string]interface{}, keys ...string) (bool, bool) {
|
|
for _, key := range keys {
|
|
if v, ok := body[key]; ok {
|
|
switch val := v.(type) {
|
|
case bool:
|
|
return val, true
|
|
case float64:
|
|
return val != 0, true
|
|
case string:
|
|
trimmed := strings.ToLower(strings.TrimSpace(val))
|
|
switch trimmed {
|
|
case "1", "true", "yes", "on":
|
|
return true, true
|
|
case "0", "false", "no", "off", "":
|
|
return false, true
|
|
}
|
|
}
|
|
}
|
|
c.ensureFormParsed()
|
|
if val := c.GetString(key); val != "" {
|
|
switch strings.ToLower(strings.TrimSpace(val)) {
|
|
case "1", "true", "yes", "on":
|
|
return true, true
|
|
case "0", "false", "no", "off":
|
|
return false, true
|
|
}
|
|
}
|
|
}
|
|
return false, false
|
|
}
|
|
|
|
// getUint64Slice 解析 ID 数组,兼容 JSON 数组与逗号分隔字符串。
|
|
func (c *BackendOrganizationController) getUint64Slice(body map[string]interface{}, keys ...string) []uint64 {
|
|
result := make([]uint64, 0)
|
|
seen := map[uint64]bool{}
|
|
|
|
appendID := func(id uint64) {
|
|
if id == 0 || seen[id] {
|
|
return
|
|
}
|
|
seen[id] = true
|
|
result = append(result, id)
|
|
}
|
|
|
|
for _, key := range keys {
|
|
if v, ok := body[key]; ok {
|
|
switch val := v.(type) {
|
|
case []interface{}:
|
|
for _, item := range val {
|
|
switch num := item.(type) {
|
|
case float64:
|
|
appendID(uint64(num))
|
|
case string:
|
|
if parsed, err := strconv.ParseUint(strings.TrimSpace(num), 10, 64); err == nil {
|
|
appendID(parsed)
|
|
}
|
|
}
|
|
}
|
|
case string:
|
|
for _, part := range strings.Split(val, ",") {
|
|
if parsed, err := strconv.ParseUint(strings.TrimSpace(part), 10, 64); err == nil {
|
|
appendID(parsed)
|
|
}
|
|
}
|
|
case float64:
|
|
appendID(uint64(val))
|
|
}
|
|
}
|
|
if len(result) > 0 {
|
|
return result
|
|
}
|
|
c.ensureFormParsed()
|
|
if raw := c.GetString(key); raw != "" {
|
|
for _, part := range strings.Split(raw, ",") {
|
|
if parsed, err := strconv.ParseUint(strings.TrimSpace(part), 10, 64); err == nil {
|
|
appendID(parsed)
|
|
}
|
|
}
|
|
}
|
|
if len(result) > 0 {
|
|
return result
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (c *BackendOrganizationController) getUintSlice(body map[string]interface{}, keys ...string) []uint {
|
|
ids := c.getUint64Slice(body, keys...)
|
|
result := make([]uint, 0, len(ids))
|
|
for _, id := range ids {
|
|
result = append(result, uint(id))
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (c *BackendOrganizationController) pathUint(name string) (uint, bool) {
|
|
id, err := strconv.ParseUint(c.Ctx.Input.Param(name), 10, 64)
|
|
return uint(id), err == nil && id > 0
|
|
}
|
|
|
|
func (c *BackendOrganizationController) pathUint64(name string) (uint64, bool) {
|
|
id, err := strconv.ParseUint(c.Ctx.Input.Param(name), 10, 64)
|
|
return id, err == nil && id > 0
|
|
}
|
|
|
|
func (c *BackendOrganizationController) nowString() string {
|
|
return time.Now().Format("2006-01-02 15:04:05")
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 与 ORM 交互的通用小工具
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func strPtrIfNotEmpty(v string) *string {
|
|
v = strings.TrimSpace(v)
|
|
if v == "" {
|
|
return nil
|
|
}
|
|
return &v
|
|
}
|
|
|
|
// nullableString 空字符串写入 NULL,便于统一区分“未填写”与“空值”。
|
|
func nullableString(v string) interface{} {
|
|
v = strings.TrimSpace(v)
|
|
if v == "" {
|
|
return nil
|
|
}
|
|
return v
|
|
}
|
|
|
|
func nullableUint64(v uint64) interface{} {
|
|
if v == 0 {
|
|
return nil
|
|
}
|
|
return v
|
|
}
|
|
|
|
func derefString(v *string) string {
|
|
if v == nil {
|
|
return ""
|
|
}
|
|
return *v
|
|
}
|
|
|
|
func boolInt(v bool) int {
|
|
if v {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func parseDatePtr(v string) *time.Time {
|
|
v = strings.TrimSpace(v)
|
|
if v == "" {
|
|
return nil
|
|
}
|
|
if t, err := time.Parse("2006-01-02", v); err == nil {
|
|
return &t
|
|
}
|
|
if t, err := time.Parse("2006-01-02 15:04:05", v); err == nil {
|
|
return &t
|
|
}
|
|
return nil
|
|
}
|