Browse Source

修改验证码

main
ZhaoYang 4 days ago
parent
commit
6cf16e6806
  1. 255
      chenhai-ui/src/components/visual/scgk.vue
  2. 282
      chenhai-ui/src/views/login.vue

255
chenhai-ui/src/components/visual/scgk.vue

@ -126,23 +126,12 @@
</div> </div>
</div> </div>
<!-- 修复后的产奶目标完成度环形进度条 + 动态百分比 -->
<div class="card quota-card"> <div class="card quota-card">
<div class="card-header"> <div class="card-header">
<span class="title">🎯 产奶目标完成度</span>
<span class="title">🐪 泌乳母驼存栏结构</span>
</div> </div>
<div class="ring-progress-wrapper">
<svg class="ring-progress" viewBox="0 0 120 120">
<circle class="ring-bg" cx="60" cy="60" r="54" fill="none" stroke="rgba(52, 152, 219, 0.2)"
stroke-width="10" />
<circle class="ring-fill" cx="60" cy="60" r="54" fill="none" stroke="#5dade2" stroke-width="10"
stroke-linecap="round" :stroke-dasharray="ringCircumference" :stroke-dashoffset="ringOffset" />
<text x="60" y="70" text-anchor="middle" class="ring-percent" fill="#fff" font-size="22"
font-weight="bold">{{ completionPercent }}%</text>
<text x="60" y="90" text-anchor="middle" fill="rgba(255,255,255,0.6)" font-size="10">完成率</text>
</svg>
</div>
<div class="quota-footer">年度目标 3500 | 已完成 {{ productionStats.totalMilk }} </div>
<div ref="lactatingBarChart" class="bar-chart-container"></div>
<div class="quota-footer">泌乳母驼 {{ lactatingCamels }} | 总存栏 {{ productionStats.camelCount }} </div>
</div> </div>
</div> </div>
</div> </div>
@ -154,9 +143,7 @@ import * as echarts from 'echarts';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn'; import 'dayjs/locale/zh-cn';
// animate-number
// vue-animate-number
// components animate-number
//
const AnimateNumber = { const AnimateNumber = {
props: { props: {
from: Number, from: Number,
@ -195,8 +182,8 @@ export default {
}, },
data() { data() {
return { return {
//
center: { lng: 105.669, lat: 38.833 },
//
center: { lng: 104.516843, lat: 40.272114 },
productionStats: { productionStats: {
totalMilk: 2845, // totalMilk: 2845, //
camelCount: 12860, camelCount: 12860,
@ -219,36 +206,39 @@ export default {
], ],
camelChartIns: null, camelChartIns: null,
trendChartIns: null, trendChartIns: null,
//
ringCircumference: 2 * Math.PI * 54, // = 2*pi*r
//
lactatingBarChartIns: null,
baiduMap: null baiduMap: null
}; };
}, },
computed: { computed: {
// 3500
completionPercent() {
let percent = (this.productionStats.totalMilk / 3500) * 100;
percent = Math.min(100, Math.max(0, percent));
return Math.floor(percent);
lactatingCamels() {
return Math.round(this.productionStats.camelCount * 0.48);
},
otherCamels() {
return this.productionStats.camelCount - this.lactatingCamels;
}, },
//
ringOffset() {
const percent = this.completionPercent / 100;
return this.ringCircumference * (1 - percent);
barChartData() {
const months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'];
const lactatingData = [];
const otherData = [];
const baseTotal = this.productionStats.camelCount;
const ratios = [0.47, 0.46, 0.45, 0.46, 0.48, 0.50, 0.52, 0.51, 0.50, 0.49, 0.48, 0.47];
for (let i = 0; i < months.length; i++) {
const lactating = Math.round(baseTotal * ratios[i]);
lactatingData.push(lactating);
otherData.push(baseTotal - lactating);
}
return {
months,
lactatingData,
otherData
};
} }
}, },
mounted() { mounted() {
this.getCurrentDateTime(); this.getCurrentDateTime();
this.initAllCharts(); this.initAllCharts();
window.addEventListener('resize', this.handleResize); window.addEventListener('resize', this.handleResize);
// <baidu-map> GLVue
// nextTick baidu-map
// template <baidu-map> vue-baidu-map
// template baidu-map div js
// mounted template div
// 使 <baidu-map>
//
this.$nextTick(() => { this.$nextTick(() => {
this.initBaiduMapNative(); this.initBaiduMapNative();
}); });
@ -257,19 +247,19 @@ export default {
window.removeEventListener('resize', this.handleResize); window.removeEventListener('resize', this.handleResize);
if (this.camelChartIns) this.camelChartIns.dispose(); if (this.camelChartIns) this.camelChartIns.dispose();
if (this.trendChartIns) this.trendChartIns.dispose(); if (this.trendChartIns) this.trendChartIns.dispose();
if (this.lactatingBarChartIns) this.lactatingBarChartIns.dispose();
if (this.baiduMap) { if (this.baiduMap) {
//
this.baiduMap.destroy(); this.baiduMap.destroy();
} }
}, },
methods: { methods: {
getCurrentDateTime() { getCurrentDateTime() {
// #cloudDate
//
//
}, },
initAllCharts() { initAllCharts() {
this.initCamelStructureChart(); this.initCamelStructureChart();
this.initTrendChart(); this.initTrendChart();
this.initLactatingBarChart();
}, },
initCamelStructureChart() { initCamelStructureChart() {
const chartDom = this.$refs.camelChart; const chartDom = this.$refs.camelChart;
@ -332,12 +322,80 @@ export default {
symbolSize: 8, symbolSize: 8,
itemStyle: { color: '#3498db' } itemStyle: { color: '#3498db' }
}], }],
grid: { containLabel: true, bottom: 10, top: 20, right: 20, left: 45 }
grid: { containLabel: true, bottom: 0, top: 40, right: 20, left: 10 }
});
},
initLactatingBarChart() {
const chartDom = this.$refs.lactatingBarChart;
if (!chartDom) return;
if (this.lactatingBarChartIns) this.lactatingBarChartIns.dispose();
this.lactatingBarChartIns = echarts.init(chartDom);
const { months, lactatingData, otherData } = this.barChartData;
this.lactatingBarChartIns.setOption({
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
backgroundColor: 'rgba(0,0,0,0.7)',
borderColor: '#3498db',
textStyle: { color: '#fff' },
formatter: (params) => {
let res = `${params[0].axisValue}<br/>`;
res += `${params[0].marker} 泌乳母驼: ${params[0].value} 峰<br/>`;
res += `${params[1].marker} 其他骆驼: ${params[1].value} 峰<br/>`;
res += `合计: ${params[0].value + params[1].value}`;
return res;
}
},
legend: {
data: ['泌乳母驼', '其他骆驼'],
textStyle: { color: '#fff' },
left: 'left',
itemWidth: 25,
itemHeight: 14
},
grid: {
containLabel: true,
bottom: 15,
top: 30,
right: 15,
left: 50
},
xAxis: {
type: 'category',
data: months,
axisLabel: { color: '#fff', rotate: 30, interval: 0 },
axisLine: { lineStyle: { color: '#5dade2' } },
axisTick: { show: false }
},
yAxis: {
type: 'value',
nameTextStyle: { color: '#fff' },
axisLabel: { color: '#fff' },
splitLine: { lineStyle: { color: 'rgba(93, 173, 226, 0.3)' } },
axisLine: { lineStyle: { color: '#5dade2' } }
},
series: [
{
name: '泌乳母驼',
type: 'bar',
stack: 'total',
data: lactatingData,
itemStyle: { color: '#3498db', borderRadius: [4, 4, 0, 0] },
label: { show: false }
},
{
name: '其他骆驼',
type: 'bar',
stack: 'total',
data: otherData,
itemStyle: { color: '#85c1e9', borderRadius: [4, 4, 0, 0] },
label: { show: false }
}
],
backgroundColor: 'transparent'
}); });
}, },
// GL ()
initBaiduMapNative() { initBaiduMapNative() {
// API
if (typeof window.BMapGL === 'undefined') { if (typeof window.BMapGL === 'undefined') {
console.error('百度地图API未加载,请检查AK或网络,稍后重试'); console.error('百度地图API未加载,请检查AK或网络,稍后重试');
setTimeout(() => this.initBaiduMapNative(), 500); setTimeout(() => this.initBaiduMapNative(), 500);
@ -348,23 +406,16 @@ export default {
console.error('地图容器未找到'); console.error('地图容器未找到');
return; return;
} }
//
mapContainer.innerHTML = ''; mapContainer.innerHTML = '';
// ()
const map = new window.BMapGL.Map(mapContainer); const map = new window.BMapGL.Map(mapContainer);
const centerPoint = new window.BMapGL.Point(105.669, 38.833); const centerPoint = new window.BMapGL.Point(105.669, 38.833);
map.centerAndZoom(centerPoint, 11); map.centerAndZoom(centerPoint, 11);
map.enableScrollWheelZoom(true); map.enableScrollWheelZoom(true);
//
map.setMapStyle({ style: 'midnight' }); map.setMapStyle({ style: 'midnight' });
//
const markerPoint = new window.BMapGL.Point(105.669, 38.833); const markerPoint = new window.BMapGL.Point(105.669, 38.833);
const marker = new window.BMapGL.Marker(markerPoint); const marker = new window.BMapGL.Marker(markerPoint);
map.addOverlay(marker); map.addOverlay(marker);
//
const infoWindow = new window.BMapGL.InfoWindow( const infoWindow = new window.BMapGL.InfoWindow(
'<div style="background:#0a1a2e;color:#fff;padding:5px;border-radius:8px;"><strong>吉兰泰骆驼产业园</strong><br/>存栏骆驼: 4200峰<br/>日产奶量: 8.6吨</div>', '<div style="background:#0a1a2e;color:#fff;padding:5px;border-radius:8px;"><strong>吉兰泰骆驼产业园</strong><br/>存栏骆驼: 4200峰<br/>日产奶量: 8.6吨</div>',
{ width: 200, offset: new window.BMapGL.Size(0, -30) } { width: 200, offset: new window.BMapGL.Size(0, -30) }
@ -373,7 +424,6 @@ export default {
map.openInfoWindow(infoWindow, markerPoint); map.openInfoWindow(infoWindow, markerPoint);
}); });
//
const circlePoint = new window.BMapGL.Point(105.62, 38.81); const circlePoint = new window.BMapGL.Point(105.62, 38.81);
const circle = new window.BMapGL.Circle(circlePoint, 5000, { const circle = new window.BMapGL.Circle(circlePoint, 5000, {
strokeColor: "#3498db", strokeColor: "#3498db",
@ -383,7 +433,6 @@ export default {
}); });
map.addOverlay(circle); map.addOverlay(circle);
//
const labelOpts = { position: new window.BMapGL.Point(105.69, 38.85), offset: new window.BMapGL.Size(20, 0) }; const labelOpts = { position: new window.BMapGL.Point(105.69, 38.85), offset: new window.BMapGL.Size(20, 0) };
const label = new window.BMapGL.Label('巴音塔拉嘎查', labelOpts); const label = new window.BMapGL.Label('巴音塔拉嘎查', labelOpts);
label.setStyle({ label.setStyle({
@ -396,7 +445,6 @@ export default {
}); });
map.addOverlay(label); map.addOverlay(label);
//
const markerPoint2 = new window.BMapGL.Point(105.59, 38.79); const markerPoint2 = new window.BMapGL.Point(105.59, 38.79);
const marker2 = new window.BMapGL.Marker(markerPoint2); const marker2 = new window.BMapGL.Marker(markerPoint2);
map.addOverlay(marker2); map.addOverlay(marker2);
@ -409,8 +457,6 @@ export default {
}); });
this.baiduMap = map; this.baiduMap = map;
// resize
setTimeout(() => { setTimeout(() => {
if (this.baiduMap) { if (this.baiduMap) {
this.baiduMap.centerAndZoom(centerPoint, 11); this.baiduMap.centerAndZoom(centerPoint, 11);
@ -420,6 +466,7 @@ export default {
handleResize() { handleResize() {
if (this.camelChartIns) this.camelChartIns.resize(); if (this.camelChartIns) this.camelChartIns.resize();
if (this.trendChartIns) this.trendChartIns.resize(); if (this.trendChartIns) this.trendChartIns.resize();
if (this.lactatingBarChartIns) this.lactatingBarChartIns.resize();
if (this.baiduMap) { if (this.baiduMap) {
setTimeout(() => { setTimeout(() => {
this.baiduMap.centerAndZoom(this.baiduMap.getCenter(), this.baiduMap.getZoom()); this.baiduMap.centerAndZoom(this.baiduMap.getCenter(), this.baiduMap.getZoom());
@ -431,7 +478,6 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
//
.production-dashboard { .production-dashboard {
width: 100%; width: 100%;
height: 100vh; height: 100vh;
@ -446,8 +492,7 @@ export default {
.dashboard-main { .dashboard-main {
display: flex; display: flex;
gap: 20px; gap: 20px;
flex-wrap: nowrap; /* 改为不换行,确保三列并排对齐,超出则滚动 */
align-items: stretch; /* 使各列高度一致 */
align-items: stretch; /* 确保所有列高度一致 */
.col-left, .col-left,
.col-right { .col-right {
@ -467,7 +512,6 @@ export default {
} }
} }
/* 响应式:当屏幕宽度较小时,允许换行滚动,但保持对齐 */
@media (max-width: 1200px) { @media (max-width: 1200px) {
.dashboard-main { .dashboard-main {
flex-wrap: wrap; flex-wrap: wrap;
@ -486,6 +530,7 @@ export default {
transition: all 0.3s ease; transition: all 0.3s ease;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex: 1; /* 让卡片自动填充可用高度 */
&:hover { &:hover {
border-color: #5dade2; border-color: #5dade2;
@ -516,15 +561,10 @@ export default {
font-size: 12px; font-size: 12px;
color: white; color: white;
} }
.sub {
font-size: 11px;
color: rgba(255, 255, 255, 0.7);
}
} }
} }
//
/* 地图上方统计指标 */
.map-stats { .map-stats {
display: flex; display: flex;
gap: 12px; gap: 12px;
@ -536,7 +576,7 @@ export default {
background: rgba(0, 0, 0, 0.3); background: rgba(0, 0, 0, 0.3);
backdrop-filter: blur(4px); backdrop-filter: blur(4px);
border-radius: 12px; border-radius: 12px;
padding: 10px 8px;
padding: 24px 8px;
text-align: center; text-align: center;
border: 1.5px solid rgba(52, 152, 219, 0.6); border: 1.5px solid rgba(52, 152, 219, 0.6);
transition: all 0.2s; transition: all 0.2s;
@ -548,14 +588,15 @@ export default {
.stat-label { .stat-label {
display: block; display: block;
font-size: 11px;
color: rgba(255, 255, 255, 0.8);
margin-bottom: 6px;
font-size: 20px;
color: rgba(255, 255, 255, 0.85);
margin-bottom: 10px;
font-weight: 500;
} }
.stat-number { .stat-number {
display: block; display: block;
font-size: 22px;
font-size: 28px;
font-weight: bold; font-weight: bold;
color: #5dade2; color: #5dade2;
@ -571,6 +612,7 @@ export default {
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
gap: 16px; gap: 16px;
padding: 20px; padding: 20px;
flex: 1;
.kpi-item { .kpi-item {
background: rgba(0, 0, 0, 0.25); background: rgba(0, 0, 0, 0.25);
@ -579,6 +621,9 @@ export default {
text-align: center; text-align: center;
border: 1.5px solid rgba(52, 152, 219, 0.5); border: 1.5px solid rgba(52, 152, 219, 0.5);
transition: all 0.2s; transition: all 0.2s;
display: flex;
flex-direction: column;
justify-content: center;
&:hover { &:hover {
border-color: #5dade2; border-color: #5dade2;
@ -619,14 +664,21 @@ export default {
width: 100%; width: 100%;
height: 220px; height: 220px;
padding: 8px; padding: 8px;
flex-shrink: 0;
}
.bar-chart-container {
width: 100%;
height: 260px;
padding: 8px 8px 0 8px;
flex-shrink: 0;
} }
/* 百度地图容器样式 - 关键修复高度自适应且不超出 */
.map-card { .map-card {
margin-top: 0; margin-top: 0;
flex: 1; flex: 1;
display: flex; display: flex;
min-height: 500px; /* 保证地图有足够高度,同时响应式 */
min-height: 500px;
.baidu-map-container { .baidu-map-container {
width: 100%; width: 100%;
@ -642,7 +694,7 @@ export default {
.alert-list, .alert-list,
.task-list { .task-list {
padding: 8px 16px; padding: 8px 16px;
max-height: 260px;
flex: 1;
overflow-y: auto; overflow-y: auto;
.alert-item, .alert-item,
@ -722,51 +774,38 @@ export default {
} }
} }
/* 环形进度条样式 */
.ring-progress-wrapper {
display: flex;
justify-content: center;
align-items: center;
padding: 20px 0 10px;
}
.ring-progress {
width: 130px;
height: 130px;
transform: rotate(-90deg);
}
.ring-bg {
stroke: rgba(52, 152, 219, 0.25);
}
.ring-fill {
stroke: #5dade2;
transition: stroke-dashoffset 0.8s ease;
filter: drop-shadow(0 0 5px rgba(93, 173, 226, 0.5));
}
.ring-percent {
dominant-baseline: middle;
font-size: 22px;
fill: #fff;
}
.quota-footer { .quota-footer {
text-align: center; text-align: center;
font-size: 12px; font-size: 12px;
padding: 12px 0 18px; padding: 12px 0 18px;
color: rgba(255, 255, 255, 0.7); color: rgba(255, 255, 255, 0.7);
border-top: 1px solid rgba(52, 152, 219, 0.4); border-top: 1px solid rgba(52, 152, 219, 0.4);
margin-top: 4px;
margin-top: auto;
flex-shrink: 0;
} }
//
.col-right .card { .col-right .card {
max-height: 100%;
flex: 1;
display: flex;
flex-direction: column;
}
/* 确保左侧卡片内容自适应 */
.col-left .card {
flex: 1;
display: flex;
flex-direction: column;
}
.col-left .kpi-card {
flex: 0 0 auto; /* KPI卡片不自动拉伸 */
}
.col-left .chart-card {
flex: 1;
min-height: 240px;
} }
//
.production-dashboard::-webkit-scrollbar { .production-dashboard::-webkit-scrollbar {
width: 6px; width: 6px;
height: 6px; height: 6px;

282
chenhai-ui/src/views/login.vue

@ -1,16 +1,5 @@
<template> <template>
<div class="login"> <div class="login">
<!-- 背景装饰元素营造牧场/田野氛围 -->
<!-- <div class="bg-decorations">
<div class="sun"></div>
<div class="cloud cloud1"></div>
<div class="cloud cloud2"></div>
<div class="grass grass-left"></div>
<div class="grass grass-right"></div>
<div class="cattle-icon cattle1">🐮</div>
<div class="cattle-icon cattle2">🐄</div>
</div> -->
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form"> <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
<!-- 品牌区域 --> <!-- 品牌区域 -->
<div class="brand-area"> <div class="brand-area">
@ -44,6 +33,25 @@
</el-input> </el-input>
</el-form-item> </el-form-item>
<!-- 优化后的验证码区域更紧凑对齐美观 -->
<el-form-item prop="code" v-if="captchaEnabled" class="captcha-item">
<div class="captcha-wrapper">
<el-input
v-model="loginForm.code"
auto-complete="off"
placeholder="验证码"
@keyup.enter.native="handleLogin"
class="captcha-input"
>
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
</el-input>
<div class="captcha-image" @click="getCode">
<img :src="codeUrl" class="captcha-img" alt="验证码" />
<span class="refresh-icon" title="点击刷新"></span>
</div>
</div>
</el-form-item>
<!-- 选项栏记住密码 + 立即注册 --> <!-- 选项栏记住密码 + 立即注册 -->
<div class="options-bar"> <div class="options-bar">
<el-checkbox v-model="loginForm.rememberMe" class="remember-checkbox">记住密码</el-checkbox> <el-checkbox v-model="loginForm.rememberMe" class="remember-checkbox">记住密码</el-checkbox>
@ -64,11 +72,6 @@
</el-form-item> </el-form-item>
</el-form> </el-form>
<!-- 底部 -->
<!-- <div class="el-login-footer">
<span>{{ footerContent }}</span>
</div> -->
</div> </div>
</template> </template>
@ -99,12 +102,13 @@ export default {
password: [ password: [
{ required: true, trigger: "blur", message: "请输入您的密码" } { required: true, trigger: "blur", message: "请输入您的密码" }
], ],
code: [{ required: true, trigger: "change", message: "请输入验证码" }]
}, },
loading: false, loading: false,
captchaEnabled: true, captchaEnabled: true,
register: false, register: false,
redirect: undefined, redirect: undefined,
showDemoTip: true //
showDemoTip: true
} }
}, },
watch: { watch: {
@ -188,95 +192,6 @@ $shadow-focus: 0 0 0 3px rgba(124, 154, 62, 0.2);
background: linear-gradient(135deg, #2b5e2b 0%, #8cb36b 50%, #d4c9a3 100%); background: linear-gradient(135deg, #2b5e2b 0%, #8cb36b 50%, #d4c9a3 100%);
overflow: hidden; overflow: hidden;
//
.bg-decorations {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 0;
}
//
.sun {
position: absolute;
top: 8%;
right: 5%;
width: 100px;
height: 100px;
background: radial-gradient(circle, #ffdf8c, #ffb347);
border-radius: 50%;
box-shadow: 0 0 50px rgba(255, 180, 70, 0.6);
animation: float 8s infinite ease-in-out;
}
//
.cloud {
position: absolute;
background: rgba(255, 255, 255, 0.85);
border-radius: 1000px;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.05);
&::before, &::after {
content: '';
position: absolute;
background: inherit;
border-radius: 50%;
}
}
.cloud1 {
top: 12%;
left: -50px;
width: 160px;
height: 70px;
&::before { width: 60px; height: 60px; top: -30px; left: 20px; }
&::after { width: 80px; height: 80px; top: -40px; left: 70px; }
animation: drift 22s infinite linear;
}
.cloud2 {
bottom: 15%;
right: -30px;
width: 200px;
height: 85px;
&::before { width: 70px; height: 70px; top: -35px; left: 20px; }
&::after { width: 90px; height: 90px; top: -45px; left: 85px; }
animation: drift 28s infinite reverse linear;
}
//
.grass {
position: absolute;
bottom: 0;
width: 100%;
height: 80px;
background: repeating-linear-gradient(45deg, #4c6a2c, #4c6a2c 30px, #5e7e38 30px, #5e7e38 60px);
opacity: 0.5;
&::before {
content: '';
position: absolute;
top: -20px;
left: 0;
width: 100%;
height: 25px;
background: radial-gradient(ellipse at top, #6f9e3f, transparent);
}
}
.grass-left { left: 0; width: 40%; border-radius: 0 40% 0 0; }
.grass-right { right: 0; width: 55%; border-radius: 40% 0 0 0; }
//
.cattle-icon {
position: absolute;
font-size: 48px;
filter: drop-shadow(2px 4px 8px rgba(0,0,0,0.2));
opacity: 0.7;
animation: bounce 4s infinite;
}
.cattle1 { bottom: 12%; left: 5%; animation-delay: 0s; }
.cattle2 { bottom: 18%; right: 8%; animation-delay: 1.2s; font-size: 56px; }
// //
.login-form { .login-form {
position: relative; position: relative;
@ -345,6 +260,100 @@ $shadow-focus: 0 0 0 3px rgba(124, 154, 62, 0.2);
} }
} }
// ========= =========
.captcha-item {
margin-bottom: 18px;
:deep(.el-form-item__content) {
line-height: initial;
}
}
.captcha-wrapper {
display: flex;
align-items: center;
gap: 12px;
width: 100%;
}
.captcha-input {
flex: 1;
:deep(.el-input__inner) {
height: 48px;
border-radius: 60px;
border: 1px solid #e2e8e6;
background: #fefef7;
padding-left: 42px;
font-size: 15px;
transition: all 0.2s;
&:focus {
border-color: $primary-color;
box-shadow: $shadow-focus;
}
}
:deep(.el-input__prefix) {
left: 16px;
top: 2px;
.input-icon {
font-size: 18px;
color: $primary-color;
}
}
}
.captcha-image {
position: relative;
flex-shrink: 0;
width: 110px;
height: 48px;
border-radius: 12px;
overflow: hidden;
cursor: pointer;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.2s, box-shadow 0.2s;
&:hover {
transform: scale(1.02);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
.refresh-icon {
opacity: 1;
}
}
}
.captcha-img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.refresh-icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 22px;
font-weight: bold;
color: white;
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
opacity: 0;
transition: opacity 0.2s;
background: rgba(0, 0, 0, 0.5);
width: 32px;
height: 32px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(2px);
pointer-events: none;
}
// + // +
.options-bar { .options-bar {
display: flex; display: flex;
@ -397,55 +406,9 @@ $shadow-focus: 0 0 0 3px rgba(124, 154, 62, 0.2);
box-shadow: 0 10px 22px rgba(92, 122, 46, 0.4); box-shadow: 0 10px 22px rgba(92, 122, 46, 0.4);
} }
} }
//
.demo-tip {
margin-top: 22px;
text-align: center;
font-size: 12px;
color: #8b9a7a;
background: #f2f6ec;
padding: 8px 12px;
border-radius: 100px;
display: inline-block;
width: 100%;
span {
display: inline-flex;
align-items: center;
gap: 5px;
}
}
// footer
.el-login-footer {
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
padding: 12px;
color: rgba(255,255,240,0.9);
font-size: 12px;
background: rgba(0,0,0,0.2);
backdrop-filter: blur(4px);
z-index: 2;
font-family: monospace;
}
} }
// //
@keyframes float {
0% { transform: translateY(0px); }
50% { transform: translateY(-12px); }
100% { transform: translateY(0px); }
}
@keyframes drift {
0% { transform: translateX(0); }
100% { transform: translateX(80px); }
}
@keyframes bounce {
0%,100%{ transform: translateY(0); }
50%{ transform: translateY(-8px); }
}
@keyframes gentleSwing { @keyframes gentleSwing {
0%,100%{ transform: rotate(0deg); } 0%,100%{ transform: rotate(0deg); }
50%{ transform: rotate(6deg); } 50%{ transform: rotate(6deg); }
@ -457,11 +420,18 @@ $shadow-focus: 0 0 0 3px rgba(124, 154, 62, 0.2);
width: 88%; width: 88%;
padding: 30px 20px; padding: 30px 20px;
} }
.bg-decorations .cattle-icon {
display: none;
.captcha-wrapper {
gap: 8px;
}
.captcha-image {
width: 95px;
height: 44px;
} }
.cloud1, .cloud2 {
opacity: 0.6;
.captcha-input :deep(.el-input__inner) {
height: 44px;
} }
} }
</style> </style>
Loading…
Cancel
Save