feat: 用户登录注册, 工具收藏

This commit is contained in:
osiris
2024-02-29 18:07:26 +08:00
parent 7456b9a35f
commit e2676f9ec8
14 changed files with 872 additions and 57 deletions
+13 -3
View File
@@ -5,11 +5,13 @@ import type {
ToolsReqData,
ToolsResponseData,
ToolCateResponseData,
ToolRecommendResponseData
ToolRecommendResponseData,
ToolCollectResponseData,
CollectReqData,
GetToolCollectResponseData
} from './type'
//项目用户相关的请求地址
enum API {
//获取tools
GET_TOOLS = '/tools',
@@ -17,6 +19,10 @@ enum API {
GET_TOOL_CATES = '/tool/cates',
//获取推荐
GET_TOOL_RECOMMEND = '/tool/recommends',
//收藏工具
COLLECT = '/tool/collects',
//我的收藏
GET_TOOL_COLLECTS = '/get/tool/collects',
}
//获取tools
export const getTools = (data: ToolsReqData) => request.get<any, ToolsResponseData>(API.GET_TOOLS, {
@@ -25,4 +31,8 @@ export const getTools = (data: ToolsReqData) => request.get<any, ToolsResponseDa
//获取tool cate
export const getToolCate = () => request.get<any, ToolCateResponseData>(API.GET_TOOL_CATES)
//获取推荐
export const getToolRecommend = () => request.get<any, ToolRecommendResponseData>(API.GET_TOOL_RECOMMEND)
export const getToolRecommend = () => request.get<any, ToolRecommendResponseData>(API.GET_TOOL_RECOMMEND)
//收藏工具
export const toolCollect = (data: CollectReqData) => request.post<any, ToolCollectResponseData>(API.COLLECT + '/' + data.toolId)
//我的收藏
export const getToolCollect = () => request.get<any, GetToolCollectResponseData>(API.GET_TOOL_COLLECTS)
+14 -1
View File
@@ -2,7 +2,8 @@ import { ResponseData } from "../common"
export interface ToolsReqData {
cateId: number,
title: string
title: string,
route: string,
}
//tools
@@ -26,6 +27,10 @@ export interface ToolCate {
list: ToolsInfo[]
}
export interface CollectReqData {
toolId: number
}
//tools list response
export interface ToolsResponseData extends ResponseData {
data: ToolsInfo[]
@@ -41,4 +46,12 @@ export interface ToolRecommendResponseData extends ResponseData {
data: ToolsInfo[]
}
//tools collect response
export interface ToolCollectResponseData extends ResponseData {
}
//get collect response
export interface GetToolCollectResponseData extends ResponseData {
}
+53
View File
@@ -0,0 +1,53 @@
import request from '@/utils/request'
import type {
LoginReqData,
LoginResponseData,
LogoutResponseData,
RegisterReqData,
RegisterResponseData,
SendCodeEmailResponseData,
sendCodeEmailReq,
UserInfoResponseData,
ForgetReqData,
ForgetResponseData
} from './type'
//项目用户相关的请求地址
enum API {
//login
LOGIN = '/login',
//logout
LOGOUT = '/logout',
//register
REGISTER = '/register',
//forget
FORGET = '/forget/password',
//注册 - 发送邮箱验证码
SEND_CODE_EMAIL = '/send/register/code',
//忘记密码 - 发送邮箱验证码
SEND_FORGET_CODE_EMAIL = '/send/forget/password/code',
//获取用户信息
USER_INFO = '/user/info'
}
//login
export const login = (data: LoginReqData) => request.post<any, LoginResponseData>(API.LOGIN, data)
//logout
export const logout = () => request.post<any, LogoutResponseData>(API.LOGOUT)
//register
export const register = (data: RegisterReqData) => request.post<any, RegisterResponseData>(API.REGISTER, data)
//forget
export const forget = (data: ForgetReqData) => request.post<any, ForgetResponseData>(API.FORGET, data)
//register - send code
export const sendCodeEmail = (data: sendCodeEmailReq) => request.post<any, SendCodeEmailResponseData>(API.SEND_CODE_EMAIL, data)
//forget - send code
export const sendForgetCodeEmail = (data: sendCodeEmailReq) => request.post<any, SendCodeEmailResponseData>(API.SEND_FORGET_CODE_EMAIL, data)
//获取用户信息
export const userInfo = () => request.get<any, UserInfoResponseData>(API.USER_INFO)
+49
View File
@@ -0,0 +1,49 @@
import { ResponseData } from "../common"
export interface LoginReqData {
email: string,
password: string
}
export interface RegisterReqData {
email: string,
code: string,
password: string,
password_confirmation: string
}
export interface ForgetReqData {
email: string,
code: string,
password: string,
password_confirmation: string
}
export interface sendCodeEmailReq {
email: string
}
export interface LoginResponseData extends ResponseData {
}
export interface LogoutResponseData extends ResponseData {
}
export interface RegisterResponseData extends ResponseData {
}
export interface ForgetResponseData extends ResponseData {
}
export interface SendCodeEmailResponseData extends ResponseData {
}
export interface UserInfoResponseData extends ResponseData {
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

+1 -1
View File
@@ -15,7 +15,7 @@
<div class="flex flex-col mt-3 flex-1">
<div class="bg-white rounded-md p-5">
<br>
<p>本项目是一个开源工具站</p>
<p>本项目是一个开源工具站, 求星星</p>
<br>
<p>本项目开源地址<el-link href="https://github.com/taoran1401/tools-web">https://github.com/taoran1401/tools-web</el-link></p>
<br>
+30 -7
View File
@@ -1,22 +1,45 @@
<script setup lang="ts">
import { onMounted } from 'vue';
import { onMounted,reactive } from 'vue';
import { RouterLink } from "vue-router"
import { Star } from '@element-plus/icons-vue'
import { useToolsStore } from '@/store/modules/tools'
import { useUserStore } from '@/store/modules/user'
import { ElMessage } from 'element-plus'
import { useRoute } from "vue-router"
//store
const toolsStore = useToolsStore()
const userStore = useUserStore()
const route = useRoute()
const getToolsCate = async () => {
try {
await toolsStore.getToolCate()
} catch (error) {
console.log(error)
} catch (error: any) {
ElMessage.error(error.message)
}
}
//收藏
const toolCollect = reactive({
toolId: 0
})
const collect = async (toolId) => {
try {
if (!userStore.isLogin()) {
//未登录,弹出登录窗口
ElMessage.error('请登录')
return
}
toolCollect.toolId = toolId
await toolsStore.toolCollect(toolCollect)
// ElMessage.success('收藏成功')
} catch (error: any) {
ElMessage.error(error.message)
}
return
}
onMounted(() => {
getToolsCate()
// getToolsCate()
if (route.query && route.query.value) {//底部导航跳转过来的则定位到响应位置
document?.querySelector('#' + `${route.query.value}`)?.scrollIntoView();
} else {//其他位置跳转过来不需要定位的则定位到顶部
@@ -35,7 +58,7 @@ onMounted(() => {
</div>
<!-- card -->
<div class="flex justify-between flex-wrap self-card-div c-xs:ml-3" :gutter="10" v-if="toolsStore.collect.length > 0">
<router-link v-for="(item, index) in toolsStore.list" :key="index" :to="item.url" class="flex flex-col mt-5 border-solid rounded-2xl border-gray w-[24%] p-2 bg-white hover:shadow-md c-xs:w-[99.5%] c-md:w-[24%] c-sm:w-[32%] p-5">
<router-link v-for="(item, index) in toolsStore.collect" :key="index" :to="item.url" class="flex flex-col mt-5 border-solid rounded-2xl border-gray w-[24%] p-2 bg-white hover:shadow-md c-xs:w-[99.5%] c-md:w-[24%] c-sm:w-[32%] p-5">
<div class="flex items-center border-b pb-2">
<el-image :src="item.logo" class="w-10 h-10 min-h-[2.5rem] min-w-[2.5rem] rounded-full"></el-image>
<div class="flex flex-col ml-2 w-full">
@@ -44,7 +67,7 @@ onMounted(() => {
</div>
<div class="flex justify-between">
<el-text size="small">{{ item.cate }}</el-text>
<el-button :icon="Star" circle size="small"/>
<el-button :icon="Star" circle size="small" @click.prevent="collect(item.id)" type="warning"/>
</div>
</div>
</div>
@@ -77,7 +100,7 @@ onMounted(() => {
</div>
<div class="flex justify-between">
<el-text size="small">{{ item.cate }}</el-text>
<el-button :icon="Star" circle size="small"/>
<el-button :icon="Star" circle size="small" @click.prevent="collect(item.id)" type="warning" :plain="!toolsStore.collectIds.includes(item.id)"/>
</div>
</div>
</div>
@@ -1,8 +1,55 @@
<script setup lang="ts">
// import { Star } from '@element-plus/icons-vue'
import { onMounted, reactive } from 'vue';
import { useRoute } from 'vue-router'
import { useToolsStore } from '@/store/modules/tools'
import { useUserStore } from '@/store/modules/user'
import { ElMessage } from 'element-plus'
const props = defineProps({
title: String
title: String,
id: Number
})
const route = useRoute()
//查询参数
const searchParam = reactive({
cateId: 0,
title: '',
route: ''
})
//store
const toolsStore = useToolsStore()
const userStore = useUserStore()
//根据路由查询tool id
const getToolInfo = async () => {
searchParam.route = route.path
await toolsStore.getToolInfo(searchParam)
}
//收藏
const toolCollect = reactive({
toolId: 0
})
const collect = async (toolId) => {
try {
if (!userStore.isLogin()) {
//未登录,弹出登录窗口
ElMessage.error('请登录')
return
}
toolCollect.toolId = toolId
await toolsStore.toolCollect(toolCollect)
// ElMessage.success('收藏成功')
} catch (error: any) {
ElMessage.error(error.message)
}
return
}
onMounted(() => {
getToolInfo()
})
</script>
<template>
@@ -20,7 +67,7 @@ const props = defineProps({
{{ props.title }}
</div>
<div>
<el-button type="primary" plain>收藏</el-button>
<el-button type="warning" :plain="!toolsStore.collectIds.includes(toolsStore.toolInfo.id)" @click="collect(toolsStore.toolInfo.id)">收藏</el-button>
<!-- <el-button type="danger">取消收藏</el-button> -->
</div>
</div>
+65 -15
View File
@@ -3,30 +3,27 @@ import { ref, reactive, onMounted } from 'vue'
import { Search } from '@element-plus/icons-vue';
import { useToolsStore } from '@/store/modules/tools'
import { useComponentStore } from '@/store/modules/component'
import { ElMessageBox } from 'element-plus'
import { ElMessageBox, ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/display.css'
import { ToolsInfo } from '@/api/tools/type';
import Login from '@/components/Layout/Login/Login.vue'
import { useUserStore } from '@/store/modules/user'
import router from '@/router';
// const isNavDrawer = ref(false)
const loading = ref(false)
const options = ref<ToolsInfo[]>([])
const loginRef = ref()
const userPopRef = ref()
//store
const toolsStore = useToolsStore()
const componentStore = useComponentStore()
const userStore = useUserStore()
//查询参数
const searchParam = reactive({
cateId: 0,
title: ''
title: '',
route: '',
})
//获取分类
const getToolCates = async () => {
try {
await toolsStore.getToolCate()
} catch (error) {
console.log(error)
}
}
//search
// const search = async () => {
@@ -69,8 +66,45 @@ const collect = () => {
})
}
const openLogin = () => {
loginRef.value.show()
}
//获取用户信息
const userInfo = async () => {
try {
//提交
await userStore.userInfo()
} catch (error: any) {
ElMessage.error(error.message)
}
}
//退出登录
const logout = async () => {
try {
//提交
await userStore.logout()
location.reload()
} catch (error: any) {
ElMessage.error(error.message)
}
}
//获取收藏
const getToolCollect = async () => {
try {
await toolsStore.getCollect()
// ElMessage.success('收藏成功')
} catch (error: any) {
ElMessage.error(error.message)
}
return
}
onMounted(() => {
getToolCates()
getToolCollect(),
userInfo()
})
</script>
@@ -136,11 +170,27 @@ onMounted(() => {
<li class="hover:text-blue-500">
<el-button link size="large" @click="collect">收藏本站</el-button>
</li>
<!-- <li class="ml-3 hover:text-blue-500"> -->
<!-- <el-button round>登录/注册</el-button> -->
<!-- </li> -->
<li class="ml-3" v-if="userStore.token?.length != 0">
<!-- userStore.avatar -->
<el-image class="w-10 h-10 cursor-pointer" fit="cover" :src="(userStore.avatar == '' || userStore.avatar == null || userStore.avatar == undefined) ? '/src/assets/default_avatar.png' : userStore.avatar" v-popover="userPopRef"></el-image>
<el-popover
ref="userPopRef"
trigger="hover"
virtual-triggering
popper-style="padding-left: 0; padding-right: 0;"
>
<div class="flex flex-col">
<el-button dlink class="mb-3">{{ userStore.email }}</el-button>
<el-button link type="danger" class="ml-0" style="margin-left: 0;" @click="logout">退出登录</el-button>
</div>
</el-popover>
</li>
<li class="ml-3 hover:text-blue-500" v-else>
<el-button size="large" type="primary" @click="openLogin">登录</el-button>
</li>
</ul>
</div>
<Login ref="loginRef"/>
</header>
</template>
+406
View File
@@ -0,0 +1,406 @@
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { ElMessage, FormInstance, FormRules } from 'element-plus'
import { useUserStore } from '@/store/modules/user'
import { Md5 } from 'ts-md5'
import 'element-plus/theme-chalk/display.css'
// import router from '@/router';
//visible
const visible = ref(false)
const reSendCount = ref(0)
const reForgetSendCount = ref(0)
//login select: 0 login; 1 reg; 2 forget
const loginSelect = ref(0)
//store
const userStore = useUserStore()
//interface
interface loginFormRule {
email: string,
password: string
}
interface registerFormRule {
email: string,
code: string,
password: string,
password_confirmation: string,
}
interface forgetFormRule {
email: string,
code: string,
password: string,
password_confirmation: string,
}
//ref
const ruleLoginFormRef = ref<FormInstance>()
const ruleRegisterFormRef = ref<FormInstance>()
const ruleForgetFormRef = ref<FormInstance>()
//login from data
const loginFrom = reactive<loginFormRule>({
email: '',
password: ''
})
//register from data
const registerFrom = reactive({
email: '',
code: '',
password: '',
password_confirmation: '',
})
//forget from data
const forgetFrom = reactive({
email: '',
code: '',
password: '',
password_confirmation: '',
})
//keep login check
const keepLogin = ref(true)
//显示弹窗
const show = () => {
visible.value = true
}
//关闭弹窗
const close = () => {
visible.value = false
}
//发送验证码
const sendCode = async () => {
try {
//发送
await userStore.sendCodeEmail({
email: registerFrom.email
})
//设置倒计时
reSendCount.value = 180
const intervalId = setInterval(() => {
if (reSendCount.value == 0) {
clearInterval(intervalId)
} else {
reSendCount.value--
}
}, 1000)
ElMessage.success('发送成功')
} catch (error: any) {
ElMessage.error(error.message)
}
}
//忘记密码 - 发送验证码
const sendForgetCode = async () => {
try {
//发送
await userStore.sendForgetCodeEmail({
email: forgetFrom.email
})
//设置倒计时
reForgetSendCount.value = 180
const intervalId = setInterval(() => {
if (reForgetSendCount.value == 0) {
clearInterval(intervalId)
} else {
reForgetSendCount.value--
}
}, 1000)
ElMessage.success('发送成功')
} catch (error: any) {
ElMessage.error(error.message)
}
}
//登录 - 提交
const loginSubmit = async (formEl: FormInstance|undefined) => {
formEl?.validate(async (valid) => {
if (valid) {
loginSubmitCore()
} else {
return false
}
})
}
//登录core
const loginSubmitCore = async (isReg: boolean = false) => {
try {
//提交
await userStore.login({
email: loginFrom.email,
password: Md5.hashStr(loginFrom.password),
})
//登录成功(通过注册调用的登录不用提示文字)
if (isReg == false) {
ElMessage.success('登录成功')
}
//关闭弹窗
// close()
location.reload()
} catch (error: any) {
ElMessage.error(error.message)
}
}
//注册 - 提交
const registerSubmit = (formEl: FormInstance|undefined) => {
formEl?.validate(async (valid) => {
if (valid) {
try {
//提交注册
await userStore.register({
email: registerFrom.email,
code: registerFrom.code,
password: Md5.hashStr(registerFrom.password),
password_confirmation: Md5.hashStr(registerFrom.password_confirmation)
})
ElMessage.success('注册成功')
//模拟登录
loginFrom.email = registerFrom.email
loginFrom.password = registerFrom.password
loginSubmitCore(true)
} catch (error: any) {
ElMessage.error(error.message)
}
} else {
return false
}
})
}
//忘记密码 - 提交
const forgetSubmit = (formEl: FormInstance|undefined) => {
formEl?.validate(async (valid) => {
if (valid) {
try {
//提交注册
await userStore.forget({
email: forgetFrom.email,
code: forgetFrom.code,
password: Md5.hashStr(forgetFrom.password),
password_confirmation: Md5.hashStr(forgetFrom.password_confirmation)
})
ElMessage.success('操作成功')
//模拟登录
loginFrom.email = forgetFrom.email
loginFrom.password = forgetFrom.password
loginSubmitCore(true)
} catch (error: any) {
ElMessage.error(error.message)
}
} else {
return false
}
})
}
//登录 - 规则验证
const loginRules = reactive<FormRules<loginFormRule>>({
email: [
{required: true, message: '请输入邮箱', trigger: 'blur'},
{type: 'email', message: '邮箱格式错误', trigger: 'blur' },
],
password: [
{required: true, message: '请输入密码', trigger: 'blur'},
{min: 6, max: 20, message: '密码长度范围6~20', trigger: 'blur'},
]
})
//自定义验证 - 重复密码验证
const confirmPassword = (_rule: any, value: any, callback: any) => {
if (registerFrom.password !== value) {
callback(new Error('重复密码不一致'))
} else {
callback()
}
}
//忘记密码 - 自定义验证 - 重复密码验证
const confirmForgetPassword = (_rule: any, value: any, callback: any) => {
if (forgetFrom.password !== value) {
callback(new Error('重复密码不一致'))
} else {
callback()
}
}
//注册 - 规则验证
const registerRules = reactive<FormRules<registerFormRule>>({
email: [
{required: true, message: '请输入邮箱', trigger: 'blur'},
{type: 'email', message: '邮箱格式错误', trigger: 'blur' },
],
code: [
{required: true, message: '请输入验证码', trigger: 'blur'}
],
password: [
{required: true, message: '请输入密码', trigger: 'blur'},
{min: 6, max: 20, message: '密码长度范围6~20', trigger: 'blur'},
],
password_confirmation: [
{required: true, message: '请重复输入密码', trigger: 'blur'},
{validator: confirmPassword, trigger: 'blur'},
]
})
//忘记密码 - 规则验证
const forgetRules = reactive<FormRules<forgetFormRule>>({
email: [
{required: true, message: '请输入邮箱', trigger: 'blur'},
{type: 'email', message: '邮箱格式错误', trigger: 'blur' },
],
code: [
{required: true, message: '请输入验证码', trigger: 'blur'}
],
password: [
{required: true, message: '请输入密码', trigger: 'blur'},
{min: 6, max: 20, message: '密码长度范围6~20', trigger: 'blur'},
],
password_confirmation: [
{required: true, message: '请重复输入密码', trigger: 'blur'},
{validator: confirmForgetPassword, trigger: 'blur'},
]
})
defineExpose({
show
})
</script>
<template>
<!-- 登录弹窗 -->
<el-dialog v-model="visible" title="" width="450" center class="pl-6 pr-6 pb-6" style="border-radius: 1rem">
<!-- 登录 -->
<el-form
v-if="loginSelect == 0"
ref="ruleLoginFormRef"
:model="loginFrom"
:rules="loginRules"
>
<el-divider><div class="text-xl font-normal">邮箱登录</div></el-divider>
<div>
<el-form-item prop="email">
<el-input class="" v-model="loginFrom.email" size="large" placeholder="请输入邮箱"></el-input>
</el-form-item>
<el-form-item prop="password" style="margin-bottom: 0;">
<el-input class="" v-model="loginFrom.password" size="large" placeholder="请输入密码" type="password" show-password></el-input>
</el-form-item>
<div class="flex items-center mt-1">
<el-checkbox v-model="keepLogin" label="" size="large" />
<div class="">保持长时间登录</div>
</div>
<el-button class="w-full" type="primary" size="large" @click="loginSubmit(ruleLoginFormRef)">登录</el-button>
<el-divider border-style="dashed" />
<div class="flex justify-between">
<el-button link @click="loginSelect = 1">还没有账号去注册</el-button>
<!-- <el-button type="danger">忘记密码</el-button> -->
<el-button link @click="loginSelect = 2">忘记密码</el-button>
</div>
</div>
</el-form>
<!-- 注册 -->
<el-form
v-if="loginSelect == 1"
ref="ruleRegisterFormRef"
:model="registerFrom"
:rules="registerRules"
>
<el-divider><div class="text-xl font-normal">邮箱注册</div></el-divider>
<div>
<el-form-item prop="email">
<el-input class="" v-model="registerFrom.email" size="large" placeholder="请输入邮箱"></el-input>
</el-form-item>
<el-form-item prop="code">
<el-input
v-model="registerFrom.code"
placeholder="请输入验证码"
class=""
size="large"
>
<template #append>
<el-button v-if="reSendCount == 0" @click="sendCode">发送验证码</el-button>
<el-button v-else>{{reSendCount}}秒后重发</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input class="" v-model="registerFrom.password" size="large" placeholder="请输入密码" type="password" show-password></el-input>
</el-form-item>
<el-form-item prop="password_confirmation">
<el-input class="" v-model="registerFrom.password_confirmation" size="large" placeholder="请重复输入密码" type="password" show-password></el-input>
</el-form-item>
<el-button class="w-full" type="primary" size="large" @click="registerSubmit(ruleRegisterFormRef)">注册</el-button>
<el-divider border-style="dashed" />
<div class="flex justify-between">
<el-button link @click="loginSelect = 0">已经有账号去登录</el-button>
</div>
</div>
</el-form>
<!-- 忘记密码 -->
<el-form
v-if="loginSelect == 2"
ref="ruleForgetFormRef"
:model="forgetFrom"
:rules="forgetRules"
>
<el-divider><div class="text-xl font-normal">忘记密码</div></el-divider>
<div>
<el-form-item prop="email">
<el-input class="" v-model="forgetFrom.email" size="large" placeholder="请输入邮箱"></el-input>
</el-form-item>
<el-form-item prop="code">
<el-input
v-model="forgetFrom.code"
placeholder="请输入验证码"
class=""
size="large"
>
<template #append>
<el-button v-if="reForgetSendCount == 0" @click="sendForgetCode">发送验证码</el-button>
<el-button v-else>{{reForgetSendCount}}秒后重发</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input class="" v-model="forgetFrom.password" size="large" placeholder="请输入密码" type="password" show-password></el-input>
</el-form-item>
<el-form-item prop="password_confirmation">
<el-input class="" v-model="forgetFrom.password_confirmation" size="large" placeholder="请重复输入密码" type="password" show-password></el-input>
</el-form-item>
<el-button class="w-full" type="primary" size="large" @click="forgetSubmit(ruleForgetFormRef)">提交</el-button>
<el-divider border-style="dashed" />
<div class="flex justify-between">
<el-button link @click="loginSelect = 0">已经有账号去登录</el-button>
</div>
</div>
</el-form>
</el-dialog>
</template>
<style scoped>
.fold-enter-active {
transition: all 1s ease-out;
}
.fold-enter-from,
.fold-leave-to {
transform: translateX(20px);
opacity: 0;
}
</style>
+48 -3
View File
@@ -1,18 +1,21 @@
//创建tools相关的小工具
import { defineStore } from 'pinia'
import { getTools, getToolCate, getToolRecommend} from '@/api/tools'
import { getTools, getToolCate, getToolRecommend, toolCollect, getToolCollect } from '@/api/tools'
import { getIp } from '@/api/ip'
import type { ToolsReqData, ToolsInfo, ToolCate } from '@/api/tools/type'
import type { ToolsReqData, ToolsInfo, ToolCate, CollectReqData } from '@/api/tools/type'
import type { IpReqData, IpInfo } from '@/api/ip/type'
import { useUserStore } from '@/store/modules/user'
export const useToolsStore = defineStore('tools', {
//用来存放变量
state: () => ({
list: [] as ToolsInfo[],
toolInfo: {} as ToolsInfo,
cates: [] as ToolCate[],
recommends: [] as ToolsInfo[],
ipData: {} as IpInfo,
collect: [],
collect: [] as ToolsInfo[],
collectIds: [] as number[],
}),
//方法
actions: {
@@ -27,6 +30,17 @@ export const useToolsStore = defineStore('tools', {
return Promise.reject(new Error(result.message))
}
},
//获取tool info
async getToolInfo(data: ToolsReqData) {
//发送请求
const result: any = await getTools(data)
if (result.code == 200) {
this.toolInfo = result.data[0]
return result.message
} else {
return Promise.reject(new Error(result.message))
}
},
//获取tools cate
async getToolCate() {
//发送请求
@@ -57,6 +71,37 @@ export const useToolsStore = defineStore('tools', {
} else {
return Promise.reject(new Error(result.message))
}
},
//收藏工具
async toolCollect(data: CollectReqData) {
if (!useUserStore().isLogin()) {
//未登录
return
}
const result: any = await toolCollect(data)
if (result.code == 200) {
//收藏成功
this.getCollect();
return result.message
} else {
return Promise.reject(new Error(result.message))
}
},
//我的收藏
async getCollect() {
if (!useUserStore().isLogin()) {
//未登录
return
}
const result: any = await getToolCollect()
if (result.code == 200) {
this.collect = result.data
this.collectIds = this.collect.map(item => item.id)
console.log(this.collectIds)
return result.message
} else {
return Promise.reject(new Error(result.message))
}
}
}
})
+105
View File
@@ -0,0 +1,105 @@
import { defineStore } from 'pinia'
import { login, register, sendCodeEmail, userInfo, logout, sendForgetCodeEmail, forget} from '@/api/user'
import type { LoginReqData, LoginResponseData, RegisterReqData, RegisterResponseData, SendCodeEmailResponseData, sendCodeEmailReq, ForgetReqData } from '@/api/user/type'
export const useUserStore = defineStore('user', {
//用来存放变量
state: () => ({
token: localStorage.getItem('TOKEN'),//token
username: '',
avatar: '',
email: '',
}),
//方法
actions: {
//获取登录状态
isLogin() {
let flag = false;
if (this.token != null && this.token != undefined && this.token != '') {
flag = true;
}
return flag;
},
//login
async login(data: LoginReqData) {
//发送请求
const result: any = await login(data)
if (result.code == 200) {
//仓库存储token
this.token = result.data.token
//本地存储token
localStorage.setItem('TOKEN', result.data.token)
return result.message
} else {
return Promise.reject(new Error(result.message))
}
},
//logout
async logout() {
//发送请求
const result: any = await logout()
if (result.code == 200) {
//本地存储token
localStorage.setItem('TOKEN', '')
return result.message
} else {
return Promise.reject(new Error(result.message))
}
},
//register
async register(data: RegisterReqData) {
//发送请求
const result: any = await register(data)
if (result.code == 200) {
return result.message
} else {
return Promise.reject(new Error(result.message))
}
},
//forget
async forget(data: ForgetReqData) {
//发送请求
const result: any = await forget(data)
if (result.code == 200) {
return result.message
} else {
return Promise.reject(new Error(result.message))
}
},
//register - send code email
async sendCodeEmail(data: sendCodeEmailReq) {
//发送请求
const result: any = await sendCodeEmail(data)
if (result.code == 200) {
return result.message
} else {
return Promise.reject(new Error(result.message))
}
},
//forget - send code email
async sendForgetCodeEmail(data: sendCodeEmailReq) {
//发送请求
const result: any = await sendForgetCodeEmail(data)
if (result.code == 200) {
return result.message
} else {
return Promise.reject(new Error(result.message))
}
},
//获取用户信息
async userInfo() {
if (this.token?.length == 0) {
return
}
//发送请求
const result: any = await userInfo()
if (result.code == 200) {
this.username = result.data.nick_name
this.avatar = result.data.avatar
this.email = result.data.email
return result.message
} else {
return Promise.reject(new Error(result.message))
}
}
}
})
+16 -1
View File
@@ -1,5 +1,9 @@
import axios from "axios";
import { ElMessage } from "element-plus";
import { useUserStore } from '@/store/modules/user'
//store
import pinia from '../store' //这里需要引入pinia
const userStore = useUserStore(pinia)
//创建axios实例
let request = axios.create({
baseURL: import.meta.env.VITE_IS_MOCK == 'true' ? import.meta.env.VITE_APP_BASE_API : import.meta.env.VITE_SERVE + import.meta.env.VITE_APP_BASE_API,
@@ -7,10 +11,20 @@ let request = axios.create({
})
//请求拦截器
request.interceptors.request.use(config => {
//获取token
if (userStore.token) {
// config.headers.token = userStore.token
config.headers.Authorization = 'Bearer ' + userStore.token
}
return config;
});
//响应拦截器
request.interceptors.response.use((response) => {
if (response.data.code == 401) {
//登录过期
localStorage.setItem('TOKEN', '')
location.reload()
}
return response.data;
}, (error) => {
//处理网络错误
@@ -18,7 +32,8 @@ request.interceptors.response.use((response) => {
let status = error.response.status;
switch (status) {
case 401:
msg = "token过期";
//msg = "token过期";
msg = "登录过期";
break;
case 403:
msg = '无权访问';