feat;全局组件

This commit is contained in:
wangzenghua 2025-01-21 03:53:24 +00:00
parent 930ce1f1f3
commit 38c19cbf06
16 changed files with 551 additions and 228 deletions

View File

@ -17,8 +17,10 @@
}, },
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "^2.3.1", "@element-plus/icons-vue": "^2.3.1",
"@vueuse/core": "^12.4.0",
"axios": "^1.6.5", "axios": "^1.6.5",
"dayjs": "^1.11.11", "dayjs": "^1.11.11",
"echarts": "^5.6.0",
"element-plus": "^2.7.3", "element-plus": "^2.7.3",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"js-base64": "^3.7.7", "js-base64": "^3.7.7",

View File

@ -0,0 +1,86 @@
<template>
<div ref="chartRef" :style="{ height, width }"></div>
</template>
<script>
import { ref, reactive, watchEffect } from 'vue';
import { cloneDeep } from 'lodash';
import { useEcharts } from '../../hooks/useEcharts';
export default {
name: 'CustomEchartBar',
props: {
chartData: {
type: Array,
default: () => [],
},
option: {
type: Object,
default: () => ({}),
},
width: {
type: String,
default: '100%',
},
height: {
type: String,
default: 'calc(100vh - 78px)',
},
seriesColor: {
type: String,
default: '#1890ff',
},
},
setup(props) {
const chartRef = ref(null);
const { setOptions } = useEcharts(chartRef);
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;
option.series[0].color = props.seriesColor;
option.xAxis.data = xAxisData;
setOptions(option);
}
return { chartRef };
},
};
</script>

View File

@ -1,5 +1,5 @@
import SvgIcon from './svg-icon'; import SvgIcon from './svg-icon';
import CustomRichEditor from './custom-rich-editor'; import CustomRichEditor from './custom-rich-editor';
import CustomEchartBar from './custom-echart-bar';
export { SvgIcon, CustomRichEditor }; export { SvgIcon, CustomEchartBar, CustomRichEditor };

View File

@ -0,0 +1,84 @@
import { ref, computed, unref } from 'vue';
import { useEventListener } from './useEventListener';
let globalScreenRef;
let globalWidthRef;
let globalRealWidthRef;
const screenMap = new Map();
screenMap.set('XS', 480);
screenMap.set('SM', 576);
screenMap.set('MD', 768);
screenMap.set('LG', 992);
screenMap.set('XL', 1200);
screenMap.set('XXL', 1600);
export function useBreakpoint() {
return {
screenRef: computed(() => unref(globalScreenRef)),
widthRef: globalWidthRef,
realWidthRef: globalRealWidthRef,
};
}
// Just call it once
export function createBreakpointListen(fn) {
const screenRef = ref('XL');
const realWidthRef = ref(window.innerWidth);
function getWindowWidth() {
const width = document.body.clientWidth;
const xs = screenMap.get('XS');
const sm = screenMap.get('SM');
const md = screenMap.get('MD');
const lg = screenMap.get('LG');
const xl = screenMap.get('XL');
const xxl = screenMap.set('XXL', 1600);
if (width < xs) {
screenRef.value = xs;
} else if (width < sm) {
screenRef.value = sm;
} else if (width < md) {
screenRef.value = md;
} else if (width < lg) {
screenRef.value = lg;
} else if (width < xl) {
screenRef.value = xl;
} else {
screenRef.value = xxl;
}
realWidthRef.value = width;
}
useEventListener({
el: window,
name: 'resize',
listener: () => {
getWindowWidth();
resizeFn();
},
// wait: 100,
});
getWindowWidth();
globalScreenRef = computed(() => unref(screenRef));
globalWidthRef = computed(() => screenMap.get(unref(screenRef)));
globalRealWidthRef = computed(() => unref(realWidthRef));
function resizeFn() {
fn?.({
screen: globalScreenRef,
width: globalWidthRef,
realWidth: globalRealWidthRef,
screenMap,
});
}
resizeFn();
return {
screenRef: globalScreenRef,
widthRef: globalWidthRef,
realWidthRef: globalRealWidthRef,
};
}

View File

@ -0,0 +1,107 @@
import { unref, nextTick, watch, computed, ref } from 'vue';
import { useDebounceFn, tryOnUnmounted } from '@vueuse/core';
import { useTimeoutFn } from './useTimeout';
import { useEventListener } from './useEventListener';
import { useBreakpoint } from './useBreakpoint';
import echarts from '../utils/echarts';
export const useEcharts = (elRef, theme = 'default') => {
const getDarkMode = computed(() => {
return theme === 'default' ? 'dark' : theme;
});
let chartInstance = null;
let resizeFn = resize;
const cacheOptions = ref({});
let removeResizeFn = () => {};
resizeFn = useDebounceFn(resize, 200);
const getOptions = computed(() => {
if (getDarkMode.value !== 'dark') {
return cacheOptions.value;
}
return {
backgroundColor: 'transparent',
...cacheOptions.value,
};
});
function initCharts(t = theme) {
const el = unref(elRef);
if (!el || !unref(el)) {
return;
}
chartInstance = echarts.init(el, t);
const { removeEvent } = useEventListener({
el: window,
name: 'resize',
listener: resizeFn,
});
removeResizeFn = removeEvent;
const { widthRef } = useBreakpoint();
if (unref(widthRef) <= 768 || el.offsetHeight === 0) {
useTimeoutFn(() => {
resizeFn();
}, 30);
}
}
function setOptions(options = {}, clear = true) {
cacheOptions.value = options;
if (unref(elRef)?.offsetHeight === 0) {
useTimeoutFn(() => {
setOptions(unref(getOptions));
}, 30);
return;
}
nextTick(() => {
useTimeoutFn(() => {
if (!chartInstance) {
initCharts(getDarkMode.value ?? 'default');
if (!chartInstance) return;
}
clear && chartInstance?.clear();
chartInstance?.setOption(unref(getOptions));
}, 30);
});
}
function resize() {
chartInstance?.resize();
}
watch(
() => getDarkMode.value,
(theme) => {
if (chartInstance) {
chartInstance.dispose();
initCharts(theme);
setOptions(cacheOptions.value);
}
}
);
tryOnUnmounted(() => {
if (!chartInstance) return;
removeResizeFn();
chartInstance.dispose();
chartInstance = null;
});
function getInstance() {
if (!chartInstance) {
initCharts(getDarkMode.value ?? 'default');
}
return chartInstance;
}
return {
setOptions,
resize,
echarts,
getInstance,
};
};

View File

@ -0,0 +1,38 @@
import { ref, watch, unref } from 'vue';
import { useThrottleFn, useDebounceFn } from '@vueuse/core';
export function useEventListener({ el = window, name, listener, options, autoRemove = true, isDebounce = true, wait = 80 }) {
let remove;
const isAddRef = ref(false);
if (el) {
const element = ref(el);
const handler = isDebounce ? useDebounceFn(listener, wait) : useThrottleFn(listener, wait);
const realHandler = wait ? handler : listener;
const removeEventListener = (e) => {
isAddRef.value = true;
e.removeEventListener(name, realHandler, options);
};
const addEventListener = (e) => e.addEventListener(name, realHandler, options);
const removeWatch = watch(
element,
(v, _ov, cleanUp) => {
if (v) {
!unref(isAddRef) && addEventListener(v);
cleanUp(() => {
autoRemove && removeEventListener(v);
});
}
},
{ immediate: true }
);
remove = () => {
removeEventListener(element.value);
removeWatch();
};
}
return { removeEvent: remove };
}

View File

@ -0,0 +1,44 @@
import { ref, watch } from 'vue';
import { tryOnUnmounted } from '@vueuse/core';
export function useTimeoutFn(handle, wait, native = false) {
if (typeof handle !== 'function') {
throw new Error('handle is not Function!');
}
const { readyRef, stop, start } = useTimeoutRef(wait);
if (native) {
handle();
} else {
watch(
readyRef,
(maturity) => {
maturity && handle();
},
{ immediate: false }
);
}
return { readyRef, stop, start };
}
export function useTimeoutRef(wait) {
const readyRef = ref(false);
let timer;
function stop() {
readyRef.value = false;
timer && window.clearTimeout(timer);
}
function start() {
stop();
timer = setTimeout(() => {
readyRef.value = true;
}, wait);
}
start();
tryOnUnmounted(stop);
return { readyRef, stop, start };
}

View File

@ -1,8 +0,0 @@
// import * as components from '../../../global/components';
// // 全局注册组件
// export const registerGlobalComponents = (app) => {
// Object.keys(components).forEach((key) => {
// app.component(key, components[key]);
// });
// };

51
main/src/utils/echarts.js Normal file
View File

@ -0,0 +1,51 @@
import * as echarts from 'echarts/core';
import { BarChart, LineChart, PieChart, MapChart, PictorialBarChart, RadarChart } from 'echarts/charts';
import {
TitleComponent,
TooltipComponent,
GridComponent,
PolarComponent,
AriaComponent,
ParallelComponent,
LegendComponent,
RadarComponent,
ToolboxComponent,
DataZoomComponent,
VisualMapComponent,
TimelineComponent,
CalendarComponent,
GraphicComponent,
} from 'echarts/components';
// TODO 如果想换成SVG渲染就导出SVGRenderer
// 并且放到 echarts.use 里,注释掉 CanvasRenderer
import { /*SVGRenderer*/ CanvasRenderer } from 'echarts/renderers';
echarts.use([
LegendComponent,
TitleComponent,
TooltipComponent,
GridComponent,
PolarComponent,
AriaComponent,
ParallelComponent,
BarChart,
LineChart,
PieChart,
MapChart,
RadarChart,
// TODO 因为要兼容Online图表自适应打印所以改成 CanvasRenderer可能会模糊
CanvasRenderer,
PictorialBarChart,
RadarComponent,
ToolboxComponent,
DataZoomComponent,
VisualMapComponent,
TimelineComponent,
CalendarComponent,
GraphicComponent,
]);
export default echarts;

View File

@ -1,6 +1,8 @@
<template> <template>
<div class="platform"> <div class="platform">
<h2>平台首页</h2> <h2>平台首页</h2>
<custom-echart-bar height="50vh" :option="{ title: { text: '销售额排行', left: 'center' } }" />
</div> </div>
</template> </template>
<script setup> <script setup>

View File

@ -791,6 +791,11 @@
resolved "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz#1d12873a8e49567371f2a75fe3e7f7edca6662d8" resolved "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz#1d12873a8e49567371f2a75fe3e7f7edca6662d8"
integrity sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ== integrity sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==
"@types/web-bluetooth@^0.0.20":
version "0.0.20"
resolved "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz#f066abfcd1cbe66267cdbbf0de010d8a41b41597"
integrity sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==
"@ungap/structured-clone@^1.2.0": "@ungap/structured-clone@^1.2.0":
version "1.2.1" version "1.2.1"
resolved "https://registry.npmmirror.com/@ungap/structured-clone/-/structured-clone-1.2.1.tgz#28fa185f67daaf7b7a1a8c1d445132c5d979f8bd" resolved "https://registry.npmmirror.com/@ungap/structured-clone/-/structured-clone-1.2.1.tgz#28fa185f67daaf7b7a1a8c1d445132c5d979f8bd"
@ -929,6 +934,16 @@
resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.13.tgz#87b309a6379c22b926e696893237826f64339b6f" resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.13.tgz#87b309a6379c22b926e696893237826f64339b6f"
integrity sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ== integrity sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==
"@vueuse/core@^12.4.0":
version "12.4.0"
resolved "https://registry.npmmirror.com/@vueuse/core/-/core-12.4.0.tgz#7a17f12fe941a16fb2ca9dbd60106975290bb34d"
integrity sha512-XnjQYcJwCsyXyIafyA6SvyN/OBtfPnjvJmbxNxQjCcyWD198urwm5TYvIUUyAxEAN0K7HJggOgT15cOlWFyLeA==
dependencies:
"@types/web-bluetooth" "^0.0.20"
"@vueuse/metadata" "12.4.0"
"@vueuse/shared" "12.4.0"
vue "^3.5.13"
"@vueuse/core@^9.1.0": "@vueuse/core@^9.1.0":
version "9.13.0" version "9.13.0"
resolved "https://registry.npmmirror.com/@vueuse/core/-/core-9.13.0.tgz#2f69e66d1905c1e4eebc249a01759cf88ea00cf4" resolved "https://registry.npmmirror.com/@vueuse/core/-/core-9.13.0.tgz#2f69e66d1905c1e4eebc249a01759cf88ea00cf4"
@ -939,11 +954,23 @@
"@vueuse/shared" "9.13.0" "@vueuse/shared" "9.13.0"
vue-demi "*" vue-demi "*"
"@vueuse/metadata@12.4.0":
version "12.4.0"
resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-12.4.0.tgz#8a21ceec6fb3866b4ed445f0a3dc45dd5a4f2b64"
integrity sha512-AhPuHs/qtYrKHUlEoNO6zCXufu8OgbR8S/n2oMw1OQuBQJ3+HOLQ+EpvXs+feOlZMa0p8QVvDWNlmcJJY8rW2g==
"@vueuse/metadata@9.13.0": "@vueuse/metadata@9.13.0":
version "9.13.0" version "9.13.0"
resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.13.0.tgz#bc25a6cdad1b1a93c36ce30191124da6520539ff" resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.13.0.tgz#bc25a6cdad1b1a93c36ce30191124da6520539ff"
integrity sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ== integrity sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==
"@vueuse/shared@12.4.0":
version "12.4.0"
resolved "https://registry.npmmirror.com/@vueuse/shared/-/shared-12.4.0.tgz#2d4b2d51068db0cc623f6e0342c54a652a9b466d"
integrity sha512-9yLgbHVIF12OSCojnjTIoZL1+UA10+O4E1aD6Hpfo/DKVm5o3SZIwz6CupqGy3+IcKI8d6Jnl26EQj/YucnW0Q==
dependencies:
vue "^3.5.13"
"@vueuse/shared@9.13.0": "@vueuse/shared@9.13.0":
version "9.13.0" version "9.13.0"
resolved "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.13.0.tgz#089ff4cc4e2e7a4015e57a8f32e4b39d096353b9" resolved "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.13.0.tgz#089ff4cc4e2e7a4015e57a8f32e4b39d096353b9"
@ -2135,6 +2162,14 @@ dunder-proto@^1.0.0, dunder-proto@^1.0.1:
es-errors "^1.3.0" es-errors "^1.3.0"
gopd "^1.2.0" gopd "^1.2.0"
echarts@^5.6.0:
version "5.6.0"
resolved "https://registry.npmmirror.com/echarts/-/echarts-5.6.0.tgz#2377874dca9fb50f104051c3553544752da3c9d6"
integrity sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==
dependencies:
tslib "2.3.0"
zrender "5.6.1"
ejs@^3.1.6: ejs@^3.1.6:
version "3.1.10" version "3.1.10"
resolved "https://registry.npmmirror.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b" resolved "https://registry.npmmirror.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b"
@ -6423,6 +6458,11 @@ trough@^1.0.0:
resolved "https://registry.npmmirror.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" resolved "https://registry.npmmirror.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406"
integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==
tslib@2.3.0:
version "2.3.0"
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
tslib@^2.0.3, tslib@^2.6.2: tslib@^2.0.3, tslib@^2.6.2:
version "2.8.1" version "2.8.1"
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" resolved "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
@ -6865,7 +6905,7 @@ vue-router@^4.2.5:
dependencies: dependencies:
"@vue/devtools-api" "^6.6.4" "@vue/devtools-api" "^6.6.4"
vue@^3.5.11: vue@^3.5.11, vue@^3.5.13:
version "3.5.13" version "3.5.13"
resolved "https://registry.npmmirror.com/vue/-/vue-3.5.13.tgz#9f760a1a982b09c0c04a867903fc339c9f29ec0a" resolved "https://registry.npmmirror.com/vue/-/vue-3.5.13.tgz#9f760a1a982b09c0c04a867903fc339c9f29ec0a"
integrity sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ== integrity sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==
@ -7034,3 +7074,10 @@ yocto-queue@^0.1.0:
version "0.1.0" version "0.1.0"
resolved "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" resolved "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
zrender@5.6.1:
version "5.6.1"
resolved "https://registry.npmmirror.com/zrender/-/zrender-5.6.1.tgz#e08d57ecf4acac708c4fcb7481eb201df7f10a6b"
integrity sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==
dependencies:
tslib "2.3.0"

View File

@ -32,8 +32,7 @@
"pinia-plugin-persistedstate": "^3.2.1", "pinia-plugin-persistedstate": "^3.2.1",
"screenfull": "^6.0.2", "screenfull": "^6.0.2",
"vue": "^3.3.11", "vue": "^3.3.11",
"vue-router": "^4.2.5", "vue-router": "^4.2.5"
"vue3-custom-component": "1.1.17"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.23.7", "@babel/core": "^7.23.7",

View File

@ -1,219 +1,8 @@
export const GenKey = (key, prefix = 'EGGY_TEAM_STORE_') => { export const GenKey = (key, prefix = 'SUB_ADMIN_STORE_') => {
return prefix ? prefix + key : key; return prefix ? prefix + key : key;
}; };
export const CONSTANTS = { export const CONSTANTS = {
PREFIX: 'EGGY_TEAM_STORE_', PREFIX: 'SUB_ADMIN_STORE_',
PRIMARY: '#409eff', PRIMARY: '#409eff',
// 总部商品可编辑属性
EDITLIST: ['amount', 'originalPrice', 'activityPrice', 'usePoints', 'points', 'status', 'sortOrder', 'perUseValue', 'displayChannelList'],
// 活动管理
LATITUDE: [
{
label: '副本【x】通关计分榜',
value: 10,
},
{
label: '副本【x】速通榜',
value: 11,
},
{
label: '副本【x】大师榜失误最少',
value: 12,
},
{
label: '副本【x】巅峰榜',
value: 13,
},
{
label: '最强闯关计分榜',
value: 14,
},
{
label: '挑战模式通关计分榜',
value: 20,
},
{
label: '挑战模式第【x】关速通榜',
value: 21,
},
{
label: '挑战模式大师榜(失误最少)',
value: 22,
},
{
label: '挑战模式巅峰榜',
value: 23,
},
],
// 维度说明
LATITUDETIPS: {
default: '榜单常驻,用户所有的游戏通关数据得分累计排列显示,不管用户参与什么模式,是否通关,只要游戏结束时候的分数累计进行排行',
10: '在榜单发起时间内,指定某个副本的通关分数总和(不通关则不计入总分)',
11: '在榜单发起时间内,指定某个副本的通关时间最快(只刷新计入最快的那次)',
12: '在榜单发起时间内,指定某个副本的扣分最少(只刷新计入扣分最少的那次)',
13: '在榜单发起时间内,指定某个副本的得分最高(只刷新计入得分最高的那次)',
14: '在榜单发起时间内,任意副本的得分总和排名(不通关则不计入总分)',
20: '在榜单发起时间内,挑战模式的通关分数总和(不通关则不计入总分)',
21: '在榜单发起时间内,指定挑战模式的某些关卡的通关时间最快(只刷新计入最快的那次)',
22: '在榜单发起时间内,挑战模式的扣分最少(只刷新计入扣分最少的那次)',
23: '在榜单发起时间内,挑战模式的得分最高(只刷新计入得分最高的那次)',
},
// 支付方式
PAYTYPE: {
prop: 'payType',
label: '支付方式',
type: 'select',
dicData: [
{
label: '余额',
value: 1,
},
{
label: '微信',
value: 2,
},
{
label: '支付宝',
value: 3,
},
{
label: '商家券',
value: 4,
},
{
label: '平台券',
value: 5,
},
{
label: '商场券',
value: 6,
},
{
label: '积分',
value: 7,
},
{
label: '美团',
value: 8,
},
{
label: '现金',
value: 9,
},
{
label: '抖音',
value: 10,
},
{
label: '小红书',
value: 11,
},
{
label: '线下优惠券',
value: 12,
},
{
label: '首单立减',
value: 13,
},
{
label: '其它一',
value: 20,
},
{
label: '其它二',
value: 21,
},
{
label: '其它三',
value: 22,
},
],
formatter: (row) => {
let value = '';
switch (row.payType) {
case 1: {
value = '余额';
break;
}
case 2: {
value = '微信';
break;
}
case 3: {
value = '支付宝';
break;
}
case 4: {
value = '商家券';
break;
}
case 5: {
value = '平台券';
break;
}
case 6: {
value = '商场券';
break;
}
case 7: {
value = '积分';
break;
}
case 8: {
value = '美团';
break;
}
case 9: {
value = '现金';
break;
}
case 10: {
value = '抖音';
break;
}
case 11: {
value = '小红书';
break;
}
case 12: {
value = '线下优惠券';
break;
}
case 13: {
value = '首单立减';
break;
}
case 20: {
value = '其它一';
break;
}
case 21: {
value = '其它二';
break;
}
case 22: {
value = '其它三';
break;
}
}
return value;
},
},
// 支付分类
PAY_CATEGORIES: [
{ prop: 'weixin', name: '微信' },
{ prop: 'alipay', name: '支付宝' },
{ prop: 'cash', name: '现金' },
{ prop: 'balance', name: '余额' },
{ prop: 'market', name: '商场券' },
{ prop: 'platform', name: '平台券' },
{ prop: 'store', name: '门店券' },
{ prop: 'meituan', name: '美团' },
{ prop: 'tiktok', name: '抖音' },
{ prop: 'xiaohongshu', name: '小红书' },
{ prop: 'offline', name: '线下优惠券' },
{ prop: 'firstOrder', name: '首单立减' },
],
}; };

View File

@ -1,5 +1,16 @@
import * as components from '../../../main/src/components'; import * as components from '../../../main/src/components';
// const modules = import.meta.glob('../../../main/src/components/**/**.vue');
// const components = Object.keys(modules).reduce((acc, path) => {
// const component = modules[path].default || modules[path];
// const componentName = path
// .split('/')
// .pop()
// .replace(/\.\w+$/, '');
// acc[componentName] = component;
// return acc;
// }, {});
// 全局注册组件 // 全局注册组件
export const registerGlobalComponents = (app) => { export const registerGlobalComponents = (app) => {
Object.keys(components).forEach((key) => { Object.keys(components).forEach((key) => {

View File

@ -0,0 +1,52 @@
const colors = ['#4db6ac', '#ffb74d', '#64b5f6', '#e57373', '#9575cd', '#a1887f', '#90a4ae', '#4dd0e1', '#81c784', '#ff8a65'];
export const getData = (() => {
let dottedBase = +new Date();
const barDataSource = [];
const barMultiData = [];
const barLineData = [];
const barLineColors = [];
for (let i = 0; i < 20; i++) {
let obj = { name: '', value: 0 };
const date = new Date((dottedBase += 1000 * 3600 * 24));
obj.name = [date.getFullYear(), date.getMonth() + 1, date.getDate()].join('-');
obj.value = Math.random() * 200;
barDataSource.push(obj);
}
for (let j = 0; j < 2; j++) {
for (let i = 0; i < 20; i++) {
let obj = { name: '', value: 0, type: 2010 + j + '' };
const date = new Date(dottedBase + 1000 * 3600 * 24 * i);
obj.name = [date.getFullYear(), date.getMonth() + 1, date.getDate()].join('-');
obj.value = Math.random() * 200;
barMultiData.push(obj);
}
}
const pieData = [
{ value: 335, name: '客服电话' },
{ value: 310, name: '奥迪官网' },
{ value: 234, name: '媒体曝光' },
{ value: 135, name: '质检总局' },
{ value: 105, name: '其他' },
];
const radarData = [
{ value: 75, name: '政治', type: '文综', max: 100 },
{ value: 65, name: '历史', type: '文综', max: 100 },
{ value: 55, name: '地理', type: '文综', max: 100 },
{ value: 74, name: '化学', type: '文综', max: 100 },
{ value: 38, name: '物理', type: '文综', max: 100 },
{ value: 88, name: '生物', type: '文综', max: 100 },
];
for (let j = 0; j < 2; j++) {
for (let i = 0; i < 15; i++) {
let obj = { name: '', value: 0, type: 2010 + j + '', seriesType: j >= 1 ? 'line' : 'bar' };
const date = new Date(dottedBase + 1000 * 3600 * 24 * i);
obj.name = [date.getFullYear(), date.getMonth() + 1, date.getDate()].join('-');
obj.value = Math.random() * 200;
barLineData.push(obj);
}
barLineColors.push(colors[j]);
}
return { barDataSource, barMultiData, pieData, barLineData, barLineColors, radarData };
})();

View File

@ -1,4 +1,23 @@
<template> <template>
<div>echart</div> <div class="p-4">
<el-card :bordered="false" style="height: 100%">
<el-tabs v-model="activeKey" class="demo-tabs" @tab-click="tabChange">
<el-tab-pane label="柱状图" name="1">
<custom-echart-bar :chart-data="barDataSource" height="50vh" :option="{ title: { text: '销售额排行', left: 'center' } }" />
</el-tab-pane>
</el-tabs>
</el-card>
</div>
</template> </template>
<script setup name="echart"></script>
<script setup>
import { ref } from 'vue';
import { getData } from './chartdemo.data';
const activeKey = ref('1');
const { barDataSource } = getData;
//tab
function tabChange(key) {
console.log('切换的key:', key);
}
</script>