Vue3后台管理系统项目实战/vue+element-plus/vue经典全套系统案例讲解
Vue2后台管理系统项目实战/vue+element-ui/vue经典全套系统案例讲解
Vue3后台管理系统项目实战/vue+element-plus/vue经典全套系统案例讲解
前端精品课】用Vue3.0全家桶实现后台管理系统搭建/前端/Vue3的新特性
若依权限系统(ruoyi前端版)
设置国内镜像地址
npm config set registry https://registry.npm.taobao.org
查看配置信息命令
npm config ls -l
node版本查看
npm -v
8.19.2
node -v
v18.12.1
vie官网:https://cn.vitejs.dev/guide/
vie 创建vue项目
npm create vite@latest vue-test-new -- --template vue
# npm 7+, extra double-dash is needed: 官方样例
npm create vite@latest my-vue-app -- --template vue
选择 vue 和 javascript
PS E:\AH\fs\vuepro> npm create vite@latest vue-admin-learn -- --template vue
√ Select a framework: » Vue
√ Select a variant: » JavaScript
Scaffolding project in E:\AH\fs\vuepro\vue-admin-learn...
Done. Now run:
cd vue-admin-learn
npm install
npm run dev
package.json
{
"name": "vue-test-new",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"vue": "^3.2.45"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.0.0",
"vite": "^4.1.0"
}
}
npm run build
生成dist文件夹,使用nginx进行部署项目
官网:https://router.vuejs.org/zh/installation.html
npm install vue-router@4
import { createRouter, createWebHistory } from "vue-router";
import HelloWorld from "../components/HelloWorld.vue"
const routes = [{
path: "/",
component: HelloWorld,
meta: {
title: "前端学习"
}
}]
const router = createRouter({
history: createWebHistory(),
routes
})
router.beforeEach((to, from, next) => {
if (to.meta.title) {
// console.log(to.meta.title)
document.title = to.meta.title
}
next()
})
export default router
import { createApp } from 'vue'
// import './style.css'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(router)
app.mount('#app')
<script setup>
</script>
<template>
<router-view></router-view>
</template>
<style>
/* 清除标签中的默认边框宽度 */
* {
margin: 0;
padding: 0;
height: 100%;
}
</style>
<script setup>
</script>
<template>
<div>
hello world
</div>
</template>
<style scoped>
</style>
npm run dev
官网:https://element-plus.gitee.io/zh-CN/
npm install element-plus --save
// main.ts
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
app.use(ElementPlus)
最终文件内容
// main.ts
import { createApp } from 'vue'
// import './style.css'
import App from './App.vue'
import router from './router'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App)
app.use(router)
app.use(ElementPlus)
app.mount('#app')
在HelloWorld.vue中使用按钮组件
<script setup>
</script>
<template>
<div>
hello world
<el-row class="mb-4">
<el-button>Default</el-button>
<el-button type="primary">Primary</el-button>
<el-button type="success">Success</el-button>
<el-button type="info">Info</el-button>
<el-button type="warning">Warning</el-button>
<el-button type="danger">Danger</el-button>
</el-row>
</div>
</template>
<style scoped>
</style>
npm run dev
src/views/Login/index.vue
src/views/Layout/index.vue
<template>
</template>
<script>
export default {
}
</script>
<style>
</style>
src/views/Login/index.vue
<template>
<h2>login</h2>
</template>
<script>
export default {
}
</script>
<style>
</style>
src/views/Layout/index.vue
<template>
<h2>layout</h2>
</template>
<script>
export default {
}
</script>
<style>
</style>
src/router/index.js
import { createRouter, createWebHistory } from "vue-router";
import HelloWorld from "../components/HelloWorld.vue"
import Layout from '../views/Layout/index.vue'
import Login from '../views/Login/index.vue'
const routes = [{
path: "/",
component: HelloWorld,
meta: {
title: "前端学习"
}
},
{
path: "/layout",
component: Layout,
meta: {
title: "首页布局"
}
},
{
path: "/login",
component: Login,
meta: {
title: "登录"
}
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
router.beforeEach((to, from, next) => {
if (to.meta.title) {
// console.log(to.meta.title)
document.title = to.meta.title
}
next()
})
export default router
参考:
//导入文件
import NotFound from '../views/NotFound/404.vue'
/router下添加如下内容
{
path: '/404',
name: '404',
component: NotFound,
meta: {
title: "error"
}
},
{
path: '/:pathMatch(.*)',
redirect: '/404'
}
404页面的vue内容
<script setup>
</script>
<template>
<div>
404, 抱歉,你访问的页面不存在
</div>
</template>
<style>
</style>
npm install normalize.css
//main.js
import 'normalize.css'
import './assets/css/base.css'
./assets/css/base.css 内容如下:
h1,
h2,
h3,
p,
ul,
li {
margin: 0;
padding: 0;
}
a {
list-style: none;
}
ul {
list-style: none;
}
需要安装单独的icon插件
参考: npm install -g @vue/cli 源文本中存在无法识别的标记。
npm install '@element-plus/icons-vue'
router/index.js中使用children配置路由跳转
npm install dayjs
let time = ref(null)
onMounted(() => {
time.value = dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss')
// console.log(time);
})
git clone https://gitee.com/daitougege/GinSkeleton.git
访问 http://localhost:20201/
func main() {
// 1.创建路由
r := gin.Default()
// 路由组1 ,处理GET请求
v1 := r.Group("api/v1")
// {} 是书写规范
{
v1.GET("/register", register)
v1.GET("login", login)
}
v2 := r.Group("api/v2")
{
v2.POST("/register", register)
v2.POST("/login", login)
}
r.Run(":8000") // 开启端口在8000
}
func login(c *gin.Context) {
name := c.DefaultQuery("name", "jack")
c.String(http.StatusOK, fmt.Sprintf("hello %s\n", name))
}
func register(c *gin.Context) {
name := c.DefaultQuery("name", "lily")
c.String(http.StatusOK, fmt.Sprintf("hello %s\n", name))
}
type Msg struct{
Name string `json:"user"`
Message string
Number int
}
r.GET("/moreJSON", func(c *gin.Context) {
msg.Name = "Lena"
msg.Message = "hey"
msg.Number = 123
// 会输出 {"user": "Lena", "Message": "hey", "Number": 123}
c.JSON(http.StatusOK, msg)
})
import "goskeleton/app/global/variable"
func InsertGoods(c *gin.Context) {
var goodsInfo GoodsModel
//variable.GormDbMysql 是全局的mysql连接客户端
DB := variable.GormDbMysql
timeStr := time.Now().Format("2006-01-02 15:04:05")
goodsInfo = GoodsModel{
CreatedTime: timeStr,
UpdatedTime: timeStr,
Title: "苹果",
Price: 10.3,
Category: "水果",
SellPoint: "好吃",
Desc: "品牌",
}
//指定数据库的名称进行操作,AutoMigrate会判断表是否存在,不存在会自动创建表
DB.Table("goods_info").AutoMigrate(&GoodsModel{})
//往表中插入数据一条数据
DB.Table("goods_info").Create(&goodsInfo)
}
select * from table_name limit 10;//检索前10行记录
select * from table_name limit 5 ,10;//从第6行开始,检索10行记录,即:检索记录行 6-15
gorm官网地址:https://gorm.io/docs/query.html#Retrieving-all-objects
//Retrieving all objects
// Get all records
result := db.Find(&users)
// SELECT * FROM users;
result.RowsAffected // returns found records count, equals `len(users)`
result.Error // returns error
//Limit & Offset
db.Limit(3).Find(&users)
// SELECT * FROM users LIMIT 3;
// Cancel limit condition with -1
db.Limit(10).Find(&users1).Limit(-1).Find(&users2)
// SELECT * FROM users LIMIT 10; (users1)
// SELECT * FROM users; (users2)
db.Offset(3).Find(&users)
// SELECT * FROM users OFFSET 3;
db.Limit(10).Offset(5).Find(&users)
// SELECT * FROM users OFFSET 5 LIMIT 10;
// Cancel offset condition with -1
db.Offset(10).Find(&users1).Offset(-1).Find(&users2)
// SELECT * FROM users OFFSET 10; (users1)
// SELECT * FROM users; (users2)
https://www.jb51.net/article/250242.htm
https://blog.51cto.com/zhangxueliang/5342587
参考:
npm install axios
//方法一
// let homeCount = reactive({ data: {} })
// homeCount.data = res.data
//方法二
// 此homeCount不能用const定义
// let homeCount = reactive({
// sale_total: 0,
// sale: 0,
// views_total: 0,
// views: 0,
// pay_total: 0,
// pay: 0,
// collect_total: 0,
// collect: 0
// });
// Object.assign(homeCount, res.data);
//方法3
let homeCount = ref({})
// homeCount.value = res.data
onMounted(() => {
api.getHomeCount().then(res => {
// console.log("获取首页统计数据", res.data);
//使用Object.assign()进行对象的赋值,不使用直接赋值,直接赋值会影响响应式
// homeCount.data = res.data
// Object.assign(homeCount, res.data);
homeCount.value = res.data
});
});
npm install less
npm install echarts
使用 element-plus 的 card组件进行做底部三个card框
# mysql 的命令
SHOW DATABASES;
USE vue_admin_learn;
SELECT * FROM goods_info;
SELECT * FROM goods_info LIMIT 3;
DROP TABLE goods_info;
分页组件其他页面也可以使用,因此放到components里面
使用element-plush组件实现
<template>
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
layout="total, prev, pager, next, jumper"
:total="total"
@current-change="handleCurrentChange"
/>
</template>
<script setup>
import { ref } from "vue";
const currentPage = ref(1);
const pageSize = ref(1);
const total = ref(10)
//ts 语法
// const handleCurrentChange = (val: number) => {
// console.log(`current page: ${val}`)
// }
//js 语法
const handleCurrentChange = (val) => {
console.log(`current page: ${val}`);
};
</script>
<style>
</style>
参考:Element-Plus 分页组件由默认英文改为中文
在 main.js 中添加以下两句语句
import locale from 'element-plus/lib/locale/lang/zh-cn'
app.use(ElementPlus, { locale });
更具页码 查询到本页数据,并且返回总的数据量的gorm写法
参考: gorm查询条件中带有limit的同时查询count总条数
type GetGoodsResponse struct {
Count int64 `json:"count"`
Data []GoodsModel `json:"data"`
}
var goodsInfo GetGoodsResponse
result := goodsDb.Limit(10).Offset(-1).Find(&goodsInfo.Data).Limit(-1).Offset(-1).Count(&goodsInfo.Count)
用到子传父,父传子,请求调用,函数的async
路由跳转
import { useRouter } from "vue-router";
const router = useRouter()
// 点击添加商品
const addGoodsEvent = () => {
router.push('/goods/addgoods')
}
import { ElMessage } from 'element-plus'
ElMessage({
message: 'Congrats, this is a success message.',
type: 'success',
})
ElMessage.error('Oops, this is a error message.')
// 添加请求拦截器
request.interceptors.request.use(function(config) {
// 在发送请求之前做些什么
if (config.method == "post") {
// config.headers["Content-Type"] = "application/json"
config.headers["Content-Type"] = "application/form-data"
console.log("data is ", config.data)
}
return config;
}, function(error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 7、商品类目选择
goodsItemCategory(params) {
return request.get(base.goodsCategory, { params })
},
// 8.添加商品
addGoods(params) {
return request.post(base.addGoods, params)
},
<el-input v-model.number="goodsForm.price" type="number" placeholder="请输入商品价格"></el-input>
//v-model.number 绑定变量表示限制字符串输入,传给后端的数据也是数字了
vue 限制输入是数字& 接口参数为数字而非字符
vue 强制组件重新渲染(重置)
// 批量删除选择框table - form操作,获取选择的id列表
const changeTable = (val) => {
let arr = []
val.forEach(ele => {
arr.push(ele.id)
});
console.log("选中的id ", arr)
}
npm install pinia
import { createPinia } from 'pinia'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
import { defineStore } from 'pinia'
export const useGoodsStore = defineStore('goods', {
state: () => ({
rowData: {},
title: "添加"
}),
getters: {
},
actions: {
// 设置数据
changeTitle(playload) {
this.title = playload
},
changeRowData(playload) {
this.rowData = playload
},
// 清空
clearGoods() {
this.title = "添加"
this.rowData = {}
}
},
})
import { useGoodsStore } from "../../store/Goods"
const goodsStore = useGoodsStore()
const handleEdit = (index, row) => {
console.log("编辑商品,", row)
goodsStore.changeTitle("编辑")
goodsStore.changeRowData(row)
routerJump.push('/goods/addgoods')
};
import { useGoodsStore } from "../../store/Goods"
const goodsStore = useGoodsStore()
//直接使用
goodsStore.title == "编辑"
const dialogVisible = ref(false)
const submit= ()=>{
dialogVisible.value = true
}
//vite/config.js中添加一下代码
build: {
chunkSizeWarningLimit: 1000,
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
return id.toString().split('node_modules/')[1].split('/')[0].toString();
}
}
}
}
}
{
path: "/",
redirect: "/redirect",
},
{
path: "/redirect",
component: WechatCode,
},
// vue代码示例
<template>
<div class="homeIndex"></div>
</template>
.homeIndex {
background: url("../../assets/scan_background.jpg");
background-size: 100% 100%;
height: 100%;
position: fixed;
width: 100%;
}
使用 async 和 await , await 会等响应完成之后在进行后面的操作, 如下的例子
const scanCodeInfo= async () => {
let res = await api.scanCodeInfo().then(res => {
let { data, errorCode } = res.data;
console.log("resdata is ---", res.data);
console.log("token data is ---", data);
console.log(errorCode);
qrCodeParams.appid = data.appid;
qrCodeParams.scanCodeUrl = data.scanCodeUrl;
console.log(qrCodeParams.appid);
console.log(qrCodeParams.scanCodeUrl);
});
// isShow.value =true
console.log("ttttttttttttttttttttt")
GetWechatCode(qrCodeParams);
};
https://blog.csdn.net/animatecat/article/details/117257037
2.在当前窗口打开新页面
window.location.href = “/classDel”
window.top.location.href = “/classDel”
window.open(“/videoAd?id=” + e.id)
window.top.open(“/videoAd?id=” + e.id)
const router = useRouter()
router.push(“/apphome”)
参考:
window.location与window.open()的区别 "top.location.href"是最外层的页面跳转
如何实现vue3界面跳转,这些代码你该记住~
//npm install crypto-js
// npm install js-base64
import CryptoJS from 'crypto-js'
// 默认的 KEY 与 iv 如果没有给
const key = CryptoJS.enc.Utf8.parse("D3]-eFJt@=v>yFQ>"); //""中与后台一样 密码
const iv = CryptoJS.enc.Utf8.parse('Ft%HorNZ9xo4w)P#'); //""中与后台一样 偏移量
/**
* AES加密 :字符串 key iv 返回base64
*/
export function Encrypt(word) {
let srcs = CryptoJS.enc.Utf8.parse(word);
var encrypted = CryptoJS.AES.encrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
console.log("加密后");
console.log(encrypted);
console.log("base64加密");
console.log(CryptoJS.enc.Base64.stringify(encrypted.ciphertext))
// return CryptoJS.enc.Hex.stringify(encrypted.ciphertext);
return CryptoJS.enc.Base64.stringify(encrypted.ciphertext); //返回base64格式密文
}
/**
* AES 解密 :字符串 key iv 返回base64
* */
export function Decrypt(word) {
let base64 = CryptoJS.enc.Base64.parse(word);
let src = CryptoJS.enc.Base64.stringify(base64);
var decrypt = CryptoJS.AES.decrypt(src, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
var decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
return decryptedStr.toString();
}
//npm install crypto-js
// npm install js-base64
//局部页面使用
import { Base64 } from 'js-base64'
var ed = Base64.encode("11111")
var dd = Base64.decode(ed)
https://www.cnblogs.com/echolun/p/9088189.html
Vue3+Element-Plus 主页布局功能功能开发 二二
https://blog.csdn.net/lalala_dxf/article/details/128567292
https://blog.csdn.net/weixin_61570458/article/details/128238360
https://www.cnblogs.com/Lilc20201212/p/15957285.html
https://blog.csdn.net/weixin_50523809/article/details/118304487
https://blog.csdn.net/weixin_47345230/article/details/128158883
https://blog.csdn.net/m0_66504310/article/details/128458971
<div class="addbutton">
<el-button type="primary" :icon="Plus" @click="handleInsert">新增</el-button>
<el-upload action="#" :limit="1" accept=".xlsx" :show-file-list="false" :before-upload="beforeUpload" :http-request="handleMany">
<el-button type="success" @click="uploadTemplate">批量导入</el-button>
</el-upload>
<el-button type="warning" @click="downloadTemplate">批量导入模板下载</el-button>
</div>
.addbutton {
display: flex; //将 列显示变为行显示
margin-bottom: 10px;
}
/* el -button和 el-upload使用 */
.el-button {
margin-right: 10px; //增加button之前的间隔
}
后端gin 程序代码
func DownloadEmployeesTemplate(c *gin.Context) {
//1.检查配置文件是否存在
templateFile := variable.BasePath + "/storage/app/idaas/employees.xlsx"
if _, err := os.Stat(templateFile); err != nil {
LogInfo("err, file not exist")
ErrorResponse(c, 400, "file not exist")
return
}
//templateFile = strings.TrimSpace(c.PostForm(templateFile))
//fmt.Println("2222222", templateFile)
c.Header("Content-Type", "application/octet-stream")
c.Header("Content-Disposition", "attachment; filename="+"employees.xlsx")
c.Header("Content-Transfer-Encoding", "binary")
c.File(templateFile)
//NormalResponse(c, "")
return
}
前端vue代码
// 在请求拦截中修改responseType 为block
if (config.url == "/api/employees/download-employees-template") {
config.timeout = 120000
//将返回的数据转成blob/ 也可以使用 在 then里面 new Blob-- 两种方法选择其中之一
config.responseType = 'blob'
}
// 下载模板
const downloadTemplate = async () => {
let res = api.downloadEmployeesTemplate().then(res => {
// 文件下载需要设置
// console.log(res.data)
let fileName = "employees.xlsx";
let href = URL.createObjectURL(res.data);
let link = document.createElement("a");
link.download = fileName;
link.href = href;
link.style.display = "none";
link.click();
//document.body.removeChild(link); //下载完成移除元素
URL.revokeObjectURL(link.href);
});
};
vue下载excel文件的方法
VUE3.X – 如何实现文件下载功能
https://blog.csdn.net/qq_44535402/article/details/128051402
Vue3生命周期、
Vue2.X和Vue3.X对比
vue2 -------> vue3
beforeCreate --------> setup(()=>{})
created --------> setup(()=>{})
beforeMount --------> onBeforeMount(()=>{})
mounted --------> onMounted(()=>{})
beforeUpdate --------> onBeforeUpdate(()=>{})
updated --------> onUpdated(()=>{})
beforeDestroy --------> onBeforeUnmount(()=>{})
destroyed --------> onUnmounted(()=>{})
activated --------> onActivated(()=>{})
deactivated --------> onDeactivated(()=>{})
errorCaptured --------> onErrorCaptured(()=>{})
https://blog.csdn.net/weixin_67560997/article/details/129342631
https://blog.csdn.net/weixin_61570458/article/details/128238360
两个字段配合使用
node-key="id"是唯一标识
current-node-key="1"是当前选中,可以用来设置默认选中
https://zhidao.baidu.com/question/1775302071392901660.html
:deep(.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content){
background-color: rgb(158, 213, 250) !important;
color: #409EFF;
}
elementUI图标按钮调整宽高后图标如何居中?
在样式中增加下面字段即可
<div class="cloudpass-tunnel">
<el-icon style="padding-left:10px"><List /></el-icon>
通道列表
</div>
display: flex;
align-items: center;
如果需要水平居中,再加
justify-content: center;
https://blog.csdn.net/AiGarry/article/details/124293561
show-overflow-tooltip="true"
https://blog.csdn.net/qq_35226176/article/details/115730325
https://blog.csdn.net/yjl13598765406/article/details/125496865
// 安装插件
npm install -S default-passive-events
// 在main.js引入
import 'default-passive-events'
v-if="title.classify==='今日要闻'"
<el-table 中某一列不需要显示,但又不能删除,即需要隐藏时
在<el-table-column 中加上 v-if="false"
https://blog.csdn.net/qq_38374286/article/details/128004501
el-select表单校验输入值之后表单规则不会自动清除
https://blog.csdn.net/m0_66899315/article/details/124494296
blur 变为change
https://blog.csdn.net/weixin_67849181/article/details/129130290
vue3中使用 vue3-slide-verify 滑块验证登录
主要参考: - vue3滑块验证使用vue3-slide-verify,宽度自适应
参考: vue-monoplasty-slide-verify在H5页面的使用和参数说明
<el-form :model="ruleForm" :rules="rules" ref="ruleForm">
<el-form-item label="版本号" prop="versionCode" :label-width="formLabelWidth">
<el-input v-model.number="ruleForm.versionCode" placeholder="输入版本号"></el-input>
</el-form-item>
</el-form>
data(){
return {
rules:{
versionCode: [
{required: true, message: "输入版本号", trigger: "blur" },
{ required: true, type:"number",message: "版本号为数字", trigger: "blur" },
],
}
}
}
解读element-ui使用el-upload,before-upload函数不好使的问题
el-upload 只能上传一个文件(完整适用方法),包括:新文件替换原文件方法。
el-upload上传读取文件内容
element-plus版本升级导致编译失败
https://blog.csdn.net/qq_45284938/article/details/129707796
vue3创建项目(五)vite配置端口号