2025-05-18

This commit is contained in:
lcc
2025-05-18 20:48:52 +08:00
parent 9f2b535dde
commit e10f47f18a
23 changed files with 888 additions and 1192 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
VUE_APP_NAME=Ele Admin
VUE_APP_NAME=后台管理
VUE_APP_API_BASE_URL=https://v2.eleadmin.com/api
+46 -65
View File
@@ -63,7 +63,7 @@
export default {
name: 'CarModelSelector',
props: {
modelValue: {
value: {
type: Object,
default: () => ({
brandId: null,
@@ -80,11 +80,7 @@
},
data() {
return {
form: {
brandId: null,
seriesId: null,
modelId: null
},
form: { ...this.value }, // 初始化时深拷贝value,
brandList: [],
seriesList: [],
modelList: [],
@@ -94,43 +90,22 @@
brandFilter: ''
};
},
watch: {
modelValue: {
deep: true,
handler(newVal) {
console.log(newVal);
this.form = { ...newVal };
this.syncFormWithProps();
}
},
'$props.modelValue': {
handler() {
this.syncFormWithProps();
}
},
'form.brandId'(val) {
this.emitValue();
if (!val) {
this.seriesList = [];
this.modelList = [];
this.form.seriesId = null;
this.form.modelId = null;
}
},
'form.seriesId'(val) {
this.emitValue();
if (!val) this.modelList = this.form.modelId = null;
},
'form.modelId': {
handler() {
this.emitValue();
},
immediate: true
}
},
created() {
this.loadBrands();
this.syncFormWithProps();
if (this.form.brandId) {
this.loadSeriesList(this.form.brandId);
}
if (this.form.seriesId) {
this.loadModelList(this.form.seriesId);
}
},
watch: {
value: {
deep: true,
handler(newVal) {
this.form = { ...newVal }; // 外部值变化时更新内部form
}
}
},
methods: {
async loadBrands(filter = '') {
@@ -138,6 +113,8 @@
try {
const res = await pageBrand({ nameLike: filter });
this.brandList = res;
this.seriesList = [];
this.modelList = [];
} catch (error) {
this.$message.error('品牌加载失败');
} finally {
@@ -150,7 +127,7 @@
try {
const res = await pageSeries({ brandId });
this.seriesList = res;
this.form.seriesId = null;
this.modelList = [];
} catch (error) {
this.$message.error('车系加载失败');
} finally {
@@ -163,7 +140,6 @@
try {
const res = await pageAutoCar({ seriesId });
this.modelList = res;
this.form.modelId = null;
} catch (error) {
this.$message.error('车型加载失败');
} finally {
@@ -172,41 +148,46 @@
},
handleBrandChange(brandId) {
if (brandId) this.loadSeriesList(brandId);
if (brandId) {
this.form.seriesId = null;
this.loadSeriesList(brandId);
}
this.emitValue();
},
handleSeriesChange(seriesId) {
if (seriesId) this.loadModelList(seriesId);
if (seriesId) {
this.form.modelId = null;
this.loadModelList(seriesId);
}
this.emitValue();
},
handleModelChange() {
this.emitValue();
},
handleModelChange() {},
handleBrandFilter(filter) {
this.brandFilter = filter;
this.loadBrands(filter);
},
emitValue() {
this.$emit('update:modelValue', {
brandId: this.form.brandId,
seriesId: this.form.seriesId,
modelId: this.form.modelId
});
this.$emit('input', { ...this.form });
},
syncFormWithProps() {
// 重置所有数据
this.brandList = [];
this.seriesList = [];
this.modelList = [];
const { brandId, seriesId, modelId } = this.modelValue;
this.form = { brandId, seriesId, modelId };
if (brandId) {
this.loadSeriesList(brandId);
if (seriesId) {
this.loadModelList(seriesId);
}
}
// this.brandList = [];
// this.seriesList = [];
// this.modelList = [];
//
// const { brandId, seriesId, modelId } = this.modelValue;
// this.form = { brandId, seriesId, modelId };
//
// if (brandId) {
// this.loadSeriesList(brandId);
// if (seriesId) {
// this.loadModelList(seriesId);
// }
// }
}
}
};
@@ -165,6 +165,29 @@
v-model="form.descript"
/>
</el-form-item>
<el-form-item label="推广文案:">
<div
style="margin: 8px 0"
v-for="(item, index) in form.promotion_text"
:key="index"
>
<el-input
clearable
:maxlength="60"
v-model="form.promotion_text[index]"
placeholder="请输入推广文案"
/>
</div>
<el-button
type="primary"
plain
size="small"
icon="el-icon-plus"
@click="addShareTitle"
>
新增推广文案
</el-button>
</el-form-item>
</el-form>
<template v-slot:footer>
<el-button @click="updateVisible(false)">取消</el-button>
@@ -301,6 +324,10 @@
/* 更新visible */
updateVisible(value) {
this.$emit('update:visible', value);
},
/* 添加海报描述 */
addShareTitle() {
this.form.promotion_text.push('');
}
},
watch: {
@@ -313,6 +340,9 @@
...this.data
});
this.isUpdate = true;
if (this.form.promotion_text.length <= 0) {
this.addShareTitle();
}
} else {
this.form.imgs = [];
this.isUpdate = false;
@@ -325,7 +355,7 @@
}
};
</script>
<style>
<style lang="scss" scoped>
.ele-image-upload-list .ele-image-upload-item {
margin-top: 2px;
margin-bottom: 2px;
+20 -7
View File
@@ -16,8 +16,7 @@
<el-col :md="24" :sm="24">
<car-model-selector
type="brandSeries"
v-model="this.where.selectedCar"
@update:modelValue="handleCarChange"
v-model="where.selectedCar"
:key="componentKey"
/>
</el-col>
@@ -67,11 +66,10 @@
</template>
<!-- 状态列 -->
<template v-slot:title="{ row }">
<el-image
style="width: 80px; height: 80px"
:src="row.imgs[0]['url']"
></el-image>
{{ row.title }}
<div class="cell-content">
<el-image :src="row.imgs[0]['url']" class="table-image" />
<span class="table-text">{{ row.title }}</span>
</div>
</template>
<template v-slot:status="{ row }">
<el-switch
@@ -296,3 +294,18 @@
}
};
</script>
<style scoped>
.cell-content {
display: flex;
align-items: center;
}
.table-image {
width: 80px;
height: 80px;
margin-right: 5px;
}
.table-text {
/* 文本样式 */
overflow: hidden;
}
</style>
@@ -1,73 +0,0 @@
<template>
<el-card shadow="never" header="热门搜索">
<v-chart
ref="hotSearchChart"
style="height: 303px"
:option="hotSearchChartOption"
/>
</el-card>
</template>
<script>
import { use } from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
import { TooltipComponent } from 'echarts/components';
import VChart from 'vue-echarts';
import 'echarts-wordcloud';
import { wordCloudColor } from 'ele-admin';
import { getWordCloudList } from '@/api/dashboard/analysis';
import { echartsMixin } from '@/utils/echarts-mixin';
use([CanvasRenderer, TooltipComponent]);
export default {
components: { VChart },
mixins: [echartsMixin(['hotSearchChart'])],
data() {
return {
// 词云图表配置
hotSearchChartOption: {}
};
},
created() {
this.getWordCloudData();
},
methods: {
/* 获取词云数据 */
getWordCloudData() {
getWordCloudList()
.then((data) => {
this.hotSearchChartOption = {
tooltip: {
show: true,
confine: true,
borderWidth: 1
},
series: [
{
type: 'wordCloud',
width: '100%',
height: '100%',
sizeRange: [12, 24],
gridSize: 6,
textStyle: {
color: wordCloudColor
},
emphasis: {
textStyle: {
shadowBlur: 8,
shadowColor: 'rgba(0, 0, 0, .15)'
}
},
data: data
}
]
};
})
.catch((e) => {
this.$message.error(e.message);
});
}
}
};
</script>
@@ -0,0 +1,119 @@
<!-- 用户信息 -->
<template>
<el-card shadow="never" body-style="padding: 20px;">
<div
:class="[
'ele-cell',
'workplace-user-card',
{ 'workplace-user-responsive': styleResponsive }
]"
>
<div class="ele-cell-content ele-cell">
<!--
<el-avatar :size="68" :src="loginUser.avatar" />
-->
<div class="ele-cell-content">
<h4 class="ele-elip"> Hi, {{ loginUser.nickname }} , 您好! </h4>
<!--
<div class="ele-text-secondary ele-elip" style="margin-top: 8px">
<i class="el-icon-heavy-rain"></i>
<em>今日阴转小雨, 22 - 32 , 出门记得带伞哦</em>
</div>
-->
</div>
</div>
<!--
<div class="workplace-count-group">
<div class="workplace-count-item">
<div class="workplace-count-header">
<el-tag size="small" class="ele-tag-round">
<i class="el-icon-menu"></i>
</el-tag>
<span class="workplace-count-name">项目数</span>
</div>
<div class="workplace-count-num ele-text-heading">3</div>
</div>
<div class="workplace-count-item">
<div class="workplace-count-header">
<el-tag type="warning" size="small" class="ele-tag-round">
<i class="el-icon-finished"></i>
</el-tag>
<span class="workplace-count-name">待办项</span>
</div>
<div class="workplace-count-num ele-text-heading">6 / 24</div>
</div>
<div class="workplace-count-item">
<div class="workplace-count-header">
<el-tag type="success" size="small" class="ele-tag-round">
<i class="el-icon-bell"></i>
</el-tag>
<span class="workplace-count-name">消息</span>
</div>
<div class="workplace-count-num ele-text-heading">1,689</div>
</div>
</div>
-->
</div>
</el-card>
</template>
<script>
export default {
computed: {
// 当前登录用户信息
loginUser() {
return this.$store.state.user.info;
},
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
}
};
</script>
<style lang="scss" scoped>
.workplace-user-card {
.ele-cell-content {
overflow: hidden;
}
.workplace-count-group {
white-space: nowrap;
}
.workplace-count-item {
padding: 0 5px 0 25px;
box-sizing: border-box;
display: inline-block;
text-align: right;
}
.workplace-count-name {
padding-left: 8px;
}
.workplace-count-num {
font-size: 24px;
margin-top: 6px;
}
}
@media screen and (max-width: 992px) {
.workplace-user-responsive .workplace-count-item {
padding: 0 5px 0 10px;
}
}
@media screen and (max-width: 768px) {
.workplace-user-responsive.workplace-user-card {
display: block;
.workplace-count-group {
display: block;
margin-top: 15px;
text-align: right;
}
}
}
</style>
@@ -1,210 +0,0 @@
<template>
<el-card shadow="never" body-style="padding: 0;">
<div class="ele-cell demo-monitor-tool">
<div class="ele-cell-content">
<el-tabs
v-model="saleSearch.type"
class="demo-monitor-tabs"
@tab-click="onSaleTypeChange"
>
<el-tab-pane label="销售额" name="saleroom" />
<el-tab-pane label="访问量" name="visits" />
</el-tabs>
</div>
<div :class="['ele-inline-block', { 'hidden-xs-only': styleResponsive }]">
<el-radio-group v-model="saleSearch.dateType" size="small">
<el-radio-button :label="0">今天</el-radio-button>
<el-radio-button :label="1">本周</el-radio-button>
<el-radio-button :label="2">本月</el-radio-button>
<el-radio-button :label="3">本年</el-radio-button>
</el-radio-group>
</div>
<div
:class="['ele-inline-block', { 'hidden-sm-and-down': styleResponsive }]"
style="width: 260px; margin-left: 10px"
>
<el-date-picker
unlink-panels
type="daterange"
class="ele-fluid"
end-placeholder="结束日期"
start-placeholder="开始日期"
v-model="saleSearch.datetime"
range-separator=""
size="small"
/>
</div>
</div>
<el-divider />
<el-row>
<el-col v-bind="styleResponsive ? { lg: 18, md: 16 } : { span: 18 }">
<div class="demo-monitor-title">
<span v-if="saleSearch.type === 'saleroom'">销售额趋势</span>
<span v-else>访问量趋势</span>
</div>
<v-chart
ref="saleChart"
style="height: 285px"
:option="saleChartOption"
/>
</el-col>
<el-col v-bind="styleResponsive ? { lg: 6, md: 8 } : { span: 6 }">
<div class="demo-monitor-title" style="display: flex">
<div>门店</div>
<div>
<span v-if="saleSearch.type === 'saleroom'">销售额</span>
<span v-else>访问量</span>
</div>
<div>排名</div>
</div>
<div
v-for="(item, index) in saleroomRankData"
:key="index"
class="demo-monitor-rank-item ele-cell"
style="margin-bottom: 15px"
>
<el-tag
size="mini"
type="info"
:effect="index < 3 ? 'dark' : 'light'"
:color="index < 3 ? '#314659' : 'hsla(0, 0%, 60%, .2)'"
style="border-color: transparent"
class="ele-tag-round"
>
{{ index + 1 }}
</el-tag>
<div class="ele-cell-content">{{ item.name }}</div>
<div class="ele-text-secondary">{{ item.value }}</div>
</div>
</el-col>
</el-row>
</el-card>
</template>
<script>
import { use } from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
import { BarChart } from 'echarts/charts';
import { GridComponent, TooltipComponent } from 'echarts/components';
import VChart from 'vue-echarts';
import { getSaleroomList } from '@/api/dashboard/analysis';
import { echartsMixin } from '@/utils/echarts-mixin';
use([CanvasRenderer, BarChart, GridComponent, TooltipComponent]);
export default {
components: { VChart },
mixins: [echartsMixin(['saleChart'])],
data() {
return {
// 销售量搜索参数
saleSearch: {
type: 'saleroom',
dateType: 0,
datetime: ''
},
// 销售量趋势数据
saleroomData1: [],
// 访问量趋势数据
saleroomData2: [],
// 门店排名数据
saleroomRankData: [
{ name: '工专路 1 号店', value: '323,234' },
{ name: '工专路 2 号店', value: '323,234' },
{ name: '工专路 3 号店', value: '323,234' },
{ name: '工专路 4 号店', value: '323,234' },
{ name: '工专路 5 号店', value: '323,234' },
{ name: '工专路 6 号店', value: '323,234' },
{ name: '工专路 7 号店', value: '323,234' }
],
// 销售额柱状图配置
saleChartOption: {}
};
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
},
created() {
this.getSaleroomData();
},
methods: {
/* 获取销售量数据 */
getSaleroomData() {
getSaleroomList()
.then((data) => {
this.saleroomData1 = data.list1;
this.saleroomData2 = data.list2;
this.onSaleTypeChange();
})
.catch((e) => {
this.$message.error(e.message);
});
},
/* 销售量tab选择改变事件 */
onSaleTypeChange() {
const isSale = this.saleSearch.type === 'saleroom';
const data = isSale ? this.saleroomData1 : this.saleroomData2;
this.saleChartOption = {
tooltip: {
trigger: 'axis'
},
xAxis: [
{
type: 'category',
data: data.map((d) => d.month)
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
type: 'bar',
data: data.map((d) => d.value)
}
]
};
}
}
};
</script>
<style lang="scss" scoped>
/* 销售额、访问量工具栏 */
.demo-monitor-tool {
padding: 0 20px;
.demo-monitor-tabs {
height: 51px;
}
:deep(.el-tabs__item) {
height: 51px;
line-height: 51px;
font-size: 15px;
}
:deep(.el-tabs__nav-wrap:after) {
display: none;
}
}
/* 小标题 */
.demo-monitor-title {
padding: 0 20px;
margin: 15px 0 5px 0;
}
/* 排名 item */
.demo-monitor-rank-item {
padding: 0 20px;
line-height: 20px;
margin-top: 18px;
}
</style>
@@ -5,99 +5,33 @@
<el-card class="analysis-chart-card" shadow="never">
<template v-slot:header>
<div class="ele-cell">
<div class="ele-cell-content">总销售额</div>
<el-tooltip content="指标说明" placement="top">
<i
class="el-icon-_question ele-text-placeholder"
style="cursor: pointer"
>
</i>
</el-tooltip>
</div>
</template>
<div class="analysis-chart-card-num ele-text-heading">¥ 126,560</div>
<div class="analysis-chart-card-content" style="padding-top: 18px">
<span class="ele-action">
<span>周同比12%</span>
<i class="el-icon-caret-top ele-text-danger"></i>
</span>
<span class="ele-action">
<span>日同比11%</span>
<i class="el-icon-caret-bottom ele-text-success"></i>
</span>
</div>
<el-divider />
<div class="analysis-chart-card-text">日销售额 ¥12,423</div>
</el-card>
</el-col>
<el-col v-bind="styleResponsive ? { lg: 6, md: 12 } : { span: 6 }">
<el-card class="analysis-chart-card" shadow="never">
<template v-slot:header>
<div class="ele-cell">
<div class="ele-cell-content">访问量</div>
<div class="ele-cell-content">今日新增线索</div>
<el-tag size="mini" type="danger"></el-tag>
</div>
</template>
<div class="analysis-chart-card-num ele-text-heading">8,846</div>
<div class="analysis-chart-card-content">
<v-chart
ref="visitChart"
style="height: 40px"
:option="visitChartOption"
/>
</div>
<div
class="analysis-chart-card-num ele-text-heading"
style="margin-bottom: 10px"
>101</div
>
<el-divider />
<div class="analysis-chart-card-text">日访问量 1,234</div>
<div class="analysis-chart-card-text">累计线索100000</div>
</el-card>
</el-col>
<el-col v-bind="styleResponsive ? { lg: 6, md: 12 } : { span: 6 }">
<el-card class="analysis-chart-card" shadow="never">
<template v-slot:header>
<div class="ele-cell">
<div class="ele-cell-content">支付笔数</div>
<el-tag size="mini"></el-tag>
<div class="ele-cell-content">当前团队成员</div>
</div>
</template>
<div class="analysis-chart-card-num ele-text-heading">6,560</div>
<div class="analysis-chart-card-content">
<v-chart
ref="payNumChart"
style="height: 40px"
:option="payNumChartOption"
/>
</div>
<div
class="analysis-chart-card-num ele-text-heading"
style="margin-bottom: 10px"
>2323</div
>
<el-divider />
<div class="analysis-chart-card-text">转化率 60%</div>
</el-card>
</el-col>
<el-col v-bind="styleResponsive ? { lg: 6, md: 12 } : { span: 6 }">
<el-card class="analysis-chart-card" shadow="never">
<template v-slot:header>
<div class="ele-cell">
<div class="ele-cell-content">运营活动效果</div>
<el-tag size="mini" type="success"></el-tag>
</div>
</template>
<div class="analysis-chart-card-num ele-text-heading">78%</div>
<div class="analysis-chart-card-content" style="padding-top: 25px">
<el-progress
:percentage="78"
:show-text="false"
:stroke-width="10"
color="#13c2c2"
/>
</div>
<el-divider />
<div class="analysis-chart-card-text">
<span class="ele-action">
<span>周同比12%</span>
<i class="el-icon-caret-top ele-text-danger"></i>
</span>
<span class="ele-action">
<span>日同比11%</span>
<i class="el-icon-caret-bottom ele-text-success"></i>
</span>
</div>
<div class="analysis-chart-card-text">历史成交100000</div>
</el-card>
</el-col>
</el-row>
@@ -108,14 +42,13 @@
import { CanvasRenderer } from 'echarts/renderers';
import { LineChart, BarChart } from 'echarts/charts';
import { GridComponent, TooltipComponent } from 'echarts/components';
import VChart from 'vue-echarts';
import { getPayNumList } from '@/api/dashboard/analysis';
import { echartsMixin } from '@/utils/echarts-mixin';
use([CanvasRenderer, LineChart, BarChart, GridComponent, TooltipComponent]);
export default {
components: { VChart },
components: {},
mixins: [echartsMixin(['visitChart', 'payNumChart'])],
data() {
return {
@@ -1,103 +0,0 @@
<template>
<el-card
shadow="never"
header="最近1小时访问情况"
body-style="padding: 14px 5px 0 0;"
>
<v-chart
ref="visitHourChart"
style="height: 323px"
:option="visitHourChartOption"
/>
</el-card>
</template>
<script>
import { use } from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
import { LineChart } from 'echarts/charts';
import {
GridComponent,
TooltipComponent,
LegendComponent
} from 'echarts/components';
import VChart from 'vue-echarts';
import { getVisitHourList } from '@/api/dashboard/analysis';
import { echartsMixin } from '@/utils/echarts-mixin';
use([
CanvasRenderer,
LineChart,
GridComponent,
TooltipComponent,
LegendComponent
]);
export default {
components: { VChart },
mixins: [echartsMixin(['visitHourChart'])],
data() {
return {
// 最近1小时访问情况折线图配置
visitHourChartOption: {}
};
},
created() {
this.getVisitHourData();
},
methods: {
/* 获取最近1小时访问情况数据 */
getVisitHourData() {
getVisitHourList()
.then((data) => {
this.visitHourChartOption = {
tooltip: {
trigger: 'axis'
},
legend: {
data: ['浏览量', '访问量'],
right: 20
},
xAxis: [
{
type: 'category',
boundaryGap: false,
data: data.map((d) => d.time)
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: '浏览量',
type: 'line',
smooth: true,
symbol: 'none',
areaStyle: {
opacity: 0.5
},
data: data.map((d) => d.views)
},
{
name: '访问量',
type: 'line',
smooth: true,
symbol: 'none',
areaStyle: {
opacity: 0.5
},
data: data.map((d) => d.visits)
}
]
};
})
.catch((e) => {
this.$message.error(e.message);
});
}
}
};
</script>
+14 -18
View File
@@ -1,37 +1,33 @@
<template>
<div class="ele-body ele-body-card">
<profile-card />
<statistics-card />
<sale-card />
<el-row :gutter="15">
<el-col v-bind="styleResponsive ? { lg: 18, md: 16 } : { span: 18 }">
<visit-hour />
</el-col>
<el-col v-bind="styleResponsive ? { lg: 6, md: 8 } : { span: 6 }">
<hot-search />
</el-col>
</el-row>
</div>
</template>
<script>
import ProfileCard from './components/profile-card.vue';
import StatisticsCard from './components/statistics-card.vue';
import SaleCard from './components/sale-card.vue';
import VisitHour from './components/visit-hour.vue';
import HotSearch from './components/hot-search.vue';
export default {
name: 'HomeAnalysis',
name: 'DashboardWorkplace',
components: {
StatisticsCard,
SaleCard,
VisitHour,
HotSearch
ProfileCard,
StatisticsCard
},
data() {
return {
data: []
};
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
}
},
methods: {}
};
</script>
<style lang="scss" scoped></style>
+22
View File
@@ -0,0 +1,22 @@
import request from '@/utils/request';
export async function pageBrand(params) {
const res = await request.get('/common/autoBrand', {
params
});
return res.data;
}
export async function pageSeries(params) {
const res = await request.get('/common/autoSeries', {
params
});
return res.data;
}
export async function pageAutoCar(params) {
const res = await request.get('/common/autoCar', {
params
});
return res.data;
}
+13
View File
@@ -60,3 +60,16 @@ export async function removeProduct(ids) {
}
return Promise.reject(new Error(res.data.message));
}
/**
* @param id 产品id
*/
export async function getProduct(id) {
const res = await request.get('/car/product/', {
id: id
});
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
+196
View File
@@ -0,0 +1,196 @@
<template>
<div class="car-model-selector">
<el-form-item label="品牌">
<el-select
v-model="form.brandId"
filterable
clearable
placeholder="请输入品牌名称搜索"
:loading="brandLoading"
@change="handleBrandChange"
@filter-change="handleBrandFilter"
>
<el-option
v-for="item in brandList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
<template v-if="type !== 'brand'">
-
<el-select
v-model="form.seriesId"
placeholder="请选择车系"
clearable
:disabled="!form.brandId"
:loading="seriesLoading"
@change="handleSeriesChange"
>
<el-option
v-for="item in seriesList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</template>
<template v-if="!type">
-
<el-select
v-model="form.modelId"
placeholder="请选择车型"
clearable
:disabled="!form.seriesId"
:loading="modelLoading"
@change="handleModelChange"
>
<el-option
v-for="item in modelList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</template>
</el-form-item>
</div>
</template>
<script>
import { pageBrand, pageSeries, pageAutoCar } from '@/api/auto';
export default {
name: 'CarModelSelector',
props: {
value: {
type: Object,
default: () => ({
brandId: null,
seriesId: null,
modelId: null
})
},
type: {
type: String,
validator: (type) => {
return !type || ['brandSeries', 'brand'].includes(type);
}
}
},
data() {
return {
form: { ...this.value }, // 初始化时深拷贝value,
brandList: [],
seriesList: [],
modelList: [],
brandLoading: false,
seriesLoading: false,
modelLoading: false,
brandFilter: ''
};
},
created() {
this.loadBrands();
if (this.form.brandId) {
this.loadSeriesList(this.form.brandId);
}
if (this.form.seriesId) {
this.loadModelList(this.form.seriesId);
}
},
watch: {
value: {
deep: true,
handler(newVal) {
this.form = { ...newVal }; // 外部值变化时更新内部form
}
}
},
methods: {
async loadBrands(filter = '') {
this.brandLoading = true;
try {
const res = await pageBrand({ nameLike: filter });
this.brandList = res;
this.seriesList = [];
this.modelList = [];
} catch (error) {
this.$message.error('品牌加载失败');
} finally {
this.brandLoading = false;
}
},
async loadSeriesList(brandId) {
this.seriesLoading = true;
try {
const res = await pageSeries({ brandId });
this.seriesList = res;
this.modelList = [];
} catch (error) {
this.$message.error('车系加载失败');
} finally {
this.seriesLoading = false;
}
},
async loadModelList(seriesId) {
this.modelLoading = true;
try {
const res = await pageAutoCar({ seriesId });
this.modelList = res;
} catch (error) {
this.$message.error('车型加载失败');
} finally {
this.modelLoading = false;
}
},
handleBrandChange(brandId) {
if (brandId) {
this.form.seriesId = null;
this.loadSeriesList(brandId);
}
this.emitValue();
},
handleSeriesChange(seriesId) {
if (seriesId) {
this.form.modelId = null;
this.loadModelList(seriesId);
}
this.emitValue();
},
handleModelChange() {
this.emitValue();
},
handleBrandFilter(filter) {
this.brandFilter = filter;
this.loadBrands(filter);
},
emitValue() {
this.$emit('input', { ...this.form });
},
syncFormWithProps() {
// 重置所有数据
// this.brandList = [];
// this.seriesList = [];
// this.modelList = [];
//
// const { brandId, seriesId, modelId } = this.modelValue;
// this.form = { brandId, seriesId, modelId };
//
// if (brandId) {
// this.loadSeriesList(brandId);
// if (seriesId) {
// this.loadModelList(seriesId);
// }
// }
}
}
};
</script>
<style scoped></style>
+4 -4
View File
@@ -7,10 +7,10 @@ export default {
logout: '退出登录'
},
footer: {
website: '官网',
document: '文档',
authorization: '授权',
copyright: 'Copyright © 2022 武汉易云智科技有限公司'
website: '',
document: '',
authorization: '',
copyright: 'Copyright © 2022 好店云(厦门)科技有限公司'
},
logout: {
title: '提示',
@@ -50,7 +50,9 @@
<i class="el-icon-_more"></i>
</div>
<!-- 修改密码弹窗 -->
<!--
<password-modal :visible.sync="passwordVisible" />
-->
<!-- 主题设置抽屉 -->
<setting-drawer :visible.sync="settingVisible" />
</div>
+124
View File
@@ -0,0 +1,124 @@
<template>
<div class="ele-body ele-body-card">
<el-card shadow="never pd10">
<el-row class="pd10">
<el-col :span="24"><h2>概况</h2></el-col>
</el-row>
<el-row class="pd10">
<el-col :span="6">品牌</el-col>
<el-col :span="6">车型</el-col>
<el-col :span="6">官方售价</el-col>
<el-col :span="6"></el-col>
</el-row>
<el-row class="pd10">
<el-col :span="24"><h2>优惠</h2></el-col>
</el-row>
<el-row class="pd10">
<el-col :span="6">置换补贴</el-col>
<el-col :span="6">报废补贴</el-col>
<el-col :span="6">优惠金额</el-col>
<el-col :span="6"></el-col>
</el-row>
<el-row class="pd10">
<el-col :span="24"><h2>客户画像</h2></el-col>
</el-row>
<el-row class="pd10">
<el-col :span="6">男性占比</el-col>
<el-col :span="6">年龄区间</el-col>
<el-col :span="6">人群标签</el-col>
<el-col :span="6"></el-col>
</el-row>
<el-row class="pd10">
<el-col :span="24"><h2>车型卖点</h2></el-col>
</el-row>
<el-row class="pd10">
<el-col :span="24">范围访问量附件为冷风机微辣</el-col>
</el-row>
<el-row class="pd10">
<el-col :span="24"><h2>推广文案</h2></el-col>
</el-row>
<el-row class="pd10">
<el-col :span="20">
<el-input
type="textarea"
:rows="2"
value="呢哦if我饿了覅就为了"
></el-input>
</el-col>
<el-col :span="4">
<el-button style="margin-left: 5px" type="primary" size="small"
>复制</el-button
>
</el-col>
</el-row>
<el-row class="pd10">
<el-col :span="24"><h2>购车链接</h2></el-col>
</el-row>
<el-row class="pd10">
<el-col :span="20">
<el-input value="呢哦if我饿了覅就为了"></el-input
></el-col>
<el-col :span="4">
<el-button style="margin-left: 5px" type="primary" size="small"
>复制</el-button
>
</el-col>
</el-row>
</el-card>
</div>
</template>
<script>
import { getProduct } from '@/api/car/product';
const ROUTE_PATH = '/car/product/detail';
export default {
name: 'carProductDetail',
components: {},
data() {
return {
loading: false,
promotionText:
'东风日产N7,官方售价11.99万起,现享10000元置换补贴和报废补贴,至高优惠10000元!适合都市白领家庭,25-40岁人群首选新能源车型。'
};
},
created() {},
methods: {
query() {
const id = this.$route.params.id;
if (!id || this.user.userId === Number(id)) {
return;
}
this.loading = true;
getProduct(Number(id))
.then((data) => {
this.loading = false;
this.$util.assignObject(this.user, {
...data,
createTime: this.$util.toDateString(data.createTime)
});
})
.catch((e) => {
this.loading = false;
this.$message.error(e.message);
});
}
},
watch: {
$route: {
handler(route) {
const { fullPath } = route;
if (!fullPath.startsWith(ROUTE_PATH)) {
return;
}
this.query();
},
immediate: true
}
}
};
</script>
<style scoped>
.pd10 {
padding: 10px;
}
</style>
+133 -142
View File
@@ -13,6 +13,13 @@
/>
</el-form-item>
</el-col>
<el-col :md="24" :sm="24">
<car-model-selector
type="brandSeries"
v-model="where.selectedCar"
:key="componentKey"
/>
</el-col>
<el-col :md="6" :sm="12">
<div class="ele-form-actions">
<el-button
@@ -37,87 +44,85 @@
cache-key="syliveActivityTable"
>
<!-- 表头工具栏 -->
<template v-slot:toolbar>
<el-button
size="small"
type="primary"
icon="el-icon-plus"
class="ele-btn-icon"
@click="edit()"
>
新建
</el-button>
<el-button
size="small"
type="danger"
icon="el-icon-delete"
class="ele-btn-icon"
@click="removeBatch"
>
删除
</el-button>
</template>
<template v-slot:toolbar> </template>
<!-- 状态列 -->
<template v-slot:title="{ row }">
<div class="cell-content">
<el-image :src="row.imgs[0]['url']" class="table-image" />
<el-link
type="primary"
:underline="false"
class="table-text"
@click="goDetail(row)"
>{{ row.title }}</el-link
>
</div>
</template>
<template v-slot:price="{ row }">
<div class="ele-text-danger">
<div>L {{ row.firstLevelClues }}</div>
<div>S {{ row.firstLevelDeal }}</div>
</div>
</template>
<template v-slot:timeBetween="{ row }">
<div>{{ row.timeStart.split(' ')[0] }}~</div>
<div>{{ row.timeEnd.split(' ')[0] }}</div>
</template>
<template v-slot:status="{ row }">
<el-switch
:active-value="1"
:inactive-value="0"
v-model="row.status"
@change="editStatus(row)"
/>
<span v-if="row.status" class="ele-text-success">已上架</span>
<span v-else class="ele-text-danger">未上架</span>
</template>
<!-- 操作列 -->
<template v-slot:action="{ row }">
<el-link
type="primary"
:underline="false"
@click="edit(row)"
icon="el-icon-edit"
@click="showPromotionText(row)"
>
修改
文案
</el-link>
<el-popconfirm
class="ele-action"
title="确定要删除此数据吗?"
@confirm="remove(row)"
>
<template v-slot:reference>
<el-link type="danger" :underline="false" icon="el-icon-delete">
删除
</el-link>
</template>
</el-popconfirm>
<el-link type="primary" :underline="false"> 购车券 </el-link>
<el-link type="primary" :underline="false"> 海报 </el-link>
</template>
</ele-pro-table>
<!-- 推广文案 -->
<el-dialog :visible.sync="showPromotion" title="推广文案" width="30%">
<template v-if="current && current.promotion_text">
<div v-for="(item, index) in current.promotion_text" :key="index">
<el-input :value="item" type="textarea" :rows="3" />
<div style="margin: 5px 0 5px 0; text-align: right">
<el-button
type="primary"
size="mini"
v-clipboard:copy="item"
v-clipboard:success="onCopy"
>复制</el-button
>
</div>
</div>
</template>
</el-dialog>
</el-card>
<!-- 编辑弹窗 -->
<edit
:data="current"
:visible.sync="showEdit"
:organization-list="organizationList"
@done="reload"
/>
</div>
</template>
<script>
import {
pageProduct,
removeProduct,
updateProductStatus
} from '@/api/car/product';
import edit from './components/edit.vue';
import { pageProduct } from '@/api/car/product';
import CarModelSelector from '@/components/CarSelector/index.vue';
export default {
name: 'carProduct',
components: { edit },
components: { CarModelSelector },
data() {
return {
where: {
title: ''
title: '',
selectedCar: {
brandId: '',
seriesId: '',
modelId: ''
}
},
// 门店数据
organizationList: [],
// 表格列配置
columns: [
{
@@ -127,17 +132,10 @@
align: 'center',
fixed: 'left'
},
{
prop: 'id',
label: 'ID',
minWidth: 40,
align: 'center',
showOverflowTooltip: true,
fixed: 'left'
},
{
prop: 'title',
label: '产品信息',
slot: 'title',
showOverflowTooltip: true,
minWidth: 200
},
@@ -148,11 +146,11 @@
minWidth: 80
},
{
prop: 'timeLaunch',
label: '上架时间',
sortable: 'custom',
prop: '',
label: '佣金',
showOverflowTooltip: true,
minWidth: 100
minWidth: 80,
slot: 'price'
},
{
prop: 'status',
@@ -163,40 +161,46 @@
slot: 'status',
showOverflowTooltip: true
},
{
prop: 'timeBetween',
label: '推广周期',
showOverflowTooltip: true,
slot: 'timeBetween',
minWidth: 100
},
{
columnKey: 'action',
label: '操作',
width: 380,
label: '推广',
width: 150,
align: 'center',
resizable: false,
slot: 'action'
},
{
columnKey: '',
label: '浏览数',
width: 80,
align: 'center',
resizable: false
},
{
columnKey: '',
label: '留资数',
width: 80,
align: 'center',
resizable: false
}
],
// 表格选中数据
selection: [],
// 当前编辑数据
current: null,
// 是否显示编辑弹窗
showEdit: false,
// 是否显示编辑商品弹窗
showEditItem: false,
// 是否显示编辑券弹窗
showEditCoupon: false,
// 是否显示编辑券弹窗
showEditDraw: false,
showEditVisitTag: false,
// 是否显示二维码弹窗
showCode: false
showPromotion: false,
componentKey: ''
};
},
created() {
//this.organizationQuery();
},
created() {},
methods: {
edit(row) {
this.current = row;
this.showEdit = true;
},
/* 表格数据源 */
datasource({ page, limit, where, order }) {
return pageProduct({ ...where, ...order, page, limit });
@@ -205,62 +209,49 @@
reload() {
this.$refs.table.reload({ page: 1, where: this.where });
},
/* 删除 */
remove(row) {
const loading = this.$loading({ lock: true });
removeProduct(row.id)
.then((msg) => {
loading.close();
this.$message.success(msg);
this.reload();
})
.catch((e) => {
loading.close();
this.$message.error(e.message);
});
},
/* 批量删除 */
removeBatch() {
if (!this.selection.length) {
this.$message.error('请至少选择一条数据');
return;
}
this.$confirm('确定要删除选中数据吗?', '提示', {
type: 'warning'
})
.then(() => {
const loading = this.$loading({ lock: true });
removeProduct(this.selection.map((d) => d.id))
.then((msg) => {
loading.close();
this.$message.success(msg);
this.reload();
})
.catch((e) => {
loading.close();
this.$message.error(e.message);
});
})
.catch(() => {});
},
/* 更改状态 */
editStatus(row) {
const loading = this.$loading({ lock: true });
updateProductStatus(row.id, row.status)
.then((msg) => {
loading.close();
this.$message.success(msg);
this.reload();
})
.catch((e) => {
loading.close();
this.$message.error(e.message);
});
},
/* 重置搜索 */
reset() {
this.where = {};
this.where = {
selectedCar: {
brandId: null,
seriesId: null,
modelId: null
}
};
// 更新 key 强制组件重新渲染
this.componentKey = Date.now();
},
showPromotionText(row) {
this.current = row;
this.showPromotion = true;
},
onCopy() {
this.$message.success('复制成功!');
},
goDetail(row) {
const path = '/car/product/detail';
this.$nextTick(() => {
this.$router.push({
path,
query: row ? { id: row.id } : undefined
});
});
}
}
};
</script>
<style scoped>
.cell-content {
display: flex;
align-items: center;
}
.table-image {
width: 80px;
height: 80px;
margin-right: 5px;
}
.table-text {
/* 文本样式 */
overflow: hidden;
}
</style>
@@ -1,73 +0,0 @@
<template>
<el-card shadow="never" header="热门搜索">
<v-chart
ref="hotSearchChart"
style="height: 303px"
:option="hotSearchChartOption"
/>
</el-card>
</template>
<script>
import { use } from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
import { TooltipComponent } from 'echarts/components';
import VChart from 'vue-echarts';
import 'echarts-wordcloud';
import { wordCloudColor } from 'ele-admin';
import { getWordCloudList } from '@/api/dashboard/analysis';
import { echartsMixin } from '@/utils/echarts-mixin';
use([CanvasRenderer, TooltipComponent]);
export default {
components: { VChart },
mixins: [echartsMixin(['hotSearchChart'])],
data() {
return {
// 词云图表配置
hotSearchChartOption: {}
};
},
created() {
this.getWordCloudData();
},
methods: {
/* 获取词云数据 */
getWordCloudData() {
getWordCloudList()
.then((data) => {
this.hotSearchChartOption = {
tooltip: {
show: true,
confine: true,
borderWidth: 1
},
series: [
{
type: 'wordCloud',
width: '100%',
height: '100%',
sizeRange: [12, 24],
gridSize: 6,
textStyle: {
color: wordCloudColor
},
emphasis: {
textStyle: {
shadowBlur: 8,
shadowColor: 'rgba(0, 0, 0, .15)'
}
},
data: data
}
]
};
})
.catch((e) => {
this.$message.error(e.message);
});
}
}
};
</script>
@@ -0,0 +1,119 @@
<!-- 用户信息 -->
<template>
<el-card shadow="never" body-style="padding: 20px;">
<div
:class="[
'ele-cell',
'workplace-user-card',
{ 'workplace-user-responsive': styleResponsive }
]"
>
<div class="ele-cell-content ele-cell">
<!--
<el-avatar :size="68" :src="loginUser.avatar" />
-->
<div class="ele-cell-content">
<h4 class="ele-elip"> Hi, {{ loginUser.nickname }} , 您好! </h4>
<!--
<div class="ele-text-secondary ele-elip" style="margin-top: 8px">
<i class="el-icon-heavy-rain"></i>
<em>今日阴转小雨, 22 - 32 , 出门记得带伞哦</em>
</div>
-->
</div>
</div>
<!--
<div class="workplace-count-group">
<div class="workplace-count-item">
<div class="workplace-count-header">
<el-tag size="small" class="ele-tag-round">
<i class="el-icon-menu"></i>
</el-tag>
<span class="workplace-count-name">项目数</span>
</div>
<div class="workplace-count-num ele-text-heading">3</div>
</div>
<div class="workplace-count-item">
<div class="workplace-count-header">
<el-tag type="warning" size="small" class="ele-tag-round">
<i class="el-icon-finished"></i>
</el-tag>
<span class="workplace-count-name">待办项</span>
</div>
<div class="workplace-count-num ele-text-heading">6 / 24</div>
</div>
<div class="workplace-count-item">
<div class="workplace-count-header">
<el-tag type="success" size="small" class="ele-tag-round">
<i class="el-icon-bell"></i>
</el-tag>
<span class="workplace-count-name">消息</span>
</div>
<div class="workplace-count-num ele-text-heading">1,689</div>
</div>
</div>
-->
</div>
</el-card>
</template>
<script>
export default {
computed: {
// 当前登录用户信息
loginUser() {
return this.$store.state.user.info;
},
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
}
};
</script>
<style lang="scss" scoped>
.workplace-user-card {
.ele-cell-content {
overflow: hidden;
}
.workplace-count-group {
white-space: nowrap;
}
.workplace-count-item {
padding: 0 5px 0 25px;
box-sizing: border-box;
display: inline-block;
text-align: right;
}
.workplace-count-name {
padding-left: 8px;
}
.workplace-count-num {
font-size: 24px;
margin-top: 6px;
}
}
@media screen and (max-width: 992px) {
.workplace-user-responsive .workplace-count-item {
padding: 0 5px 0 10px;
}
}
@media screen and (max-width: 768px) {
.workplace-user-responsive.workplace-user-card {
display: block;
.workplace-count-group {
display: block;
margin-top: 15px;
text-align: right;
}
}
}
</style>
@@ -1,210 +0,0 @@
<template>
<el-card shadow="never" body-style="padding: 0;">
<div class="ele-cell demo-monitor-tool">
<div class="ele-cell-content">
<el-tabs
v-model="saleSearch.type"
class="demo-monitor-tabs"
@tab-click="onSaleTypeChange"
>
<el-tab-pane label="销售额" name="saleroom" />
<el-tab-pane label="访问量" name="visits" />
</el-tabs>
</div>
<div :class="['ele-inline-block', { 'hidden-xs-only': styleResponsive }]">
<el-radio-group v-model="saleSearch.dateType" size="small">
<el-radio-button :label="0">今天</el-radio-button>
<el-radio-button :label="1">本周</el-radio-button>
<el-radio-button :label="2">本月</el-radio-button>
<el-radio-button :label="3">本年</el-radio-button>
</el-radio-group>
</div>
<div
:class="['ele-inline-block', { 'hidden-sm-and-down': styleResponsive }]"
style="width: 260px; margin-left: 10px"
>
<el-date-picker
unlink-panels
type="daterange"
class="ele-fluid"
end-placeholder="结束日期"
start-placeholder="开始日期"
v-model="saleSearch.datetime"
range-separator=""
size="small"
/>
</div>
</div>
<el-divider />
<el-row>
<el-col v-bind="styleResponsive ? { lg: 18, md: 16 } : { span: 18 }">
<div class="demo-monitor-title">
<span v-if="saleSearch.type === 'saleroom'">销售额趋势</span>
<span v-else>访问量趋势</span>
</div>
<v-chart
ref="saleChart"
style="height: 285px"
:option="saleChartOption"
/>
</el-col>
<el-col v-bind="styleResponsive ? { lg: 6, md: 8 } : { span: 6 }">
<div class="demo-monitor-title" style="display: flex">
<div>门店</div>
<div>
<span v-if="saleSearch.type === 'saleroom'">销售额</span>
<span v-else>访问量</span>
</div>
<div>排名</div>
</div>
<div
v-for="(item, index) in saleroomRankData"
:key="index"
class="demo-monitor-rank-item ele-cell"
style="margin-bottom: 15px"
>
<el-tag
size="mini"
type="info"
:effect="index < 3 ? 'dark' : 'light'"
:color="index < 3 ? '#314659' : 'hsla(0, 0%, 60%, .2)'"
style="border-color: transparent"
class="ele-tag-round"
>
{{ index + 1 }}
</el-tag>
<div class="ele-cell-content">{{ item.name }}</div>
<div class="ele-text-secondary">{{ item.value }}</div>
</div>
</el-col>
</el-row>
</el-card>
</template>
<script>
import { use } from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
import { BarChart } from 'echarts/charts';
import { GridComponent, TooltipComponent } from 'echarts/components';
import VChart from 'vue-echarts';
import { getSaleroomList } from '@/api/dashboard/analysis';
import { echartsMixin } from '@/utils/echarts-mixin';
use([CanvasRenderer, BarChart, GridComponent, TooltipComponent]);
export default {
components: { VChart },
mixins: [echartsMixin(['saleChart'])],
data() {
return {
// 销售量搜索参数
saleSearch: {
type: 'saleroom',
dateType: 0,
datetime: ''
},
// 销售量趋势数据
saleroomData1: [],
// 访问量趋势数据
saleroomData2: [],
// 门店排名数据
saleroomRankData: [
{ name: '工专路 1 号店', value: '323,234' },
{ name: '工专路 2 号店', value: '323,234' },
{ name: '工专路 3 号店', value: '323,234' },
{ name: '工专路 4 号店', value: '323,234' },
{ name: '工专路 5 号店', value: '323,234' },
{ name: '工专路 6 号店', value: '323,234' },
{ name: '工专路 7 号店', value: '323,234' }
],
// 销售额柱状图配置
saleChartOption: {}
};
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
},
created() {
this.getSaleroomData();
},
methods: {
/* 获取销售量数据 */
getSaleroomData() {
getSaleroomList()
.then((data) => {
this.saleroomData1 = data.list1;
this.saleroomData2 = data.list2;
this.onSaleTypeChange();
})
.catch((e) => {
this.$message.error(e.message);
});
},
/* 销售量tab选择改变事件 */
onSaleTypeChange() {
const isSale = this.saleSearch.type === 'saleroom';
const data = isSale ? this.saleroomData1 : this.saleroomData2;
this.saleChartOption = {
tooltip: {
trigger: 'axis'
},
xAxis: [
{
type: 'category',
data: data.map((d) => d.month)
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
type: 'bar',
data: data.map((d) => d.value)
}
]
};
}
}
};
</script>
<style lang="scss" scoped>
/* 销售额、访问量工具栏 */
.demo-monitor-tool {
padding: 0 20px;
.demo-monitor-tabs {
height: 51px;
}
:deep(.el-tabs__item) {
height: 51px;
line-height: 51px;
font-size: 15px;
}
:deep(.el-tabs__nav-wrap:after) {
display: none;
}
}
/* 小标题 */
.demo-monitor-title {
padding: 0 20px;
margin: 15px 0 5px 0;
}
/* 排名 item */
.demo-monitor-rank-item {
padding: 0 20px;
line-height: 20px;
margin-top: 18px;
}
</style>
@@ -5,99 +5,33 @@
<el-card class="analysis-chart-card" shadow="never">
<template v-slot:header>
<div class="ele-cell">
<div class="ele-cell-content">总销售额</div>
<el-tooltip content="指标说明" placement="top">
<i
class="el-icon-_question ele-text-placeholder"
style="cursor: pointer"
>
</i>
</el-tooltip>
</div>
</template>
<div class="analysis-chart-card-num ele-text-heading">¥ 126,560</div>
<div class="analysis-chart-card-content" style="padding-top: 18px">
<span class="ele-action">
<span>周同比12%</span>
<i class="el-icon-caret-top ele-text-danger"></i>
</span>
<span class="ele-action">
<span>日同比11%</span>
<i class="el-icon-caret-bottom ele-text-success"></i>
</span>
</div>
<el-divider />
<div class="analysis-chart-card-text">日销售额 ¥12,423</div>
</el-card>
</el-col>
<el-col v-bind="styleResponsive ? { lg: 6, md: 12 } : { span: 6 }">
<el-card class="analysis-chart-card" shadow="never">
<template v-slot:header>
<div class="ele-cell">
<div class="ele-cell-content">访问量</div>
<div class="ele-cell-content">今日新增线索</div>
<el-tag size="mini" type="danger"></el-tag>
</div>
</template>
<div class="analysis-chart-card-num ele-text-heading">8,846</div>
<div class="analysis-chart-card-content">
<v-chart
ref="visitChart"
style="height: 40px"
:option="visitChartOption"
/>
</div>
<div
class="analysis-chart-card-num ele-text-heading"
style="margin-bottom: 10px"
>101</div
>
<el-divider />
<div class="analysis-chart-card-text">日访问量 1,234</div>
<div class="analysis-chart-card-text">累计线索100000</div>
</el-card>
</el-col>
<el-col v-bind="styleResponsive ? { lg: 6, md: 12 } : { span: 6 }">
<el-card class="analysis-chart-card" shadow="never">
<template v-slot:header>
<div class="ele-cell">
<div class="ele-cell-content">支付笔数</div>
<el-tag size="mini"></el-tag>
<div class="ele-cell-content">当前团队成员</div>
</div>
</template>
<div class="analysis-chart-card-num ele-text-heading">6,560</div>
<div class="analysis-chart-card-content">
<v-chart
ref="payNumChart"
style="height: 40px"
:option="payNumChartOption"
/>
</div>
<div
class="analysis-chart-card-num ele-text-heading"
style="margin-bottom: 10px"
>2323</div
>
<el-divider />
<div class="analysis-chart-card-text">转化率 60%</div>
</el-card>
</el-col>
<el-col v-bind="styleResponsive ? { lg: 6, md: 12 } : { span: 6 }">
<el-card class="analysis-chart-card" shadow="never">
<template v-slot:header>
<div class="ele-cell">
<div class="ele-cell-content">运营活动效果</div>
<el-tag size="mini" type="success"></el-tag>
</div>
</template>
<div class="analysis-chart-card-num ele-text-heading">78%</div>
<div class="analysis-chart-card-content" style="padding-top: 25px">
<el-progress
:percentage="78"
:show-text="false"
:stroke-width="10"
color="#13c2c2"
/>
</div>
<el-divider />
<div class="analysis-chart-card-text">
<span class="ele-action">
<span>周同比12%</span>
<i class="el-icon-caret-top ele-text-danger"></i>
</span>
<span class="ele-action">
<span>日同比11%</span>
<i class="el-icon-caret-bottom ele-text-success"></i>
</span>
</div>
<div class="analysis-chart-card-text">历史成交100000</div>
</el-card>
</el-col>
</el-row>
@@ -108,14 +42,13 @@
import { CanvasRenderer } from 'echarts/renderers';
import { LineChart, BarChart } from 'echarts/charts';
import { GridComponent, TooltipComponent } from 'echarts/components';
import VChart from 'vue-echarts';
import { getPayNumList } from '@/api/dashboard/analysis';
import { echartsMixin } from '@/utils/echarts-mixin';
use([CanvasRenderer, LineChart, BarChart, GridComponent, TooltipComponent]);
export default {
components: { VChart },
components: {},
mixins: [echartsMixin(['visitChart', 'payNumChart'])],
data() {
return {
@@ -1,103 +0,0 @@
<template>
<el-card
shadow="never"
header="最近1小时访问情况"
body-style="padding: 14px 5px 0 0;"
>
<v-chart
ref="visitHourChart"
style="height: 323px"
:option="visitHourChartOption"
/>
</el-card>
</template>
<script>
import { use } from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
import { LineChart } from 'echarts/charts';
import {
GridComponent,
TooltipComponent,
LegendComponent
} from 'echarts/components';
import VChart from 'vue-echarts';
import { getVisitHourList } from '@/api/dashboard/analysis';
import { echartsMixin } from '@/utils/echarts-mixin';
use([
CanvasRenderer,
LineChart,
GridComponent,
TooltipComponent,
LegendComponent
]);
export default {
components: { VChart },
mixins: [echartsMixin(['visitHourChart'])],
data() {
return {
// 最近1小时访问情况折线图配置
visitHourChartOption: {}
};
},
created() {
this.getVisitHourData();
},
methods: {
/* 获取最近1小时访问情况数据 */
getVisitHourData() {
getVisitHourList()
.then((data) => {
this.visitHourChartOption = {
tooltip: {
trigger: 'axis'
},
legend: {
data: ['浏览量', '访问量'],
right: 20
},
xAxis: [
{
type: 'category',
boundaryGap: false,
data: data.map((d) => d.time)
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: '浏览量',
type: 'line',
smooth: true,
symbol: 'none',
areaStyle: {
opacity: 0.5
},
data: data.map((d) => d.views)
},
{
name: '访问量',
type: 'line',
smooth: true,
symbol: 'none',
areaStyle: {
opacity: 0.5
},
data: data.map((d) => d.visits)
}
]
};
})
.catch((e) => {
this.$message.error(e.message);
});
}
}
};
</script>
+14 -18
View File
@@ -1,37 +1,33 @@
<template>
<div class="ele-body ele-body-card">
<profile-card />
<statistics-card />
<sale-card />
<el-row :gutter="15">
<el-col v-bind="styleResponsive ? { lg: 18, md: 16 } : { span: 18 }">
<visit-hour />
</el-col>
<el-col v-bind="styleResponsive ? { lg: 6, md: 8 } : { span: 6 }">
<hot-search />
</el-col>
</el-row>
</div>
</template>
<script>
import ProfileCard from './components/profile-card.vue';
import StatisticsCard from './components/statistics-card.vue';
import SaleCard from './components/sale-card.vue';
import VisitHour from './components/visit-hour.vue';
import HotSearch from './components/hot-search.vue';
export default {
name: 'HomeAnalysis',
name: 'DashboardWorkplace',
components: {
StatisticsCard,
SaleCard,
VisitHour,
HotSearch
ProfileCard,
StatisticsCard
},
data() {
return {
data: []
};
},
computed: {
// 是否开启响应式布局
styleResponsive() {
return this.$store.state.theme.styleResponsive;
}
}
},
methods: {}
};
</script>
<style lang="scss" scoped></style>