提交 ba12d455 authored 作者: pengxiaohui's avatar pengxiaohui

v1.1版本更新

上级 10567d42
...@@ -2,10 +2,9 @@ ...@@ -2,10 +2,9 @@
<div class="menu-box"> <div class="menu-box">
<ul class="menu"> <ul class="menu">
<template v-for="(item, index) in menuList"> <template v-for="(item, index) in menuList">
{{index === 0 ? '' : '|'}}<li :class="{ active: path.includes(item.path), disabled: item.disabled.includes(role)}" :key="index" @click="menuSelect(item)">{{item.label}}</li> {{index === 0 ? '' : '|'}}<li :class="{ active: path.includes(item.path), disabled: item.disabled.includes(role)}" :key="index" @click="handleClick(item)">{{item.label}}</li>
</template> </template>
</ul> </ul>
<el-button @click="selectProducts" style="height: fit-content;" type="primary" v-if="$route.path.includes('/product-analysis')">产品柜</el-button>
</div> </div>
</template> </template>
<script> <script>
...@@ -16,7 +15,7 @@ export default { ...@@ -16,7 +15,7 @@ export default {
return { return {
menuList: [ menuList: [
{ label: '首页', path: '/home', disabled: [] }, { label: '首页', path: '/home', disabled: [] },
{ label: '产品分析', path: '/product-analysis', disabled: [0, 2, 3] }, { label: '产品分析', path: '/product-analysis/report', disabled: [0, 2, 3] },
{ label: '用户分析', path: '/user-study', disabled: [0, 1, 3] }, { label: '用户分析', path: '/user-study', disabled: [0, 1, 3] },
{ label: '营销工具使用', path: '/market-tools', disabled: [0, 1, 2] }, { label: '营销工具使用', path: '/market-tools', disabled: [0, 1, 2] },
{ label: '作品展示', path: '/works-show', disabled: [0] } { label: '作品展示', path: '/works-show', disabled: [0] }
...@@ -32,24 +31,29 @@ export default { ...@@ -32,24 +31,29 @@ export default {
} }
}, },
methods: { methods: {
async menuSelect(item) { handleClick(item) {
if (this.role === 0) { if (!item.disabled.includes(this.role)) {
this.$message.error('请选择角色') this.$router.push(item.path)
} else if (item.disabled.includes(this.role)) {
this.$message.error('您当前的角色禁止访问该页面')
} else {
if (['/user-study', '/market-tools'].includes(item.path)) {
const flag = await this.fetchWorkStatus()
if (flag) {
this.$router.push(item.path)
} else {
this.$message.error('请先完成产品分析报告,再进行' + item.label)
}
} else {
this.$router.push(item.path)
}
} }
}, },
// async menuSelect(item) {
// if (this.role === 0) {
// this.$message.error('请选择角色')
// } else if (item.disabled.includes(this.role)) {
// this.$message.error('您当前的角色禁止访问该页面')
// } else {
// if (['/user-study', '/market-tools'].includes(item.path)) {
// const flag = await this.fetchWorkStatus()
// if (flag) {
// this.$router.push(item.path)
// } else {
// this.$message.error('请先完成产品分析报告,再进行' + item.label)
// }
// } else {
// this.$router.push(item.path)
// }
// }
// },
selectProducts() { selectProducts() {
console.log(2222) console.log(2222)
this.$confirm('切换案例,当前填写的内容不会保存', '提示', { this.$confirm('切换案例,当前填写的内容不会保存', '提示', {
...@@ -57,8 +61,9 @@ export default { ...@@ -57,8 +61,9 @@ export default {
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
console.log(1111) // console.log(1111)
this.$router.push({ path: '/product-analysis' }) // this.$router.push({ path: '/product-analysis' })
this.visible = true
}).catch(() => {}) }).catch(() => {})
}, },
fetchWorkStatus() { fetchWorkStatus() {
......
<template>
<el-dialog custom-class="case-dialog" title="" :visible="value" :close-on-click-modal="false" :close-on-press-escape="false" top="20px" :show-close="showClose" @close="handleClose">
<product v-if="!type" @select="handleProdSelect"></product>
<case v-else @select="handleCaseSelect"></case>
</el-dialog>
<!-- <div class="popup">
<div class="popup-container">
<i v-if="showClose" class="el-icon-close icon-close" @click="handleCaseSelect"></i>
<product v-if="!type" @select="handleProdSelect"></product>
<case v-else @select="handleCaseSelect"></case>
</div>
<div class="overlay"></div>
</div> -->
</template>
<script>
import Product from './product.vue'
import Case from './case.vue'
export default {
components: { Product, Case },
props: {
value: {
type: Boolean,
default: false
},
showClose: {
type: Boolean,
default: true
}
},
data() {
return {
type: '',
dialogVisible: true
}
},
watch: {
value(val) {
this.dialogVisible = val
}
},
methods: {
handleClose() {
this.$emit('input', false)
},
handleProdSelect(val) {
this.type = val
},
handleCaseSelect() {
this.$emit('input', false)
}
}
}
</script>
<style scoped>
::v-deep .case-dialog{
width:95%;
max-width:1160px;
margin-bottom:20px;
}
</style>
import httpRequest from '@/utils/axios'
/**
* 获取产品类型列表
*/
export function getCategories(id) {
return httpRequest.get(`/api/xtraining/api/v1/${id}/categories`).then({})
}
// 获取案例列表
export function getCasesList(id) {
return httpRequest.get(`/api/xtraining/api/v1/${id}/cases`)
}
// 选中案例
export function selectCase(id) {
return httpRequest.post(`/api/xtraining/api/v1/${id}/select-case`, {})
}
\ No newline at end of file
<template>
<div class="case-select">
<div class="inner">
<div class="left">
<div class="case">
<el-radio-group v-model="caseSelect">
<el-radio :label="item.id" v-for="(item, index) in caseList" :key="index">{{item.name}}</el-radio>
</el-radio-group>
<!-- <el-radio-group v-model="caseSelect">
<el-radio label="item.id" v-for="(item, index) in 15" :key="index">1111</el-radio>
</el-radio-group> -->
</div>
</div>
<div class="right">
<ul>
<li :class="{ active: index === selected }" v-for="(item, index) in list" :key="index" @click="handleClick(item, index)">{{item.name}}</li>
</ul>
<el-button type="primary" size="medium" plain style="margin-left:20px;" @click="handleGo">选好了</el-button>
</div>
</div>
</div>
</template>
<script>
import { getCategories, getCasesList, selectCase } from './api'
export default {
data() {
return {
caseList: [
{ label: '股票型基金案例:广发银行优选股票A', id: '111' },
{ label: '股票型基金案例:广发银行优选股票B', id: '222' },
{ label: '股票型基金案例:广发银行优选股票C', id: '333' },
{ label: '股票型基金案例:广发银行优选股票D', id: '444' }
],
caseSelect: '',
list: [],
selected: 0
}
},
mounted() {
this.getCategories()
},
methods: {
getCategories() {
getCategories(1).then(res => {
this.getCasesList(res.data.items[0].id)
this.list = res.data.items
})
},
handleClick(item, index) {
this.selected = index
this.getCasesList(item.id)
},
handleGo() {
if (Array.isArray(this.$store.state.case)) {
this.selectConfirm()
} else {
this.$confirm('切换案例,当前填写的内容不会保存', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.selectCase()
})
}
// console.log(this.$store.state.case, '1231')
},
selectConfirm() {
const data = this.caseList.find(item => { return item.id === this.caseSelect })
this.$store.commit('setCase', data)
this.selectCase(data.id)
},
getCasesList(id) {
getCasesList(id).then(res => {
this.caseList = res.data.items
this.caseSelect = res.data.items[0].id
})
},
selectCase() {
const data = this.caseList.find(item => { return item.id === this.caseSelect })
this.$store.commit('setCase', data)
selectCase(data.id).then(res => {
this.$emit('select', data)
})
}
}
}
</script>
<style lang="scss" scoped>
.case-select{
height:548px;
// margin:24px 30px 60px 30px;
padding-top:32px;
position:relative;
}
.inner{
display: flex;
height:500px;
width:100%;
margin:0 auto;
}
.left{
flex:1;
padding:35px 18px 80px 225px;
background:url('@/assets/images/product_analysis_case.png') no-repeat left center;
}
.case{
height:100%;
width:100%;
position:relative;
overflow-y: auto;
&::-webkit-scrollbar{
width: 4px;
height: 4px;
}
&::-webkit-scrollbar-button{
width: 0;
height: 0;
}
&::-webkit-scrollbar-track{
}
&::-webkit-scrollbar-thumb{
border-radius: 8px;
background-color: #c3e3db;
}
&::-webkit-scrollbar-thumb:hover {
background-color: #68b8a4;
}
&::-webkit-scrollbar-thumb:active {
background-color: #68b8a4;
}
}
.case .el-radio-group{
position:absolute;
left:50%;
top:50%;
transform: translate(-50%, -50%);
max-height:100%;
}
.case ::v-deep.el-radio{
display:block;
margin-bottom:20px;
}
.case ::v-deep.el-radio.all .el-radio__input.is-checked .el-radio__inner{
border-color:#636363;
background:#636363;
}
.right{
width:280px;
margin-top:32px;
flex-wrap:wrap;
flex-direction: column;
}
ul{
display:flex;
flex-wrap:wrap;
flex-direction: row;
align-content: flex-start;
height:380px;
}
li{
width:122px;
height:40px;
font-size:16px;
line-height:40px;
text-align:center;
color:#666;
margin:0 0 10px 10px;
cursor:pointer;
background:#f8f8f8;
}
li.active{
background:#68B8A4;
color:#fff;
}
</style>
<template>
<div class="product-analysis">
<h5>选择一款金融产品进行分析吧。</h5>
<ul class="list">
<li class="item" v-for="(item, index) in list" :key="index" @click="handleClick(item)">
<span class="btn">{{ item.label }}</span>
<img :src="item.image" />
</li>
</ul>
</div>
</template>
<script>
import fundIcon from '@/assets/images/fund_icon.png'
import financeIcon from '@/assets/images/finance_icon.png'
import insuranceIcon from '@/assets/images/insurance_icon.png'
export default {
data() {
return {
list: [
{ label: '基金', image: fundIcon, type: '1' },
{ label: '理财', image: financeIcon, type: '2' },
{ label: '保险', image: insuranceIcon, type: '3' }
]
}
},
mounted() {
// console.log(this.$store.state.case, '123')
},
methods: {
handleClick(item) {
this.$emit('select', item.type)
}
}
}
</script>
<style scoped>
.pad-lr-30{
padding: 0 30px;
}
.product-analysis {
background: #fff;
/* width: 1340px; */
height: 520px;
}
h5 {
font-size: 22px;
font-weight: normal;
text-align: center;
color: #666;
padding-top: 56px;
}
.list {
display: flex;
overflow-x: auto;
padding-top: 56px;
}
.item {
width: 33.3%;
text-align: center;
}
.item .btn {
display: inline-block;
width: 97px;
height: 40px;
background: #c7d4d5;
font-size: 22px;
line-height: 40px;
color: #fff;
margin-bottom: 40px;
cursor: pointer;
}
.item img {
display: block;
margin: 0 auto;
width:80%;
}
</style>
<template> <template>
<header class="app-header"> <header class="app-header">
<app-menu /> <div class="header-bar">
<app-menu />
<div>
<el-button @click="visible = true" style="height: fit-content;" type="primary" v-if="showCaseSelect">切换案例</el-button>
<el-button @click="drawerVisible = true" style="height: fit-content;" type="primary" v-if="showCaseDetails">查看案例</el-button>
</div>
</div>
<case-select v-model="visible"></case-select>
<el-drawer title="" size="640px" :visible.sync="drawerVisible">
<embed class="embed" width="100%" height="100%" :src="cases.pdf_uris[0]" />
</el-drawer>
</header> </header>
</template> </template>
<script> <script>
import AppMenu from '../base/AppMenu.vue' import AppMenu from '../base/AppMenu.vue'
import CaseSelect from '@/components/caseSelect/Index.vue'
export default { export default {
name: 'AppHeader', name: 'AppHeader',
components: { AppMenu } components: { AppMenu, CaseSelect },
computed: {
path() {
return this.$route.path
},
showCaseSelect() {
if (this.path !== '/home' && !this.path.includes('/works-show')) return true
else return false
},
showCaseDetails() {
if (this.path.includes('/user-study') || this.path.includes('/market-tools')) return true
else return false
},
cases() {
return this.$store.state.case
}
},
data() {
return {
visible: false,
drawerVisible: false
}
}
} }
</script> </script>
...@@ -17,4 +50,24 @@ export default { ...@@ -17,4 +50,24 @@ export default {
// width:1360px; // width:1360px;
padding:30px 33px 0; padding:30px 33px 0;
} }
.header-bar{
display: flex;
justify-content: space-between;
align-items: center;
}
/* element-ui drawer reset */
.app-header ::v-deep .el-drawer__header{
padding:6px 16px;
margin:0;
border-bottom:1px solid #DCDFE6;
}
.app-header ::v-deep .el-drawer__header>h5{
font-size:16px;
color:#666;
font-weight:600;
}
.app-header ::v-deep .el-drawer__body{
height:calc(100% - 82px);
overflow-y: auto;
}
</style> </style>
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<div class="home"> <div class="home">
<div class="top"> <div class="top">
<el-button style="margin-left:10px;" type="primary" size="medium" plain round @click="handleLogout">退出系统</el-button> <el-button style="margin-left:10px;" type="primary" size="medium" plain round @click="handleLogout">退出系统</el-button>
<el-button type="primary" size="medium" plain round @click="visible = true">切换角色</el-button> <el-button type="primary" size="medium" plain round @click="roleVisible = true">切换角色</el-button>
</div> </div>
<div class="inner"> <div class="inner">
<div class="header"> <div class="header">
...@@ -11,20 +11,23 @@ ...@@ -11,20 +11,23 @@
</div> </div>
<btn v-for="(item, index) in btnList" :key="index" :attrs="{ title: item.label, left: item.left, top: item.top }" @click.native="handleClick(item)" :disabled="item.disabled.includes(role)"/> <btn v-for="(item, index) in btnList" :key="index" :attrs="{ title: item.label, left: item.left, top: item.top }" @click.native="handleClick(item)" :disabled="item.disabled.includes(role)"/>
</div> </div>
<role-select :visible="visible" @roleSelect="fetchSelectRole" /> <role-select :visible="roleVisible" @roleSelect="fetchSelectRole" />
<case-select v-model="visible" :show-close="false"></case-select>
</div> </div>
</template> </template>
<script> <script>
import AppMenu from '@/components/base/AppMenu.vue' import AppMenu from '@/components/base/AppMenu.vue'
import RoleSelect from '../components/RoleSelect.vue' import RoleSelect from '../components/RoleSelect.vue'
import CaseSelect from '@/components/caseSelect/Index.vue'
import Btn from '../components/Btn.vue' import Btn from '../components/Btn.vue'
import { selectRole } from '../api' import { selectRole } from '../api'
import { getWorkStatus } from '@/api/base.js' import { getWorkStatus } from '@/api/base.js'
export default { export default {
components: { AppMenu, RoleSelect, Btn }, components: { AppMenu, Btn, CaseSelect, RoleSelect },
data() { data() {
return { return {
roleVisible: false,
visible: false, visible: false,
btnList: [ btnList: [
{ label: '产品分析', path: '/product-analysis', disabled: [0, 2, 3], left: '960px', top: '134px' }, { label: '产品分析', path: '/product-analysis', disabled: [0, 2, 3], left: '960px', top: '134px' },
...@@ -47,34 +50,37 @@ export default { ...@@ -47,34 +50,37 @@ export default {
} }
}, },
created() { created() {
if (!this.role) { if (this.case && !this.case.id) {
this.visible = true this.visible = true
} }
if (this.role !== 4) {
this.fetchSelectRole(4)
}
}, },
methods: { methods: {
// handleClick(item) { handleClick(item) {
// if (!item.disabled.includes(this.role)) { if (!item.disabled.includes(this.role)) {
// this.$router.push(item.path) this.$router.push(item.path)
// }
// },
async handleClick(item) {
if (this.role === 0) {
this.$message.error('请选择角色')
} else if (item.disabled.includes(this.role)) {
this.$message.error('您当前的角色禁止访问该页面')
} else {
if (['/user-study', '/market-tools'].includes(item.path)) {
const flag = await this.fetchWorkStatus()
if (flag) {
this.$router.push(item.path)
} else {
this.$message.error('请先完成产品分析报告,再进行' + item.label)
}
} else {
this.$router.push(item.path)
}
} }
}, },
// async handleClick(item) {
// if (this.role === 0) {
// this.$message.error('请选择角色')
// } else if (item.disabled.includes(this.role)) {
// this.$message.error('您当前的角色禁止访问该页面')
// } else {
// if (['/user-study', '/market-tools'].includes(item.path)) {
// const flag = await this.fetchWorkStatus()
// if (flag) {
// this.$router.push(item.path)
// } else {
// this.$message.error('请先完成产品分析报告,再进行' + item.label)
// }
// } else {
// this.$router.push(item.path)
// }
// }
// },
fetchWorkStatus() { fetchWorkStatus() {
return new Promise((resolve) => { return new Promise((resolve) => {
getWorkStatus().then(res => { getWorkStatus().then(res => {
...@@ -97,11 +103,11 @@ export default { ...@@ -97,11 +103,11 @@ export default {
fetchSelectRole(role) { fetchSelectRole(role) {
selectRole({ role }).then(res => { selectRole({ role }).then(res => {
if (res.code === 0 && res.data && res.data.status) { if (res.code === 0 && res.data && res.data.status) {
this.$message.success('选择角色成功!') // this.$message.success('选择角色成功!')
this.$store.commit('setRole', role) this.$store.commit('setRole', role)
this.visible = false // this.visible = false
} else { } else {
this.$message.error(res.message) // this.$message.error(res.message)
} }
}).catch(err => { }).catch(err => {
console.log(err) console.log(err)
......
<template> <template>
<div> <div class="in-coder-panel">
<codemirror class="code" v-model="code"></codemirror> <textarea ref="textarea"></textarea>
<el-select class="code-mode-select" v-model="mode"
@change="changeMode">
<el-option v-for="mode in modes"
:key="mode.value" :label="mode.label" :value="mode.value">
</el-option>
</el-select>
</div> </div>
</template> </template>
<script>
export default { <script type="text/ecmascript-6">
data() { // 引入全局实例
return { import _CodeMirror from 'codemirror'
code: ''
// 核心样式
import 'codemirror/lib/codemirror.css'
// 引入主题后还需要在 options 中指定主题才会生效
import 'codemirror/theme/cobalt.css'
// 需要引入具体的语法高亮库才会有对应的语法高亮效果
// codemirror 官方其实支持通过 /addon/mode/loadmode.js 和 /mode/meta.js 来实现动态加载对应语法高亮库
// 但 vue 貌似没有无法在实例初始化后再动态加载对应 JS ,所以此处才把对应的 JS 提前引入
import 'codemirror/mode/javascript/javascript.js'
import 'codemirror/mode/css/css.js'
import 'codemirror/mode/xml/xml.js'
import 'codemirror/mode/clike/clike.js'
import 'codemirror/mode/markdown/markdown.js'
import 'codemirror/mode/python/python.js'
import 'codemirror/mode/r/r.js'
import 'codemirror/mode/shell/shell.js'
import 'codemirror/mode/sql/sql.js'
import 'codemirror/mode/swift/swift.js'
import 'codemirror/mode/vue/vue.js'
// 尝试获取全局实例
const CodeMirror = window.CodeMirror || _CodeMirror
export default {
name: 'in-coder',
props: {
// 外部传入的内容,用于实现双向绑定
value: String,
// 外部传入的语法类型
language: {
type: String,
default: null
}
},
data () {
return {
// 内部真实的内容
code: '',
// 默认的语法类型
mode: 'javascript',
// 编辑器实例
coder: null,
// 默认配置
options: {
// 缩进格式
tabSize: 2,
// 主题,对应主题库 JS 需要提前引入
theme: 'cobalt',
// 显示行号
lineNumbers: true,
line: true
},
// 支持切换的语法高亮类型,对应 JS 已经提前引入
// 使用的是 MIME-TYPE ,不过作为前缀的 text/ 在后面指定时写死了
modes: [{
value: 'css',
label: 'CSS'
}, {
value: 'javascript',
label: 'Javascript'
}, {
value: 'html',
label: 'XML/HTML'
}, {
value: 'x-java',
label: 'Java'
}, {
value: 'x-objectivec',
label: 'Objective-C'
}, {
value: 'x-python',
label: 'Python'
}, {
value: 'x-rsrc',
label: 'R'
}, {
value: 'x-sh',
label: 'Shell'
}, {
value: 'x-sql',
label: 'SQL'
}, {
value: 'x-swift',
label: 'Swift'
}, {
value: 'x-vue',
label: 'Vue'
}, {
value: 'markdown',
label: 'Markdown'
}]
}
},
mounted () {
// 初始化
this._initialize()
},
methods: {
// 初始化
_initialize () {
// 初始化编辑器实例,传入需要被实例化的文本域对象和默认配置
this.coder = CodeMirror.fromTextArea(this.$refs.textarea, this.options)
// 编辑器赋值
this.coder.setValue(this.value || this.code)
// 支持双向绑定
this.coder.on('change', (coder) => {
this.code = coder.getValue()
if (this.$emit) {
this.$emit('input', this.code)
}
})
// 尝试从父容器获取语法类型
if (this.language) {
// 获取具体的语法类型对象
let modeObj = this._getLanguage(this.language)
// 判断父容器传入的语法是否被支持
if (modeObj) {
this.mode = modeObj.label
}
}
},
// 获取当前语法类型
_getLanguage (language) {
// 在支持的语法类型列表中寻找传入的语法类型
return this.modes.find((mode) => {
// 所有的值都忽略大小写,方便比较
let currentLanguage = language.toLowerCase()
let currentLabel = mode.label.toLowerCase()
let currentValue = mode.value.toLowerCase()
// 由于真实值可能不规范,例如 java 的真实值是 x-java ,所以讲 value 和 label 同时和传入语法进行比较
return currentLabel === currentLanguage || currentValue === currentLanguage
})
},
// 更改模式
changeMode (val) {
// 修改编辑器的语法配置
this.coder.setOption('mode', `text/${val}`)
// 获取修改后的语法
let label = this._getLanguage(val).label.toLowerCase()
// 允许父容器通过以下函数监听当前的语法值
this.$emit('language-change', label)
}
} }
} }
}
</script> </script>
<style scoped>
.code ::v-deep.CodeMirror { <style>
height: 398px; .in-coder-panel{
flex-grow: 1;
display: flex;
position: relative
}
.CodeMirror{
flex-grow: 1;
z-index: 1
}
.code-mode-select{
position: absolute;
z-index: 2;
right: 10px;
top: 10px;
max-width: 130px;
} }
</style> </style>
...@@ -16,11 +16,19 @@ export function getChart(params) { ...@@ -16,11 +16,19 @@ export function getChart(params) {
export function submitReport(data) { export function submitReport(data) {
return httpRequest.post('/api/xtraining/api/v1/analysis-users/report', data) return httpRequest.post('/api/xtraining/api/v1/analysis-users/report', data)
} }
/** 保存用户分析报告 */
export function saveReport(id, data) {
return httpRequest.post(`/api/xtraining//api/v1/answer/${id}/save-user-analysis-record`, data)
}
/** 提交用户分析报告 */ /** 提交用户分析报告 */
export function clearScore() { export function clearScore() {
return httpRequest.post('/api/xtraining/api/v1/analysis-users/clear-error-score') return httpRequest.post('/api/xtraining/api/v1/analysis-users/clear-error-score')
} }
/** 获取当前选择题对应的图表数据 */ /** 根据记录id查询报告详情 */
export function getReport(params) { export function getReportDetails(id) {
return httpRequest.get('/api/xtraining/api/v1/analysis-users/report-detail', { params }) return httpRequest.get(`/api/xtraining/api/v1/answer/${id}/user-analysis-report`)
}
/** 检验是否有未完成的报告记录 */
export function getReportRecord(id, type) {
return httpRequest.post(`/api/xtraining/api/v1/answer/${id}/check-record/${type}`)
} }
<template> <template>
<div class="answer-list"> <div class="answer-list">
<div class="answer-item" v-for="(item, index) in list" :key="index" @click="handleClick(item)"> <div :class="{'answer-item': true, multi: item.display_multi === 1}" v-for="(item, index) in list" :key="index" @click="handleClick(item)">
<!-- <span v-if="!multiple">{{item.selection[0].label}}</span> --> <!-- <span v-if="!multiple">{{item.selection[0].label}}</span> -->
<!-- <ul v-else> <!-- <ul v-else>
<li v-for="(it, idx) in item.selection" :key="idx">{{it.label}}</li> <li v-for="(it, idx) in item.selection" :key="idx">{{it.label}}</li>
</ul> --> </ul> -->
<template v-if="!multiple"> <template v-if="item.display_multi === 0">
<span>{{ item.selection[0] ? item.selection[0].subject : ''}}</span> <span>{{ item.selection[0] ? item.selection[0].subject : ''}}</span>
</template> </template>
<template v-else> <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> <el-tag v-show="item.selection.includes(it)" size="small" v-for="(it, idx) in item.options" :key="idx">{{it.subject}}</el-tag>
</template> </template>
</div> </div>
<!-- <div class="answer-item">双皮奶</div> --> <!-- <div class="answer-item">双皮奶</div> -->
...@@ -32,6 +32,9 @@ export default { ...@@ -32,6 +32,9 @@ export default {
data() { data() {
return {} return {}
}, },
created() {
console.log(this.list)
},
methods: { methods: {
handleClick(item) { handleClick(item) {
this.$emit('select', item) this.$emit('select', item)
...@@ -63,6 +66,9 @@ export default { ...@@ -63,6 +66,9 @@ export default {
transition: border-color .2s cubic-bezier(.645,.045,.355,1); transition: border-color .2s cubic-bezier(.645,.045,.355,1);
cursor:pointer; cursor:pointer;
} }
.answer-item.multi{
width:464px;
}
.answer-item-inner{ .answer-item-inner{
height:34px; height:34px;
vertical-align: top; vertical-align: top;
......
<template> <template>
<div class="multiple-choice"> <div class="multiple-choice">
<p class="title" v-if="choice.subject">{{choice.index}}{{choice.subject}}</p> <p class="title" v-if="choice.subject">{{choice.index}}{{choice.subject}}<span>{{choice.display_multi === 1 ? '多' : '单'}}选)</span></p>
<ul class="options"> <ul class="options">
<li :class="{ active: selection.includes(item) }" v-for="item in choice.options" :key="item.value" @click="handleSelect(item)">{{item.subject}}</li> <li :class="{ active: selection.includes(item) }" v-for="item in choice.options" :key="item.value" @click="handleSelect(item)">{{item.subject}}</li>
</ul> </ul>
...@@ -52,7 +52,7 @@ export default { ...@@ -52,7 +52,7 @@ export default {
const index = this.selection.indexOf(item) const index = this.selection.indexOf(item)
this.selection.splice(index, 1) this.selection.splice(index, 1)
} else { } else {
if (this.multiple) { if (this.choice.display_multi === 1) {
this.selection.push(item) this.selection.push(item)
} else { } else {
this.selection.splice(0, 1, item) this.selection.splice(0, 1, item)
......
...@@ -85,21 +85,6 @@ ...@@ -85,21 +85,6 @@
<script> <script>
import { getUserList } from '../api' import { getUserList } from '../api'
import { fieldsMap } from '../userFieldsMap.js' import { fieldsMap } from '../userFieldsMap.js'
const propertyMap = {
1: '10万以下',
2: '10万-20万',
3: '20-50万',
4: '50-80万',
5: '80-100万',
6: '100万-300万',
7: '300万以上'
}
const experienceMap = {
1: '没有经验',
2: '1-3年',
3: '3-5年',
4: '5年以上'
}
export default { export default {
props: { props: {
params: { params: {
...@@ -112,18 +97,12 @@ export default { ...@@ -112,18 +97,12 @@ export default {
data() { data() {
return { return {
tableData: [], tableData: [],
total: 1000, total: 0,
page: 1, page: 1,
limit: 10 limit: 10
} }
}, },
filters: { filters: {
propertyFilter(val) {
return propertyMap[val]
},
experienceFilter(val) {
return experienceMap[val]
},
fieldsFilter(val, field) { fieldsFilter(val, field) {
const map = fieldsMap[field] const map = fieldsMap[field]
return map[val] return map[val]
......
...@@ -12,8 +12,9 @@ ...@@ -12,8 +12,9 @@
<template #btn-prev v-if="status === '0'"> <template #btn-prev v-if="status === '0'">
<el-button v-if="current.index !== 0" size="medium" @click="handlePrev" round>上一题</el-button> <el-button v-if="current.index !== 0" size="medium" @click="handlePrev" round>上一题</el-button>
</template> </template>
<template #btn-center v-if="status === '2'"> <template #btn-center>
<el-button size="medium" @click="handleReturn" round>返回</el-button> <el-button v-if="status === '2'" size="medium" @click="handleReturn" round>返回</el-button>
<el-button v-else size="medium" type="primary" @click="handleFinish(false)" plain round>保存报告</el-button>
</template> </template>
<template #btn-next v-if="status === '0'"> <template #btn-next v-if="status === '0'">
<el-button v-if="current.index < questions.length - 1" type="primary" size="medium" @click="handleNext" round>下一题</el-button> <el-button v-if="current.index < questions.length - 1" type="primary" size="medium" @click="handleNext" round>下一题</el-button>
...@@ -24,7 +25,8 @@ ...@@ -24,7 +25,8 @@
<!-- <p>根据您选择的目标人群特征分析,此类受众并不适合当前的金融产品,请重新选择!</p> --> <!-- <p>根据您选择的目标人群特征分析,此类受众并不适合当前的金融产品,请重新选择!</p> -->
<answer-list :list="questions" @select="handleSelect"></answer-list> <answer-list :list="questions" @select="handleSelect"></answer-list>
<div style="text-align:center;"> <div style="text-align:center;">
<el-button v-if="status !== '3'" type="primary" size="medium" @click="handleFinish" round>完成报告</el-button> <el-button v-if="status !== '3'" type="primary" size="medium" @click="handleFinish(false)" plain round>保存报告</el-button>
<el-button v-if="status !== '3'" type="primary" size="medium" @click="handleFinish(1)" round>完成报告</el-button>
</div> </div>
</div> </div>
</div> </div>
...@@ -61,7 +63,7 @@ import UserTable from '../components/UserTable.vue' ...@@ -61,7 +63,7 @@ import UserTable from '../components/UserTable.vue'
import EchartBar from '../components/EchartBar.vue' import EchartBar from '../components/EchartBar.vue'
import ScoreSvg from '../components/ScoreSvg.vue' import ScoreSvg from '../components/ScoreSvg.vue'
// api // api
import { getQuestions, submitReport, clearScore, getReport } from '../api' import { getQuestions, submitReport, clearScore, getReportDetails, saveReport, getReportRecord } from '../api'
export default { export default {
components: { MultipleChoice, Tabs, AnswerList, UserTable, EchartBar, ScoreSvg }, components: { MultipleChoice, Tabs, AnswerList, UserTable, EchartBar, ScoreSvg },
data() { data() {
...@@ -87,14 +89,20 @@ export default { ...@@ -87,14 +89,20 @@ export default {
index: 0, index: 0,
choice: {} choice: {}
}, },
status: '0', // '0':未完成,'1':已完成,'2':修改, '3':成绩 status: '0', // '0':未完成,'1':已完成选择,'2':修改, '3':显示成绩
code: '', code: '',
tabActive: '1', tabActive: '1',
list: [ list: [
{ label: '数据展示', value: '1' }, { label: '数据展示', value: '1' },
{ label: '数据列表', value: '2' } { label: '数据列表', value: '2' }
], ],
score: 0 score: 0,
recordId: ''
}
},
computed: {
case() {
return this.$store.state.case
} }
}, },
created() { created() {
...@@ -102,17 +110,28 @@ export default { ...@@ -102,17 +110,28 @@ export default {
this.$router.push('/home') this.$router.push('/home')
return return
} }
this.init() this.recordId = this.$route.query.id || ''
this.status = this.$route.query.type || '0' this.status = this.$route.query.type || '0'
this.init()
}, },
methods: { methods: {
init() { init() {
Promise.all([this.fetchQuestions(), this.fetchGetReport()]).then(res => { Promise.all([this.fetchQuestions(), this.fetchGetReport()]).then(res => {
console.log(res)
const singleChoice = []
const multiChoice = []
// 组装数据 // 组装数据
const questions = res[0] res[0].forEach(item => {
console.log(res[0], res[1]) // 模拟多选题
// if (['学历', '可支配资产总额', '娱乐偏好', '购物服务要求程度', '感兴趣的金融信息', '感兴趣的优惠方式', '金融产品服务要求程度'].includes(item.subject)) {
// item.display_multi = 1
// }
if (item.display_multi === 0) singleChoice.push(item)
else multiChoice.push(item)
})
const questions = [...singleChoice, ...multiChoice]
let selection = [] let selection = []
if (res[1].answer && Array.isArray(res[1].answer.options)) { if (res[1] && res[1].answer && Array.isArray(res[1].answer.options)) {
selection = res[1].answer.options selection = res[1].answer.options
this.score = res[1].answer.score this.score = res[1].answer.score
} }
...@@ -166,21 +185,26 @@ export default { ...@@ -166,21 +185,26 @@ export default {
handleReturn() { handleReturn() {
this.status = '1' this.status = '1'
}, },
handleFinish() { handleFinish(isComplete) {
const selection = [] const selection = []
let isFinish = true let isFinish = true
for (let i = 0; i < this.questions.length; i++) { for (let i = 0; i < this.questions.length; i++) {
const item = this.questions[i] const item = this.questions[i]
if (item.selection.length) { if (item.selection.length) {
selection.push(item.selection[0].id) item.selection.forEach(it => selection.push(it.id))
// selection.push(item.selection[0].id)
} else { } else {
this.$message.error('请完成全部选题再提交')
isFinish = false isFinish = false
break if (isComplete) break
} }
} }
if (isFinish) { if (isComplete) {
this.fetchSubmitReport(selection) if (isFinish) this.fetchSubmitReport(selection)
else this.$message.error('请完成全部选题再提交')
} else {
console.log(selection)
if (selection.length > 0) this.fetchSaveReport(selection)
else this.$message.error('您并没有选中项需要保存')
} }
}, },
handleSubmit() { handleSubmit() {
...@@ -193,8 +217,8 @@ export default { ...@@ -193,8 +217,8 @@ export default {
selectItem = selection.find(it => it.question_id === item.id) selectItem = selection.find(it => it.question_id === item.id)
} }
if (selectItem) { if (selectItem) {
const opt = item.options.find(it => it.id === selectItem.id) const opt = item.options.filter(it => it.id === selectItem.id)
item.selection = [opt] item.selection = [...opt]
} else { } else {
item.selection = [] item.selection = []
} }
...@@ -205,18 +229,6 @@ export default { ...@@ -205,18 +229,6 @@ export default {
this.current.choice = this.questions[0] this.current.choice = this.questions[0]
}, },
fetchQuestions() { fetchQuestions() {
// getQuestions().then(res => {
// if (res.code === 0 && res.data && Array.isArray(res.data.items)) {
// const list = res.data.items
// list.forEach((item, index) => {
// item.selection = []
// item.index = index + 1
// })
// this.questions = list
// this.current.index = 0
// this.current.choice = this.questions[0]
// }
// })
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
getQuestions().then(res => { getQuestions().then(res => {
if (res.code === 0 && res.data && Array.isArray(res.data.items)) { if (res.code === 0 && res.data && Array.isArray(res.data.items)) {
...@@ -231,6 +243,7 @@ export default { ...@@ -231,6 +243,7 @@ export default {
const params = { const params = {
option_ids: JSON.stringify(list) option_ids: JSON.stringify(list)
} }
if (this.recordId) params.id = this.recordId
submitReport(params).then(res => { submitReport(params).then(res => {
if (res.data) { if (res.data) {
this.score = res.data.score this.score = res.data.score
...@@ -254,6 +267,16 @@ export default { ...@@ -254,6 +267,16 @@ export default {
// this.$message.error(err.message || '根据您选择的目标人群特征分析,此类受众并不适合当前的金融产品,请重新选择!') // this.$message.error(err.message || '根据您选择的目标人群特征分析,此类受众并不适合当前的金融产品,请重新选择!')
}) })
}, },
fetchSaveReport(list) {
const params = {
option_ids: JSON.stringify(list)
}
saveReport(this.case.id, params).then(res => {
if (res.code === 0) {
this.$message.success('保存成功!')
}
})
},
fetchClearScore() { fetchClearScore() {
clearScore().then(res => { clearScore().then(res => {
if (res.code === 0 && res.data && res.data.status) { if (res.code === 0 && res.data && res.data.status) {
...@@ -270,13 +293,24 @@ export default { ...@@ -270,13 +293,24 @@ export default {
}, },
fetchGetReport() { fetchGetReport() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
getReport().then(res => { if (this.recordId) {
if (res.code === 0 && res.data && res.data.records) { getReportDetails(this.recordId).then(res => {
resolve(res.data.records) if (res.code === 0 && res.data && res.data.detail) {
} else { resolve(res.data.detail)
reject(res) } else {
} reject(res)
}).catch((err) => reject(err)) }
}).catch((err) => reject(err))
} else {
getReportRecord(this.case.id, 3).then(res => {
if (res.code === 0 && res.data && Array.isArray(res.data.items)) {
if (res.data.items[0]) this.recordId = res.data.items[0].id
resolve(res.data.items[0])
} else {
reject(res)
}
})
}
}) })
} }
} }
......
import httpRequest from '@/utils/axios'
/** 获取产品分析记录 */
export function getProdRecords(params) {
return httpRequest.get('/api/xtraining/api/v1/answer/case-reports', { params })
}
/** 获取用户分析记录 */
export function getUserRecords(params) {
return httpRequest.get('/api/xtraining/api/v1/answer/user-analysis-reports', { params })
}
/** 获取营销工具记录 */
export function getToolRecords(params) {
return httpRequest.get('/api/xtraining/api/v1/answer/marketing-reports', { params })
}
...@@ -6,6 +6,10 @@ const routes = [ ...@@ -6,6 +6,10 @@ const routes = [
{ {
path: '', path: '',
component: () => import('./views/Index.vue') component: () => import('./views/Index.vue')
},
{
path: 'history',
component: () => import('./views/List.vue')
} }
] ]
} }
......
...@@ -4,33 +4,27 @@ ...@@ -4,33 +4,27 @@
<div class="container"> <div class="container">
<div class="product"> <div class="product">
产品分析报告 产品分析报告
<div class="btn-bar" v-if="case_status"> <div class="btn-bar">
<el-button type="primary" size="medium" plain round :disabled="[0, 2, 3].includes(role)" @click="handleGo(1)">编辑</el-button> <el-button type="primary" size="medium" plain round @click="handleGo(1)">查看成绩</el-button>
<el-button type="primary" size="medium" round :disabled="[0, 2, 3].includes(role)" @click="handleGo(2)">成绩</el-button>
</div> </div>
<p class="tips" v-else>您还未完成产品分析报告,<br>请先去完成吧!</p>
</div> </div>
<div class="user"> <div class="user">
用户分析报告 用户分析报告
<div class="btn-bar" v-if="user_analysis_status"> <div class="btn-bar">
<el-button type="primary" size="medium" plain round :disabled="[0, 1, 3].includes(role)" @click="handleGo(3, 1)">编辑</el-button> <el-button type="primary" size="medium" plain round @click="handleGo(2)">查看成绩</el-button>
<el-button type="primary" size="medium" round :disabled="[0, 1, 3].includes(role)" @click="handleGo(3, 3)">成绩</el-button>
</div> </div>
<p class="tips" v-else>您还未完成用户分析报告,<br>请先去完成吧!</p>
</div> </div>
<div class="tool"> <div class="tool">
营销工具使用 营销工具使用
<div class="btn-bar" v-if="marketing_status"> <div class="btn-bar">
<el-button type="primary" size="medium" plain round :disabled="[0, 1, 2].includes(role)" @click="handleGo(4)">编辑</el-button> <el-button type="primary" size="medium" plain round @click="handleGo(3)">查看成绩</el-button>
</div> </div>
<p class="tips" v-else>您还未完成营销工具使用,<br>请先去完成吧!</p>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { getWorkStatus } from '@/api/base'
export default { export default {
data() { data() {
return { return {
...@@ -45,29 +39,9 @@ export default { ...@@ -45,29 +39,9 @@ export default {
} }
} }
}, },
computed: {
role() {
return this.$store.state.role
}
},
created() {
this.fetchWorkStatus()
},
methods: { methods: {
handleGo(index, type) { handleGo(type) {
const path = this.navMap[index] this.$router.push({ path: 'works-show/history', query: { type } })
this.$router.push({ path, query: { type } })
},
fetchWorkStatus() {
getWorkStatus().then(res => {
if (res.code === 0 && res.data) {
this.case_status = res.data.case_status
this.marketing_status = res.data.marketing_status
this.user_analysis_status = res.data.user_analysis_status
}
}).catch(err => {
console.log(err)
})
} }
} }
} }
......
<template>
<div class="history">
<el-tabs v-model="tabActive" type="card" @tab-click="handleTabClick">
<el-tab-pane label="产品分析报告" name="1">
<el-table :data="prod.data" style="width: 100%" :header-row-style="{background:'#ededed',color:'#4d4d4d'}" :header-cell-style="{background: 'transparent'}">
<el-table-column type="index" :index="prod.tableIndex" label="序号" width="50" />
<el-table-column prop="case_info.name" label="案例名称" min-width="160" />
<el-table-column prop="score" label="分数" min-width="120" />
<el-table-column prop="updated_at" label="保存时间" min-width="160" />
<el-table-column label="操作" width="100">
<template slot-scope="scope">
<el-button @click="handleClick(scope.row)" type="text" size="small">{{scope.row.is_complete ? '查看' : '继续完成'}}</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination :current-page.sync="prod.page" layout="prev, pager, next" :total="prod.total" @current-change="fetchProdRecords"></el-pagination>
</div>
</el-tab-pane>
<el-tab-pane label="用户分析报告" name="2">
<el-table :data="user.data" style="width: 100%" :header-row-style="{background:'#ededed',color:'#4d4d4d'}" :header-cell-style="{background: 'transparent'}">
<el-table-column type="index" :index="user.tableIndex" label="序号" width="50" />
<el-table-column prop="case_info.name" label="案例名称" min-width="160" />
<el-table-column prop="score" label="分数" min-width="120" />
<el-table-column prop="updated_at" label="保存时间" min-width="160" />
<el-table-column label="操作" width="100">
<template slot-scope="scope">
<el-button @click="handleClick(scope.row)" type="text" size="small">{{scope.row.is_complete ? '查看' : '继续完成'}}</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination :current-page.sync="user.page" layout="prev, pager, next" :total="user.total" @current-change="fetchUserRecords"></el-pagination>
</div>
</el-tab-pane>
<el-tab-pane label="营销工具使用" name="3">
<el-table :data="tool.data" style="width: 100%" :header-row-style="{background:'#ededed',color:'#4d4d4d'}" :header-cell-style="{background: 'transparent'}">
<el-table-column type="index" :index="tool.tableIndex" label="序号" width="50" />
<el-table-column prop="case_info.name" label="案例名称" min-width="160" />
<el-table-column prop="score" label="分数" min-width="120" />
<el-table-column prop="updated_at" label="保存时间" min-width="160" />
<el-table-column label="操作" width="100">
<template slot-scope="scope">
<el-button @click="handleClick(scope.row)" type="text" size="small">{{scope.row.is_complete ? '查看' : '继续完成'}}</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination :current-page.sync="tool.page" layout="prev, pager, next" :total="tool.total" @current-change="fetchUserRecords"></el-pagination>
</div>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import { getProdRecords, getUserRecords, getToolRecords } from '../api'
export default {
data() {
return {
tabActive: '1',
prod: {
data: [],
total: 0,
page: 1,
limit: 10,
tableIndex: 1
},
user: {
data: [],
total: 0,
page: 1,
limit: 10,
tableIndex: 1
},
tool: {
data: [],
total: 0,
page: 1,
limit: 10,
tableIndex: 1
},
navMap: {
1: '/product-analysis/report',
2: '/product-analysis/result',
3: '/user-study',
4: '/market-tools/tool'
}
}
},
created() {
this.tabActive = this.$route.query.type
this.fetchProdRecords()
this.fetchUserRecords()
this.fetchToolRecords()
},
methods: {
handleTabClick() {
},
handleClick(val) {
switch (this.tabActive) {
case '1':
if (val.is_complete === 1) {
this.$router.push({ path: '/product-analysis/report', query: { id: val.id } })
} else this.$router.push({ path: '/product-analysis/result', query: { id: val.id } })
break
case '2':
const type = val.is_complete === 1 ? '3' : '1'
this.$router.push({ path: '/user-study', query: { id: val.id, type } })
break
case '3':
const _type = val.is_complete === 1 ? '1' : '0'
this.$router.push({ path: '/market-tools/tool', query: { id: val.id, type: _type } })
break
}
},
fetchProdRecords() {
const params = {
page: this.prod.page,
limit: this.prod.limit
}
this.prod.tableIndex = (this.prod.page - 1) * 10 + 1
getProdRecords(params).then(res => {
if (res.code === 0) {
this.prod.data = res.data.data
this.prod.total = res.data.total
}
})
},
fetchUserRecords() {
const params = {
page: this.user.page,
limit: this.user.limit
}
this.user.tableIndex = (this.user.page - 1) * 10 + 1
getUserRecords(params).then(res => {
if (res.code === 0) {
this.user.data = res.data.data
this.user.total = res.data.total
}
})
},
fetchToolRecords() {
const params = {
page: this.tool.page,
limit: this.tool.limit
}
this.tool.tableIndex = (this.tool.page - 1) * 10 + 1
getToolRecords(params).then(res => {
if (res.code === 0) {
this.tool.data = res.data.data
this.tool.total = res.data.total
}
})
}
}
}
</script>
<style scoped>
.history{
width:1260px;
padding-bottom:40px;
/* height:calc(100vh - 86px); */
margin:30px auto 0;
background:#fff;
padding:10px 30px;
}
.history ::v-deep.el-table .el-table__cell.gutter{
background:#ededed;
}
.pagination{
padding-top:7px;
text-align:right;
}
</style>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论