Compare commits
5 Commits
4467bc536d
...
00ebfdd24f
| Author | SHA1 | Date |
|---|---|---|
|
|
00ebfdd24f | |
|
|
5980ee19a8 | |
|
|
a193605e5c | |
|
|
e78a9836b4 | |
|
|
2ac2d61551 |
Binary file not shown.
|
|
@ -25,6 +25,13 @@ func (w *statusWriter) Write(b []byte)(int, error){
|
|||
|
||||
func withAccess(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
w.Header().Set("Access-Control-Allow-Methods", "GET,POST,PATCH,DELETE,OPTIONS")
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
||||
if r.Method == http.MethodOptions {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
start := time.Now()
|
||||
sw := &statusWriter{ResponseWriter: w, status: 200}
|
||||
h.ServeHTTP(sw, r)
|
||||
|
|
@ -43,4 +50,3 @@ func withAccess(h http.Handler) http.Handler {
|
|||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ func (a *ExportsAPI) create(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
var fs []string
|
||||
json.Unmarshal(fields, &fs)
|
||||
wl := whitelist()
|
||||
wl := Whitelist()
|
||||
req := exporter.BuildRequest{MainTable: main, Datasource: ds, Fields: fs, Filters: p.Filters}
|
||||
q, args, err := exporter.BuildSQL(req, wl)
|
||||
if err != nil {
|
||||
|
|
@ -106,11 +106,12 @@ func (a *ExportsAPI) create(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
r = WithSQL(r, q)
|
||||
dataDB := a.selectDataDB(ds)
|
||||
expRows, score, err := exporter.RunExplain(dataDB, q, args)
|
||||
score, sugg, err := exporter.EvaluateExplain(dataDB, q, args)
|
||||
if err != nil {
|
||||
fail(w, r, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
sugg = append(sugg, exporter.IndexSuggestions(req)...)
|
||||
const passThreshold = 60
|
||||
if score < passThreshold {
|
||||
fail(w, r, http.StatusBadRequest, fmt.Sprintf("EXPLAIN 未通过:评分=%d,请优化索引或缩小查询范围", score))
|
||||
|
|
@ -128,17 +129,9 @@ func (a *ExportsAPI) create(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
}
|
||||
for _, r := range expRows {
|
||||
if r.Table.Valid && r.Table.String == "order" && r.Rows.Valid {
|
||||
estimate = r.Rows.Int64
|
||||
break
|
||||
}
|
||||
if r.Rows.Valid {
|
||||
estimate += r.Rows.Int64
|
||||
}
|
||||
}
|
||||
estimate = 0
|
||||
}()
|
||||
labels := fieldLabels()
|
||||
labels := FieldLabels()
|
||||
hdrs := make([]string, len(fs))
|
||||
for i, tf := range fs {
|
||||
if v, ok := labels[tf]; ok {
|
||||
|
|
@ -150,10 +143,12 @@ func (a *ExportsAPI) create(w http.ResponseWriter, r *http.Request) {
|
|||
// owner from query userId if provided
|
||||
owner := uint64(0)
|
||||
if uidStr := r.URL.Query().Get("userId"); uidStr != "" {
|
||||
if n, err := strconv.ParseUint(uidStr, 10, 64); err == nil { owner = n }
|
||||
if n, err := strconv.ParseUint(uidStr, 10, 64); err == nil {
|
||||
owner = n
|
||||
}
|
||||
}
|
||||
ejSQL := "INSERT INTO export_jobs (template_id, status, requested_by, owner_id, permission_scope_json, filters_json, options_json, explain_json, explain_score, row_estimate, file_format, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"
|
||||
ejArgs := []interface{}{p.TemplateID, "queued", p.RequestedBy, owner, toJSON(p.Permission), toJSON(p.Filters), toJSON(p.Options), toJSON(expRows), score, estimate, p.FileFormat, time.Now(), time.Now()}
|
||||
ejArgs := []interface{}{p.TemplateID, "queued", p.RequestedBy, owner, toJSON(p.Permission), toJSON(p.Filters), toJSON(p.Options), toJSON(map[string]interface{}{"sql": q, "suggestions": sugg}), score, estimate, p.FileFormat, time.Now(), time.Now()}
|
||||
log.Printf("trace_id=%s sql=%s args=%v", TraceIDFrom(r), ejSQL, ejArgs)
|
||||
res, err := a.meta.Exec(ejSQL, ejArgs...)
|
||||
if err != nil {
|
||||
|
|
@ -191,7 +186,7 @@ func (a *ExportsAPI) runJob(id uint64, db *sql.DB, q string, args []interface{},
|
|||
var fl map[string]interface{}
|
||||
json.Unmarshal(fieldsJSON, &fs)
|
||||
json.Unmarshal(filtersJSON, &fl)
|
||||
wl := whitelist()
|
||||
wl := Whitelist()
|
||||
var chunks [][2]string
|
||||
if v, ok := fl["create_time_between"]; ok {
|
||||
if arr, ok2 := v.([]interface{}); ok2 && len(arr) == 2 {
|
||||
|
|
@ -244,9 +239,6 @@ func (a *ExportsAPI) runJob(id uint64, db *sql.DB, q string, args []interface{},
|
|||
}
|
||||
}
|
||||
vals = transformRow(fs, vals)
|
||||
vals = transformRow(fields, vals)
|
||||
vals = transformRow(fields, vals)
|
||||
vals = transformRow(fields, vals)
|
||||
w.WriteRow(vals)
|
||||
count++
|
||||
partCount++
|
||||
|
|
@ -525,7 +517,7 @@ func (a *ExportsAPI) runJob(id uint64, db *sql.DB, q string, args []interface{},
|
|||
var fl map[string]interface{}
|
||||
json.Unmarshal(fieldsJSON, &fs)
|
||||
json.Unmarshal(filtersJSON, &fl)
|
||||
wl := whitelist()
|
||||
wl := Whitelist()
|
||||
var chunks [][2]string
|
||||
if v, ok := fl["create_time_between"]; ok {
|
||||
if arr, ok2 := v.([]interface{}); ok2 && len(arr) == 2 {
|
||||
|
|
@ -578,10 +570,6 @@ func (a *ExportsAPI) runJob(id uint64, db *sql.DB, q string, args []interface{},
|
|||
}
|
||||
}
|
||||
vals = transformRow(fs, vals)
|
||||
vals = transformRow(fs, vals)
|
||||
vals = transformRow(fs, vals)
|
||||
vals = transformRow(fs, vals)
|
||||
vals = transformRow(fields, vals)
|
||||
x.WriteRow(vals)
|
||||
count++
|
||||
partCount++
|
||||
|
|
@ -804,11 +792,11 @@ func (a *ExportsAPI) getSQL(w http.ResponseWriter, r *http.Request, id string) {
|
|||
var fl map[string]interface{}
|
||||
json.Unmarshal(fields, &fs)
|
||||
json.Unmarshal(filters, &fl)
|
||||
wl := whitelist()
|
||||
wl := Whitelist()
|
||||
req := exporter.BuildRequest{MainTable: main, Datasource: ds, Fields: fs, Filters: fl}
|
||||
q, args, err := exporter.BuildSQL(req, wl)
|
||||
if err != nil {
|
||||
fail(w, r, http.StatusBadRequest, err.Error())
|
||||
failCat(w, r, http.StatusBadRequest, err.Error(), "sql_build_error")
|
||||
return
|
||||
}
|
||||
formatArg := func(a interface{}) string {
|
||||
|
|
@ -988,7 +976,7 @@ func (a *ExportsAPI) list(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
if err != nil {
|
||||
fail(w, r, http.StatusInternalServerError, err.Error())
|
||||
failCat(w, r, http.StatusInternalServerError, err.Error(), "explain_error")
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/http"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func MetadataHandler(meta, marketing *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 = meta }
|
||||
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 }
|
||||
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})
|
||||
})
|
||||
}
|
||||
|
||||
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 "开放平台发放记录"
|
||||
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 == "1" { // 直充卡密
|
||||
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 == "2" { // 立减金
|
||||
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 == "3" { // 红包
|
||||
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
|
||||
}
|
||||
|
|
@ -42,3 +42,10 @@ func ok(w http.ResponseWriter, r *http.Request, data interface{}) {
|
|||
func fail(w http.ResponseWriter, r *http.Request, status int, msg string) {
|
||||
writeJSON(w, r, status, 1, msg, nil)
|
||||
}
|
||||
|
||||
func failCat(w http.ResponseWriter, r *http.Request, status int, msg string, kind string) {
|
||||
writeJSON(w, r, status, 1, msg, nil)
|
||||
tid := TraceIDFrom(r)
|
||||
meta := MetaFrom(r)
|
||||
log.Printf("kind=%s trace_id=%s status=%d method=%s path=%s msg=%s", kind, tid, status, meta.Method, meta.Path, msg)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ func NewRouter(metaDB *sql.DB, marketingDB *sql.DB) http.Handler {
|
|||
mux.Handle("/api/templates/", withAccess(withTrace(TemplatesHandler(metaDB, marketingDB))))
|
||||
mux.Handle("/api/exports", withAccess(withTrace(ExportsHandler(metaDB, marketingDB))))
|
||||
mux.Handle("/api/exports/", withAccess(withTrace(ExportsHandler(metaDB, marketingDB))))
|
||||
mux.Handle("/api/metadata/fields", withAccess(withTrace(MetadataHandler(metaDB, marketingDB))))
|
||||
mux.Handle("/api/creators", withAccess(withTrace(CreatorsHandler(marketingDB))))
|
||||
mux.Handle("/api/creators/", withAccess(withTrace(CreatorsHandler(marketingDB))))
|
||||
mux.Handle("/api/resellers", withAccess(withTrace(ResellersHandler(marketingDB))))
|
||||
|
|
|
|||
|
|
@ -3,12 +3,14 @@ package api
|
|||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"marketing-system-data-tool/server/internal/exporter"
|
||||
"marketing-system-data-tool/server/internal/schema"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type TemplatesAPI struct {
|
||||
|
|
@ -72,7 +74,9 @@ func (a *TemplatesAPI) createTemplate(w http.ResponseWriter, r *http.Request) {
|
|||
if uidStr != "" {
|
||||
var uid uint64
|
||||
_, _ = fmt.Sscan(uidStr, &uid)
|
||||
if uid > 0 { p.OwnerID = uid }
|
||||
if uid > 0 {
|
||||
p.OwnerID = uid
|
||||
}
|
||||
}
|
||||
now := time.Now()
|
||||
tplSQL := "INSERT INTO export_templates (name, datasource, main_table, fields_json, filters_json, file_format, visibility, owner_id, enabled, stats_enabled, last_validated_at, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"
|
||||
|
|
@ -94,7 +98,7 @@ func (a *TemplatesAPI) listTemplates(w http.ResponseWriter, r *http.Request) {
|
|||
sqlText += " WHERE owner_id IN (0, ?)"
|
||||
args = append(args, uidStr)
|
||||
}
|
||||
sqlText += " ORDER BY updated_at DESC LIMIT 200"
|
||||
sqlText += " ORDER BY datasource ASC, id DESC LIMIT 200"
|
||||
rows, err := a.meta.Query(sqlText, args...)
|
||||
if err != nil {
|
||||
fail(w, r, http.StatusInternalServerError, err.Error())
|
||||
|
|
@ -212,10 +216,11 @@ func (a *TemplatesAPI) deleteTemplate(w http.ResponseWriter, r *http.Request, id
|
|||
}
|
||||
|
||||
func (a *TemplatesAPI) validateTemplate(w http.ResponseWriter, r *http.Request, id string) {
|
||||
row := a.meta.QueryRow("SELECT main_table, fields_json, filters_json FROM export_templates WHERE id=?", id)
|
||||
row := a.meta.QueryRow("SELECT datasource, main_table, fields_json, filters_json FROM export_templates WHERE id= ?", id)
|
||||
var ds string
|
||||
var main string
|
||||
var fields, filters []byte
|
||||
err := row.Scan(&main, &fields, &filters)
|
||||
err := row.Scan(&ds, &main, &fields, &filters)
|
||||
if err != nil {
|
||||
fail(w, r, http.StatusNotFound, "not found")
|
||||
return
|
||||
|
|
@ -224,7 +229,30 @@ func (a *TemplatesAPI) validateTemplate(w http.ResponseWriter, r *http.Request,
|
|||
var fl map[string]interface{}
|
||||
json.Unmarshal(fields, &fs)
|
||||
json.Unmarshal(filters, &fl)
|
||||
ok(w, r, nil)
|
||||
wl := Whitelist()
|
||||
req := exporter.BuildRequest{MainTable: main, Datasource: ds, Fields: fs, Filters: fl}
|
||||
q, args, err := exporter.BuildSQL(req, wl)
|
||||
if err != nil {
|
||||
failCat(w, r, http.StatusBadRequest, err.Error(), "sql_build_error")
|
||||
return
|
||||
}
|
||||
dataDB := a.selectDataDB(ds)
|
||||
score, sugg, err := exporter.EvaluateExplain(dataDB, q, args)
|
||||
if err != nil {
|
||||
failCat(w, r, http.StatusBadRequest, err.Error(), "explain_error")
|
||||
return
|
||||
}
|
||||
idxSugg := exporter.IndexSuggestions(req)
|
||||
sugg = append(sugg, idxSugg...)
|
||||
_, _ = a.meta.Exec("UPDATE export_templates SET explain_json=?, explain_score=?, last_validated_at=?, updated_at=? WHERE id=?", toJSON(map[string]interface{}{"sql": q, "suggestions": sugg}), score, time.Now(), time.Now(), id)
|
||||
ok(w, r, map[string]interface{}{"score": score, "suggestions": sugg})
|
||||
}
|
||||
|
||||
func (a *TemplatesAPI) selectDataDB(ds string) *sql.DB {
|
||||
if ds == "ymt" {
|
||||
return a.meta
|
||||
}
|
||||
return a.marketing
|
||||
}
|
||||
|
||||
func toJSON(v interface{}) []byte {
|
||||
|
|
@ -238,445 +266,8 @@ func fromJSON(b []byte) interface{} {
|
|||
return v
|
||||
}
|
||||
|
||||
func whitelist() map[string]bool {
|
||||
m := map[string]bool{
|
||||
"order.order_number": true,
|
||||
"order.key": true,
|
||||
"order.creator": true,
|
||||
"order.out_trade_no": true,
|
||||
"order.type": true,
|
||||
"order.status": true,
|
||||
"order.account": true,
|
||||
"order.product_id": true,
|
||||
"order.reseller_id": true,
|
||||
"order.plan_id": true,
|
||||
"order.key_batch_id": true,
|
||||
"order.code_batch_id": true,
|
||||
"order.pay_type": true,
|
||||
"order.pay_status": true,
|
||||
"order.use_coupon": true,
|
||||
"order.deliver_status": true,
|
||||
"order.expire_time": true,
|
||||
"order.recharge_time": true,
|
||||
"order.contract_price": true,
|
||||
"order.num": true,
|
||||
"order.total": true,
|
||||
"order.pay_amount": true,
|
||||
"order.create_time": true,
|
||||
"order.update_time": true,
|
||||
"order.official_price": true,
|
||||
"order.merchant_name": true,
|
||||
"order.activity_name": true,
|
||||
"order.goods_name": true,
|
||||
"order.pay_time": true,
|
||||
"order.coupon_id": true,
|
||||
"order.discount_amount": true,
|
||||
"order.supplier_product_name": true,
|
||||
"order.is_inner": true,
|
||||
"order.icon": true,
|
||||
"order.cost_price": true,
|
||||
"order.success_num": true,
|
||||
"order.is_reset": true,
|
||||
"order.is_retry": true,
|
||||
"order.channel": true,
|
||||
"order.is_store": true,
|
||||
"order.trace_id": true,
|
||||
"order.out_order_no": true,
|
||||
"order.next_retry_time": true,
|
||||
"order.recharge_suc_time": true,
|
||||
"order.supplier_id": true,
|
||||
"order.supplier_product_id": true,
|
||||
"order.merchant_id": true,
|
||||
"order.goods_id": true,
|
||||
"order.activity_id": true,
|
||||
"order.key_batch_name": true,
|
||||
"order_detail.plan_title": true,
|
||||
"order_detail.reseller_name": true,
|
||||
"order_detail.product_name": true,
|
||||
"order_detail.show_url": true,
|
||||
"order_detail.official_price": true,
|
||||
"order_detail.cost_price": true,
|
||||
"order_detail.create_time": true,
|
||||
"order_detail.update_time": true,
|
||||
"order_cash.channel": true,
|
||||
"order_cash.order_no": true,
|
||||
"order_cash.trade_no": true,
|
||||
"order_cash.wechat_detail_id": true,
|
||||
"order_cash.denomination": true,
|
||||
"order_cash.account": true,
|
||||
"order_cash.receive_name": true,
|
||||
"order_cash.app_id": true,
|
||||
"order_cash.cash_activity_id": true,
|
||||
"order_cash.receive_status": true,
|
||||
"order_cash.receive_time": true,
|
||||
"order_cash.success_time": true,
|
||||
"order_cash.cash_packet_id": true,
|
||||
"order_cash.cash_id": true,
|
||||
"order_cash.amount": true,
|
||||
"order_cash.activity_id": true,
|
||||
"order_cash.goods_id": true,
|
||||
"order_cash.merchant_id": true,
|
||||
"order_cash.supplier_id": true,
|
||||
"order_cash.user_id": true,
|
||||
"order_cash.status": true,
|
||||
"order_cash.expire_time": true,
|
||||
"order_cash.create_time": true,
|
||||
"order_cash.update_time": true,
|
||||
"order_cash.version": true,
|
||||
"order_cash.is_confirm": true,
|
||||
"order_voucher.channel": true,
|
||||
"order_voucher.channel_activity_id": true,
|
||||
"order_voucher.channel_voucher_id": true,
|
||||
"order_voucher.status": true,
|
||||
"order_voucher.receive_mode": true,
|
||||
"order_voucher.grant_time": true,
|
||||
"order_voucher.usage_time": true,
|
||||
"order_voucher.refund_time": true,
|
||||
"order_voucher.status_modify_time": true,
|
||||
"order_voucher.overdue_time": true,
|
||||
"order_voucher.refund_amount": true,
|
||||
"order_voucher.official_price": true,
|
||||
"order_voucher.out_biz_no": true,
|
||||
"order_voucher.account_no": true,
|
||||
"plan.id": true,
|
||||
"plan.title": true,
|
||||
"plan.status": true,
|
||||
"plan.begin_time": true,
|
||||
"plan.end_time": true,
|
||||
"key_batch.id": true,
|
||||
"key_batch.batch_name": true,
|
||||
"key_batch.bind_object": true,
|
||||
"key_batch.quantity": true,
|
||||
"key_batch.stock": true,
|
||||
"key_batch.begin_time": true,
|
||||
"key_batch.end_time": true,
|
||||
"code_batch.id": true,
|
||||
"code_batch.title": true,
|
||||
"code_batch.status": true,
|
||||
"code_batch.begin_time": true,
|
||||
"code_batch.end_time": true,
|
||||
"code_batch.quantity": true,
|
||||
"code_batch.usage": true,
|
||||
"code_batch.stock": true,
|
||||
"voucher.channel": true,
|
||||
"voucher.channel_activity_id": true,
|
||||
"voucher.price": true,
|
||||
"voucher.balance": true,
|
||||
"voucher.used_amount": true,
|
||||
"voucher.denomination": true,
|
||||
"voucher_batch.channel_activity_id": true,
|
||||
"voucher_batch.temp_no": true,
|
||||
"voucher_batch.provider": true,
|
||||
"voucher_batch.weight": true,
|
||||
"merchant_key_send.merchant_id": true,
|
||||
"merchant_key_send.out_biz_no": true,
|
||||
"merchant_key_send.key": true,
|
||||
"merchant_key_send.status": true,
|
||||
"merchant_key_send.usage_time": true,
|
||||
"merchant_key_send.create_time": true,
|
||||
"order_digit.order_no": true,
|
||||
"order_digit.card_no": true,
|
||||
"order_digit.account": true,
|
||||
"order_digit.goods_id": true,
|
||||
"order_digit.merchant_id": true,
|
||||
"order_digit.supplier_id": true,
|
||||
"order_digit.activity_id": true,
|
||||
"order_digit.user_id": true,
|
||||
"order_digit.success_time": true,
|
||||
"order_digit.supplier_product_no": true,
|
||||
"order_digit.order_type": true,
|
||||
"order_digit.end_time": true,
|
||||
"order_digit.create_time": true,
|
||||
"order_digit.update_time": true,
|
||||
"order_digit.code": true,
|
||||
"order_digit.sms_channel": true,
|
||||
"goods_voucher_batch.channel_batch_no": true,
|
||||
"goods_voucher_batch.voucher_subject_id": true,
|
||||
"goods_voucher_batch.id": true,
|
||||
"goods_voucher_batch.goods_voucher_id": true,
|
||||
"goods_voucher_batch.supplier_id": true,
|
||||
"goods_voucher_batch.temp_no": true,
|
||||
"goods_voucher_batch.index": true,
|
||||
"goods_voucher_batch.create_time": true,
|
||||
"goods_voucher_batch.update_time": true,
|
||||
"goods_voucher_subject_config.id": true,
|
||||
"goods_voucher_subject_config.name": true,
|
||||
"goods_voucher_subject_config.type": true,
|
||||
"goods_voucher_subject_config.create_time": true,
|
||||
"merchant.id": true,
|
||||
"merchant.name": true,
|
||||
"merchant.user_id": true,
|
||||
"merchant.merchant_no": true,
|
||||
"merchant.subject": true,
|
||||
"merchant.third_party": true,
|
||||
"merchant.status": true,
|
||||
"merchant.balance": true,
|
||||
"merchant.total_consumption": true,
|
||||
"merchant.contact_name": true,
|
||||
"merchant.contact_phone": true,
|
||||
"merchant.contact_email": true,
|
||||
"merchant.create_time": true,
|
||||
"merchant.update_time": true,
|
||||
"activity.id": true,
|
||||
"activity.name": true,
|
||||
"activity.user_id": true,
|
||||
"activity.merchant_id": true,
|
||||
"activity.user_name": true,
|
||||
"activity.activity_no": true,
|
||||
"activity.status": true,
|
||||
"activity.key_total_num": true,
|
||||
"activity.key_generate_num": true,
|
||||
"activity.key_usable_num": true,
|
||||
"activity.domain_url": true,
|
||||
"activity.theme_login_id": true,
|
||||
"activity.theme_list_id": true,
|
||||
"activity.theme_verify_id": true,
|
||||
"activity.settlement_type": true,
|
||||
"activity.key_expire_type": true,
|
||||
"activity.key_valid_day": true,
|
||||
"activity.key_begin_time": true,
|
||||
"activity.key_end_time": true,
|
||||
"activity.key_style": true,
|
||||
"activity.begin_time": true,
|
||||
"activity.end_time": true,
|
||||
"activity.is_retry": true,
|
||||
"activity.create_time": true,
|
||||
"activity.update_time": true,
|
||||
"activity.discard_time": true,
|
||||
"activity.delete_time": true,
|
||||
"activity.auto_charge": true,
|
||||
"activity.stock": true,
|
||||
"activity.approval_trade_no": true,
|
||||
"activity.amount": true,
|
||||
"activity.channels": true,
|
||||
"activity.key_begin": true,
|
||||
"activity.key_end": true,
|
||||
"activity.key_unit": true,
|
||||
"activity.key_pay_button_text": true,
|
||||
"activity.goods_pay_button_text": true,
|
||||
"activity.is_open_db_transaction": true,
|
||||
"activity.bank_tag": true,
|
||||
}
|
||||
return m
|
||||
}
|
||||
func Whitelist() map[string]bool { return schema.AllWhitelist() }
|
||||
|
||||
func fieldLabels() map[string]string {
|
||||
return map[string]string{
|
||||
"order.order_number": "订单编号",
|
||||
"order.key": "KEY",
|
||||
"order.creator": "创建者ID",
|
||||
"order.out_trade_no": "支付流水号",
|
||||
"order.type": "订单类型",
|
||||
"order.status": "订单状态",
|
||||
"order.account": "账号",
|
||||
"order.product_id": "商品ID",
|
||||
"order.reseller_id": "分销商ID",
|
||||
"order.plan_id": "计划ID",
|
||||
"order.key_batch_id": "KEY批次ID",
|
||||
"order.code_batch_id": "兑换批次ID",
|
||||
"order.pay_type": "支付方式",
|
||||
"order.pay_status": "支付状态",
|
||||
"order.use_coupon": "是否使用优惠券",
|
||||
"order.deliver_status": "投递状态",
|
||||
"order.expire_time": "过期处理时间",
|
||||
"order.recharge_time": "充值时间",
|
||||
"order.contract_price": "合同单价",
|
||||
"order.num": "数量",
|
||||
"order.total": "总金额",
|
||||
"order.pay_amount": "支付金额",
|
||||
"order.create_time": "创建时间",
|
||||
"order.update_time": "更新时间",
|
||||
"order.official_price": "官方价",
|
||||
"order.merchant_name": "分销商名称",
|
||||
"order.activity_name": "活动名称",
|
||||
"order.goods_name": "商品名称",
|
||||
"order.pay_time": "支付时间",
|
||||
"order.coupon_id": "优惠券ID",
|
||||
"order.discount_amount": "优惠金额",
|
||||
"order.supplier_product_name": "供应商产品名称",
|
||||
"order.is_inner": "内部供应商订单",
|
||||
"order.icon": "订单图片",
|
||||
"order.cost_price": "成本价",
|
||||
"order.success_num": "到账数量",
|
||||
"order.is_reset": "是否重置",
|
||||
"order.is_retry": "是否重试",
|
||||
"order.channel": "支付渠道",
|
||||
"order.is_store": "是否退还库存",
|
||||
"order.trace_id": "TraceID",
|
||||
"order.out_order_no": "外部订单号",
|
||||
"order.next_retry_time": "下次重试时间",
|
||||
"order.recharge_suc_time": "充值成功时间",
|
||||
"order.supplier_id": "供应商ID",
|
||||
"order.supplier_product_id": "供应商产品ID",
|
||||
"order.merchant_id": "分销商ID",
|
||||
"order.goods_id": "商品ID",
|
||||
"order.activity_id": "活动ID",
|
||||
"order.key_batch_name": "key批次名称",
|
||||
"order_detail.plan_title": "计划标题",
|
||||
"order_detail.reseller_name": "分销商名称",
|
||||
"order_detail.product_name": "商品名称",
|
||||
"order_detail.show_url": "商品图片URL",
|
||||
"order_detail.official_price": "官方价",
|
||||
"order_detail.cost_price": "成本价",
|
||||
"order_detail.create_time": "创建时间",
|
||||
"order_detail.update_time": "更新时间",
|
||||
"order_cash.order_no": "订单号",
|
||||
"order_cash.trade_no": "交易号",
|
||||
"order_cash.wechat_detail_id": "微信明细单号",
|
||||
"order_cash.channel": "渠道",
|
||||
"order_cash.denomination": "红包面额",
|
||||
"order_cash.account": "领取账号",
|
||||
"order_cash.receive_name": "真实姓名",
|
||||
"order_cash.app_id": "转账AppID",
|
||||
"order_cash.cash_activity_id": "红包批次号",
|
||||
"order_cash.receive_status": "领取状态",
|
||||
"order_cash.receive_time": "拆红包时间",
|
||||
"order_cash.success_time": "成功时间",
|
||||
"order_cash.cash_packet_id": "红包ID",
|
||||
"order_cash.cash_id": "红包规则ID",
|
||||
"order_cash.amount": "红包额度",
|
||||
"order_cash.activity_id": "活动ID",
|
||||
"order_cash.goods_id": "商品ID",
|
||||
"order_cash.merchant_id": "分销商ID",
|
||||
"order_cash.supplier_id": "供应商ID",
|
||||
"order_cash.user_id": "创建者ID",
|
||||
"order_cash.status": "状态",
|
||||
"order_cash.expire_time": "过期时间",
|
||||
"order_cash.create_time": "创建时间",
|
||||
"order_cash.update_time": "更新时间",
|
||||
"order_cash.version": "版本",
|
||||
"order_cash.is_confirm": "是否确认",
|
||||
"order_voucher.channel": "渠道",
|
||||
"order_voucher.channel_activity_id": "渠道立减金批次",
|
||||
"order_voucher.channel_voucher_id": "渠道立减金ID",
|
||||
"order_voucher.status": "状态",
|
||||
"order_voucher.receive_mode": "领取方式",
|
||||
"order_voucher.grant_time": "领取时间",
|
||||
"order_voucher.usage_time": "核销时间",
|
||||
"order_voucher.refund_time": "退款时间",
|
||||
"order_voucher.status_modify_time": "状态更新时间",
|
||||
"order_voucher.overdue_time": "过期时间",
|
||||
"order_voucher.refund_amount": "退款金额",
|
||||
"order_voucher.official_price": "官方价",
|
||||
"order_voucher.out_biz_no": "外部业务号",
|
||||
"order_voucher.account_no": "账户号",
|
||||
"plan.id": "计划ID",
|
||||
"plan.title": "计划标题",
|
||||
"plan.status": "状态",
|
||||
"plan.begin_time": "开始时间",
|
||||
"plan.end_time": "结束时间",
|
||||
"key_batch.id": "批次ID",
|
||||
"key_batch.batch_name": "批次名称",
|
||||
"key_batch.bind_object": "绑定对象",
|
||||
"key_batch.quantity": "发放数量",
|
||||
"key_batch.stock": "剩余库存",
|
||||
"key_batch.begin_time": "开始时间",
|
||||
"key_batch.end_time": "结束时间",
|
||||
"code_batch.id": "兑换批次ID",
|
||||
"code_batch.title": "标题",
|
||||
"code_batch.status": "状态",
|
||||
"code_batch.begin_time": "开始时间",
|
||||
"code_batch.end_time": "结束时间",
|
||||
"code_batch.quantity": "数量",
|
||||
"code_batch.usage": "使用数",
|
||||
"code_batch.stock": "库存",
|
||||
"voucher.channel": "渠道",
|
||||
"voucher.channel_activity_id": "渠道批次号",
|
||||
"voucher.price": "合同单价",
|
||||
"voucher.balance": "剩余额度",
|
||||
"voucher.used_amount": "已用额度",
|
||||
"voucher.denomination": "面额",
|
||||
"voucher_batch.channel_activity_id": "渠道批次号",
|
||||
"voucher_batch.temp_no": "模板编号",
|
||||
"voucher_batch.provider": "服务商",
|
||||
"voucher_batch.weight": "权重",
|
||||
"merchant_key_send.merchant_id": "商户ID",
|
||||
"merchant_key_send.out_biz_no": "商户业务号",
|
||||
"merchant_key_send.key": "券码",
|
||||
"merchant_key_send.status": "状态",
|
||||
"merchant_key_send.usage_time": "核销时间",
|
||||
"merchant_key_send.create_time": "创建时间",
|
||||
"order_digit.order_no": "订单号",
|
||||
"order_digit.card_no": "卡号",
|
||||
"order_digit.account": "充值账号",
|
||||
"order_digit.goods_id": "商品ID",
|
||||
"order_digit.merchant_id": "分销商ID",
|
||||
"order_digit.supplier_id": "供应商ID",
|
||||
"order_digit.activity_id": "活动ID",
|
||||
"order_digit.user_id": "创建者ID",
|
||||
"order_digit.success_time": "到账时间",
|
||||
"order_digit.supplier_product_no": "供应商产品编码",
|
||||
"order_digit.order_type": "订单类型",
|
||||
"order_digit.end_time": "卡密有效期",
|
||||
"order_digit.create_time": "创建时间",
|
||||
"order_digit.update_time": "更新时间",
|
||||
"order_digit.code": "验证码",
|
||||
"order_digit.sms_channel": "短信渠道",
|
||||
"goods_voucher_batch.channel_batch_no": "渠道批次号",
|
||||
"goods_voucher_batch.voucher_subject_id": "主体配置ID",
|
||||
"goods_voucher_batch.id": "ID",
|
||||
"goods_voucher_batch.goods_voucher_id": "立减金ID",
|
||||
"goods_voucher_batch.supplier_id": "供应商ID",
|
||||
"goods_voucher_batch.temp_no": "模板编号",
|
||||
"goods_voucher_batch.index": "权重",
|
||||
"goods_voucher_batch.create_time": "创建时间",
|
||||
"goods_voucher_batch.update_time": "更新时间",
|
||||
"goods_voucher_subject_config.id": "主体配置ID",
|
||||
"goods_voucher_subject_config.name": "主体名称",
|
||||
"goods_voucher_subject_config.type": "主体类型",
|
||||
"goods_voucher_subject_config.create_time": "创建时间",
|
||||
"merchant.id": "客户ID",
|
||||
"merchant.name": "客户名称",
|
||||
"merchant.user_id": "用户中心ID",
|
||||
"merchant.merchant_no": "商户编码",
|
||||
"merchant.subject": "客户主体",
|
||||
"merchant.third_party": "来源类型",
|
||||
"merchant.status": "状态",
|
||||
"merchant.balance": "客户余额",
|
||||
"merchant.total_consumption": "累计消费",
|
||||
"merchant.contact_name": "联系人名称",
|
||||
"merchant.contact_phone": "联系人电话",
|
||||
"merchant.contact_email": "联系人Email",
|
||||
"merchant.create_time": "创建时间",
|
||||
"merchant.update_time": "编辑时间",
|
||||
"activity.id": "活动ID",
|
||||
"activity.name": "活动名称",
|
||||
"activity.user_id": "创建者ID",
|
||||
"activity.merchant_id": "客户ID",
|
||||
"activity.user_name": "创建者名称",
|
||||
"activity.activity_no": "活动编号",
|
||||
"activity.status": "状态",
|
||||
"activity.key_total_num": "Key码总量",
|
||||
"activity.key_generate_num": "Key码已生成数量",
|
||||
"activity.key_usable_num": "Key可使用次数",
|
||||
"activity.domain_url": "域名",
|
||||
"activity.theme_login_id": "登录模版ID",
|
||||
"activity.theme_list_id": "列表模版ID",
|
||||
"activity.theme_verify_id": "验证模版ID",
|
||||
"activity.settlement_type": "结算方式",
|
||||
"activity.key_expire_type": "Key有效期类型",
|
||||
"activity.key_valid_day": "有效天数",
|
||||
"activity.key_begin_time": "Key有效开始时间",
|
||||
"activity.key_end_time": "Key有效结束时间",
|
||||
"activity.key_style": "Key样式",
|
||||
"activity.begin_time": "开始时间",
|
||||
"activity.end_time": "结束时间",
|
||||
"activity.is_retry": "是否自动重试",
|
||||
"activity.create_time": "创建时间",
|
||||
"activity.update_time": "修改时间",
|
||||
"activity.discard_time": "作废时间",
|
||||
"activity.delete_time": "删除时间",
|
||||
"activity.auto_charge": "是否充值到账",
|
||||
"activity.stock": "已使用库存",
|
||||
"activity.approval_trade_no": "审批交易号",
|
||||
"activity.amount": "支付金额",
|
||||
"activity.channels": "支付渠道",
|
||||
"activity.key_begin": "开始月份",
|
||||
"activity.key_end": "截止月份",
|
||||
"activity.key_unit": "时间单位",
|
||||
"activity.key_pay_button_text": "Key支付按钮文本",
|
||||
"activity.goods_pay_button_text": "商品支付按钮文本",
|
||||
"activity.is_open_db_transaction": "是否开启事务",
|
||||
"activity.bank_tag": "银行标识",
|
||||
}
|
||||
func FieldLabels() map[string]string {
|
||||
return schema.AllLabels()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
package exporter
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
"marketing-system-data-tool/server/internal/schema"
|
||||
)
|
||||
|
||||
func EvaluateExplain(db *sql.DB, q string, args []interface{}) (int, []string, error) {
|
||||
rows, score, err := RunExplain(db, q, args)
|
||||
if err != nil { return 0, nil, err }
|
||||
sugg := []string{}
|
||||
for _, r := range rows {
|
||||
// tbl := r.Table.String
|
||||
typ := r.Type.String
|
||||
if typ == "" && r.SelectType.Valid { typ = r.SelectType.String }
|
||||
if typ == "ALL" {
|
||||
sugg = append(sugg, "出现全表扫描(ALL),请在过滤或连接列上建立索引")
|
||||
}
|
||||
if r.Extra.Valid {
|
||||
e := r.Extra.String
|
||||
if contains(e, "Using temporary") || contains(e, "Using filesort") {
|
||||
sugg = append(sugg, "出现临时表或文件排序,请优化排序列及索引覆盖")
|
||||
}
|
||||
}
|
||||
}
|
||||
return score, sugg, nil
|
||||
}
|
||||
|
||||
func IndexSuggestions(req BuildRequest) []string {
|
||||
sugg := []string{}
|
||||
sch := schema.Get(req.Datasource, req.MainTable)
|
||||
// Filter-based suggestions
|
||||
has := func(k string) bool { _, ok := req.Filters[k]; return ok }
|
||||
add := func(s string){ if s != "" { sugg = append(sugg, s) } }
|
||||
if has("creator_in") && has("create_time_between") {
|
||||
add(fmt.Sprintf("建议在 `%s`(create_time, %s) 建立复合索引以覆盖权限与时间范围", sch.TableName("order"), colName(sch, "creator_in")))
|
||||
} else {
|
||||
if has("creator_in") { add(fmt.Sprintf("建议在 `%s`(%s) 建立索引以覆盖权限过滤", sch.TableName("order"), colName(sch, "creator_in"))) }
|
||||
if has("create_time_between") { add(fmt.Sprintf("建议在 `%s`(create_time) 建立索引以覆盖时间范围", sch.TableName("order"))) }
|
||||
}
|
||||
if has("plan_id_eq") { add(fmt.Sprintf("建议在 `%s`(%s) 建立索引以覆盖活动/计划过滤", sch.TableName("order"), colName(sch, "plan_id_eq"))) }
|
||||
if has("reseller_id_eq") { add(fmt.Sprintf("建议在 `%s`(%s) 建立索引以覆盖分销商过滤", sch.TableName("order"), colName(sch, "reseller_id_eq"))) }
|
||||
if has("product_id_eq") { add(fmt.Sprintf("建议在 `%s`(%s) 建立索引以覆盖商品过滤", sch.TableName("order"), colName(sch, "product_id_eq"))) }
|
||||
if has("out_trade_no_eq") { add(fmt.Sprintf("建议在 `%s`(%s) 建立索引以覆盖支付流水过滤", sch.TableName("order"), colName(sch, "out_trade_no_eq"))) }
|
||||
// Table usage-based join suggestions
|
||||
usedTables := map[string]bool{}
|
||||
for _, tf := range req.Fields {
|
||||
parts := strings.Split(tf, ".")
|
||||
if len(parts)==2 { usedTables[parts[0]] = true }
|
||||
}
|
||||
if req.MainTable == "order_info" {
|
||||
add("建议在 `order_info`(order_no) 建立索引以优化与子表的连接")
|
||||
if usedTables["order_cash"] { add("建议在 `order_cash`(order_no) 建立索引以优化与主表的连接") }
|
||||
if usedTables["order_voucher"] { add("建议在 `order_voucher`(order_no) 建立索引以优化与主表的连接") }
|
||||
if usedTables["order_digit"] { add("建议在 `order_digit`(order_no) 建立索引以优化与主表的连接") }
|
||||
if usedTables["goods_voucher_batch"] { add("建议在 `goods_voucher_batch`(channel_batch_no) 建立索引以优化与订单立减金的连接") }
|
||||
if usedTables["goods_voucher_subject_config"] { add("建议在 `goods_voucher_subject_config`(id) 上确保主键索引以优化连接") }
|
||||
if usedTables["merchant"] { add("建议在 `merchant`(id) 上确保主键索引以优化连接") }
|
||||
if usedTables["activity"] { add("建议在 `activity`(id) 上确保主键索引以优化连接") }
|
||||
}
|
||||
return dedup(sugg)
|
||||
}
|
||||
|
||||
func colName(sch schema.Schema, key string) string {
|
||||
if _, col, ok := sch.FilterColumn(key); ok { return col }
|
||||
return ""
|
||||
}
|
||||
|
||||
func dedup(arr []string) []string {
|
||||
m := map[string]bool{}
|
||||
out := []string{}
|
||||
for _, s := range arr { if !m[s] { m[s]=true; out = append(out, s) } }
|
||||
return out
|
||||
}
|
||||
|
|
@ -3,6 +3,8 @@ package exporter
|
|||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"marketing-system-data-tool/server/internal/schema"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
|
@ -18,6 +20,7 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
|
|||
if req.MainTable != "order" && req.MainTable != "order_info" {
|
||||
return "", nil, errors.New("unsupported main table")
|
||||
}
|
||||
sch := schema.Get(req.Datasource, req.MainTable)
|
||||
cols := []string{}
|
||||
need := map[string]bool{}
|
||||
for _, tf := range req.Fields {
|
||||
|
|
@ -30,56 +33,52 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
|
|||
}
|
||||
t, f := parts[0], parts[1]
|
||||
need[t] = true
|
||||
if t == "order" {
|
||||
if req.MainTable == "order_info" {
|
||||
switch f {
|
||||
case "order_number": f = "order_no"
|
||||
case "key": f = "key_code"
|
||||
case "creator": f = "user_id"
|
||||
case "out_trade_no": f = "out_order_no"
|
||||
case "plan_id": f = "activity_id"
|
||||
case "reseller_id": f = "merchant_id"
|
||||
case "product_id": f = "goods_id"
|
||||
case "pay_amount": f = "pay_price"
|
||||
case "key_batch_id": f = "key_batch_name"
|
||||
}
|
||||
cols = append(cols, "`order_info`."+escape(f))
|
||||
mt := sch.TableName(t)
|
||||
mf, _ := sch.MapField(t, f)
|
||||
if t == "order" && req.MainTable == "order" {
|
||||
if f == "status" {
|
||||
cols = append(cols, "CASE `order`.type WHEN 1 THEN '直充卡密' WHEN 2 THEN '立减金' WHEN 3 THEN '红包' ELSE '' END AS type")
|
||||
cols = append(cols, "CASE `order`.status WHEN 0 THEN '待充值' WHEN 1 THEN '充值中' WHEN 2 THEN '已完成' WHEN 3 THEN '充值失败' WHEN 4 THEN '已取消' WHEN 5 THEN '已过期' WHEN 6 THEN '待支付' END AS status")
|
||||
continue
|
||||
}
|
||||
if f == "status" {
|
||||
cols = append(cols, "CASE `order`.type " +
|
||||
"WHEN 1 THEN (CASE `order`.status WHEN 0 THEN '待充值' WHEN 1 THEN '充值中' WHEN 2 THEN '已完成' WHEN 3 THEN '充值失败' WHEN 4 THEN '已取消' WHEN 5 THEN '已过期' WHEN 6 THEN '待支付' END) " +
|
||||
"WHEN 2 THEN (CASE `order`.status WHEN 0 THEN '待领取' WHEN 1 THEN '待领取' WHEN 2 THEN '已领取' WHEN 3 THEN '领取失败' WHEN 4 THEN '已取消' WHEN 5 THEN '已过期' WHEN 6 THEN '待支付' END) " +
|
||||
"WHEN 3 THEN (CASE `order`.status WHEN 0 THEN '待领取' WHEN 1 THEN '待领取' WHEN 2 THEN '已核销' WHEN 3 THEN '领取失败' WHEN 4 THEN '已取消' WHEN 5 THEN '已过期' WHEN 6 THEN '' END) " +
|
||||
"ELSE (CASE `order`.status WHEN 0 THEN '待充值' WHEN 1 THEN '充值中' WHEN 2 THEN '已完成' WHEN 3 THEN '充值失败' WHEN 4 THEN '已取消' WHEN 5 THEN '已过期' WHEN 6 THEN '待支付' END) END AS status")
|
||||
} else if f == "type" {
|
||||
if f == "type" {
|
||||
cols = append(cols, "CASE `order`.type WHEN 1 THEN '直充卡密' WHEN 2 THEN '立减金' WHEN 3 THEN '红包' ELSE '' END AS type")
|
||||
} else if f == "type" {
|
||||
cols = append(cols, "CASE `order`.type WHEN 1 THEN '直充卡密' WHEN 2 THEN '立减金' WHEN 3 THEN '红包' ELSE '' END AS type")
|
||||
} else if f == "pay_type" {
|
||||
cols = append(cols, "CASE `order`.pay_type WHEN 1 THEN '支付宝' WHEN 5 THEN '微信' ELSE '' END AS pay_type")
|
||||
} else if f == "pay_status" {
|
||||
cols = append(cols, "CASE `order`.pay_status WHEN 1 THEN '待支付' WHEN 2 THEN '已支付' WHEN 3 THEN '已退款' ELSE '' END AS pay_status")
|
||||
} else {
|
||||
cols = append(cols, "`order`."+escape(f))
|
||||
continue
|
||||
}
|
||||
if f == "pay_type" {
|
||||
cols = append(cols, "CASE `order`.pay_type WHEN 1 THEN '支付宝' WHEN 5 THEN '微信' ELSE '' END AS pay_type")
|
||||
continue
|
||||
}
|
||||
if f == "pay_status" {
|
||||
cols = append(cols, "CASE `order`.pay_status WHEN 1 THEN '待支付' WHEN 2 THEN '已支付' WHEN 3 THEN '已退款' ELSE '' END AS pay_status")
|
||||
continue
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if t == "order_cash" && f == "receive_status" {
|
||||
cols = append(cols, "CASE `order_cash`.receive_status WHEN 0 THEN '待领取' WHEN 1 THEN '领取中' WHEN 2 THEN '领取成功' WHEN 3 THEN '领取失败' ELSE '' END AS receive_status")
|
||||
} else if t == "order_cash" && f == "channel" {
|
||||
continue
|
||||
}
|
||||
if t == "order_cash" && f == "channel" {
|
||||
cols = append(cols, "CASE `order_cash`.channel WHEN 1 THEN '支付宝' WHEN 2 THEN '微信' WHEN 3 THEN '云闪付' ELSE '' END AS channel")
|
||||
} else if t == "order_voucher" && f == "channel" {
|
||||
continue
|
||||
}
|
||||
if t == "order_voucher" && f == "channel" {
|
||||
cols = append(cols, "CASE `order_voucher`.channel WHEN 1 THEN '支付宝' WHEN 2 THEN '微信' ELSE '' END AS channel")
|
||||
} else if t == "order_voucher" && f == "status" {
|
||||
continue
|
||||
}
|
||||
if t == "order_voucher" && f == "status" {
|
||||
cols = append(cols, "CASE `order_voucher`.status WHEN 1 THEN '可用' WHEN 2 THEN '已实扣' WHEN 3 THEN '已过期' WHEN 4 THEN '已退款' WHEN 5 THEN '领取失败' WHEN 6 THEN '发放中' WHEN 7 THEN '部分退款' WHEN 8 THEN '已退回' WHEN 9 THEN '发放失败' ELSE '' END AS status")
|
||||
} else if t == "order_voucher" && f == "receive_mode" {
|
||||
continue
|
||||
}
|
||||
if t == "order_voucher" && f == "receive_mode" {
|
||||
cols = append(cols, "CASE `order_voucher`.receive_mode WHEN 1 THEN '渠道授权用户id' WHEN 2 THEN '手机号或邮箱' ELSE '' END AS receive_mode")
|
||||
} else if t == "order_voucher" && f == "out_biz_no" {
|
||||
continue
|
||||
}
|
||||
if t == "order_voucher" && f == "out_biz_no" {
|
||||
cols = append(cols, "'' AS out_biz_no")
|
||||
} else {
|
||||
cols = append(cols, "`"+t+"`."+escape(f))
|
||||
}
|
||||
continue
|
||||
}
|
||||
cols = append(cols, "`"+mt+"`."+escape(mf))
|
||||
}
|
||||
if len(cols) == 0 {
|
||||
return "", nil, errors.New("no fields")
|
||||
|
|
@ -88,67 +87,8 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
|
|||
sb.WriteString("SELECT ")
|
||||
sb.WriteString(strings.Join(cols, ","))
|
||||
sb.WriteString(" FROM `" + req.MainTable + "`")
|
||||
// JOINs based on need
|
||||
// order_detail
|
||||
if need["order_detail"] && req.MainTable == "order" {
|
||||
sb.WriteString(" LEFT JOIN `order_detail` ON `order_detail`.order_number = `order`.order_number")
|
||||
}
|
||||
// order_cash
|
||||
if need["order_cash"] {
|
||||
if req.MainTable == "order_info" {
|
||||
sb.WriteString(" LEFT JOIN `order_cash` ON `order_cash`.order_no = `order_info`.order_no")
|
||||
} else {
|
||||
sb.WriteString(" LEFT JOIN `order_cash` ON `order_cash`.order_number = `order`.order_number")
|
||||
}
|
||||
}
|
||||
// order_voucher
|
||||
if need["order_voucher"] {
|
||||
if req.MainTable == "order_info" {
|
||||
sb.WriteString(" LEFT JOIN `order_voucher` ON `order_voucher`.order_no = `order_info`.order_no")
|
||||
} else {
|
||||
sb.WriteString(" LEFT JOIN `order_voucher` ON `order_voucher`.order_number = `order`.order_number")
|
||||
}
|
||||
}
|
||||
// order_digit (ymt only)
|
||||
if need["order_digit"] && req.MainTable == "order_info" {
|
||||
sb.WriteString(" LEFT JOIN `order_digit` ON `order_digit`.order_no = `order_info`.order_no")
|
||||
}
|
||||
// goods_voucher_batch (ymt)
|
||||
if need["goods_voucher_batch"] && req.MainTable == "order_info" {
|
||||
sb.WriteString(" LEFT JOIN `goods_voucher_batch` ON `goods_voucher_batch`.channel_batch_no = `order_voucher`.channel_batch_no")
|
||||
}
|
||||
// goods_voucher_subject_config (ymt)
|
||||
if need["goods_voucher_subject_config"] && req.MainTable == "order_info" {
|
||||
sb.WriteString(" LEFT JOIN `goods_voucher_subject_config` ON `goods_voucher_subject_config`.id = `goods_voucher_batch`.voucher_subject_id")
|
||||
}
|
||||
// merchant (ymt)
|
||||
if need["merchant"] && req.MainTable == "order_info" {
|
||||
sb.WriteString(" LEFT JOIN `merchant` ON `merchant`.id = `order_info`.merchant_id")
|
||||
}
|
||||
// activity (ymt)
|
||||
if need["activity"] && req.MainTable == "order_info" {
|
||||
sb.WriteString(" LEFT JOIN `activity` ON `activity`.id = `order_info`.activity_id")
|
||||
}
|
||||
// plan
|
||||
if req.MainTable == "order" {
|
||||
if need["plan"] || need["key_batch"] {
|
||||
sb.WriteString(" LEFT JOIN `plan` ON `plan`.id = `order`.plan_id")
|
||||
}
|
||||
if need["key_batch"] {
|
||||
sb.WriteString(" LEFT JOIN `key_batch` ON `key_batch`.plan_id = `plan`.id")
|
||||
}
|
||||
if need["code_batch"] {
|
||||
sb.WriteString(" LEFT JOIN `code_batch` ON `code_batch`.key_batch_id = `key_batch`.id")
|
||||
}
|
||||
if need["voucher"] {
|
||||
sb.WriteString(" LEFT JOIN `voucher` ON `voucher`.channel_activity_id = `order_voucher`.channel_activity_id")
|
||||
}
|
||||
if need["voucher_batch"] {
|
||||
sb.WriteString(" LEFT JOIN `voucher_batch` ON `voucher_batch`.voucher_id = `voucher`.id")
|
||||
}
|
||||
if need["merchant_key_send"] {
|
||||
sb.WriteString(" LEFT JOIN `merchant_key_send` ON `order`." + escape("key") + " = `merchant_key_send`.key")
|
||||
}
|
||||
for _, j := range sch.BuildJoins(need, req.MainTable) {
|
||||
sb.WriteString(j)
|
||||
}
|
||||
|
||||
args := []interface{}{}
|
||||
|
|
@ -187,10 +127,8 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
|
|||
}
|
||||
ph := strings.Repeat("?,", len(ids))
|
||||
ph = strings.TrimSuffix(ph, ",")
|
||||
if req.MainTable == "order_info" {
|
||||
where = append(where, "`order_info`.user_id IN ("+ph+")")
|
||||
} else {
|
||||
where = append(where, "`order`.creator IN ("+ph+")")
|
||||
if tbl, col, ok := sch.FilterColumn("creator_in"); ok {
|
||||
where = append(where, fmt.Sprintf("`%s`.%s IN (%s)", sch.TableName(tbl), escape(col), ph))
|
||||
}
|
||||
args = append(args, ids...)
|
||||
}
|
||||
|
|
@ -201,10 +139,8 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
|
|||
if len(arr) != 2 {
|
||||
return "", nil, errors.New("create_time_between requires 2 values")
|
||||
}
|
||||
if req.MainTable == "order_info" {
|
||||
where = append(where, "`order_info`.create_time BETWEEN ? AND ?")
|
||||
} else {
|
||||
where = append(where, "`order`.create_time BETWEEN ? AND ?")
|
||||
if tbl, col, ok := sch.FilterColumn("create_time_between"); ok {
|
||||
where = append(where, fmt.Sprintf("`%s`.%s BETWEEN ? AND ?", sch.TableName(tbl), escape(col)))
|
||||
}
|
||||
args = append(args, arr[0], arr[1])
|
||||
}
|
||||
|
|
@ -226,10 +162,8 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
|
|||
}
|
||||
}
|
||||
if tv == 1 || tv == 2 || tv == 3 {
|
||||
if req.MainTable == "order_info" {
|
||||
where = append(where, "`order_info`.type = ?")
|
||||
} else {
|
||||
where = append(where, "`order`.type = ?")
|
||||
if tbl, col, ok := sch.FilterColumn("type_eq"); ok {
|
||||
where = append(where, fmt.Sprintf("`%s`.%s = ?", sch.TableName(tbl), escape(col)))
|
||||
}
|
||||
args = append(args, tv)
|
||||
}
|
||||
|
|
@ -237,10 +171,8 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
|
|||
if v, ok := req.Filters["out_trade_no_eq"]; ok {
|
||||
s := toString(v)
|
||||
if s != "" {
|
||||
if req.MainTable == "order_info" {
|
||||
where = append(where, "`order_info`.out_order_no = ?")
|
||||
} else {
|
||||
where = append(where, "`order`.out_trade_no = ?")
|
||||
if tbl, col, ok := sch.FilterColumn("out_trade_no_eq"); ok {
|
||||
where = append(where, fmt.Sprintf("`%s`.%s = ?", sch.TableName(tbl), escape(col)))
|
||||
}
|
||||
args = append(args, s)
|
||||
}
|
||||
|
|
@ -248,10 +180,8 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
|
|||
if v, ok := req.Filters["account_eq"]; ok {
|
||||
s := toString(v)
|
||||
if s != "" {
|
||||
if req.MainTable == "order_info" {
|
||||
where = append(where, "`order_info`.account = ?")
|
||||
} else {
|
||||
where = append(where, "`order`.account = ?")
|
||||
if tbl, col, ok := sch.FilterColumn("account_eq"); ok {
|
||||
where = append(where, fmt.Sprintf("`%s`.%s = ?", sch.TableName(tbl), escape(col)))
|
||||
}
|
||||
args = append(args, s)
|
||||
}
|
||||
|
|
@ -259,10 +189,8 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
|
|||
if v, ok := req.Filters["plan_id_eq"]; ok {
|
||||
s := toString(v)
|
||||
if s != "" {
|
||||
if req.MainTable == "order_info" {
|
||||
where = append(where, "`order_info`.activity_id = ?")
|
||||
} else {
|
||||
where = append(where, "`order`.plan_id = ?")
|
||||
if tbl, col, ok := sch.FilterColumn("plan_id_eq"); ok {
|
||||
where = append(where, fmt.Sprintf("`%s`.%s = ?", sch.TableName(tbl), escape(col)))
|
||||
}
|
||||
args = append(args, s)
|
||||
}
|
||||
|
|
@ -270,10 +198,8 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
|
|||
if v, ok := req.Filters["key_batch_id_eq"]; ok {
|
||||
s := toString(v)
|
||||
if s != "" {
|
||||
if req.MainTable == "order_info" {
|
||||
where = append(where, "`order_info`.key_batch_name = ?")
|
||||
} else {
|
||||
where = append(where, "`order`.key_batch_id = ?")
|
||||
if tbl, col, ok := sch.FilterColumn("key_batch_id_eq"); ok {
|
||||
where = append(where, fmt.Sprintf("`%s`.%s = ?", sch.TableName(tbl), escape(col)))
|
||||
}
|
||||
args = append(args, s)
|
||||
}
|
||||
|
|
@ -281,10 +207,8 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
|
|||
if v, ok := req.Filters["product_id_eq"]; ok {
|
||||
s := toString(v)
|
||||
if s != "" {
|
||||
if req.MainTable == "order_info" {
|
||||
where = append(where, "`order_info`.goods_id = ?")
|
||||
} else {
|
||||
where = append(where, "`order`.product_id = ?")
|
||||
if tbl, col, ok := sch.FilterColumn("product_id_eq"); ok {
|
||||
where = append(where, fmt.Sprintf("`%s`.%s = ?", sch.TableName(tbl), escape(col)))
|
||||
}
|
||||
args = append(args, s)
|
||||
}
|
||||
|
|
@ -292,10 +216,8 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
|
|||
if v, ok := req.Filters["reseller_id_eq"]; ok {
|
||||
s := toString(v)
|
||||
if s != "" {
|
||||
if req.MainTable == "order_info" {
|
||||
where = append(where, "`order_info`.merchant_id = ?")
|
||||
} else {
|
||||
where = append(where, "`order`.reseller_id = ?")
|
||||
if tbl, col, ok := sch.FilterColumn("reseller_id_eq"); ok {
|
||||
where = append(where, fmt.Sprintf("`%s`.%s = ?", sch.TableName(tbl), escape(col)))
|
||||
}
|
||||
args = append(args, s)
|
||||
}
|
||||
|
|
@ -303,10 +225,8 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
|
|||
if v, ok := req.Filters["code_batch_id_eq"]; ok {
|
||||
s := toString(v)
|
||||
if s != "" {
|
||||
if req.MainTable == "order_info" {
|
||||
where = append(where, "`order_info`.supplier_product_id = ?")
|
||||
} else {
|
||||
where = append(where, "`order`.code_batch_id = ?")
|
||||
if tbl, col, ok := sch.FilterColumn("code_batch_id_eq"); ok {
|
||||
where = append(where, fmt.Sprintf("`%s`.%s = ?", sch.TableName(tbl), escape(col)))
|
||||
}
|
||||
args = append(args, s)
|
||||
}
|
||||
|
|
@ -314,10 +234,8 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
|
|||
if v, ok := req.Filters["order_cash_cash_activity_id_eq"]; ok {
|
||||
s := toString(v)
|
||||
if s != "" {
|
||||
if req.MainTable == "order_info" {
|
||||
where = append(where, "`order_cash`.activity_id = ?")
|
||||
} else {
|
||||
where = append(where, "`order_cash`.cash_activity_id = ?")
|
||||
if tbl, col, ok := sch.FilterColumn("order_cash_cash_activity_id_eq"); ok {
|
||||
where = append(where, fmt.Sprintf("`%s`.%s = ?", sch.TableName(tbl), escape(col)))
|
||||
}
|
||||
args = append(args, s)
|
||||
}
|
||||
|
|
@ -325,10 +243,8 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
|
|||
if v, ok := req.Filters["order_voucher_channel_activity_id_eq"]; ok {
|
||||
s := toString(v)
|
||||
if s != "" {
|
||||
if req.MainTable == "order_info" {
|
||||
where = append(where, "`order_voucher`.channel_batch_no = ?")
|
||||
} else {
|
||||
where = append(where, "`order_voucher`.channel_activity_id = ?")
|
||||
if tbl, col, ok := sch.FilterColumn("order_voucher_channel_activity_id_eq"); ok {
|
||||
where = append(where, fmt.Sprintf("`%s`.%s = ?", sch.TableName(tbl), escape(col)))
|
||||
}
|
||||
args = append(args, s)
|
||||
}
|
||||
|
|
@ -336,8 +252,8 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
|
|||
if v, ok := req.Filters["voucher_batch_channel_activity_id_eq"]; ok {
|
||||
s := toString(v)
|
||||
if s != "" {
|
||||
if req.MainTable == "order" { // only marketing schema has voucher_batch
|
||||
where = append(where, "`voucher_batch`.channel_activity_id = ?")
|
||||
if tbl, col, ok := sch.FilterColumn("voucher_batch_channel_activity_id_eq"); ok {
|
||||
where = append(where, fmt.Sprintf("`%s`.%s = ?", sch.TableName(tbl), escape(col)))
|
||||
args = append(args, s)
|
||||
}
|
||||
}
|
||||
|
|
@ -345,8 +261,8 @@ func BuildSQL(req BuildRequest, whitelist map[string]bool) (string, []interface{
|
|||
if v, ok := req.Filters["merchant_out_biz_no_eq"]; ok {
|
||||
s := toString(v)
|
||||
if s != "" {
|
||||
if req.MainTable == "order" { // marketing only
|
||||
where = append(where, "`merchant_key_send`.out_biz_no = ?")
|
||||
if tbl, col, ok := sch.FilterColumn("merchant_out_biz_no_eq"); ok {
|
||||
where = append(where, fmt.Sprintf("`%s`.%s = ?", sch.TableName(tbl), escape(col)))
|
||||
}
|
||||
args = append(args, s)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,455 @@
|
|||
package schema
|
||||
|
||||
func AllWhitelist() map[string]bool {
|
||||
m := map[string]bool{
|
||||
"order.order_number": true,
|
||||
"order.key": true,
|
||||
"order.creator": true,
|
||||
"order.out_trade_no": true,
|
||||
"order.type": true,
|
||||
"order.status": true,
|
||||
"order.account": true,
|
||||
"order.product_id": true,
|
||||
"order.reseller_id": true,
|
||||
"order.plan_id": true,
|
||||
"order.key_batch_id": true,
|
||||
"order.code_batch_id": true,
|
||||
"order.pay_type": true,
|
||||
"order.pay_status": true,
|
||||
"order.use_coupon": true,
|
||||
"order.deliver_status": true,
|
||||
"order.expire_time": true,
|
||||
"order.recharge_time": true,
|
||||
"order.contract_price": true,
|
||||
"order.num": true,
|
||||
"order.total": true,
|
||||
"order.pay_amount": true,
|
||||
"order.create_time": true,
|
||||
"order.update_time": true,
|
||||
"order.official_price": true,
|
||||
"order.merchant_name": true,
|
||||
"order.activity_name": true,
|
||||
"order.goods_name": true,
|
||||
"order.pay_time": true,
|
||||
"order.coupon_id": true,
|
||||
"order.discount_amount": true,
|
||||
"order.supplier_product_name": true,
|
||||
"order.is_inner": true,
|
||||
"order.icon": true,
|
||||
"order.cost_price": true,
|
||||
"order.success_num": true,
|
||||
"order.is_reset": true,
|
||||
"order.is_retry": true,
|
||||
"order.channel": true,
|
||||
"order.is_store": true,
|
||||
"order.trace_id": true,
|
||||
"order.out_order_no": true,
|
||||
"order.next_retry_time": true,
|
||||
"order.recharge_suc_time": true,
|
||||
"order.supplier_id": true,
|
||||
"order.supplier_product_id": true,
|
||||
"order.merchant_id": true,
|
||||
"order.goods_id": true,
|
||||
"order.activity_id": true,
|
||||
"order.key_batch_name": true,
|
||||
"order_detail.plan_title": true,
|
||||
"order_detail.reseller_name": true,
|
||||
"order_detail.product_name": true,
|
||||
"order_detail.show_url": true,
|
||||
"order_detail.official_price": true,
|
||||
"order_detail.cost_price": true,
|
||||
"order_detail.create_time": true,
|
||||
"order_detail.update_time": true,
|
||||
"order_cash.order_no": true,
|
||||
"order_cash.trade_no": true,
|
||||
"order_cash.wechat_detail_id": true,
|
||||
"order_cash.channel": true,
|
||||
"order_cash.denomination": true,
|
||||
"order_cash.account": true,
|
||||
"order_cash.receive_name": true,
|
||||
"order_cash.app_id": true,
|
||||
"order_cash.cash_activity_id": true,
|
||||
"order_cash.receive_status": true,
|
||||
"order_cash.receive_time": true,
|
||||
"order_cash.success_time": true,
|
||||
"order_cash.cash_packet_id": true,
|
||||
"order_cash.cash_id": true,
|
||||
"order_cash.amount": true,
|
||||
"order_cash.activity_id": true,
|
||||
"order_cash.goods_id": true,
|
||||
"order_cash.merchant_id": true,
|
||||
"order_cash.supplier_id": true,
|
||||
"order_cash.user_id": true,
|
||||
"order_cash.status": true,
|
||||
"order_cash.expire_time": true,
|
||||
"order_cash.create_time": true,
|
||||
"order_cash.update_time": true,
|
||||
"order_cash.version": true,
|
||||
"order_cash.is_confirm": true,
|
||||
"order_voucher.channel": true,
|
||||
"order_voucher.channel_activity_id": true,
|
||||
"order_voucher.channel_voucher_id": true,
|
||||
"order_voucher.status": true,
|
||||
"order_voucher.receive_mode": true,
|
||||
"order_voucher.grant_time": true,
|
||||
"order_voucher.usage_time": true,
|
||||
"order_voucher.refund_time": true,
|
||||
"order_voucher.status_modify_time": true,
|
||||
"order_voucher.overdue_time": true,
|
||||
"order_voucher.refund_amount": true,
|
||||
"order_voucher.official_price": true,
|
||||
"order_voucher.out_biz_no": true,
|
||||
"order_voucher.account_no": true,
|
||||
"plan.id": true,
|
||||
"plan.title": true,
|
||||
"plan.status": true,
|
||||
"plan.begin_time": true,
|
||||
"plan.end_time": true,
|
||||
"key_batch.id": true,
|
||||
"key_batch.batch_name": true,
|
||||
"key_batch.bind_object": true,
|
||||
"key_batch.quantity": true,
|
||||
"key_batch.stock": true,
|
||||
"key_batch.begin_time": true,
|
||||
"key_batch.end_time": true,
|
||||
"code_batch.id": true,
|
||||
"code_batch.title": true,
|
||||
"code_batch.status": true,
|
||||
"code_batch.begin_time": true,
|
||||
"code_batch.end_time": true,
|
||||
"code_batch.quantity": true,
|
||||
"code_batch.usage": true,
|
||||
"code_batch.stock": true,
|
||||
"voucher.channel": true,
|
||||
"voucher.channel_activity_id": true,
|
||||
"voucher.price": true,
|
||||
"voucher.balance": true,
|
||||
"voucher.used_amount": true,
|
||||
"voucher.denomination": true,
|
||||
"voucher_batch.channel_activity_id": true,
|
||||
"voucher_batch.temp_no": true,
|
||||
"voucher_batch.provider": true,
|
||||
"voucher_batch.weight": true,
|
||||
"merchant_key_send.merchant_id": true,
|
||||
"merchant_key_send.out_biz_no": true,
|
||||
"merchant_key_send.key": true,
|
||||
"merchant_key_send.status": true,
|
||||
"merchant_key_send.usage_time": true,
|
||||
"merchant_key_send.create_time": true,
|
||||
"order_digit.order_no": true,
|
||||
"order_digit.card_no": true,
|
||||
"order_digit.account": true,
|
||||
"order_digit.goods_id": true,
|
||||
"order_digit.merchant_id": true,
|
||||
"order_digit.supplier_id": true,
|
||||
"order_digit.activity_id": true,
|
||||
"order_digit.user_id": true,
|
||||
"order_digit.success_time": true,
|
||||
"order_digit.supplier_product_no": true,
|
||||
"order_digit.order_type": true,
|
||||
"order_digit.end_time": true,
|
||||
"order_digit.create_time": true,
|
||||
"order_digit.update_time": true,
|
||||
"order_digit.code": true,
|
||||
"order_digit.sms_channel": true,
|
||||
"goods_voucher_batch.channel_batch_no": true,
|
||||
"goods_voucher_batch.voucher_subject_id": true,
|
||||
"goods_voucher_batch.id": true,
|
||||
"goods_voucher_batch.goods_voucher_id": true,
|
||||
"goods_voucher_batch.supplier_id": true,
|
||||
"goods_voucher_batch.temp_no": true,
|
||||
"goods_voucher_batch.index": true,
|
||||
"goods_voucher_batch.create_time": true,
|
||||
"goods_voucher_batch.update_time": true,
|
||||
"goods_voucher_subject_config.id": true,
|
||||
"goods_voucher_subject_config.name": true,
|
||||
"goods_voucher_subject_config.type": true,
|
||||
"goods_voucher_subject_config.create_time": true,
|
||||
"merchant.id": true,
|
||||
"merchant.name": true,
|
||||
"merchant.user_id": true,
|
||||
"merchant.merchant_no": true,
|
||||
"merchant.subject": true,
|
||||
"merchant.third_party": true,
|
||||
"merchant.status": true,
|
||||
"merchant.balance": true,
|
||||
"merchant.total_consumption": true,
|
||||
"merchant.contact_name": true,
|
||||
"merchant.contact_phone": true,
|
||||
"merchant.contact_email": true,
|
||||
"merchant.create_time": true,
|
||||
"merchant.update_time": true,
|
||||
"activity.id": true,
|
||||
"activity.name": true,
|
||||
"activity.user_id": true,
|
||||
"activity.merchant_id": true,
|
||||
"activity.user_name": true,
|
||||
"activity.activity_no": true,
|
||||
"activity.status": true,
|
||||
"activity.key_total_num": true,
|
||||
"activity.key_generate_num": true,
|
||||
"activity.key_usable_num": true,
|
||||
"activity.domain_url": true,
|
||||
"activity.theme_login_id": true,
|
||||
"activity.theme_list_id": true,
|
||||
"activity.theme_verify_id": true,
|
||||
"activity.settlement_type": true,
|
||||
"activity.key_expire_type": true,
|
||||
"activity.key_valid_day": true,
|
||||
"activity.key_begin_time": true,
|
||||
"activity.key_end_time": true,
|
||||
"activity.key_style": true,
|
||||
"activity.begin_time": true,
|
||||
"activity.end_time": true,
|
||||
"activity.is_retry": true,
|
||||
"activity.create_time": true,
|
||||
"activity.update_time": true,
|
||||
"activity.discard_time": true,
|
||||
"activity.delete_time": true,
|
||||
"activity.auto_charge": true,
|
||||
"activity.stock": true,
|
||||
"activity.approval_trade_no": true,
|
||||
"activity.amount": true,
|
||||
"activity.channels": true,
|
||||
"activity.key_begin": true,
|
||||
"activity.key_end": true,
|
||||
"activity.key_unit": true,
|
||||
"activity.key_pay_button_text": true,
|
||||
"activity.goods_pay_button_text": true,
|
||||
"activity.is_open_db_transaction": true,
|
||||
"activity.bank_tag": true,
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func AllLabels() map[string]string {
|
||||
return map[string]string{
|
||||
"order.order_number": "订单编号",
|
||||
"order.key": "KEY",
|
||||
"order.creator": "创建者ID",
|
||||
"order.out_trade_no": "支付流水号",
|
||||
"order.type": "订单类型",
|
||||
"order.status": "订单状态",
|
||||
"order.account": "账号",
|
||||
"order.product_id": "商品ID",
|
||||
"order.reseller_id": "分销商ID",
|
||||
"order.plan_id": "计划ID",
|
||||
"order.key_batch_id": "KEY批次ID",
|
||||
"order.code_batch_id": "兑换批次ID",
|
||||
"order.pay_type": "支付方式",
|
||||
"order.pay_status": "支付状态",
|
||||
"order.use_coupon": "是否使用优惠券",
|
||||
"order.deliver_status": "投递状态",
|
||||
"order.expire_time": "过期处理时间",
|
||||
"order.recharge_time": "充值时间",
|
||||
"order.contract_price": "合同单价",
|
||||
"order.num": "数量",
|
||||
"order.total": "总金额",
|
||||
"order.pay_amount": "支付金额",
|
||||
"order.create_time": "创建时间",
|
||||
"order.update_time": "更新时间",
|
||||
"order.official_price": "官方价",
|
||||
"order.merchant_name": "分销商名称",
|
||||
"order.activity_name": "活动名称",
|
||||
"order.goods_name": "商品名称",
|
||||
"order.pay_time": "支付时间",
|
||||
"order.coupon_id": "优惠券ID",
|
||||
"order.discount_amount": "优惠金额",
|
||||
"order.supplier_product_name": "供应商产品名称",
|
||||
"order.is_inner": "内部供应商订单",
|
||||
"order.icon": "订单图片",
|
||||
"order.cost_price": "成本价",
|
||||
"order.success_num": "到账数量",
|
||||
"order.is_reset": "是否重置",
|
||||
"order.is_retry": "是否重试",
|
||||
"order.channel": "支付渠道",
|
||||
"order.is_store": "是否退还库存",
|
||||
"order.trace_id": "TraceID",
|
||||
"order.out_order_no": "外部订单号",
|
||||
"order.next_retry_time": "下次重试时间",
|
||||
"order.recharge_suc_time": "充值成功时间",
|
||||
"order.supplier_id": "供应商ID",
|
||||
"order.supplier_product_id": "供应商产品ID",
|
||||
"order.merchant_id": "分销商ID",
|
||||
"order.goods_id": "商品ID",
|
||||
"order.activity_id": "活动ID",
|
||||
"order.key_batch_name": "key批次名称",
|
||||
"order_detail.plan_title": "计划标题",
|
||||
"order_detail.reseller_name": "分销商名称",
|
||||
"order_detail.product_name": "商品名称",
|
||||
"order_detail.show_url": "商品图片URL",
|
||||
"order_detail.official_price": "官方价",
|
||||
"order_detail.cost_price": "成本价",
|
||||
"order_detail.create_time": "创建时间",
|
||||
"order_detail.update_time": "更新时间",
|
||||
"order_cash.order_no": "订单号",
|
||||
"order_cash.trade_no": "交易号",
|
||||
"order_cash.wechat_detail_id": "微信明细单号",
|
||||
"order_cash.channel": "渠道",
|
||||
"order_cash.denomination": "红包面额",
|
||||
"order_cash.account": "领取账号",
|
||||
"order_cash.receive_name": "真实姓名",
|
||||
"order_cash.app_id": "转账AppID",
|
||||
"order_cash.cash_activity_id": "红包批次号",
|
||||
"order_cash.receive_status": "领取状态",
|
||||
"order_cash.receive_time": "拆红包时间",
|
||||
"order_cash.success_time": "成功时间",
|
||||
"order_cash.cash_packet_id": "红包ID",
|
||||
"order_cash.cash_id": "红包规则ID",
|
||||
"order_cash.amount": "红包额度",
|
||||
"order_cash.activity_id": "活动ID",
|
||||
"order_cash.goods_id": "商品ID",
|
||||
"order_cash.merchant_id": "分销商ID",
|
||||
"order_cash.supplier_id": "供应商ID",
|
||||
"order_cash.user_id": "创建者ID",
|
||||
"order_cash.status": "状态",
|
||||
"order_cash.expire_time": "过期时间",
|
||||
"order_cash.create_time": "创建时间",
|
||||
"order_cash.update_time": "更新时间",
|
||||
"order_cash.version": "版本",
|
||||
"order_cash.is_confirm": "是否确认",
|
||||
"order_voucher.channel": "渠道",
|
||||
"order_voucher.channel_activity_id": "渠道立减金批次",
|
||||
"order_voucher.channel_voucher_id": "渠道立减金ID",
|
||||
"order_voucher.status": "状态",
|
||||
"order_voucher.receive_mode": "领取方式",
|
||||
"order_voucher.grant_time": "领取时间",
|
||||
"order_voucher.usage_time": "核销时间",
|
||||
"order_voucher.refund_time": "退款时间",
|
||||
"order_voucher.status_modify_time": "状态更新时间",
|
||||
"order_voucher.overdue_time": "过期时间",
|
||||
"order_voucher.refund_amount": "退款金额",
|
||||
"order_voucher.official_price": "官方价",
|
||||
"order_voucher.out_biz_no": "外部业务号",
|
||||
"order_voucher.account_no": "账户号",
|
||||
"plan.id": "计划ID",
|
||||
"plan.title": "计划标题",
|
||||
"plan.status": "状态",
|
||||
"plan.begin_time": "开始时间",
|
||||
"plan.end_time": "结束时间",
|
||||
"key_batch.id": "批次ID",
|
||||
"key_batch.batch_name": "批次名称",
|
||||
"key_batch.bind_object": "绑定对象",
|
||||
"key_batch.quantity": "发放数量",
|
||||
"key_batch.stock": "剩余库存",
|
||||
"key_batch.begin_time": "开始时间",
|
||||
"key_batch.end_time": "结束时间",
|
||||
"code_batch.id": "兑换批次ID",
|
||||
"code_batch.title": "标题",
|
||||
"code_batch.status": "状态",
|
||||
"code_batch.begin_time": "开始时间",
|
||||
"code_batch.end_time": "结束时间",
|
||||
"code_batch.quantity": "数量",
|
||||
"code_batch.usage": "使用数",
|
||||
"code_batch.stock": "库存",
|
||||
"voucher.channel": "渠道",
|
||||
"voucher.channel_activity_id": "渠道批次号",
|
||||
"voucher.price": "合同单价",
|
||||
"voucher.balance": "剩余额度",
|
||||
"voucher.used_amount": "已用额度",
|
||||
"voucher.denomination": "面额",
|
||||
"voucher_batch.channel_activity_id": "渠道批次号",
|
||||
"voucher_batch.temp_no": "模板编号",
|
||||
"voucher_batch.provider": "服务商",
|
||||
"voucher_batch.weight": "权重",
|
||||
"merchant_key_send.merchant_id": "商户ID",
|
||||
"merchant_key_send.out_biz_no": "商户业务号",
|
||||
"merchant_key_send.key": "券码",
|
||||
"merchant_key_send.status": "状态",
|
||||
"merchant_key_send.usage_time": "核销时间",
|
||||
"merchant_key_send.create_time": "创建时间",
|
||||
"order_digit.order_no": "订单号",
|
||||
"order_digit.card_no": "卡号",
|
||||
"order_digit.account": "充值账号",
|
||||
"order_digit.goods_id": "商品ID",
|
||||
"order_digit.merchant_id": "分销商ID",
|
||||
"order_digit.supplier_id": "供应商ID",
|
||||
"order_digit.activity_id": "活动ID",
|
||||
"order_digit.user_id": "创建者ID",
|
||||
"order_digit.success_time": "到账时间",
|
||||
"order_digit.supplier_product_no": "供应商产品编码",
|
||||
"order_digit.order_type": "订单类型",
|
||||
"order_digit.end_time": "卡密有效期",
|
||||
"order_digit.create_time": "创建时间",
|
||||
"order_digit.update_time": "更新时间",
|
||||
"order_digit.code": "验证码",
|
||||
"order_digit.sms_channel": "短信渠道",
|
||||
"goods_voucher_batch.channel_batch_no": "渠道批次号",
|
||||
"goods_voucher_batch.voucher_subject_id": "主体配置ID",
|
||||
"goods_voucher_batch.id": "ID",
|
||||
"goods_voucher_batch.goods_voucher_id": "立减金ID",
|
||||
"goods_voucher_batch.supplier_id": "供应商ID",
|
||||
"goods_voucher_batch.temp_no": "模板编号",
|
||||
"goods_voucher_batch.index": "权重",
|
||||
"goods_voucher_batch.create_time": "创建时间",
|
||||
"goods_voucher_batch.update_time": "更新时间",
|
||||
"goods_voucher_subject_config.id": "主体配置ID",
|
||||
"goods_voucher_subject_config.name": "主体名称",
|
||||
"goods_voucher_subject_config.type": "主体类型",
|
||||
"goods_voucher_subject_config.create_time": "创建时间",
|
||||
"merchant.id": "客户ID",
|
||||
"merchant.name": "客户名称",
|
||||
"merchant.user_id": "用户中心ID",
|
||||
"merchant.merchant_no": "商户编码",
|
||||
"merchant.subject": "客户主体",
|
||||
"merchant.third_party": "来源类型",
|
||||
"merchant.status": "状态",
|
||||
"merchant.balance": "客户余额",
|
||||
"merchant.total_consumption": "累计消费",
|
||||
"merchant.contact_name": "联系人名称",
|
||||
"merchant.contact_phone": "联系人电话",
|
||||
"merchant.contact_email": "联系人Email",
|
||||
"merchant.create_time": "创建时间",
|
||||
"merchant.update_time": "编辑时间",
|
||||
"activity.id": "活动ID",
|
||||
"activity.name": "活动名称",
|
||||
"activity.user_id": "创建者ID",
|
||||
"activity.merchant_id": "客户ID",
|
||||
"activity.user_name": "创建者名称",
|
||||
"activity.activity_no": "活动编号",
|
||||
"activity.status": "状态",
|
||||
"activity.key_total_num": "Key码总量",
|
||||
"activity.key_generate_num": "Key码已生成数量",
|
||||
"activity.key_usable_num": "Key可使用次数",
|
||||
"activity.domain_url": "域名",
|
||||
"activity.theme_login_id": "登录模版ID",
|
||||
"activity.theme_list_id": "列表模版ID",
|
||||
"activity.theme_verify_id": "验证模版ID",
|
||||
"activity.settlement_type": "结算方式",
|
||||
"activity.key_expire_type": "Key有效期类型",
|
||||
"activity.key_valid_day": "有效天数",
|
||||
"activity.key_begin_time": "Key有效开始时间",
|
||||
"activity.key_end_time": "Key有效结束时间",
|
||||
"activity.key_style": "Key样式",
|
||||
"activity.begin_time": "开始时间",
|
||||
"activity.end_time": "结束时间",
|
||||
"activity.is_retry": "是否自动重试",
|
||||
"activity.create_time": "创建时间",
|
||||
"activity.update_time": "修改时间",
|
||||
"activity.discard_time": "作废时间",
|
||||
"activity.delete_time": "删除时间",
|
||||
"activity.auto_charge": "是否充值到账",
|
||||
"activity.stock": "已使用库存",
|
||||
"activity.approval_trade_no": "审批交易号",
|
||||
"activity.amount": "支付金额",
|
||||
"activity.channels": "支付渠道",
|
||||
"activity.key_begin": "开始月份",
|
||||
"activity.key_end": "截止月份",
|
||||
"activity.key_unit": "时间单位",
|
||||
"activity.key_pay_button_text": "Key支付按钮文本",
|
||||
"activity.goods_pay_button_text": "商品支付按钮文本",
|
||||
"activity.is_open_db_transaction": "是否开启事务",
|
||||
"activity.bank_tag": "银行标识",
|
||||
}
|
||||
}
|
||||
|
||||
func RecommendedDefaultFields(ds string) []string {
|
||||
if ds == "ymt" {
|
||||
return []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",
|
||||
}
|
||||
}
|
||||
return []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",
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package schema
|
||||
|
||||
type marketingSchema struct{}
|
||||
|
||||
func (marketingSchema) TableName(t string) string { return t }
|
||||
|
||||
func (marketingSchema) MapField(t, f string) (string, bool) { return f, true }
|
||||
|
||||
func (marketingSchema) BuildJoins(need map[string]bool, main string) []string {
|
||||
out := []string{}
|
||||
if need["order_detail"] {
|
||||
out = append(out, " LEFT JOIN `order_detail` ON `order_detail`.order_number = `order`.order_number")
|
||||
}
|
||||
if need["order_cash"] {
|
||||
out = append(out, " LEFT JOIN `order_cash` ON `order_cash`.order_number = `order`.order_number")
|
||||
}
|
||||
if need["order_voucher"] {
|
||||
out = append(out, " LEFT JOIN `order_voucher` ON `order_voucher`.order_number = `order`.order_number")
|
||||
}
|
||||
if need["plan"] || need["key_batch"] {
|
||||
out = append(out, " LEFT JOIN `plan` ON `plan`.id = `order`.plan_id")
|
||||
}
|
||||
if need["key_batch"] {
|
||||
out = append(out, " LEFT JOIN `key_batch` ON `key_batch`.plan_id = `plan`.id")
|
||||
}
|
||||
if need["code_batch"] {
|
||||
out = append(out, " LEFT JOIN `code_batch` ON `code_batch`.key_batch_id = `key_batch`.id")
|
||||
}
|
||||
if need["voucher"] {
|
||||
out = append(out, " LEFT JOIN `voucher` ON `voucher`.channel_activity_id = `order_voucher`.channel_activity_id")
|
||||
}
|
||||
if need["voucher_batch"] {
|
||||
out = append(out, " LEFT JOIN `voucher_batch` ON `voucher_batch`.voucher_id = `voucher`.id")
|
||||
}
|
||||
if need["merchant_key_send"] {
|
||||
out = append(out, " LEFT JOIN `merchant_key_send` ON `order`.`key` = `merchant_key_send`.key")
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (marketingSchema) FilterColumn(key string) (string, string, bool) {
|
||||
switch key {
|
||||
case "creator_in": return "order", "creator", true
|
||||
case "create_time_between": return "order", "create_time", true
|
||||
case "type_eq": return "order", "type", true
|
||||
case "out_trade_no_eq": return "order", "out_trade_no", true
|
||||
case "account_eq": return "order", "account", true
|
||||
case "plan_id_eq": return "order", "plan_id", true
|
||||
case "key_batch_id_eq": return "order", "key_batch_id", true
|
||||
case "product_id_eq": return "order", "product_id", true
|
||||
case "reseller_id_eq": return "order", "reseller_id", true
|
||||
case "code_batch_id_eq": return "order", "code_batch_id", true
|
||||
case "order_cash_cash_activity_id_eq": return "order_cash", "cash_activity_id", true
|
||||
case "order_voucher_channel_activity_id_eq": return "order_voucher", "channel_activity_id", true
|
||||
case "voucher_batch_channel_activity_id_eq": return "voucher_batch", "channel_activity_id", true
|
||||
case "merchant_out_biz_no_eq": return "merchant_key_send", "out_biz_no", true
|
||||
default:
|
||||
return "", "", false
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package schema
|
||||
|
||||
type Schema interface {
|
||||
TableName(string) string
|
||||
MapField(string, string) (string, bool)
|
||||
BuildJoins(map[string]bool, string) []string
|
||||
FilterColumn(string) (string, string, bool)
|
||||
}
|
||||
|
||||
func Get(datasource string, main string) Schema {
|
||||
if datasource == "ymt" || main == "order_info" {
|
||||
return ymtSchema{}
|
||||
}
|
||||
return marketingSchema{}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
package schema
|
||||
|
||||
type ymtSchema struct{}
|
||||
|
||||
func (ymtSchema) TableName(t string) string {
|
||||
if t == "order" {
|
||||
return "order_info"
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (s ymtSchema) MapField(t, f string) (string, bool) {
|
||||
if t == "order" {
|
||||
switch f {
|
||||
case "order_number": return "order_no", true
|
||||
case "key": return "key_code", true
|
||||
case "creator": return "user_id", true
|
||||
case "out_trade_no": return "out_order_no", true
|
||||
case "plan_id": return "activity_id", true
|
||||
case "reseller_id": return "merchant_id", true
|
||||
case "product_id": return "goods_id", true
|
||||
case "pay_amount": return "pay_price", true
|
||||
case "key_batch_id": return "key_batch_name", true
|
||||
default:
|
||||
return f, true
|
||||
}
|
||||
}
|
||||
return f, true
|
||||
}
|
||||
|
||||
func (s ymtSchema) BuildJoins(need map[string]bool, main string) []string {
|
||||
out := []string{}
|
||||
if need["order_cash"] {
|
||||
out = append(out, " LEFT JOIN `order_cash` ON `order_cash`.order_no = `order_info`.order_no")
|
||||
}
|
||||
if need["order_voucher"] {
|
||||
out = append(out, " LEFT JOIN `order_voucher` ON `order_voucher`.order_no = `order_info`.order_no")
|
||||
}
|
||||
if need["order_digit"] {
|
||||
out = append(out, " LEFT JOIN `order_digit` ON `order_digit`.order_no = `order_info`.order_no")
|
||||
}
|
||||
if need["goods_voucher_batch"] {
|
||||
out = append(out, " LEFT JOIN `goods_voucher_batch` ON `goods_voucher_batch`.channel_batch_no = `order_voucher`.channel_batch_no")
|
||||
}
|
||||
if need["goods_voucher_subject_config"] {
|
||||
out = append(out, " LEFT JOIN `goods_voucher_subject_config` ON `goods_voucher_subject_config`.id = `goods_voucher_batch`.voucher_subject_id")
|
||||
}
|
||||
if need["merchant"] {
|
||||
out = append(out, " LEFT JOIN `merchant` ON `merchant`.id = `order_info`.merchant_id")
|
||||
}
|
||||
if need["activity"] {
|
||||
out = append(out, " LEFT JOIN `activity` ON `activity`.id = `order_info`.activity_id")
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (s ymtSchema) FilterColumn(key string) (string, string, bool) {
|
||||
switch key {
|
||||
case "creator_in": return "order", "user_id", true
|
||||
case "create_time_between": return "order", "create_time", true
|
||||
case "type_eq": return "order", "type", true
|
||||
case "out_trade_no_eq": return "order", "out_order_no", true
|
||||
case "account_eq": return "order", "account", true
|
||||
case "plan_id_eq": return "order", "activity_id", true
|
||||
case "key_batch_id_eq": return "order", "key_batch_name", true
|
||||
case "product_id_eq": return "order", "goods_id", true
|
||||
case "reseller_id_eq": return "order", "merchant_id", true
|
||||
case "code_batch_id_eq": return "order", "supplier_product_id", true
|
||||
case "order_cash_cash_activity_id_eq": return "order_cash", "activity_id", true
|
||||
case "order_voucher_channel_activity_id_eq": return "order_voucher", "channel_batch_no", true
|
||||
default:
|
||||
return "", "", false
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -123,7 +123,7 @@
|
|||
ref="fieldsCascader"
|
||||
v-model="form.fieldsSel"
|
||||
:key="form.datasource + '-' + String(form.orderType)"
|
||||
:options="fieldOptions"
|
||||
:options="fieldOptionsDynamic"
|
||||
:props="{ multiple: true, checkStrictly: false, expandTrigger: 'hover', checkOnClickNode: true, checkOnClickLeaf: true }"
|
||||
:teleported="false"
|
||||
collapse-tags
|
||||
|
|
@ -187,7 +187,7 @@
|
|||
ref="editFieldsCascader"
|
||||
v-model="edit.fieldsSel"
|
||||
:key="edit.datasource + '-' + String(edit.orderType)"
|
||||
:options="editFieldOptions"
|
||||
:options="editFieldOptionsDynamic"
|
||||
:props="{ multiple: true, checkStrictly: false, expandTrigger: 'hover', checkOnClickNode: true, checkOnClickLeaf: true }"
|
||||
:teleported="false"
|
||||
collapse-tags
|
||||
|
|
|
|||
209
web/main.js
209
web/main.js
|
|
@ -342,6 +342,165 @@ const { createApp, reactive } = Vue;
|
|||
{ value: 'is_open_db_transaction', label: '是否开启事务' },
|
||||
{ value: 'bank_tag', label: '银行标识' }
|
||||
]
|
||||
FIELDS_MAP.marketing = {}
|
||||
FIELDS_MAP.ymt = {}
|
||||
const metaFM = Vue.ref({})
|
||||
const loadFieldsMeta = async (ds, type)=>{
|
||||
try{
|
||||
const res = await fetch(API_BASE + '/api/metadata/fields?datasource=' + encodeURIComponent(ds) + '&order_type=' + encodeURIComponent(String(type||0)))
|
||||
const data = await res.json()
|
||||
const tables = Array.isArray(data?.data?.tables) ? data.data.tables : (Array.isArray(data?.tables)? data.tables: [])
|
||||
const m = {}
|
||||
tables.forEach(t=>{
|
||||
const arr = Array.isArray(t.fields) ? t.fields : []
|
||||
m[t.table] = arr.map(it=>({ value: it.field, label: it.label }))
|
||||
})
|
||||
metaFM.value = m
|
||||
}catch(_e){ metaFM.value = {} }
|
||||
}
|
||||
const FM_OF = (ds)=>{ return Object.keys(metaFM.value||{}).length ? (metaFM.value||{}) : (FIELDS_MAP[ds]||{}) }
|
||||
const fieldOptionsDynamic = Vue.computed(()=>{
|
||||
const ds = state.form.datasource
|
||||
const FM = FM_OF(ds)
|
||||
const node = (table, children=[])=>({ value: table, label: TABLE_LABELS[table]||table, children })
|
||||
const fieldsNode = (table)=> (FM[table]||[])
|
||||
const type = Number(state.form.orderType || 0)
|
||||
if(ds === 'ymt'){
|
||||
const orderChildrenBase = []
|
||||
orderChildrenBase.push(...fieldsNode('order'))
|
||||
const orderChildrenFor = (t)=>{
|
||||
const ch = [...orderChildrenBase]
|
||||
ch.push(node('merchant', fieldsNode('merchant')))
|
||||
ch.push(node('activity', fieldsNode('activity')))
|
||||
if(t===2){
|
||||
ch.push(node('order_voucher', fieldsNode('order_voucher')))
|
||||
ch.push(node('goods_voucher_batch', fieldsNode('goods_voucher_batch')))
|
||||
ch.push(node('goods_voucher_subject_config', fieldsNode('goods_voucher_subject_config')))
|
||||
} else if(t===3){
|
||||
ch.push(node('order_cash', fieldsNode('order_cash')))
|
||||
} else if(t===1){
|
||||
ch.push(node('order_digit', fieldsNode('order_digit')))
|
||||
} else if(!t){
|
||||
ch.push(node('order_voucher', fieldsNode('order_voucher')))
|
||||
ch.push(node('order_cash', fieldsNode('order_cash')))
|
||||
ch.push(node('order_digit', fieldsNode('order_digit')))
|
||||
ch.push(node('goods_voucher_batch', fieldsNode('goods_voucher_batch')))
|
||||
ch.push(node('goods_voucher_subject_config', fieldsNode('goods_voucher_subject_config')))
|
||||
}
|
||||
return ch
|
||||
}
|
||||
const orderNode = node('order', orderChildrenFor(type))
|
||||
if(type){ return [ orderNode ] }
|
||||
return [ { value: 'scene_order', label: '订单数据', children: [ orderNode ] } ]
|
||||
}
|
||||
const orderChildrenBase = []
|
||||
orderChildrenBase.push(...fieldsNode('order'))
|
||||
orderChildrenBase.push(node('order_detail', fieldsNode('order_detail')))
|
||||
const planChildren = []
|
||||
planChildren.push(...fieldsNode('plan'))
|
||||
planChildren.push(node('key_batch', [
|
||||
...fieldsNode('key_batch'),
|
||||
node('code_batch', fieldsNode('code_batch'))
|
||||
]))
|
||||
const voucherChildren = []
|
||||
voucherChildren.push(...fieldsNode('order_voucher'))
|
||||
voucherChildren.push(node('voucher', [
|
||||
...fieldsNode('voucher'),
|
||||
node('voucher_batch', fieldsNode('voucher_batch'))
|
||||
]))
|
||||
const orderChildrenFor = (t)=>{
|
||||
const ch = [...orderChildrenBase]
|
||||
if(t===1){
|
||||
ch.push(node('plan', planChildren))
|
||||
ch.push(node('merchant_key_send', fieldsNode('merchant_key_send')))
|
||||
} else if(t===2){
|
||||
ch.push(node('order_voucher', voucherChildren))
|
||||
ch.push(node('plan', planChildren))
|
||||
} else if(t===3){
|
||||
ch.push(node('order_cash', fieldsNode('order_cash')))
|
||||
ch.push(node('plan', planChildren))
|
||||
} else {
|
||||
ch.push(node('order_cash', fieldsNode('order_cash')))
|
||||
ch.push(node('order_voucher', voucherChildren))
|
||||
ch.push(node('plan', planChildren))
|
||||
ch.push(node('merchant_key_send', fieldsNode('merchant_key_send')))
|
||||
}
|
||||
return ch
|
||||
}
|
||||
const orderNode = node('order', orderChildrenFor(type))
|
||||
if(type){ return [ orderNode ] }
|
||||
return [ { value: 'scene_order', label: '订单数据', children: [ orderNode ] } ]
|
||||
})
|
||||
const editFieldOptionsDynamic = Vue.computed(()=>{
|
||||
const ds = state.edit.datasource
|
||||
const FM = FM_OF(ds)
|
||||
const node = (table, children=[])=>({ value: table, label: TABLE_LABELS[table]||table, children })
|
||||
const fieldsNode = (table)=> (FM[table]||[])
|
||||
const type = Number(state.edit.orderType || 0)
|
||||
if(ds === 'ymt'){
|
||||
const orderChildrenBase = []
|
||||
orderChildrenBase.push(...fieldsNode('order'))
|
||||
const orderChildrenFor = (t)=>{
|
||||
const ch = [...orderChildrenBase]
|
||||
ch.push(node('merchant', fieldsNode('merchant')))
|
||||
ch.push(node('activity', fieldsNode('activity')))
|
||||
if(t===2){
|
||||
ch.push(node('order_voucher', fieldsNode('order_voucher')))
|
||||
ch.push(node('goods_voucher_batch', fieldsNode('goods_voucher_batch')))
|
||||
ch.push(node('goods_voucher_subject_config', fieldsNode('goods_voucher_subject_config')))
|
||||
} else if(t===3){
|
||||
ch.push(node('order_cash', fieldsNode('order_cash')))
|
||||
} else if(t===1){
|
||||
ch.push(node('order_digit', fieldsNode('order_digit')))
|
||||
} else if(!t){
|
||||
ch.push(node('order_voucher', fieldsNode('order_voucher')))
|
||||
ch.push(node('order_cash', fieldsNode('order_cash')))
|
||||
ch.push(node('order_digit', fieldsNode('order_digit')))
|
||||
ch.push(node('goods_voucher_batch', fieldsNode('goods_voucher_batch')))
|
||||
ch.push(node('goods_voucher_subject_config', fieldsNode('goods_voucher_subject_config')))
|
||||
}
|
||||
return ch
|
||||
}
|
||||
const orderNode = node('order', orderChildrenFor(type))
|
||||
return [ orderNode ]
|
||||
}
|
||||
const orderChildrenBase = []
|
||||
orderChildrenBase.push(...fieldsNode('order'))
|
||||
orderChildrenBase.push(node('order_detail', fieldsNode('order_detail')))
|
||||
const planChildren = []
|
||||
planChildren.push(...fieldsNode('plan'))
|
||||
planChildren.push(node('key_batch', [
|
||||
...fieldsNode('key_batch'),
|
||||
node('code_batch', fieldsNode('code_batch'))
|
||||
]))
|
||||
const voucherChildren = []
|
||||
voucherChildren.push(...fieldsNode('order_voucher'))
|
||||
voucherChildren.push(node('voucher', [
|
||||
...fieldsNode('voucher'),
|
||||
node('voucher_batch', fieldsNode('voucher_batch'))
|
||||
]))
|
||||
const orderChildrenFor = (t)=>{
|
||||
const ch = [...orderChildrenBase]
|
||||
if(t===1){
|
||||
ch.push(node('plan', planChildren))
|
||||
ch.push(node('merchant_key_send', fieldsNode('merchant_key_send')))
|
||||
} else if(t===2){
|
||||
ch.push(node('order_voucher', voucherChildren))
|
||||
ch.push(node('plan', planChildren))
|
||||
} else if(t===3){
|
||||
ch.push(node('order_cash', fieldsNode('order_cash')))
|
||||
ch.push(node('plan', planChildren))
|
||||
} else {
|
||||
ch.push(node('order_cash', fieldsNode('order_cash')))
|
||||
ch.push(node('order_voucher', voucherChildren))
|
||||
ch.push(node('plan', planChildren))
|
||||
ch.push(node('merchant_key_send', fieldsNode('merchant_key_send')))
|
||||
}
|
||||
return ch
|
||||
}
|
||||
const orderNode = node('order', orderChildrenFor(type))
|
||||
return [ orderNode ]
|
||||
})
|
||||
const TABLE_LABELS = {
|
||||
order: '订单主表',
|
||||
order_detail: '订单详情',
|
||||
|
|
@ -443,30 +602,53 @@ const { createApp, reactive } = Vue;
|
|||
marketing: 'order_number,creator,out_trade_no,type,status,contract_price,num,total,pay_amount,create_time',
|
||||
ymt: 'order_number,creator,out_trade_no,type,status,contract_price,num,pay_amount,create_time'
|
||||
}
|
||||
Vue.watch(()=>state.form.datasource, (ds)=>{
|
||||
const recommendedMeta = Vue.ref([])
|
||||
Vue.watch(()=>state.form.datasource, async (ds)=>{
|
||||
state.form.fieldsSel = []
|
||||
state.form.fieldsRaw = DEFAULT_FIELDS[ds] || ''
|
||||
state.form.main_table = (ds==='ymt' ? 'order_info' : 'order')
|
||||
state.form.orderType = 1
|
||||
await loadFieldsMeta(ds, state.form.orderType)
|
||||
recommendedMeta.value = []
|
||||
try{
|
||||
const res = await fetch(API_BASE + '/api/metadata/fields?datasource=' + encodeURIComponent(ds) + '&order_type=' + encodeURIComponent(String(state.form.orderType||0)))
|
||||
const data = await res.json()
|
||||
const rec = Array.isArray(data?.data?.recommended) ? data.data.recommended : (Array.isArray(data?.recommended)? data.recommended: [])
|
||||
recommendedMeta.value = rec
|
||||
}catch(_e){ recommendedMeta.value = [] }
|
||||
const recOrderFields = (recommendedMeta.value||[]).filter(k=>String(k).startsWith('order.')).map(k=>String(k).split('.')[1])
|
||||
state.form.fieldsRaw = (recOrderFields.length ? recOrderFields.join(',') : (DEFAULT_FIELDS[ds] || ''))
|
||||
})
|
||||
Vue.watch(()=>state.form.orderType, ()=>{
|
||||
Vue.watch(()=>state.form.orderType, async ()=>{
|
||||
state.form.fieldsSel = []
|
||||
// 订单类型变化,刷新推荐字段
|
||||
const ds = state.form.datasource
|
||||
await loadFieldsMeta(ds, state.form.orderType)
|
||||
try{
|
||||
const res = await fetch(API_BASE + '/api/metadata/fields?datasource=' + encodeURIComponent(ds) + '&order_type=' + encodeURIComponent(String(state.form.orderType||0)))
|
||||
const data = await res.json()
|
||||
const rec = Array.isArray(data?.data?.recommended) ? data.data.recommended : (Array.isArray(data?.recommended)? data.recommended: [])
|
||||
recommendedMeta.value = rec
|
||||
}catch(_e){ recommendedMeta.value = [] }
|
||||
const recOrderFields = (recommendedMeta.value||[]).filter(k=>String(k).startsWith('order.')).map(k=>String(k).split('.')[1])
|
||||
state.form.fieldsRaw = (recOrderFields.length ? recOrderFields.join(',') : (DEFAULT_FIELDS[ds] || ''))
|
||||
})
|
||||
Vue.watch(()=>state.edit.datasource, (ds)=>{
|
||||
Vue.watch(()=>state.edit.datasource, async (ds)=>{
|
||||
state.edit.fieldsSel = []
|
||||
state.edit.main_table = (ds==='ymt' ? 'order_info' : 'order')
|
||||
await loadFieldsMeta(ds, state.edit.orderType)
|
||||
})
|
||||
Vue.watch(()=>state.edit.orderType, ()=>{
|
||||
Vue.watch(()=>state.edit.orderType, async ()=>{
|
||||
state.edit.fieldsSel = []
|
||||
await loadFieldsMeta(state.edit.datasource, state.edit.orderType)
|
||||
})
|
||||
const orderLeafPaths = (ds)=>{
|
||||
const FM = FIELDS_MAP[ds] || {}
|
||||
const FM = FM_OF(ds)
|
||||
const arr = (FM.order || []).map(f=>['order', f.value])
|
||||
return arr
|
||||
}
|
||||
|
||||
const hasOrderPath = (arr)=> Array.isArray(arr) && arr.some(p=>Array.isArray(p) && p.length===1 && p[0]==='order')
|
||||
const tableKeys = (ds)=> Object.keys(FIELDS_MAP[ds] || {})
|
||||
const tableKeys = (ds)=> Object.keys(FM_OF(ds) || {})
|
||||
const isGroupPath = (ds, path)=> Array.isArray(path) && path.length>=1 && tableKeys(ds).includes(path[path.length-1])
|
||||
|
||||
const msg = (t, type='success')=>ElementPlus.ElMessage({message:t,type});
|
||||
|
|
@ -784,7 +966,9 @@ const { createApp, reactive } = Vue;
|
|||
})
|
||||
}
|
||||
} else {
|
||||
fields = state.form.fieldsRaw.split(',').map(s=>s.trim()).filter(Boolean)
|
||||
const rec = (recommendedMeta.value||[])
|
||||
if(Array.isArray(rec) && rec.length){ fields = rec }
|
||||
else { fields = state.form.fieldsRaw.split(',').map(s=>s.trim()).filter(Boolean).map(f=>('order.'+f)) }
|
||||
}
|
||||
const payload = {
|
||||
name: state.form.name,
|
||||
|
|
@ -894,6 +1078,7 @@ const { createApp, reactive } = Vue;
|
|||
} else {
|
||||
state.edit.orderType = 1
|
||||
}
|
||||
await loadFieldsMeta(state.edit.datasource, state.edit.orderType)
|
||||
const fields = Array.isArray(tpl.fields) ? tpl.fields : []
|
||||
const toPath = (tf)=>{
|
||||
const parts = String(tf||'').split('.')
|
||||
|
|
@ -910,6 +1095,11 @@ const { createApp, reactive } = Vue;
|
|||
if(table==='voucher_batch') return ['order','order_voucher','voucher','voucher_batch',field]
|
||||
if(table==='merchant_key_send') return ['order','merchant_key_send',field]
|
||||
if(table==='order_cash') return ['order','order_cash',field]
|
||||
if(table==='order_digit') return ['order','order_digit',field]
|
||||
if(table==='goods_voucher_batch') return ['order','goods_voucher_batch',field]
|
||||
if(table==='goods_voucher_subject_config') return ['order','goods_voucher_subject_config',field]
|
||||
if(table==='merchant') return ['order','merchant',field]
|
||||
if(table==='activity') return ['order','activity',field]
|
||||
return null
|
||||
}
|
||||
state.edit.fieldsSel = fields.map(toPath).filter(p=>Array.isArray(p) && p.length>=2)
|
||||
|
|
@ -984,8 +1174,9 @@ const { createApp, reactive } = Vue;
|
|||
}catch(_e){ state.sqlText=''; state.sqlVisible=false; msg('加载SQL失败','error') }
|
||||
}
|
||||
loadTemplates()
|
||||
loadFieldsMeta(state.form.datasource, state.form.orderType)
|
||||
|
||||
return { ...Vue.toRefs(state), visibilityOptions, formatOptions, datasourceOptions, fieldOptions, editFieldOptions, sceneOptions, editSceneOptions, loadTemplates, createTemplate, openExport, submitExport, loadJob, loadJobs, openJobs, closeJobs, download, openSQL, openEdit, saveEdit, removeTemplate, resizeDialog, createRules, exportRules, editRules, createFormRef, exportFormRef, editFormRef, dsLabel, exportType, isOrder, exportTitle, creatorOptions, resellerOptions, planOptions, hasCreators, hasReseller, hasPlan, hasKeyBatch, hasCodeBatch, jobPercent, fmtDT, fieldsCascader, editFieldsCascader, createCascaderRoot, editCascaderRoot, onCascaderVisible, onFieldsSelChange, hasUserId, currentUserId }
|
||||
return { ...Vue.toRefs(state), visibilityOptions, formatOptions, datasourceOptions, fieldOptionsDynamic, editFieldOptionsDynamic, sceneOptions, editSceneOptions, loadTemplates, createTemplate, openExport, submitExport, loadJob, loadJobs, openJobs, closeJobs, download, openSQL, openEdit, saveEdit, removeTemplate, resizeDialog, createRules, exportRules, editRules, createFormRef, exportFormRef, editFormRef, dsLabel, exportType, isOrder, exportTitle, creatorOptions, resellerOptions, planOptions, hasCreators, hasReseller, hasPlan, hasKeyBatch, hasCodeBatch, jobPercent, fmtDT, fieldsCascader, editFieldsCascader, createCascaderRoot, editCascaderRoot, onCascaderVisible, onFieldsSelChange, hasUserId, currentUserId }
|
||||
}
|
||||
})
|
||||
app.use(ElementPlus)
|
||||
|
|
|
|||
Loading…
Reference in New Issue