@@ -105,6 +105,9 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
105105 case "register" :
106106 await this . _handleRegister ( msg ) ;
107107 break ;
108+ case "sendCode" :
109+ await this . _handleSendCode ( msg ) ;
110+ break ;
108111 case "logout" :
109112 await this . _handleLogout ( ) ;
110113 break ;
@@ -166,9 +169,9 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
166169 }
167170 }
168171
169- private async _handleRegister ( msg : { email : string ; username : string ; password : string } ) : Promise < void > {
172+ private async _handleRegister ( msg : { email : string ; username : string ; password : string ; emailCode ?: string } ) : Promise < void > {
170173 try {
171- const result = await this . _client . cloudRegister ( msg . email , msg . username , msg . password ) ;
174+ const result = await this . _client . cloudRegister ( msg . email , msg . username , msg . password , msg . emailCode ) ;
172175 await this . _context . secrets . store ( "testpilot.token" , result . access_token ) ;
173176 if ( result . refresh_token ) {
174177 await this . _context . secrets . store ( "testpilot.refresh_token" , result . refresh_token ) ;
@@ -188,6 +191,24 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
188191 }
189192 }
190193
194+ private async _handleSendCode ( msg : { email : string } ) : Promise < void > {
195+ try {
196+ const result = await this . _client . cloudSendEmailCode ( msg . email ) ;
197+ this . _postMessage ( {
198+ command : "sendCodeResult" ,
199+ success : true ,
200+ message : result . message ,
201+ devCode : result . dev_code , // 开发模式下返回,方便调试
202+ } ) ;
203+ } catch ( e : any ) {
204+ this . _postMessage ( {
205+ command : "sendCodeResult" ,
206+ success : false ,
207+ error : e . message || "发送失败,请稍后重试" ,
208+ } ) ;
209+ }
210+ }
211+
191212 private async _handleLogout ( ) : Promise < void > {
192213 await this . _context . secrets . delete ( "testpilot.token" ) ;
193214 await this . _context . secrets . delete ( "testpilot.refresh_token" ) ;
@@ -1658,16 +1679,28 @@ ${commonRules}`;
16581679 .sdrop-pass-wrap {
16591680 position: relative; margin-bottom: 5px;
16601681 }
1661- .sdrop-pass-wrap input {
1662- width: 100%; box-sizing: border-box; padding-right: 28px; margin-bottom: 0;
1682+ /* 三层选择器权重高于 .sdrop-auth-panel input,确保 margin-bottom:0 生效 */
1683+ .sdrop-auth-panel .sdrop-pass-wrap input {
1684+ margin-bottom: 0; padding-right: 26px;
16631685 }
16641686 .sdrop-eye-btn {
1665- position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
1687+ position: absolute; right: 4px; top: 0; bottom: 0;
1688+ display: flex; align-items: center;
16661689 background: none; border: none; cursor: pointer;
1667- font-size: 13px; line-height: 1; padding: 2px; color: var(--muted);
1690+ font-size: 12px; padding: 0 2px; color: var(--muted);
16681691 opacity: 0.6; transition: opacity 0.1s;
16691692 }
16701693 .sdrop-eye-btn:hover { opacity: 1; }
1694+ /* 发送验证码按钮 */
1695+ .sdrop-code-row { display: flex; gap: 4px; margin-bottom: 5px; }
1696+ .sdrop-code-row input { flex: 1; margin-bottom: 0; }
1697+ .sdrop-send-code-btn {
1698+ flex-shrink: 0; padding: 5px 6px; font-size: 10px; font-weight: 600;
1699+ background: none; color: var(--btn-bg);
1700+ border: 1px solid var(--btn-bg); border-radius: 3px; cursor: pointer;
1701+ white-space: nowrap; min-width: 44px;
1702+ }
1703+ .sdrop-send-code-btn:disabled { opacity: 0.4; cursor: not-allowed; }
16711704 .sdrop-login-btn {
16721705 width: 100%; padding: 6px; font-size: 11px; font-weight: 600;
16731706 background: var(--btn-bg); color: var(--btn-fg);
@@ -1741,7 +1774,11 @@ ${commonRules}`;
17411774 <!-- 注册表单 -->
17421775 <div id="registerForm" style="display:none">
17431776 <div id="regError" class="auth-error"></div>
1744- <input id="regEmail" type="email" placeholder="邮箱地址" autocomplete="email" />
1777+ <div class="sdrop-code-row">
1778+ <input id="regEmail" type="email" placeholder="邮箱地址" autocomplete="email" />
1779+ <button class="sdrop-send-code-btn" id="btnSendCode">获取</button>
1780+ </div>
1781+ <input id="regCode" type="text" placeholder="邮箱验证码(6位)" autocomplete="off" maxlength="6" />
17451782 <input id="regUser" type="text" placeholder="用户名" autocomplete="username" />
17461783 <div class="sdrop-pass-wrap">
17471784 <input id="regPass" type="password" placeholder="密码" autocomplete="new-password" />
@@ -2042,13 +2079,37 @@ ${commonRules}`;
20422079 function doRegister() {
20432080 showRegError('');
20442081 const email = (document.getElementById('regEmail')).value.trim();
2082+ const code = (document.getElementById('regCode')).value.trim();
20452083 const user = (document.getElementById('regUser')).value.trim();
20462084 const pass = (document.getElementById('regPass')).value;
20472085 const confirm = (document.getElementById('regConfirm')).value;
20482086 if (!email || !user || !pass) { showRegError('请填写所有字段'); return; }
20492087 if (pass !== confirm) { showRegError('两次密码不一致'); return; }
20502088 if (pass.length < 6) { showRegError('密码至少6位'); return; }
2051- vscode.postMessage({ command: 'register', email, username: user, password: pass });
2089+ vscode.postMessage({ command: 'register', email, username: user, password: pass, emailCode: code || undefined });
2090+ }
2091+
2092+ // 发送验证码(60s 倒计时)
2093+ let _codeCountdown = 0;
2094+ let _codeTimer = null;
2095+ function doSendCode() {
2096+ const emailEl = document.getElementById('regEmail');
2097+ const email = emailEl ? emailEl.value.trim() : '';
2098+ if (!email || !email.includes('@')) { showRegError('请先填写正确的邮箱地址'); return; }
2099+ showRegError('');
2100+ vscode.postMessage({ command: 'sendCode', email });
2101+ // 立即开始倒计时
2102+ const btn = document.getElementById('btnSendCode');
2103+ _codeCountdown = 60;
2104+ if (btn) btn.disabled = true;
2105+ _codeTimer = setInterval(() => {
2106+ _codeCountdown--;
2107+ if (btn) btn.textContent = _codeCountdown + 's';
2108+ if (_codeCountdown <= 0) {
2109+ clearInterval(_codeTimer);
2110+ if (btn) { btn.disabled = false; btn.textContent = '获取'; }
2111+ }
2112+ }, 1000);
20522113 }
20532114
20542115 function doLogout() {
@@ -2063,6 +2124,8 @@ ${commonRules}`;
20632124 if (authLoginBtn) authLoginBtn.addEventListener('click', doAuth);
20642125 const authRegisterSubmit = document.getElementById('authRegisterSubmit');
20652126 if (authRegisterSubmit) authRegisterSubmit.addEventListener('click', doRegister);
2127+ const btnSendCode = document.getElementById('btnSendCode');
2128+ if (btnSendCode) btnSendCode.addEventListener('click', (e) => { e.stopPropagation(); doSendCode(); });
20662129 const authLogoutBtn = document.getElementById('authLogoutBtn');
20672130 if (authLogoutBtn) authLogoutBtn.addEventListener('click', doLogout);
20682131 const themeToggleLabel = document.getElementById('themeToggleLabel');
@@ -2490,6 +2553,23 @@ ${commonRules}`;
24902553 }
24912554 }
24922555 break;
2556+ case "sendCodeResult": {
2557+ const btn = document.getElementById('btnSendCode');
2558+ if (!msg.success) {
2559+ // 发送失败:重置倒计时
2560+ if (_codeTimer) { clearInterval(_codeTimer); _codeTimer = null; }
2561+ _codeCountdown = 0;
2562+ if (btn) { btn.disabled = false; btn.textContent = '获取'; }
2563+ showRegError(msg.error || '发送失败');
2564+ } else {
2565+ // 开发模式:dev_code 直接填入验证码框方便测试
2566+ if (msg.devCode) {
2567+ const codeEl = document.getElementById('regCode');
2568+ if (codeEl) codeEl.value = msg.devCode;
2569+ }
2570+ }
2571+ break;
2572+ }
24932573 case "shareResult":
24942574 if (btnShareExperience) {
24952575 btnShareExperience.disabled = false;
0 commit comments