Files
learning-system-portal/src/views/ucurrency/Index.vue
2022-10-18 11:05:59 +08:00

854 lines
26 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="u-currency">
<div class="myubi">
<div class="ubi-hear">
<h6>我的U币:{{uinfo.uCurrency}}</h6><span class="pointer" @click="dialogVisible = true">U币规则
<i class="el-icon-arrow-right"></i> </span>
<el-button icon="el-icon-document" @click="exportRecord()">导出记录</el-button>
</div>
<div style="max-height:600px;overflow-y:auto;padding-right:30px">
<div class="Ubi-hist">
<h6>U币历史记录</h6><span>最多保留近7天的记录</span>
<div style="height:290px;min-width: 350px;" ref="chart"></div>
</div>
<div v-if="uCoinRecord.length > 0">
<div class="my-Recording" v-for="(day, index) in uCoinRecord" :key="index">
<h3>{{day.dayNmae}}</h3>
<div class="Recording-info" v-for="info in day.list">
<div class="info-tit">{{info.content}}</div>
<div class="info-Gold"><img :src="`${webBaseUrl}/images/Uimg.png`" alt="">{{info.uvalue > 0? '+':''}}
{{info.uvalue}}</div>
</div>
</div>
</div>
<div v-else class="home-no-list">
<img class="img" style="width:76px;height:76px" :src="`${webBaseUrl}/images/homeWu/u-wu.png`" alt=""
srcset="">
<p class="text">最近7天你可能太忙了快开始 努力获得U币吧</p>
</div>
</div>
</div>
<div class="experience">
<div class="exp-hear">
<div class="exp-hear-text">
经验值排行榜<svg-icon style="margin-left: 5px;font-size:20px;padding-top: 4px;" icon-class="doubt"></svg-icon>
<span class="exp-hear-textbor"></span>
</div>
<div class="exp-hear-xiala">
<el-dropdown trigger="click" @command="handleCommand">
<span class="el-dropdown-link pointer">
{{name}}<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="total">累计</el-dropdown-item>
<el-dropdown-item command="weeks">本周</el-dropdown-item>
<el-dropdown-item command="months">本月</el-dropdown-item>
<el-dropdown-item command="years">本年</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
<div class="myselftext">
<div class="myranking">
我的排名 : <span> {{currentUserRankingData.rankingNo}}</span>
</div>
<div class="myexperience">
我的经验值 :
<span>{{currentUserRankingData.total || currentUserRankingData.months || currentUserRankingData.years || currentUserRankingData.weeks}}</span>
</div>
</div>
<div class="exp-bar">
<h6> {{currentUserRankingData.total || currentUserRankingData.months || currentUserRankingData.years || currentUserRankingData.weeks}}/{{current.endValue}}</h6>
<div class="exp-barbox">
<el-progress :percentage="currentUserRankingData.total*100/current.endValue
|| currentUserRankingData.weeks*100/current.endValue
|| currentUserRankingData.years*100/current.endValue
|| currentUserRankingData.months*100/current.endValue" color="#387DF7"></el-progress>
<!-- <div class="exp-bar-cont"></div> -->
</div>
<div class="exp-barname">
<span>{{current.start}}</span>
<span>{{current.end}}</span>
</div>
</div>
<div class="exp-table" style="height:550px;overflow-y:auto">
<div class="table-hear">
<div style="margin-left:5px">排名</div>
<div style="margin-left:5px">姓名</div>
<div class="bm">部门</div>
<div class="jy">经验值</div>
</div>
<div>
<div class="table-hear" style="margin-top:40px;border-bottom: 1px solid #ddd;padding-bottom:20px"
v-for="(ran,index) in rankingData" :key="ran.id">
<div class="tab-rank">
<img v-if="index == 0" :src="`${webBaseUrl}/images/rank1.png`" alt="" />
<img v-if="index == 1" :src="`${webBaseUrl}/images/rank2.png`" alt="" />
<img v-if="index == 2" :src="`${webBaseUrl}/images/rank3.png`" alt="" />
<div v-if="index > 2" style="line-height: 40px;padding-left:15px;font-size: 16px;color: #333333;">
{{index+1}}</div>
</div>
<div class="tab-name">
<author-img :avatar="ran.authorInfo.avatar" :aid="ran.authorInfo.aid" :sex="ran.authorInfo.sex">
</author-img> <span>{{ran.authorInfo.name}}</span>
</div>
<div class="bm tab-bm" style="margin-left:30px;">{{ran.authorInfo.orgInfo}}</div>
<div class="jy tab-jy">
<div v-if="cycle == 'total'" style="font-size: 18px;color: #333333;font-weight: 600;">{{ran.total}}</div>
<div v-if="cycle == 'months'" style="font-size: 18px;color: #333333;font-weight: 600;">{{ran.months}}</div>
<div v-if="cycle == 'years'" style="font-size: 18px;color: #333333;font-weight: 600;">{{ran.years}}</div>
<div v-if="cycle == 'weeks'" style="font-size: 18px;color: #333333;font-weight: 600;">{{ran.weeks}}</div>
</div>
</div>
</div>
<div v-if="currentUserRankingData.rankingNo>4" class="omit">
<div>.</div>
<div>.</div>
<div>.</div>
</div>
<div class="table-hear" style="margin-top:40px;border-bottom: 1px solid #ddd;padding-bottom:20px"
v-if="currentUserRankingData.authorInfo && currentUserRankingData.authorInfo.aid && currentUserRankingData.rankingNo>4">
<div style="color: #0059FF;line-height: 40px;padding-left:15px;font-size: 16px;" class="tab-rank">
{{currentUserRankingData.rankingNo}}</div>
<div class="tab-name">
<author-img :avatar="currentUserRankingData.authorInfo.avatar" :aid="currentUserRankingData.authorInfo.aid"
:sex="currentUserRankingData.authorInfo.sex"></author-img> <span
style="color: #0059FF;">{{currentUserRankingData.authorInfo.name}}</span>
</div>
<div class="bm tab-bm" style="margin-left:30px;color: #0059FF;">{{currentUserRankingData.authorInfo.orgInfo}}
</div>
<div class="jy tab-jy">
<div v-if="cycle == 'total'" style="font-size: 18px;color: #333333;font-weight: 600;color: #0059FF;">{{currentUserRankingData.total}}</div>
<div v-if="cycle == 'months'" style="font-size: 18px;color: #333333;font-weight: 600;color: #0059FF;">{{currentUserRankingData.months}}</div>
<div v-if="cycle == 'years'" style="font-size: 18px;color: #333333;font-weight: 600;color: #0059FF;">{{currentUserRankingData.years}}</div>
<div v-if="cycle == 'weeks'" style="font-size: 18px;color: #333333;font-weight: 600;color: #0059FF;">{{currentUserRankingData.weeks}}</div>
</div>
</div>
</div>
</div>
<el-dialog :visible.sync="dialogVisible" :show-close="false" width="716px">
<div class="dialog-box">
<div class="box-top">
<p style="font-size: 26px;font-weight: 600;margin-bottom: 4px;">U币规则</p>
<p style="font-size: 14px;line-height: 20px;">学员每日通过积分规则获得积分的上限为150积分当天达到上限后 不能通过积分规则获得积分</p>
</div>
<div style="max-height:420px;overflow-y: auto;">
<div class="box-table">
<p class="table-title portal-title-tow"><span></span>学习</p>
<el-table :data="tableData" style="">
<el-table-column prop="name" label="分类" width="180"></el-table-column>
<el-table-column prop="name" label="描述" width="180">
<template slot-scope="scope">
<p v-for="(rem,index) in scope.row.hear" :key="index">{{rem}}</p>
<p style="font-size:12px;color: #999999;" v-if="scope.row.label">{{scope.row.label}}</p>
</template>
</el-table-column>
<el-table-column align="right" label="经验值/U币">
<template slot-scope="scope">
<p style="font-size:16px;color: #999999;" v-for="(val,index) in scope.row.value" :key="index">{{val}}
</p>
</template>
</el-table-column>
<el-table-column prop="upperlimit" align="right" label="每日上限">
</el-table-column>
</el-table>
</div>
<div class="box-table">
<p class="table-title portal-title-tow"><span></span>知识贡献</p>
<el-table :data="tableList" style="">
<el-table-column prop="name" label="分类" width="180">
</el-table-column>
<el-table-column prop="name" label="描述" width="180">
<template slot-scope="scope">
<p v-for="(rem,index) in scope.row.hear" :key="index">{{rem}}</p>
</template>
</el-table-column>
<el-table-column align="right" label="经验值/U币">
<template slot-scope="scope">
<p style="font-size:16px;color: #333333;font-weight: 600;" v-for="(val,index) in scope.row.value"
:key="index">{{val}}</p>
</template>
</el-table-column>
<el-table-column prop="upperlimit" align="right" label="每日上限">
</el-table-column>
</el-table>
</div>
</div>
<div class="dialog-close" @click="dialogVisible=false">
<img style="width:86px;height:86px" :src="`${webBaseUrl}/images/homeWu/u-close.png`" alt="">
</div>
</div>
</el-dialog>
</div>
</template>
<script>
import apiStat from '@/api/phase2/stat.js';
import {
mapGetters
} from 'vuex';
import {
getUType
} from '@/utils/tools.js'
import authorImg from '@/components/Portal/authorImg.vue';
import author from '@/components/Portal/authorInfo.vue';
import apiUser from "@/api/system/user.js";
import * as echarts from 'echarts'
import {
translate,
experienceValue
} from "@/utils/tools.js";
export default {
computed: {
...mapGetters(['userInfo']),
},
components: {
authorImg,
author
},
data() {
return {
current: {
percentage: 0
},
experienceValue,
translate,
cycle: 'total',
name: '累计',
getUType,
dialogVisible: false,
tableData: [{
name: '试听学习',
hear: ['每日累计学习10分钟', '每日累计学习20分钟', '每日累计学习30分钟', '每日累计学习45分钟', '每日累计学习60分钟', ],
value: ['+10', '+20', '+30', '+40', "+50"],
upperlimit: 50
},
{
name: '案例学习',
hear: ['完成一个案例的阅读', ],
value: ['+5'],
upperlimit: 30,
label: '最低3分钟'
},
{
name: '文章学习',
hear: ['完成一个文章的阅读', ],
value: ['+5'],
upperlimit: 30,
label: '最低2分钟'
},
],
tableList: [{
name: '发布音视频课程',
hear: ['完成一个案音视频课', ],
value: ['+60'],
upperlimit: null
},
{
name: '面授课记录',
hear: ['有一个完成的面授课记录(<4h', '有一个完成的面授课记录(>=4h'],
value: ['+40', '+60'],
upperlimit: null
},
{
name: '发布文章',
hear: ['每发布1篇文章', ],
value: ['+40'],
upperlimit: null
},
{
name: '发布案例',
hear: ['每发布1篇案例', ],
value: ['+50'],
upperlimit: null
},
{
name: '发布笔记',
hear: ['每发布公开笔记1篇', ],
value: ["+5"],
upperlimit: 30
},
{
name: '发表评论',
hear: ['在课程问答案例中发表1个评论', ],
value: ['+2'],
upperlimit: 20
},
],
uCoinRecord: [],
chart: null,
currentUserRankingData: {},
rankingData: [],
uinfo: {
uCurrency: 0 // 用户累计U币
},
}
},
mounted() {
this.getList();
this.getRanking();
this.getLevel();
},
methods: {
handleCommand(e) {
this.cycle = e;
this.name = this.translate(e)
this.getRanking();
},
getRanking() {
let data = {
aid: this.userInfo.aid, // #用户id
statType: 20, // #统计类型 10学习时长 11 学习天数 20表经验值 30表u币 40表获取天数
field: this.cycle, // #统计周期 todays-当天,weeks-周,months-月,years-年 total-总计
num: 4, // #显示的条数
}
apiStat.getRanking(data).then(res => {
if (res.status == 200) {
if (res.result.currentUserRankingData) {
res.result.currentUserRankingData.authorInfo = {
aid: "",
name: "",
orgInfo: "",
avatar: "",
sex: null
}
this.getUserData([res.result.currentUserRankingData.aid], [res.result.currentUserRankingData])
this.currentUserRankingData = res.result.currentUserRankingData;
if(this.cycle == 'total'){this.current = this.experienceValue(res.result.currentUserRankingData.total);}
if(this.cycle == 'weeks'){this.current = this.experienceValue(res.result.currentUserRankingData.weeks);}
if(this.cycle == 'months'){this.current = this.experienceValue(res.result.currentUserRankingData.months);}
if(this.cycle == 'years'){this.current = this.experienceValue(res.result.currentUserRankingData.years);}
}
const ids = [];
res.result.rankingData.forEach(item => {
ids.push(item.aid)
item.authorInfo = {
aid: "",
name: "",
orgInfo: "",
avatar: "",
sex: null
}
})
this.getUserData(ids, res.result.rankingData)
this.rankingData = res.result.rankingData;
}
})
},
getUserData(ids, list) {
const noReapetIds = [...new Set(ids)];
apiUser.getByIds(noReapetIds).then(res => {
if (res.status == 200) {
list.forEach((item, index) => {
res.result.some(author => {
if (author.aid == item.aid) {
item.authorInfo = author;
return true;
} else {
return false;
}
});
});
} else {
this.$message.error(res.message);
}
});
},
exportRecord() {
let downUrl='';
let curHost=window.location.host;
console.log(window.location.host,'window.location.host');
// if(curHost=='localhost' || curHost='127.0.0.1'){
// downUrl=process.env.VUE_APP_BOE_WEB_URL+process.env.VUE_APP_CESOURCE_BASE_API+'/xboe/m/stat/usercoinrecord/export?aid=' + this.userInfo.aid;
// }else{
// //let urlPre = window.location.protocol + '//' + window.location.host;
// downUrl=process.env.VUE_APP_CESOURCE_BASE_API+'/xboe/m/stat/usercoinrecord/export?aid=' + this.userInfo.aid;
// }
downUrl=process.env.VUE_APP_BOE_WEB_URL+process.env.VUE_APP_CESOURCE_BASE_API+'/xboe/m/stat/usercoinrecord/export?aid=' + this.userInfo.aid;
const el = document.createElement('a');
el.style.display = 'none';
el.setAttribute('target', '_blank');
/**
* download的属性是HTML5新增的属性
* href属性的地址必须是非跨域的地址如果引用的是第三方的网站或者说是前后端分离的项目(调用后台的接口)这时download就会不起作用。
* 此时,如果是下载浏览器无法解析的文件,例如.exe,.xlsx..那么浏览器会自动下载,但是如果使用浏览器可以解析的文件,比如.txt,.png,.pdf....浏览器就会采取预览模式
* 所以,对于.txt,.png,.pdf等的预览功能我们就可以直接不设置download属性(前提是后端响应头的Content-Type: application/octet-stream如果为application/pdf浏览器则会判断文件为 pdf ,自动执行预览的策略)
*/
el.setAttribute('download', '我的U币记录');
el.href = downUrl;
console.log(el);
document.body.appendChild(el);
el.click();
document.body.removeChild(el);
},
initChat(chatData) {
this.chart = echarts.init(this.$refs.chart);
const option = {
tooltip: {
trigger: 'item'
},
legend: {
top: 'center',
right: 100,
orient: 'vertical',
itemWidth: 8,
itemHeight: 8,
borderRadius: '50%',
itemGap: 26,
formatter: function(name) {
let data = option.series[0].data;
let total = 0;
let tarValue = 0; //每一项值
for (let i = 0; i < data.length; i++) {
total += data[i].value;
if (data[i].name == name) {
tarValue = data[i].value;
}
}
let p = total != 0 ? Math.round((tarValue / total) * 100) + '%' : 0 + '%';
return ` ${p} ${name}`
}
},
series: [{
// name: 'name',
type: 'pie',
radius: ['50%', '40%'],
avoidLabelOverlap: false,
center: ['32%', '50%'],
itemStyle: {
borderRadius: 0,
borderColor: '#fff',
borderWidth: 2,
normal: {
color: function(colors) {
let colorList = ['#5bb9fe', '#f7b36b', '#72e5d5', '#e1e1f9'];
return colorList[colors.dataIndex];
},
}
},
label: {
show: false,
position: 'center',
},
labelLine: {
show: false
},
data: chatData,
}]
};
this.chart.setOption(option);
},
getList() {
apiStat.userCoinList(this.userInfo.aid, 7).then(res => {
if (res.status == 200) {
this.uCoinRecord = [];
for (let key in res.result.uCoinRecord) {
this.uCoinRecord.push({
dayNmae: key,
list: res.result.uCoinRecord[key]
})
}
let chatData = [];
for (let key in res.result.chatData) {
chatData.push({
value: res.result.chatData[key],
name: this.getUType(key)
})
}
this.initChat(chatData);
}
})
},
getLevel() { //获取用户累计U币
apiStat.getUserStatTotalInfo(this.userInfo.aid).then(res => {
if (res.status == 200) {
this.uinfo.uCurrency = res.result.uvalue;
}
});
},
}
}
</script>
<style lang="scss" scoped>
.u-currency {
padding: 10px 18px;
display: flex;
justify-content: space-between; overflow-x: auto;
}
.experience {
font-size: 16px;
min-width: 480px;
font-weight: 600;
color: #333333;
}
.myubi {
flex: 1;
padding-right: 30px;
}
::v-deep .el-dialog {
border-radius: 8px;
}
::v-deep .el-dialog__header {
display: none;
}
::v-deep .el-dialog__body {
padding: 0;
// ::v-deep .el-table td.el-table__cell{
// font-size: 14px;
// color: #333333;
// }
}
::v-deep .el-table__body-wrapper {
font-size: 14px;
color: #333333;
}
.dialog-box {
position: relative;
.dialog-close {
position: absolute;
left: 50%;
transform: translate(-50%);
bottom: -127px;
}
.box-top {
color: #FBA511;
padding: 26px 212px 17px 61px;
background: url('../../../public/images/homeWu/u-bg.png') no-repeat;
}
.box-table {
padding: 26px 14px 40px 66px;
.table-title {
margin-bottom: 18px;
span {
display: inline-block;
width: 6px;
height: 18px;
background: #0060FF;
border-radius: 4px;
margin-right: 10px;
}
}
}
}
.Recording-info {
margin-top: 12px;
height: 45px;
border-bottom: 1px solid #ddd;
.info-tit {
float: left;
font-size: 14px;
font-weight: 400;
color: #333333;
line-height: 40px;
}
.info-Gold {
float: right;
font-size: 18px;
color: #333333;
font-weight: 400;
line-height: 40px;
img {
width: 54px;
height: 32px;
vertical-align: middle;
}
}
}
.Ubi-hist {
margin-top: 15px;
h6 {
font-size: 16px;
font-weight: 600;
color: #333333;
margin: 0;
float: left;
}
span {
font-size: 14px;
font-weight: 600;
color: #999999;
}
}
.ubi-hear {
height: 40px;
button {
width: 140px;
height: 40px;
margin-right: 30px;
border-radius: 2px;
border: 1px solid rgba(153, 153, 153, 0.35);
float: right;
}
span {
font-size: 14px;
font-weight: 400;
color: #333333;
line-height: 40px;
}
h6 {
margin: 0;
margin-right: 18px;
line-height: 40px;
float: left;
color: #333333;
font-size: 18px;
font-weight: 600;
}
}
.omit {
padding-left: 20px;
div {
font-size: 30px;
line-height: 10px;
color: #D8D8D8;
}
}
.exp-table {
//width: 100%;
padding-left: 25px;
padding-right: 20px;
.table-hear {
display: flex;
div {
min-width: 90px;
font-size: 14px;
font-weight: 400;
color: #999999;
}
.bm {
flex: 1;
margin-left: 20px;
}
.jy {
margin-left: auto;
text-align: right;
margin-right: 0;
text-align: center;
}
}
}
.myselftext {
height: 75px;
padding: 0 25px;
//width: 100%;
display: flex;
.myranking {
flex: 1;
line-height: 75px;
font-size: 14px;
font-weight: 400;
color: #666666;
span {
color: #333;
font-weight: 600;
font-size: 18px;
}
}
.myexperience {
text-align: right;
line-height: 75px;
margin-left: auto;
font-size: 14px;
font-weight: 400;
color: #666666;
span {
color: #333;
font-weight: 600;
font-size: 18px;
}
}
}
.tab-jy {
padding-top: 10px;
div {
line-height: 28px;
width: 70px;
text-align: center;
font-size: 18px;
color: #333333;
font-weight: 600;
height: 28px;
background: #F7F8FA;
border-radius: 14px;
}
}
.tab-bm {
line-height: 40px;
}
.tab-name {
display: flex;
min-width:98px;
::v-deep .item-author {
min-width: 50px !important;
}
img {
width: 40px;
height: 40px;
vertical-align: middle;
}
span {
display: block;
margin-top: 10px;
color: #333333;
font-size: 14px;
font-weight: 600;
}
}
.tab-rank {
img {
width: 40px;
height: 40px;
}
}
.experience {
flex: 1;
.exp-hear {
//width: 100%;
height: 65px;
background: url('../../../public/images/expbg.png') no-repeat 100% / 100%;
.exp-hear-text {
float: left;
line-height: 65px;
margin-left: 25px;
font-size: 18px;
font-weight: 600;
color: #333333;
position: relative;
z-index: 888;
.exp-hear-textbor {
width: 108px;
height: 10px;
background: #9CC7FC;
border-radius: 9px;
display: inline-block;
position: absolute;
left: 0;
z-index: -1;
top: 60%;
}
}
.exp-hear-xiala {
line-height: 65px;
float: right;
margin-right: 15px;
}
}
.exp-bar {
//width: 100%;
h6 {
font-size: 14px;
color: #666666;
font-weight: 600;
margin: 0;
margin-left: 50px;
}
.exp-barname {
//width: 100%;
padding: 20px 35px;
display: flex;
span {
flex: 1;
}
}
.exp-barbox {
//width: 100%;
height: 8px;
// background: #ECF1FE;
border-radius: 6px;
margin-left: 25px;
margin-top: 3px;
position: relative;
z-index: 1;
::v-deep .el-progress__text {
display: none;
}
.exp-bar-cont {
width: 230px;
height: 6px;
background: #0059FF;
border-radius: 6px;
opacity: 0.56;
position: absolute;
left: 0;
z-index: 999;
}
}
}
}
</style>