diff --git a/apps/backend/src/services/worker-platform/worker-service.ts b/apps/backend/src/services/worker-platform/worker-service.ts index 8ed96f83..ff65df88 100644 --- a/apps/backend/src/services/worker-platform/worker-service.ts +++ b/apps/backend/src/services/worker-platform/worker-service.ts @@ -189,10 +189,16 @@ export async function registerWorker(payload: JsonObject = {}) { const phone = normalizeWorkerPhone(payload.phone) const code = String(payload.code || payload.smsCode || '').trim() const password = normalizePassword(payload.password) - const displayName = String(payload.displayName || payload.nickname || phone).trim() + const displayName = String(payload.displayName || payload.nickname || '').trim() const inviteCode = String(payload.inviteCode || '').trim().toUpperCase() validateWorkerPassword(password) + if (!displayName) { + throw createHttpError('请输入昵称', { + statusCode: 400, + errorCode: 'worker_display_name_required', + }) + } if (!code) { throw createHttpError('请输入短信验证码', { statusCode: 400, diff --git a/apps/frontend/src/main.tsx b/apps/frontend/src/main.tsx index f1e03f33..ac7860b8 100644 --- a/apps/frontend/src/main.tsx +++ b/apps/frontend/src/main.tsx @@ -32,7 +32,9 @@ ReactDOM.createRoot(document.getElementById('root')!).render( }} theme={{ token: { - colorPrimary: '#1677ff', + colorPrimary: '#ff6a00', + colorLink: '#ff6a00', + colorInfo: '#ff6a00', borderRadius: 6, fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif', diff --git a/apps/frontend/src/pages/worker/WorkerLoginPage.tsx b/apps/frontend/src/pages/worker/WorkerLoginPage.tsx index 7b984ff2..87b8cefa 100644 --- a/apps/frontend/src/pages/worker/WorkerLoginPage.tsx +++ b/apps/frontend/src/pages/worker/WorkerLoginPage.tsx @@ -1,5 +1,13 @@ -import { LockOutlined, MobileOutlined, UserOutlined } from '@ant-design/icons' -import { App, Button, Card, Form, Input, Space, Tabs, Typography } from 'antd' +import { + GiftOutlined, + GlobalOutlined, + LockOutlined, + MobileOutlined, + SafetyCertificateOutlined, + ThunderboltOutlined, + UserOutlined, +} from '@ant-design/icons' +import { App, Button, Form, Input, Space, Tabs } from 'antd' import { useEffect, useState } from 'react' import { Navigate, useNavigate } from 'react-router' @@ -8,6 +16,24 @@ import { hasWorkerSession, setWorkerSession } from '@/utils/worker-auth' const SMS_COUNTDOWN_SECONDS = 60 +const brandFeatures = [ + { + icon: , + title: '实时派单', + desc: '新单自动刷新,空闲时优先看大厅', + }, + { + icon: , + title: '押金保障', + desc: '接单冻结押金,验收后按规则释放', + }, + { + icon: , + title: '结算清晰', + desc: '订单收益、冻结与提现记录统一查看', + }, +] + export default function WorkerLoginPage() { const navigate = useNavigate() const { message } = App.useApp() @@ -65,7 +91,7 @@ export default function WorkerLoginPage() { phone: string code: string password: string - displayName?: string + displayName: string inviteCode?: string }) { setLoading(true) @@ -81,88 +107,194 @@ export default function WorkerLoginPage() { } return ( - - - 接单平台 - - 使用手机号验证码注册,注册后可直接进入抢单大厅。 - - - - } autoComplete="username" /> - - - } autoComplete="current-password" /> - - - 登录 - - - ), - }, - { - key: 'register', - label: '注册', - children: ( - - - } autoComplete="tel" maxLength={11} /> - - - - - 0} onClick={requestSmsCode}> - {countdown > 0 ? `${countdown}s 后重发` : '获取验证码'} - - - - - - - - - - - } autoComplete="new-password" /> - - - 注册 - - - ), - }, - ]} - /> - + + + {/* 品牌信息区:移动端隐藏 */} + + + {/* 登录注册表单区 */} + + + {/* 移动端精简品牌栏 */} + + + + + 王大锤 · 接单平台 + + + + + 欢迎回来 + 使用账号或手机号登录,进入抢单大厅 + + + + } autoComplete="username" /> + + + } + autoComplete="current-password" + /> + + + 登录 + + + > + ), + }, + { + key: 'register', + label: '注册', + children: ( + <> + + 创建账号 + 手机号验证码注册,注册后即可开始接单 + + + + } autoComplete="tel" maxLength={11} /> + + + + } + placeholder="6 位数字验证码" + maxLength={6} + /> + 0} + onClick={requestSmsCode} + > + {countdown > 0 ? `${countdown}s 后重发` : '获取验证码'} + + + + + } /> + + + } + maxLength={8} + placeholder="填写邀请人邀请码" + /> + + + } autoComplete="new-password" /> + + + 注册 + + + > + ), + }, + ]} + /> + + 注册即代表同意平台《服务协议》与《隐私政策》 + + + ) } diff --git a/apps/frontend/src/services/worker.ts b/apps/frontend/src/services/worker.ts index 8eca418e..e9f69812 100644 --- a/apps/frontend/src/services/worker.ts +++ b/apps/frontend/src/services/worker.ts @@ -24,7 +24,7 @@ export function registerWorker(payload: { phone: string code: string password: string - displayName?: string + displayName: string inviteCode?: string }) { return apiPost<{ worker: WorkerUser; reviewRequired: boolean }>( diff --git a/apps/frontend/src/styles/main.css b/apps/frontend/src/styles/main.css index ddb237dd..94dc1257 100644 --- a/apps/frontend/src/styles/main.css +++ b/apps/frontend/src/styles/main.css @@ -1,4 +1,10 @@ :root { + --theme-primary: #ff6a00; + --theme-primary-hover: #ff7a1a; + --theme-primary-active: #e65f00; + --theme-primary-soft: #fff3e8; + --theme-primary-soft-hover: #ffe6d1; + --theme-primary-shadow: rgba(255, 106, 0, 0.14); color: #1f2937; background: #f5f7fb; font-synthesis: none; @@ -24,34 +30,323 @@ select { font: inherit; } -.login-page { +/* ===== 登录页:工作台入口布局 ===== */ + +.auth-page { min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + padding: 48px 24px; + background: + linear-gradient(135deg, rgba(255, 106, 0, 0.055), transparent 30%), + linear-gradient(315deg, rgba(31, 41, 55, 0.045), transparent 38%), #f5f7fb; +} + +.auth-shell { + width: min(940px, 100%); + min-height: 560px; + display: grid; + grid-template-columns: minmax(300px, 0.84fr) minmax(420px, 1fr); + overflow: hidden; + border: 1px solid rgba(226, 232, 240, 0.86); + border-radius: 18px; + background: #fff; + box-shadow: 0 28px 72px rgba(15, 23, 42, 0.12); +} + +.auth-brand { + position: relative; + display: flex; + flex-direction: column; + justify-content: space-between; + gap: 34px; + padding: 40px; + color: #f9fafb; + background: + radial-gradient(circle at 100% 0%, rgba(255, 106, 0, 0.28), transparent 34%), + linear-gradient(160deg, #211816 0%, #171717 100%); + overflow: hidden; +} + +.auth-brand::before { + content: ''; + position: absolute; + inset: 0 auto 0 0; + width: 4px; + background: linear-gradient(180deg, var(--theme-primary), #ffb45a); +} + +.auth-brand::after { + content: ''; + position: absolute; + right: 28px; + bottom: 28px; + width: 108px; + height: 108px; + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 24px; + transform: rotate(12deg); +} + +.auth-brand-top, +.auth-brand-features, +.auth-brand-footer { + position: relative; + z-index: 1; +} + +.auth-brand-logo { + display: flex; + align-items: center; + gap: 12px; +} + +.auth-brand-logo .auth-logo-mark { + width: 42px; + height: 42px; display: grid; place-items: center; - padding: 24px; - background: - linear-gradient(135deg, rgba(22, 119, 255, 0.1), rgba(19, 194, 194, 0.08)), - #f5f7fb; + border-radius: 10px; + background: var(--theme-primary); + color: #fff; + font-size: 21px; + box-shadow: 0 14px 30px rgba(255, 106, 0, 0.26); } -.login-panel { - width: min(440px, 100%); - box-shadow: 0 18px 50px rgba(15, 23, 42, 0.12); +.auth-brand-logo strong, +.auth-brand-logo div > span { + display: block; } -.login-heading { +.auth-brand-logo strong { + color: #fff; + font-size: 18px; + line-height: 1.2; +} + +.auth-brand-logo div > span { + margin-top: 3px; + color: rgba(249, 250, 251, 0.58); + font-size: 12px; + line-height: 1.2; +} + +.auth-brand-body { + max-width: 320px; + margin-top: 58px; +} + +.auth-brand-kicker { + display: inline-flex; + align-items: center; + min-height: 26px; + margin-bottom: 18px; + padding: 0 10px; + border: 1px solid rgba(255, 106, 0, 0.36); + border-radius: 999px; + color: #ffbd85; + font-size: 12px; + font-weight: 700; +} + +.auth-brand-body h2 { + margin: 0 0 16px; + color: #fff; + font-size: 30px; + font-weight: 700; + line-height: 1.28; +} + +.auth-brand-body p { + margin: 0; + color: rgba(249, 250, 251, 0.68); + font-size: 14px; + line-height: 1.8; +} + +.auth-brand-features { + display: grid; + gap: 12px; +} + +.auth-brand-feature { + display: flex; + align-items: flex-start; + gap: 12px; + min-height: 74px; + padding: 14px; + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 10px; + background: rgba(255, 255, 255, 0.045); +} + +.auth-brand-feature .auth-feature-icon { + flex: 0 0 34px; + width: 34px; + height: 34px; + display: grid; + place-items: center; + border-radius: 8px; + background: rgba(255, 106, 0, 0.16); + color: #ffb45a; + font-size: 16px; +} + +.auth-brand-feature-text strong { + display: block; + margin-bottom: 4px; + color: #fff; + font-size: 14px; +} + +.auth-brand-feature-text span { + color: rgba(249, 250, 251, 0.58); + font-size: 12px; + line-height: 1.55; +} + +.auth-brand-footer { + color: rgba(249, 250, 251, 0.42); + font-size: 12px; +} + +.auth-form-side { + display: flex; + align-items: center; + justify-content: center; + padding: 56px 52px; + background: #fff; +} + +.auth-form-card { + width: min(410px, 100%); +} + +.auth-form-header { + margin: 22px 0 22px; +} + +.auth-form-header h1 { + margin: 0 0 8px; + color: #111827; + font-size: 25px; + font-weight: 700; +} + +.auth-form-header p { + margin: 0; + color: #6b7280; + font-size: 13px; + line-height: 1.7; +} + +.auth-form-card .ant-tabs { + margin-bottom: 2px; +} + +.auth-form-card .ant-tabs-nav { + margin-bottom: 0; +} + +.auth-form-card .ant-tabs-tab { + padding: 8px 0; + font-size: 16px; +} + +.auth-form-card .ant-form-item { + margin-bottom: 17px; +} + +.auth-form-card .ant-form-item-label { + padding-bottom: 7px; +} + +.auth-form-card .ant-input-affix-wrapper { + height: 46px; + display: flex; + align-items: center; + padding: 0 14px; +} + +.auth-form-card .ant-input-affix-wrapper .ant-input { + height: auto; + min-height: 0; + padding: 0; + line-height: 22px; +} + +.auth-form-card .ant-input-affix-wrapper .ant-input-prefix, +.auth-form-card .ant-input-affix-wrapper .ant-input-suffix { + display: inline-flex; + align-items: center; +} + +.auth-form-card .ant-input { + height: 46px; + padding: 0 14px; + line-height: 22px; +} + +.auth-form-card .ant-btn-lg, +.auth-form-card .ant-space-compact .ant-btn { + height: 46px; +} + +.auth-form-card .ant-btn-lg { + font-size: 15px; + font-weight: 600; +} + +.auth-form-footer { + margin-top: 24px; + color: #9ca3af; + text-align: center; + font-size: 13px; +} + +.auth-mobile-brand { + display: none; + align-items: center; + gap: 10px; margin-bottom: 24px; } -.login-heading h1 { - margin: 8px 0 0; - font-size: 28px; +.auth-mobile-brand .auth-logo-mark { + width: 36px; + height: 36px; + display: grid; + place-items: center; + border-radius: 9px; + background: var(--theme-primary); + color: #fff; + font-size: 18px; } -.eyebrow { - color: #1677ff; - font-weight: 700; - letter-spacing: 0; +.auth-mobile-brand strong { + color: #111827; + font-size: 18px; +} + +@media (max-width: 860px) { + .auth-shell { + width: 100%; + min-height: 0; + display: block; + border-radius: 14px; + } + + .auth-brand { + display: none; + } + + .auth-form-side { + padding: 32px 24px; + } + + .auth-mobile-brand { + display: flex; + } } .admin-shell { @@ -339,11 +634,11 @@ select { } .kuaishou-industry-row-selected > td { - background: #eef6ff !important; + background: var(--theme-primary-soft) !important; } .kuaishou-industry-row-selected:hover > td { - background: #e5f0ff !important; + background: var(--theme-primary-soft-hover) !important; } .kuaishou-industry-tool-card .ant-card-body { @@ -656,9 +951,7 @@ select { } .payload-text { - font-family: - ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', - monospace; + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', monospace; font-size: 12px; color: #4b5563; word-break: break-all; @@ -741,7 +1034,7 @@ select { } .claim-step-dot.active { - background: #1677ff; + background: var(--theme-primary); color: #ffffff; } @@ -778,7 +1071,7 @@ select { } .claim-icon-info { - color: #1677ff; + color: var(--theme-primary); } .claim-icon-error { @@ -1072,7 +1365,7 @@ select { .claim-feifei-main p { margin: 0; - color: #1677ff; + color: var(--theme-primary); font-weight: 700; } @@ -1097,7 +1390,7 @@ select { } .claim-product-items-header strong { - color: #1677ff; + color: var(--theme-primary); font-weight: 700; } @@ -1329,8 +1622,8 @@ select { .platform-select-card.active, .platform-source-card.active { - border-color: #1677ff; - box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.08); + border-color: var(--theme-primary); + box-shadow: 0 0 0 2px var(--theme-primary-shadow); } .platform-select-card span { @@ -1348,8 +1641,8 @@ select { min-height: 32px; padding: 0 12px; border-radius: 6px; - background: #eef6ff; - color: #1677ff; + background: var(--theme-primary-soft); + color: var(--theme-primary); font-weight: 700; } @@ -1669,7 +1962,6 @@ select { background: #f5f7fb; } -.worker-auth-card, .collect-card { width: min(520px, 100%); } @@ -1687,12 +1979,14 @@ select { .worker-order-summary-card { cursor: pointer; - transition: border-color 0.2s ease, box-shadow 0.2s ease; + transition: + border-color 0.2s ease, + box-shadow 0.2s ease; } .worker-order-summary-card.active { - border-color: #1677ff; - box-shadow: 0 0 0 1px #1677ff inset; + border-color: var(--theme-primary); + box-shadow: 0 0 0 1px var(--theme-primary) inset; } .worker-order-summary-card .ant-statistic-title { @@ -2039,7 +2333,6 @@ select { .worker-hall-card-grab-row { flex-direction: column; } - } @media (max-width: 480px) {
使用账号或手机号登录,进入抢单大厅
手机号验证码注册,注册后即可开始接单