@@ -69,6 +69,7 @@ your_dashboard = Dashboard | |||
your_profile = Profile | |||
your_starred = Starred | |||
your_settings = Settings | |||
invite_friends = Invite Friends | |||
all = All | |||
sources = Sources | |||
@@ -69,6 +69,7 @@ your_dashboard=个人中心 | |||
your_profile=个人信息 | |||
your_starred=已点赞 | |||
your_settings=设置 | |||
invite_friends=邀请好友 | |||
all=所有 | |||
sources=自建 | |||
@@ -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> | |||
@@ -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> | |||
@@ -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> | |||
@@ -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> | |||
@@ -35,6 +35,9 @@ | |||
{{if .DisableRegistration}} | |||
<p>{{.i18n.Tr "auth.disable_register_prompt"}}</p> | |||
{{else}} | |||
<div class="field" style="font-weight:400;font-size:14px;color:rgba(250,140,22,1);"> | |||
<span>您的好友 <span>Itx003</span> 邀请你加入启智社区AI协作平台,畅享充沛的免费算力资源!</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>推荐人</span> | |||
</div> | |||
<input style="flex:1;margin-left:12px;" id="shared_user" name="shared_user" value="{{.password}}" 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> | |||
@@ -18,6 +18,9 @@ | |||
v-cloak | |||
> | |||
<div> | |||
<div style="height:60px;"> | |||
<a href="/user/invitation_tpl"><img src="/img/ad/ad02.png" style="width:100%;height:100%" /></a> | |||
</div> | |||
<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> | |||
@@ -48,6 +48,12 @@ | |||
</li> | |||
{{end}} | |||
{{end}} | |||
<li> | |||
{{svg "octicon-clock" 16}} {{.i18n.Tr "user.join_on"}} {{.Owner.CreatedUnix.FormatShort}} | |||
<div style="margin-top:6px;height:50px;"> | |||
<a href="/user/invitation_tpl"><img src="/img/ad/ad02.png" style="width:100%;height:100%" /></a> | |||
</div> | |||
</li> | |||
<li>{{svg "octicon-clock" 16}} {{.i18n.Tr "user.join_on"}} {{.Owner.CreatedUnix.FormatShort}}</li> | |||
{{if and .Orgs .HasOrgsVisible}} | |||
@@ -0,0 +1,7 @@ | |||
{{template "base/head" .}} | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-user-invite.css?v={{MD5 AppVer}}" /> | |||
<div class="user settings invite"> | |||
<div id="__vue-root"></div> | |||
</div> | |||
<script src="{{StaticUrlPrefix}}/js/vp-user-invite.js?v={{MD5 AppVer}}"></script> | |||
{{template "base/footer" .}} |
@@ -0,0 +1,87 @@ | |||
; (function () { | |||
const adList = [{ | |||
id: 1, | |||
pos: { | |||
left: 50, | |||
bottom: 50, | |||
}, | |||
src: '/img/ad/ad01.png', | |||
url: '/user/invitation_tpl', | |||
width: 144, | |||
height: 108, | |||
}/*, { | |||
id: 2, | |||
pos: { | |||
right: 50, | |||
bottom: 50, | |||
}, | |||
src: '/img/ad/ad01.png', | |||
url: '/user/invitation_tpl', | |||
width: 144, | |||
height: 108, | |||
}*/]; | |||
function createAd(adList) { | |||
const adInfoStr = window.localStorage.getItem('ads') || '{}'; | |||
let adInfoObj = JSON.parse(adInfoStr); | |||
const today = new Date(); | |||
const timeEnd = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1).getTime(); | |||
const now = Date.now(); | |||
if (!adInfoObj.expires || adInfoObj.expires <= now) { | |||
adInfoObj = { | |||
expires: timeEnd, | |||
}; | |||
} | |||
for (var i = 0, iLen = adList.length; i < iLen; i++) { | |||
var adI = adList[i]; | |||
var showOr = adInfoObj[adI.id] === false ? false : true; | |||
adInfoObj[adI.id] = showOr; | |||
if (!showOr) continue; | |||
var adEl = $(`<div class="__ad_c__" _id="${adI.id}" 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>`); | |||
$('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__').animate({ bottom: 50 + offSet + 'px' }, 0); | |||
timeHandler = setTimeout(function () { | |||
$('.__ad_c__').animate({ bottom: 50 + 'px' }, 0); | |||
}, 20); | |||
}); | |||
} | |||
setTimeout(function () { | |||
createAd(adList); | |||
initAdEvent(); | |||
}, 0); | |||
})(); |
@@ -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; | |||
@@ -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(); | |||
@@ -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 { | |||
@@ -0,0 +1,11 @@ | |||
import service from '../service'; | |||
// 邀请好友页面数据 | |||
export const getUserInvitationCode = () => { | |||
return service({ | |||
url: '/user/invitation_code', | |||
method: 'get', | |||
params: {}, | |||
data: {}, | |||
}); | |||
} |
@@ -0,0 +1,279 @@ | |||
<template> | |||
<div class="ui container"> | |||
<div class="title"> | |||
<div class="title-1"><span>邀请好友</span></div> | |||
<div class="title-2"><span>复制二维码或者邀请注册链接分享给好友</span></div> | |||
</div> | |||
<div class="content-1"> | |||
<div class="img-c"> | |||
<img class="img" src="/img/ad/ad03.jpg" /> | |||
<div class="txt">邀请好友来启智,用免费算力还能赚奖金!</div> | |||
</div> | |||
<div class="descr"> | |||
<span>新一期的开源打榜活动,每邀请一名好友注册并激活,就可以获得5打榜积分。快快邀请更多好友帮你冲击榜单吧~ </span> | |||
<a>点击查看活动详情</a> | |||
</div> | |||
</div> | |||
<div class="content-2"> | |||
<div class="txt-c"> | |||
<div class="txt-1"> | |||
<span>启智AI协作平台是启智社区面向AI开发者提供的一站式AI开发协作平台,提供了代码托管、数据集管理、基于异构计算资源的模型调试与训练等功能。目前已经与鹏城云脑、中国算力网(C²NET)一期打通,免费提供丰富算力资源,支撑大家完成AI开发任务。</span> | |||
</div> | |||
<div class="txt-2"><span>{{ sharedLink }}</span></div> | |||
<div class="txt-3"><span>推荐人:</span><span>{{ sharedUser }}</span></div> | |||
<el-button class="__copy_link_btn__" type="primary">复制注册邀请链接</el-button> | |||
</div> | |||
<div class="qr-code"> | |||
<img src="" alt="" style="width:120px;height:120px;"> | |||
</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="已邀请好友" align="left" header-align="center"> | |||
<template slot-scope="scope"> | |||
<div style="display:flex;align-items:center;padding-left:20px;"> | |||
<img src="" 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="状态" 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="注册时间" 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 { formatDate } from 'element-ui/lib/utils/date-util'; | |||
import Clipboard from 'clipboard'; | |||
export default { | |||
data() { | |||
return { | |||
sharedLink: 'https://git.openi.org.cn/user/sign_up?sharedUser=Openihu', | |||
sharedUser: 'Openihu', | |||
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.sharedLink; | |||
}, | |||
}) | |||
clipboard.on('success', (e) => { | |||
this.$message({ | |||
type: 'success', | |||
message: '分享内容已复制到剪切板' | |||
}); | |||
}); | |||
}, | |||
getTableData() { | |||
const data = new Array(10).fill(0).map((item, index) => { | |||
const status = Math.random() > 0.5 ? '1' : '2'; | |||
return { | |||
userName: 'userName-' + index + '-' + Math.random().toFixed(2), | |||
userLink: 'userLink-' + index + '-' + Math.random().toFixed(2), | |||
status: status, | |||
statusStr: status == '1' ? '已激活' : '未激活', | |||
statusColor: status == '1' ? 'rgb(82, 196, 26)' : 'rgb(245, 34, 45)', | |||
regTime: 'regTime' + index + Math.random().toFixed(2), | |||
} | |||
}); | |||
this.tableData = data; | |||
return; | |||
const params = { | |||
page: this.pageInfo.curpage, | |||
pagesize: this.pageInfo.pageSize, | |||
}; | |||
this.loading = true; | |||
getResSceneList(params).then(res => { | |||
this.loading = false; | |||
res = res.data; | |||
if (res.Code === 0) { | |||
const list = res.Data.List; | |||
const data = list.map((item) => { | |||
return { | |||
} | |||
}); | |||
this.tableData = data; | |||
this.pageInfo.total = res.Data.TotalSize; | |||
} | |||
}).catch(err => { | |||
console.log(err); | |||
this.loading = false; | |||
}); | |||
}, | |||
currentChange(val) { | |||
this.pageInfo.curpage = val; | |||
this.getTableData(); | |||
}, | |||
}, | |||
mounted() { | |||
this.initCopy(); | |||
this.getTableData(); | |||
}, | |||
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> |
@@ -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'); |