feat: 解析mmkv数据,优化账号选择体验

This commit is contained in:
H3CoF6
2026-03-16 07:30:08 +08:00
parent 1f676254a9
commit 579b63b036
5 changed files with 264 additions and 39 deletions

View File

@@ -1705,7 +1705,7 @@
.wxid-dialog-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
padding: 14px 16px;
border-radius: 10px;
@@ -1743,6 +1743,66 @@
justify-content: flex-end;
}
.wxid-profile-row {
display: flex;
align-items: center;
gap: 12px;
.wxid-avatar {
width: 38px;
height: 38px;
border-radius: 8px;
object-fit: cover;
}
.wxid-avatar-fallback {
width: 38px;
height: 38px;
border-radius: 8px;
background: var(--bg-tertiary);
display: flex;
align-items: center;
justify-content: center;
color: var(--text-tertiary);
}
.wxid-info-col {
display: flex;
flex-direction: column;
gap: 2px;
}
}
.wxid-profile-mini {
display: flex;
align-items: center;
gap: 10px;
.wxid-avatar {
width: 26px;
height: 26px;
border-radius: 6px;
object-fit: cover;
}
.wxid-avatar-fallback {
width: 26px;
height: 26px;
border-radius: 6px;
background: var(--bg-tertiary);
display: flex;
align-items: center;
justify-content: center;
color: var(--text-tertiary);
}
.wxid-info-col {
display: flex;
flex-direction: column;
align-items: flex-start;
}
}
// 通知过滤双列表容器
.notification-filter-container {
display: grid;

View File

@@ -10,7 +10,7 @@ import {
Eye, EyeOff, FolderSearch, FolderOpen, Search, Copy,
RotateCcw, Trash2, Plug, Check, Sun, Moon, Monitor,
Palette, Database, HardDrive, Info, RefreshCw, ChevronDown, Download, Mic,
ShieldCheck, Fingerprint, Lock, KeyRound, Bell, Globe, BarChart2, X
ShieldCheck, Fingerprint, Lock, KeyRound, Bell, Globe, BarChart2, X, UserRound
} from 'lucide-react'
import { Avatar } from '../components/Avatar'
import './SettingsPage.scss'
@@ -34,6 +34,8 @@ const tabs: { id: SettingsTab; label: string; icon: React.ElementType }[] = [
interface WxidOption {
wxid: string
modifiedTime: number
nickname?: string
avatarUrl?: string
}
interface SettingsPageProps {
@@ -2132,14 +2134,24 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
</div>
<div className="wxid-dialog-list">
{wxidOptions.map((opt) => (
<div
key={opt.wxid}
className={`wxid-dialog-item ${opt.wxid === wxid ? 'active' : ''}`}
onClick={() => handleSelectWxid(opt.wxid)}
>
<span className="wxid-id">{opt.wxid}</span>
<span className="wxid-date"> {new Date(opt.modifiedTime).toLocaleString()}</span>
</div>
<div
key={opt.wxid}
className={`wxid-dialog-item ${opt.wxid === wxid ? 'active' : ''}`}
onClick={() => handleSelectWxid(opt.wxid)}
>
<div className="wxid-profile-row">
{opt.avatarUrl ? (
<img src={opt.avatarUrl} alt="avatar" className="wxid-avatar" />
) : (
<div className="wxid-avatar-fallback"><UserRound size={18}/></div>
)}
<div className="wxid-info-col">
<span className="wxid-id">{opt.nickname || opt.wxid}</span>
{opt.nickname && <span className="wxid-date">{opt.wxid}</span>}
</div>
</div>
<span className="wxid-date" style={{marginLeft: 'auto'}}> {new Date(opt.modifiedTime).toLocaleString()}</span>
</div>
))}
</div>
<div className="wxid-dialog-footer">

View File

@@ -488,6 +488,48 @@
white-space: nowrap;
}
.wxid-profile {
display: flex;
align-items: center;
gap: 10px;
}
.wxid-avatar {
width: 32px;
height: 32px;
border-radius: 6px;
object-fit: cover;
}
.wxid-avatar-fallback {
width: 32px;
height: 32px;
border-radius: 6px;
background: var(--bg-tertiary);
display: flex;
align-items: center;
justify-content: center;
color: var(--text-tertiary);
}
.wxid-info {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 2px;
}
.wxid-nickname {
font-weight: 600;
font-size: 13px;
color: var(--text-primary);
}
.wxid-sub {
font-size: 11px;
color: var(--text-tertiary);
}
.field-with-toggle {
position: relative;
}

View File

@@ -47,7 +47,12 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
const [imageAesKey, setImageAesKey] = useState('')
const [cachePath, setCachePath] = useState('')
const [wxid, setWxid] = useState('')
const [wxidOptions, setWxidOptions] = useState<Array<{ wxid: string; modifiedTime: number }>>([])
const [wxidOptions, setWxidOptions] = useState<Array<{
avatarUrl?: string;
nickname?: string;
wxid: string;
modifiedTime: number
}>>([])
const [showWxidSelect, setShowWxidSelect] = useState(false)
const wxidSelectRef = useRef<HTMLDivElement>(null)
const [error, setError] = useState('')
@@ -688,22 +693,32 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
onChange={(e) => setWxid(e.target.value)}
/>
{showWxidSelect && wxidOptions.length > 0 && (
<div className="wxid-dropdown">
{wxidOptions.map((opt) => (
<button
key={opt.wxid}
type="button"
className={`wxid-option ${opt.wxid === wxid ? 'active' : ''}`}
onClick={() => {
setWxid(opt.wxid)
setShowWxidSelect(false)
}}
>
<span className="wxid-name">{opt.wxid}</span>
<span className="wxid-time">{formatModifiedTime(opt.modifiedTime)}</span>
</button>
))}
</div>
<div className="wxid-dropdown">
{wxidOptions.map((opt) => (
<button
key={opt.wxid}
type="button"
className={`wxid-option ${opt.wxid === wxid ? 'active' : ''}`}
onClick={() => {
setWxid(opt.wxid)
setShowWxidSelect(false)
}}
>
<div className="wxid-profile">
{opt.avatarUrl ? (
<img src={opt.avatarUrl} alt="avatar" className="wxid-avatar" />
) : (
<div className="wxid-avatar-fallback"><UserRound size={14}/></div>
)}
<div className="wxid-info">
<span className="wxid-nickname">{opt.nickname || opt.wxid}</span>
{opt.nickname && <span className="wxid-sub">{opt.wxid}</span>}
</div>
</div>
<span className="wxid-time">{formatModifiedTime(opt.modifiedTime)}</span>
</button>
))}
</div>
)}
</div>