提交 610f306d authored 作者: pengxiaohui's avatar pengxiaohui

feat: 用户分析模块、首页、作品展示

上级 6d54fcb3
<template>
<div class="btn" :style="{ left: attrs.left, top: attrs.top }">
<button>{{attrs.title || ''}}</button>
</div>
</template>
<script>
export default {
props: {
attrs: {
type: Object,
default() {
return {}
}
}
}
}
</script>
<style scoped>
.btn{
position:absolute;
left:0;
top:0;
}
button{
display: inline-block;
line-height: 1;
white-space: nowrap;
cursor: pointer;
background: #60A797;
border: 1px solid #a7a7a7;
color: #fff;
-webkit-appearance: none;
text-align: center;
box-sizing: border-box;
outline: none;
margin: 0;
transition: .1s;
font-weight: 500;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
font-size: 14px;
line-height:32px;
height:32px;
width:120px;
border-radius: 16px;
}
button:hover{
background:rgba(96,167,151, .8);
}
</style>
<template>
<div class="popup" v-show="visible">
<div class="popup-container">
<p>你好呀~<br>欢迎来到金融产品数字化营销实训系统!<br>首先,请选择你的身份角色吧。</p>
<ul>
<li class="item" v-for="item in roleList" :key="item.id">
<img :src="item.icon">
<p>
<el-radio v-model="roleSelected" :label="item.id">{{item.label}}</el-radio>
</p>
</li>
</ul>
<div style="text-align:center;margin-top:25px;">
<el-button type="primary" size="small" round @click="handleSelect"> 选好了 </el-button>
</div>
</div>
<div class="overlay"></div>
</div>
</template>
<script>
import role1 from '@/assets/images/role_1.png'
import role2 from '@/assets/images/role_2.png'
import role3 from '@/assets/images/role_3.png'
import role4 from '@/assets/images/role_4.png'
export default {
props: {
visible: {
type: Boolean,
default: false
}
},
data() {
return {
roleList: [
{ label: '我是产品分析员', icon: role1, id: '1' },
{ label: '我是用户分析员', icon: role2, id: '2' },
{ label: '我是营销专员', icon: role3, id: '3' },
{ label: '我是团队组长', icon: role4, id: '4' }
],
roleSelected: ''
}
},
methods: {
handleSelect() {
this.$emit('roleSelect', this.roleSelected)
}
}
}
</script>
<style scoped>
.overlay{
position:fixed;
left:0;
top:0;
right:0;
bottom:0;
z-index:1999;
background:rgba(0, 0, 0, .5);
}
.popup-container{
position:fixed;
left:50%;
top:50%;
transform:translate(-50%, -50%);
z-index:2000;
width:735px;
height:462px;
border-radius:10px;
box-shadow: 0 1px 3px rgb(0 0 0 / 30%);
background:#fff;
background-size:313px;
}
.popup-container>p{
padding:36px 0 36px 48px;
font-size:18px;
color:#333;
line-height:24px;
}
.popup-container ul{
display: flex;
}
.popup-container ul li{
width:25%;
text-align:center;
position:relative;
padding-top:200px;
}
.popup-container ul li img{
position:absolute;
left:50%;
top:0;
transform: translateX(-50%);
}
</style>
<template>
<div>
<codemirror class="code" v-model="code"></codemirror>
</div>
</template>
<script>
export default {
data() {
return {
code: ''
}
}
}
</script>
<style scoped>
.code ::v-deep.CodeMirror {
height: 398px;
}
</style>
<template>
<div class="echart">
<div id="myChart" :style="{width: '600px', height: '300px'}"></div>
</div>
</template>
<script>
// 引入基本模板
import * as echarts from 'echarts'
export default {
data() {
return {}
},
mounted() {
this.drawLine()
},
methods: {
drawLine() {
// 基于准备好的dom,初始化echarts实例
const myChart = echarts.init(document.getElementById('myChart'))
// 绘制图表
myChart.setOption({
title: { text: '年龄分布' },
tooltip: {},
legend: {
data: ['基金', '全网分布', '平均温度']
},
xAxis: {
data: ['≤19', '20-29', '30-39', '40-49', '≥50']
},
yAxis: [
{
type: 'value',
name: '温度',
position: 'left',
axisLine: {
show: true,
lineStyle: {
color: '#333'
}
},
axisLabel: {
formatter: '{value} %'
}
}
],
series: [
{
name: '基金',
type: 'bar',
barWidth: '30%',
data: [13, 28, 46, 23, 20],
itemStyle: {
normal: {
color: '#68B8A4'
}
}
},
{
name: '全网分布',
type: 'bar',
barWidth: '30%',
data: [8, 12, 30, 15, 9],
itemStyle: {
normal: {
color: '#63C7E3'
}
}
}
]
})
}
}
}
</script>
<style scoped>
.echart{
background:#fff;
padding:50px;
margin-top:50px;
}
</style>
import httpRequest from '@/utils/axios'
/** 获取用户分析多选题 */
export function getQuestions() {
return httpRequest.get('/api/finance/api/v1/analysis-users/multiple-questions')
}
\ No newline at end of file
<template>
<div class="answer-list">
<div class="answer-item" v-for="(item, index) in list" :key="index" @click="handleClick(item)">
<!-- <span v-if="!multiple">{{item.selection[0].label}}</span> -->
<!-- <ul v-else>
<li v-for="(it, idx) in item.selection" :key="idx">{{it.label}}</li>
</ul> -->
<template v-if="!multiple">
<span>{{ item.selection[0] ? item.selection[0].label : ''}}</span>
</template>
<template v-else>
<el-tag v-show="item.selection.includes(it)" size="small" v-for="(it, idx) in item.options" :key="idx">{{it.label}}</el-tag>
</template>
</div>
<!-- <div class="answer-item">双皮奶</div> -->
</div>
</template>
<script>
export default {
props: {
list: {
type: Array,
default() {
return []
}
},
multiple: {
type: Boolean,
default: false
}
},
data() {
return {}
},
created() {
console.log(this.list)
},
methods: {
handleClick(item) {
this.$emit('select', item)
}
}
}
</script>
<style scoped>
.answer-list{
display:flex;
/* justify-content:space-around; */
flex-wrap:wrap;
padding:20px 0;
}
.answer-item{
border-radius: 4px;
border: 1px solid #c3e3db;
box-sizing: border-box;
background: #f0f8f6;
color: #68b8a4;
display: inline-block;
font-size: inherit;
min-width:225px;
min-height: 36px;
line-height: 34px;
outline: none;
padding: 0 10px;
margin:0 8px 15px 7px;
transition: border-color .2s cubic-bezier(.645,.045,.355,1);
cursor:pointer;
}
.answer-item-inner{
height:34px;
vertical-align: top;
}
.el-tag{
margin-right:10px;
margin-top:-5px;
vertical-align: middle;
}
</style>
<template>
<div class="echart-bar" id="myChart"></div>
</template>
<script>
import * as echarts from 'echarts'
export default {
props: {
value: {
type: Object,
default() {
return {}
}
}
},
data() {
return {
options: {
title: { text: '年龄分布' },
tooltip: {},
// legend: {
// data: ['基金', '全网分布', '平均温度']
// },
grid: {
top: '20%',
bottom: 90
},
xAxis: {
data: ['≤19', '20-29', '30-39', '40-49', '≥50'],
axisLabel: {
rotate: 45
}
},
yAxis: [
{
type: 'value',
name: '百分比',
position: 'left',
axisLine: {
show: true,
lineStyle: {
color: '#333'
}
},
axisLabel: {
formatter: '{value} %'
}
}
],
series: [
{
name: '基金',
type: 'bar',
barWidth: '50%',
data: [],
itemStyle: {
normal: {
color: '#68B8A4'
}
}
}
]
},
echart: null
}
},
watch: {
value: {
handler(v) {
if (v.id) {
console.log(v.options)
this.options.xAxis.data = v.options.map(item => item.label)
this.$nextTick(() => {
this.echart.setOption(this.options)
})
this.fetchEchartsData()
}
},
immediate: true
}
},
mounted() {
this.echart = echarts.init(document.getElementById('myChart'))
},
methods: {
drawerEchartBar() {
myChart.setOption(this.options)
},
fetchEchartsData() {
window.setTimeout(() => {
this.options.series[0].data = [13, 28, 46, 23, 20]
this.echart.setOption(this.options)
}, 1000)
}
}
}
</script>
<style scoped>
.echart-bar{
width:100%;
height:100%;
}
</style>
\ No newline at end of file
<template>
<div class="multiple-choice">
<p class="title" v-if="choice.title">{{choice.index}}{{choice.title}}</p>
<ul class="options">
<li :class="{ active: selection.includes(item) }" v-for="item in choice.options" :key="item.value" @click="handleSelect(item)">{{item.label}}</li>
</ul>
<div class="btn-bar">
<div>
<slot name="btn-prev" />
</div>
<div>
<slot name="btn-center" />
</div>
<div>
<slot name="btn-next" />
</div>
</div>
</div>
</template>
<script>
export default {
props: {
choice: {
type: Object,
default () {
return {}
}
},
multiple: {
type: Boolean,
default: false
}
},
data() {
return {
selection: []
}
},
watch: {
choice: {
handler(nv) {
if (nv.id) {
this.selection = nv.selection
}
},
immediate: true
}
},
methods: {
handleSelect(item) {
if (this.selection.includes(item)) {
const index = this.selection.indexOf(item)
this.selection.splice(index, 1)
} else {
if (this.multiple) {
this.selection.push(item)
} else {
this.selection.splice(0, 1, item)
}
}
}
}
}
</script>
<style scoped>
.multiple-choice{
padding:5px 25px;
}
.title{
font-size:16px;
line-height:40px;
color:#333;
user-select: none;
}
.options{
display:flex;
/* justify-content:space-around; */
flex-wrap:wrap;
padding-top:20px;
}
.options li{
width:200px;
height:40px;
background:#f3f3f3;
border-radius:20px;
font-size:16px;
line-height:40px;
color:#666;
text-align:center;
cursor:pointer;
user-select: none;
margin:0 10px 20px 15px;
}
.options li.active{
background:#68b8a4;
color:#fff;
}
.btn-bar{
padding-top:30px;
display:flex;
}
.btn-bar>div{
width:33.3%;
text-align:center;
}
.btn-bar .el-button{
padding:8px 30px;
}
</style>
<template>
<ul class="tabs">
<li :class="{ active: value === item.value }" v-for="(item, index) in list" :key="index" @click="handleClick(item)">{{item.label}}</li>
</ul>
</template>
<script>
export default {
props: {
list: {
type: Array,
default() {
return []
}
},
value: {
type: [String, Number],
default: ''
}
},
methods: {
handleClick(item) {
this.$emit('input', item.value)
}
}
}
</script>
<style scoped>
ul{
display:flex;
}
li{
width:192px;
height:54px;
background:#f5f5f5;
font-size:16px;
line-height:54px;
color:#666;
text-align:center;
border-top:4px solid #f5f5f5;
box-shadow: 0 2px 4px 0 rgb(0 0 0 / 12%), 0 0 6px 0 rgb(0 0 0 / 4%);
cursor:pointer;
user-select: none;
}
li.active{
background:#fff;
border-top:4px solid #68B8A4;
}
</style>
\ No newline at end of file
<template>
<div class="user-table">
<el-table :data="tableData" stripe size="medium" height="calc(100% - 26px)" style="width: 100%" :header-row-style="{background:'#ededed',color:'#4d4d4d'}" :header-cell-style="{background: 'transparent'}">
<el-table-column prop="name" label="客户姓名" min-width="120" />
<el-table-column prop="id" label="客户编号" min-width="120" />
<el-table-column prop="age" label="年龄" min-width="100" />
<el-table-column prop="gendar" label="性别" min-width="100" />
<el-table-column prop="property" label="可支配资产" min-width="120" />
<el-table-column prop="experience" label="理财经验" min-width="120" />
</el-table>
<div class="pagination">
<el-pagination layout="prev, pager, next" :total="total"></el-pagination>
</div>
</div>
</template>
<script>
export default {
data() {
return {
tableData: [
{ name: '某某某', id: '1111', age: 18, gendar: '男', property: '20万', experience: '3年' },
{ name: '张三', id: '2222', age: 22, gendar: '女', property: '5-10万', experience: '5-10年' },
{ name: '李四', id: '3333', age: 19, gendar: '男', property: '30万', experience: '3年以内' }
],
total: 1000
}
}
}
</script>
<style scoped>
.user-table{
padding:28px 20px 20px;
box-sizing:border-box;
height:484px;
}
.pagination{
padding-top:7px;
text-align:right;
}
</style>
\ No newline at end of file
@charset "utf-8";
.CodeMirror.cm-s-default {
font-family: Menlo, Monaco, Consolas, Courier, monospace;
line-height: 16px;
font-size: 12px;
}
.CodeMirror-hints.default {
z-index: 9999;
padding: 0px;
border: 1px solid #e4e7ed;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.CodeMirror-hints.default .CodeMirror-hint {
font-family: Menlo, Monaco, Consolas, Courier, monospace;
line-height: 16px;
padding: 0 10px;
border-radius: 0;
border-left: 2px solid transparent;
}
.CodeMirror-hints.default li.CodeMirror-hint-active {
background: #f5f7fa;
color: #409eff;
font-weight: 700;
border-left: 2px solid #409eff;
}
// require lib
import Vue from 'vue'
import VueCodemirror from 'vue-codemirror'
// require styles
import 'codemirror/lib/codemirror.css'
// require more codemirror resource...
// import 'codemirror/mode/javascript/javascript'
// import 'codemirror/mode/css/css'
// import 'codemirror/mode/xml/xml'
import 'codemirror/mode/python/python.js'
import 'codemirror/mode/htmlmixed/htmlmixed'
import 'codemirror/mode/markdown/markdown'
// 代码折叠
import 'codemirror/addon/fold/foldgutter.css'
import 'codemirror/addon/fold/foldcode'
import 'codemirror/addon/fold/foldgutter'
import 'codemirror/addon/fold/brace-fold'
import 'codemirror/addon/fold/xml-fold'
import 'codemirror/addon/fold/indent-fold'
import 'codemirror/addon/fold/markdown-fold'
import 'codemirror/addon/fold/comment-fold'
// 代码自动补全
import 'codemirror/addon/hint/show-hint.css'
import 'codemirror/addon/hint/show-hint'
import 'codemirror/addon/hint/javascript-hint'
import 'codemirror/addon/hint/css-hint'
import 'codemirror/addon/hint/html-hint'
// 高亮行
import 'codemirror/addon/selection/active-line'
// 括号配对
import 'codemirror/addon/edit/matchbrackets'
// you can set default global options and events when use
Vue.use(VueCodemirror, {
options: {
mode: 'python',
tabSize: 2, // 缩进
smartIndent: true, // 智能缩进
indentUnit: 2, // 智能缩进单位为4个空格长度
indentWithTabs: true, // 使用制表符进行智能缩进
lineNumbers: true, // 行号
lineWrapping: false, // 换行
foldGutter: true, // 折叠
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'], // 折叠
matchBrackets: true, // 括号配对
autoCloseBrackets: true, // 自动闭合符号
styleActiveLine: true, // 高亮行
extraKeys: { Ctrl: 'autocomplete' } // 快捷键代码自动补全
}
})
Vue.use(VueCodemirror)
function cmOption(mod) {
let option = {};
switch (mod) {
case "js":
option = {
mode: { name: "javascript" }
};
break;
case "css":
option = {
mode: { name: "css" }
};
break;
case "html":
option = {
mode: "text/html"
};
break;
case "json":
option = {
mode: { name: "javascript", json: true }
};
break;
}
return option;
}
export {
cmOption
}
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论