Java 小项目开发日记 06(Vue3 前端开发)

Java 小项目开发日记 06(Vue3 前端开发)

在这里插入图片描述

一、环境准备

1.1 创建vue工程(big-event-admin)

npm init vue@latestcd big-event-admin
npm install

1.2 安装插件

1. 安装element-plus

cnpm i element-plus --save

2. 安装axios

  cnpm i axios

3. 安装sass依赖

   cnpm i sass -D

4. 安装路由

cnpm install vue-router

5. 安装 pinia 插件

Pinia是Vue的专属状态管理库,它允许你跨组件或页面共享状态

cnpm install pinia

6. 安装 persist 插件

默认情况下,由于pinia是内存存储,当你刷新页面的时候pinia中的数据会丢失,可以借助于persist插件解决这个问题,persist插件支持将pinia中的数据持久化到sessionStorage和localStorage中

cnpm install pinia-persistedstate-plugin

二、vite.config.js

import { fileURLToPath, URL } from 'node:url'import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'// https://vitejs.dev/config/
export default defineConfig({plugins: [vue(),],resolve: {alias: {'@': fileURLToPath(new URL('./src', import.meta.url))}},// 配置代理server: {proxy: {'/api': { // 获取请求中带 /api 的请求target: 'http://localhost:8080',  // 后台服务器的源changeOrigin: true,   // 修改源rewrite: (path) => path.replace(/^\/api/, "")   //  /api 替换为空字符串}}}
})

三、main.js

import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import router from '@/router';
import {createPinia} from 'pinia'
import { createPersistedState } from 'pinia-persistedstate-plugin';
// 创建 app 实例
const app = createApp(App);// 创建 pinia 实例
const pinia = createPinia();// 创建 pinia 插件
const persist = createPersistedState()
// 使用 pinia 插件
pinia.use(persist)// 挂载 ElementPlus
app.use(router).use(pinia).use(ElementPlus);
app.mount('#app');

四、 src目录

api

article.js

// 导入 request.js 请求工具
import request from '@/utils/request.js';// 获取登录用户的全部文章
export const getMySelfAllCategoryService = () => {return request.get('/category');
}// 添加文章分类
export const addCategoryService = (categoryData) => {return request.post('/category', categoryData);
}

user.js

// 导入 request.js 请求工具
import request from '@/utils/request.js';// 注册
export const userRegisterService = (registerData) => {const params = new URLSearchParams();for (let key in registerData) {params.append(key, registerData[key]);}return request.post('/user/register', params);
}
// 登录
export const userLoginService = (loginData) => {const params = new URLSearchParams();for (let key in loginData) {params.append(key, loginData[key]);}return request.post('/user/login', params);
}

router

index.js

// 导入 vue-router
import { createRouter, createWebHistory } from 'vue-router'// 导入组件
import Login from "@/views/login/Login.vue";
import Main from "@/views/main/Main.vue";
import ArticleCategory from "@/views/article/ArticleCategory.vue";
import ArticleManage from "@/views/article/ArticleManage.vue";
import UserAvatar from "@/views/user/UserAvatar.vue";
import UserInfo from "@/views/user/UserInfo.vue";
import UserResetPassword from "@/views/user/UserResetPassword.vue";// 定义路由关系
const routes = [{ path: '/login', component: Login },{path: '/', component: Main,// 子路由children: [{path: '/article/category', component: ArticleCategory},{path: '/article/manage', component: ArticleManage},{path: '/user/info', component: UserInfo},{path: '/user/avatar', component: UserAvatar},{path: '/user/password', component: UserResetPassword},],redirect: '/article/category'},
]// 创建路由
const router = createRouter({history: createWebHistory(),routes: routes
});export default router;

store

token.js

import { defineStore } from 'pinia';
import { ref } from 'vue'/*** @description:* @param {*} token 名字需要唯一性* @param {*} 函数  函数的内部可以定义状态的所有内容* @return {*}*/
export const useTokenStore = defineStore('token', () => {// 描述 tokenconst token = ref('');// 定义修改 token 的方法const setToken = (newToken) => {token.value = newToken;}// 定义移除 token 的方法const removeToken = () => {token.value = '';}return { token, setToken, removeToken }
},{persist: true});

utils

request.js

/** @Date: 2024-03-03 16:45:08* @LastEditors: zhong* @LastEditTime: 2024-03-04 20:04:17* @FilePath: \big-event-vue\big-event-admin\src\utils\request.js*/
// 导入 axios 依赖
import router from '@/router';
import { useTokenStore } from '@/store/token.js';
import axios from 'axios';
import { ElMessage } from 'element-plus'
// 定义baseUrl
const baseURL = '/api';
// 创建实例
const instance = axios.create({baseURL: baseURL,
});// 添加请求拦截
instance.interceptors.request.use((config) => {// 请求成功操作let tokenStore = useTokenStore();if (tokenStore.token) {config.headers.Authorization = tokenStore.token;}return config;},(err) => {// 请求错误操作return Promise.reject(err);}
)// 添加响应拦截器
instance.interceptors.response.use(result => {if (result.data.code === 0) {return result.data;}ElMessage.error(result.data.message ? result.data.message : "服务异常");return Promise.reject(result.data);},err => {// 如果响应状态码为 401 代表未登录 跳转至首页  路由守卫if (err.response.status === 401) {ElMessage.error("请先登录!");router.push('/login');} else {ElMessage.error("服务异常");}return Promise.reject(err);}
)export default instance;

五、views

article

ArticleCategory.vue

<!--* @Date: 2024-03-04 16:14:29* @LastEditors: zhong* @LastEditTime: 2024-03-04 20:06:54* @FilePath: \big-event-vue\big-event-admin\src\views\article\ArticleCategory.vue
--><script setup>
import {Edit,Delete
} from '@element-plus/icons-vue'
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { getMySelfAllCategoryService, addCategoryService } from "@/api/article.js"const categorys = ref([])// 获取数据
const articleCategoryList = async () => {let data = await getMySelfAllCategoryService();categorys.value = data.data;
}
articleCategoryList();//控制添加分类弹窗
const dialogVisible = ref(false)//添加分类数据模型
const categoryModel = ref({categoryName: '',categoryAlias: ''
})
//添加分类表单校验
const rules = {categoryName: [{ required: true, message: '请输入分类名称', trigger: 'blur' },],categoryAlias: [{ required: true, message: '请输入分类别名', trigger: 'blur' },]
}// 添加文章分类
const addCategory = async () => {// 调用接口let result = await addCategoryService(categoryModel.value)ElMessage.success(result.message ? result.message : "添加成功")// 重新加载分类数据articleCategoryList();// 关闭弹窗dialogVisible.value = false;}
</script><template><el-card class="page-container"><template #header><div class="header"><span>文章分类</span><div class="extra"><el-button type="primary" @click="dialogVisible = true">添加分类</el-button></div></div></template><el-table :data="categorys" style="width: 100%"><el-table-column label="序号" width="100" type="index"> </el-table-column><el-table-column label="分类名称" prop="categoryName"></el-table-column><el-table-column label="分类别名" prop="categoryAlias"></el-table-column><el-table-column label="操作" width="100"><template #default="{ row }"><el-button :icon="Edit" circle plain type="primary"></el-button><el-button :icon="Delete" circle plain type="danger"></el-button></template></el-table-column><template #empty><el-empty description="没有数据" /></template></el-table></el-card><!-- 添加分类弹窗 --><el-dialog v-model="dialogVisible" title="添加弹层" width="30%"><el-form :model="categoryModel" :rules="rules" label-width="100px" style="padding-right: 30px"><el-form-item label="分类名称" prop="categoryName"><el-input v-model="categoryModel.categoryName" minlength="1" maxlength="10"></el-input></el-form-item><el-form-item label="分类别名" prop="categoryAlias"><el-input v-model="categoryModel.categoryAlias" minlength="1" maxlength="15"></el-input></el-form-item></el-form><template #footer><span class="dialog-footer"><el-button @click="dialogVisible = false">取消</el-button><el-button type="primary" @click="addCategory()"> 确认 </el-button></span></template></el-dialog>
</template><style lang="scss" scoped>
.page-container {min-height: 100%;box-sizing: border-box;.header {display: flex;align-items: center;justify-content: space-between;}
}
</style>

ArticleManage.vue

<template>文章管理
</template>

login

Login.vue

<script setup>
import { User, Lock } from "@element-plus/icons-vue";
import { ElMessage } from 'element-plus'
import { ref, reactive } from "vue";
import { useTokenStore } from '@/store/token.js'
import { userRegisterService, userLoginService } from "@/api/user.js";
// 导入并创建路由
import { useRouter } from "vue-router";
const router = useRouter();//控制注册与登录表单的显示, 默认显示注册
const isRegister = ref(false);
// 清空数据模型
const clearDataAll = () => {// 设置延时 清空太快了不习惯setTimeout(() => {registerData.value = {username: "",password: "",rePassword: ""}}, 1000)
}const registerData = ref({username: "",password: "",rePassword: ""
})// 密码重复校验规则
const checkRePassword = (rule, value, callback) => {if (value === '') {callback(new Error('请再次确认密码'))} else if (value !== registerData.value.password) {callback(new Error('两次密码不一致'))} else {callback()}
}// 表单校验规则
const rules = {username: [{ required: true, message: '请输入用户名', trigger: 'blur' },{ min: 4, max: 12, message: '请输入 4-12 长度的用户名', trigger: 'blur' },],password: [{ required: true, message: '请输入密码', trigger: 'blur' },{ min: 6, max: 12, message: '请输入 6-12 长度的密码', trigger: 'blur' },],rePassword: [{ validator: checkRePassword, trigger: 'blur' },{ min: 6, max: 12, message: '请输入 6-12 长度的密码', trigger: 'blur' },]
}
// token 获取 token
const tokenStore = useTokenStore();// 登录
const login = async () => {// 调用登录请求let result = await userLoginService(registerData.value);ElMessage.success(result.message ? result.message : "登录成功");// 登录成功存储 tokentokenStore.setToken(result.data);// 跳转到首页router.push("/");
}
// 注册
const register = async () => {// 调用注册请求let result = await userRegisterService(registerData.value)ElMessage.success(result.message ? result.message : "注册成功");
}</script><template><el-row class="login-page"><el-col :span="12" class="bg"></el-col><el-col :span="6" :offset="3" class="form"><div class="name"><h1>欢迎访问后台</h1><h1>管理系统</h1></div><!-- 注册表单 --><el-form ref="form" size="large" autocomplete="off" v-if="isRegister" :model="registerData" :rules="rules"><el-form-item><h1>注册</h1></el-form-item><el-form-item prop="username"><el-input :prefix-icon="User" placeholder="请输入用户名" v-model="registerData.username"></el-input></el-form-item><el-form-item prop="password"><el-input :prefix-icon="Lock" type="password" placeholder="请输入密码" v-model="registerData.password"></el-input></el-form-item><el-form-item prop="rePassword"><el-input :prefix-icon="Lock" type="password" placeholder="请输入再次密码"v-model="registerData.rePassword"></el-input></el-form-item><!-- 注册按钮 --><el-form-item><el-button class="button" type="primary" auto-insert-space @click="register(); clearDataAll()">注册</el-button></el-form-item><el-form-item class="flex"><el-link type="info" :underline="false" @click="isRegister = false">← 返回</el-link></el-form-item></el-form><!-- 登录表单 --><el-form ref="form" size="large" autocomplete="off" :model="registerData" :rules="rules" v-else><el-form-item><h1>登录</h1></el-form-item><el-form-item prop="username"><el-input :prefix-icon="User" placeholder="请输入用户名" v-model="registerData.username"></el-input></el-form-item><el-form-item prop="password"><el-input name="password" :prefix-icon="Lock" type="password" placeholder="请输入密码"v-model="registerData.password"></el-input></el-form-item><el-form-item class="flex"><div class="flex"><el-checkbox>记住我</el-checkbox><el-link type="primary" :underline="false">忘记密码?</el-link></div></el-form-item><!-- 登录按钮 --><el-form-item><el-button class="button" type="primary" auto-insert-space @click="login(); clearDataAll()">登录</el-button></el-form-item><el-form-item class="flex"><el-link type="info" :underline="false" @click="isRegister = true; clearDataAll()">注册 →</el-link></el-form-item></el-form></el-col></el-row>
</template><style lang="scss" scoped>
/* 样式 */
.login-page {height: 100vh;background-color: #fff;background-color: #eaecf5;.bg {background: url("@/assets/back-jk.jpg") no-repeat center / cover;border-radius: 0 20px 20px 0;}.form {display: flex;flex-direction: column;justify-content: center;user-select: none;.name {text-align: center;font-size: 26px;}.title {margin: 0 auto;}.button {width: 100%;}.flex {width: 100%;display: flex;justify-content: space-between;}}
}
</style>

main

Main.vue

<script setup>
import {Management,Promotion,UserFilled,User,Crop,EditPen,SwitchButton,CaretBottom
} from '@element-plus/icons-vue'
import avatar from '@/assets/default.png'
</script><template><el-container class="layout-container"><!-- 左侧菜单 --><el-aside width="300px"><div class="el-aside__logo"></div><el-menu active-text-color="#ffd04b" background-color="#232323" text-color="#fff" router><el-menu-item index="/article/category"><el-icon><Management /></el-icon><span>文章分类</span></el-menu-item><el-menu-item index="/article/manage"><el-icon><Promotion /></el-icon><span>文章管理</span></el-menu-item><el-sub-menu class="sub_menu"><template #title><el-icon><UserFilled /></el-icon><span>个人中心</span></template><el-menu-item index="/user/info"><el-icon><User /></el-icon><span>基本资料</span></el-menu-item><el-menu-item index="/user/avatar"><el-icon><Crop /></el-icon><span>更换头像</span></el-menu-item><el-menu-item index="/user/password"><el-icon><EditPen /></el-icon><span>重置密码</span></el-menu-item></el-sub-menu></el-menu></el-aside><!-- 右侧主区域 --><el-container><!-- 头部区域 --><el-header><div>云尚校园:<strong>小钟</strong></div><el-dropdown placement="bottom-end"><span class="el-dropdown__box"><el-avatar :src="avatar" /><el-icon><CaretBottom /></el-icon></span><template #dropdown><el-dropdown-menu><el-dropdown-item command="profile" :icon="User">基本资料</el-dropdown-item><el-dropdown-item command="avatar" :icon="Crop">更换头像</el-dropdown-item><el-dropdown-item command="password" :icon="EditPen">重置密码</el-dropdown-item><el-dropdown-item command="logout" :icon="SwitchButton">退出登录</el-dropdown-item></el-dropdown-menu></template></el-dropdown></el-header><!-- 中间区域 --><el-main><div style="height: 570px;border: 1px solid red;"><router-view></router-view></div></el-main><!-- 底部区域 --><el-footer>云尚校园后台管理系统 ©2024 Created by 小钟</el-footer></el-container></el-container>
</template><style lang="scss" scoped>
span {font-size: 20px;
}.el-icon svg {height: 3em;width: 3em;}.layout-container {height: 100vh;.el-aside {background-color: #232323;margin-top: 20px;&__logo {height: 120px;margin-top: 20px;background: url('@/assets/back-jk.jpg') no-repeat center / 120px auto;}.el-menu {justify-content: center;border-right: none;.el-menu-item {align-items: center;justify-content: center;}.sub_menu {margin-left: 25%;}}}.el-header {background-color: #fff;display: flex;align-items: center;justify-content: space-between;padding-top: 20px;.el-dropdown__box {display: flex;align-items: center;.el-icon {color: #999;margin-left: 10px;}&:active,&:focus {outline: none;}}}.el-footer {display: flex;align-items: center;justify-content: center;font-size: 14px;color: #666;}
}
</style>

user

UserAvatar.vue

<template>更换头像
</template>

UserInfo.vue

<template>基本资料
</template>

UserResetPassword.vue

<template>重置密码
</template>

App.vue

<script setup></script><template><router-view></router-view>
</template><style scoped></style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/511727.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

重学SpringBoot3-yaml文件配置

重学SpringBoot3-yaml文件配置 引言YAML 基本语法YAML 数据类型YAML 对象YAML 数组复合结构标量引用 YAML 文件结构Spring Boot 中的 YAML 配置注意事项总结参考 引言 YAML&#xff08;YAML Ain’t Markup Language&#xff09;是一种常用于配置文件的数据序列化格式&#xff…

STM32(16)使用串口向电脑发送数据

发送字节 发送数组 发送字符和字符串 字符&#xff1a; 字符串&#xff1a; 字符串在电脑中以字符数组的形式存储

智元兔AI-免费论文写作神器

还在为写论文焦虑&#xff1f;免费AI写作大师来帮你三步搞定&#xff01; 智元兔AI是ChatGPT的人工智能助手&#xff0c;并且具有出色的论文写作能力。它能够根据用户提供的题目或要求&#xff0c;自动生成高质量的论文。 不论是论文、毕业论文、散文、科普文章、新闻稿件&…

分享一套高质量武器模型!免费速取!

继续分享一波 CC0 优质游戏资源&#xff0c;有喜欢的欢迎到Cocos Store上自取&#xff01; 01 低模手维武器模型 资源特点 FBX模型14个模型预制体14个模型面数&#xff1a;200~550资源包含 Cocos Creator 展示场景 资产种类 武器 10 个盾牌 4 个 下载地址&#xff1a;https://s…

【数据库】SQLite的基本指令、数据约束、联结表、触发器及索引的使用技巧

目录 一、SQLite 语句基础 1、创建表&#xff1a;create 语句 2、创建表&#xff1a;create 语句 (设置主键&#xff09; ​编辑 3、查看表 4、修改表&#xff1a;alter 5、删除表&#xff1a;drop table 语句 6、插入新行&#xff1a;insert into 语句--全部赋值 7、…

全局渐变滚动条样式

效果如下&#xff1a; APP.vue<style> /* 整个滚动条 */ ::-webkit-scrollbar {width: 5px;height: 10px; } /* 滚动条上的滚动滑块 */ ::-webkit-scrollbar-thumb {background-color: #49b1f5;/* 关键代码 */background-image: -webkit-linear-gradient(45deg,rgba(255,…

Neo4J

1.重装Neo4J出现的一些问题。 解决方案&#xff1a;直接将隐藏文件.Neo4JDesktop文件夹全部删除即可。 2.Neo4J Desktop的一些介绍 3.如何新建项目 参见&#xff1a; 【Neo4j Desktop】自存&#xff5c;Windows安装PythonJupyter notebook_nep4j链接jupyter-CSDN博客 图数据…

【编程学习】数组转矩阵

一、题目&#xff1a; 给定一个一维数组&#xff0c;要求是将数组转化成一个矩阵。数组的输入作为矩阵的第一列&#xff0c;之后每一列的数值&#xff0c;都要比上一列下移一行。 举例 输入&#xff1a; [1,2,3,4,5,6,7,8,9,10] 输出&#xff1a; 1 10 9 8 7 6 5 4 3 2 2 …

Redis基础---Java客户端应用

目录 一、介绍 二、Jedis的使用 三、SpringDataRedis的使用 创建&#xff1a; 一、介绍 在Redis官网&#xff0c;提供了多种编程语言的客户端&#xff0c;如Java、C等&#xff0c;官网地址&#xff1a;Clients | Redis 而对于Java的客户端有很多&#xff0c;但是用的最多的就是…

【图说】电脑发展史

免责声明:文中有一些图片来源自网络,如有版权请通知我删除,谢谢! “结绳记事”是计算的开端 如果说“结绳记事”仅是计数,那么“算筹”就是真正的计算工具 算盘也是我们老祖宗的杰出发明,最擅长“加减乘除”,包括但不限于乘方、开方、对数等。还能进行开发智力的“珠心算…

【好书推荐】这本书太好了!150页就能让你上手大模型应用开发《大模型应用开发极简入门:基于GPT-4和ChatGPT》

如果问个问题&#xff1a;有哪些产品曾经创造了伟大的奇迹&#xff1f;ChatGPT 应该会当之无愧入选。仅仅发布 5 天&#xff0c;ChatGPT 就吸引了 100 万用户——当然&#xff0c;数据不是关键&#xff0c;关键是其背后的技术开启了新的 AI 狂潮&#xff0c;成为技术变革的点火…

【深度学习】脑部MRI图像分割

案例4&#xff1a;脑部MRI图像分割 相关知识点&#xff1a;语义分割、医学图像处理&#xff08;skimage, medpy&#xff09;、可视化&#xff08;matplotlib&#xff09; 1 任务目标 1.1 任务简介 本次案例将使用深度学习技术来完成脑部MRI(磁共振)图像分割任务&#xff0c…