222
This commit is contained in:
parent
0fd7cf4c72
commit
63fb522484
|
|
@ -0,0 +1,27 @@
|
||||||
|
# 实现邀请码升级功能
|
||||||
|
|
||||||
|
## 1. 修改 Waitlist.vue 组件
|
||||||
|
- 在现有界面中添加邀请码输入框和提交按钮
|
||||||
|
- 设计输入框样式与现有界面风格保持一致
|
||||||
|
- 添加表单验证逻辑
|
||||||
|
|
||||||
|
## 2. 引入必要的模块和方法
|
||||||
|
- 引入 user 模块的 upgrade 方法
|
||||||
|
- 引入 auth store 的 updateUserInfo 方法
|
||||||
|
- 引入 ElMessage 用于显示操作结果
|
||||||
|
|
||||||
|
## 3. 实现提交逻辑
|
||||||
|
1. 用户输入邀请码并点击提交按钮
|
||||||
|
2. 调用 `/views/user/index.js` 中的 `upgrade` 方法
|
||||||
|
3. 成功后调用 `/stores/auth.js` 中的 `updateUserInfo` 方法刷新用户信息
|
||||||
|
4. 刷新成功后返回首页
|
||||||
|
|
||||||
|
## 4. 添加错误处理
|
||||||
|
- 邀请码验证失败时显示错误信息
|
||||||
|
- 网络请求失败时显示错误提示
|
||||||
|
- 确保用户体验流畅
|
||||||
|
|
||||||
|
## 5. 界面优化
|
||||||
|
- 输入框添加合适的占位符
|
||||||
|
- 按钮状态管理(加载中、禁用等)
|
||||||
|
- 保持响应式设计,适配不同屏幕尺寸
|
||||||
|
|
@ -4,6 +4,9 @@ import { useRouter, useRoute } from 'vue-router'
|
||||||
import MainLayout from '@/components/layout/MainLayout.vue'
|
import MainLayout from '@/components/layout/MainLayout.vue'
|
||||||
import AppHeader from '@/components/layout/AppHeader.vue'
|
import AppHeader from '@/components/layout/AppHeader.vue'
|
||||||
import AppSidebar from '@/components/layout/AppSidebar.vue'
|
import AppSidebar from '@/components/layout/AppSidebar.vue'
|
||||||
|
import { useAuthStore } from '@/stores/auth';
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
authStore.updateUserInfo()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
// 判断当前是否为登录页面
|
// 判断当前是否为登录页面
|
||||||
const isLoginPage = computed(() => route.path === '/login')
|
const isLoginPage = computed(() => route.path === '/login')
|
||||||
|
|
|
||||||
|
|
@ -173,6 +173,14 @@ router.beforeEach(async (to, from, next) => {
|
||||||
// window.localStorage.setItem('token','123')
|
// window.localStorage.setItem('token','123')
|
||||||
// return next()
|
// return next()
|
||||||
// }
|
// }
|
||||||
|
if(to.path=='/login'||to.path=='/login/phone'||to.path=='/register'||to.path=='/forgot-password'){
|
||||||
|
const token = localStorage.getItem('token')
|
||||||
|
// 如果有 token,跳转到首页
|
||||||
|
if (token) {
|
||||||
|
next('/czhome')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
const newto = freeRoutes.find(route => route.path == to.path)
|
const newto = freeRoutes.find(route => route.path == to.path)
|
||||||
if (newto?.meta?.requiresAuth) {
|
if (newto?.meta?.requiresAuth) {
|
||||||
const token = localStorage.getItem('token')
|
const token = localStorage.getItem('token')
|
||||||
|
|
@ -184,8 +192,10 @@ router.beforeEach(async (to, from, next) => {
|
||||||
}
|
}
|
||||||
// 检查是否需要添加动态路由
|
// 检查是否需要添加动态路由
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
const user_role = authStore.user?.user_role;
|
// const info = await authStore.updateUserInfo();
|
||||||
if(user_role != '0' && router.getRoutes().length == routes.length) {
|
// console.log(info,'infoinfo');
|
||||||
|
const user_role = authStore.user?.userRole;
|
||||||
|
if((user_role == 1||user_role == 2) && router.getRoutes().length == routes.length) {
|
||||||
// 添加动态路由
|
// 添加动态路由
|
||||||
addDynamicRoutes();
|
addDynamicRoutes();
|
||||||
if(isDynamicRoute(to.path)) {
|
if(isDynamicRoute(to.path)) {
|
||||||
|
|
@ -195,7 +205,7 @@ router.beforeEach(async (to, from, next) => {
|
||||||
}, 20);
|
}, 20);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}else if(user_role == '0'){
|
}else if(user_role == 0){
|
||||||
// 恢复默认路由
|
// 恢复默认路由
|
||||||
removeDynamicRoutes()
|
removeDynamicRoutes()
|
||||||
router.addRoute(
|
router.addRoute(
|
||||||
|
|
|
||||||
|
|
@ -57,9 +57,11 @@ export const useAuthStore = defineStore('auth', () => {
|
||||||
//登录成功方法
|
//登录成功方法
|
||||||
const loginSuccess = (data,callback=null) => {
|
const loginSuccess = (data,callback=null) => {
|
||||||
token.value = data.accessToken
|
token.value = data.accessToken
|
||||||
user.value = data
|
// user.value = data
|
||||||
localStorage.setItem('token', token.value);
|
localStorage.setItem('token', token.value);
|
||||||
callback&&callback(data);
|
updateUserInfo().then(res => {
|
||||||
|
callback&&callback(data);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
// 登出方法
|
// 登出方法
|
||||||
const logout = async (callback) => {
|
const logout = async (callback) => {
|
||||||
|
|
@ -79,8 +81,28 @@ export const useAuthStore = defineStore('auth', () => {
|
||||||
window?.Redirectlogin()
|
window?.Redirectlogin()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//更新用户信息方法
|
||||||
|
const updateUserInfo = async (data) => {
|
||||||
|
if(!token.value){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const res = await requestUtils.common(clientApi.default.USER_INFO, data)
|
||||||
|
if(res.code === 0){
|
||||||
|
let data = res.data;
|
||||||
|
// 更新成功,保存用户信息
|
||||||
|
user.value = data
|
||||||
|
resolve(res)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('更新用户信息失败:', error)
|
||||||
|
reject(error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
|
updateUserInfo,
|
||||||
user,
|
user,
|
||||||
token,
|
token,
|
||||||
login,
|
login,
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,6 @@ const goToRegister = () => {
|
||||||
const goToPhoneLogin = () => {
|
const goToPhoneLogin = () => {
|
||||||
router.push('/login/phone')
|
router.push('/login/phone')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 页面挂载时初始化认证状态
|
// 页面挂载时初始化认证状态
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -480,7 +480,7 @@ const handleCreatePromptCard = (index,params) => {
|
||||||
status:'loading',
|
status:'loading',
|
||||||
imgyt:imgyt||'',
|
imgyt:imgyt||'',
|
||||||
type:'image',
|
type:'image',
|
||||||
inspirationImage:cardData.inspirationImage||'',
|
// inspirationImage:cardData.inspirationImage||'',
|
||||||
},index);
|
},index);
|
||||||
console.log(newCard,'newCardnewCard');
|
console.log(newCard,'newCardnewCard');
|
||||||
// 添加到卡片数组
|
// 添加到卡片数组
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,24 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="waitlist-title">{{ t('waitlist.title') }}</div>
|
<div class="waitlist-title">{{ t('waitlist.title') }}</div>
|
||||||
<div class="waitlist-description">{{ t('waitlist.description') }}</div>
|
<div class="waitlist-description">{{ t('waitlist.description') }}</div>
|
||||||
|
|
||||||
|
<!-- 邀请码输入区域 -->
|
||||||
|
<div class="invite-code-section">
|
||||||
|
<el-input
|
||||||
|
v-model="inviteCode"
|
||||||
|
placeholder="请输入邀请码"
|
||||||
|
class="invite-code-input"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
class="primary-button"
|
||||||
|
@click="submitInviteCode"
|
||||||
|
:loading="submitting"
|
||||||
|
>
|
||||||
|
提交邀请码
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<button class="primary-button" @click="goHome">
|
<button class="primary-button" @click="goHome">
|
||||||
{{ t('waitlist.goHome') }}
|
{{ t('waitlist.goHome') }}
|
||||||
|
|
@ -26,20 +44,60 @@
|
||||||
<script>
|
<script>
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { UserController } from './user/index.js'
|
||||||
|
import { useAuthStore } from '@/stores/auth.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Waitlist',
|
name: 'Waitlist',
|
||||||
setup() {
|
setup() {
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const authStore = useAuthStore()
|
||||||
|
const userController = new UserController()
|
||||||
|
|
||||||
|
const inviteCode = ref('')
|
||||||
|
const submitting = ref(false)
|
||||||
|
|
||||||
const goHome = () => {
|
const goHome = () => {
|
||||||
router.push('/')
|
router.push('/')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 提交邀请码升级
|
||||||
|
const submitInviteCode = async () => {
|
||||||
|
if (!inviteCode.value.trim()) {
|
||||||
|
ElMessage.warning('请输入邀请码')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
submitting.value = true
|
||||||
|
try {
|
||||||
|
// 调用upgrade方法
|
||||||
|
const upgradeRes = await userController.upgrade({ inviteCode: inviteCode.value })
|
||||||
|
if (upgradeRes.code === 0) {
|
||||||
|
// 升级成功,刷新用户信息
|
||||||
|
await authStore.updateUserInfo()
|
||||||
|
ElMessage.success('升级成功')
|
||||||
|
// 返回首页
|
||||||
|
goHome()
|
||||||
|
} else {
|
||||||
|
ElMessage.error(upgradeRes.message || '升级失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('升级失败:', error)
|
||||||
|
ElMessage.error(error.message || '升级失败,请稍后重试')
|
||||||
|
} finally {
|
||||||
|
submitting.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
t,
|
t,
|
||||||
goHome
|
goHome,
|
||||||
|
inviteCode,
|
||||||
|
submitting,
|
||||||
|
submitInviteCode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -150,6 +208,48 @@ export default {
|
||||||
left: 10%;
|
left: 10%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 邀请码输入区域样式 */
|
||||||
|
.invite-code-section {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invite-code-input {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 400px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invite-code-input :deep(.el-input__wrapper) {
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid rgba(107, 70, 193, 0.3);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invite-code-input :deep(.el-input__wrapper:hover) {
|
||||||
|
border-color: rgba(107, 70, 193, 0.6);
|
||||||
|
box-shadow: 0 0 0 2px rgba(107, 70, 193, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.invite-code-input :deep(.el-input__wrapper.is-focus) {
|
||||||
|
border-color: #6B46C1;
|
||||||
|
box-shadow: 0 0 0 2px rgba(107, 70, 193, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 按钮加载状态样式 */
|
||||||
|
.primary-button:disabled {
|
||||||
|
opacity: 0.7;
|
||||||
|
cursor: not-allowed;
|
||||||
|
transform: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary-button:disabled:hover {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.waitlist-title {
|
.waitlist-title {
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
|
|
@ -167,6 +267,10 @@ export default {
|
||||||
.primary-button {
|
.primary-button {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.invite-code-input {
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 480px) {
|
@media (max-width: 480px) {
|
||||||
|
|
@ -193,5 +297,9 @@ export default {
|
||||||
width: 100px;
|
width: 100px;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.invite-code-input {
|
||||||
|
max-width: 250px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -53,4 +53,41 @@ export class UserController {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
// 返回用户信息
|
||||||
|
async getUserInfo() {
|
||||||
|
return await requestUtils.common(clientApi.default.USER_INFO);
|
||||||
|
/*
|
||||||
|
返回示例:
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"id": 9007199254740991,
|
||||||
|
"nickname": "string",
|
||||||
|
"email": "string",
|
||||||
|
"avatarUrl": "string",
|
||||||
|
"phone": "string",
|
||||||
|
"lastActive": "2025-12-19T09:45:20.801Z",
|
||||||
|
"status": "string",
|
||||||
|
"userRole": 1073741824,
|
||||||
|
"inviteCode": "string",
|
||||||
|
"otherInfo": {
|
||||||
|
"additionalProp1": {},
|
||||||
|
"additionalProp2": {},
|
||||||
|
"additionalProp3": {}
|
||||||
|
},
|
||||||
|
"createdAt": "2025-12-19T09:45:20.801Z",
|
||||||
|
"updatedAt": "2025-12-19T09:45:20.801Z"
|
||||||
|
},
|
||||||
|
"message": "操作成功"
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
// 候补会员使用邀请码升级为正式会员
|
||||||
|
async upgrade(data) {
|
||||||
|
let parmas = {
|
||||||
|
inviteCode:data.inviteCode,
|
||||||
|
}
|
||||||
|
return await requestUtils.common(clientApi.default.UPGRADE,parmas);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,5 +4,7 @@ const login = {
|
||||||
INVITE_CODES:{url:'/api-base/user/invite/codes',method:'GET'},// 返回当前用户的邀请码列表及使用状态
|
INVITE_CODES:{url:'/api-base/user/invite/codes',method:'GET'},// 返回当前用户的邀请码列表及使用状态
|
||||||
INVITE_RECORDS:{url:'/api-base/user/invite/records',method:'GET'},// 返回邀请的用户列表,包含奖励明细
|
INVITE_RECORDS:{url:'/api-base/user/invite/records',method:'GET'},// 返回邀请的用户列表,包含奖励明细
|
||||||
combined:{url:'/api-base/prompt/active',method:'GET'},// 返回动态提示词
|
combined:{url:'/api-base/prompt/active',method:'GET'},// 返回动态提示词
|
||||||
|
UPGRADE:{url:'/api-base/user/upgrade',method:'POST'},// 候补会员使用邀请码升级为正式会员
|
||||||
|
USER_INFO:{url:'/api-base/user/info',method:'GET',isLoading:true},// 返回用户信息
|
||||||
}
|
}
|
||||||
export default login;
|
export default login;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue