This commit is contained in:
浅念
2026-02-12 09:55:05 +08:00
parent 5ba8456a88
commit f9f23ace09
2 changed files with 0 additions and 754 deletions
-125
View File
@@ -1,125 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>Progress</title>
<style>
body {
background:#0b0f14;
display:flex;
justify-content:center;
align-items:center;
height:100vh;
}
.progress-wrap {
width:680px;
height:30px;
padding:3px;
border-radius:20px;
background:linear-gradient(180deg,#ffb15a,#ff8c2a);
box-shadow:0 0 8px rgba(255,153,51,.6);
}
.progress-bg {
position:relative;
width:100%;
height:100%;
background:#1a1f26;
border-radius:16px;
overflow:hidden;
}
.progress-bar {
position:relative;
height:100%;
width:0%;
border-radius:16px;
background:
repeating-linear-gradient(
45deg,
rgba(255,255,255,.25) 0,
rgba(255,255,255,.25) 8px,
rgba(255,255,255,.12) 8px,
rgba(255,255,255,.12) 16px
),
linear-gradient(180deg,#ffd27d,#ff8c2a);
animation:move 1.2s linear infinite;
box-shadow:inset 0 0 6px rgba(255,255,255,.6);
}
@keyframes move {
from { background-position:0 0; }
to { background-position:40px 0; }
}
/* 箭头容器(圆形) */
.progress-info {
position:absolute;
right: 0px;
top:50%;
transform:translateY(-50%);
display:flex;
align-items:center;
gap:6px;
color:#fff;
font-size:13px;
font-weight:600;
white-space:nowrap;
}
.play-btn {
width: 24px;
height: 24px;
border-radius:50%;
background: #dc7439;
border: 2px solid #ffb521;
/* box-shadow:
0 0 6px rgba(255,170,60,.8),
inset 0 0 3px rgba(255,255,255,.9); */
display:flex;
align-items:center;
justify-content:center;
}
.play-btn::before {
content:"";
margin-left:2px;
width:0;
height:0;
border-top:5px solid transparent;
border-bottom:5px solid transparent;
border-left:7px solid #fff;
}
</style>
</head>
<body>
<div class="progress-wrap">
<div class="progress-bg">
<div class="progress-bar" id="bar">
<div class="progress-info">
<div class="play-btn"></div>
</div>
</div>
</div>
</div>
<script>
let value = 0;
const target = 77.05;
const bar = document.getElementById('bar');
const percent = document.getElementById('percent');
const timer = setInterval(() => {
value += 0.4;
if (value >= target) {
value = target;
clearInterval(timer);
}
bar.style.width = value + '%';
}, 20);
</script>
</body>
</html>
-629
View File
@@ -1,629 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>年度销售数据看板</title>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Microsoft YaHei', Arial, sans-serif;
background: linear-gradient(135deg, #0a0e27 0%, #1a1f3a 100%);
min-height: 100vh;
color: #fff;
overflow-x: hidden;
}
.container {
max-width: 1920px;
margin: 0 auto;
padding: 30px;
}
/* 顶部年度标题 */
.year-title {
text-align: center;
font-size: 36px;
color: #fff;
margin-bottom: 30px;
font-weight: bold;
letter-spacing: 4px;
}
/* 顶部销售额区域 */
.sales-header {
margin-bottom: 40px;
padding: 40px;
background: rgba(255, 255, 255, 0.03);
border-radius: 20px;
border: 1px solid rgba(240, 138, 49, 0.2);
}
.sales-section {
display: flex;
flex-direction: column;
align-items: stretch;
margin-bottom: 40px;
width: 100%;
}
.sales-progress-wrapper {
display: flex;
align-items: center;
justify-content: flex-start;
gap: 15px;
margin-bottom: 15px;
width: 100%;
}
.sales-section .sales-info {
text-align: center;
display: flex;
justify-content: center;
}
.progress-label {
font-size: 18px;
color: #f08a31;
font-weight: bold;
min-width: 70px;
}
.goal-section {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
}
.goal-section .sales-info {
margin-bottom: 15px;
}
.full-width {
width: 100% !important;
}
.sales-info {
display: flex;
align-items: baseline;
justify-content: center;
gap: 15px;
}
.sales-label {
font-size: 28px;
color: #f08a31;
font-weight: 500;
}
.sales-value {
font-size: 56px;
font-weight: bold;
color: #f08a31;
text-shadow: 0 0 20px rgba(240, 138, 49, 0.5);
letter-spacing: 2px;
}
.sales-unit {
font-size: 24px;
color: #f08a31;
}
.target-info {
display: flex;
align-items: center;
gap: 20px;
}
.target-row {
display: flex;
align-items: center;
gap: 20px;
}
.target-label {
font-size: 18px;
white-space: nowrap;
}
.target-label.completed {
color: #f08a31;
}
.target-label.goal {
color: #ff4d4f;
}
.progress-bar-container {
position: relative;
width: 800px;
height: 20px;
background: rgba(255, 255, 255, 0.1);
border-radius: 15px;
overflow: hidden;
}
.progress-bar {
height: 100%;
background: linear-gradient(90deg, #f08a31, #ffb347);
border-radius: 15px;
transition: width 1s ease;
position: relative;
}
.target-line {
position: absolute;
top: 0;
bottom: 0;
width: 3px;
background: #ff4d4f;
box-shadow: 0 0 10px rgba(255, 77, 79, 0.8);
}
.target-line::before,
.target-line::after {
content: '';
position: absolute;
left: -6px;
width: 0;
height: 0;
border-left: 8px solid #ff4d4f;
border-top: 6px solid transparent;
border-bottom: 6px solid transparent;
}
.target-line::before {
top: -6px;
}
.target-line::after {
bottom: -6px;
transform: rotate(180deg);
}
.progress-value {
font-size: 18px;
color: #f08a31;
min-width: 60px;
}
.goal-text {
font-size: 18px;
color: #ff4d4f;
}
.sales-label.goal {
color: #ff4d4f;
font-size: 20px;
}
.sales-value.goal {
color: #ff4d4f;
text-shadow: 0 0 20px rgba(255, 77, 79, 0.5);
font-size: 20px;
}
.sales-unit.goal {
color: #ff4d4f;
}
.goal-bar {
background: linear-gradient(90deg, #ff4d4f, #ff7875);
}
/* 内容区域 */
.content-section {
margin-bottom: 30px;
}
.section-title {
font-size: 22px;
color: #f08a31;
margin-bottom: 20px;
padding-left: 20px;
border-left: 4px solid #f08a31;
}
.rank-container {
display: flex;
gap: 20px;
background: rgba(255, 255, 255, 0.03);
border-radius: 15px;
padding: 25px;
border: 1px solid rgba(240, 138, 49, 0.15);
align-items: stretch;
}
/* 排名列表 */
.rank-list {
width: 33.33%;
min-width: 300px;
display: flex;
flex-direction: column;
height: 100%;
}
.rank-item {
display: flex;
align-items: center;
padding: 15px 20px;
margin-bottom: 12px;
background: rgba(255, 255, 255, 0.05);
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
}
.rank-item:hover {
background: rgba(240, 138, 49, 0.15);
border-color: rgba(240, 138, 49, 0.4);
transform: translateX(5px);
}
.rank-item.top-1 {
background: linear-gradient(135deg, rgba(255, 215, 0, 0.2), rgba(255, 215, 0, 0.05));
border-color: rgba(255, 215, 0, 0.5);
}
.rank-item.top-2 {
background: linear-gradient(135deg, rgba(192, 192, 192, 0.2), rgba(192, 192, 192, 0.05));
border-color: rgba(192, 192, 192, 0.5);
}
.rank-item.top-3 {
background: linear-gradient(135deg, rgba(205, 127, 50, 0.2), rgba(205, 127, 50, 0.05));
border-color: rgba(205, 127, 50, 0.5);
}
.rank-number {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
font-weight: bold;
border-radius: 50%;
margin-right: 15px;
flex-shrink: 0;
}
.rank-item.top-1 .rank-number {
background: linear-gradient(135deg, #ffd700, #ffed4e);
color: #000;
}
.rank-item.top-2 .rank-number {
background: linear-gradient(135deg, #c0c0c0, #e8e8e8);
color: #000;
}
.rank-item.top-3 .rank-number {
background: linear-gradient(135deg, #cd7f32, #daa520);
color: #fff;
}
.rank-item:not(.top-1):not(.top-2):not(.top-3) .rank-number {
background: rgba(255, 255, 255, 0.1);
color: #fff;
}
.rank-info {
flex: 1;
min-width: 0;
}
.rank-name {
font-size: 18px;
color: #fff;
margin-bottom: 5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.rank-sales {
font-size: 14px;
color: #f08a31;
}
.rank-rate {
font-size: 14px;
color: #4ade80;
margin-left: 10px;
}
/* 图表区域 */
.chart-container {
flex: 1;
min-height: 300px;
height: 100%;
}
/* 响应式 */
@media (max-width: 1400px) {
.sales-value {
font-size: 42px;
}
.progress-bar-container {
width: 500px;
}
}
@media (max-width: 1024px) {
.rank-container {
flex-direction: column;
}
.rank-list,
.chart-container {
width: 100%;
}
.sales-section,
.goal-section {
align-items: center;
}
.sales-info {
flex-direction: column;
align-items: center;
}
.progress-bar-container {
width: 100%;
}
.sales-progress-wrapper {
justify-content: center;
}
}
</style>
</head>
<body>
<div class="container">
<!-- 年度标题 -->
<div class="year-title">数据看板</div>
<!-- 顶部销售额区域 -->
<div class="sales-header">
<!-- 总销售额区域:进度条在上,金额在下,居左 -->
<div class="sales-section">
<div class="sales-progress-wrapper">
<div class="progress-bar-container">
<div class="progress-bar"></div>
</div>
<div class="progress-label">77.05%</div>
</div>
<div class="sales-info">
<span class="sales-label">总销售额</span>
<span class="sales-value">231,154,000,000</span>
<span class="sales-unit">元</span>
</div>
</div>
<!-- 年度目标区域:金额居中,进度条在下 -->
<div class="goal-section">
<div class="sales-info">
<span class="sales-label goal">年度目标</span>
<span class="sales-value goal">300,000,000,000</span>
<span class="sales-unit goal">元</span>
</div>
<div class="progress-bar-container full-width">
<div class="progress-bar goal-bar" style="width: 100%"></div>
</div>
</div>
</div>
<!-- 小组排名区域 -->
<div class="content-section">
<div class="section-title">小组排名</div>
<div class="rank-container">
<div class="rank-list" id="groupRankList"></div>
<div class="chart-container" id="groupChart"></div>
</div>
</div>
<!-- 个人排名区域 -->
<div class="content-section">
<div class="section-title">个人排名</div>
<div class="rank-container">
<div class="rank-list" id="personRankList"></div>
<div class="chart-container" id="personChart"></div>
</div>
</div>
</div>
<script>
// 模拟数据 - 小组排名
const groupData = [
{ name: '华东一组', target: 50000000000, actual: 62000000000 },
{ name: '华南二组', target: 45000000000, actual: 51000000000 },
{ name: '华北三组', target: 40000000000, actual: 43500000000 },
{ name: '西南四组', target: 35000000000, actual: 28000000000 },
{ name: '东北五组', target: 30000000000, actual: 26500000000 }
];
// 模拟数据 - 个人排名
const personData = [
{ name: '张伟', target: 5000000000, actual: 7200000000 },
{ name: '李娜', target: 4500000000, actual: 5800000000 },
{ name: '王强', target: 4000000000, actual: 4900000000 },
{ name: '刘洋', target: 3800000000, actual: 4100000000 },
{ name: '陈静', target: 3500000000, actual: 3600000000 }
];
// 格式化数字
function formatNumber(num) {
return (num / 100000000).toFixed(1) + '亿';
}
// 渲染排名列表
function renderRankList(containerId, data, type) {
const container = document.getElementById(containerId);
container.innerHTML = data.map((item, index) => {
const rate = ((item.actual / item.target) * 100).toFixed(1);
const rankClass = index < 3 ? `top-${index + 1}` : '';
return `
<div class="rank-item ${rankClass}">
<div class="rank-number">${index + 1}</div>
<div class="rank-info">
<div class="rank-name">${item.name}</div>
<div class="rank-sales">销售额: ${formatNumber(item.actual)} | 目标: ${formatNumber(item.target)}
<span class="rank-rate">完成率: ${rate}%</span>
</div>
</div>
</div>
`;
}).join('');
}
// 渲染图表
function renderChart(containerId, data, type) {
const chartDom = document.getElementById(containerId);
const chart = echarts.init(chartDom);
const names = data.map(item => item.name);
const targets = data.map(item => item.target / 100000000);
const actuals = data.map(item => item.actual / 100000000);
const option = {
backgroundColor: 'transparent',
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: function(params) {
let result = params[0].name + '<br/>';
params.forEach(item => {
result += `${item.marker}${item.seriesName}: ${item.value}亿<br/>`;
});
return result;
}
},
legend: {
data: ['目标销售额', '实际销售额'],
textStyle: {
color: '#fff'
},
top: 10
},
grid: {
left: '10%',
right: '5%',
bottom: '3%',
top: '15%',
containLabel: true
},
xAxis: {
type: 'value',
name: '销售额(亿)',
nameTextStyle: {
color: '#fff'
},
axisLabel: {
color: '#fff',
fontSize: 12
},
axisLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.2)'
}
},
splitLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.1)'
}
}
},
yAxis: {
type: 'category',
data: names,
axisLabel: {
color: '#fff',
fontSize: 14
},
axisLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.2)'
}
}
},
series: [
{
name: '目标销售额',
type: 'bar',
data: targets,
itemStyle: {
color: 'rgba(255, 77, 79, 0.6)',
borderRadius: [0, 0, 0, 0]
},
barMaxWidth: 30
},
{
name: '实际销售额',
type: 'bar',
data: actuals,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
{ offset: 0, color: '#f08a31' },
{ offset: 1, color: '#ffb347' }
]),
borderRadius: [0, 0, 0, 0]
},
barMaxWidth: 30
}
]
};
chart.setOption(option);
chart.resize();
// 响应式
window.addEventListener('resize', () => {
chart.resize();
});
}
// 初始化
document.addEventListener('DOMContentLoaded', () => {
renderRankList('groupRankList', groupData, 'group');
renderRankList('personRankList', personData, 'person');
// 确保DOM完全渲染后再初始化图表
setTimeout(() => {
// 确保图表容器高度与排名列表一致
function syncChartHeight() {
const groupRankList = document.getElementById('groupRankList');
const groupChart = document.getElementById('groupChart');
const personRankList = document.getElementById('personRankList');
const personChart = document.getElementById('personChart');
if (groupRankList && groupChart) {
groupChart.style.height = groupRankList.offsetHeight + 'px';
}
if (personRankList && personChart) {
personChart.style.height = personRankList.offsetHeight + 'px';
}
}
syncChartHeight();
renderChart('groupChart', groupData, 'group');
renderChart('personChart', personData, 'person');
// 响应式调整
window.addEventListener('resize', () => {
syncChartHeight();
// 重新调整图表大小
const groupChart = echarts.getInstanceByDom(document.getElementById('groupChart'));
const personChart = echarts.getInstanceByDom(document.getElementById('personChart'));
if (groupChart) groupChart.resize();
if (personChart) personChart.resize();
});
}, 200);
});
</script>
</body>
</html>