refactor: 项目架构重构 - 目录标准化 + 清理冗余
- 目录重命名: backend/wdkj-server/ → server/, frontend/ai-dimension/ → client/ - 删除 20+ 冗余文件(WDKJ 旧脚本、Windows 脚本、过时文档、设计稿) - 更新 package.json 元数据(移除 wdkj 命名) - 完善三级 .gitignore(根 + server + client) - 重写 README.md 和 CHANGELOG.md - 工具脚本移至 scripts/
This commit is contained in:
@@ -0,0 +1,392 @@
|
||||
<template>
|
||||
<view class="login-page">
|
||||
<!-- 背景装饰 -->
|
||||
<view class="bg-orb orb-1"></view>
|
||||
<view class="bg-orb orb-2"></view>
|
||||
<view class="bg-orb orb-3"></view>
|
||||
|
||||
<view class="login-container">
|
||||
<!-- Logo -->
|
||||
<view class="logo-wrap">
|
||||
<view class="logo-ring"></view>
|
||||
<text class="logo-text">AI</text>
|
||||
</view>
|
||||
<text class="app-title">宇之然 AI 维度</text>
|
||||
<text class="app-subtitle">从 5 个维度系统理解人工智能</text>
|
||||
|
||||
<!-- Tab 切换 — 两种模式共用 -->
|
||||
<view class="tab-switch">
|
||||
<text class="tab-item" :class="{ active: activeTab === 'login' }" @click="activeTab = 'login'">登录</text>
|
||||
<text class="tab-item" :class="{ active: activeTab === 'register' }" @click="activeTab = 'register'">注册</text>
|
||||
</view>
|
||||
|
||||
<!-- 登录表单 -->
|
||||
<view class="form-card" v-if="activeTab === 'login'">
|
||||
<view class="form-item">
|
||||
<text class="form-label">用户名</text>
|
||||
<input class="form-input" v-model="loginForm.username" placeholder="请输入用户名" />
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="form-label">密码</text>
|
||||
<input class="form-input" v-model="loginForm.password" type="password" placeholder="请输入密码" />
|
||||
</view>
|
||||
<view class="submit-btn" :class="{ loading: loading }" @click="handleLogin">
|
||||
<text>{{ loading ? '登录中...' : '登录' }}</text>
|
||||
</view>
|
||||
<!-- 微信小程序一键登录入口 -->
|
||||
<view class="wx-login-row" v-if="isMiniApp">
|
||||
<view class="wx-login-btn" @click="wechatLogin">
|
||||
<text>微信一键登录</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 注册表单 -->
|
||||
<view class="form-card" v-if="activeTab === 'register'">
|
||||
<view class="form-item">
|
||||
<text class="form-label">用户名</text>
|
||||
<input class="form-input" v-model="registerForm.username" placeholder="3-20 位字符" />
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="form-label">昵称</text>
|
||||
<input class="form-input" v-model="registerForm.nickName" placeholder="显示名称(选填)" />
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="form-label">密码</text>
|
||||
<input class="form-input" v-model="registerForm.password" type="password" placeholder="至少 6 位" />
|
||||
</view>
|
||||
<view class="submit-btn" :class="{ loading: loading }" @click="handleRegister">
|
||||
<text>{{ loading ? '注册中...' : '注册' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部信息 -->
|
||||
<view class="footer-info">
|
||||
<text>© 2026 宇之然 · AI 维度</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { useUserStore } from '@/stores/index'
|
||||
|
||||
// 检测是否为微信小程序环境
|
||||
const isMiniApp = ref(false)
|
||||
const platform = uni.getSystemInfoSync().platform
|
||||
try {
|
||||
const sysInfo = uni.getSystemInfoSync()
|
||||
// 小程序环境:platform 为 ios/android/devtools,且有 brand/version 等字段
|
||||
if (sysInfo && sysInfo.version && sysInfo.platform) {
|
||||
// 有 weixin 特有字段即为小程序
|
||||
isMiniApp.value = true
|
||||
}
|
||||
} catch (e) {
|
||||
// H5 环境
|
||||
}
|
||||
|
||||
const activeTab = ref('login')
|
||||
const loading = ref(false)
|
||||
const userStore = useUserStore()
|
||||
|
||||
// H5 表单
|
||||
const loginForm = ref({ username: '', password: '' })
|
||||
const registerForm = ref({ username: '', password: '', nickName: '' })
|
||||
|
||||
/**
|
||||
* 微信小程序登录
|
||||
*/
|
||||
const wechatLogin = async () => {
|
||||
try {
|
||||
const loginRes = await new Promise((resolve, reject) => {
|
||||
uni.login({
|
||||
success: resolve,
|
||||
fail: reject
|
||||
})
|
||||
})
|
||||
|
||||
if (!loginRes.code) {
|
||||
uni.showToast({ title: '登录失败,请重试', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
await userStore.login(loginRes.code, {})
|
||||
|
||||
uni.showToast({ title: '登录成功', icon: 'success' })
|
||||
setTimeout(() => {
|
||||
uni.switchTab({ url: '/pages/index/index' })
|
||||
}, 1000)
|
||||
} catch (err) {
|
||||
console.error('微信登录失败:', err)
|
||||
uni.showToast({ title: '登录失败,请重试', icon: 'none' })
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* H5 用户名密码登录
|
||||
*/
|
||||
const handleLogin = async () => {
|
||||
if (!loginForm.value.username || !loginForm.value.password) {
|
||||
uni.showToast({ title: '请填写完整信息', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
await userStore.h5Login(loginForm.value.username, loginForm.value.password)
|
||||
uni.showToast({ title: '登录成功', icon: 'success' })
|
||||
setTimeout(() => {
|
||||
uni.switchTab({ url: '/pages/index/index' })
|
||||
}, 1000)
|
||||
} catch (err) {
|
||||
uni.showToast({ title: err.message || '登录失败', icon: 'none' })
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* H5 注册
|
||||
*/
|
||||
const handleRegister = async () => {
|
||||
if (!registerForm.value.username || !registerForm.value.password) {
|
||||
uni.showToast({ title: '请填写完整信息', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (registerForm.value.password.length < 6) {
|
||||
uni.showToast({ title: '密码至少 6 位', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
await userStore.h5Register(
|
||||
registerForm.value.username,
|
||||
registerForm.value.password,
|
||||
registerForm.value.nickName || ''
|
||||
)
|
||||
uni.showToast({ title: '注册成功', icon: 'success' })
|
||||
setTimeout(() => {
|
||||
uni.switchTab({ url: '/pages/index/index' })
|
||||
}, 1000)
|
||||
} catch (err) {
|
||||
uni.showToast({ title: err.message || '注册失败', icon: 'none' })
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.login-page {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--bg-primary);
|
||||
|
||||
// 背景装饰光球
|
||||
.bg-orb {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
filter: blur(60px);
|
||||
opacity: 0.3;
|
||||
pointer-events: none;
|
||||
}
|
||||
.orb-1 {
|
||||
width: 200px; height: 200px;
|
||||
top: -50px; left: -50px;
|
||||
background: var(--dim1-color);
|
||||
}
|
||||
.orb-2 {
|
||||
width: 160px; height: 160px;
|
||||
top: 30%; right: -40px;
|
||||
background: var(--dim3-color);
|
||||
}
|
||||
.orb-3 {
|
||||
width: 180px; height: 180px;
|
||||
bottom: -60px; left: 30%;
|
||||
background: var(--dim5-color);
|
||||
}
|
||||
|
||||
.login-container {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
max-width: 360px;
|
||||
padding: 0 32px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
// Logo
|
||||
.logo-wrap {
|
||||
position: relative;
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.logo-ring {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: 18px;
|
||||
background: linear-gradient(135deg, var(--dim1-color), var(--dim3-color));
|
||||
box-shadow: 0 8px 32px rgba(124, 77, 255, 0.2);
|
||||
}
|
||||
.logo-text {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.app-title {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
letter-spacing: 1px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.app-subtitle {
|
||||
font-size: 13px;
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
// Tab 切换
|
||||
.tab-switch {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
border-bottom: 1px solid var(--glass-border);
|
||||
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 10px 0;
|
||||
color: var(--text-secondary);
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
border-bottom: 2px solid transparent;
|
||||
transition: all 0.3s;
|
||||
|
||||
&.active {
|
||||
color: var(--color-brand);
|
||||
border-bottom-color: var(--color-brand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表单卡片
|
||||
.form-card {
|
||||
width: 100%;
|
||||
background: var(--glass-bg);
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: 16px;
|
||||
padding: 24px 20px;
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 16px;
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: 6px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.form-input {
|
||||
width: 100%;
|
||||
height: 44px;
|
||||
background: var(--bg-secondary);
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: 10px;
|
||||
padding: 0 14px;
|
||||
color: var(--text-primary);
|
||||
font-size: 14px;
|
||||
box-sizing: border-box;
|
||||
outline: none;
|
||||
|
||||
&::placeholder {
|
||||
color: var(--text-disabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 提交按钮
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
height: 46px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: linear-gradient(135deg, var(--color-brand), var(--dim3-color));
|
||||
color: white;
|
||||
border-radius: 10px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
margin-top: 8px;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 4px 16px rgba(124, 77, 255, 0.25);
|
||||
transition: opacity 0.3s;
|
||||
|
||||
&:active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
&.loading {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
// 微信一键登录
|
||||
.wx-login-row {
|
||||
margin-top: 16px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid var(--glass-border);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.wx-login-btn {
|
||||
padding: 10px 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
background: linear-gradient(135deg, #07c160, #06ad56);
|
||||
color: white;
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 4px 16px rgba(7, 193, 96, 0.3);
|
||||
|
||||
&:active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 底部信息
|
||||
.footer-info {
|
||||
margin-top: 40px;
|
||||
font-size: 11px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user