feat: 后台用户管理新增 VIP 列
ci/woodpecker/tag/build Pipeline was successful

- 列表接口返回 vipStatus(active/expired/none)与 vipExpireAt
- 表格新增 VIP 列:有效显示金色徽标+到期日期,过期显示已过期,未开通显示非VIP
This commit is contained in:
becomer
2026-09-08 22:31:42 +08:00
parent cc4aa1c00e
commit 99c16652a7
2 changed files with 40 additions and 5 deletions
+15
View File
@@ -29,6 +29,8 @@ type SysUserListItem struct {
InviterName string `json:"inviterName"` // 邀请人展示名(姓名优先,其次用户名)
TaskCount int64 `json:"taskCount"`
ExecutedCount int64 `json:"executedCount"` // 累计成功执行次数
VipStatus string `json:"vipStatus"` // vip: active / expired / none
VipExpireAt string `json:"vipExpireAt"` // VIP 到期时间,未开通为空
TodayStatus string `json:"todayStatus"` // today: success / fail / none
Status string `json:"status"`
CreatedAt string `json:"createdAt"`
@@ -174,6 +176,17 @@ func ListUsers(c *fiber.Ctx) error {
if u.InviterID != nil {
inviterName = inviterNameMap[*u.InviterID]
}
// VIP 状态:active=有效期内 / expired=已过期 / none=未开通
vipStatus := "none"
vipExpireAt := ""
if u.VipExpireAt != nil {
vipExpireAt = u.VipExpireAt.Format("2006-01-02 15:04")
if u.VipExpireAt.After(time.Now()) {
vipStatus = "active"
} else {
vipStatus = "expired"
}
}
items = append(items, SysUserListItem{
ID: u.ID,
Username: u.Username,
@@ -190,6 +203,8 @@ func ListUsers(c *fiber.Ctx) error {
InviterName: inviterName,
TaskCount: taskCountMap[u.ID],
ExecutedCount: executedMap[u.ID],
VipStatus: vipStatus,
VipExpireAt: vipExpireAt,
TodayStatus: todayStatus,
Status: u.Status,
CreatedAt: u.CreatedAt.Format("2006-01-02 15:04:05"),
+25 -5
View File
@@ -51,6 +51,8 @@ interface UserItem {
inviterName: string
taskCount: number
executedCount: number
vipStatus: string
vipExpireAt: string
todayStatus: string
status: string
createdAt: string
@@ -442,16 +444,17 @@ function todayStatusLabel(s: string) {
<table class="w-full text-sm table-fixed min-w-[1260px]">
<thead>
<tr class="bg-gray-50 text-left text-xs text-gray-500">
<th class="px-4 py-3 font-medium w-[9%]">学工号</th>
<th class="px-4 py-3 font-medium w-[8%]">学工号</th>
<th class="px-4 py-3 font-medium w-[6%]">真实姓名</th>
<th class="px-4 py-3 font-medium w-[13%]">学校</th>
<th class="px-4 py-3 font-medium w-[11%]">设备码</th>
<th class="px-4 py-3 font-medium w-[10%]">学校</th>
<th class="px-4 py-3 font-medium w-[10%]">设备码</th>
<th class="px-4 py-3 font-medium w-[8%]">可执行/已执行</th>
<th class="px-4 py-3 font-medium w-[8%]">VIP</th>
<th class="px-4 py-3 font-medium w-[8%]">积分/邀请数</th>
<th class="px-4 py-3 font-medium w-[7%]">邀请人</th>
<th class="px-4 py-3 font-medium w-[8%]">今天执行状态</th>
<th class="px-4 py-3 font-medium w-[10%]">创建时间</th>
<th class="px-4 py-3 font-medium text-center w-[20%]">操作</th>
<th class="px-4 py-3 font-medium w-[9%]">创建时间</th>
<th class="px-4 py-3 font-medium text-center w-[18%]">操作</th>
</tr>
</thead>
<tbody>
@@ -482,6 +485,23 @@ function todayStatusLabel(s: string) {
<span class="text-gray-300 mx-0.5">/</span>
<span class="text-gray-500">{{ user.executedCount }}</span>
</td>
<td class="px-4 py-3">
<span
v-if="user.vipStatus === 'active'"
class="text-[10px] px-1.5 py-0.5 rounded-full font-medium bg-amber-100 text-amber-700"
:title="`VIP 到期时间:${user.vipExpireAt}`"
>
VIP · {{ user.vipExpireAt.slice(5, 10) }}
</span>
<span
v-else-if="user.vipStatus === 'expired'"
class="text-[10px] px-1.5 py-0.5 rounded-full font-medium bg-gray-100 text-gray-400"
:title="`VIP 已于 ${user.vipExpireAt} 过期`"
>
VIP · 已过期
</span>
<span v-else class="text-xs text-gray-300">非VIP</span>
</td>
<td class="px-4 py-3">
<span class="font-medium text-gray-900">{{ user.inviteReward }}</span>
<span class="text-gray-300 mx-0.5">/</span>