Commit 5c891193 authored by 赵茹林's avatar 赵茹林

团队概况 基本表格

webpack热加载优化
parent 206c0178
...@@ -21,15 +21,16 @@ module.exports = { ...@@ -21,15 +21,16 @@ module.exports = {
output: { output: {
path: config.build.assetsRoot, path: config.build.assetsRoot,
filename: '[name].js', filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production' publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
}, },
resolve: { resolve: {
extensions: ['.js', '.vue', '.json'], extensions: ['.js', '.vue', '.json'],
alias: { alias: {
'vue$': 'vue/dist/vue.esm.js', 'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'), '@': resolve('src'),
'@util': resolve('src/util'),
'@service': resolve('src/service'),
'@framework': resolve('src/components/framework'),
} }
}, },
module: { module: {
......
...@@ -34,14 +34,14 @@ const devWebpackConfig = merge(baseWebpackConfig, { ...@@ -34,14 +34,14 @@ const devWebpackConfig = merge(baseWebpackConfig, {
host: HOST || config.dev.host, host: HOST || config.dev.host,
port: PORT || config.dev.port, port: PORT || config.dev.port,
open: config.dev.autoOpenBrowser, open: config.dev.autoOpenBrowser,
overlay: config.dev.errorOverlay overlay: config.dev.errorOverlay ? { warnings: false, errors: true } : false,
? { warnings: false, errors: true }
: false,
publicPath: config.dev.assetsPublicPath, publicPath: config.dev.assetsPublicPath,
proxy: config.dev.proxyTable, proxy: config.dev.proxyTable,
quiet: true, // necessary for FriendlyErrorsPlugin quiet: true, // necessary for FriendlyErrorsPlugin
watchOptions: { watchOptions: {
poll: config.dev.poll, poll: config.dev.poll,
aggregateTimeout: 500,
ignored : ['static', 'dist', 'dev', 'node_modules', 'src/assets'],
} }
}, },
plugins: [ plugins: [
...@@ -84,9 +84,7 @@ module.exports = new Promise((resolve, reject) => { ...@@ -84,9 +84,7 @@ module.exports = new Promise((resolve, reject) => {
compilationSuccessInfo: { compilationSuccessInfo: {
messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`], messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
}, },
onErrors: config.dev.notifyOnErrors onErrors: config.dev.notifyOnErrors ? utils.createNotifierCallback() : undefined
? utils.createNotifierCallback()
: undefined
})) }))
resolve(devWebpackConfig) resolve(devWebpackConfig)
......
...@@ -33,7 +33,7 @@ module.exports = { ...@@ -33,7 +33,7 @@ module.exports = {
// Various Dev Server settings // Various Dev Server settings
host: getIP(), // can be overwritten by process.env.HOST host: getIP(), // can be overwritten by process.env.HOST
port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
autoOpenBrowser: false, autoOpenBrowser: true,
errorOverlay: true, errorOverlay: true,
notifyOnErrors: true, notifyOnErrors: true,
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
......
<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=referrer content=never><link rel=stylesheet href=https://at.alicdn.com/t/font_746649_x1rivf5f5.css><link rel=stylesheet href=https://lib.baomitu.com/element-ui/2.11.1/theme-chalk/index.css><title>唱唱启蒙-后台</title></head><body><script src=https://lib.baomitu.com/vue/2.5.17/vue.js></script><script src=https://lib.baomitu.com/vuex/3.0.1/vuex.min.js></script><script src=https://lib.baomitu.com/axios/0.18.0/axios.min.js></script><script src=https://lib.baomitu.com/element-ui/2.11.1/index.js></script><div id=app></div><script type=text/javascript src=/static/js/manifest.4fa8c3e44c5f2cb7e588.js></script><script type=text/javascript src=/static/js/vendor.fdfa49e267f48089768a.js></script><script type=text/javascript src=/static/js/app.771316ce36eae7e98b65.js></script></body><script>let el = document.getElementsByTagName("script");
el.onerror = function(a,b,c){
console.log('error:',a,b,c);
};
// document.getElementsByTagName('script').onerror</script></html>
\ No newline at end of file
...@@ -313,6 +313,14 @@ ...@@ -313,6 +313,14 @@
} }
} }
.table-refresh-header {
display: inline-block;
cursor: help;
i {
color: #409eff;
}
}
// 修复样式 // 修复样式
.el-tree-node__content { .el-tree-node__content {
.el-checkbox { .el-checkbox {
......
...@@ -23,9 +23,9 @@ ...@@ -23,9 +23,9 @@
<script> <script>
import headIndex from './headIndex' import headIndex from './headIndex'
import leftMenu from './leftMenu' import leftMenu from './leftMenu'
import tab from './tab' // import tab from './tab'
export default { export default {
components: {leftMenu, headIndex,tab}, components: {leftMenu, headIndex},
data(){ data(){
return { return {
transitionName: 'slide-left', transitionName: 'slide-left',
......
...@@ -85,7 +85,7 @@ ...@@ -85,7 +85,7 @@
<script> <script>
import {addPeriodsClassUserDescApi,getUserDescListApi,editUserReplyApi} from "../../service/api"; import {addPeriodsClassUserDescApi,getUserDescListApi,editUserReplyApi} from "../../service/api";
import CallBack from '@/components/callBack/index'; import CallBack from '@/components/userDetail/callBack';
export default { export default {
name: "teacherDesc", name: "teacherDesc",
......
...@@ -6,10 +6,10 @@ ...@@ -6,10 +6,10 @@
</div> </div>
<div class="subcompany-list"> <div class="subcompany-list">
<div class="subcompany-list-content" v-if="subcompanyList.length > 0"> <div class="subcompany-list-content" v-if="subcompanyList.length > 0">
<el-form :inline="true" v-for="item in subcompanyList" class="demo-form-inline" size="mini"> <el-form :inline="true" :key="item.id" v-for="item in subcompanyList" class="demo-form-inline" size="mini">
<el-form-item label="销售层级"> <el-form-item label="销售层级">
<el-select v-model="item.sale_level" @change="modifyLevel(item.id, item.sale_level)" @focus="focusOldVal(item.sale_level)" placeholder="销售层级"> <el-select v-model="item.sale_level" @change="modifyLevel(item.id, item.sale_level)" @focus="focusOldVal(item.sale_level)" placeholder="销售层级">
<el-option v-for="itemSale in saleLevel" :label="itemSale.label" :value="itemSale.value"></el-option> <el-option :key="itemSale.value" v-for="itemSale in saleLevel" :label="itemSale.label" :value="itemSale.value"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="级别名称"> <el-form-item label="级别名称">
......
<template>
<div class="admin-refresh">
<el-tabs v-model="search.team" type="card" class="tabs-refresh" @tab-click="getData">
<el-tab-pane label="总计" name=""/>
<el-tab-pane v-for="i in 10" :key="i" :label="'T'+i" :name="i.toString()"/>
</el-tabs>
<el-table class="team-table" border size="small" :data="list" v-loading="loading">
<el-table-column label="组别" width="50px">
<template slot-scope="scope">{{`T${scope.row.squad}`}}</template>
</el-table-column>
<el-table-column prop="staff_name" label="销售顾问"></el-table-column>
<el-table-column prop="reach_class_num">
<template slot="header" slot-scope="scope">
<el-tooltip effect="dark" :content="TIP_TEAM['reach_class_num']" placement="top">
<span class="table-refresh-header">
30 <i class="el-icon-question"></i><br>到班
</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="reach_course_num">
<template slot="header" slot-scope="scope">
<el-tooltip effect="dark" :content="TIP_TEAM['reach_course_num']" placement="top">
<span class="table-refresh-header">
30 <i class="el-icon-question"></i><br>到课
</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="wait_add_friend">
<template slot="header" slot-scope="scope">
<el-tooltip effect="dark" :content="TIP_TEAM['wait_add_friend']" placement="top">
<span class="table-refresh-header">
7 <i class="el-icon-question"></i><br>待添
</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="wait_visit_num">
<template slot="header" slot-scope="scope">
<el-tooltip effect="dark" :content="TIP_TEAM['wait_visit_num']" placement="top">
<span class="table-refresh-header">
当日 <i class="el-icon-question"></i><br>待回访
</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="over_visit_num">
<template slot="header" slot-scope="scope">
<el-tooltip effect="dark" :content="TIP_TEAM['over_visit_num']" placement="top">
<span class="table-refresh-header">
当日 <i class="el-icon-question"></i><br>已回访
</span>
</el-tooltip>
</template>
<template slot-scope="scope">
<el-link @click="dialogToggle">{{scope.row.over_visit_num}}</el-link>
</template>
</el-table-column>
<el-table-column prop="chat_contact_count">
<template slot="header" slot-scope="scope">
<el-tooltip effect="dark" :content="TIP_TEAM['chat_contact_count']" placement="top">
<span class="table-refresh-header">
当日 <i class="el-icon-question"></i><br>微信沟
</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="valid_chat_contact_count">
<template slot="header" slot-scope="scope">
<el-tooltip effect="dark" :content="TIP_TEAM['valid_chat_contact_count']" placement="top">
<span class="table-refresh-header">
当日 <i class="el-icon-question"></i><br>微信有效沟
</span>
</el-tooltip>
</template>
<template slot-scope="scope">
<el-link @click="dialogToggle">{{scope.row.valid_chat_contact_count}}</el-link>
</template>
</el-table-column>
<el-table-column prop="valid_phone_counts">
<template slot="header" slot-scope="scope">
<el-tooltip effect="dark" :content="TIP_TEAM['valid_phone_counts']" placement="top">
<span class="table-refresh-header">
当日 <i class="el-icon-question"></i><br>有效通
</span>
</el-tooltip>
</template>
<template slot-scope="scope">
<el-link @click="dialogToggle">{{scope.row.valid_phone_counts}}</el-link>
</template>
</el-table-column>
<el-table-column prop="phone_total_time">
<template slot="header" slot-scope="scope">
<!--TODO-->
<el-tooltip effect="dark" :content="TIP_TEAM['phone_total_time']" placement="top">
<span class="table-refresh-header">
当日 <i class="el-icon-question"></i><br>有效通
</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="lately_class_num">
<template slot="header" slot-scope="scope">
<el-tooltip effect="dark" :content="TIP_TEAM['lately_class_num']" placement="top">
<span class="table-refresh-header">
未来7 <i class="el-icon-question"></i><br>开课班
</span>
</el-tooltip>
</template>
<template slot-scope="scope">
<el-link @click="dialogToggle">{{scope.row.lately_class_num}}</el-link>
</template>
</el-table-column>
<el-table-column prop="month_order_num">
<template slot="header" slot-scope="scope">
<el-tooltip effect="dark" :content="TIP_TEAM['month_order_num']" placement="top">
<span class="table-refresh-header">
当月 <i class="el-icon-question"></i><br>订
</span>
</el-tooltip>
</template>
<template slot-scope="scope">
<el-link @click="dialogToggle">{{scope.row.month_order_num}}</el-link>
</template>
</el-table-column>
<el-table-column prop="month_order_rate">
<template slot="header" slot-scope="scope">
<el-tooltip effect="dark" :content="TIP_TEAM['month_order_rate']" placement="top">
<span class="table-refresh-header">
当月 <i class="el-icon-question"></i><br>平均转
</span>
</el-tooltip>
</template>
<template slot-scope="scope">
<el-link @click="dialogToggle">{{scope.row.month_order_rate}}</el-link>
</template>
</el-table-column>
<el-table-column prop="order_money_count">
<template slot="header" slot-scope="scope">
<el-tooltip effect="dark" :content="TIP_TEAM['order_money_count']" placement="top">
<span class="table-refresh-header">
当月 <i class="el-icon-question"></i><br>总业
</span>
</el-tooltip>
</template>
<template slot-scope="scope">
<el-link @click="dialogToggle">{{scope.row.order_money_count}}</el-link>
</template>
</el-table-column>
</el-table>
<page :total="total" :limit="limit" @pageChange="onPageChange" @sizeChange="onSizeChange"/>
</div>
</template>
<script>
import page from '@framework/page'
import {getTeamApi} from '@service/api';
import {TIP_TEAM} from '@util/tipArr';
export default {
name: "index",
components: {page},
data() {
return {
TIP_TEAM: TIP_TEAM,
loading: true,
search: {
team: '1'
},
list: [],
total: 0,
nowPage: 1,
limit: 10,
}
},
mounted() {
this.getData();
},
methods: {
dialogToggle() {
},
getData() {
this.loading = true;
let json = {
team: this.search.team
}
getTeamApi(json).then(res => {
this.list = res.page_data;
this.total = res.total;
this.loading = false;
})
},
onPageChange(val) {
this.nowPage = val
this.getData()
},
onSizeChange(val) {
this.limit = val;
this.nowPage = 1;
this.getData()
},
},
}
</script>
<style lang="less">
.team-table {
.el-link {
font-weight: normal;
text-decoration: underline;
}
}
</style>
...@@ -525,7 +525,7 @@ ...@@ -525,7 +525,7 @@
import {INVITETYPE, ORDERSTATUS, BUYTYPE, USERSTATUSFORMATER} from "../../util/wordbook"; import {INVITETYPE, ORDERSTATUS, BUYTYPE, USERSTATUSFORMATER} from "../../util/wordbook";
import teacherDialog from './dialog' import teacherDialog from './dialog'
import UserList from '../class/userList' import UserList from '../class/userList'
import CallBack from '@/components/callBack/index' import CallBack from '@/components/userDetail/callBack';
import sourceByDateDialog from '../teacherDetail/sourceByDateDialog' import sourceByDateDialog from '../teacherDetail/sourceByDateDialog'
import AddressArray from "../framework/address-picker/addr"; import AddressArray from "../framework/address-picker/addr";
......
...@@ -6,7 +6,7 @@ import router from './router' ...@@ -6,7 +6,7 @@ import router from './router'
import store from './store' import store from './store'
import element_ui from 'element-ui' import element_ui from 'element-ui'
Vue.use(element_ui); Vue.use(element_ui);
Vue.config.productionTip = false Vue.config.productionTip = false;
/* eslint-disable no-new */ /* eslint-disable no-new */
new Vue({ new Vue({
......
...@@ -1469,3 +1469,7 @@ export const putBrokerageApi = function (id, json) { ...@@ -1469,3 +1469,7 @@ export const putBrokerageApi = function (id, json) {
export const deleteBrokerageApi = function (id) { export const deleteBrokerageApi = function (id) {
return Vue.prototype.$del(`${_baseUrl}api/admin/bkge/config/${id}`) return Vue.prototype.$del(`${_baseUrl}api/admin/bkge/config/${id}`)
}; };
// 获取团队概况
export const getTeamApi = function (json) {
return Vue.prototype.$fetch(`${_baseUrl}api/admin/teacher/teamprofile`, json)
};
...@@ -185,6 +185,16 @@ export default [ ...@@ -185,6 +185,16 @@ export default [
name: 'brokerage', name: 'brokerage',
component: e => require(['@/components/brokerage'], e), component: e => require(['@/components/brokerage'], e),
} }
}, {
value: '团队概况',
routerName: 'team',
path: '/team',
cover: '11-9',
router: {
path: '/team',
name: 'team',
component: e => require(['@/components/team'], e),
}
}, },
] ]
}, { }, {
......
export const tipArr = { export const tipArr = {
'到课率':'浏览过一次及以上课包的人数/学员人数;不含观摩班', '到课率': '浏览过一次及以上课包的人数/学员人数;不含观摩班',
'看课率':'(课包浏览数量*看课学员数)/(已解锁课包数*学员人数);不含观摩班', '看课率': '(课包浏览数量*看课学员数)/(已解锁课包数*学员人数);不含观摩班',
'完课率':'浏览过所有课包的人数/学员人数;不含观摩班', '完课率': '浏览过所有课包的人数/学员人数;不含观摩班',
'打卡率':'完成过一次及以上课包分享的人数/学员数;不含观摩班', '打卡率': '完成过一次及以上课包分享的人数/学员数;不含观摩班',
'全勤打卡率':'完成过所有课包分享的人数/学员数;不含观摩班', '全勤打卡率': '完成过所有课包分享的人数/学员数;不含观摩班',
'转化率':'晚于体验营开课时间的正式课购课学员数量/学员数;不含观摩班', '转化率': '晚于体验营开课时间的正式课购课学员数量/学员数;不含观摩班',
}; };
export const tipArr2 = { export const tipArr2 = {
'订单数':'支付成功且未全额退款的订单数量(*月课、季课全勤返现完成的订单也会排除)', '订单数': '支付成功且未全额退款的订单数量(*月课、季课全勤返现完成的订单也会排除)',
'到班数':'进入系统课程期数班级的学员数量', '到班数': '进入系统课程期数班级的学员数量',
'到班率':'到班数/订单数', '到班率': '到班数/订单数',
'好友数':'班主任在系统内标注用已成为微信好友的户数量,包含老师主动添加数和用户主动添加数', '好友数': '班主任在系统内标注用已成为微信好友的户数量,包含老师主动添加数和用户主动添加数',
'到课数':'浏览过一次及以上课包的人数', // '到课数':'浏览过一次及以上课包的人数',
'好友率':'好友数/订单数', '好友率': '好友数/订单数',
'到课数':'浏览过一次及以上课包的人数', '到课数': '浏览过一次及以上课包的人数',
'到课率':'到课数/订单数', '到课率': '到课数/订单数',
'转化人数':'购买一年课、两年课且未全额退款的人数(*个别退课但未全额退款的学员包含在内)', '转化人数': '购买一年课、两年课且未全额退款的人数(*个别退课但未全额退款的学员包含在内)',
'转化率':'转化人数/订单数', '转化率': '转化人数/订单数',
'一年课购买人数':'购买一年课且未全额退款的人数', '一年课购买人数': '购买一年课且未全额退款的人数',
'两年课购买人数':'购买两年课且未全额退款的人数', '两年课购买人数': '购买两年课且未全额退款的人数',
'转化总额':'一年课和两年课的转化金额合计', '转化总额': '一年课和两年课的转化金额合计',
'一年课转化金额':'购买一年课且未全额退款的订单实付金额(云集订单为商品金额,不扣除优惠券、抵现)', '一年课转化金额': '购买一年课且未全额退款的订单实付金额(云集订单为商品金额,不扣除优惠券、抵现)',
'两年课转化金额':'购买两年课且未全额退款的订单实付金额(云集订单为商品金额,不扣除优惠券、抵现)', '两年课转化金额': '购买两年课且未全额退款的订单实付金额(云集订单为商品金额,不扣除优惠券、抵现)',
}; };
export const tipArr3 = { export const tipArr3 = {
'到班数':'进入系统课程期数班级的学员数量', '到班数': '进入系统课程期数班级的学员数量',
'好友数':'班主任在系统内标注用已成为微信好友的户数量,包含老师主动添加数和用户主动添加数', '好友数': '班主任在系统内标注用已成为微信好友的户数量,包含老师主动添加数和用户主动添加数',
'到课数':'浏览过一次及以上课包的人数', // '到课数':'浏览过一次及以上课包的人数',
'好友率':'好友数/到班数', '好友率': '好友数/到班数',
'到课数':'浏览过一次及以上课包的人数', '到课数': '浏览过一次及以上课包的人数',
'到课率':'到课数/到班数', '到课率': '到课数/到班数',
'转化人数':'购买一年课、两年课且未全额退款的人数(*个别退课但未全额退款的学员包含在内)', '转化人数': '购买一年课、两年课且未全额退款的人数(*个别退课但未全额退款的学员包含在内)',
'转化率':'转化人数/到班数', '转化率': '转化人数/到班数',
'一年课购买人数':'购买一年课且未全额退款的人数', '一年课购买人数': '购买一年课且未全额退款的人数',
'两年课购买人数':'购买两年课且未全额退款的人数', '两年课购买人数': '购买两年课且未全额退款的人数',
'转化总额':'一年课和两年课的转化金额合计', '转化总额': '一年课和两年课的转化金额合计',
'一年课转化金额':'购买一年课且未全额退款的订单实付金额(云集订单为商品金额,不扣除优惠券、抵现)', '一年课转化金额': '购买一年课且未全额退款的订单实付金额(云集订单为商品金额,不扣除优惠券、抵现)',
'两年课转化金额':'购买两年课且未全额退款的订单实付金额(云集订单为商品金额,不扣除优惠券、抵现)', '两年课转化金额': '购买两年课且未全额退款的订单实付金额(云集订单为商品金额,不扣除优惠券、抵现)',
};
export const TIP_TEAM = {
'reach_class_num': '近30天,进入系统课程期数班级的学员数', // 到班数
'reach_course_num': '近30天,浏览过1次以上课件的学员数', // 到课数
'wait_add_friend': '近7天,到班,但没有添加好友', // 待添加
'wait_visit_num': '当天待回访的学员数(标记了回访日期,回访日期=查询日,且没有回访行为)', // 待回访
'over_visit_num': '当天做了回访的学员数', // 已回访
'chat_contact_count': '当天CC在微信中发出去的信息条数(不包括群)', // 微信沟通
'valid_chat_contact_count': '当天CC在微信1对1沟通中有1轮以上回复的条数(CC发出一条,客户回复一条)', // 微信有效沟通
'valid_phone_counts': '当天接通的电话次数', // 有效通次
'phone_total_time': '当天接通的电话通时,格式为hms,小时分钟秒', // 有效通时
'lately_class_num': '当天往后推7自然日内,关联到该CC的开期的班的数量', // 未来开课
'month_order_num': '年、两年课的订单总和(除去全额退款的)', // 当月订单
'month_order_rate': '当月订单数/当月到班人数', // 当月转化
'order_money_count': '当月一年、两年课的业绩(减掉全额退款的)', // 当月业绩
}; };
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment