213 lines
6.1 KiB
Go
213 lines
6.1 KiB
Go
package api
|
||
|
||
import (
|
||
"database/sql"
|
||
"net/http"
|
||
"sort"
|
||
"strings"
|
||
|
||
"server/internal/schema"
|
||
)
|
||
|
||
func MetadataHandler(meta, marketing, ymt *sql.DB) http.Handler {
|
||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||
ds := r.URL.Query().Get("datasource")
|
||
ot := r.URL.Query().Get("order_type")
|
||
db := marketing
|
||
if ds == "ymt" {
|
||
db = ymt
|
||
}
|
||
|
||
// 从代码中获取隐藏字段列表
|
||
hiddenFields := getHiddenFieldsFromCode(ds)
|
||
|
||
tables := []string{}
|
||
if ds == "ymt" {
|
||
tables = []string{"order_info", "order_cash", "order_voucher", "order_digit", "goods_voucher_batch", "goods_voucher_subject_config", "merchant", "activity"}
|
||
} else {
|
||
tables = []string{"order", "order_detail", "order_cash", "order_voucher", "plan", "key_batch", "code_batch", "voucher", "voucher_batch", "merchant_key_send"}
|
||
}
|
||
out := []map[string]interface{}{}
|
||
for _, tbl := range tables {
|
||
cols := getColumns(db, tbl)
|
||
fields := []map[string]string{}
|
||
for _, c := range cols {
|
||
tCanonical, fCanonical := canonicalField(ds, tbl, c.Name)
|
||
if tCanonical == "" || fCanonical == "" {
|
||
continue
|
||
}
|
||
|
||
// 检查字段是否在隐藏列表中
|
||
if isFieldHidden(hiddenFields, tCanonical, fCanonical) {
|
||
continue
|
||
}
|
||
|
||
lab := c.Comment
|
||
if lab == "" {
|
||
lab = fCanonical
|
||
}
|
||
fields = append(fields, map[string]string{"key": tCanonical + "." + fCanonical, "field": fCanonical, "label": lab})
|
||
}
|
||
tDisplay := displayTable(ds, tbl)
|
||
out = append(out, map[string]interface{}{"table": tDisplay, "label": tableLabel(tDisplay), "fields": fields})
|
||
}
|
||
sort.Slice(out, func(i, j int) bool { return out[i]["table"].(string) < out[j]["table"].(string) })
|
||
rec := recommendedDefaults(ds, ot)
|
||
ok(w, r, map[string]interface{}{"datasource": ds, "tables": out, "recommended": rec})
|
||
})
|
||
}
|
||
|
||
// getHiddenFieldsFromCode 从代码中获取指定数据源的隐藏字段映射
|
||
func getHiddenFieldsFromCode(ds string) map[string]map[string]bool {
|
||
// 从字段白名单构建隐藏字段映射,所有字段默认 true(隐藏)
|
||
return buildHiddenFieldsFromWhitelist()
|
||
}
|
||
|
||
// buildHiddenFieldsFromWhitelist 读取 schema.AllWhitelist 中的所有字段,按表分组,全部标记为 true
|
||
func buildHiddenFieldsFromWhitelist() map[string]map[string]bool {
|
||
out := make(map[string]map[string]bool)
|
||
for k := range schema.AllWhitelist() {
|
||
parts := strings.SplitN(k, ".", 2)
|
||
if len(parts) != 2 {
|
||
continue
|
||
}
|
||
tbl, field := parts[0], parts[1]
|
||
if _, ok := out[tbl]; !ok {
|
||
out[tbl] = make(map[string]bool)
|
||
}
|
||
out[tbl][field] = true
|
||
}
|
||
return out
|
||
}
|
||
|
||
// isFieldHidden 检查字段是否在隐藏列表中
|
||
func isFieldHidden(hiddenFields map[string]map[string]bool, table, field string) bool {
|
||
tableFields, ok := hiddenFields[table]
|
||
if !ok {
|
||
return false
|
||
}
|
||
return tableFields[field]
|
||
}
|
||
|
||
func tableLabel(t string) string {
|
||
switch t {
|
||
case "order":
|
||
return "订单主表"
|
||
case "order_detail":
|
||
return "订单详情"
|
||
case "order_cash":
|
||
return "红包订单"
|
||
case "order_voucher":
|
||
return "立减金订单"
|
||
case "order_digit":
|
||
return "直充卡密订单"
|
||
case "plan":
|
||
return "活动"
|
||
case "key_batch":
|
||
return "key批次"
|
||
case "code_batch":
|
||
return "兑换码批次"
|
||
case "voucher":
|
||
return "立减金"
|
||
case "voucher_batch":
|
||
return "立减金批次"
|
||
case "merchant_key_send":
|
||
return "key码API发放记录"
|
||
case "goods_voucher_batch":
|
||
return "立减金批次表"
|
||
case "goods_voucher_subject_config":
|
||
return "立减金主体"
|
||
case "merchant":
|
||
return "客户"
|
||
case "activity":
|
||
return "活动"
|
||
default:
|
||
return t
|
||
}
|
||
}
|
||
|
||
func displayTable(ds, tbl string) string {
|
||
if ds == "ymt" && tbl == "order_info" {
|
||
return "order"
|
||
}
|
||
return tbl
|
||
}
|
||
|
||
func canonicalField(ds, tbl, col string) (string, string) {
|
||
if ds == "ymt" && tbl == "order_info" {
|
||
switch col {
|
||
case "order_no":
|
||
return "order", "order_number"
|
||
case "key_code":
|
||
return "order", "key"
|
||
case "user_id":
|
||
return "order", "creator"
|
||
case "out_order_no":
|
||
return "order", "out_trade_no"
|
||
case "activity_id":
|
||
return "order", "plan_id"
|
||
case "merchant_id":
|
||
return "order", "reseller_id"
|
||
case "goods_id":
|
||
return "order", "product_id"
|
||
case "pay_price":
|
||
return "order", "pay_amount"
|
||
case "key_batch_name":
|
||
return "order", "key_batch_id"
|
||
default:
|
||
return "order", col
|
||
}
|
||
}
|
||
// other tables: canonical equals actual
|
||
return tbl, col
|
||
}
|
||
|
||
type columnMeta struct {
|
||
Name string
|
||
Comment string
|
||
}
|
||
|
||
func getColumns(db *sql.DB, tbl string) []columnMeta {
|
||
rows, err := db.Query("SELECT COLUMN_NAME, COLUMN_COMMENT FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = ? ORDER BY ORDINAL_POSITION", tbl)
|
||
if err != nil {
|
||
return []columnMeta{}
|
||
}
|
||
defer rows.Close()
|
||
cols := []columnMeta{}
|
||
for rows.Next() {
|
||
var name, comment string
|
||
if err := rows.Scan(&name, &comment); err == nil {
|
||
cols = append(cols, columnMeta{Name: name, Comment: comment})
|
||
}
|
||
}
|
||
return cols
|
||
}
|
||
|
||
func recommendedDefaults(ds, orderType string) []string {
|
||
base := []string{"order.order_number", "order.creator", "order.out_trade_no", "order.type", "order.status", "order.contract_price", "order.num", "order.pay_amount", "order.create_time"}
|
||
if ds != "ymt" {
|
||
base = []string{"order.order_number", "order.creator", "order.out_trade_no", "order.type", "order.status", "order.contract_price", "order.num", "order.total", "order.pay_amount", "order.create_time"}
|
||
}
|
||
t := orderType
|
||
if t == "2" { // 直充卡密
|
||
if ds == "ymt" {
|
||
base = append(base, "order_digit.order_no", "order_digit.account", "order_digit.success_time")
|
||
} else {
|
||
base = append(base, "plan.title")
|
||
}
|
||
} else if t == "3" { // 立减金
|
||
if ds == "ymt" {
|
||
base = append(base, "order_voucher.channel", "order_voucher.status", "goods_voucher_batch.channel_batch_no")
|
||
} else {
|
||
base = append(base, "order_voucher.channel", "voucher.denomination")
|
||
}
|
||
} else if t == "1" { // 红包
|
||
if ds == "ymt" {
|
||
base = append(base, "order_cash.channel", "order_cash.receive_status", "order_cash.denomination")
|
||
} else {
|
||
base = append(base, "order_cash.channel", "order_cash.receive_status", "order_cash.amount")
|
||
}
|
||
}
|
||
return base
|
||
}
|