前端和后端源码,合并到一个git仓库中,方便用户下载,避免前后端不匹配的问题

This commit is contained in:
JEECG
2024-06-23 10:39:52 +08:00
parent bb918b742e
commit 0325e34dcb
1439 changed files with 171106 additions and 0 deletions

View File

@ -0,0 +1,89 @@
<template>
<div ref="chartRef" :style="{ height, width }"></div>
</template>
<script lang="ts">
import { defineComponent, PropType, ref, Ref, reactive, watchEffect } from 'vue';
import { useECharts } from '/@/hooks/web/useECharts';
import { cloneDeep } from 'lodash-es';
export default defineComponent({
name: 'bar',
props: {
chartData: {
type: Array,
default: () => [],
},
option: {
type: Object,
default: () => ({}),
},
width: {
type: String as PropType<string>,
default: '100%',
},
height: {
type: String as PropType<string>,
default: 'calc(100vh - 78px)',
},
// update-begin--author:liaozhiyang---date:20240407---for【QQYUN-8762】首页默认及echars颜色调整
seriesColor: {
type: String,
default: '#1890ff',
},
// update-end--author:liaozhiyang---date:20240407---for【QQYUN-8762】首页默认及echars颜色调整
},
setup(props) {
const chartRef = ref<HTMLDivElement | null>(null);
const { setOptions, echarts } = useECharts(chartRef as Ref<HTMLDivElement>);
const option = reactive({
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
label: {
show: true,
backgroundColor: '#333',
},
},
},
xAxis: {
type: 'category',
data: [],
},
yAxis: {
type: 'value',
},
series: [
{
name: 'bar',
type: 'bar',
data: [],
color: props.seriesColor,
},
],
});
watchEffect(() => {
props.chartData && initCharts();
});
function initCharts() {
if (props.option) {
Object.assign(option, cloneDeep(props.option));
}
let seriesData = props.chartData.map((item) => {
return item.value;
});
let xAxisData = props.chartData.map((item) => {
return item.name;
});
option.series[0].data = seriesData;
// update-begin--author:liaozhiyang---date:20240407---for【QQYUN-8762】首页默认及echars颜色调整
option.series[0].color = props.seriesColor;
// update-end--author:liaozhiyang---date:20240407---for【QQYUN-8762】首页默认及echars颜色调整
option.xAxis.data = xAxisData;
setOptions(option);
}
return { chartRef };
},
});
</script>

View File

@ -0,0 +1,86 @@
<template>
<div ref="chartRef" :style="{ height, width }"></div>
</template>
<script lang="ts">
import { defineComponent, PropType, ref, Ref, reactive, watchEffect } from 'vue';
import { useECharts } from '/@/hooks/web/useECharts';
import { cloneDeep } from 'lodash-es';
export default defineComponent({
name: 'barAndLine',
props: {
chartData: {
type: Array,
default: () => [],
},
option: {
type: Object,
default: () => ({}),
},
width: {
type: String as PropType<string>,
default: '100%',
},
height: {
type: String as PropType<string>,
default: 'calc(100vh - 78px)',
},
},
setup(props) {
const chartRef = ref<HTMLDivElement | null>(null);
const { setOptions, echarts } = useECharts(chartRef as Ref<HTMLDivElement>);
const option = reactive({
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
label: {
show: true,
backgroundColor: '#333',
},
},
},
xAxis: {
type: 'category',
data: [],
},
yAxis: {
type: 'value',
},
series: [
{
name: 'bar',
type: 'bar',
data: [],
},
],
});
watchEffect(() => {
props.chartData && initCharts();
});
function initCharts() {
if (props.option) {
Object.assign(option, cloneDeep(props.option));
}
//图例类型
let typeArr = Array.from(new Set(props.chartData.map((item) => item.type)));
//轴数据
let xAxisData = Array.from(new Set(props.chartData.map((item) => item.name)));
let seriesData = [];
typeArr.forEach((type) => {
let obj = { name: type };
let chartArr = props.chartData.filter((item) => type === item.type);
//data数据
obj['data'] = chartArr.map((item) => item.value);
obj['type'] = chartArr[0].seriesType;
seriesData.push(obj);
});
option.series = seriesData;
option.xAxis.data = xAxisData;
setOptions(option);
}
return { chartRef };
},
});
</script>

View File

@ -0,0 +1,122 @@
<template>
<div ref="chartRef" :style="{ height, width }"></div>
</template>
<script lang="ts">
import { defineComponent, PropType, ref, Ref, reactive, watchEffect } from 'vue';
import { useECharts } from '/@/hooks/web/useECharts';
import { cloneDeep } from 'lodash-es';
export default defineComponent({
name: 'BarMulti',
props: {
chartData: {
type: Array,
default: () => [],
required: true,
},
option: {
type: Object,
default: () => ({}),
},
type: {
type: String as PropType<string>,
default: 'bar',
},
width: {
type: String as PropType<string>,
default: '100%',
},
height: {
type: String as PropType<string>,
default: 'calc(100vh - 78px)',
},
// update-begin--author:liaozhiyang---date:20240407---for【QQYUN-8762】首页默认及echars颜色调整
seriesColor: {
type: Array,
default: () => [],
},
// update-end--author:liaozhiyang---date:20240407---for【QQYUN-8762】首页默认及echars颜色调整
},
emits: ['click'],
setup(props, { emit }) {
const chartRef = ref<HTMLDivElement | null>(null);
const { setOptions, getInstance } = useECharts(chartRef as Ref<HTMLDivElement>);
const option = reactive({
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
label: {
show: true,
backgroundColor: '#333',
},
},
},
legend: {
top: 30,
},
grid: {
top: 60,
},
xAxis: {
type: 'category',
data: [],
},
yAxis: {
type: 'value',
},
series: [],
});
watchEffect(() => {
props.chartData && initCharts();
});
function initCharts() {
if (props.option) {
Object.assign(option, cloneDeep(props.option));
}
//图例类型
let typeArr = Array.from(new Set(props.chartData.map((item) => item.type)));
//轴数据
let xAxisData = Array.from(new Set(props.chartData.map((item) => item.name)));
let seriesData = [];
typeArr.forEach((type) => {
let obj: any = { name: type, type: props.type };
// update-begin-author:liusq date:2023-7-12 for: [issues/613] LineMulti 在数据不对齐时,横坐标计算错误
let data = [];
xAxisData.forEach((x) => {
let dataArr = props.chartData.filter((item) => type === item.type && item.name == x);
if (dataArr && dataArr.length > 0) {
data.push(dataArr[0].value);
} else {
data.push(null);
}
});
// update-end-author:liusq date:2023-7-12 for: [issues/613] LineMulti 在数据不对齐时,横坐标计算错误
//data数据
obj['data'] = data;
// update-begin--author:liaozhiyang---date:20240407---for【QQYUN-8762】首页默认及echars颜色调整
if (props.seriesColor?.length) {
const findItem = props.seriesColor.find((item: any) => item.type === type);
if (findItem?.color) {
obj['color'] = findItem.color;
}
}
// update-end--author:liaozhiyang---date:20240407---for【QQYUN-8762】首页默认及echars颜色调整
seriesData.push(obj);
});
option.series = seriesData;
option.xAxis.data = xAxisData;
setOptions(option);
getInstance()?.off('click', onClick);
getInstance()?.on('click', onClick);
}
function onClick(params) {
emit('click', params);
}
return { chartRef };
},
});
</script>

View File

@ -0,0 +1,109 @@
<template>
<a-card :loading="loading" :body-style="{ padding: '20px 24px 8px' }" :bordered="false">
<div class="chart-card-header">
<div class="meta">
<span class="chart-card-title">{{ title }}</span>
<span class="chart-card-action">
<slot name="action"></slot>
</span>
</div>
<div class="total"
><span>{{ total }}</span></div
>
</div>
<div class="chart-card-content">
<div class="content-fix">
<slot></slot>
</div>
</div>
<div class="chart-card-footer">
<div class="field">
<slot name="footer"></slot>
</div>
</div>
</a-card>
</template>
<script lang="ts" setup>
defineProps({
title: {
type: String,
default: '',
},
total: {
type: [Number, String],
default: '',
},
loading: {
type: Boolean,
default: false,
},
});
</script>
<style lang="less" scoped>
.chart-card-header {
position: relative;
overflow: hidden;
width: 100%;
.meta {
position: relative;
overflow: hidden;
width: 100%;
color: rgba(0, 0, 0, 0.45);
font-size: 14px;
line-height: 22px;
}
}
.chart-card-action {
cursor: pointer;
position: absolute;
top: 0;
right: 0;
}
.chart-card-footer {
border-top: 1px solid #e8e8e8;
padding-top: 9px;
margin-top: 8px;
> * {
position: relative;
}
.field {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin: 0;
}
}
.chart-card-content {
margin-bottom: 12px;
position: relative;
height: 46px;
width: 100%;
.content-fix {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
}
}
.total {
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
white-space: nowrap;
margin-top: 4px;
margin-bottom: 0;
font-size: 30px;
line-height: 38px;
height: 38px;
}
</style>

View File

@ -0,0 +1,110 @@
<template>
<div ref="chartRef" :style="{ height, width }"></div>
</template>
<script lang="ts">
import { defineComponent, PropType, ref, Ref, reactive, watchEffect } from 'vue';
import { useECharts } from '/@/hooks/web/useECharts';
import { GaugeChart } from 'echarts/charts';
import { cloneDeep } from 'lodash-es';
export default defineComponent({
name: 'Gauge',
props: {
chartData: {
type: Object as PropType<Object>,
default: () => [],
},
option: {
type: Object,
default: () => ({}),
},
width: {
type: String as PropType<string>,
default: '100%',
},
height: {
type: String as PropType<string>,
default: 'calc(100vh - 78px)',
},
// update-begin--author:liaozhiyang---date:20240407---for【QQYUN-8762】首页默认及echars颜色调整
seriesColor: {
type: String,
default: '#1890ff',
},
// update-end--author:liaozhiyang---date:20240407---for【QQYUN-8762】首页默认及echars颜色调整
},
setup(props) {
const chartRef = ref<HTMLDivElement | null>(null);
const { setOptions, echarts } = useECharts(chartRef as Ref<HTMLDivElement>);
const option = reactive({
series: [
{
type: 'gauge',
progress: {
show: true,
width: 12,
},
axisLine: {
lineStyle: {
width: 12,
},
},
axisTick: {
show: false,
},
splitLine: {
length: 12,
lineStyle: {
width: 1,
color: '#999',
},
},
axisLabel: {
distance: 25,
color: '#999',
fontSize: 12,
},
anchor: {
show: true,
showAbove: true,
size: 20,
itemStyle: {
borderWidth: 5,
},
},
title: {},
detail: {
valueAnimation: true,
fontSize: 25,
formatter: '{value}%',
offsetCenter: [0, '80%'],
},
data: [
{
value: 70,
name: '本地磁盘',
},
],
},
],
});
watchEffect(() => {
props.chartData && initCharts();
});
function initCharts() {
echarts.use(GaugeChart);
if (props.option) {
Object.assign(option, cloneDeep(props.option));
}
option.series[0].data[0].name = props.chartData.name;
option.series[0].data[0].value = props.chartData.value;
// update-begin--author:liaozhiyang---date:20240407---for【QQYUN-8762】首页默认及echars颜色调整
option.series[0].color = props.seriesColor;
// update-end--author:liaozhiyang---date:20240407---for【QQYUN-8762】首页默认及echars颜色调整
setOptions(option);
}
return { chartRef };
},
});
</script>

View File

@ -0,0 +1,79 @@
<template>
<div class="head-info" :class="center && 'center'">
<span>{{ title }}</span>
<p :style="{ color: `${$props.iconColor}` }">{{ content }} <a-icon :type="icon" :style="{ fontSize: `24px`, color: `${$props.iconColor}` }" /></p>
<em v-if="bordered" />
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'HeadInfo',
props: {
title: {
type: String,
default: '',
},
content: {
type: String,
default: '',
},
bordered: {
type: Boolean,
default: false,
},
center: {
type: Boolean,
default: true,
},
icon: {
type: String,
default: false,
},
// update-begin--author:liaozhiyang---date:20240407---for【QQYUN-8762】首页默认及echars颜色调整
iconColor: {
type: String,
default: '#2b99ff',
},
// update-end--author:liaozhiyang---date:20240407---for【QQYUN-8762】首页默认及echars颜色调整
},
});
</script>
<style lang="less" scoped>
.head-info {
position: relative;
text-align: left;
padding: 0 32px 0 0;
min-width: 125px;
&.center {
text-align: center;
padding: 0 32px;
}
span {
display: inline-block;
font-size: 14px;
line-height: 22px;
margin-bottom: 4px;
}
p {
font-size: 24px;
line-height: 32px;
margin: 0;
}
em {
background-color: #e8e8e8;
position: absolute;
height: 56px;
width: 1px;
top: 0;
right: 0;
}
}
</style>

View File

@ -0,0 +1,116 @@
<template>
<div ref="chartRef" :style="{ height, width }"></div>
</template>
<script lang="ts">
import { defineComponent, PropType, ref, Ref, reactive, watchEffect } from 'vue';
import { useECharts } from '/@/hooks/web/useECharts';
import { cloneDeep } from 'lodash-es';
export default defineComponent({
name: 'LineMulti',
props: {
chartData: {
type: Array,
default: () => [],
required: true,
},
option: {
type: Object,
default: () => ({}),
},
type: {
type: String as PropType<string>,
default: 'line',
},
width: {
type: String as PropType<string>,
default: '100%',
},
height: {
type: String as PropType<string>,
default: 'calc(100vh - 78px)',
},
},
emits: ['click'],
setup(props, { emit }) {
const chartRef = ref<HTMLDivElement | null>(null);
const { setOptions, getInstance } = useECharts(chartRef as Ref<HTMLDivElement>);
const option = reactive({
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
label: {
show: true,
backgroundColor: '#333',
},
},
},
legend: {
top: 30,
},
grid: {
top: 60,
},
xAxis: {
type: 'category',
data: [],
},
yAxis: {
type: 'value',
},
series: [],
});
watchEffect(() => {
props.chartData && initCharts();
});
function initCharts() {
if (props.option) {
Object.assign(option, cloneDeep(props.option));
}
//图例类型
let typeArr = Array.from(new Set(props.chartData.map((item) => item.type)));
//轴数据
let xAxisData = Array.from(new Set(props.chartData.map((item) => item.name)));
let seriesData = [];
typeArr.forEach((type) => {
let obj: any = { name: type, type: props.type };
// update-begin--author:liaozhiyang---date:20240407---for【QQYUN-8762】首页默认及echars颜色调整
const findItem: any = props.chartData.find((item: any) => item.type == type);
if (findItem && findItem.color) {
obj.color = findItem.color;
}
// update-end--author:liaozhiyang---date:20240407---for【QQYUN-8762】首页默认及echars颜色调整
// update-begin-author:liusq date:2023-7-12 for: [issues/613] LineMulti 在数据不对齐时,横坐标计算错误
let data = [];
xAxisData.forEach((x) => {
let dataArr = props.chartData.filter((item) => type === item.type && item.name == x);
if (dataArr && dataArr.length > 0) {
data.push(dataArr[0].value);
} else {
data.push(null);
}
});
// update-end-author:liusq date:2023-7-12 for: [issues/613] LineMulti 在数据不对齐时,横坐标计算错误
//data数据
obj['data'] = data;
seriesData.push(obj);
});
option.series = seriesData;
option.xAxis.data = xAxisData;
console.log('option', option);
setOptions(option);
getInstance()?.off('click', onClick);
getInstance()?.on('click', onClick);
}
function onClick(params) {
emit('click', params);
}
return { chartRef };
},
});
</script>

View File

@ -0,0 +1,89 @@
<template>
<div ref="chartRef" :style="{ height, width }"></div>
</template>
<script lang="ts">
import { defineComponent, PropType, ref, Ref, watchEffect, reactive, watch } from 'vue';
import { useECharts } from '/@/hooks/web/useECharts';
import { cloneDeep } from 'lodash-es';
export default defineComponent({
name: 'Pie',
props: {
chartData: {
type: Array,
default: () => [],
},
size: {
type: Object,
default: () => {},
},
option: {
type: Object,
default: () => ({}),
},
width: {
type: String as PropType<string>,
default: '100%',
},
height: {
type: String as PropType<string>,
default: 'calc(100vh - 78px)',
},
},
emits: ['click'],
setup(props, { emit }) {
const chartRef = ref<HTMLDivElement | null>(null);
const { setOptions, getInstance, resize } = useECharts(chartRef as Ref<HTMLDivElement>);
const option = reactive({
tooltip: {
formatter: '{b} ({c})',
},
series: [
{
type: 'pie',
radius: '72%',
center: ['50%', '55%'],
data: [],
labelLine: { show: true },
label: {
show: true,
formatter: '{b} \n ({d}%)',
color: '#B1B9D3',
},
},
],
});
watchEffect(() => {
props.chartData && initCharts();
});
/**
* 监听拖拽大小变化
*/
watch(
() => props.size,
() => {
resize();
},
{
immediate: true,
}
);
function initCharts() {
if (props.option) {
Object.assign(option, cloneDeep(props.option));
}
option.series[0].data = props.chartData;
setOptions(option);
resize();
getInstance()?.off('click', onClick);
getInstance()?.on('click', onClick);
}
function onClick(params) {
emit('click', params);
}
return { chartRef };
},
});
</script>

View File

@ -0,0 +1,282 @@
# 报表组件文档
## 柱状图
##### 引用方式
```js
import Bar from '/@/components/chart/Bar.vue';
```
##### 参数列表
| 参数名 | 类型 | 必填 | 说明 |
| --------- | ------ | ---- | ---------- |
| chartData | array | ✔️ | 报表数据源 |
| width | number | | 报表宽度 |
| height | number | | 报表高度 |
##### chartData 示例
```json
[
{
"name": "1月",
"value": 320
},
{
"name": "2月",
"value": 457
},
{
"name": "3月",
"value": 182
}
]
```
##### 代码示例
```html
<template>
<Bar :chartData="chartData"></Bar>
</template>
<script lang="ts" setup>
import Bar from '/@/components/chart/Bar.vue';
const chartData = [
{
name: '1月',
value: 320,
},
{
name: '2月',
value: 457,
},
{
name: '3月',
value: 182,
},
];
</script>
<style></style>
```
## 多列柱状图
##### 引用方式
```js
import BarMulti from '/@/components/chart/BarMulti.vue';
```
##### 参数列表
| 参数名 | 类型 | 必填 | 说明 |
| --------- | ------ | ---- | ---------- |
| chartData | array | ✔️ | 报表数据源 |
| width | number | | 报表宽度 |
| height | number | | 报表高度 |
##### chartData 示例
```json
[
{
"name": "1月",
"value": 320,
"type": "2021"
},
{
"name": "2月",
"value": 457,
"type": "2021"
},
{
"name": "3月",
"value": 182,
"type": "2021"
},
{
"name": "1月",
"value": 240,
"type": "2022"
},
{
"name": "2月",
"value": 357,
"type": "2022"
},
{
"name": "3月",
"value": 456,
"type": "2022"
}
]
```
## 迷你柱状图
同柱形图,修改配置即可
## 面积图
##### 引用方式
```js
import Line from '/@/components/chart/Line.vue';
```
##### 参数列表
| 参数名 | 类型 | 必填 | 说明 |
| --------- | ------ | ---- | ---------- |
| chartData | array | ✔️ | 报表数据源 |
| width | number | | 报表宽度 |
| height | number | | 报表高度 |
| option | object | | 配置项 |
##### chartData 示例
```json
[
{
"name": "1月",
"value": 320
},
{
"name": "2月",
"value": 457
},
{
"name": "3月",
"value": 182
}
]
```
## 多行折线图
##### 引用方式
```js
import LineMulti from '/@/components/chart/LineMulti.vue';
```
##### 参数列表
| 参数名 | 类型 | 必填 | 说明 |
| --------- | ------ | ---- | ---------- |
| chartData | array | ✔️ | 报表数据源 |
| width | number | | 报表宽度 |
| height | number | | 报表高度 |
| option | object | | 配置项 |
##### chartData 示例
同柱形图
## 饼状图
##### 引用方式
```js
import Pie from '/@/components/chart/Pie';
```
##### 参数列表
| 参数名 | 类型 | 必填 | 说明 |
| --------- | ------ | ---- | ---------- |
| chartData | array | ✔️ | 报表数据源 |
| width | number | | 报表宽度 |
| height | number | | 报表高度 |
| option | object | | 配置项 |
##### chartData 示例
```json
[
{ "name": "一月", "value": 40 },
{ "name": "二月", "value": 21 },
{ "name": "三月", "value": 17 },
{ "name": "四月", "value": 13 },
{ "name": "五月", "value": 9 }
]
```
## 雷达图
##### 引用方式
```js
import Radar from '/@/components/chart/Radar';
```
##### 参数列表
| 参数名 | 类型 | 必填 | 说明 |
| --------- | ------ | ---- | ---------- |
| chartData | array | ✔️ | 报表数据源 |
| width | number | | 报表宽度 |
| height | number | | 报表高度 |
| option | object | | 配置项 |
##### chartData 示例
```json
[
{ "item": "一月", "score": 40 },
{ "item": "二月", "score": 20 },
{ "item": "三月", "score": 67 },
{ "item": "四月", "score": 43 },
{ "item": "五月", "score": 90 }
]
```
## 仪表盘
##### 引用方式
```js
import Gauge from '/@/components/chart/Gauge';
```
##### 参数列表
| 参数名 | 类型 | 必填 | 说明 |
| --------- | ------ | ---- | ---------- |
| chartData | array | ✔️ | 报表数据源 |
| width | number | | 报表宽度 |
| height | number | | 报表高度 |
| option | object | | 配置项 |
## 排名列表
##### 引用方式
```js
import RankList from '@/components/chart/RankList';
```
##### 参数列表
| 参数名 | 类型 | 必填 | 说明 |
| ------ | ------ | ---- | ------------------------ |
| title | string | | 报表标题 |
| list | array | | 排名列表数据 |
| height | number | | 报表高度,默认自适应高度 |
##### list 示例
```json
[
{ "name": "北京朝阳 1 号店", "total": 1981 },
{ "name": "北京朝阳 2 号店", "total": 1359 },
{ "name": "北京朝阳 3 号店", "total": 1354 },
{ "name": "北京朝阳 4 号店", "total": 263 },
{ "name": "北京朝阳 5 号店", "total": 446 },
{ "name": "北京朝阳 6 号店", "total": 796 }
]
```

View File

@ -0,0 +1,89 @@
<template>
<div ref="chartRef" :style="{ height, width }"></div>
</template>
<script lang="ts">
import { defineComponent, PropType, ref, Ref, reactive, watchEffect } from 'vue';
import { useECharts } from '/@/hooks/web/useECharts';
import { cloneDeep } from 'lodash-es';
export default defineComponent({
name: 'Radar',
props: {
chartData: {
type: Array,
default: () => [],
},
option: {
type: Object,
default: () => ({}),
},
width: {
type: String as PropType<string>,
default: '100%',
},
height: {
type: String as PropType<string>,
default: 'calc(100vh - 78px)',
},
},
setup(props) {
const chartRef = ref<HTMLDivElement | null>(null);
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
const option = reactive({
title: {
text: '基础雷达图',
},
legend: {
data: ['文综'],
},
radar: {
indicator: [{ name: '历史' }, { name: '地理' }, { name: '生物' }, { name: '化学' }, { name: '物理' }, { name: '政治' }],
},
series: [
{
type: 'radar' as 'custom',
data: [
{
value: [82, 70, 60, 55, 90, 66],
name: '文综',
},
],
},
],
});
watchEffect(() => {
props.chartData && initCharts();
});
function initCharts() {
if (props.option) {
Object.assign(option, cloneDeep(props.option));
}
//图例类型
let typeArr = Array.from(new Set(props.chartData.map((item) => item.type)));
//雷达数据
let indicator = Array.from(
new Set(
props.chartData.map((item) => {
let { name, max } = item;
return { name, max };
})
)
);
let data = [];
typeArr.forEach((type) => {
let obj = { name: type };
let chartArr = props.chartData.filter((item) => type === item.type);
obj['value'] = chartArr.map((item) => item.value);
//data数据
data.push(obj);
});
option.radar.axisName = indicator;
option.series[0]['data'] = data;
setOptions(option);
}
return { chartRef };
},
});
</script>

View File

@ -0,0 +1,79 @@
<template>
<div class="rank">
<h4 class="title">{{ title }}</h4>
<ul class="list" :style="{ height: height ? `${height}px` : 'auto', overflow: 'auto' }">
<li :key="index" v-for="(item, index) in list">
<span :class="index < 3 ? 'active' : null">{{ index + 1 }}</span>
<span>{{ item.name }}</span>
<span>{{ item.total }}</span>
</li>
</ul>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'RankList',
props: {
title: {
type: String,
default: '',
},
list: {
type: Array,
default: null,
},
height: {
type: Number,
default: null,
},
},
});
</script>
<style lang="less" scoped>
.rank {
padding: 0 32px 32px 72px;
.list {
margin: 25px 0 0;
padding: 0;
list-style: none;
li {
margin-top: 16px;
span {
font-size: 14px;
line-height: 22px;
&:first-child {
background-color: #f5f5f5;
color: rgba(0, 0, 0, 0.65);
border-radius: 20px;
display: inline-block;
font-size: 12px;
font-weight: 600;
margin-right: 24px;
height: 20px;
line-height: 20px;
width: 20px;
text-align: center;
}
&.active {
background-color: #314659;
color: #fff;
}
&:last-child {
float: right;
}
}
}
}
}
.mobile .rank {
padding: 0 32px 32px 32px;
}
</style>

View File

@ -0,0 +1,91 @@
<template>
<div ref="chartRef" :style="{ height, width }"></div>
</template>
<script lang="ts">
import { defineComponent, PropType, ref, Ref, reactive, watchEffect } from 'vue';
import { useECharts } from '/@/hooks/web/useECharts';
import { cloneDeep } from 'lodash-es';
export default defineComponent({
name: 'single-line',
props: {
chartData: {
type: Array,
default: () => [],
},
option: {
type: Object,
default: () => ({}),
},
width: {
type: String as PropType<string>,
default: '100%',
},
height: {
type: String as PropType<string>,
default: 'calc(100vh - 78px)',
},
// update-begin--author:liaozhiyang---date:20240407---for【QQYUN-8762】首页默认及echars颜色调整
seriesColor: {
type: String,
default: '#1890ff',
},
// update-end--author:liaozhiyang---date:20240407---for【QQYUN-8762】首页默认及echars颜色调整
},
setup(props) {
const chartRef = ref<HTMLDivElement | null>(null);
const { setOptions, echarts } = useECharts(chartRef as Ref<HTMLDivElement>);
const option = reactive({
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
label: {
show: true,
backgroundColor: '#333',
},
},
},
xAxis: {
type: 'category',
data: [],
},
yAxis: {
type: 'value',
},
series: [
{
type: 'line',
showSymbol: false,
smooth: true,
areaStyle: {},
data: [],
color: props.seriesColor,
},
],
});
watchEffect(() => {
props.chartData && initCharts();
});
function initCharts() {
if (props.option) {
Object.assign(option, cloneDeep(props.option));
}
let seriesData = props.chartData.map((item) => {
return item.value;
});
let xAxisData = props.chartData.map((item) => {
return item.name;
});
option.series[0].data = seriesData;
// update-begin--author:liaozhiyang---date:20240407---for【QQYUN-8762】首页默认及echars颜色调整
option.series[0].color = props.seriesColor;
// update-end--author:liaozhiyang---date:20240407---for【QQYUN-8762】首页默认及echars颜色调整
option.xAxis.data = xAxisData;
setOptions(option);
}
return { chartRef };
},
});
</script>

View File

@ -0,0 +1,107 @@
<template>
<div ref="chartRef" :style="{ height, width }"></div>
</template>
<script lang="ts">
import { defineComponent, PropType, ref, Ref, reactive, watchEffect, watch } from 'vue';
import { useECharts } from '/@/hooks/web/useECharts';
import { cloneDeep } from 'lodash-es';
export default defineComponent({
name: 'StackBar',
props: {
chartData: {
type: Array,
default: () => [],
required: true,
},
size: {
type: Object,
default: () => {},
},
option: {
type: Object,
default: () => ({}),
},
type: {
type: String as PropType<string>,
default: 'bar',
},
width: {
type: String as PropType<string>,
default: '100%',
},
height: {
type: String as PropType<string>,
default: 'calc(100vh - 78px)',
},
},
setup(props) {
const chartRef = ref<HTMLDivElement | null>(null);
const { setOptions, echarts, resize } = useECharts(chartRef as Ref<HTMLDivElement>);
const option = reactive({
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
label: {
show: true,
backgroundColor: '#333',
},
},
},
legend: {
top: 30,
},
grid: {
top: 60,
},
xAxis: {
type: 'value',
},
yAxis: {
type: 'category',
data: [],
},
series: [],
});
watchEffect(() => {
props.chartData && initCharts();
});
/**
* 监听拖拽大小变化
*/
watch(
() => props.size,
() => {
console.log('props.size', props.size);
resize();
},
{
immediate: true,
}
);
function initCharts() {
if (props.option) {
Object.assign(option, cloneDeep(props.option));
}
//图例类型
let typeArr = Array.from(new Set(props.chartData.map((item) => item.type)));
//轴数据
let yAxisData = Array.from(new Set(props.chartData.map((item) => item.name)));
let seriesData = [];
typeArr.forEach((type) => {
let obj = { name: type, type: props.type, stack: 'total' };
let chartArr = props.chartData.filter((item) => type === item.type);
//data数据
obj['data'] = chartArr.map((item) => item.value);
seriesData.push(obj);
});
option.series = seriesData;
option.yAxis.data = yAxisData;
setOptions(option);
}
return { chartRef };
},
});
</script>

View File

@ -0,0 +1,90 @@
<template>
<div class="chart-trend">
{{ term }}
<span>{{ rate }}%</span>
<span :class="['trend-icon', trend]"><Icon :icon="'ant-design:caret-' + trend + '-outlined'" /></span>
</div>
</template>
<script lang="ts">
import { defineComponent, computed } from 'vue';
export default defineComponent({
name: 'Trend',
props: {
// 同title
term: {
type: String,
default: '',
required: true,
},
// 百分比
percentage: {
type: Number,
default: null,
},
type: {
type: Boolean,
default: null,
},
target: {
type: Number,
default: 0,
},
value: {
type: Number,
default: 0,
},
fixed: {
type: Number,
default: 2,
},
},
setup(props) {
const trend = computed(() => {
let type = props.type === null ? props.value >= props.target : props.type;
return type ? 'up' : 'down';
});
const rate = computed(() =>
(props.percentage === null ? (Math.abs(props.value - props.target) * 100) / props.target : props.percentage).toFixed(props.fixed)
);
return {
trend,
rate,
};
},
});
</script>
<style lang="less" scoped>
.chart-trend {
display: inline-block;
font-size: 14px;
line-height: 22px;
.trend-icon {
font-size: 12px;
&.up,
&.down {
margin-left: 4px;
position: relative;
top: 1px;
i {
font-size: 12px;
transform: scale(0.83);
}
}
&.up {
color: #f5222d;
}
&.down {
color: #52c41a;
top: -1px;
}
}
}
</style>