添加登录和后端校验

完成后端设计(未在本仓库体现),通过安全的手段完成了登录鉴权
This commit is contained in:
2026-08-06 16:27:36 +08:00
commit b19a56003f
286 changed files with 51650 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
export default definePageConfig({
navigationStyle: 'custom',
navigationBarTitleText: '用户数据库'
})
+204
View File
@@ -0,0 +1,204 @@
.udb-page {
padding: 0 24px 40px;
min-height: 100vh;
}
/* 锁屏验证 */
.udb-lock-card {
display: flex;
flex-direction: column;
align-items: center;
padding: 60px 40px;
text-align: center;
}
.udb-lock-icon {
font-size: 80px;
margin-bottom: 24px;
}
.udb-lock-title {
font-size: 36px;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 12px;
display: block;
}
.udb-lock-desc {
font-size: 26px;
color: var(--text-secondary);
margin-bottom: 32px;
display: block;
}
.udb-password-input {
width: 100%;
height: 80px;
background: var(--bg-input);
border: 2px solid var(--line-star);
border-radius: 16px;
padding: 0 24px;
font-size: 30px;
color: var(--text-primary);
text-align: center;
margin-bottom: 24px;
box-sizing: border-box;
}
.udb-error {
font-size: 24px;
color: #e64340;
margin-bottom: 20px;
display: block;
}
.udb-btn {
width: 100%;
padding: 20px 0;
font-size: 30px;
}
/* 工具栏 */
.udb-toolbar {
margin: 20px 0;
display: flex;
justify-content: flex-end;
}
.udb-add-btn {
padding: 14px 28px;
font-size: 26px;
}
/* 数据表格 */
.udb-table {
background: var(--bg-card);
border: var(--line-card);
border-radius: 24px;
overflow: hidden;
}
.udb-row {
display: flex;
align-items: center;
padding: 20px 16px;
border-bottom: 1px solid rgba(0, 0, 0, 0.04);
}
.udb-row:last-child {
border-bottom: none;
}
.udb-header {
background: var(--bg-input);
padding: 16px;
}
.udb-header .udb-col {
font-weight: 700;
font-size: 24px;
color: var(--text-primary);
}
.udb-col {
font-size: 24px;
color: var(--text-secondary);
flex-shrink: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding: 0 6px;
}
.col-nick {
flex: 0 0 22%;
}
.col-id {
flex: 0 0 36%;
}
.col-stats {
flex: 0 0 18%;
text-align: center;
}
.col-action {
flex: 1;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
}
.udb-row.active {
background: rgba(91, 140, 255, 0.06);
}
.udb-link {
padding: 6px 14px;
border-radius: 8px;
font-size: 22px;
color: var(--accent-blue);
background: rgba(91, 140, 255, 0.08);
}
.udb-danger {
color: #e64340;
background: rgba(230, 67, 64, 0.08);
}
.udb-current {
font-size: 22px;
color: var(--accent-blue);
font-weight: 600;
}
.udb-empty {
padding: 40px;
text-align: center;
color: var(--text-secondary);
font-size: 28px;
}
/* 弹窗 */
.udb-add-card {
padding: 48px 36px;
width: 80%;
}
.udb-add-title {
font-size: 32px;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 24px;
display: block;
text-align: center;
}
.udb-add-input {
width: 100%;
height: 80px;
background: var(--bg-input);
border: 2px solid var(--line-star);
border-radius: 16px;
padding: 0 24px;
font-size: 28px;
color: var(--text-primary);
margin-bottom: 32px;
box-sizing: border-box;
}
.udb-add-actions {
display: flex;
align-items: center;
gap: 20px;
}
.udb-add-actions .btn-outline,
.udb-add-actions .btn-gradient {
flex: 1;
padding: 18px 0;
text-align: center;
}
+187
View File
@@ -0,0 +1,187 @@
import { View, Text, Input, Button } from '@tarojs/components'
import Taro from '@tarojs/taro'
import { useState, useEffect } from 'react'
import './index.scss'
import {
listAllUsers,
switchUser,
deleteUser,
createUser,
getUserInfo,
verifyAdminPassword
} from '../../utils/store'
import { useThemeContext } from '../../context/ThemeContext'
import { useSafeArea } from '../../hooks/useSafeArea'
import { useStatusBar } from '../../hooks/useStatusBar'
export default function UserDatabasePage() {
const { theme, resolvedTheme } = useThemeContext()
const safe = useSafeArea()
useStatusBar(resolvedTheme)
const [isUnlocked, setIsUnlocked] = useState(false)
const [password, setPassword] = useState('')
const [pwdError, setPwdError] = useState(false)
const [users, setUsers] = useState<any[]>([])
const [showAdd, setShowAdd] = useState(false)
const [newNick, setNewNick] = useState('')
const refresh = () => setUsers(listAllUsers())
useEffect(() => {
refresh()
}, [])
const handleUnlock = () => {
if (verifyAdminPassword(password)) {
setIsUnlocked(true)
setPwdError(false)
refresh()
} else {
setPwdError(true)
}
}
const handleSwitch = (openid: string) => {
if (switchUser(openid)) {
Taro.showToast({ title: '切换成功', icon: 'success' })
refresh()
} else {
Taro.showToast({ title: '切换失败', icon: 'none' })
}
}
const handleDelete = (openid: string) => {
Taro.showModal({
title: '确认删除',
content: '删除后将清空该用户所有数据,无法恢复',
confirmColor: '#e64340',
success: (res) => {
if (res.confirm) {
deleteUser(openid)
refresh()
Taro.showToast({ title: '已删除', icon: 'success' })
}
}
})
}
const handleCreate = () => {
if (!newNick.trim()) {
Taro.showToast({ title: '请输入昵称', icon: 'none' })
return
}
createUser(newNick.trim())
setShowAdd(false)
setNewNick('')
refresh()
Taro.showToast({ title: '创建成功', icon: 'success' })
}
const activeOpenid = getUserInfo()?.openid || ''
if (!isUnlocked) {
return (
<View className={`theme-${resolvedTheme}`}>
<View className='udb-page'>
<View className='udb-lock-card dashed-card mt-20'>
<View className='star-badge' />
<Text className='udb-lock-icon'>🔐</Text>
<Text className='udb-lock-title'></Text>
<Text className='udb-lock-desc'>访</Text>
<Input
className='udb-password-input'
type='text'
password
placeholder='输入密码'
value={password}
onInput={(e: any) => setPassword(e.detail.value)}
/>
{pwdError && (
<Text className='udb-error'></Text>
)}
<View className='btn-gradient udb-btn' onTap={handleUnlock}>
<Text></Text>
</View>
</View>
</View>
</View>
)
}
return (
<View className={`theme-${resolvedTheme}`}>
<View className='udb-page'>
<View className='page-header dashed-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='star-badge' />
<Text className='page-title'></Text>
</View>
<View className='udb-toolbar'>
<View className='btn-gradient udb-add-btn' onTap={() => setShowAdd(true)}>
<Text>+ </Text>
</View>
</View>
<View className='udb-table'>
<View className='udb-row udb-header'>
<Text className='udb-col col-nick'></Text>
<Text className='udb-col col-id'>ID</Text>
<Text className='udb-col col-stats'>/</Text>
<Text className='udb-col col-action'></Text>
</View>
{users.map((u) => (
<View key={u.openid} className={`udb-row ${u.openid === activeOpenid ? 'active' : ''}`}>
<Text className='udb-col col-nick'>{u.nickName}</Text>
<Text className='udb-col col-id'>{u.openid}</Text>
<Text className='udb-col col-stats'>{u.designCount} / {u.orderCount}</Text>
<View className='udb-col col-action'>
{u.openid !== activeOpenid && (
<View className='udb-link' onTap={() => handleSwitch(u.openid)}>
<Text></Text>
</View>
)}
{u.openid === activeOpenid && (
<Text className='udb-current'></Text>
)}
<View className='udb-link udb-danger' onTap={() => handleDelete(u.openid)}>
<Text></Text>
</View>
</View>
</View>
))}
{users.length === 0 && (
<View className='udb-empty'>
<Text></Text>
</View>
)}
</View>
{/* 新建账号弹窗 */}
{showAdd && (
<View className='modal-overlay'>
<View className='udb-add-card dashed-card'>
<View className='star-badge' />
<Text className='udb-add-title'></Text>
<Input
className='udb-add-input'
type='text'
placeholder='请输入昵称'
value={newNick}
onInput={(e: any) => setNewNick(e.detail.value)}
/>
<View className='udb-add-actions'>
<View className='btn-outline' onTap={() => setShowAdd(false)}>
<Text></Text>
</View>
<View className='btn-gradient' onTap={handleCreate}>
<Text></Text>
</View>
</View>
</View>
</View>
)}
</View>
</View>
)
}