mirror of
				https://github.com/yangjian102621/geekai.git
				synced 2025-11-04 16:23:42 +08:00 
			
		
		
		
	feat: 完成众筹后台管理功能
This commit is contained in:
		
							
								
								
									
										57
									
								
								api/handler/admin/reward_handler.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								api/handler/admin/reward_handler.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
package admin
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"chatplus/core"
 | 
			
		||||
	"chatplus/handler"
 | 
			
		||||
	"chatplus/store/model"
 | 
			
		||||
	"chatplus/store/vo"
 | 
			
		||||
	"chatplus/utils"
 | 
			
		||||
	"chatplus/utils/resp"
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type RewardHandler struct {
 | 
			
		||||
	handler.BaseHandler
 | 
			
		||||
	db *gorm.DB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewRewardHandler(app *core.AppServer, db *gorm.DB) *RewardHandler {
 | 
			
		||||
	h := RewardHandler{db: db}
 | 
			
		||||
	h.App = app
 | 
			
		||||
	return &h
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *RewardHandler) List(c *gin.Context) {
 | 
			
		||||
	var items []model.Reward
 | 
			
		||||
	res := h.db.Find(&items)
 | 
			
		||||
	var rewards = make([]vo.Reward, 0)
 | 
			
		||||
	if res.Error == nil {
 | 
			
		||||
		userIds := make([]uint, 0)
 | 
			
		||||
		for _, v := range items {
 | 
			
		||||
			userIds = append(userIds, v.UserId)
 | 
			
		||||
		}
 | 
			
		||||
		var users []model.User
 | 
			
		||||
		h.db.Where("id IN ?", userIds).Find(&users)
 | 
			
		||||
		var userMap = make(map[uint]model.User)
 | 
			
		||||
		for _, u := range users {
 | 
			
		||||
			userMap[u.Id] = u
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, v := range items {
 | 
			
		||||
			var r vo.Reward
 | 
			
		||||
			err := utils.CopyObject(v, &r)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			r.Id = v.Id
 | 
			
		||||
			r.Username = userMap[v.UserId].Username
 | 
			
		||||
			r.CreatedAt = v.CreatedAt.Unix()
 | 
			
		||||
			r.UpdatedAt = v.UpdatedAt.Unix()
 | 
			
		||||
			rewards = append(rewards, r)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp.SUCCESS(c, rewards)
 | 
			
		||||
}
 | 
			
		||||
@@ -136,6 +136,7 @@ func main() {
 | 
			
		||||
		fx.Provide(admin.NewApiKeyHandler),
 | 
			
		||||
		fx.Provide(admin.NewUserHandler),
 | 
			
		||||
		fx.Provide(admin.NewChatRoleHandler),
 | 
			
		||||
		fx.Provide(admin.NewRewardHandler),
 | 
			
		||||
 | 
			
		||||
		// 创建服务
 | 
			
		||||
		fx.Provide(service.NewAliYunSmsService),
 | 
			
		||||
@@ -213,6 +214,10 @@ func main() {
 | 
			
		||||
			group.POST("sort", h.SetSort)
 | 
			
		||||
			group.GET("remove", h.Remove)
 | 
			
		||||
		}),
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, h *admin.RewardHandler) {
 | 
			
		||||
			group := s.Engine.Group("/api/admin/reward/")
 | 
			
		||||
			group.GET("list", h.List)
 | 
			
		||||
		}),
 | 
			
		||||
 | 
			
		||||
		fx.Invoke(func(s *core.AppServer, db *gorm.DB) {
 | 
			
		||||
			err := s.Run(db)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								api/store/vo/reward.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								api/store/vo/reward.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
package vo
 | 
			
		||||
 | 
			
		||||
type Reward struct {
 | 
			
		||||
	BaseVo
 | 
			
		||||
	UserId   uint    `json:"user_id"` // 用户 ID
 | 
			
		||||
	Username string  `json:"username"`
 | 
			
		||||
	TxId     string  `json:"tx_id"`  // 交易ID
 | 
			
		||||
	Amount   float64 `json:"amount"` // 打赏金额
 | 
			
		||||
	Remark   string  `json:"remark"` // 打赏备注
 | 
			
		||||
	Status   bool    `json:"status"` // 核销状态
 | 
			
		||||
}
 | 
			
		||||
@@ -79,6 +79,11 @@ const items = [
 | 
			
		||||
    index: '/admin/apikey',
 | 
			
		||||
    title: 'API-KEY 管理',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    icon: 'reward',
 | 
			
		||||
    index: '/admin/reward',
 | 
			
		||||
    title: '众筹管理',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    icon: 'log',
 | 
			
		||||
    index: '/admin/loginLog',
 | 
			
		||||
 
 | 
			
		||||
@@ -69,6 +69,12 @@ const routes = [
 | 
			
		||||
                meta: {title: 'API-KEY 管理'},
 | 
			
		||||
                component: () => import('@/views/admin/ApiKey.vue'),
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                path: '/admin/reward',
 | 
			
		||||
                name: 'admin-reward',
 | 
			
		||||
                meta: {title: '众筹管理'},
 | 
			
		||||
                component: () => import('@/views/admin/RewardList.vue'),
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                path: '/admin/loginLog',
 | 
			
		||||
                name: 'admin-loginLog',
 | 
			
		||||
 
 | 
			
		||||
@@ -1,373 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="admin-body common-layout">
 | 
			
		||||
    <el-container>
 | 
			
		||||
      <el-container>
 | 
			
		||||
        <el-aside
 | 
			
		||||
            :style="{
 | 
			
		||||
            height: winHeight + 'px',
 | 
			
		||||
            width: sideWidth + 'px',
 | 
			
		||||
          }"
 | 
			
		||||
        >
 | 
			
		||||
          <div :class="showSidebar?'title':'title hide'">
 | 
			
		||||
            <el-image :src="logo" class="logo"/>
 | 
			
		||||
            <span class="text">{{ title }}</span>
 | 
			
		||||
            <span
 | 
			
		||||
                class="fold"
 | 
			
		||||
                @click="showSidebar = !showSidebar"
 | 
			
		||||
                :style="{ right: foldIconRight + 'px' }"
 | 
			
		||||
            >
 | 
			
		||||
              <el-icon>
 | 
			
		||||
                <Fold/>
 | 
			
		||||
              </el-icon>
 | 
			
		||||
            </span>
 | 
			
		||||
          </div>
 | 
			
		||||
          <ul class="nav-list">
 | 
			
		||||
            <li
 | 
			
		||||
                v-for="nav in navs"
 | 
			
		||||
                :key="nav.id"
 | 
			
		||||
                :style="{ paddingLeft: nodeListPaddingLeft + 'px' }"
 | 
			
		||||
                :class="nav.active?'active':''"
 | 
			
		||||
                @click="addTab(nav)"
 | 
			
		||||
            >
 | 
			
		||||
              <el-tooltip
 | 
			
		||||
                  class="box-item"
 | 
			
		||||
                  effect="light"
 | 
			
		||||
                  :content="nav.title"
 | 
			
		||||
                  placement="right"
 | 
			
		||||
              >
 | 
			
		||||
                <el-icon>
 | 
			
		||||
                  <Menu/>
 | 
			
		||||
                </el-icon>
 | 
			
		||||
              </el-tooltip>
 | 
			
		||||
 | 
			
		||||
              <span v-if="showSidebar">{{ nav.title }}</span>
 | 
			
		||||
            </li>
 | 
			
		||||
          </ul>
 | 
			
		||||
 | 
			
		||||
          <el-row class="nav-footer">
 | 
			
		||||
            <div class="source">
 | 
			
		||||
              <i class="iconfont icon-github"></i>
 | 
			
		||||
              <el-link href="https://github.com/yangjian102621/chatgpt-plus" target="_blank">ChatGPT-Plus-V3</el-link>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="logout" @click="logout">
 | 
			
		||||
              <i class="iconfont icon-logout"></i>
 | 
			
		||||
              <span>退出登录</span>
 | 
			
		||||
            </div>
 | 
			
		||||
          </el-row>
 | 
			
		||||
        </el-aside>
 | 
			
		||||
 | 
			
		||||
        <el-main>
 | 
			
		||||
          <div
 | 
			
		||||
              class="main-container"
 | 
			
		||||
              :style="{ height: winHeight + 'px' }"
 | 
			
		||||
          >
 | 
			
		||||
            <x-welcome v-if="curTab==='welcome'"/>
 | 
			
		||||
 | 
			
		||||
            <div v-else>
 | 
			
		||||
              <el-tabs
 | 
			
		||||
                  v-model="curTab"
 | 
			
		||||
                  class="content-tabs"
 | 
			
		||||
                  type="card"
 | 
			
		||||
                  closable
 | 
			
		||||
                  @tab-remove="removeTab"
 | 
			
		||||
                  @tab-change="changeTab"
 | 
			
		||||
              >
 | 
			
		||||
                <el-tab-pane label="系统配置" name="config" v-if="arrayContains(tabs, 'config')">
 | 
			
		||||
                  <sys-config v-if="curTab==='config'"/>
 | 
			
		||||
                </el-tab-pane>
 | 
			
		||||
 | 
			
		||||
                <el-tab-pane label="用户管理" name="user" v-if="arrayContains(tabs, 'user')">
 | 
			
		||||
                  <user-list v-if="curTab==='user'"/>
 | 
			
		||||
                </el-tab-pane>
 | 
			
		||||
 | 
			
		||||
                <el-tab-pane label="角色管理" name="role" v-if="arrayContains(tabs, 'role')">
 | 
			
		||||
                  <role-list v-if="curTab==='role'"/>
 | 
			
		||||
                </el-tab-pane>
 | 
			
		||||
                <el-tab-pane label="API KEY" name="apikey" v-if="arrayContains(tabs, 'apikey')">
 | 
			
		||||
                  <api-key v-if="curTab==='apikey'"/>
 | 
			
		||||
                </el-tab-pane>
 | 
			
		||||
                <el-tab-pane label="登录日志" name="loginLog" v-if="arrayContains(tabs, 'loginLog')">
 | 
			
		||||
                  <login-log v-if="curTab==='loginLog'"/>
 | 
			
		||||
                </el-tab-pane>
 | 
			
		||||
              </el-tabs>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </el-main>
 | 
			
		||||
      </el-container>
 | 
			
		||||
    </el-container>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
import {computed, onMounted, ref} from 'vue'
 | 
			
		||||
import {Fold, Menu} from "@element-plus/icons-vue"
 | 
			
		||||
import XWelcome from "@/views/admin/Welcome.vue";
 | 
			
		||||
import SysConfig from "@/views/admin/SysConfig.vue";
 | 
			
		||||
import {arrayContains, removeArrayItem} from "@/utils/libs";
 | 
			
		||||
import UserList from "@/views/admin/UserList.vue";
 | 
			
		||||
import RoleList from "@/views/admin/RoleList.vue";
 | 
			
		||||
import {httpGet} from "@/utils/http";
 | 
			
		||||
import {ElMessage} from "element-plus";
 | 
			
		||||
import {useRouter} from "vue-router";
 | 
			
		||||
import ApiKey from "@/views/admin/ApiKey.vue";
 | 
			
		||||
import LoginLog from "@/views/admin/LoginLog.vue";
 | 
			
		||||
 | 
			
		||||
const title = ref('Chat-Plus 控制台')
 | 
			
		||||
const logo = ref('images/logo.png')
 | 
			
		||||
const navs = ref([
 | 
			
		||||
  {
 | 
			
		||||
    id: 1,
 | 
			
		||||
    title: '系统配置',
 | 
			
		||||
    tab: 'config',
 | 
			
		||||
    active: false,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    id: 2,
 | 
			
		||||
    title: '用户管理',
 | 
			
		||||
    tab: 'user',
 | 
			
		||||
    active: false,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    id: 3,
 | 
			
		||||
    title: '角色管理',
 | 
			
		||||
    tab: 'role',
 | 
			
		||||
    active: false,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    id: 4,
 | 
			
		||||
    title: 'API KEY',
 | 
			
		||||
    tab: 'apikey',
 | 
			
		||||
    active: false,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    id: 5,
 | 
			
		||||
    title: '登录日志',
 | 
			
		||||
    tab: 'loginLog',
 | 
			
		||||
    active: false,
 | 
			
		||||
  }
 | 
			
		||||
])
 | 
			
		||||
const tabs = ref([])
 | 
			
		||||
const curNav = ref(null)
 | 
			
		||||
const curTab = ref('welcome')
 | 
			
		||||
const winHeight = ref(window.innerHeight)
 | 
			
		||||
const showSidebar = ref(true)
 | 
			
		||||
 | 
			
		||||
const sideWidth = computed(() => {
 | 
			
		||||
  return showSidebar.value ? 250 : 30
 | 
			
		||||
})
 | 
			
		||||
const foldIconRight = computed(() => {
 | 
			
		||||
  return showSidebar.value ? 3 : 0
 | 
			
		||||
})
 | 
			
		||||
const nodeListPaddingLeft = computed(() => {
 | 
			
		||||
  return showSidebar.value ? 20 : 5
 | 
			
		||||
})
 | 
			
		||||
const router = useRouter()
 | 
			
		||||
 | 
			
		||||
// 获取会话信息
 | 
			
		||||
httpGet("/api/admin/session").then(() => {
 | 
			
		||||
  // 加载系统配置
 | 
			
		||||
  httpGet('/api/admin/config/get?key=system').then(res => {
 | 
			
		||||
    title.value = res.data['admin_title'];
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    ElMessage.error("加载系统配置失败: " + e.message)
 | 
			
		||||
  })
 | 
			
		||||
}).catch(() => {
 | 
			
		||||
  router.push('/admin/login')
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  window.addEventListener("resize", function () {
 | 
			
		||||
    winHeight.value = window.innerHeight
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const logout = function () {
 | 
			
		||||
  httpGet("/api/admin/logout").then(() => {
 | 
			
		||||
    router.push('/admin/login')
 | 
			
		||||
  }).catch((e) => {
 | 
			
		||||
    ElMessage.error("注销失败: " + e.message);
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 添加 tab 窗口
 | 
			
		||||
const addTab = function (nav) {
 | 
			
		||||
  if (curNav.value) {
 | 
			
		||||
    curNav.value.active = false
 | 
			
		||||
  }
 | 
			
		||||
  nav.active = true
 | 
			
		||||
  curNav.value = nav;
 | 
			
		||||
  curTab.value = nav.tab;
 | 
			
		||||
  if (!arrayContains(tabs.value, nav.tab)) {
 | 
			
		||||
    this.tabs.push(nav.tab);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 切换 tab 窗口
 | 
			
		||||
const changeTab = function (name) {
 | 
			
		||||
  for (let i = 0; i < navs.value.length; i++) {
 | 
			
		||||
    let _nav = navs.value[i]
 | 
			
		||||
    if (_nav.tab === name) {
 | 
			
		||||
      curNav.value.active = false // 取消上一个 active 窗口的激活状态
 | 
			
		||||
      _nav.active = true
 | 
			
		||||
      curNav.value = _nav;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 删除 tab 窗口
 | 
			
		||||
const removeTab = function (name) {
 | 
			
		||||
  tabs.value = removeArrayItem(tabs.value, name);
 | 
			
		||||
  if (tabs.value.length === 0) {
 | 
			
		||||
    curTab.value = 'welcome';
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  for (let i = 0; i < navs.value.length; i++) {
 | 
			
		||||
    if (navs.value[i].tab === tabs.value[tabs.value.length - 1]) {
 | 
			
		||||
      addTab(navs.value[i]);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="stylus">
 | 
			
		||||
$sideBgColor = #252526;
 | 
			
		||||
$borderColor = #4676d0;
 | 
			
		||||
.admin-body {
 | 
			
		||||
  .el-aside {
 | 
			
		||||
    background-color: $sideBgColor;
 | 
			
		||||
 | 
			
		||||
    .title {
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      line-height: 60px;
 | 
			
		||||
      color: #fff;
 | 
			
		||||
      font-size: 20px;
 | 
			
		||||
      border-bottom: 2px solid #333841;
 | 
			
		||||
      display flex
 | 
			
		||||
      flex-direction row
 | 
			
		||||
 | 
			
		||||
      .logo {
 | 
			
		||||
        background-color #ffffff
 | 
			
		||||
        border-radius 50%;
 | 
			
		||||
        width 32px;
 | 
			
		||||
        height 32px;
 | 
			
		||||
        margin: 12px 5px 0 5px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .fold {
 | 
			
		||||
        cursor: pointer;
 | 
			
		||||
        position: relative;
 | 
			
		||||
        top: 2px;
 | 
			
		||||
        margin-left 10px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .title.hide {
 | 
			
		||||
      .text {
 | 
			
		||||
        display none
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .logo {
 | 
			
		||||
        display none
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .fold {
 | 
			
		||||
        margin-left 5px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .nav-list {
 | 
			
		||||
      list-style: none;
 | 
			
		||||
      position: relative;
 | 
			
		||||
      margin: 0;
 | 
			
		||||
      padding-left: 0;
 | 
			
		||||
      text-align: left;
 | 
			
		||||
 | 
			
		||||
      li {
 | 
			
		||||
        line-height: 40px;
 | 
			
		||||
        color: #ffffff;
 | 
			
		||||
        font-size: 14px;
 | 
			
		||||
        cursor: pointer;
 | 
			
		||||
        padding: 0 10px 0 10px;
 | 
			
		||||
        border-bottom: 1px dashed #333841;
 | 
			
		||||
 | 
			
		||||
        i {
 | 
			
		||||
          margin-right: 6px;
 | 
			
		||||
          position: relative;
 | 
			
		||||
          top: 1px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .delete {
 | 
			
		||||
          float: right;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      li.active {
 | 
			
		||||
        background-color: #363535
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .nav-footer {
 | 
			
		||||
      flex-direction column
 | 
			
		||||
 | 
			
		||||
      div {
 | 
			
		||||
        padding 10px 20px;
 | 
			
		||||
        font-size 14px;
 | 
			
		||||
        color #aaaaaa
 | 
			
		||||
 | 
			
		||||
        .el-link {
 | 
			
		||||
          color #aaaaaa
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .iconfont {
 | 
			
		||||
          margin-right 5px
 | 
			
		||||
          position relative
 | 
			
		||||
          top 1px
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .logout {
 | 
			
		||||
        cursor pointer
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .el-main {
 | 
			
		||||
    --el-main-padding: 0;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
 | 
			
		||||
    .main-container {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      flex-flow: column;
 | 
			
		||||
 | 
			
		||||
      .el-tabs {
 | 
			
		||||
        background: #ffffff;
 | 
			
		||||
        padding 10px 20px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus">
 | 
			
		||||
.pagination {
 | 
			
		||||
  padding-top 20px;
 | 
			
		||||
  display flex
 | 
			
		||||
  justify-content center
 | 
			
		||||
  width 100%
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.el-tabs__item {
 | 
			
		||||
  height 35px
 | 
			
		||||
  line-height 35px
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.el-tabs__content {
 | 
			
		||||
  padding-bottom 20px;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										75
									
								
								web/src/views/admin/RewardList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								web/src/views/admin/RewardList.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="container list" v-loading="loading">
 | 
			
		||||
 | 
			
		||||
    <el-row>
 | 
			
		||||
      <el-table :data="items" :row-key="row => row.id">
 | 
			
		||||
        <el-table-column prop="username" label="用户名"/>
 | 
			
		||||
        <el-table-column prop="tx_id" label="转账单号"/>
 | 
			
		||||
        <el-table-column prop="amount" label="转账金额"/>
 | 
			
		||||
 | 
			
		||||
        <el-table-column label="转账时间">
 | 
			
		||||
          <template #default="scope">
 | 
			
		||||
            <span>{{ dateFormat(scope.row['created_at']) }}</span>
 | 
			
		||||
          </template>
 | 
			
		||||
        </el-table-column>
 | 
			
		||||
 | 
			
		||||
        <el-table-column label="核销时间">
 | 
			
		||||
          <template #default="scope">
 | 
			
		||||
            <span v-if="scope.row['status']">{{ dateFormat(scope.row['updated_at']) }}</span>
 | 
			
		||||
            <el-tag v-else>未核销</el-tag>
 | 
			
		||||
          </template>
 | 
			
		||||
        </el-table-column>
 | 
			
		||||
 | 
			
		||||
      </el-table>
 | 
			
		||||
    </el-row>
 | 
			
		||||
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
import {reactive, ref} from "vue";
 | 
			
		||||
import {httpGet, httpPost} from "@/utils/http";
 | 
			
		||||
import {ElMessage} from "element-plus";
 | 
			
		||||
import {dateFormat, disabledDate, removeArrayItem} from "@/utils/libs";
 | 
			
		||||
import {Plus} from "@element-plus/icons-vue";
 | 
			
		||||
 | 
			
		||||
// 变量定义
 | 
			
		||||
const items = ref([])
 | 
			
		||||
const loading = ref(true)
 | 
			
		||||
 | 
			
		||||
// 获取数据
 | 
			
		||||
httpGet('/api/admin/reward/list').then((res) => {
 | 
			
		||||
  if (res.data) {
 | 
			
		||||
    // 初始化数据
 | 
			
		||||
    const arr = res.data;
 | 
			
		||||
    for (let i = 0; i < arr.length; i++) {
 | 
			
		||||
      arr[i].last_used_at = dateFormat(arr[i].last_used_at)
 | 
			
		||||
    }
 | 
			
		||||
    items.value = arr
 | 
			
		||||
  }
 | 
			
		||||
  loading.value = false
 | 
			
		||||
}).catch(() => {
 | 
			
		||||
  ElMessage.error("获取数据失败");
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
.list {
 | 
			
		||||
 | 
			
		||||
  .opt-box {
 | 
			
		||||
    padding-bottom: 10px;
 | 
			
		||||
    display flex;
 | 
			
		||||
    justify-content flex-end
 | 
			
		||||
 | 
			
		||||
    .el-icon {
 | 
			
		||||
      margin-right: 5px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .el-select {
 | 
			
		||||
    width: 100%
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
                @selection-change="handleSelectionChange">
 | 
			
		||||
        <el-table-column type="selection" width="38"/>
 | 
			
		||||
        <el-table-column prop="username" label="用户名"/>
 | 
			
		||||
        <el-table-column prop="mobile" label="手机号"/>
 | 
			
		||||
        <el-table-column prop="nickname" label="昵称"/>
 | 
			
		||||
        <el-table-column prop="calls" label="提问次数" width="100"/>
 | 
			
		||||
        <el-table-column label="状态" width="80">
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user