Skip to content

Commit

Permalink
feat: support redeem code operation (coaidev#90)
Browse files Browse the repository at this point in the history
  • Loading branch information
zmh-program committed Mar 11, 2024
1 parent 296c1f8 commit 6f5dae5
Show file tree
Hide file tree
Showing 18 changed files with 192 additions and 98 deletions.
20 changes: 10 additions & 10 deletions admin/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,27 +133,27 @@ func UserTypeAnalysisAPI(c *gin.Context) {

func RedeemListAPI(c *gin.Context) {
db := utils.GetDBFromContext(c)
c.JSON(http.StatusOK, GetRedeemData(db))
}

func RedeemSegmentAPI(c *gin.Context) {
quota := utils.ParseFloat32(c.Query("quota"))
onlyUnused := utils.ParseBool(c.Query("unused"))
page, _ := strconv.Atoi(c.Query("page"))
c.JSON(http.StatusOK, GetRedeemData(db, int64(page)))
}

func DeleteRedeemAPI(c *gin.Context) {
db := utils.GetDBFromContext(c)

data, err := GetRedeemSegment(db, quota, onlyUnused)
if err != nil {
var form DeleteInvitationForm
if err := c.ShouldBindJSON(&form); err != nil {
c.JSON(http.StatusOK, gin.H{
"status": false,
"error": err.Error(),
})
return

}

err := DeleteRedeemCode(db, form.Code)
c.JSON(http.StatusOK, gin.H{
"status": true,
"data": data,
"status": err == nil,
"error": err,
})
}

Expand Down
78 changes: 41 additions & 37 deletions admin/redeem.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,60 +5,64 @@ import (
"chat/utils"
"database/sql"
"fmt"
"math"
"strings"
)

func GetRedeemData(db *sql.DB) []RedeemData {
var data []RedeemData
func GetRedeemData(db *sql.DB, page int64) PaginationForm {
var data []interface{}
var total int64
if err := globals.QueryRowDb(db, `
SELECT COUNT(*) FROM redeem
`).Scan(&total); err != nil {
return PaginationForm{
Status: false,
Message: err.Error(),
}
}

rows, err := globals.QueryDb(db, `
SELECT quota, COUNT(*) AS total, SUM(IF(used = 0, 0, 1)) AS used
SELECT code, quota, used, created_at, updated_at
FROM redeem
GROUP BY quota
`)
ORDER BY id DESC LIMIT ? OFFSET ?
`, pagination, page*pagination)

if err != nil {
return data
return PaginationForm{
Status: false,
Message: err.Error(),
}
}

for rows.Next() {
var d RedeemData
if err := rows.Scan(&d.Quota, &d.Total, &d.Used); err != nil {
return data
var redeem RedeemData
var createdAt []uint8
var updatedAt []uint8
if err := rows.Scan(&redeem.Code, &redeem.Quota, &redeem.Used, &createdAt, &updatedAt); err != nil {
return PaginationForm{
Status: false,
Message: err.Error(),
}
}
data = append(data, d)
}

return data
}

func GetRedeemSegment(db *sql.DB, quota float32, onlyUnused bool) ([]string, error) {
var codes []string
var rows *sql.Rows
var err error

if onlyUnused {
rows, err = globals.QueryDb(db, `
SELECT code FROM redeem WHERE quota = ? AND used = 0
`, quota)
} else {
rows, err = globals.QueryDb(db, `
SELECT code FROM redeem WHERE quota = ?
`, quota)
redeem.CreatedAt = utils.ConvertTime(createdAt).Format("2006-01-02 15:04:05")
redeem.UpdatedAt = utils.ConvertTime(updatedAt).Format("2006-01-02 15:04:05")
data = append(data, redeem)
}

if err != nil {
return codes, err
return PaginationForm{
Status: true,
Total: int(math.Ceil(float64(total) / float64(pagination))),
Data: data,
}
}

for rows.Next() {
var code string
if err := rows.Scan(&code); err != nil {
return codes, err
}
codes = append(codes, code)
}
func DeleteRedeemCode(db *sql.DB, code string) error {
_, err := globals.ExecDb(db, `
DELETE FROM redeem WHERE code = ?
`, code)

return codes, nil
return err
}

func GenerateRedeemCodes(db *sql.DB, num int, quota float32) RedeemGenerateResponse {
Expand Down
2 changes: 1 addition & 1 deletion admin/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ func Register(app *gin.RouterGroup) {
app.POST("/admin/invitation/delete", DeleteInvitationAPI)

app.GET("/admin/redeem/list", RedeemListAPI)
app.GET("/admin/redeem/segment", RedeemSegmentAPI)
app.POST("/admin/redeem/generate", GenerateRedeemAPI)
app.POST("/admin/redeem/delete", DeleteRedeemAPI)

app.GET("/admin/user/list", UserPaginationAPI)
app.POST("/admin/user/quota", UserQuotaAPI)
Expand Down
8 changes: 5 additions & 3 deletions admin/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,11 @@ type InvitationData struct {
}

type RedeemData struct {
Quota float32 `json:"quota"`
Used float32 `json:"used"`
Total float32 `json:"total"`
Code string `json:"code"`
Quota float32 `json:"quota"`
Used bool `json:"used"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}

type InvitationGenerateResponse struct {
Expand Down
2 changes: 1 addition & 1 deletion app/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
},
"package": {
"productName": "chatnio",
"version": "3.10.5"
"version": "3.10.6"
},
"tauri": {
"allowlist": {
Expand Down
17 changes: 7 additions & 10 deletions app/src/admin/api/chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,25 +128,22 @@ export async function generateInvitation(
}
}

export async function getRedeemList(): Promise<RedeemResponse> {
export async function getRedeemList(page: number): Promise<RedeemResponse> {
try {
const response = await axios.get("/admin/redeem/list");
const response = await axios.get(`/admin/redeem/list?page=${page}`);
return response.data as RedeemResponse;
} catch (e) {
console.warn(e);
return [];
return { status: false, message: getErrorMessage(e), data: [], total: 0 };
}
}

export async function getRedeemSegment(quota: number, only_unused: boolean) {
export async function deleteRedeem(code: string): Promise<CommonResponse> {
try {
const response = await axios.get(
`/admin/redeem/segment?quota=${quota}&unused=${only_unused}`,
);
return response.data as RedeemResponse;
const response = await axios.post("/admin/redeem/delete", { code });
return response.data as CommonResponse;
} catch (e) {
console.warn(e);
return [];
return { status: false, message: getErrorMessage(e) };
}
}

Expand Down
13 changes: 10 additions & 3 deletions app/src/admin/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,21 @@ export type InvitationResponse = {
};

export type Redeem = {
code: string;
quota: number;
used: boolean;
created_at: string;
updated_at: string;
};

export type RedeemForm = {
data: Redeem[];
total: number;
};

export type RedeemResponse = Redeem[];
export type RedeemSegmentResponse = CommonResponse & {
data: string[];
export type RedeemResponse = CommonResponse & {
data: Redeem[];
total: number;
};

export type InvitationGenerateResponse = {
Expand Down
6 changes: 6 additions & 0 deletions app/src/assets/globals.less
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@
--destructive: 0 67.22% 50.59%;
--destructive-foreground: 0 0% 98%;

--success: 120 100% 50%;
--success-foreground: 0 0% 98%;

--failure: 0 67.22% 50.59%;
--failure-foreground: 0 0% 98%;

--border: 240 5.9% 90%;
--border-hover: 240 5.9% 85%;
--border-active: 240 5.9% 80%;
Expand Down
5 changes: 4 additions & 1 deletion app/src/components/admin/InvitationTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { PaginationAction } from "@/components/ui/pagination.tsx";
import { Badge } from "@/components/ui/badge.tsx";
import OperationAction from "@/components/OperationAction.tsx";
import { toastState } from "@/api/common.ts";
import StateBadge from "@/components/admin/common/StateBadge.tsx";

function GenerateDialog({ update }: { update: () => void }) {
const { t } = useTranslation();
Expand Down Expand Up @@ -191,7 +192,9 @@ function InvitationTable() {
<TableCell>
<Badge>{invitation.type}</Badge>
</TableCell>
<TableCell>{t(`admin.used-${invitation.used}`)}</TableCell>
<TableCell>
<StateBadge state={invitation.used} />
</TableCell>
<TableCell>{invitation.username || "-"}</TableCell>
<TableCell>{invitation.created_at}</TableCell>
<TableCell>{invitation.updated_at}</TableCell>
Expand Down
Loading

0 comments on commit 6f5dae5

Please sign in to comment.