Compare commits

...

4 Commits

Author SHA1 Message Date
JustSong
34bce5b464 style: add positive attribute to submit buttons (close #113) 2023-05-22 22:30:11 +08:00
JustSong
d4794fc051 feat: return user's quota with billing api (close #92) 2023-05-22 17:10:31 +08:00
JustSong
8b43e0dd3f fix: add no-cache for index.html 2023-05-22 00:54:53 +08:00
JustSong
92c88fa273 fix: remove no-store for index.html 2023-05-22 00:44:27 +08:00
10 changed files with 91 additions and 26 deletions

41
controller/billing.go Normal file
View File

@@ -0,0 +1,41 @@
package controller
import (
"github.com/gin-gonic/gin"
"one-api/model"
)
func GetSubscription(c *gin.Context) {
userId := c.GetInt("id")
quota, err := model.GetUserQuota(userId)
if err != nil {
openAIError := OpenAIError{
Message: err.Error(),
Type: "one_api_error",
}
c.JSON(200, gin.H{
"error": openAIError,
})
return
}
subscription := OpenAISubscriptionResponse{
Object: "billing_subscription",
HasPaymentMethod: true,
SoftLimitUSD: float64(quota),
HardLimitUSD: float64(quota),
SystemHardLimitUSD: float64(quota),
}
c.JSON(200, subscription)
return
}
func GetUsage(c *gin.Context) {
//userId := c.GetInt("id")
// TODO: get usage from database
usage := OpenAIUsageResponse{
Object: "list",
TotalUsage: 0,
}
c.JSON(200, usage)
return
}

View File

@@ -13,12 +13,27 @@ import (
"time" "time"
) )
// https://github.com/songquanpeng/one-api/issues/79
type OpenAISubscriptionResponse struct { type OpenAISubscriptionResponse struct {
HasPaymentMethod bool `json:"has_payment_method"` Object string `json:"object"`
HardLimitUSD float64 `json:"hard_limit_usd"` HasPaymentMethod bool `json:"has_payment_method"`
SoftLimitUSD float64 `json:"soft_limit_usd"`
HardLimitUSD float64 `json:"hard_limit_usd"`
SystemHardLimitUSD float64 `json:"system_hard_limit_usd"`
}
type OpenAIUsageDailyCost struct {
Timestamp float64 `json:"timestamp"`
LineItems []struct {
Name string `json:"name"`
Cost float64 `json:"cost"`
}
} }
type OpenAIUsageResponse struct { type OpenAIUsageResponse struct {
Object string `json:"object"`
//DailyCosts []OpenAIUsageDailyCost `json:"daily_costs"`
TotalUsage float64 `json:"total_usage"` // unit: 0.01 dollar TotalUsage float64 `json:"total_usage"` // unit: 0.01 dollar
} }

View File

@@ -6,7 +6,11 @@ import (
func Cache() func(c *gin.Context) { func Cache() func(c *gin.Context) {
return func(c *gin.Context) { return func(c *gin.Context) {
c.Header("Cache-Control", "max-age=604800") // one week if c.Request.RequestURI == "/" {
c.Header("Cache-Control", "no-cache")
} else {
c.Header("Cache-Control", "max-age=604800") // one week
}
c.Next() c.Next()
} }
} }

View File

@@ -8,11 +8,14 @@ import (
) )
func SetDashboardRouter(router *gin.Engine) { func SetDashboardRouter(router *gin.Engine) {
apiRouter := router.Group("/dashboard") apiRouter := router.Group("/")
apiRouter.Use(gzip.Gzip(gzip.DefaultCompression)) apiRouter.Use(gzip.Gzip(gzip.DefaultCompression))
apiRouter.Use(middleware.GlobalAPIRateLimit()) apiRouter.Use(middleware.GlobalAPIRateLimit())
apiRouter.Use(middleware.TokenAuth()) apiRouter.Use(middleware.TokenAuth())
{ {
apiRouter.GET("/billing/credit_grants", controller.GetTokenStatus) apiRouter.GET("/dashboard/billing/subscription", controller.GetSubscription)
apiRouter.GET("/v1/dashboard/billing/subscription", controller.GetSubscription)
apiRouter.GET("/dashboard/billing/usage", controller.GetUsage)
apiRouter.GET("/v1/dashboard/billing/usage", controller.GetUsage)
} }
} }

View File

@@ -16,7 +16,7 @@ func SetWebRouter(router *gin.Engine, buildFS embed.FS, indexPage []byte) {
router.Use(middleware.Cache()) router.Use(middleware.Cache())
router.Use(static.Serve("/", common.EmbedFolder(buildFS, "web/build"))) router.Use(static.Serve("/", common.EmbedFolder(buildFS, "web/build")))
router.NoRoute(func(c *gin.Context) { router.NoRoute(func(c *gin.Context) {
c.Header("Cache-Control", "no-cache, no-store, must-revalidate") c.Header("Cache-Control", "no-cache")
c.Data(http.StatusOK, "text/html; charset=utf-8", indexPage) c.Data(http.StatusOK, "text/html; charset=utf-8", indexPage)
}) })
} }

View File

@@ -167,7 +167,7 @@ const EditChannel = () => {
/> />
) )
} }
<Button onClick={submit}>提交</Button> <Button positive onClick={submit}>提交</Button>
</Form> </Form>
</Segment> </Segment>
</> </>

View File

@@ -111,7 +111,7 @@ const EditRedemption = () => {
</Form.Field> </Form.Field>
</> </>
} }
<Button onClick={submit}>提交</Button> <Button positive onClick={submit}>提交</Button>
</Form> </Form>
</Segment> </Segment>
</> </>

View File

@@ -133,22 +133,24 @@ const EditToken = () => {
type='datetime-local' type='datetime-local'
/> />
</Form.Field> </Form.Field>
<Button type={'button'} onClick={() => { <div style={{ lineHeight: '40px' }}>
setExpiredTime(0, 0, 0, 0); <Button type={'button'} onClick={() => {
}}>永不过期</Button> setExpiredTime(0, 0, 0, 0);
<Button type={'button'} onClick={() => { }}>永不过期</Button>
setExpiredTime(1, 0, 0, 0); <Button type={'button'} onClick={() => {
}}>一个月后过期</Button> setExpiredTime(1, 0, 0, 0);
<Button type={'button'} onClick={() => { }}>一个月后过期</Button>
setExpiredTime(0, 1, 0, 0); <Button type={'button'} onClick={() => {
}}>一天后过期</Button> setExpiredTime(0, 1, 0, 0);
<Button type={'button'} onClick={() => { }}>一天后过期</Button>
setExpiredTime(0, 0, 1, 0); <Button type={'button'} onClick={() => {
}}>一小时后过期</Button> setExpiredTime(0, 0, 1, 0);
<Button type={'button'} onClick={() => { }}>一小时后过期</Button>
setExpiredTime(0, 0, 0, 1); <Button type={'button'} onClick={() => {
}}>一分钟后过期</Button> setExpiredTime(0, 0, 0, 1);
<Button onClick={submit}>提交</Button> }}>一分钟后过期</Button>
</div>
<Button positive onClick={submit} style={{marginTop: '12px'}}>提交</Button>
</Form> </Form>
</Segment> </Segment>
</> </>

View File

@@ -65,7 +65,7 @@ const AddUser = () => {
required required
/> />
</Form.Field> </Form.Field>
<Button type={'submit'} onClick={submit}> <Button positive type={'submit'} onClick={submit}>
提交 提交
</Button> </Button>
</Form> </Form>

View File

@@ -142,7 +142,7 @@ const EditUser = () => {
readOnly readOnly
/> />
</Form.Field> </Form.Field>
<Button onClick={submit}>提交</Button> <Button positive onClick={submit}>提交</Button>
</Form> </Form>
</Segment> </Segment>
</> </>