Commit f1a15c83 by renyizhao

大屏修改

parent c03775b8
......@@ -8,6 +8,7 @@ export interface ResourceConfig {
sort: number; // 排序
status?: number; // 状态:0=启用,1=禁用
detailRemark: string; // 详情备注(如:i7-13700K 16核24线程)
compute?: number; // 算力值(TOPS),默认 0,可由运营手动配置
}
// 算力资源配置 API
......
<template>
<div ref="mapRef" class="map-main"></div>
</template>
<script setup>
import { onBeforeUnmount, onMounted, ref, nextTick, inject, watch } from 'vue'
import * as echarts from 'echarts/core'
import { TooltipComponent, VisualMapComponent, GeoComponent, GridComponent, LegendComponent } from 'echarts/components'
import {
TooltipComponent,
VisualMapComponent,
GeoComponent,
GridComponent,
LegendComponent
} from 'echarts/components'
import {
MapChart,
ScatterChart
......@@ -40,7 +45,7 @@ const geoCoordMap = ref({
天津市: [117.190182, 39.125523],
河北省: [114.502462, 38.045494],
山西省: [112.549248, 37.857014],
内蒙古自治区: [111.751990, 40.841470],
内蒙古自治区: [111.75199, 40.84147],
辽宁省: [123.429096, 41.796767],
吉林省: [125.324498, 43.886845],
黑龙江省: [126.642464, 45.802755],
......@@ -51,24 +56,24 @@ const geoCoordMap = ref({
福建省: [119.306239, 26.075302],
江西省: [115.892151, 28.676461],
山东省: [117.000923, 36.675807],
河南省: [113.625367, 34.746570],
河南省: [113.625367, 34.74657],
湖北省: [114.305539, 30.593098],
湖南省: [112.982279, 28.194090],
广东省: [113.264385, 23.129110],
湖南省: [112.982279, 28.19409],
广东省: [113.264385, 23.12911],
广西壮族自治区: [108.320004, 22.824018],
海南省: [110.198289, 20.044008],
重庆市: [106.551559, 29.563010],
重庆市: [106.551559, 29.56301],
四川省: [104.065735, 30.659462],
贵州省: [106.707221, 26.598278],
云南省: [102.712251, 25.040609],
西藏自治区: [91.132212, 29.660359],
陕西省: [108.939838, 34.341275],
甘肃省: [103.823557, 36.058039],
青海省: [101.777820, 36.616990],
宁夏回族自治区: [106.278080, 38.466370],
青海省: [101.77782, 36.61699],
宁夏回族自治区: [106.27808, 38.46637],
新疆维吾尔自治区: [87.617733, 43.792818],
台湾省: [121.520076, 25.047310],
香港特别行政区: [114.165460, 22.275345],
台湾省: [121.520076, 25.04731],
香港特别行政区: [114.16546, 22.275345],
澳门特别行政区: [113.549148, 22.198755]
})
......@@ -107,7 +112,7 @@ const convertData = function (data) {
return res
}
function initMapChart (el) {
function initMapChart(el) {
const chartDom = el
const myChart = echarts.init(chartDom)
echarts.registerMap('china', geoJson)
......@@ -134,7 +139,8 @@ function initMapChart (el) {
},
label: {
show: false,
color: '#fff'
color: '#fff',
fontSize: 32
},
itemStyle: {
borderColor: '#00BDCA',
......@@ -203,7 +209,7 @@ function initMapChart (el) {
padding: [44, 0, 0, 2]
}
},
formatter (params) {
formatter(params) {
const {
// dataIndex,
data
......@@ -248,7 +254,7 @@ function initMapChart (el) {
padding: [44, 0, 0, 7]
}
},
formatter (params) {
formatter(params) {
const {
// dataIndex,
data
......@@ -267,7 +273,6 @@ function initMapChart (el) {
return myChart
}
const mapRef = ref(null)
let chartInst = null
......@@ -288,21 +293,25 @@ onMounted(async () => {
})
// 监听数据变化
watch(() => dashboardData.value.mapData, (newData) => {
mapData2.value = newData || []
if (chartInst) {
chartInst.setOption({
series: [
{
data: convertData(mapData.value)
},
{
data: convertData(mapData2.value)
}
]
})
}
}, { deep: true })
watch(
() => dashboardData.value.mapData,
(newData) => {
mapData2.value = newData || []
if (chartInst) {
chartInst.setOption({
series: [
{
data: convertData(mapData.value)
},
{
data: convertData(mapData2.value)
}
]
})
}
},
{ deep: true }
)
onBeforeUnmount(() => {
window.removeEventListener('resize', resize)
......@@ -315,7 +324,6 @@ onBeforeUnmount(() => {
<style scoped>
.map-main {
width: 100%;
height: 100%;
min-height: 800px;
height: calc(100% - 100px);
}
</style>
......@@ -89,6 +89,7 @@ const fetchComputeDistribution = () => {
name: getDictLabel(DICT_TYPE.COMPUTE_RESOURCE_SOURCE, item.name) || item.name,
value: item.value
}))
console.log('datasets', data.source)
datasets.value.resource = data.resource || []
}
......@@ -110,18 +111,19 @@ const getOption = (which) => {
text: titles[which],
left: 'center',
top: 12,
textStyle: { color: '#77CCFF', fontSize: 28, fontWeight: 600 }
textStyle: { color: '#77CCFF', fontSize: 32, fontWeight: 600 }
},
tooltip: {
trigger: 'item',
formatter: ({ name, value, percent }) => `${name}: ${value} (${percent}%)`
formatter: ({ name, value, percent }) => `${name}: ${value} (${percent}%)`,
textStyle: { fontSize: 32 }
},
legend: {
bottom: 8,
left: 'center',
itemWidth: 12,
itemHeight: 12,
textStyle: { color: '#DAF7FF', fontSize: 18 },
textStyle: { color: '#DAF7FF', fontSize: 32 },
data: data.map((d) => d.name),
formatter: (name) => {
const v = dataMap[name] ?? 0
......@@ -129,36 +131,36 @@ const getOption = (which) => {
return `${name} ${v} (${p}%)`
}
},
graphic: [
{
type: 'text',
left: '50%',
top: '55%',
style: {
text: `${titles[which]}\n总计: ${total}`,
fill: '#FFFFFF',
fontSize: 20,
fontWeight: 'bold',
textAlign: 'center',
textVerticalAlign: 'middle',
lineHeight: 28,
textShadowColor: 'rgba(5,25,32,0.6)',
textShadowBlur: 8
}
}
],
// graphic: [
// {
// type: 'text',
// left: '50%',
// top: '55%',
// style: {
// text: `${titles[which]}\n总计: ${total}`,
// fill: '#FFFFFF',
// fontSize: 32,
// fontWeight: 'bold',
// textAlign: 'center',
// textVerticalAlign: 'middle',
// lineHeight: 28,
// textShadowColor: 'rgba(5,25,32,0.6)',
// textShadowBlur: 8
// }
// }
// ],
series: [
{
name: titles[which],
type: 'pie',
radius: '62%', // 实心饼图(非环形)
center: ['50%', '58%'],
radius: '50%', // 实心饼图(非环形)
center: ['50%', '45%'],
avoidLabelOverlap: true,
selectedMode: false,
labelLayout: { hideOverlap: true },
label: {
color: '#FFFFFF',
fontSize: 20,
fontSize: 32,
formatter: '{b}\n{d}%'
},
labelLine: { length: 18, length2: 10 },
......
......@@ -437,7 +437,7 @@ onBeforeUnmount(() => {
document.removeEventListener('MSFullscreenChange', handleFsChange)
})
// 提供全屏控制给子组件(如 EnergyManage 在“今日电耗”处放按钮调用)
// 提供全屏控制给子组件(如 EnergyManage 在"今日电耗"处放按钮调用)
provide('fsState', { isFullscreen, toggleFullscreen })
</script>
......@@ -474,6 +474,7 @@ provide('fsState', { isFullscreen, toggleFullscreen })
top: 0;
width: 100%;
height: 100%;
overflow: auto;
}
.page-container {
......
......@@ -32,7 +32,7 @@ const dashboardData = inject('dashboardData', {})
let myChart = null
function init () {
function init() {
const chartDom = document.getElementById('nvestment')
if (!myChart) {
myChart = echarts.init(chartDom)
......@@ -52,7 +52,8 @@ function init () {
label: {
backgroundColor: '#6a7985'
}
}
},
textStyle: { fontSize: 32 }
},
legend: {
data: ['上线应用', '上线API'],
......@@ -63,7 +64,7 @@ function init () {
itemGap: 40,
textStyle: {
color: '#77CCFF',
fontSize: 24
fontSize: 32
}
},
grid: {
......@@ -79,7 +80,7 @@ function init () {
boundaryGap: true,
data: years,
axisLabel: {
fontSize: 24,
fontSize: 32,
color: '#ffffff'
},
axisLine: {
......@@ -92,15 +93,15 @@ function init () {
yAxis: [
{
type: 'value',
name: '(万元)',
name: '()',
// min: 0,
// interval: 2,
nameTextStyle: {
fontSize: 24,
fontSize: 32,
color: '#77CCFF'
},
axisLabel: {
fontSize: 24,
fontSize: 32,
color: '#77CCFF'
},
splitLine: {
......@@ -111,13 +112,13 @@ function init () {
},
{
type: 'value',
name: '(万元)',
name: '()',
nameTextStyle: {
fontSize: 24,
fontSize: 32,
color: '#77CCFF'
},
axisLabel: {
fontSize: 24,
fontSize: 32,
color: '#77CCFF'
},
splitLine: {
......@@ -176,9 +177,13 @@ onMounted(() => {
})
// 监听数据变化
watch(() => dashboardData.value.serviceCapability, () => {
init()
}, { deep: true })
watch(
() => dashboardData.value.serviceCapability,
() => {
init()
},
{ deep: true }
)
</script>
<style scoped lang="scss">
......
......@@ -6,36 +6,41 @@
>
<div class="trend-toolbar">
<div class="switcher">
<button
:class="{ active: rangeType === 'd' }"
@click="changeRange('d')"
type="button"
>日</button>
<button
:class="{ active: rangeType === 'm' }"
@click="changeRange('m')"
type="button"
>月</button>
<button
:class="{ active: rangeType === 'y' }"
@click="changeRange('y')"
type="button"
>年</button>
<button :class="{ active: rangeType === 'd' }" @click="changeRange('d')" type="button"
>日</button
>
<button :class="{ active: rangeType === 'm' }" @click="changeRange('m')" type="button"
>月</button
>
<button :class="{ active: rangeType === 'y' }" @click="changeRange('y')" type="button"
>年</button
>
</div>
</div>
<div ref="chartRef" class="echart-wrap"></div>
</div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, inject, watch } from 'vue'
import { ref, onMounted, onBeforeUnmount, watch, inject } from 'vue'
import * as echarts from 'echarts/core'
import { GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
import {
GridComponent,
TooltipComponent,
LegendComponent,
GraphicComponent
} from 'echarts/components'
import { LineChart } from 'echarts/charts'
import { CanvasRenderer } from 'echarts/renderers'
echarts.use([GridComponent, TooltipComponent, LegendComponent, LineChart, CanvasRenderer])
echarts.use([
GridComponent,
TooltipComponent,
LegendComponent,
GraphicComponent,
LineChart,
CanvasRenderer
])
const chartRef = ref(null)
let chart = null
......@@ -129,41 +134,54 @@ const getChartData = () => {
}
// 直接使用后端返回的 countDate
const x = data.map(item => item.countDate)
const y = data.map(item => item.callsCount)
const x = data.map((item) => item.countDate)
const y = data.map((item) => item.callsCount)
return { x, y }
}
function getOption(x, y) {
// ====== 手动调整这些值看效果 ======
// xAxis 文字大小(普通屏下视觉 = 22 * 0.356 ≈ 7.8px,会突破浏览器 12px 字体下限)
const xFontSize = 32
// yAxis 文字大小
const yFontSize = 32
// yAxis 名称("请求次数")文字大小
const yNameFontSize = 32
// tooltip 弹窗文字大小(弹窗是 DOM 渲染到 body,不受外层 transform: scale 影响)
const tooltipFontSize = 32
// legend 文字大小(本图未启用 legend,可选)
// const legendFontSize = 18
// ====== 调整区结束 ======
return {
tooltip: {
trigger: 'axis',
axisPointer: { type: 'line' },
textStyle: { fontSize: tooltipFontSize },
formatter: (params) => {
const p = params && params[0]
if (!p) return ''
return `${p.axisValue}<br/>请求次数:${p.data.toLocaleString()}`
}
},
grid: { left: 90, right: 30, top: 30, bottom: 40, containLabel: true },
grid: { left: 60, right: 30, top: 90, bottom: 0, containLabel: true },
xAxis: {
type: 'category',
data: x,
boundaryGap: false,
axisLabel: { color: '#FFFFFF', fontSize: 22 },
axisLabel: { color: '#FFFFFF', fontSize: xFontSize },
axisLine: { lineStyle: { color: '#105E86' } }
},
yAxis: {
type: 'value',
name: '请求次数',
nameLocation: 'middle',
nameRotate: 90,
nameGap: 50,
nameTextStyle: { color: '#77CCFF', fontSize: 20 },
nameGap: 20,
nameTextStyle: { color: '#77CCFF', fontSize: yNameFontSize },
axisLabel: {
color: '#77CCFF', fontSize: 20,
formatter: (v) => v >= 10000 ? (v / 10000).toFixed(0) + '万' : v
color: '#77CCFF',
fontSize: yFontSize,
formatter: (v) => (v >= 10000 ? (v / 10000).toFixed(0) + '万' : v)
},
splitLine: { lineStyle: { color: '#105E86' } }
},
......@@ -213,7 +231,8 @@ function detectIframe() {
}
function onFsChange() {
const el = document.fullscreenElement ||
const el =
document.fullscreenElement ||
document.webkitFullscreenElement ||
document.mozFullScreenElement ||
document.msFullscreenElement
......@@ -246,9 +265,13 @@ onMounted(() => {
})
// 监听数据变化
watch(() => dashboardData.value.apiCalls, () => {
render()
}, { deep: true })
watch(
() => dashboardData.value.apiCalls,
() => {
render()
},
{ deep: true }
)
// 监听维度切换
watch(rangeType, () => {
......@@ -279,7 +302,10 @@ onBeforeUnmount(() => {
margin-bottom: 8px;
padding: 0 6px;
}
.trend-toolbar .muted { color: rgba(218,247,255,0.7); font-size: 16px; }
.trend-toolbar .muted {
color: rgba(218, 247, 255, 0.7);
font-size: 16px;
}
.trend-toolbar .switcher {
display: flex;
......@@ -290,16 +316,16 @@ onBeforeUnmount(() => {
font-size: 18px;
line-height: 1;
padding: 6px 14px;
color: #A3E9FF;
color: #a3e9ff;
background: rgba(16, 94, 134, 0.35);
border: 1px solid #1DBAFF;
border: 1px solid #1dbaff;
border-radius: 2px;
cursor: pointer;
}
.trend-toolbar .switcher button.active {
color: #FFFFFF;
background: linear-gradient(90deg, rgba(19,101,106,0.9), rgba(38,169,163,0.9));
color: #ffffff;
background: linear-gradient(90deg, rgba(19, 101, 106, 0.9), rgba(38, 169, 163, 0.9));
}
.echart-wrap {
......
......@@ -2,9 +2,15 @@
<div class="order-manage-wrap">
<div class="toolbar">
<div class="switcher">
<button :class="{ active: dateType === 'd' }" @click="changeType('d')" type="button">日</button>
<button :class="{ active: dateType === 'm' }" @click="changeType('m')" type="button">月</button>
<button :class="{ active: dateType === 'y' }" @click="changeType('y')" type="button">年</button>
<button :class="{ active: dateType === 'd' }" @click="changeType('d')" type="button"
>日</button
>
<button :class="{ active: dateType === 'm' }" @click="changeType('m')" type="button"
>月</button
>
<button :class="{ active: dateType === 'y' }" @click="changeType('y')" type="button"
>年</button
>
</div>
<!-- 全屏按钮 -->
<button
......@@ -48,45 +54,50 @@ const { t } = useI18n()
const dateType = ref<'d' | 'm' | 'y'>('d')
let chart: echarts.ECharts | null = null
function getOption(xData: string[], seriesData: {
computeCount: number[]
apiCount: number[]
computeAmount: number[]
apiAmount: number[]
}): EChartsOption {
function getOption(
xData: string[],
seriesData: {
computeCount: number[]
apiCount: number[]
computeAmount: number[]
apiAmount: number[]
}
): EChartsOption {
return {
tooltip: {
trigger: 'axis'
trigger: 'axis',
textStyle: { fontSize: 32 }
},
legend: {
data: ['算力订单', 'API订单', '算力订单金额', 'API订单金额'],
right: '2%',
top: 0,
textStyle: { color: '#A3E9FF', fontSize: 18 }
textStyle: { color: '#A3E9FF', fontSize: 32 }
},
grid: { left: 80, right: 80, top: 40, bottom: 30, containLabel: true },
grid: { left: 80, right: 80, top: 100, bottom: 30, containLabel: true },
xAxis: {
type: 'category',
boundaryGap: false,
data: xData,
axisLabel: { color: '#FFFFFF', fontSize: 20 },
axisLabel: { color: '#FFFFFF', fontSize: 32 },
axisLine: { lineStyle: { color: '#105E86' } }
},
yAxis: [
{
type: 'value',
name: '数量',
nameTextStyle: { color: '#77CCFF', fontSize: 18 },
axisLabel: { color: '#77CCFF', fontSize: 18 },
nameTextStyle: { color: '#77CCFF', fontSize: 32 },
axisLabel: { color: '#77CCFF', fontSize: 32 },
splitLine: { lineStyle: { color: '#105E86' } }
},
{
type: 'value',
name: '金额(元)',
position: 'right',
nameTextStyle: { color: '#77CCFF', fontSize: 18 },
nameTextStyle: { color: '#77CCFF', fontSize: 32 },
axisLabel: {
color: '#77CCFF', fontSize: 18,
color: '#77CCFF',
fontSize: 32,
formatter: (v: number) => Number(v).toLocaleString()
},
splitLine: { show: false }
......@@ -146,7 +157,9 @@ async function render() {
const x = res.map((item: any) => t(item.countDate))
const computeCount = res.map((item: any) => item.computeOrdersCount || 0)
const apiCount = res.map((item: any) => item.apiOrdersCount || 0)
const computeAmount = res.map((item: any) => Number(((item.computeOrdersAmount || 0) / 100).toFixed(2)))
const computeAmount = res.map((item: any) =>
Number(((item.computeOrdersAmount || 0) / 100).toFixed(2))
)
const apiAmount = res.map((item: any) => Number(((item.apiOrdersAmount || 0) / 100).toFixed(2)))
if (!chart) {
......@@ -166,9 +179,13 @@ function changeType(t: 'd' | 'm' | 'y') {
const onResize = () => chart && chart.resize()
// 监听数据变化
watch(() => dashboardData.value.orders, () => {
render()
}, { deep: true })
watch(
() => dashboardData.value.orders,
() => {
render()
},
{ deep: true }
)
onMounted(() => {
render()
......@@ -184,7 +201,9 @@ onBeforeUnmount(() => {
})
</script>
<style scoped lang="scss">
.order-manage-wrap { position: relative; }
.order-manage-wrap {
position: relative;
}
.toolbar {
position: absolute;
......@@ -205,19 +224,23 @@ onBeforeUnmount(() => {
font-size: 18px;
line-height: 1;
padding: 6px 14px;
color: #A3E9FF;
color: #a3e9ff;
background: rgba(16, 94, 134, 0.35);
border: 1px solid #1DBAFF;
border: 1px solid #1dbaff;
border-radius: 2px;
cursor: pointer;
}
.switcher button.active {
color: #FFFFFF;
background: linear-gradient(90deg, rgba(19,101,106,0.9), rgba(38,169,163,0.9));
color: #ffffff;
background: linear-gradient(90deg, rgba(19, 101, 106, 0.9), rgba(38, 169, 163, 0.9));
}
.echart-wrap { height: 640px; padding-top: 100px; box-sizing: border-box; }
.echart-wrap {
height: 640px;
padding-top: 100px;
box-sizing: border-box;
}
/* 全屏按钮样式,与项目现有风格一致 */
.fs-float-btn {
......
......@@ -2,9 +2,15 @@
<div class="order-manage-wrap">
<div class="toolbar">
<div class="switcher">
<button :class="{ active: dateType === 'd' }" @click="changeType('d')" type="button">日</button>
<button :class="{ active: dateType === 'm' }" @click="changeType('m')" type="button">月</button>
<button :class="{ active: dateType === 'y' }" @click="changeType('y')" type="button">年</button>
<button :class="{ active: dateType === 'd' }" @click="changeType('d')" type="button"
>日</button
>
<button :class="{ active: dateType === 'm' }" @click="changeType('m')" type="button"
>月</button
>
<button :class="{ active: dateType === 'y' }" @click="changeType('y')" type="button"
>年</button
>
</div>
</div>
<div id="userManageChart" class="echart-wrap"></div>
......@@ -38,33 +44,41 @@ const { t } = useI18n()
const dateType = ref<'d' | 'm' | 'y'>('d')
let chart: echarts.ECharts | null = null
function getOption(xData: string[], growth: number[], active: number[]): EChartsOption {
function getOption(
xData: string[],
total: number[],
growth: number[],
active: number[]
): EChartsOption {
return {
tooltip: { trigger: 'axis' },
tooltip: {
trigger: 'axis',
textStyle: { fontSize: 32 }
},
legend: {
data: ['增长用户数', '活跃用户数'],
data: ['累计用户数', '增长用户数', '活跃用户数'],
right: '2%',
top: 0,
textStyle: { color: '#A3E9FF', fontSize: 18 }
textStyle: { color: '#A3E9FF', fontSize: 32 }
},
grid: { left: 80, right: 40, top: 40, bottom: 30, containLabel: true },
grid: { left: 80, right: 40, top: 80, bottom: 0, containLabel: true },
xAxis: {
type: 'category',
boundaryGap: false,
data: xData,
axisLabel: { color: '#FFFFFF', fontSize: 20 },
axisLabel: { color: '#FFFFFF', fontSize: 32 },
axisLine: { lineStyle: { color: '#105E86' } }
},
yAxis: {
type: 'value',
name: '用户数',
nameTextStyle: { color: '#77CCFF', fontSize: 18 },
axisLabel: { color: '#77CCFF', fontSize: 18 },
nameTextStyle: { color: '#77CCFF', fontSize: 32 },
axisLabel: { color: '#77CCFF', fontSize: 32 },
splitLine: { lineStyle: { color: '#105E86' } }
},
series: [
{
name: '增长用户数',
name: '累计用户数',
type: 'line',
smooth: true,
symbol: 'circle',
......@@ -72,10 +86,10 @@ function getOption(xData: string[], growth: number[], active: number[]): ECharts
itemStyle: { color: '#67C23A' },
lineStyle: { width: 3, color: '#67C23A' },
areaStyle: { opacity: 0.08 },
data: growth
data: total
},
{
name: '活跃用户数',
name: '增长用户数',
type: 'line',
smooth: true,
symbol: 'diamond',
......@@ -83,6 +97,17 @@ function getOption(xData: string[], growth: number[], active: number[]): ECharts
itemStyle: { color: '#409EFF' },
lineStyle: { width: 3, color: '#409EFF' },
areaStyle: { opacity: 0.06 },
data: growth
},
{
name: '活跃用户数',
type: 'line',
smooth: true,
symbol: 'triangle',
symbolSize: 6,
itemStyle: { color: '#E6A23C' },
lineStyle: { width: 3, color: '#E6A23C' },
areaStyle: { opacity: 0.05 },
data: active
}
]
......@@ -95,17 +120,19 @@ async function render() {
const arr = users[dateType.value] || []
const x = arr.map((item: any) => t(item.countDate))
const growth = arr.map((item: any) => item.growthUsersCount ?? item.usersCount ?? 0)
const active = arr.map((item: any, idx: number) =>
item.activeUsersCount ?? item.visitUserCount ?? Math.round((item.usersCount ?? 0) * 1.4 + (idx % 3 === 0 ? 3 : 8))
)
// 累计用户数 = 后端 usersCount
const total = arr.map((item: any) => item.usersCount ?? 0)
// 增长用户数 = 后端 growthUsersCount(每日新增,独立于累计)
const growth = arr.map((item: any) => item.growthUsersCount ?? 0)
// 活跃用户数 = 后端 activeUsersCount(按天/月对登录成功的 userId 去重计数)
const active = arr.map((item: any) => item.activeUsersCount ?? 0)
if (!chart) {
const el = document.getElementById('userManageChart') as HTMLElement | null
if (!el) return
chart = echarts.init(el)
}
chart.setOption(getOption(x, growth, active), true)
chart.setOption(getOption(x, total, growth, active), true)
}
function changeType(t: 'd' | 'm' | 'y') {
......@@ -117,9 +144,13 @@ function changeType(t: 'd' | 'm' | 'y') {
const onResize = () => chart && chart.resize()
// 监听数据变化
watch(() => dashboardData.value.users, () => {
render()
}, { deep: true })
watch(
() => dashboardData.value.users,
() => {
render()
},
{ deep: true }
)
// 监听维度切换
watch(dateType, () => {
......@@ -140,7 +171,9 @@ onBeforeUnmount(() => {
})
</script>
<style scoped lang="scss">
.order-manage-wrap { position: relative; }
.order-manage-wrap {
position: relative;
}
.toolbar {
position: absolute;
......@@ -161,18 +194,21 @@ onBeforeUnmount(() => {
font-size: 18px;
line-height: 1;
padding: 6px 14px;
color: #A3E9FF;
color: #a3e9ff;
background: rgba(16, 94, 134, 0.35);
border: 1px solid #1DBAFF;
border: 1px solid #1dbaff;
border-radius: 2px;
cursor: pointer;
}
.switcher button.active {
color: #FFFFFF;
background: linear-gradient(90deg, rgba(19,101,106,0.9), rgba(38,169,163,0.9));
color: #ffffff;
background: linear-gradient(90deg, rgba(19, 101, 106, 0.9), rgba(38, 169, 163, 0.9));
}
.echart-wrap { height: 560px; padding-top: 100px; box-sizing: border-box; }
.echart-wrap {
height: 560px;
padding-top: 100px;
box-sizing: border-box;
}
</style>
......@@ -42,6 +42,16 @@
<el-form-item label="详情备注" prop="detailRemark">
<el-input v-model="formData.detailRemark" placeholder="请输入详情备注"/>
</el-form-item>
<el-form-item label="算力(TOPS)" prop="compute">
<el-input-number
v-model="formData.compute"
controls-position="right"
:min="0"
:precision="2"
:step="0.01"
placeholder="默认 0,运营可手动配置"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
......@@ -71,7 +81,8 @@ const formData = ref({
configOption: undefined,
sort: undefined,
status: 0,
detailRemark: undefined
detailRemark: undefined,
compute: 0
})
const formRules = reactive({
configCategory: [{required: true, message: '配置类别不能为空', trigger: 'blur'}],
......@@ -130,7 +141,8 @@ const resetForm = () => {
configOption: undefined,
sort: undefined,
status: 0,
detailRemark: undefined
detailRemark: undefined,
compute: 0
}
formRef.value?.resetFields()
}
......
......@@ -134,6 +134,7 @@
</template>
</el-table-column>
<el-table-column label="详情备注" align="center" prop="detailRemark" min-width="200" />
<el-table-column label="算力(TOPS)" align="center" prop="compute" width="120px" />
<el-table-column
label="创建时间"
align="center"
......
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="100px"
>
<el-tabs v-model="activeTab" @tab-change="handleTabChange">
<!-- 全部订单 Tab:含搜索表单 -->
<el-tab-pane label="全部订单" name="all">
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="100px"
>
<!-- <el-form-item label="下单用户ID" prop="userId">-->
<!-- <el-input-->
<!-- v-model="queryParams.userId"-->
......@@ -44,21 +47,21 @@
<!-- class="!w-240px"-->
<!-- />-->
<!-- </el-form-item>-->
<!-- <el-form-item label="订单状态" prop="status">-->
<!-- <el-select-->
<!-- v-model="queryParams.status"-->
<!-- placeholder="请选择订单状态"-->
<!-- clearable-->
<!-- class="!w-240px"-->
<!-- >-->
<!-- <el-option-->
<!-- v-for="dict in getIntDictOptions(DICT_TYPE.COMPUTE_RESOURCE_ORDER_STATUS)"-->
<!-- :key="dict.value"-->
<!-- :label="dict.label"-->
<!-- :value="dict.value"-->
<!-- />-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<el-form-item label="订单状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="请选择订单状态"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.COMPUTE_RESOURCE_ORDER_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<!-- <el-form-item label="市场价格" prop="marketPrice">-->
<!-- <el-input-->
<!-- v-model="queryParams.marketPrice"-->
......@@ -253,7 +256,27 @@
</el-button> -->
</el-form-item>
</el-form>
</ContentWrap>
</el-tab-pane>
<!-- 待发货 Tab -->
<el-tab-pane name="pendingDelivery">
<template #label>
<el-badge :value="pendingDeliveryCount" :hidden="pendingDeliveryCount === 0" :max="99">
<span>待发货</span>
</el-badge>
</template>
</el-tab-pane>
<!-- 待退款 Tab -->
<el-tab-pane name="pendingRefund">
<template #label>
<el-badge :value="pendingRefundCount" :hidden="pendingRefundCount === 0" :max="99">
<span>待退款</span>
</el-badge>
</template>
</el-tab-pane>
</el-tabs>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
......@@ -490,6 +513,9 @@ defineOptions({ name: 'ResourceOrder' })
const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化
const activeTab = ref<'all' | 'pendingDelivery' | 'pendingRefund'>('all') // 当前 Tab
const pendingDeliveryCount = ref(0) // 待发货数量
const pendingRefundCount = ref(0) // 待退款数量
const loading = ref(true) // 列表的加载中
const list = ref<ResourceOrder[]>([]) // 列表的数据
const total = ref(0) // 列表的总页数
......@@ -527,16 +553,49 @@ const detailRef = ref() // 详情弹窗ref
const pdfDialogVisible = ref(false) // 发票预览弹窗
const invoiceUrl = ref('') // 发票地址
/** 根据当前 Tab 解析出实际请求时的 status(待发货/待退款强制覆盖,搜索表单的 status 仅在「全部订单」Tab 生效) */
const resolveStatus = (): number | undefined => {
if (activeTab.value === 'pendingDelivery') return 5 // PENDING_DELIVERY
if (activeTab.value === 'pendingRefund') return 7 // PENDING_REFUND
return queryParams.status
}
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await ResourceOrderApi.getResourceOrderPage(queryParams)
const data = await ResourceOrderApi.getResourceOrderPage({
...queryParams,
status: resolveStatus()
})
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
// 异步刷新待发货 / 待退款角标
getPendingCount()
}
/** Tab 切换:仅重置分页与列表,status 由 resolveStatus 统一处理 */
const handleTabChange = () => {
queryParams.pageNo = 1
getList()
}
/** 获取待发货 / 待退款角标数量(不受当前 Tab / 搜索表单影响,始终统计全局) */
const getPendingCount = async () => {
try {
const [delivery, refund] = await Promise.all([
ResourceOrderApi.getResourceOrderPage({ pageNo: 1, pageSize: 1, status: 5 }),
ResourceOrderApi.getResourceOrderPage({ pageNo: 1, pageSize: 1, status: 7 })
])
pendingDeliveryCount.value = delivery?.total ?? 0
pendingRefundCount.value = refund?.total ?? 0
} catch {
pendingDeliveryCount.value = 0
pendingRefundCount.value = 0
}
}
/** 搜索按钮操作 */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment