Browse Source

fix: 登录验证码去清空按钮并遮住即梦AI水印

四处验证码输入去掉 clearable;登录背景右下角用 CSS
遮罩盖住即梦AI 标识,文案层级抬到遮罩之上。
main
xiaosi 3 weeks ago
parent
commit
3331ddbd8a
  1. 57
      docs/superpowers/plans/2026-08-28-login-captcha-clear-watermark.md
  2. 56
      src/views/LoginView/LoginView.vue

57
docs/superpowers/plans/2026-08-28-login-captcha-clear-watermark.md

@ -0,0 +1,57 @@
# Login Captcha Clear + Watermark Cover Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans or implement inline for this tiny change.
**Goal:** 去掉登录相关验证码输入框的 clear 按钮,并用 CSS 遮住登录背景右下角「即梦AI」水印。
**Architecture:** 仅改 `LoginView.vue`:四处 `t-input` 去掉 `clearable`;在 `.visual` 上加右下角遮罩伪元素。不改原图、不改后台。
**Tech Stack:** Vue 3 + TDesign Input、现有 LoginView scoped CSS
**Spec:** `docs/superpowers/specs/2026-08-28-login-captcha-clear-watermark-design.md`
---
### Task 1: 去掉验证码 clearable
**Files:**
- Modify: `src/views/LoginView/LoginView.vue`
- [ ] 移除这四处 `clearable`
1. `v-model="captcha"`(图形验证码)
2. 短信登录 `smsCode`(placeholder「请输入短信验证码」)
3. 注册 `reg.smsCode`
4. 找回密码 `forgot.code`
- [ ] 账号/密码/手机号等其它 `clearable` 保持不动
- [ ] Commit: `fix: 登录验证码输入框去掉清空按钮`
### Task 2: CSS 遮罩「即梦AI」
**Files:**
- Modify: `src/views/LoginView/LoginView.vue`
- [ ] 在 `.visual`(`position: relative` 已有)增加伪元素,例如:
```css
.visual::after {
content: '';
position: absolute;
right: 0;
bottom: 0;
width: min(280px, 28vw);
height: min(72px, 10vh);
z-index: 2;
pointer-events: none;
background: linear-gradient(135deg, transparent 20%, #102a35 55%);
}
```
- [ ] 确保 `.brand` / `.copy` / `.footer` 的 z-index ≥ 伪元素,文案不被挡
- [ ] Commit: `fix: 登录背景遮住即梦AI水印`
### Task 3: 浏览器冒烟
- [ ] 打开 `/login`
- [ ] 图形验证码输入有内容时无 ×;账号/密码仍有 clear
- [ ] 右下角看不到「即梦AI」
- [ ] 必要时微调遮罩宽高后再 commit

56
src/views/LoginView/LoginView.vue

@ -79,13 +79,15 @@ async function submitLogin() {
const token = data?.accessToken || data?.token || data?.jToken
if (!token) {
loginError.value = '登录成功但未返回 token,请检查后端响应字段。'
if (method.value === 'password') await refreshCaptcha()
return
}
userStore.setLogin(token, data.user || data.userInfo || null, data.refreshToken || '')
ui.toast('登录成功')
router.push('/monitor')
} catch (e) {
//
//
if (method.value === 'password') await refreshCaptcha()
} finally {
loading.value = false
}
@ -198,7 +200,7 @@ async function submitForgot() {
<div :class="s.visualMap" />
<div :class="s.visualShade" />
<div :class="s.brand">
<div :class="s.brandMark"><span /><span /><span /></div>
<img :class="s.brandMark" src="/assets/logo.png" alt="嘉谷" />
<div>
<strong>嘉谷</strong>
<small>低空智控平台</small>
@ -297,7 +299,6 @@ async function submitForgot() {
<t-input
v-model="smsCode"
size="large"
clearable
:maxlength="6"
placeholder="请输入短信验证码"
>
@ -323,7 +324,6 @@ async function submitForgot() {
<t-input
v-model="captcha"
size="large"
clearable
:maxlength="4"
placeholder="请输入验证码"
>
@ -427,7 +427,7 @@ async function submitForgot() {
<t-form-item>
<div :class="s.codeRow">
<t-input v-model="reg.smsCode" size="large" clearable :maxlength="6" placeholder="请输入短信验证码" />
<t-input v-model="reg.smsCode" size="large" :maxlength="6" placeholder="请输入短信验证码" />
<t-button theme="default" variant="outline" size="large" @click="sendRegisterCode">获取验证码</t-button>
</div>
</t-form-item>
@ -510,7 +510,6 @@ async function submitForgot() {
<t-input
v-model="forgot.code"
size="large"
clearable
:maxlength="6"
placeholder="请输入短信验证码"
/>
@ -571,9 +570,22 @@ async function submitForgot() {
linear-gradient(0deg, rgba(9, 26, 34, 0.72), transparent 42%);
}
.brand {
.visual::after {
content: '';
position: absolute;
right: 0;
bottom: 0;
width: min(300px, 30vw);
height: min(80px, 11vh);
z-index: 1;
pointer-events: none;
background: linear-gradient(135deg, transparent 18%, #102a35 58%);
}
.brand {
position: absolute;
z-index: 2;
top: 36px;
left: 40px;
display: flex;
@ -595,33 +607,15 @@ async function submitForgot() {
}
.brandMark {
display: grid;
grid-template-columns: repeat(3, 6px);
gap: 4px;
span {
width: 6px;
height: 18px;
border-radius: 2px;
background: #5ec8f0;
&:nth-child(2) {
opacity: 0.7;
height: 12px;
align-self: end;
}
&:nth-child(3) {
opacity: 0.45;
height: 8px;
align-self: end;
}
}
width: 28px;
height: 28px;
object-fit: contain;
flex-shrink: 0;
}
.visualCopy {
position: absolute;
z-index: 1;
z-index: 2;
left: 40px;
bottom: 96px;
max-width: 420px;
@ -648,7 +642,7 @@ async function submitForgot() {
.visualFooter {
position: absolute;
z-index: 1;
z-index: 2;
left: 40px;
right: 40px;
bottom: 28px;

Loading…
Cancel
Save