更新依赖和一些基础的功能
This commit is contained in:
14
package.json
14
package.json
@@ -9,12 +9,22 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/vite": "^4.1.4",
|
|
||||||
"tailwindcss": "^4.1.4",
|
"tailwindcss": "^4.1.4",
|
||||||
"vue": "^3.5.13"
|
"vue": "^3.5.13",
|
||||||
|
"@ant-design-vue/pro-layout": "^3.2.5",
|
||||||
|
"@ant-design/icons-vue": "^7.0.1",
|
||||||
|
"@tailwindcss/vite": "^4.1.4",
|
||||||
|
"@vueuse/head": "^2.0.0",
|
||||||
|
"ant-design-vue": "^4.1.1",
|
||||||
|
"axios": "^1.6.2",
|
||||||
|
"lucide-vue-next": "^0.507.0",
|
||||||
|
"pinia": "^2.1.7",
|
||||||
|
"swiper": "^11.0.5",
|
||||||
|
"vue-router": "^4.2.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^5.2.2",
|
"@vitejs/plugin-vue": "^5.2.2",
|
||||||
|
"sass": "^1.71.0",
|
||||||
"vite": "^6.3.1"
|
"vite": "^6.3.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
915
pnpm-lock.yaml
generated
915
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
34
src/App.vue
34
src/App.vue
@@ -1,38 +1,10 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import HelloWorld from './components/HelloWorld.vue'
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="bg-gray-100 min-h-screen">
|
<router-view />
|
||||||
<header class="bg-gradient-to-r from-blue-500 to-indigo-600 text-white py-4 px-6 flex items-center justify-between">
|
|
||||||
<div class="flex items-center space-x-4">
|
|
||||||
<!-- Logo -->
|
|
||||||
<img src="https://via.placeholder.com/40" alt="Logo" class="h-8 w-8 rounded-full">
|
|
||||||
<span class="font-bold">My App</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Menu -->
|
|
||||||
<nav class="hidden md:flex space-x-4">
|
|
||||||
<a href="#" class="hover:text-gray-300">Home</a>
|
|
||||||
<a href="#" class="hover:text-gray-300">About</a>
|
|
||||||
<a href="#" class="hover:text-gray-300">Services</a>
|
|
||||||
<a href="#" class="hover:text-gray-300">Contact</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<!-- User Profile -->
|
|
||||||
<div class="flex items-center space-x-4">
|
|
||||||
<button class="text-sm bg-gray-800 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded">
|
|
||||||
Personal Center
|
|
||||||
</button>
|
|
||||||
<img src="https://via.placeholder.com/40" alt="User Avatar" class="h-8 w-8 rounded-full cursor-pointer">
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<main class="p-6">
|
|
||||||
<slot></slot>
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style lang='scss' scoped>
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
75
src/api/request.js
Normal file
75
src/api/request.js
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import {message as msg} from "ant-design-vue";
|
||||||
|
|
||||||
|
// 创建 Axios 实例
|
||||||
|
const service = axios.create({
|
||||||
|
baseURL: '/api/', // 这里可以设置你的 API 基础地址
|
||||||
|
timeout: 5000 // 请求超时时间
|
||||||
|
});
|
||||||
|
|
||||||
|
// 请求拦截器
|
||||||
|
service.interceptors.request.use(
|
||||||
|
config => {
|
||||||
|
// 从本地存储中获取 token
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
|
if (token) {
|
||||||
|
// 设置请求头中的 Authorization
|
||||||
|
config.headers['Authorization'] = `Bearer ${token}`;
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log(error); // 打印错误信息
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 响应拦截器
|
||||||
|
service.interceptors.response.use(
|
||||||
|
response => {
|
||||||
|
const {code, result, message} = response.data;
|
||||||
|
if (code === 0) {
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
if (code === 401) {
|
||||||
|
msg.error(message).then(r => {
|
||||||
|
localStorage.removeItem('token');
|
||||||
|
localStorage.removeItem('user');
|
||||||
|
window.location.href = '/'
|
||||||
|
msg.destroy()
|
||||||
|
})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
msg.error(message).then(r => {
|
||||||
|
msg.destroy()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log('err' + error); // 打印错误信息
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 封装 get 请求
|
||||||
|
const get = (url, params = {}) => {
|
||||||
|
return service.get(url, { params });
|
||||||
|
};
|
||||||
|
|
||||||
|
// 封装 post 请求
|
||||||
|
const post = (url, data = {}) => {
|
||||||
|
return service.post(url, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 封装上传文件请求
|
||||||
|
const upload = (url, file) => {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
return service.post(url, formData, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { get, post, upload };
|
||||||
10
src/api/request/upload.js
Normal file
10
src/api/request/upload.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import {upload} from '../request.js'
|
||||||
|
|
||||||
|
const prefix = 'upload'
|
||||||
|
|
||||||
|
export function uploadImageApi(credentials) {
|
||||||
|
return upload(`${prefix}/image`, credentials)
|
||||||
|
}
|
||||||
|
export function uploadVideoApi(credentials) {
|
||||||
|
return upload(`${prefix}/video`, credentials)
|
||||||
|
}
|
||||||
92
src/api/request/user.js
Normal file
92
src/api/request/user.js
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
import {get, post} from '../request.js'
|
||||||
|
|
||||||
|
const prefix = 'user'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录
|
||||||
|
* @param credentials
|
||||||
|
* @returns {Promise<axios.AxiosResponse<any>>}
|
||||||
|
*/
|
||||||
|
export function loginApi(credentials) {
|
||||||
|
return post('login', credentials)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 注册
|
||||||
|
* @param credentials
|
||||||
|
* @returns {Promise<axios.AxiosResponse<any>>}
|
||||||
|
*/
|
||||||
|
export function registerApi(credentials) {
|
||||||
|
return post('register', credentials)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户列表
|
||||||
|
* @param credentials
|
||||||
|
* @returns {Promise<axios.AxiosResponse<any>>}
|
||||||
|
*/
|
||||||
|
export function userListApi(credentials) {
|
||||||
|
return get(`${prefix}/list`, credentials)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前登录用户信息
|
||||||
|
* @param credentials
|
||||||
|
* @returns {Promise<axios.AxiosResponse<any>>}
|
||||||
|
*/
|
||||||
|
export function userMyInfoApi(credentials) {
|
||||||
|
return get(`${prefix}/my-info`, credentials)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户统计信息
|
||||||
|
* @param credentials
|
||||||
|
* @returns {Promise<axios.AxiosResponse<any>>}
|
||||||
|
*/
|
||||||
|
export function userStatsApi(credentials) {
|
||||||
|
return get(`${prefix}/user-stats`, credentials)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建用户
|
||||||
|
* @param credentials
|
||||||
|
* @returns {Promise<axios.AxiosResponse<any>>}
|
||||||
|
*/
|
||||||
|
export function createUserApi(credentials) {
|
||||||
|
return post(`${prefix}/create`, credentials)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新用户
|
||||||
|
* @param credentials
|
||||||
|
* @returns {Promise<axios.AxiosResponse<any>>}
|
||||||
|
*/
|
||||||
|
export function updateUserApi(credentials) {
|
||||||
|
return post(`${prefix}/update`, credentials)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除用户
|
||||||
|
* @param credentials
|
||||||
|
* @returns {Promise<axios.AxiosResponse<any>>}
|
||||||
|
*/
|
||||||
|
export function deleteUserApi(credentials) {
|
||||||
|
return post(`${prefix}/delete`, credentials)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置密码
|
||||||
|
* @param credentials
|
||||||
|
* @returns {Promise<axios.AxiosResponse<any>>}
|
||||||
|
*/
|
||||||
|
export function resetPasswordApi(credentials) {
|
||||||
|
return post(`${prefix}/reset-password`, credentials)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置密码
|
||||||
|
* @param credentials
|
||||||
|
* @returns {Promise<axios.AxiosResponse<any>>}
|
||||||
|
*/
|
||||||
|
export function changePasswordApi(credentials) {
|
||||||
|
return post(`${prefix}/change-password`, credentials)
|
||||||
|
}
|
||||||
32
src/layouts/Header.vue
Normal file
32
src/layouts/Header.vue
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<header class="bg-gradient-to-r from-blue-500 to-indigo-600 text-white py-4 px-6 flex items-center justify-between">
|
||||||
|
<div class="flex items-center space-x-4">
|
||||||
|
<!-- Logo -->
|
||||||
|
<img src="https://via.placeholder.com/40" alt="Logo" class="h-8 w-8 rounded-full">
|
||||||
|
<span class="font-bold">My App</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Menu -->
|
||||||
|
<nav class="hidden md:flex space-x-4">
|
||||||
|
<a href="#" class="hover:text-gray-300">首页</a>
|
||||||
|
<a href="#" class="hover:text-gray-300">About</a>
|
||||||
|
<a href="#" class="hover:text-gray-300">Services</a>
|
||||||
|
<a href="#" class="hover:text-gray-300">Contact</a>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- User Profile -->
|
||||||
|
<div class="flex items-center space-x-4">
|
||||||
|
<button class="text-sm bg-gray-800 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded">
|
||||||
|
Personal Center
|
||||||
|
</button>
|
||||||
|
<img src="https://via.placeholder.com/40" alt="User Avatar" class="h-8 w-8 rounded-full cursor-pointer">
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
13
src/main.js
13
src/main.js
@@ -1,5 +1,16 @@
|
|||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
|
import { createPinia } from 'pinia'
|
||||||
|
import Antd from 'ant-design-vue'
|
||||||
import './style.css'
|
import './style.css'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
|
// 注册路由
|
||||||
|
import router from './router'
|
||||||
|
|
||||||
createApp(App).mount('#app')
|
const app = createApp(App)
|
||||||
|
|
||||||
|
|
||||||
|
// 注册Ant Design组件
|
||||||
|
app.use(createPinia())
|
||||||
|
app.use(router)
|
||||||
|
app.use(Antd)
|
||||||
|
app.mount('#app')
|
||||||
|
|||||||
38
src/router/index.js
Normal file
38
src/router/index.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
|
import { useUserStore } from '@/stores/user'
|
||||||
|
import MainLayout from '@/layouts/Header.vue'
|
||||||
|
|
||||||
|
// 在路由配置中添加个人中心路由
|
||||||
|
const routes = [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
component: MainLayout,
|
||||||
|
children: [
|
||||||
|
{ path: '', name: 'Home', component: () => import('@/views/index/index.vue') },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHistory(),
|
||||||
|
routes,
|
||||||
|
scrollBehavior(to, from, savedPosition) {
|
||||||
|
return savedPosition || { top: 0 }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
router.beforeEach((to, from) => {
|
||||||
|
const userStore = useUserStore()
|
||||||
|
if (to.meta.requiresAuth && !userStore.user) {
|
||||||
|
return { name: 'Login', query: { redirect: to.fullPath } }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default router
|
||||||
|
|
||||||
|
router.beforeEach((to, from) => {
|
||||||
|
const userStore = useUserStore()
|
||||||
|
if (to.meta.requiresAuth && !userStore.user) {
|
||||||
|
return { name: 'Login', query: { redirect: to.fullPath } }
|
||||||
|
}
|
||||||
|
})
|
||||||
87
src/stores/user.js
Normal file
87
src/stores/user.js
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import {loginApi, registerApi} from "@/api/request/user.js";
|
||||||
|
import {message, notification} from "ant-design-vue";
|
||||||
|
|
||||||
|
export const useUserStore = defineStore('user', () => {
|
||||||
|
const user = ref(JSON.parse(localStorage.getItem('user') || 'null'))
|
||||||
|
const modal = ref(localStorage.getItem('authModal') || 'false')
|
||||||
|
|
||||||
|
// 添加初始化状态校验
|
||||||
|
const initUser = () => {
|
||||||
|
const userData = localStorage.getItem('user')
|
||||||
|
if (!userData) return null
|
||||||
|
try {
|
||||||
|
return JSON.parse(userData)
|
||||||
|
} catch {
|
||||||
|
localStorage.removeItem('user')
|
||||||
|
localStorage.removeItem('token')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const isAuthenticated = computed(() => !!user.value?.nick_name)
|
||||||
|
|
||||||
|
function login(credentials, functionName) {
|
||||||
|
console.log(functionName, 'sssssssssssss')
|
||||||
|
loginApi({
|
||||||
|
account: credentials.username,
|
||||||
|
password: credentials.password,
|
||||||
|
remember: credentials.remember,
|
||||||
|
}).then((res) => {
|
||||||
|
const userData = {
|
||||||
|
nick_name: res.nick_name,
|
||||||
|
role_name: res.role_name,
|
||||||
|
role_value: res.role_value,
|
||||||
|
}
|
||||||
|
user.value = userData;
|
||||||
|
localStorage.setItem('user', JSON.stringify(userData))
|
||||||
|
localStorage.setItem('token', res.token)
|
||||||
|
notification.success({
|
||||||
|
message: '登录成功',
|
||||||
|
description: `欢迎回来${res.nick_name}`,
|
||||||
|
})
|
||||||
|
functionName()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function register(credentials, functionName) {
|
||||||
|
registerApi({
|
||||||
|
account: credentials.username,
|
||||||
|
password: credentials.password,
|
||||||
|
email: credentials.email,
|
||||||
|
code: credentials.code,
|
||||||
|
}).then((res) => {
|
||||||
|
const userData = {
|
||||||
|
nick_name: res.nick_name,
|
||||||
|
role_name: res.role_name,
|
||||||
|
role_value: res.role_value,
|
||||||
|
}
|
||||||
|
user.value = userData;
|
||||||
|
localStorage.setItem('user', JSON.stringify(userData))
|
||||||
|
localStorage.setItem('token', res.token)
|
||||||
|
message.success('注册成功')
|
||||||
|
functionName()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function logout() {
|
||||||
|
user.value = null
|
||||||
|
localStorage.removeItem('user')
|
||||||
|
localStorage.removeItem('token')
|
||||||
|
}
|
||||||
|
|
||||||
|
function setModal(value) {
|
||||||
|
modal.value = modal.value === 'false' ? 'true' : 'false';
|
||||||
|
localStorage.setItem('authModal', value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
modal,
|
||||||
|
user,
|
||||||
|
isAuthenticated,
|
||||||
|
setModal,
|
||||||
|
login,
|
||||||
|
register,
|
||||||
|
logout
|
||||||
|
}
|
||||||
|
})
|
||||||
11
src/views/index/index.vue
Normal file
11
src/views/index/index.vue
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
你好
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import {defineConfig} from 'vite'
|
import {defineConfig} from 'vite'
|
||||||
import vue from '@vitejs/plugin-vue'
|
import vue from '@vitejs/plugin-vue'
|
||||||
import tailwindcss from "@tailwindcss/vite";
|
import tailwindcss from "@tailwindcss/vite"
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
@@ -8,4 +9,20 @@ export default defineConfig({
|
|||||||
vue(),
|
vue(),
|
||||||
tailwindcss()
|
tailwindcss()
|
||||||
],
|
],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': path.resolve(__dirname, './src')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
port: 8888,
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
// target: 'http://127.0.0.1:18007/api/',
|
||||||
|
target: 'http://127.0.0.1:18001/api/',
|
||||||
|
changeOrigin: true,
|
||||||
|
rewrite: (path) => path.replace(/^\/api/, '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user