Browse Source

提交代码,老拉新活动。

Signed-off-by: zouap <zouap@pcl.ac.cn>
tags/v1.22.9.2^2
zouap 3 years ago
parent
commit
3bc06f7b6c
24 changed files with 1165 additions and 30 deletions
  1. +1
    -0
      models/models.go
  2. +90
    -0
      models/user_invitation.go
  3. +8
    -0
      options/locale/locale_en-US.ini
  4. +8
    -0
      options/locale/locale_zh-CN.ini
  5. +15
    -0
      routers/home.go
  6. +293
    -0
      routers/repo/user_invitation.go
  7. +107
    -0
      routers/user/Invitation.go
  8. +28
    -24
      routers/user/auth.go
  9. +4
    -0
      templates/base/head_navbar.tmpl
  10. +4
    -0
      templates/base/head_navbar_fluid.tmpl
  11. +4
    -0
      templates/base/head_navbar_home.tmpl
  12. +4
    -0
      templates/base/head_navbar_pro.tmpl
  13. +38
    -0
      templates/user/auth/signup_inner.tmpl
  14. +5
    -0
      templates/user/dashboard/repolist.tmpl
  15. +32
    -0
      templates/user/profile.tmpl
  16. +140
    -0
      web_src/js/features/ad.js
  17. +1
    -0
      web_src/js/index.js
  18. +15
    -5
      web_src/js/standalone/phoneverify.js
  19. +2
    -1
      web_src/less/standalone/_phoneverify.less
  20. +11
    -0
      web_src/vuepages/apis/modules/userinvite.js
  21. +14
    -0
      web_src/vuepages/langs/config/en-US.js
  22. +14
    -0
      web_src/vuepages/langs/config/zh-CN.js
  23. +310
    -0
      web_src/vuepages/pages/user/invite/index.vue
  24. +17
    -0
      web_src/vuepages/pages/user/invite/vp-user-invite.js

+ 1
- 0
models/models.go View File

@@ -170,6 +170,7 @@ func init() {
new(UserLoginLog),
new(UserMetrics),
new(UserAnalysisPara),
new(Invitation),
)

gonicNames := []string{"SSL", "UID"}


+ 90
- 0
models/user_invitation.go View File

@@ -0,0 +1,90 @@
package models

import (
"fmt"

"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
)

// Follow represents relations of user and his/her followers.
type Invitation struct {
ID int64 `xorm:"pk autoincr"`
SrcUserID int64 `xorm:"NOT NULL DEFAULT 0"`
UserID int64 `xorm:"NOT NULL DEFAULT 0"`
Phone string `xorm:"INDEX"`
Avatar string `xorm:"-"`
Name string `xorm:"-"`
InvitationUserNum int `xorm:"-"`
IsActive bool `xorm:"-"`
CreatedUnix timeutil.TimeStamp `xorm:"created"`
}

func QueryInvitaionByPhone(phone string) []*Invitation {
statictisSess := xStatistic.NewSession()
defer statictisSess.Close()
cond := "phone ='" + phone + "'"
invitationList := make([]*Invitation, 0)
if err := statictisSess.Table(new(Invitation)).Where(cond).
Find(&invitationList); err != nil {
return nil
} else {
return invitationList
}
}

func GetAllUserName() map[int64]string {
sess := x.NewSession()
defer sess.Close()
sess.Select("id,name").Table("user")
userList := make([]*User, 0)
reMap := make(map[int64]string)
sess.Find(&userList)
for _, user := range userList {
reMap[user.ID] = user.Name
}
return reMap
}

func QueryInvitaionPage(start int, pageSize int) ([]*Invitation, int64) {
statictisSess := xStatistic.NewSession()
defer statictisSess.Close()
//cond := "created_unix >=" + fmt.Sprint(startTime) + " and created_unix <=" + fmt.Sprint(endTime)

allCount, err := statictisSess.Count(new(Invitation))
if err != nil {
log.Info("query error." + err.Error())
return nil, 0
}
invitationList := make([]*Invitation, 0)
if err := statictisSess.Table(new(Invitation)).OrderBy("created_unix desc").Limit(pageSize, start).
Find(&invitationList); err != nil {
return nil, 0
}
return invitationList, allCount
}

func InsertInvitaion(invitationUser *Invitation) error {
statictisSess := xStatistic.NewSession()
defer statictisSess.Close()
_, err := statictisSess.Insert(invitationUser)
return err
}

func QueryInvitaionBySrcUserId(srcUserId int64, start int, pageSize int) ([]*Invitation, int64) {
statictisSess := xStatistic.NewSession()
defer statictisSess.Close()
cond := "src_user_id =" + fmt.Sprint(srcUserId)
allCount, err := statictisSess.Where(cond).Count(new(Invitation))
if err != nil {
log.Info("query error." + err.Error())
return nil, 0
}
invitationList := make([]*Invitation, 0)

if err := statictisSess.Table(new(Invitation)).Where(cond).OrderBy("created_unix desc").Limit(pageSize, start).
Find(&invitationList); err != nil {
return nil, 0
}
return invitationList, allCount
}

+ 8
- 0
options/locale/locale_en-US.ini View File

@@ -69,6 +69,10 @@ your_dashboard = Dashboard
your_profile = Profile
your_starred = Starred
your_settings = Settings
invite_friends = Invite Friends
your_friend=Your friend
invite_you_to_join_the_OpenI_AI_Collaboration_Platform_and_enjoy_abundant_free_computing_resources=invite you to join the OpenI AI Collaboration Platform and enjoy abundant free computing resources!
recommender=Recommender

all = All
sources = Sources
@@ -531,6 +535,10 @@ form.name_reserved = The username '%s' is reserved.
form.name_pattern_not_allowed = The pattern '%s' is not allowed in a username.
form.name_chars_not_allowed = User name '%s' contains invalid characters.

static.invitationdetailsheetname=User Invitation Detail
static.invitationNum=User Invitation Count
static.invitationsheetname=User Invitation
static.srcUserId=Recommended User ID
static.sheetname=User Analysis
static.id=ID
static.name=User Name


+ 8
- 0
options/locale/locale_zh-CN.ini View File

@@ -69,6 +69,10 @@ your_dashboard=个人中心
your_profile=个人信息
your_starred=已点赞
your_settings=设置
invite_friends=邀请好友
your_friend=您的好友
invite_you_to_join_the_OpenI_AI_Collaboration_Platform_and_enjoy_abundant_free_computing_resources=邀请你加入启智社区AI协作平台,畅享充沛的免费算力资源!
recommender=推荐人

all=所有
sources=自建
@@ -536,7 +540,11 @@ form.name_reserved='%s' 用户名被保留。
form.name_pattern_not_allowed=用户名中不允许使用 "%s"。
form.name_chars_not_allowed=用户名 '%s' 包含无效字符。

static.invitationdetailsheetname=用户邀请详细数据
static.invitationNum=邀请用户数
static.sheetname=用户分析
static.srcUserId=推荐用户ID
static.invitationsheetname=用户邀请分析
static.id=ID
static.name=用户名
static.codemergecount=PR数


+ 15
- 0
routers/home.go View File

@@ -106,6 +106,11 @@ func Dashboard(ctx *context.Context) {
log.Info("set image info=" + pictureInfo[0]["url"])
ctx.Data["image_url"] = pictureInfo[0]["url"]
ctx.Data["image_link"] = pictureInfo[0]["image_link"]

if len(pictureInfo) > 1 {
ctx.Data["invite_image_url"] = pictureInfo[1]["url"]
ctx.Data["invite_image_link"] = pictureInfo[1]["image_link"]
}
}
if !ctx.User.IsActive && setting.Service.RegisterEmailConfirm {
ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
@@ -728,6 +733,16 @@ func getImageInfo(filename string) ([]map[string]string, error) {
return imageInfo, nil
}

func GetMapInfo(ctx *context.Context) {
filename := ctx.Query("filename")
url := setting.RecommentRepoAddr + filename
result, err := repository.RecommendContentFromPromote(url)
if err != nil {
log.Info("get file error:" + err.Error())
}
ctx.JSON(http.StatusOK, result)
}

func GetRankUser(index string) ([]map[string]interface{}, error) {
url := setting.RecommentRepoAddr + "user_rank_" + index
result, err := repository.RecommendFromPromote(url)


+ 293
- 0
routers/repo/user_invitation.go View File

@@ -0,0 +1,293 @@
package repo

import (
"fmt"
"net/http"
"net/url"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"github.com/360EntSecGroup-Skylar/excelize/v2"
)

func QueryInvitationCurrentMonth(ctx *context.Context) {
// userName := ctx.Query("userName")
// currentTimeNow := time.Now()
// pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, currentTimeNow.Location())
// pageStartTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), 1, 0, 0, 0, 0, currentTimeNow.Location())

//queryUserDataPage(ctx, "public.user_business_analysis_current_month", new(models.UserBusinessAnalysisCurrentMonth))
//_, count := models.QueryUserStaticDataByTableName(1, 1, "public.user_business_analysis_current_month", new(models.UserBusinessAnalysisCurrentMonth), userName, 1)

queryDataFromStaticTable(ctx, "public.user_business_analysis_current_month", new(models.UserBusinessAnalysisCurrentMonth))
}

func getInvitationExcelHeader(ctx *context.Context) map[string]string {
excelHeader := make([]string, 0)
excelHeader = append(excelHeader, ctx.Tr("user.static.id"))
excelHeader = append(excelHeader, ctx.Tr("user.static.name"))
excelHeader = append(excelHeader, ctx.Tr("user.static.invitationNum"))
excelHeader = append(excelHeader, ctx.Tr("user.static.phone"))
excelHeader = append(excelHeader, ctx.Tr("user.static.registdate"))

excelHeaderMap := make(map[string]string, 0)
var i byte
i = 0
for _, value := range excelHeader {
excelColumn := getColumn(i) + fmt.Sprint(1)
excelHeaderMap[excelColumn] = value
i++
}
return excelHeaderMap
}

func getInvitationDetailExcelHeader(ctx *context.Context) map[string]string {
excelHeader := make([]string, 0)
excelHeader = append(excelHeader, ctx.Tr("user.static.id"))
excelHeader = append(excelHeader, ctx.Tr("user.static.name"))
excelHeader = append(excelHeader, ctx.Tr("user.static.srcUserId"))
excelHeader = append(excelHeader, ctx.Tr("user.static.phone"))
excelHeader = append(excelHeader, ctx.Tr("user.static.registdate"))

excelHeaderMap := make(map[string]string, 0)
var i byte
i = 0
for _, value := range excelHeader {
excelColumn := getColumn(i) + fmt.Sprint(1)
excelHeaderMap[excelColumn] = value
i++
}
return excelHeaderMap
}

func writeInvitationExcel(row int, xlsx *excelize.File, sheetName string, userRecord *models.UserBusinessAnalysisAll) {
rows := fmt.Sprint(row)
var tmp byte
tmp = 0
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.ID)
tmp = tmp + 1
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.Name)
tmp = tmp + 1

xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.InvitationUserNum)
tmp = tmp + 1

xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.Phone)
tmp = tmp + 1

formatTime := userRecord.RegistDate.Format("2006-01-02 15:04:05")
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, formatTime[0:len(formatTime)-3])

}

func writeInvitationDetailExcel(row int, xlsx *excelize.File, sheetName string, userRecord *models.Invitation) {
rows := fmt.Sprint(row)
var tmp byte
tmp = 0
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.UserID)
tmp = tmp + 1
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.Name)
tmp = tmp + 1

xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.SrcUserID)
tmp = tmp + 1

xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userRecord.Phone)
tmp = tmp + 1

formatTime := userRecord.CreatedUnix.Format("2006-01-02 15:04:05")
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, formatTime[0:len(formatTime)-3])

}

func DownloadInvitationDetail(ctx *context.Context) {
xlsx := excelize.NewFile()
sheetName := ctx.Tr("user.static.invitationdetailsheetname")
index := xlsx.NewSheet(sheetName)
xlsx.DeleteSheet("Sheet1")
excelHeader := getInvitationDetailExcelHeader(ctx)
for k, v := range excelHeader {
//设置单元格的值
xlsx.SetCellValue(sheetName, k, v)
}
userNameMap := models.GetAllUserName()
_, count := models.QueryInvitaionPage(1, 1)
var indexTotal int64
indexTotal = 0
row := 1
for {
re, _ := models.QueryInvitaionPage(int(indexTotal), PAGE_SIZE)
log.Info("return count=" + fmt.Sprint(count))
for _, userRecord := range re {
row++
userRecord.Name = userNameMap[userRecord.UserID]
writeInvitationDetailExcel(row, xlsx, sheetName, userRecord)
}
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
}
//设置默认打开的表单
xlsx.SetActiveSheet(index)
filename := sheetName + ".xlsx"
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(filename))
ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
if _, err := xlsx.WriteTo(ctx.Resp); err != nil {
log.Info("writer exel error." + err.Error())
}
}

func queryDataFromStaticTable(ctx *context.Context, tableName string, queryObj interface{}) {
page, pageSize := getPageInfo(ctx)
userName := ctx.Query("userName")
IsReturnFile := ctx.QueryBool("IsReturnFile")

if IsReturnFile {
//writer exec file.
xlsx := excelize.NewFile()
sheetName := ctx.Tr("user.static.invitationsheetname")
index := xlsx.NewSheet(sheetName)
xlsx.DeleteSheet("Sheet1")
excelHeader := getInvitationExcelHeader(ctx)
for k, v := range excelHeader {
//设置单元格的值
xlsx.SetCellValue(sheetName, k, v)
}
_, count := models.QueryUserInvitationDataByTableName(1, 1, tableName, queryObj, "", 1)
var indexTotal int64
indexTotal = 0
row := 1
for {
re, _ := models.QueryUserInvitationDataByTableName(int(indexTotal), PAGE_SIZE, tableName, queryObj, "", 1)
log.Info("return count=" + fmt.Sprint(count))
for _, userRecord := range re {
row++
writeInvitationExcel(row, xlsx, sheetName, userRecord)
}
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
}
//设置默认打开的表单
xlsx.SetActiveSheet(index)
filename := sheetName + "_" + ctx.Tr("user.static."+tableName) + ".xlsx"
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(filename))
ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
if _, err := xlsx.WriteTo(ctx.Resp); err != nil {
log.Info("writer exel error." + err.Error())
}
} else {
resultRecord, count := models.QueryUserInvitationDataByTableName((page-1)*pageSize, pageSize, tableName, queryObj, userName, 1)
result := make([]models.Invitation, 0)
for _, record := range resultRecord {
invi := models.Invitation{
SrcUserID: record.ID,
Name: record.Name,
InvitationUserNum: record.InvitationUserNum,
Phone: record.Phone,
CreatedUnix: record.RegistDate,
}
result = append(result, invi)
}
mapInterface := make(map[string]interface{})
mapInterface["data"] = result
mapInterface["count"] = count
ctx.JSON(http.StatusOK, mapInterface)
}
}

func QueryInvitationCurrentWeek(ctx *context.Context) {
// currentTimeNow := time.Now()
// offset := int(time.Monday - currentTimeNow.Weekday())
// if offset > 0 {
// offset = -6
// }
// pageStartTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, offset)
// pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, currentTimeNow.Location())
// queryData(ctx, pageStartTime.Unix(), pageEndTime.Unix())
queryDataFromStaticTable(ctx, "public.user_business_analysis_current_week", new(models.UserBusinessAnalysisCurrentWeek))
}

func QueryInvitationLastWeek(ctx *context.Context) {
// currentTimeNow := time.Now()
// offset := int(time.Monday - currentTimeNow.Weekday())
// if offset > 0 {
// offset = -6
// }
// pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, offset)
// pageStartTime := pageEndTime.AddDate(0, 0, -7)
// queryData(ctx, pageStartTime.Unix(), pageEndTime.Unix())

queryDataFromStaticTable(ctx, "public.user_business_analysis_last_week", new(models.UserBusinessAnalysisLastWeek))
}

func QueryInvitationCurrentYear(ctx *context.Context) {
// currentTimeNow := time.Now()
// pageStartTime := time.Date(currentTimeNow.Year(), 1, 1, 0, 0, 0, 0, currentTimeNow.Location())
// pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, currentTimeNow.Location())
// queryData(ctx, pageStartTime.Unix(), pageEndTime.Unix())

queryDataFromStaticTable(ctx, "public.user_business_analysis_current_year", new(models.UserBusinessAnalysisCurrentYear))
}

func QueryInvitationLast30Day(ctx *context.Context) {
// currentTimeNow := time.Now()
// pageStartTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, -30)
// pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, currentTimeNow.Location())
// queryData(ctx, pageStartTime.Unix(), pageEndTime.Unix())

queryDataFromStaticTable(ctx, "public.user_business_analysis_last30_day", new(models.UserBusinessAnalysisLast30Day))
}

func QueryInvitationLastMonth(ctx *context.Context) {
// currentTimeNow := time.Now()
// thisMonth := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), 1, 0, 0, 0, 0, currentTimeNow.Location())
// pageStartTime := thisMonth.AddDate(0, -1, 0)
// pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), 1, 23, 59, 59, 0, currentTimeNow.Location()).AddDate(0, 0, -1)
// queryData(ctx, pageStartTime.Unix(), pageEndTime.Unix())

queryDataFromStaticTable(ctx, "public.user_business_analysis_last_month", new(models.UserBusinessAnalysisLastMonth))
}

func QueryInvitationYesterday(ctx *context.Context) {
// currentTimeNow := time.Now().AddDate(0, 0, -1)
// pageStartTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local)
// pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location())
// queryData(ctx, pageStartTime.Unix(), pageEndTime.Unix())

queryDataFromStaticTable(ctx, "public.user_business_analysis_yesterday", new(models.UserBusinessAnalysisYesterday))
}

func QueryInvitationAll(ctx *context.Context) {
// currentTimeNow := time.Now()
// pageStartTime := time.Date(2022, 8, 5, 0, 0, 0, 0, currentTimeNow.Location())
// pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, currentTimeNow.Location())
// queryData(ctx, pageStartTime.Unix(), pageEndTime.Unix())

queryDataFromStaticTable(ctx, "public.user_business_analysis_all", new(models.UserBusinessAnalysisAll))
}

// func queryData(ctx *context.Context, startTime int64, endTime int64) {
// page, pageSize := getPageInfo(ctx)
// result, count := models.QueryInvitaionPage(startTime, endTime, (page-1)*pageSize, pageSize)
// mapInterface := make(map[string]interface{})
// mapInterface["data"] = result
// mapInterface["count"] = count
// ctx.JSON(http.StatusOK, mapInterface)
// }

func getPageInfo(ctx *context.Context) (int, int) {
page := ctx.QueryInt("page")
if page <= 0 {
page = 1
}
pageSize := ctx.QueryInt("pageSize")
if pageSize <= 0 {
pageSize = setting.UI.IssuePagingNum
}
return page, pageSize
}

+ 107
- 0
routers/user/Invitation.go View File

@@ -0,0 +1,107 @@
package user

import (
"errors"
"strconv"
"strings"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/repository"
)

const (
tplInvitation base.TplName = "user/settings/invite"
)

func GetInvitaionCode(ctx *context.Context) {
page := ctx.QueryInt("page")
if page <= 0 {
page = 1
}
pageSize := ctx.QueryInt("pageSize")
if pageSize <= 0 {
pageSize = setting.UI.IssuePagingNum
}

url := setting.RecommentRepoAddr + "invitaion_page"
result, err := repository.RecommendFromPromote(url)
resultJsonMap := make(map[string]interface{}, 0)
if err == nil {
for _, strLine := range result {
tmpIndex := strings.Index(strLine, "=")
if tmpIndex != -1 {
key := strLine[0:tmpIndex]
value := strLine[tmpIndex+1:]
resultJsonMap[key] = value
}
}
}

if ctx.IsSigned {
resultJsonMap["invitation_code"] = getInvitaionCode(ctx)
re, count := models.QueryInvitaionBySrcUserId(ctx.User.ID, (page-1)*pageSize, pageSize)
for _, record := range re {
tmpUser, err := models.GetUserByID(record.UserID)
if err == nil {
record.Avatar = strings.TrimRight(setting.AppSubURL, "/") + "/user/avatar/" + tmpUser.Name + "/" + strconv.Itoa(-1)
record.IsActive = tmpUser.IsActive
record.Name = tmpUser.Name
}
}
resultJsonMap["invitation_users"] = re
resultJsonMap["invitation_users_count"] = count
}

ctx.JSON(200, resultJsonMap)
}

func InviationTpl(ctx *context.Context) {
ctx.HTML(200, tplInvitation)
}

func RegisteUserByInvitaionCode(invitationcode string, newUserId int64) error {
user := parseInvitaionCode(invitationcode)
if user == nil {
return errors.New("The invitated user not existed.")
}

if user.PhoneNumber != "" {
re := models.QueryInvitaionByPhone(user.PhoneNumber)
if re != nil {
if len(re) > 0 {
log.Info("The phone has been invitated. so ingore it.")
return errors.New("The phone has been invitated.")
}
}
} else {
log.Info("the phone number is null. user name=" + user.Name)
}

invitation := &models.Invitation{
SrcUserID: user.ID,
UserID: newUserId,
Phone: user.PhoneNumber,
}

err := models.InsertInvitaion(invitation)
if err != nil {
log.Info("insert error," + err.Error())
}
return err
}

func getInvitaionCode(ctx *context.Context) string {
return ctx.User.Name
}

func parseInvitaionCode(invitationcode string) *models.User {
user, err := models.GetUserByName(invitationcode)
if err == nil {
return user
}
return nil
}

+ 28
- 24
routers/user/auth.go View File

@@ -8,11 +8,12 @@ package user
import (
"errors"
"fmt"
"github.com/gomodule/redigo/redis"
"net/http"
"strconv"
"strings"

"github.com/gomodule/redigo/redis"

"code.gitea.io/gitea/modules/slideimage"

phoneService "code.gitea.io/gitea/services/phone"
@@ -352,18 +353,17 @@ func SignInPostCommon(ctx *context.Context, form auth.SignInForm) {
ctx.Redirect(setting.AppSubURL + "/user/two_factor")
}


func SignInCloudBrainPost(ctx *context.Context, form auth.SignInForm) {
ctx.Data["PageIsCloudBrainLogin"] = true
ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login/cloud_brain"
SignInPostCommon(ctx,form)
SignInPostCommon(ctx, form)
}

// SignInPost response for sign in request
func SignInPost(ctx *context.Context, form auth.SignInForm) {
ctx.Data["PageIsLogin"] = true
ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login"
SignInPostCommon(ctx,form)
SignInPostCommon(ctx, form)
}

// TwoFactor shows the user a two-factor authentication page.
@@ -1264,9 +1264,9 @@ func SignUp(ctx *context.Context) {
// SignUpPost response for sign up information submission
func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterForm) {
ctx.Data["Title"] = ctx.Tr("sign_up")
invitationCode := ctx.Query("invitation_code")
ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/sign_up"
ctx.Data["invitationCode"] = invitationCode
ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha
ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL
ctx.Data["CaptchaType"] = setting.Service.CaptchaType
@@ -1366,6 +1366,11 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo
}
log.Trace("Account created: %s", u.Name, ctx.Data["MsgID"])

log.Info("enter here, and form.InvitaionCode =" + invitationCode)
if invitationCode != "" {
RegisteUserByInvitaionCode(invitationCode, u.ID)
}

err := models.AddEmailAddress(&models.EmailAddress{
UID: u.ID,
Email: form.Email,
@@ -1919,7 +1924,7 @@ func SendVerifyCode(ctx *context.Context, slideImage *slideimage.SlideImage, for
return
}

if form.Mode==0 { //注册
if form.Mode == 0 { //注册

if has {
ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.already_register")))
@@ -1935,32 +1940,31 @@ func SendVerifyCode(ctx *context.Context, slideImage *slideimage.SlideImage, for

} else {
//修改手机号 mode=2 绑定手机
u, err := models.GetUserByPhoneNumber(phoneNumber)
if err != nil && !models.IsErrUserNotExist(err) {
log.Warn("sql err", err)
ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.query_err")))
return
}

if u != nil {
u, err := models.GetUserByPhoneNumber(phoneNumber)
if err != nil && !models.IsErrUserNotExist(err) {
log.Warn("sql err", err)
ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.query_err")))
return
}

if u.ID == ctx.User.ID { //没有修改手机号
ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.not_modify")))
return
} else { //修改的手机已经被别的用户注册
ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.already_register")))
return
}
if u != nil {

if u.ID == ctx.User.ID { //没有修改手机号
ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.not_modify")))
return
} else { //修改的手机已经被别的用户注册
ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.already_register")))
return
}
}

}
}

redisConn := labelmsg.Get()
defer redisConn.Close()

sendTimes, err := phoneService.GetPhoneNumberSendTimes(redisConn, phoneNumber)
if err != nil && err!=redis.ErrNil {
if err != nil && err != redis.ErrNil {
log.Warn("redis err", err)
ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("phone.query_err")))
return


+ 4
- 0
templates/base/head_navbar.tmpl View File

@@ -180,6 +180,10 @@
</i>
{{.i18n.Tr "custom.Platform_Tutorial"}}
</a>
<a class="item" href="{{AppSubUrl}}/user/invitation_tpl">
<i class="icon users"></i>
{{.i18n.Tr "invite_friends"}}
</a>
{{if .IsAdmin}}
<div class="divider"></div>



+ 4
- 0
templates/base/head_navbar_fluid.tmpl View File

@@ -177,6 +177,10 @@
</svg>
</i>
{{.i18n.Tr "custom.Platform_Tutorial"}}
</a>
<a class="item" href="{{AppSubUrl}}/user/invitation_tpl">
<i class="icon users"></i>
{{.i18n.Tr "invite_friends"}}
</a>
{{if .IsAdmin}}
<div class="divider"></div>


+ 4
- 0
templates/base/head_navbar_home.tmpl View File

@@ -160,6 +160,10 @@
</i>
{{.i18n.Tr "custom.Platform_Tutorial"}}
</a>
<a class="item" href="{{AppSubUrl}}/user/invitation_tpl">
<i class="icon users"></i>
{{.i18n.Tr "invite_friends"}}
</a>
{{if .IsAdmin}}
<div class="divider"></div>



+ 4
- 0
templates/base/head_navbar_pro.tmpl View File

@@ -181,6 +181,10 @@
</i>
{{.i18n.Tr "custom.Platform_Tutorial"}}
</a>
<a class="item" href="{{AppSubUrl}}/user/invitation_tpl">
<i class="icon users"></i>
{{.i18n.Tr "invite_friends"}}
</a>
{{if .IsAdmin}}
<div class="divider"></div>



+ 38
- 0
templates/user/auth/signup_inner.tmpl View File

@@ -35,6 +35,9 @@
{{if .DisableRegistration}}
<p>{{.i18n.Tr "auth.disable_register_prompt"}}</p>
{{else}}
<div class="field invitation_tips" style="font-weight:400;font-size:14px;color:rgba(250,140,22,1);{{if not .invitationCode}}display:none;{{end}}">
<span>{{.i18n.Tr "your_friend"}} <span class="__invitation_code__">{{.invitationCode}}</span> {{.i18n.Tr "invite_you_to_join_the_OpenI_AI_Collaboration_Platform_and_enjoy_abundant_free_computing_resources"}}</span>
</div>
<div class="field {{if and (.Err_UserName) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister))}}error{{end}}">
<input id="user_name" name="user_name" value="{{.user_name}}" placeholder="{{.i18n.Tr "username"}}" autofocus required>
</div>
@@ -71,6 +74,16 @@
{{template "user/auth/phone_verify" .}}
</div>
{{end}}
<div class="field">
<div style="display:flex;">
<div style="display:flex;align-items:center;">
<span>{{.i18n.Tr "recommender"}}</span>
</div>
<input style="flex:1;margin-left:12px;" id="invitation_code" name="invitation_code" value="{{.invitationCode}}" {{if .invitationCode}}readonly="true"{{end}} autocomplete="off" />
</div>
</div>

<div class="field">
<div class="ui checkbox">
<input name="agree" type="checkbox" tabindex="0" class="hidden" {{if .agree}}checked{{end}}><label>{{.i18n.Tr "use_and_privacy_agree" "/home/term" "/home/privacy" | Safe}}</label>
@@ -94,3 +107,28 @@
</div>
</div>
</div>
<script>
; (function() {
var getUrlParams = function() {
var url = window.location.search;
var index = url.indexOf('?');
var obj = {};
if (index !== -1) {
var str = url.substr(1);
var arr = str.split('&');
for (var i = 0, iLen = arr.length; i < iLen; i++) {
var list = arr[i].split('=');
obj[list[0]] = list[1];
}
}
return obj;
};
var sharedUser = getUrlParams()['sharedUser'];
if (sharedUser) {
setTimeout(function() {
$('.invitation_tips').show().find('.__invitation_code__').text(sharedUser);
$('input#invitation_code').val(sharedUser).attr('readonly', true);
}, 20);
}
})();
</script>

+ 5
- 0
templates/user/dashboard/repolist.tmpl View File

@@ -18,6 +18,11 @@
v-cloak
>
<div>
{{if .invite_image_url}}
<div style="height:60px;">
<a href="{{.invite_image_link}}" target="_blank"><img src="{{.invite_image_url}}" style="width:100%;height:100%" /></a>
</div>
{{end}}
<div v-if="!isOrganization" class="ui two item tabable menu">
<a :class="{item: true, active: tab === 'repos'}" @click="changeTab('repos')">{{.i18n.Tr "repository"}}</a>
<a :class="{item: true, active: tab === 'organizations'}" @click="changeTab('organizations')">{{.i18n.Tr "organization"}}</a>


+ 32
- 0
templates/user/profile.tmpl View File

@@ -48,6 +48,38 @@
</li>
{{end}}
{{end}}
{{if and .IsSigned (eq .SignedUserName .Owner.Name)}}
<li>
{{svg "octicon-clock" 16}} {{.i18n.Tr "user.join_on"}} {{.Owner.CreatedUnix.FormatShort}}
<div class=__ad_profile_c__ style="margin-top:6px;height:50px;display:none;">
<a class="__ad_profile__" href="" target="_blank"><img src="" style="width:100%;height:100%" /></a>
</div>
<script>
;(function(){
document.addEventListener("DOMContentLoaded", function() {
$.ajax({
type: "GET",
url: "/dashboard/invitation",
dataType: "json",
data: { filename: 'ad-profile.json' },
success: function (res) {
try {
var data = JSON.parse(res);
$('.__ad_profile__').attr('href', data.url).find('img').attr('src', data.src);
$('.__ad_profile_c__').show();
} catch (err) {
console.log(err);
}
},
error: function (err) {
console.log(err);
}
});
});
})();
</script>
</li>
{{end}}
<li>{{svg "octicon-clock" 16}} {{.i18n.Tr "user.join_on"}} {{.Owner.CreatedUnix.FormatShort}}</li>
{{if and .Orgs .HasOrgsVisible}}


+ 140
- 0
web_src/js/features/ad.js View File

@@ -0,0 +1,140 @@
; (function () {
/*const adList = [
{
"width": 144,
"height": 108,
"pos": {
"left": 50,
"bottom": 50
},
"src": "https://git.openi.org.cn/OpenIOSSG/promote/raw/branch/master/imgs/invitation/pic-01.png",
"url": "/user/invitation_tpl",
"show": true
},
{
"width": 144,
"height": 108,
"pos": {
"right": 50,
"bottom": 50
},
"src": "https://git.openi.org.cn/OpenIOSSG/promote/raw/branch/master/imgs/invitation/pic-01.png",
"url": "/user/invitation_tpl",
"show": false
}
];*/
const exceptPages = [
// '/user/invitation_tpl'
];

function initAd() {
$.ajax({
type: "GET",
url: "/dashboard/invitation",
dataType: "json",
data: { filename: 'ad-pop-up.json' },
success: function (res) {
try {
var data = JSON.parse(res);
createAd(data);
} catch (err) {
console.log(err);
}
},
error: function (err) {
console.log(err);
}
});
}

function createAd(adList) {
const adInfoStr = window.localStorage.getItem('ads') || '{}';
let adInfoObj = JSON.parse(adInfoStr);
const today = new Date();
const timeTodayEnd = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1).getTime();
const now = Date.now();
const expTime = now + 4 * 60 * 60 * 1000;
if (!adInfoObj.expires || adInfoObj.expires <= now) {
adInfoObj = {
expires: Math.min(timeTodayEnd, expTime),
};
}
for (var i = 0, iLen = adList.length; i < iLen; i++) {
var adI = adList[i];
if (adI.show === false) continue;
var showOr = adInfoObj[i] === false ? false : true;
adInfoObj[i] = showOr;
if (!showOr) continue;
var adEl = $(`<div class="__ad_c__" _id="${i}" style="position:fixed;z-index:99999999;
width:${adI.width}px;height:${adI.height}px;
left:${adI.pos.left !== undefined ? adI.pos.left + 'px' : ''};
top:${adI.pos.top !== undefined ? adI.pos.top + 'px' : ''};
right:${adI.pos.right !== undefined ? adI.pos.right + 'px' : ''};
bottom:${adI.pos.bottom !== undefined ? adI.pos.bottom + 'px' : ''};">
<a style="" href="${adI.url}" target="_blank">
<img style="height:100%;width:100%;" src="${adI.src}" />
</a>
<div class="__ad_close_c__" style="position:absolute;top:6px;right:6px;">
<i class="ri-close-circle-line __ad_close__" style="color:white;font-size:18px;cursor:pointer;"></i>
</div>
</div>`);
adEl.data('data', adI);
$('body').append(adEl);
}
window.localStorage.setItem('ads', JSON.stringify(adInfoObj));
}

function initAdEvent() {
$('body').on('click', '.__ad_c__ .__ad_close__', function () {
var self = $(this);
var adEl = self.closest('.__ad_c__');
var adId = adEl.attr('_id');
const adInfoStr = window.localStorage.getItem('ads') || '{}';
const adInfoObj = JSON.parse(adInfoStr);
adInfoObj[adId] = false;
window.localStorage.setItem('ads', JSON.stringify(adInfoObj));
adEl.remove();
});
var scrollTopOld = $(document).scrollTop();
var timeHandler = null;
$(window).scroll(function (e) {
var scrollTop = $(document).scrollTop();
var offSet = scrollTop - scrollTopOld;
scrollTopOld = scrollTop;
timeHandler && clearTimeout(timeHandler);
$('.__ad_c__').each(function (_, item) {
var self = $(item);
var adData = self.data('data');
if (adData.pos.bottom !== undefined) {
self.animate({ bottom: adData.pos.bottom + offSet + 'px' }, 0);
}
if (adData.pos.top !== undefined) {
self.animate({ top: adData.pos.top - offSet + 'px' }, 0);
}
})
timeHandler = setTimeout(function () {
$('.__ad_c__').each(function (_, item) {
var self = $(item);
var adData = self.data('data');
if (adData.pos.bottom !== undefined) {
self.animate({ bottom: adData.pos.bottom + 'px' }, 0);
}
if (adData.pos.top !== undefined) {
self.animate({ top: adData.pos.top + 'px' }, 0);
}
})
}, 20);
});
}

setTimeout(function () {
if (!$('meta[name="_uid"]').length) { // 未登录,不显示
window.localStorage.removeItem('ads');
return;
}
var pathName = window.location.pathname;
if (exceptPages.indexOf(pathName) > -1) return; // 排除页,不显示
initAd();
initAdEvent();
}, 0);
})();

+ 1
- 0
web_src/js/index.js View File

@@ -52,6 +52,7 @@ import router from "./router/index.js";
import { Message } from "element-ui";

import { i18nVue } from "./features/i18nVue.js";
import './features/ad.js';

Vue.use(ElementUI);
Vue.prototype.$axios = axios;


+ 15
- 5
web_src/js/standalone/phoneverify.js View File

@@ -77,7 +77,7 @@
});

function mouseMove(e) {
var _clientX = e.clientX;
var _clientX = e.clientX !== undefined ? e.clientX : e.targetTouches[0].clientX;
var offset = _clientX - clientX;
var triggerEl = self.dom.find('.slide-trigger');
var triggerWidth = triggerEl.width();
@@ -99,6 +99,8 @@
function mouseUp(e) {
$(document).off('mousemove', mouseMove);
$(document).off('mouseup', mouseUp);
$(document).off('touchmove', mouseMove);
$(document).off('touchend', mouseUp);
self.isMoving = false;
$.ajax({
url: '/verifySlideImage',
@@ -106,7 +108,7 @@
dataType: 'json',
data: {
slide_id: self.imgID,
x: parseInt(self.dom.find('.slide-image-small').position().left)
x: parseInt(self.dom.find('.slide-image-small').position().left / self.dom.find('.slide-image-big').attr('scale'))
},
success: function (res) {
if (res && res.Code === 0) {
@@ -138,13 +140,18 @@
});
}

this.dom.find('.slide-trigger').on('mousedown', function (e) {
function mouseDown(e) {
if (self.verifySucess) return;
clientX = e.clientX;
clientX = e.clientX !== undefined ? e.clientX : e.targetTouches[0].clientX;
oLeft = $(this).position().left;
$(document).on('mousemove', mouseMove);
$(document).on('mouseup', mouseUp);
});
$(document).on('touchmove', mouseMove);
$(document).on('touchend', mouseUp);
}

this.dom.find('.slide-trigger').on('mousedown', mouseDown);
this.dom.find('.slide-trigger').on('touchstart', mouseDown);

this.dom.find('.verify-code-send-btn').on('click', function () {
if (!self.canSendCode) return;
@@ -199,6 +206,7 @@
self.dom.find('.slide-bar-wrap').css('display', 'flex');
self.dom.find('.verify-code-c').css('display', 'flex');
self.dom.find('.modify-phone-number').hide();
self.refreshImages();
});
};

@@ -210,6 +218,8 @@
this.imgID = '';
this.dom.find('.slide-bar').removeClass('sucess error').css('width', '30px');
this.dom.find('.slide-trigger').removeClass('sucess error').css('left', '0px');
var scale = this.dom.find('.slide-bar-bg').width() / 391;
this.dom.find('.slide-image-big').css('transform', `scale(${scale})`).attr('scale', scale);
this.dom.find('.slide-trigger .icon').hide();
this.dom.find('.slide-trigger .icon.arrow').show();
this.dom.find('.slide-txt').show();


+ 2
- 1
web_src/less/standalone/_phoneverify.less View File

@@ -174,10 +174,11 @@
width: 391px;
height: 196px;
top: 36px;
left: 0;
left: 1px;
border-radius: 2px;
z-index: 100;
display: none;
transform-origin: 0 0;
}

.__phone-verify-code .slide-bar-c .slide-image-small {


+ 11
- 0
web_src/vuepages/apis/modules/userinvite.js View File

@@ -0,0 +1,11 @@
import service from '../service';

// 邀请好友页面数据
export const getUserInvitationCode = (params) => { // page pageSize
return service({
url: '/user/invitation_code',
method: 'get',
params: params,
data: {},
});
}

+ 14
- 0
web_src/vuepages/langs/config/en-US.js View File

@@ -129,6 +129,7 @@ const en = {
shareMem: 'Share Memory',
unitPrice: 'Unit Price',
point_hr: 'Point/hr',
free: 'Free',
onShelfConfirm: 'Are you sure to on shelf the resources specification?',
offShelfConfirm: 'Are you sure to off shelf the resources specification?',
onShelfCode1001: 'On shelf failed, the resources queues not available.',
@@ -157,6 +158,19 @@ const en = {
available: 'Available',
notAvailable: 'Not Available',
},
user: {
inviteFriends: 'Invite Friends',
inviteFriendsTips: 'Copy QR code or invite registration link to share with friends',
clickToViewTheEventDetails: 'Click to view the event details',
copyRegistrationInvitationLink: 'Copy registration invitation link',
recommender: 'Recommender: ',
invitedFriends: 'Invited friends',
registrationTime: 'Registration time',
theSharedContentHasBeenCopiedToTheClipboard: 'The shared content has been copied to the clipboard',
copyError: 'Copy error',
Activated: 'Activated',
notActive: 'Not active',
},
}

export default en;

+ 14
- 0
web_src/vuepages/langs/config/zh-CN.js View File

@@ -129,6 +129,7 @@ const zh = {
shareMem: '共享内存',
unitPrice: '单价',
point_hr: '积分/时',
free: '免费',
onShelfConfirm: '请确认上架该规格?',
offShelfConfirm: '请确认下架该规格?',
onShelfCode1001: '上架失败,资源池(队列)不可用。',
@@ -157,6 +158,19 @@ const zh = {
available: '可用',
notAvailable: '不可用',
},
user: {
inviteFriends: '邀请好友',
inviteFriendsTips: '复制二维码或者邀请注册链接分享给好友',
clickToViewTheEventDetails: '点击查看活动详情',
copyRegistrationInvitationLink: '复制注册邀请链接',
recommender: '推荐人:',
invitedFriends: '已邀请好友',
registrationTime: '注册时间',
theSharedContentHasBeenCopiedToTheClipboard: '分享内容已复制到剪切板',
copyError: '复制错误',
Activated: '已激活',
notActive: '未激活',
},
}

export default zh;

+ 310
- 0
web_src/vuepages/pages/user/invite/index.vue View File

@@ -0,0 +1,310 @@
<template>
<div class="ui container">
<div class="title">
<div class="title-1"><span>{{ $t('user.inviteFriends') }}</span></div>
<div class="title-2"><span>{{ $t('user.inviteFriendsTips') }}</span></div>
</div>
<div class="content-1">
<div class="img-c">
<img class="img" :src="bannerImg" />
<div class="txt">{{ bannerTitle }}</div>
</div>
<div class="descr">
<span>{{ pageLinkDesc }}</span>
<a :href="pageLink" target="_blank">{{ $t('user.clickToViewTheEventDetails') }}</a>
</div>
</div>
<div class="content-2">
<div class="txt-c">
<div class="txt-1">
<span>{{ pageOpeniDesc }}</span>
</div>
<div class="txt-2"><span>{{ invitationLink + invitationCode }}</span></div>
<div class="txt-3"><span>{{ $t('user.recommender') }}</span><span>{{ invitationCode }}</span></div>
<el-button class="__copy_link_btn__" type="primary">{{ $t('user.copyRegistrationInvitationLink') }}</el-button>
</div>
<div class="qr-code">
<div id="__qr-code__" style="width:120px;height:120px;"></div>
</div>
</div>
<div class="table-container">
<div>
<el-table border :data="tableData" style="width:100%" v-loading="loading" stripe>
<el-table-column prop="ID" :label="$t('user.invitedFriends')" align="left" header-align="center">
<template slot-scope="scope">
<div style="display:flex;align-items:center;padding-left:20px;">
<img :src="scope.row.avatarSrc" alt="" style="height:45px;width:45px;margin-right:10px;" />
<a :href="scope.row.userLink" style="font-weight:500;font-size:15px;">{{ scope.row.userName }}</a>
</div>
</template>
</el-table-column>
<el-table-column prop="statusStr" :label="$t('status')" align="center" header-align="center">
<template slot-scope="scope">
<span :style="{ color: scope.row.statusColor }">{{ scope.row.statusStr }}</span>
</template>
</el-table-column>
<el-table-column prop="regTime" :label="$t('user.registrationTime')" align="center" header-align="center">
</el-table-column>
<template slot="empty">
<span style="font-size: 12px">{{
loading ? $t('loading') : $t('noData')
}}</span>
</template>
</el-table>
</div>
<div class="__r_p_pagination">
<div style="margin-top: 2rem">
<div class="center">
<el-pagination background @current-change="currentChange" :current-page="pageInfo.curpage"
:page-sizes="pageInfo.pageSizes" :page-size="pageInfo.pageSize"
layout="total, sizes, prev, pager, next, jumper" :total="pageInfo.total">
</el-pagination>
</div>
</div>
</div>
</div>
</div>
</template>

<script>
import Clipboard from 'clipboard';
import QRCode from 'qrcodejs2';
import { formatDate } from 'element-ui/lib/utils/date-util';
import { getUserInvitationCode } from '~/apis/modules/userinvite';

export default {
data() {
return {
bannerImg: '',
bannerTitle: '',
pageLink: '',
pageLinkDesc: '',
invitationLink: window.origin + '/user/sign_up?sharedUser=',
invitationCode: '',
pageOpeniDesc: '',

loading: false,
tableData: [],
pageInfo: {
curpage: 1,
pageSize: 10,
pageSizes: [10],
total: 0,
},
};
},
components: {},
methods: {
initCopy() {
const clipboard = new Clipboard('.__copy_link_btn__', {
text: () => {
return this.invitationLink + this.invitationCode;
},
});
clipboard.on('success', (e) => {
this.$message({
type: 'success',
message: this.$t('user.theSharedContentHasBeenCopiedToTheClipboard')
});
});
clipboard.on('error', (e) => {
this.$message({
type: 'error',
message: this.$t('user.copyError')
});
});
},
transRowData(item) {
return {
userName: item.Name,
avatarSrc: item.Avatar,
userLink: window.origin + '/' + item.Name,
statusStr: item.IsActive ? this.$t('user.Activated') : this.$t('user.notActive'),
statusColor: item.IsActive ? 'rgb(82, 196, 26)' : 'rgb(245, 34, 45)',
regTime: formatDate(new Date(item.CreatedUnix * 1000), 'yyyy-MM-dd HH:mm:ss'),
}
},
initData() {
getUserInvitationCode({ page: this.pageInfo.curpage, pageSize: this.pageInfo.pageSize }).then(res => {
res = res.data;
if (res) {
this.bannerImg = res.page_banner_img;
this.bannerTitle = res.page_banner_title;
this.pageLink = res.page_link;
this.pageLinkDesc = res.page_link_desc;
this.invitationCode = res.invitation_code;
this.pageOpeniDesc = res.page_openi_desc;
this.tableData = (res.invitation_users || []).map((item, index) => {
return this.transRowData(item);
});
this.pageInfo.total = res.invitation_users_count;
const qrCode = new QRCode("__qr-code__", {
text: this.invitationLink + this.invitationCode,
width: 120,
height: 120,
colorDark: '#000000',
colorLight: '#ffffff',
correctLevel: QRCode.CorrectLevel.H
});
}
}).catch(err => {
console.log(err);
});
},
getTableData() {
const params = {
page: this.pageInfo.curpage,
pageSize: this.pageInfo.pageSize,
};
this.loading = true;
getUserInvitationCode(params).then(res => {
this.loading = false;
res = res.data;
const data = (res.invitation_users || []).map((item, index) => {
return this.transRowData(item);
});
this.tableData = data;
this.pageInfo.total = res.invitation_users_count;
}).catch(err => {
console.log(err);
this.loading = false;
});
},
currentChange(val) {
this.pageInfo.curpage = val;
this.getTableData();
},
},
mounted() {
this.initData();
this.initCopy();
},
beforeDestroy() {
},
};
</script>

<style scoped lang="less">
.title {
margin-top: 15px;
margin-bottom: 15px;

.title-1 {
font-weight: 500;
font-size: 20px;
color: rgba(16, 16, 16, 1);
margin-bottom: 10px;
}

.title-2 {
font-weight: 400;
font-size: 14px;
color: rgba(136, 136, 136, 1);
}
}

.content-1 {
margin-bottom: 32px;

.img-c {
height: 80px;
position: relative;

.img {
width: 100%;
height: 100%;
}

.txt {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
line-height: 80px;
padding-left: 25px;
font-weight: 500;
font-size: 24px;
color: rgb(255, 255, 255);
}
}

.descr {
font-weight: 300;
font-size: 16px;
color: rgb(16, 16, 16);
padding: 25px;
border-left: 1px solid rgba(0, 0, 0, 0.1);
border-right: 1px solid rgba(0, 0, 0, 0.1);
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 0px 0px 4px 4px;
}
}

.content-2 {
display: flex;
background-color: rgb(228, 242, 255);
border-color: rgb(228, 242, 255);
border-width: 1px;
border-style: solid;
border-radius: 5px;
padding: 25px;
margin-bottom: 32px;

.txt-c {
flex: 1;
font-weight: 300;
font-size: 16px;
color: rgb(16, 16, 16);

span {
line-height: 24px;
}

div {
margin-bottom: 6px;
}

.txt-3 {
margin-bottom: 15px;
}
}

.qr-code {
width: 150px;
display: flex;
flex-direction: column;
align-items: end;
}
}

.table-container {
margin-bottom: 16px;

/deep/ .el-table__header {
th {
background: rgb(245, 245, 246);
font-size: 12px;
color: rgb(36, 36, 36);
}
}

/deep/ .el-table__body {
td {
font-size: 12px;
}
}

.op-btn {
cursor: pointer;
font-size: 12px;
color: rgb(25, 103, 252);
margin: 0 5px;
}
}

.center {
display: flex;
justify-content: center;
}
</style>

+ 17
- 0
web_src/vuepages/pages/user/invite/vp-user-invite.js View File

@@ -0,0 +1,17 @@
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import localeEn from 'element-ui/lib/locale/lang/en';
import localeZh from 'element-ui/lib/locale/lang/zh-CN';
import { i18n, lang } from '~/langs';
import App from './index.vue';

Vue.use(ElementUI, {
locale: lang === 'zh-CN' ? localeZh : localeEn,
size: 'small',
});

new Vue({
i18n,
render: (h) => h(App),
}).$mount('#__vue-root');

Loading…
Cancel
Save