diff --git a/cmd/jintai-visitor-proxy/main.go b/cmd/jintai-visitor-proxy/main.go index 1aafe4d..02c4400 100644 --- a/cmd/jintai-visitor-proxy/main.go +++ b/cmd/jintai-visitor-proxy/main.go @@ -352,8 +352,8 @@ func renderResultHTML(raw []byte) template.HTML { for i, record := range records { b.WriteString(renderVisitorCard(record, i+1, len(records))) } - b.WriteString(`
详细字段`) - b.WriteString(renderAny(result, "访客记录")) + b.WriteString(`
展开表格`) + b.WriteString(renderRecordsTable(records)) b.WriteString(`
`) } else { b.WriteString(renderAny(result, "访客记录")) @@ -387,34 +387,18 @@ func collectRecords(v any) []map[string]any { } func renderVisitorCard(obj map[string]any, index, total int) string { - name := firstField(obj, "姓名", "访客姓名") - if name == "" { - name = "访客" - } - gender := firstField(obj, "性别", "性别_dict", "性别_dictText") - title := "访客" - if gender == "男" { - title = "先生" - } else if gender == "女" { - title = "女士" - } - - company := firstField(obj, "访客公司", "公司", "单位") start := firstField(obj, "开始时间", "来访时间") end := firstField(obj, "结束时间", "离开时间") - reason := firstField(obj, "来访事由_dictText", "来访事由_dict", "来访事由") - host := firstField(obj, "接待人名称", "接待人", "person") qrText := firstField(obj, "备注", "二维码", "通行码", "访客码", "QRCode", "qrCode", "qr") qrSrc, qrErr := qrImageDataURL(qrText) var b strings.Builder b.WriteString(`
`) - b.WriteString(`
访客证`) + b.WriteString(`
访客二维码`) if total > 1 { b.WriteString(`` + html.EscapeString(fmt.Sprintf("%d / %d", index, total)) + ``) } b.WriteString(`
`) - b.WriteString(`
尊敬的` + html.EscapeString(name) + `` + html.EscapeString(title) + `
`) if qrSrc != "" { b.WriteString(`
访客二维码
`) } else { @@ -424,13 +408,9 @@ func renderVisitorCard(obj map[string]any, index, total int) string { } b.WriteString(`
` + html.EscapeString(msg) + `
`) } - b.WriteString(`
进园区时,请出示此二维码
`) - b.WriteString(`
` + html.EscapeString(firstNonEmpty(company, "-")) + `
`) b.WriteString(`
`) b.WriteString(renderMetaRow("开始时间", start)) b.WriteString(renderMetaRow("结束时间", end)) - b.WriteString(renderMetaRow("来访事由", reason)) - b.WriteString(renderMetaRow("接待人", host)) b.WriteString(`
`) return b.String() } @@ -442,6 +422,35 @@ func renderMetaRow(label, value string) string { return `
` + html.EscapeString(label) + `` + html.EscapeString(value) + `
` } +func renderRecordsTable(records []map[string]any) string { + var b strings.Builder + for i, record := range records { + keys := make([]string, 0, len(record)) + for k := range record { + keys = append(keys, k) + } + sort.Strings(keys) + + if len(records) > 1 { + b.WriteString(`

记录 ` + html.EscapeString(fmt.Sprint(i+1)) + `

`) + } + b.WriteString(`
`) + for _, key := range keys { + value := stringify(record[key]) + b.WriteString(``) + } + b.WriteString(`
` + html.EscapeString(key) + ``) + if src, ok := imageSrc(key, value); ok { + b.WriteString(`` + html.EscapeString(key) + ``) + b.WriteString(`
` + html.EscapeString(value) + `
`) + } else { + b.WriteString(html.EscapeString(value)) + } + b.WriteString(`
`) + } + return b.String() +} + func renderAny(v any, title string) string { switch x := v.(type) { case map[string]any: @@ -721,19 +730,10 @@ var pageTemplate = template.Must(template.New("page").Parse(` font-weight: 700; } .card-head strong { font-size: 13px; font-weight: 600; } - .welcome { - display: flex; - align-items: baseline; - justify-content: center; - gap: 8px; - padding: 20px 18px 12px; - font-size: 16px; - } - .welcome b { font-size: 22px; } .qr-wrap { display: flex; justify-content: center; - padding: 8px 0 10px; + padding: 20px 0 10px; background: #fff; } .qr-code { @@ -752,22 +752,10 @@ var pageTemplate = template.Must(template.New("page").Parse(` line-height: 1.6; background: #fff7f7; } - .qr-tip { - padding: 0 18px 14px; - color: #8f6f34; - text-align: center; - font-size: 14px; - } - .company { - padding: 14px 18px; + .card-meta { + padding: 12px 18px 18px; border-top: 1px solid #efe2c8; - border-bottom: 1px solid #efe2c8; - text-align: center; - font-size: 15px; - line-height: 1.6; - word-break: break-word; } - .card-meta { padding: 12px 18px 16px; } .meta-row { display: flex; justify-content: space-between; @@ -797,6 +785,39 @@ var pageTemplate = template.Must(template.New("page").Parse(` font-size: 14px; user-select: none; } + .table-title { + margin: 0; + padding: 12px 14px 0; + color: var(--text); + font-size: 15px; + } + .table-wrap { + width: 100%; + overflow-x: auto; + padding: 12px 14px 14px; + } + .detail-table { + width: 100%; + min-width: 520px; + border-collapse: collapse; + table-layout: fixed; + font-size: 14px; + line-height: 1.55; + } + .detail-table th, .detail-table td { + border: 1px solid var(--line); + padding: 10px 12px; + vertical-align: top; + white-space: pre-wrap; + word-break: break-word; + } + .detail-table th { + width: 170px; + color: var(--muted); + background: #f8fafc; + font-weight: 500; + text-align: left; + } .api-message, .empty, .single-value { padding: 14px 16px; color: var(--muted); @@ -907,7 +928,7 @@ var pageTemplate = template.Must(template.New("page").Parse(` {{.ResultHTML}} - {{if .RawJSON}}
原始响应
{{.RawJSON}}
{{end}} + {{if .RawJSON}}
原始 JSON
{{.RawJSON}}
{{end}} `))