feat: 从黄果 NET hgdjnet-server 9bfbafe 导入 HKDJ 官网后端

来源:hgdjnet-server 9bfbafe10d417deea959bd53117bc88a10e60a83
项目身份 HKDJ / JHA-216,独立官网仓库,Jenkins 守卫键 hkdjnet
测试目录 /server/hkdj_net,App/Web API 30331/30332

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-10-16 11:20:04 +08:00
co-authored by Claude Opus 4.7
parent 99a4854def
commit 85c0071fd8
653 changed files with 85000 additions and 0 deletions
+129
View File
@@ -0,0 +1,129 @@
package utils
import (
"encoding/json"
"hkdj-web-server/pub/common/netutil"
"math/rand/v2"
"strings"
"github.com/gosimple/slug"
)
// BinarySearch BinarySearch
func BinarySearch(s []string, t string, n int) (idx int) {
idx = -1
if n == 0 {
return
}
start, end := 0, n-1
for start <= end {
mid := (start + end) >> 1
if s[mid] < t {
start = mid + 1
} else if s[mid] > t {
end = mid - 1
} else {
idx = mid
break
}
}
return
}
var YesOrNo = map[bool]string{
true: "是",
false: "否",
}
// ApplyImgCdn 尝试解析节点 Content JSON,若含 "img" 字段则对其拼接 CDN 后重新序列化。
// 不符合 {"img": "..."} 结构的 Content 原样返回。
func ApplyImgCdn(cdn, content string) string {
if content == "" || cdn == "" {
return content
}
var m map[string]interface{}
if err := json.Unmarshal([]byte(content), &m); err != nil {
return content // 非 JSON 对象,原样返回
}
imgVal, ok := m["img"]
if !ok {
return content // 无 img 字段,原样返回
}
imgStr, ok := imgVal.(string)
if !ok || imgStr == "" {
return content
}
m["img"] = netutil.MergeURL(cdn, imgStr)
b, err := json.Marshal(m)
if err != nil {
return content
}
return string(b)
}
// 截取指定长度的字符串
func GetPrefix(s string, n int) string {
runes := []rune(s)
if len(runes) <= n {
return s
}
return string(runes[:n])
}
func GetRandomLetters(n int) string {
const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
b := make([]byte, n)
for i := range b {
b[i] = letters[rand.IntN(len(letters))]
}
return string(b)
}
func GetSlugInfo(text string) string {
return SanitizeSlug(slug.Make(text))
}
// SanitizeSlug 去掉 slug 中的横杠等特殊符号,只保留字母和数字
func SanitizeSlug(s string) string {
s = strings.TrimSpace(s)
if s == "" {
return ""
}
var b strings.Builder
b.Grow(len(s))
for _, r := range s {
if r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z' || r >= '0' && r <= '9' {
b.WriteRune(r)
}
}
return b.String()
}
// IsSlugAllDigits 判断 slug 是否全为数字
func IsSlugAllDigits(s string) bool {
s = strings.TrimSpace(s)
if s == "" {
return false
}
for _, r := range s {
if r < '0' || r > '9' {
return false
}
}
return true
}
// MakeUniqueSlug 生成唯一 slug;exists 返回 true 表示已被占用。生成结果不能全是数字。
func MakeUniqueSlug(source string, exists func(string) bool) string {
pinyin := GetSlugInfo(source)
if pinyin == "" {
pinyin = GetRandomLetters(5)
} else if IsSlugAllDigits(pinyin) {
pinyin = pinyin + GetRandomLetters(3)
}
finalSlug := pinyin
for exists(finalSlug) {
finalSlug = pinyin + GetRandomLetters(3)
}
return finalSlug
}