hookehuyr

Merge branch 'feature/后端测试' into develop

<!--
* @Date: 2025-03-20 19:53:12
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-03-21 15:28:49
* @LastEditTime: 2025-03-24 09:55:15
* @FilePath: /mlaj/src/App.vue
* @Description: 文件描述
* @Description: 入口文件
-->
<script setup>
import { RouterView } from "vue-router";
......@@ -18,12 +18,12 @@ import { wxJsAPI } from "@/api/wx/config";
import { apiList } from "@/api/wx/jsApiList.js";
import { wxInfo, getUrlParams, stringifyQuery } from "@/utils/tools";
// 提供认证和购物车上下文
provideAuth();
provideCart();
provideAuth(); // 提供全局认证状态
provideCart(); // 提供全局购物车状态
</script>
<template>
<!-- 通过v-slot获取当前路由组件。使用component是为了实现动态组件渲染和加载状态的控制:当Component存在时渲染路由组件,不存在时显示加载动画。直接使用 -->
<router-view v-slot="{ Component }">
<div v-if="Component">
<component :is="Component" />
......
/*
* @Date: 2022-06-17 14:54:29
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-07-04 17:05:30
* @FilePath: /data-table/src/api/data.js
* @Description: 表单数据接口
*/
import { fn, fetch } from '@/api/fn';
const Api = {
ADD_FORM_DATA: '/srv/?a=add_formdata',
QUERY_FORM_DATA: '/srv/?a=query_formdata',
MODI_FORM_DATA: '/srv/?a=modi_formdata',
FLOW_FORM_DATA: '/srv/?a=flow_formdata',
}
/**
* @description: 添加表单数据
* @param: form_code 表单唯一标识
* @param: data 待添加的数据,json对象结构;键值对记录变更的字段和值;
*/
export const addFormDataAPI = (params) => fn(fetch.post(Api.ADD_FORM_DATA, params));
/**
* @description: 查询表单数据
* @param: form_code 表单唯一标识
* @param: id 数据ID
*/
export const queryFormDataAPI = (params) => fn(fetch.get(Api.QUERY_FORM_DATA, params));
/**
* @description: 修改表单数据
* @param: form_code 表单唯一标识
* @param: id 数据ID
* @param: data 待添加的数据,json对象结构;键值对记录变更的字段和值;
*/
export const modiFormDataAPI = (params) => fn(fetch.post(Api.MODI_FORM_DATA, params));
/**
* @description: 流程表单数据
* @param: form_code 表单唯一标识
* @param: data_id 数据ID
* @param: data 待添加的数据,json对象结构;键值对记录变更的字段和值;
* @param: flow_node_code 流程节点
* @param: flow_node_action_id 用户点击的流程节点按钮ID
* @param: flow_content 流程审批的文本意见
*/
export const flowFormDataAPI = (params) => fn(fetch.post(Api.FLOW_FORM_DATA, params));
/*
* @Date: 2025-03-23 23:45:53
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-03-23 23:45:54
* @FilePath: /mlaj/src/api/users.js
* @Description: 用户相关接口
*/
import { fn, fetch } from './fn';
const Api = {
USER_LOGIN: '/users/login',
USER_REGISTER: '/users/register',
USER_INFO: '/users/info',
}
/**
* @description: 用户登录
* @param: email 用户邮箱
* @param: password 用户密码
*/
export const loginAPI = (params) => fn(fetch.post(Api.USER_LOGIN, params));
/**
* @description: 用户注册
* @param: name 用户名称
* @param: email 用户邮箱
* @param: password 用户密码
*/
export const registerAPI = (params) => fn(fetch.post(Api.USER_REGISTER, params));
/**
* @description: 获取用户信息
*/
export const getUserInfoAPI = () => fn(fetch.get(Api.USER_INFO));
/*
* @Date: 2025-03-20 21:11:31
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-03-22 10:08:20
* @LastEditTime: 2025-03-24 01:10:13
* @FilePath: /mlaj/src/contexts/auth.js
* @Description: 文件描述
* @Description: 认证上下文管理模块,提供用户认证状态管理、登录登出功能
*/
// 导入Vue的组合式API相关函数
import { ref, provide, inject, onMounted } from 'vue'
// 创建认证上下文的key
// 创建认证上下文的Symbol key,用于provide/inject依赖注入
// 使用Symbol确保key的唯一性,避免命名冲突
const authKey = Symbol('auth')
/**
* 提供认证功能的组合式函数
* 该函数创建并提供认证上下文,包含:
* 1. 用户状态管理(currentUser)
* 2. 加载状态管理(loading)
* 3. 登录登出功能
* 4. Token过期检查
*/
export function provideAuth() {
// 当前用户状态,初始为null表示未登录
const currentUser = ref(null)
// 加载状态标志,用于控制加载动画等UI展示
const loading = ref(true)
// 检查token是否过期(24小时)
/**
* 检查登录token是否过期
* @returns {boolean} true表示token有效,false表示token已过期
*/
const checkTokenExpiration = () => {
const loginTimestamp = localStorage.getItem('loginTimestamp')
if (loginTimestamp) {
const now = Date.now()
const diff = now - parseInt(loginTimestamp)
if (diff > 24 * 60 * 60 * 1000) { // 24小时
// 清理登录状态并返回false表示token已过期
// 检查是否超过24小时(24 * 60 * 60 * 1000 毫秒)
if (diff > 24 * 60 * 60 * 1000) {
// token过期,清理登录状态并返回false
logout()
return false
}
......@@ -32,34 +46,64 @@ export function provideAuth() {
return true
}
// 初始化时检查本地存储的用户信息
/**
* 组件挂载时初始化用户状态
* 1. 从localStorage读取保存的用户信息
* 2. 检查token是否过期
* 3. 恢复用户状态或保持登出状态
*/
onMounted(() => {
const savedUser = localStorage.getItem('currentUser')
if (savedUser) {
// 只有在token未过期的情况下才恢复用户信息
// 检查token是否有效,有效则恢复用户状态
if (checkTokenExpiration()) {
currentUser.value = JSON.parse(savedUser)
}
}
// 初始化完成,关闭加载状态
loading.value = false
})
// 登录函数
/**
* 用户登录函数
* @param {Object} userData - 用户数据对象,包含用户基本信息
* @returns {boolean} 登录是否成功
*/
const login = (userData) => {
// 更新当前用户状态
currentUser.value = userData
if (currentUser.value) {
try {
// 持久化存储用户信息和登录时间戳
localStorage.setItem('currentUser', JSON.stringify(userData))
localStorage.setItem('loginTimestamp', Date.now().toString())
} catch (error) {
console.error('Failed to save user data to localStorage:', error)
}
}
return true
}
// 登出函数
/**
* 用户登出函数
* 清理用户状态和本地存储的认证信息
*/
const logout = () => {
// 清空当前用户状态
currentUser.value = null
// 清理本地存储的用户信息和登录时间戳
localStorage.removeItem('currentUser')
localStorage.removeItem('loginTimestamp')
}
// 提供认证上下文
/**
* 提供认证上下文给子组件使用
* 包含:
* - currentUser: 当前用户状态
* - loading: 加载状态
* - login: 登录函数
* - logout: 登出函数
*/
provide(authKey, {
currentUser,
loading,
......@@ -67,6 +111,7 @@ export function provideAuth() {
logout
})
// 返回认证相关的状态和方法,供组件直接使用
return {
currentUser,
loading,
......@@ -76,11 +121,14 @@ export function provideAuth() {
}
/**
* 使用认证功能的组合式函数
* @returns {Object} 认证上下文值
* 在子组件中使用认证功能的组合式函数
* @returns {Object} 认证上下文对象,包含用户状态和认证方法
* @throws {Error} 如果在provideAuth范围外使用则抛出错误
*/
export function useAuth() {
// 注入认证上下文
const auth = inject(authKey)
// 确保在provideAuth的范围内使用
if (!auth) {
throw new Error('useAuth 必须在 provideAuth 的范围内使用')
}
......
......@@ -12,6 +12,7 @@ import qs from 'Qs'
import { strExist } from '@/utils/tools'
// import { parseQueryString } from '@/utils/tools'
axios.defaults.baseURL = 'http://localhost:3000/api';
axios.defaults.params = {
f: 'good',
};
......
......@@ -114,15 +114,16 @@ import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import FrostedGlass from '@/components/ui/FrostedGlass.vue'
import { useAuth } from '@/contexts/auth'
import { useTitle } from '@vueuse/core';
import { useTitle } from '@vueuse/core'
import { loginAPI } from '@/api/users'
const $route = useRoute();
const $router = useRouter();
useTitle($route.meta.title);
const router = useRouter()
const { login } = useAuth()
const email = ref('')
const password = ref('')
const email = ref('user1@example.com')
const password = ref('password123')
const error = ref('')
const loading = ref(false)
......@@ -136,13 +137,20 @@ const handleSubmit = async () => {
error.value = ''
loading.value = true
// 使用auth.js中的login函数
const success = login({
// 调用登录接口
const response = await loginAPI({
email: email.value,
name: '李玉红',
avatar: 'https://cdn.ipadbiz.cn/mlaj/images/user-avatar-1.jpg'
password: password.value
})
if (response.code !== 1) {
error.value = response.msg || '登录失败,请检查您的凭据'
return
}
// 登录成功,更新auth状态
const success = login(response.data)
if (success) {
// 如果有重定向参数,登录成功后跳转到对应页面
const redirect = $route.query.redirect
......