mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-09-17 16:56:38 +08:00
opt: optimize styles for invitation page
This commit is contained in:
parent
a4a1eec30b
commit
5c5210625e
@ -2,6 +2,7 @@ package handler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"chatplus/core"
|
"chatplus/core"
|
||||||
|
"chatplus/core/types"
|
||||||
"chatplus/store/model"
|
"chatplus/store/model"
|
||||||
"chatplus/store/vo"
|
"chatplus/store/vo"
|
||||||
"chatplus/utils"
|
"chatplus/utils"
|
||||||
@ -55,7 +56,36 @@ func (h *InviteHandler) Code(c *gin.Context) {
|
|||||||
// List Log 用户邀请记录
|
// List Log 用户邀请记录
|
||||||
func (h *InviteHandler) List(c *gin.Context) {
|
func (h *InviteHandler) List(c *gin.Context) {
|
||||||
|
|
||||||
resp.SUCCESS(c)
|
var data struct {
|
||||||
|
Page int `json:"page"`
|
||||||
|
PageSize int `json:"page_size"`
|
||||||
|
}
|
||||||
|
if err := c.ShouldBindJSON(&data); err != nil {
|
||||||
|
resp.ERROR(c, types.InvalidArgs)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userId := h.GetLoginUserId(c)
|
||||||
|
session := h.db.Session(&gorm.Session{}).Where("inviter_id = ?", userId)
|
||||||
|
var total int64
|
||||||
|
session.Model(&model.InviteLog{}).Count(&total)
|
||||||
|
var items []model.InviteLog
|
||||||
|
var list = make([]vo.InviteLog, 0)
|
||||||
|
offset := (data.Page - 1) * data.PageSize
|
||||||
|
res := session.Order("id DESC").Offset(offset).Limit(data.PageSize).Find(&items)
|
||||||
|
if res.Error == nil {
|
||||||
|
for _, item := range items {
|
||||||
|
var v vo.InviteLog
|
||||||
|
err := utils.CopyObject(item, &v)
|
||||||
|
if err == nil {
|
||||||
|
v.Id = item.Id
|
||||||
|
v.CreatedAt = item.CreatedAt.Unix()
|
||||||
|
list = append(list, v)
|
||||||
|
} else {
|
||||||
|
logger.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resp.SUCCESS(c, vo.NewPage(total, data.Page, data.PageSize, list))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hits 访问邀请码
|
// Hits 访问邀请码
|
||||||
|
@ -350,7 +350,7 @@ func main() {
|
|||||||
fx.Invoke(func(s *core.AppServer, h *handler.InviteHandler) {
|
fx.Invoke(func(s *core.AppServer, h *handler.InviteHandler) {
|
||||||
group := s.Engine.Group("/api/invite/")
|
group := s.Engine.Group("/api/invite/")
|
||||||
group.GET("code", h.Code)
|
group.GET("code", h.Code)
|
||||||
group.GET("list", h.List)
|
group.POST("list", h.List)
|
||||||
group.GET("hits", h.Hits)
|
group.GET("hits", h.Hits)
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
99
web/src/components/InviteList.vue
Normal file
99
web/src/components/InviteList.vue
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<template>
|
||||||
|
<div class="invite-list" v-loading="loading">
|
||||||
|
<el-row v-if="items.length > 0">
|
||||||
|
<el-table :data="items" :row-key="row => row.id" table-layout="auto" border
|
||||||
|
style="--el-table-border-color:#373C47;
|
||||||
|
--el-table-tr-bg-color:#2D323B;
|
||||||
|
--el-table-row-hover-bg-color:#373C47;
|
||||||
|
--el-table-header-bg-color:#474E5C;
|
||||||
|
--el-table-text-color:#d1d1d1">
|
||||||
|
<el-table-column prop="username" label="用户"/>
|
||||||
|
<el-table-column prop="invite_code" label="邀请码"/>
|
||||||
|
<el-table-column label="邀请奖励">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>对话:{{ scope.row['reward']['chat_calls'] }}次</span>,
|
||||||
|
<span>绘图:{{ scope.row['reward']['chat_calls'] }}次</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="注册时间">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ dateFormat(scope.row['created_at']) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-row>
|
||||||
|
<el-empty :image-size="100" v-else/>
|
||||||
|
<div class="pagination">
|
||||||
|
<el-pagination v-if="total > 0" background
|
||||||
|
layout="total,prev, pager, next"
|
||||||
|
:hide-on-single-page="true"
|
||||||
|
v-model:current-page="page"
|
||||||
|
v-model:page-size="pageSize"
|
||||||
|
@current-change="fetchData()"
|
||||||
|
:total="total"/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {onMounted, ref, watch} from "vue";
|
||||||
|
import {httpGet, httpPost} from "@/utils/http";
|
||||||
|
import {ElMessage} from "element-plus";
|
||||||
|
import {dateFormat} from "@/utils/libs";
|
||||||
|
import {DocumentCopy} from "@element-plus/icons-vue";
|
||||||
|
import Clipboard from "clipboard";
|
||||||
|
|
||||||
|
const items = ref([])
|
||||||
|
const total = ref(0)
|
||||||
|
const page = ref(1)
|
||||||
|
const pageSize = ref(10)
|
||||||
|
const loading = ref(true)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchData()
|
||||||
|
const clipboard = new Clipboard('.copy-order-no');
|
||||||
|
clipboard.on('success', () => {
|
||||||
|
ElMessage.success("复制成功!");
|
||||||
|
})
|
||||||
|
|
||||||
|
clipboard.on('error', () => {
|
||||||
|
ElMessage.error('复制失败!');
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 获取数据
|
||||||
|
const fetchData = () => {
|
||||||
|
httpPost('/api/invite/list', {page: page.value, page_size: pageSize.value}).then((res) => {
|
||||||
|
if (res.data) {
|
||||||
|
items.value = res.data.items
|
||||||
|
total.value = res.data.total
|
||||||
|
page.value = res.data.page
|
||||||
|
pageSize.value = res.data.page_size
|
||||||
|
}
|
||||||
|
loading.value = false
|
||||||
|
}).catch(e => {
|
||||||
|
ElMessage.error("获取数据失败:" + e.message);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="stylus">
|
||||||
|
.invite-list {
|
||||||
|
.pagination {
|
||||||
|
margin: 20px 0 0 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-order-no {
|
||||||
|
cursor pointer
|
||||||
|
position relative
|
||||||
|
left 6px
|
||||||
|
top 2px
|
||||||
|
color #20a0ff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="user-bill" v-loading="loading">
|
<div class="user-bill" v-loading="loading">
|
||||||
<el-row>
|
<el-row v-if="items.length > 0">
|
||||||
<el-table :data="items" :row-key="row => row.id" table-layout="auto" border
|
<el-table :data="items" :row-key="row => row.id" table-layout="auto" border
|
||||||
style="--el-table-border-color:#373C47;
|
style="--el-table-border-color:#373C47;
|
||||||
--el-table-tr-bg-color:#2D323B;
|
--el-table-tr-bg-color:#2D323B;
|
||||||
@ -31,7 +31,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
<el-empty :image-size="100" v-else/>
|
||||||
<div class="pagination">
|
<div class="pagination">
|
||||||
<el-pagination v-if="total > 0" background
|
<el-pagination v-if="total > 0" background
|
||||||
layout="total,prev, pager, next"
|
layout="total,prev, pager, next"
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
<h2>会员推广计划</h2>
|
<h2>会员推广计划</h2>
|
||||||
<div class="share-box">
|
<div class="share-box">
|
||||||
<div class="info">
|
<div class="info">
|
||||||
我们非常欢迎您把此应用分享给您身边的朋友,分享成功注册后您将获得 {{ inviteChatCalls }} 次对话额度以及
|
我们非常欢迎您把此应用分享给您身边的朋友,分享成功注册后您将获得 <strong>{{ inviteChatCalls }}</strong> 次对话额度以及
|
||||||
{{ inviteImgCalls }} 次AI绘画额度作为奖励。
|
<strong>{{ inviteImgCalls }}</strong> 次AI绘画额度作为奖励。
|
||||||
你可以保存下面的二维码或者直接复制分享您的专属推广链接发送给微信好友。
|
你可以保存下面的二维码或者直接复制分享您的专属推广链接发送给微信好友。
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -19,10 +19,66 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="invite-stats">
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="8">
|
||||||
|
<div class="item-box yellow">
|
||||||
|
<el-row :gutter="10">
|
||||||
|
<el-col :span="10">
|
||||||
|
<div class="item-icon">
|
||||||
|
<i class="iconfont icon-role"></i>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="14">
|
||||||
|
<div class="item-info">
|
||||||
|
<div class="num">{{ hits }}</div>
|
||||||
|
<div class="text">点击量</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<div class="item-box blue">
|
||||||
|
<el-row :gutter="10">
|
||||||
|
<el-col :span="10">
|
||||||
|
<div class="item-icon">
|
||||||
|
<i class="iconfont icon-order"></i>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="14">
|
||||||
|
<div class="item-info">
|
||||||
|
<div class="num">{{ regNum }}</div>
|
||||||
|
<div class="text">注册量</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<div class="item-box green">
|
||||||
|
<el-row :gutter="10">
|
||||||
|
<el-col :span="10">
|
||||||
|
<div class="item-icon">
|
||||||
|
<i class="iconfont icon-chart"></i>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="14">
|
||||||
|
<div class="item-info">
|
||||||
|
<div class="num">{{ rate }}%</div>
|
||||||
|
<div class="text">转化率</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h2>您推荐用户</h2>
|
<h2>您推荐用户</h2>
|
||||||
|
|
||||||
<div class="invite-logs">
|
<div class="invite-logs">
|
||||||
<el-empty :image-size="100"/>
|
<invite-list/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -34,17 +90,26 @@ import QRCode from "qrcode";
|
|||||||
import {httpGet} from "@/utils/http";
|
import {httpGet} from "@/utils/http";
|
||||||
import {ElMessage} from "element-plus";
|
import {ElMessage} from "element-plus";
|
||||||
import Clipboard from "clipboard";
|
import Clipboard from "clipboard";
|
||||||
|
import InviteList from "@/components/InviteList.vue";
|
||||||
|
|
||||||
const inviteURL = ref("")
|
const inviteURL = ref("")
|
||||||
const qrImg = ref("")
|
const qrImg = ref("")
|
||||||
const inviteChatCalls = ref(0)
|
const inviteChatCalls = ref(0)
|
||||||
const inviteImgCalls = ref(0)
|
const inviteImgCalls = ref(0)
|
||||||
const users = ref([])
|
const users = ref([])
|
||||||
|
const hits = ref(0)
|
||||||
|
const regNum = ref(0)
|
||||||
|
const rate = ref(0)
|
||||||
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
httpGet("/api/invite/code").then(res => {
|
httpGet("/api/invite/code").then(res => {
|
||||||
const text = `${location.protocol}//${location.host}/register?invite_code=${res.data.code}`
|
const text = `${location.protocol}//${location.host}/register?invite_code=${res.data.code}`
|
||||||
|
hits.value = res.data["hits"]
|
||||||
|
regNum.value = res.data["reg_num"]
|
||||||
|
if (hits.value > 0) {
|
||||||
|
rate.value = ((regNum.value / hits.value) * 100).toFixed(2)
|
||||||
|
}
|
||||||
QRCode.toDataURL(text, {width: 400, height: 400, margin: 2}, (error, url) => {
|
QRCode.toDataURL(text, {width: 400, height: 400, margin: 2}, (error, url) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
@ -57,6 +122,13 @@ onMounted(() => {
|
|||||||
ElMessage.error("获取邀请码失败:" + e.message)
|
ElMessage.error("获取邀请码失败:" + e.message)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
httpGet("/api/admin/config/get?key=system").then(res => {
|
||||||
|
inviteChatCalls.value = res.data["invite_chat_calls"]
|
||||||
|
inviteImgCalls.value = res.data["invite_img_calls"]
|
||||||
|
}).catch(e => {
|
||||||
|
ElMessage.error("获取系统配置失败:" + e.message)
|
||||||
|
})
|
||||||
|
|
||||||
// 复制链接
|
// 复制链接
|
||||||
const clipboard = new Clipboard('.copy-link');
|
const clipboard = new Clipboard('.copy-link');
|
||||||
clipboard.on('success', () => {
|
clipboard.on('success', () => {
|
||||||
@ -77,7 +149,7 @@ onMounted(() => {
|
|||||||
height 100vh
|
height 100vh
|
||||||
|
|
||||||
.inner {
|
.inner {
|
||||||
max-width 800px
|
max-width 1000px
|
||||||
width 100%
|
width 100%
|
||||||
color #e1e1e1
|
color #e1e1e1
|
||||||
|
|
||||||
@ -91,6 +163,10 @@ onMounted(() => {
|
|||||||
border 1px solid #444444
|
border 1px solid #444444
|
||||||
border-radius 10px
|
border-radius 10px
|
||||||
padding 10px
|
padding 10px
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color #f56c6c
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.invite-qrcode {
|
.invite-qrcode {
|
||||||
@ -113,6 +189,54 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.invite-stats {
|
||||||
|
padding 30px 10px
|
||||||
|
|
||||||
|
.item-box {
|
||||||
|
border-radius 10px
|
||||||
|
padding 0 10px
|
||||||
|
|
||||||
|
.el-col {
|
||||||
|
height 140px
|
||||||
|
display flex
|
||||||
|
align-items center
|
||||||
|
justify-content center
|
||||||
|
|
||||||
|
.iconfont {
|
||||||
|
font-size 60px
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-info {
|
||||||
|
font-size 18px
|
||||||
|
|
||||||
|
.text, .num {
|
||||||
|
padding 3px 0
|
||||||
|
text-align center
|
||||||
|
}
|
||||||
|
|
||||||
|
.num {
|
||||||
|
font-size 40px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.yellow {
|
||||||
|
background-color #ffeecc
|
||||||
|
color #D68F00
|
||||||
|
}
|
||||||
|
|
||||||
|
.blue {
|
||||||
|
background-color #D6E4FF
|
||||||
|
color #1062FE
|
||||||
|
}
|
||||||
|
|
||||||
|
.green {
|
||||||
|
background-color #E7F8EB
|
||||||
|
color #2D9F46
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user