master
Evan Chen 2022-01-04 20:39:28 +08:00
parent 7a40fcbcc7
commit 90ecb636f0
11 changed files with 199 additions and 22 deletions

4
api.go
View File

@ -8,6 +8,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/line/line-bot-sdk-go/v7/linebot"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
@ -26,6 +27,9 @@ func ApiUpdateEmail(c *gin.Context) {
} }
DB.Model(&User{}).Where("id = ?", data.ID).Update("email", data.Email) DB.Model(&User{}).Where("id = ?", data.ID).Update("email", data.Email)
OK(c, "ok") OK(c, "ok")
msg := linebot.NewTextMessage("更新成功!")
sticker := linebot.NewStickerMessage("1070", "17840")
SendMessage("", data.ID, msg, sticker, DefaultMsg())
} }
func ApiPostReceipt(c *gin.Context) { func ApiPostReceipt(c *gin.Context) {

View File

@ -50,6 +50,8 @@ func postback(event *linebot.Event) {
ApiPrepareClaim(event) ApiPrepareClaim(event)
case strings.HasPrefix(data, "cat="): case strings.HasPrefix(data, "cat="):
ApiListProductOfCat(event) ApiListProductOfCat(event)
case strings.HasPrefix(data, "purchase="):
ApiPurchase(event)
case data == "list-tags": case data == "list-tags":
ApiListCategories(event) ApiListCategories(event)
} }
@ -62,6 +64,9 @@ func controller(event *linebot.Event) {
log.Error().Msg("controller not impemented") log.Error().Msg("controller not impemented")
return return
} }
if !valid(event) {
return
}
Hit(msg.Text, event.Source.UserID) Hit(msg.Text, event.Source.UserID)
switch { switch {
@ -80,6 +85,8 @@ func controller(event *linebot.Event) {
case strings.HasPrefix(msg.Text, "我是"): case strings.HasPrefix(msg.Text, "我是"):
case msg.Text == "我知道": case msg.Text == "我知道":
case msg.Text == "我要理賠": case msg.Text == "我要理賠":
case msg.Text == "修改完成":
case msg.Text == "我要投保":
default: default:
// route to watson // route to watson

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"strconv"
"strings" "strings"
"github.com/line/line-bot-sdk-go/v7/linebot" "github.com/line/line-bot-sdk-go/v7/linebot"
@ -37,13 +38,40 @@ func ApiListProductOfCat(event *linebot.Event) {
data := event.Postback.Data data := event.Postback.Data
data = strings.TrimPrefix(data, "cat=") data = strings.TrimPrefix(data, "cat=")
msg := linebot.NewTextMessage(data + ":") var prods []Product
DB.Find(prods, "id in (select product_id from product_categories where category_name = ?)", data)
columns := make([]*linebot.CarouselColumn, len(prods))
for i, prod := range prods {
columns[i] = linebot.NewCarouselColumn(
prod.Img, prod.Name, prod.Brief,
linebot.NewURIAction("保單詳細", flagBase+"/product/"+strconv.Itoa(int(prod.ID))),
linebot.NewPostbackAction("我要投保", "purchase="+prod.Name, "我要投保", ""),
)
}
template := linebot.NewCarouselTemplate(columns...)
msg := linebot.NewTemplateMessage("我要投保", template)
if _, err := SendMessage(event.ReplyToken, event.Source.UserID, msg); err != nil { if _, err := SendMessage(event.ReplyToken, event.Source.UserID, msg); err != nil {
panic(err) panic(err)
} }
} }
func ApiGetProduct(event *linebot.Event) {} func ApiPurchase(event *linebot.Event) {
data := event.Postback.Data
data = strings.TrimPrefix(data, "purchase=")
prod := &Product{}
if err := DB.Preload("Categories").First(prod, "name = ?", data); err != nil {
panic(err)
}
// show amount and finish purchase
msg := linebot.NewTextMessage(`,
: XXX
`)
SendMessage(event.ReplyToken, event.Source.UserID, msg)
}
func ApiListRecommanded(event *linebot.Event) { func ApiListRecommanded(event *linebot.Event) {
var prods []Product var prods []Product

View File

@ -1,9 +1,13 @@
package main package main
import "github.com/line/line-bot-sdk-go/v7/linebot" import (
"strconv"
"github.com/line/line-bot-sdk-go/v7/linebot"
)
func ApiMe(event *linebot.Event) { func ApiMe(event *linebot.Event) {
leftBtn := linebot.NewURIAction("修改資料", flagBase+"/profile") leftBtn := linebot.NewURIAction("修改資料", flagBase+"/profile/"+event.Source.UserID)
rightBtn := linebot.NewMessageAction("我的保單", "我的保單") rightBtn := linebot.NewMessageAction("我的保單", "我的保單")
template := linebot.NewConfirmTemplate("請問想辦理甚麼服務?", leftBtn, rightBtn) template := linebot.NewConfirmTemplate("請問想辦理甚麼服務?", leftBtn, rightBtn)
msg := linebot.NewTemplateMessage("請問想辦理甚麼服務?", template) msg := linebot.NewTemplateMessage("請問想辦理甚麼服務?", template)
@ -12,6 +16,28 @@ func ApiMe(event *linebot.Event) {
} }
} }
func valid(event *linebot.Event) bool {
msg, _ := event.Message.(*linebot.TextMessage)
if msg.Text == "我的資料" {
return true
}
usr := &User{}
if err := DB.First(usr, "id = ?", event.Source.UserID).Error; err != nil {
panic(err)
}
if usr.Email == "" {
text := "您的基本資料不完整, 請您協助填寫。"
tmp := linebot.NewButtonsTemplate("", "", text,
linebot.NewURIAction("點我填寫", flagBase+"/profile/"+event.Source.UserID))
msg := linebot.NewTemplateMessage(text, tmp)
if _, err := SendMessage(event.ReplyToken, event.Source.UserID, msg); err != nil {
panic(err)
}
return false
}
return true
}
func ApiMyOrders(event *linebot.Event) { func ApiMyOrders(event *linebot.Event) {
var orders []Order var orders []Order
DB.Order("product_id").Find(&orders, "user_id = ?", event.Source.UserID) DB.Order("product_id").Find(&orders, "user_id = ?", event.Source.UserID)
@ -36,7 +62,7 @@ func ApiMyOrders(event *linebot.Event) {
for i, prod := range products { for i, prod := range products {
columns[i] = linebot.NewCarouselColumn( columns[i] = linebot.NewCarouselColumn(
prod.Img, prod.Name, prod.Brief, prod.Img, prod.Name, prod.Brief,
linebot.NewURIAction("保單詳細", flagBase+"/product"), linebot.NewURIAction("保單詳細", flagBase+"/product/"+strconv.Itoa(int(prod.ID))),
linebot.NewPostbackAction("我要理賠", "claim="+prod.Name, "我要理賠", ""), linebot.NewPostbackAction("我要理賠", "claim="+prod.Name, "我要理賠", ""),
// linebot.NewPostbackAction("我是"+prof.Name, "select="+prof.Name, "我是"+prof.Name, ""), // linebot.NewPostbackAction("我是"+prof.Name, "select="+prof.Name, "我是"+prof.Name, ""),
) )

2
db.go
View File

@ -44,7 +44,7 @@ func migrateDB() {
if err := DB.SetupJoinTable(&User{}, "Products", &Order{}); err != nil { if err := DB.SetupJoinTable(&User{}, "Products", &Order{}); err != nil {
panic(err) panic(err)
} }
if err := DB.AutoMigrate(&Node{}, &User{}, &Profile{}, &Product{}, &Order{}); err != nil { if err := DB.AutoMigrate(&Node{}, &User{}, &Profile{}, &Product{}, &Order{}, &Price{}); err != nil {
panic(err) panic(err)
} }
} }

View File

@ -77,13 +77,16 @@ func main() {
server.GET("/check", func(c *gin.Context) { server.GET("/check", func(c *gin.Context) {
c.Writer.Write(check_web) c.Writer.Write(check_web)
}) })
server.GET("/profile", func(c *gin.Context) { server.GET("/profile/:uid", func(c *gin.Context) {
log.Debug().Str("uid", c.Param("uid")).Msg("profile")
c.Writer.Write(profile_web) c.Writer.Write(profile_web)
}) })
server.GET("/claim", func(c *gin.Context) { server.GET("/claim/:oid", func(c *gin.Context) {
log.Debug().Str("oid", c.Param("oid")).Msg("claim")
c.Writer.Write(claim_web) c.Writer.Write(claim_web)
}) })
server.GET("/product", func(c *gin.Context) { server.GET("/product/:pid", func(c *gin.Context) {
log.Debug().Str("pid", c.Param("pid")).Msg("product")
c.Writer.Write(product_web) c.Writer.Write(product_web)
}) })

View File

@ -27,14 +27,29 @@ type User struct {
type Profile struct { type Profile struct {
ID uint `gorm:"primaryKey"` ID uint `gorm:"primaryKey"`
Name string Name string
Brief string Brief string
Img string Img string
Age int
Gender string
Occupation string
PersonalID string
Phone string
Address string
CreatedAt time.Time CreatedAt time.Time
UpdatedAt time.Time UpdatedAt time.Time
} }
type Price struct {
ProfileID uint `gorm:"primaryKey"`
ProductID uint `gorm:"primaryKey"`
PlanPrice float32
PlanUnit int
Detials string
}
type Product struct { type Product struct {
ID uint `gorm:"primaryKey"` ID uint `gorm:"primaryKey"`

View File

@ -1,11 +1,25 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>核身</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css">
<title>核身</title>
</head> </head>
<body> <body>
<h1>HI</h1> <section class="hero is-fullheight" style="background-color:#d70c18;">
<div class="hero-body">
<div class="container">
<h1 class="has-text-white has-text-weight-bold has-text-centered is-size-2">身分檢核中</h1>
<br>
<progress class="progress is-large is-info" max="100">60%</progress>
</div>
</div>
</section>
</body> </body>
<script>
// setTimeout(function(){
// window.location = "https://line.me/R/oaMessage/@565zednv/?完成"
// },1000)
</script>
</html> </html>

View File

@ -3,6 +3,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css">
<title>上傳收據</title> <title>上傳收據</title>
</head> </head>
<body> <body>

View File

@ -3,6 +3,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css">
<title>保單詳細</title> <title>保單詳細</title>
</head> </head>
<body> <body>

View File

@ -1,11 +1,89 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>修改基本資料</title> <title>修改基本資料</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css">
</head> </head>
<body> <body>
<h1>基本資料</h1> <section class="hero is-fullheight" style="background-color:#d70c18;" id="loader">
<div class="hero-body">
<div class="container">
<h1 class="has-text-white has-text-weight-bold has-text-centered is-size-2">身分檢核中</h1>
<br>
<progress class="progress is-large is-info" max="100">60%</progress>
</div>
</div>
</section>
<div id="err" class="notification is-danger is-light is-hidden"
style="position: absolute;width: 100%;">
<button class="delete" onclick="close()"></button>
電子郵件地址格式錯誤
</div>
<section class="hero is-danger is-fullheight is-hidden"
style="background-color:#d70c18;" id="form">
<div class="hero-body">
<div class="container">
<div class="field">
<label class="label has-text-white">Email</label>
<div class="control">
<input id="email" class="input is-danger" type="email" placeholder="請輸入電子郵件">
</div>
</div>
<div class="buttons is-right">
<button id="save" class="button" onclick="save()">送出</button>
</div>
</div>
</div>
</section>
</body> </body>
<script>
setTimeout(function(){
let loader = document.getElementById('loader');
loader.classList.add("is-hidden")
let form = document.getElementById('form');
form.classList.remove("is-hidden")
},3000)
function save(){
let btn = document.getElementById('save');
btn.classList.add("is-loading")
let el = document.getElementById('email');
// get uid
let parts = window.location.href.split('/');
let uid = parts.pop() || parts.pop();
fetch("/api/email", {
method: 'POST',
body: JSON.stringify({id: uid,email: el.value}),
headers: new Headers({
'Content-Type': 'application/json'
})
})
.then(function(res){
if (res.status != 200){
let err = document.getElementById('err');
err.classList.remove("is-hidden")
} else {
setTimeout(function(){
window.location = "https://line.me/R/oaMessage/@565zednv/?"
},500)
}
})
.catch(function(){})
.finally(function() {
btn.classList.remove("is-loading")
})
}
function close(){
let err = document.getElementById('err');
err.classList.add("is-hidden")
}
</script>
</html> </html>