Mercurial > mercurial > hgweb_golang.cgi
diff src/kaigo/Perori/perori.go @ 41:34a474fb83c3
add perori/porori/nk.
author | pyon@macmini |
---|---|
date | Wed, 04 Mar 2020 23:46:59 +0900 |
parents | |
children | c58172a59534 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/kaigo/Perori/perori.go Wed Mar 04 23:46:59 2020 +0900 @@ -0,0 +1,386 @@ +package main + +import ( + "flag" + "compress/gzip" + "encoding/csv" + "fmt" + "html/template" + "io/ioutil" + "log" + "os" + "strings" + "sort" + "time" + + "golang.org/x/text/encoding/japanese" + "golang.org/x/text/transform" +) + +var debug_log bool + +// Constants +const version = "0.2" +const default_dbfile = "ikenshoirai.db" +const default_csvfile = "ikenshoirai.csv" + +const tpl = ` +<!DOCTYPE html> <html> + <head> + <style type="text/css"> + body { font-size: 9pt; margin-left: 0px;} + h2 { font-size: 11pt; margin-bottom: 1px; background-color: #ccccff; padding-left: 5px; } + h3 { font-size: 11pt; margin-bottom: 1px; background-color: #f0a8a8; padding-left: 10px; } + table, th, td { border: 0.3px #c0c0c0 solid; border-collapse:collapse; } + table { margin-bottom: 5px; margin-left: 15px; } + th { background-color: #ccffcc; } + hr { page-break-before: always; } + </style> + <title> - </title> + </head> + <body> + + <h2> List <small>( Date = {{.Ymd}} / N = {{.NHhs}} / Dr = {{.NDr}} )</small> </h2> + {{range .Doctors}} + <h3>{{.Name}}<small> ..... {{.Hp}}:{{.Senmon}}</small></h3> + {{range .Clients}} + <table> + <tr> + <td width=140 style="background-color: #98f0f0; padding-left: 10px;">{{.Name}}</td> + <td width=120 align=center>{{.Kubun}} {{.Ymd}}</td> + <td width=480 style="padding-left: 10px;"> + + {{if .Prev.Ymd}} + {{if eq .DrId .Prev.DrId}} + {{str2cp932 "★ 継続 -"}} {{.Prev.Ymd}} + {{else}} + {{.Prev.Dr}} {{.Prev.Ymd}} + {{end}} + {{else}} + New ! + {{end}} + + </td> + <td width=80 align=center>{{.Hhsno}}</td> + </tr> + <tr> + <td colspan=4 style="font-family: serif; font-size: 8pt; padding-left: 10px;">{{.Biko}}</td> + </tr> + + </table> + {{end}} + {{end}} + + <hr /> + {{$hpno := 0}} + <h2> N by Hp </h2> + <table> + <tr> <th> no </th> <th> hp </th> <th width=60> n </th> </tr> + {{range $hp, $n := .Hp}} + <tr> + {{$hpno = add1 $hpno}} + <td align=right style="padding-right: 5px;"> {{$hpno}} </td> + <td style="padding-left: 5px;"> {{$hp}} </td> + <td align=right style="padding-right: 5px;"> {{$n}} </td> + </tr> + {{end}} + <tr> <td></td> <td align=right> sum > > ></td> <td align=right style="padding-right: 5px;"> <b> {{.HpSum}} </b> </td> </tr> + </table> + </body> +</html>` + + +// Define Types +type PrevSinsei struct { + Biko string + DrId string + Dr string + IraiYmd string + Ymd string + Kubun string +} + +type Sinsei struct { + Hhsno string + Name string + Biko string + DrId string + Dr string + DrKana string + Hp string + IraiYmd string + Ymd string + Kubun string + Senmon string + Prev PrevSinsei +} + +func (s *Sinsei) SetPrev(prev PrevSinsei) { + s.Prev = prev +} + +func (s Sinsei) String() string { + return strings.Join([]string{s.Hhsno, s.Name, s.Ymd, s.Kubun, s.Dr, s.Hp, s.Senmon, s.IraiYmd, s.Biko}, ",") +} + +func (s *Sinsei) Humanize() { + var buf string + + switch s.Kubun { + case "01": + buf = "新規" + case "02": + buf = "更新" + case "10": + buf = "支介" + case "05": + buf = "区変" + case "03": + buf = "転入" + case "09": + buf = "証交" + } + s.Kubun, _, _ = transform.String(japanese.ShiftJIS.NewEncoder(), buf) + + s.Ymd = strings.Join([]string{s.Ymd[4:6], s.Ymd[6:8]}, ".") +} + +type Doctor struct { + Id string + Name string + Kana string + Hp string + Senmon string + Clients []Sinsei +} + +func (d *Doctor) AddClient(sinsei Sinsei) { + d.Clients = append(d.Clients, sinsei) +} + +func (d Doctor) String() string { + return d.Name +} + +// Main +func main() { + var csvfile, dbfile, date string + + today := time.Now().Format("20060102") + + flag.StringVar(&csvfile, "c", default_csvfile, "csv file") + flag.StringVar(&dbfile, "b", default_dbfile, "db file") + flag.StringVar(&date, "r", today, "Ikensho Irai YMD") + flag.BoolVar(&debug_log, "d", false, "print debug-log (stderr)") + flag.Parse() + + csvdata, hhshash, err := getdata_fromCSV(csvfile, date) + if err != nil { + log.Fatal(err) + } + print_debug_log(fmt.Sprintf("csvdata: n=%d", len(csvdata))) // + print_debug_log(fmt.Sprintf("hhshash: n=%d", len(hhshash))) // + + dbdata, err := getdata_fromDB(dbfile, hhshash) + if err != nil { + log.Fatal(err) + } + print_debug_log(fmt.Sprintf("dbdata: n=%d", len(dbdata))) // + + dbdata = append(dbdata, csvdata...) + print_debug_log(fmt.Sprintf("dbdata: n=%d", len(dbdata))) // + + sort.Slice(dbdata, func(i, j int) bool { + if dbdata[i].Hhsno != dbdata[j].Hhsno { + return dbdata[i].Hhsno < dbdata[j].Hhsno + } + if dbdata[i].Ymd != dbdata[j].Ymd { + return dbdata[i].Ymd > dbdata[j].Ymd + } + return false + }) + + var recentdata []Sinsei + prevhash := make(map[string]PrevSinsei) + hhscnt := make(map[string]int) + for _, ss := range dbdata { + ss.Humanize() + if n := hhscnt[ss.Hhsno]; n == 1 { + prevhash[ss.Hhsno] = PrevSinsei{ + Biko: ss.Biko, + DrId: ss.DrId, + Dr: ss.Dr + "(" + ss.Hp + ":" + ss.Senmon + ")", + IraiYmd: ss.IraiYmd, + Ymd: ss.Ymd, + Kubun: ss.Kubun, + } + } else { + recentdata = append(recentdata, ss) + hhscnt[ss.Hhsno]++; + } + } + print_debug_log(fmt.Sprintf("recentdata: n=%d", len(recentdata))) // + + doctorhash := make(map[string]Doctor) + hpcnt := make(map[string]int) + var hpcntsum int + for _, ss := range recentdata { + ss.SetPrev(prevhash[ss.Hhsno]) + if d, ok := doctorhash[ss.DrId]; !ok { + doctorhash[ss.DrId] = Doctor{ + Id: ss.DrId, + Name: ss.Dr, + Kana: ss.DrKana, + Hp: ss.Hp, + Senmon: ss.Senmon, + Clients: []Sinsei{ss}, + } + } else { + d.AddClient(ss) + doctorhash[ss.DrId] = d + } + hpcnt[ss.Hp]++ + hpcntsum++ + } + + var doctors []Doctor + for _, dr := range doctorhash { + doctors = append(doctors, dr) + } + sort.Slice(doctors, func(i, j int) bool { + return doctors[i].Kana < doctors[j].Kana + }) + + irai := struct { + Ymd string + NHhs int + NSinsei int + NDr int + Doctors []Doctor + Hp map[string]int + HpSum int + }{ + Ymd: strings.Join([]string{date[0:4], date[4:6], date[6:8]}, "."), + NHhs: len(hhshash), + NSinsei: len(dbdata), + NDr: len(doctors), + Doctors: doctors, + Hp: hpcnt, + HpSum: hpcntsum, + } + + funcmap := template.FuncMap{ + "shorten": shorten, + "str2cp932": str2cp932, + "add1": func(a int) int { return a + 1 }, + } + + t, err := template.New("webpage").Funcs(funcmap).Parse(tpl) + if err != nil { + log.Fatal(err) + } + + err = t.Execute(os.Stdout, irai) + if err != nil { + log.Fatal(err) + } +} + +// Utility functions +func csv2sinsei(record []string) Sinsei { + return Sinsei{ + Hhsno: strings.TrimSpace(record[0]), + Name: strings.TrimSpace(record[1]), + Biko: strings.TrimSpace(record[2]), + DrId: strings.TrimSpace(record[3]), + Dr: strings.TrimSpace(record[4]), + DrKana: strings.TrimSpace(record[5]), + Hp: strings.TrimSpace(record[6]), + IraiYmd: strings.TrimSpace(record[7]), + Ymd: strings.TrimSpace(record[8]), + Kubun: strings.TrimSpace(record[9]), + Senmon: strings.TrimSpace(record[10]), + } +} + +func getdata_fromCSV(file, date string) (sinsei []Sinsei, hhshash map[string]bool, err error) { + hhshash = make(map[string]bool) + + data, err := ioutil.ReadFile(file) + if err != nil { + return sinsei, hhshash, err + } + + r := csv.NewReader(strings.NewReader(string(data))) + records, err := r.ReadAll() + if err != nil { + return sinsei, hhshash, err + } + + for _, record := range records { + ss := csv2sinsei(record) + if ss.IraiYmd != date { + continue + } + hhshash[ss.Hhsno] = true + sinsei = append(sinsei, ss) + } + + return sinsei, hhshash, nil +} + +func getdata_fromDB(file string, hhshash map[string]bool) (sinsei []Sinsei, err error) { + f, err := os.Open(file) + if err != nil { + return sinsei, err + } + defer f.Close() + + zr, err := gzip.NewReader(f) + if err != nil { + return sinsei, err + } + + data, err := ioutil.ReadAll(zr) + if err != nil { + return sinsei, err + } + + if err := zr.Close(); err != nil { + return sinsei, err + } + + r := csv.NewReader(strings.NewReader(string(data))) + records, err := r.ReadAll() + if err != nil { + return sinsei, err + } + + for _, record := range records { + hno := strings.TrimSpace(record[0]) + if _, ok := hhshash[hno]; ok { + sinsei = append(sinsei, csv2sinsei(record)) + } + } + + return sinsei, nil +} + +func shorten(msg string, length int) string { + if len(msg) > length { + msg = msg[0:length] + "..." + } + return msg +} + +func str2cp932(s string) string { + s, _, _ = transform.String(japanese.ShiftJIS.NewEncoder(), s) + return s +} + +func print_debug_log(msg string) { + if debug_log { + fmt.Fprintf(os.Stderr, "%s\n", msg) + } +} +