开始尝试从0写一个项目--前端(三)
kussmcx 2024-08-31 09:33:04 阅读 66
器材管理板块
添加器材管理导航
src\views\home\Home.vue
src\router\index.js
src\views\equipment\Equipment.vue
<code><template>
<div>
hello!
</div>
</template>
测试
搜索导航+分页查询
src\views\equipment\Equipment.vue
<code><template>
<div>
<!-- 导航 -->
<el-form :inline="true" class="demo-form-inline">code>
<div style="float: left">code>
<label style="margin-right: 5px">器材名称: </label>code>
<el-input v-model="name" placeholder="请输入器材名称" style="width: 40%" />code>
<el-button type="primary" style="margin-left: 20px" >查询</el-button>code>
</div>
<div>
<el-button type="primary" style="float: right" >+添加器材</el-button>code>
</div>
</el-form>
<!-- 分页查询 -->
<div>
<el-table :data="records" stripe style="width: 100%">code>
<el-table-column prop="name" label="器材名称" width="180">code>
</el-table-column>
<el-table-column prop="img" label="图片" width="180">code>
</el-table-column>
<el-table-column prop="number" label="数量" width="180">code>
</el-table-column>
<el-table-column prop="comment" label="描述" width="180">code>
</el-table-column>
<el-table-column prop="status" label="器材状态">code>
<template slot-scope="scope">{ { scope.row.status === 0 ? "禁用" : "启用" }}</template>code>
</el-table-column>
<el-table-column prop="updateTime" label="最后操作时间"></el-table-column>code>
<el-table-column label="操作">code>
<template slot-scope="scope">code>
<el-button type="text" @click="handleUpdateStu(scope.row)">修改</el-button>code>
<el-button type="text" @click="handleStartOrStop(scope.row)">{ { scope.row.status === 0 ? "启用" :code>
"禁用"
}}</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script>
export default {
data() {
return {
name: '', //器材名称,对应上面的输入框
page: 1, //页码
pageSize: 10, // 每页记录数
total: 0, //总记录数
records: [] //当前页要展示的数据集合
}
},
}
</script>
src\views\equipment\Equipment.vue
<code><template>
<div>
<el-form :inline="true" :model="formInline" class="demo-form-inline">code>
<div style="float: left">code>
<label style="margin-right: 5px">学生姓名: </label>code>
<el-input v-model="name" placeholder="请输入学生姓名" style="width: 40%" />code>
<el-button type="primary" style="margin-left: 20px" @click="pageQuery()">查询</el-button>code>
</div>
<div>
<el-button type="primary" style="float: right" @click="handleAddStu">+添加学生</el-button>code>
</div>
</el-form>
<br>
<br>
<br>
<div>
<el-table :data="records" stripe style="width: 100%">code>
<el-table-column prop="name" label="学生姓名" width="180">code>
</el-table-column>
<el-table-column prop="username" label="账号" width="180">code>
</el-table-column>
<el-table-column prop="phone" label="手机号">code>
</el-table-column>
<el-table-column prop="status" label="账号状态">code>
<template slot-scope="scope">{ { scope.row.status === 0 ? "禁用" : "启用" }}</template>code>
</el-table-column>
<el-table-column prop="updateTime" label="最后操作时间">code>
</el-table-column>
<el-table-column label="操作">code>
<template slot-scope="scope">code>
<el-button type="text" @click="handleUpdateStu(scope.row)">修改</el-button>code>
<el-button type="text" @click="handleStartOrStop(scope.row)">{ { scope.row.status === 0 ? "启用" :code>
"禁用"
}}</el-button>
</template>
</el-table-column>
</el-table>
</div>
<br>
<div>
<el-pagination class="pageList" @size-change="handleSizeChange" @current-change="handleCurrentChange"code>
:current-page="page" :page-sizes="[10, 20, 30, 40]" :page-size="pageSize"code>
layout="total, sizes, prev, pager, next, jumper" :total="total">code>
</el-pagination>
</div>
</div>
</template>
<script>
// import request from '@/utils/request'
import { page, startOrStopStatus } from '@/api/Student'
export default {
data() {
return {
name: '', //学生姓名,对应上面的输入框
page: 1, //页码
pageSize: 10, // 每页记录数
total: 0, //总记录数
records: [] //当前页要展示的数据集合
}
},
created() {
this.pageQuery()
},
methods: {
pageQuery() {
//准备参数
const params = {
page: this.page,
pageSize: this.pageSize,
name: this.name
}
/* request({
url: "/api/admin/student/page", // 请求地址
method: "get", // 请求方法
params: params,
headers: { // 请求头
"Content-Type": "application/json",
},
}) */
page(params)
.then((res) => {
//解析结果
if (res.data.code === 1) {
this.total = res.data.data.total
this.records = res.data.data.records
}
}).catch(err => {
this.$router.push("/login");
})
},
//每页记录数发生变化时触发
handleSizeChange(pageSize) {
this.pageSize = pageSize
this.pageQuery()
},
//page发生变化时触发
handleCurrentChange(page) {
this.page = page
this.pageQuery()
},
//新增员工
handleAddStu() {
this.$router.push('/student/addStudent')
},
//启用禁用员工状态
handleStartOrStop(row) {
//判断账号是否是管理员账号,不能更改管理员账号
if (row.username === 'admin') {
this.$message.error("这是管理员账号,不允许更改!")
return
}
this.$confirm('是否确认修改员工状态?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const p = {
id: row.id,
status: !row.status ? 1 : 0
}
startOrStopStatus(p)
.then(res =>{
if(res.data.code === 1){
this.$message.success("状态修改成功!")
this.pageQuery()
}
})
})
},
//修改编辑学生信息
handleUpdateStu(row){
if(row.username === 'admin'){
this.$message.error("这是管理员账号,不允许修改!!")
return
}
//跳转到修改页面,通过地址栏传递参数
this.$router.push({ path: '/student/addStudent', query: {id: row.id}})
}
}
}
</script>
src\api\Equipment.js
import request from '@/utils/request'
/* 分页查询 */
export const pageEquipment = (params) =>
request({
'url': '/api/admin/equipment/page',
'method': 'get',
params: params
})
新增器材
src\router\index.js
src\views\equipment\Equipment.vue
src\views\equipment\addEquipment.vue
<code><template>
<div>hello</div>
</template>
测试
完善表单
请求
src\api\Equipment.js
<code>import request from '@/utils/request'
/* 分页查询 */
export const pageEquipment = (params) =>
request({
'url': '/api/admin/equipment/page',
'method': 'get',
params: params
})
/* 新增器材 */
export const addEquipment = (params) =>
request({
'url': '/api/admin/equipment',
'method': 'post',
data: params
})
新增板块的界面
src\views\equipment\addEquipment.vue
<template>
<div class="form-container">code>
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">code>
<el-form-item label="器材名称:" required prop="name">code>
<el-input v-model="ruleForm.name"></el-input>code>
</el-form-item>
<el-form-item label="数量:" required prop="number">code>
<el-input v-model="ruleForm.number"></el-input>code>
</el-form-item>
<el-form-item label="描述" prop="comment">code>
<el-input v-model="ruleForm.comment"></el-input>code>
</el-form-item>
<el-form-item label="器材图片:" prop="img">code>
<div class="img-upload-container">code>
<!-- 监听 update:imageUrl 事件并更新 ruleForm.img -->
<img-upload @update:imageUrl="handleImageUrlUpdate" />code>
<!-- <img-upload :prop-image-url="ruleForm.img"></img-upload> -->code>
<span class="img-upload-instructions">图片大小不超过2M<br>仅能上传 PNG JPEGcode>
JPG类型图片<br>建议上传200*200或300*300尺寸的图片</span>
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">保存</el-button>code>
<el-button @click="$router.push('/equipment');">返回</el-button>code>
</el-form-item>
</el-form>
</div>
</template>
<script>
import ImgUpload from '@/components/img-upload/img-upload.vue'
import { addEquipment } from '@/api/Equipment'
export default {
components: {
ImgUpload,
},
data() {
return {
// imageUrl: '',
ruleForm: {
name: '',
img: '',
number: '',
comment: ''
},
rules: {
name: [
{ required: true, message: '请输入器材名称', trigger: 'blur' }],
number: [
{ required: true, message: '请输入器材数量', trigger: 'blur' }],
},
}
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
alert(this.ruleForm.img)
if (!this.ruleForm.img)
return this.$message.error('套餐图片不能为空')
addEquipment(this.ruleForm)
.then((res) => {
if (res.data.code === 1) {
this.$message.success("添加成功!")
this.$router.push('/equipment')
} else {
this.$message.error("res.data.msg")
}
})
} else {
console.log('error submit!!');
return false;
}
});
},
handleImageUrlUpdate(newImageUrl) {
alert(newImageUrl)
this.ruleForm.img = newImageUrl;
}
},
}
</script>
<style scoped>
.form-container {
display: flex;
justify-content: center;
align-items: center;
height: 70vh;
/* 或者你想要的任何高度 */
width: 100%;
max-width: 600px;
/* 限制最大宽度以适应较小的屏幕 */
margin: 0 auto;
/* 水平居中 */
padding: 20px;
/* 内边距 */
background-color: #ffffff;
/* 背景颜色 */
border-radius: 8px;
/* 圆角 */
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
/* 阴影效果 */
}
/* 为提示文字设置样式 */
.img-upload-instructions {
font-size: 12px;
/* 根据需要调整字体大小 */
color: #666;
/* 根据需要调整颜色 */
margin-bottom: 5px;
/* 可选: 添加底部边距 */
}
/* 为整个上传组件设置样式 */
.img-upload-container {
display: flex;
/* 使用Flex布局 */
align-items: center;
/* 垂直居中 */
gap: 10px;
/* 间距 */
}
</style>
上传文件OSS的逻辑
src\components\img-upload\img-upload.vue
<template>
<div class="upload-item">code>
<el-upload ref="uploadfiles" :accept="type" :class="{ borderNone: imageUrl }" class="avatar-uploader"code>
action="/api/admin/common/upload" :show-file-list="false" :on-success="handleAvatarSuccess"code>
:on-remove="handleRemove" :on-error="handleError" :before-upload="beforeAvatarUpload" :headers="headers">code>
<img v-if="imageUrl" :src="imageUrl" class="avatar">code>
<i v-else class="el-icon-plus avatar-uploader-icon" />code>
<span v-if="imageUrl" class="el-upload-list__item-actions">code>
<span class="el-upload-span" @click.stop="oploadImgDel">code>
删除图片
</span>
<span class="el-upload-span"> 重新上传 </span>code>
</span>
</el-upload>
<p class="upload-tips">code>
<slot />
</p>
</div>
</template>
<script>
import { getToken } from '@/utils/cookies'
export default {
name: 'UploadImage',
props: {
type: {
type: String,
default: '.jpg,.jpeg,.png'
},
size: {
type: Number,
default: 2
},
propImageUrl: {
type: String,
default: ''
}
},
data() {
return {
headers: {
token: getToken()
},
imageUrl: ''
};
},
methods: {
handleRemove() {
// 方法实现
},
oploadImgDel() {
this.imageUrl = '';
this.$emit('imageChange', this.imageUrl);
},
beforeAvatarUpload(file) {
const isLt2M = file.size / 1024 / 1024 < this.size;
if (!isLt2M) {
this.$message({
message: `上传文件大小不能超过${this.size}M!`,
type: 'error'
});
return false;
}
},
handleError(err, file, fileList) {
console.log(err, file, fileList, 'handleError');
this.$message({
message: '图片上传失败',
type: 'error'
});
},
handleAvatarSuccess(response) {
this.imageUrl = `${response.data}`;
// 发出一个事件,包含新的图片 URL
this.$emit('update:imageUrl', this.imageUrl);
}
},
watch: {
propImageUrl: function (val) {
this.imageUrl = val;
}
}
};
</script>
<style lang='scss'>code>
.borderNone {
.el-upload {
border: 1px solid #d9d9d9 !important;
}
}
</style>
<style scoped lang="scss">code>
.avatar-uploader .el-icon-plus:after {
position: absolute;
display: inline-block;
content: ' ' !important;
left: calc(50% - 20px);
top: calc(50% - 40px);
width: 40px;
height: 40px;
// background: url('./../../assets/icons/icon_upload@2x.png') center center no-repeat;
background-size: 20px;
}
.el-upload-list__item-actions:hover .upload-icon {
display: inline-block;
}
.el-icon-zoom-in:before {
content: '\E626';
}
.el-icon-delete:before {
content: '\E612';
}
.el-upload-list__item-actions:hover {
opacity: 1;
}
.upload-item {
.el-form-item__content {
width: 500px !important;
}
display: flex;
align-items: center;
border: 1px solid #ccc;
/* 添加边框*/
width: 200px;
/* 设置宽度 */
height: 200px;
/* 设置高度,使之与宽度相同 */
}
.upload-tips {
font-size: 12px;
color: #666666;
display: inline-block;
line-height: 17px;
margin-left: 36px;
}
.el-upload-list__item-actions {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
cursor: default;
text-align: center;
color: #fff;
opacity: 0;
font-size: 20px;
background-color: rgba(0, 0, 0, 0.5);
transition: opacity 0.3s;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader {
display: inline-block;
}
.avatar-uploader .el-upload:hover {
border-color: #ffc200;
}
.el-upload-span {
width: 100px;
height: 30px;
border: 1px solid #ffffff;
border-radius: 4px;
font-size: 14px;
text-align: center;
line-height: 30px;
}
.el-upload-span:first-child {
margin-bottom: 20px;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 200px;
height: 160px;
line-height: 160px;
text-align: center;
}
.avatar {
width: 200px;
height: 160px;
display: block;
}
</style>
上传oss图片文件时需要的jwt令牌获取
src\utils\cookies.js
import Cookies from 'js-cookie';
// 获取令牌
export const getToken = () => sessionStorage.getItem('jwtToken');
ps:如果出现模块找不到,不存在的时候,直接
npm install 模块
例如:
Module not found: Error: Can't resolve 'js-cookie' in 'D:\bishe\project\sems-front\src\utils'
解决方法:
这个错误表明你的项目无法找到js-cookie
模块,这意味着你可能还没有安装它或者路径配置有问题。js-cookie
是一个用于操作浏览器Cookies的小型JavaScript库。
解决方案
安装 js-cookie
确保你已经安装了js-cookie
。你可以通过运行以下命令来安装它:
npm install js-cookie --save
或者如果你使用的是Yarn:
yarn add js-cookie
测试
ps:OSS折磨死我了,踩了无数的坑,全靠各种搜索资料,卡了我2天,呜呜呜,麻了,有什么不知道的真可以问我,呜呜呜,你们踩的坑我应该都踩过,麻了
禁用启用器材
因为vscode不好用,我将前端代码转移到了idea中去
问题:ESLint: Component name "Equipment" should always be multi-word.(vue/multi-word-component-names
解决:
package.json
{
"rules": {
"vue/multi-word-component-names": "off"
}
}
请求
src/api/Equipment.js
<code>/* 禁用启用器材状态 */
export const startOrStopStatus = (params) =>
request({
'url': `/api/admin/equipment/status/${params.status}`,
'method': 'post',
params: {id: params.id}
})
绑定方法
src/views/equipment/Equipment.vue
<template>
<div>
<!-- 导航 -->
<el-form :inline="true">code>
<div style="float: left">code>
<label style="margin-right: 5px">器材名称: </label>code>
<el-input v-model="name" placeholder="请输入器材名称" style="width: 40%" />code>
<el-button type="primary" style="margin-left: 20px" @click="pageQuery()">查询</el-button>code>
</div>
<div>
<el-button type="primary" style="float: right" @click="handleAddEquipment">+添加器材</el-button>code>
</div>
</el-form>
<br>
<br>
<br>
<!-- 分页查询 -->
<div>
<el-table :data="records" stripe style="width: 100%">code>
<el-table-column prop="name" label="器材名称" width="180">code>
</el-table-column>
<el-table-column prop="img" label="图片" width="180">code>
<template #default="scope">code>
<div class="cell-content">code>
<img :src="scope.row.img" alt="图片" style="max-width: 100%; width: 100%;">code>
</div>
</template>
</el-table-column>
<el-table-column prop="number" label="数量" width="180">code>
</el-table-column>
<el-table-column prop="comment" label="描述" width="180">code>
</el-table-column>
<el-table-column prop="status" label="器材状态">code>
<template slot-scope="scope">{ { scope.row.status === 0 ? "禁用" : "启用" }}</template>code>
</el-table-column>
<el-table-column prop="updateTime" label="最后操作时间"></el-table-column>code>
<el-table-column label="操作">code>
<template slot-scope="scope">code>
<el-button type="text" @click="handleUpdateStu(scope.row)">修改</el-button>code>
<el-button type="text" @click="handleStartOrStop(scope.row)">{ { scope.row.status === 0 ? "启用" :code>
"禁用"
}}</el-button>
</template>
</el-table-column>
</el-table>
</div>
<br>
<!-- 分页底部的导航 -->
<div>
<el-pagination class="pageList" @size-change="handleSizeChange" @current-change="handleCurrentChange"code>
:current-page="page" :page-sizes="[10, 20, 30, 40]" :page-size="pageSize"code>
layout="total, sizes, prev, pager, next, jumper" :total="total">code>
</el-pagination>
</div>
</div>
</template>
<script>
import { pageEquipment } from '@/api/Equipment'
import { startOrStopStatus } from '@/api/Equipment'
export default {
data() {
return {
name: '', //器材名称,对应上面的输入框
page: 1, //页码
pageSize: 10, // 每页记录数
total: 0, //总记录数
records: [] //当前页要展示的数据集合
}
},
created() {
this.pageQuery()
},
methods: {
pageQuery() {
//准备参数
const params = {
page: this.page,
pageSize: this.pageSize,
name: this.name
}
pageEquipment(params)
.then(res => {
if (res.data.code === 1) {
this.total = res.data.data.total
this.records = res.data.data.records
}
}).catch(() => {
this.$router.push("/login")
})
},
//每页记录数发生变化时触发
handleSizeChange(pageSize) {
this.pageSize = pageSize
this.pageQuery()
},
//page发生变化时触发
handleCurrentChange(page) {
this.page = page
this.pageQuery()
},
//新增器材
handleAddEquipment() {
this.$router.push('/equipment/addEquipment')
},
//修改器材状态
handleStartOrStop(row){
this.$confirm('是否确认修改器材状态?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const p = {
id: row.id,
status: !row.status ? 1 : 0
}
startOrStopStatus(p)
.then(res => {
if(res.data.code === 1){
this.$message.success("状态修改成功!")
this.pageQuery()
}
}).catch(err =>{
this.$message.error("请求出错了~");
alert(err);
})
})
}
}
}
</script>
<style scoped>
/* 使表格单元格内的内容垂直居中 */
.el-table__body td {
display: flex;
align-items: center; /* 垂直居中对齐 */
justify-content: center; /* 水平居中对齐 */
}
/* 使图片容器在单元格内居中 */
.cell-content {
display: flex;
align-items: center; /* 垂直居中对齐 */
justify-content: center; /* 水平居中对齐 */
height: 100%; /* 占满单元格高度 */
}
/* 使图片在容器内居中 */
.cell-content img {
max-width: 100%; /* 确保图片宽度不超过容器宽度 */
width: auto; /* 自动调整宽度 */
height: auto; /* 自动调整高度 */
}
</style>
bug修复
我只写了点击确定后的逻辑,如果点击取消就会报错,所以改一下这个bug
vue.config.js
添加这个代码,作用是:禁用 overlay 功能
<code>client: {
overlay: false,
},
修改器材
请求
src/api/Equipment.js
<code>/* 根据器材id查询信息 */
export const queryEquipmentById = (id) =>
request({
'url': `/api/admin/equipment/${id}`,
'method': 'get'
})
/* 编辑器材 */
export const updateEquipment = (params) =>
request({
'url': '/api/admin/equipment',
'method': 'put',
data: params
})
回显
src/views/equipment/addEquipment.vue
created() {
//获取路由参数,如果有就是修改,没有就是新增操作
this.optType = this.$route.query.id ? 'update' : 'add'
if (this.optType === 'update') {
//修改操作,根据id查询原始数据,用于回显
queryEquipmentById(this.$route.query.id)
.then((res) => {
if (res.data.code === 1) {
this.ruleForm = res.data.data
}
})
}
},
问题来了,图片不回显了~~~
啊啊啊啊啊
过了30分钟.........
解决了!!
src/views/equipment/addEquipment.vue
代码开发
src/views/equipment/addEquipment.vue
<code><template>
<div class="form-container">code>
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">code>
<el-form-item label="器材名称:" required prop="name">code>
<el-input v-model="ruleForm.name"></el-input>code>
</el-form-item>
<el-form-item label="数量:" required prop="number">code>
<el-input v-model="ruleForm.number"></el-input>code>
</el-form-item>
<el-form-item label="描述" prop="comment">code>
<el-input v-model="ruleForm.comment"></el-input>code>
</el-form-item>
<el-form-item label="器材图片:" prop="img">code>
<div class="img-upload-container">code>
<!-- 监听 imageChange 事件并更新 ruleForm.img -->
<img-upload :propImageUrl="ruleForm.img" @imageChange="handleImageUrlUpdate"/>code>
<span class="img-upload-instructions">图片大小不超过2M<br>仅能上传 PNG JPEGcode>
JPG类型图片<br>建议上传200*200或300*300尺寸的图片</span>
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">保存</el-button>code>
<el-button @click="$router.push('/equipment');">返回</el-button>code>
</el-form-item>
</el-form>
</div>
</template>
<script>
import ImgUpload from '@/components/img-upload/img-upload.vue'
import {addEquipment, queryEquipmentById, updateEquipment} from '@/api/Equipment'
export default {
components: {
ImgUpload,
},
data() {
return {
// imageUrl: '',
optType: '',//当前操作的类型:add还是update
ruleForm: {
name: '',
img: '',
number: '',
comment: ''
},
rules: {
name: [
{required: true, message: '请输入器材名称', trigger: 'blur'}],
number: [
{required: true, message: '请输入器材数量', trigger: 'blur'}],
},
}
},
created() {
//获取路由参数,如果有就是修改,没有就是新增操作
this.optType = this.$route.query.id ? 'update' : 'add'
if (this.optType === 'update') {
//修改操作,根据id查询原始数据,用于回显
queryEquipmentById(this.$route.query.id)
.then((res) => {
if (res.data.code === 1) {
this.ruleForm = res.data.data
}
})
}
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
if(this.optType === 'add'){
if (!this.ruleForm.img)
return this.$message.error('套餐图片不能为空')
addEquipment(this.ruleForm)
.then((res) => {
if (res.data.code === 1) {
this.$message.success("添加成功!")
this.$router.push('/equipment')
} else {
this.$message.error("res.data.msg")
}
})
}else {
updateEquipment(this.ruleForm)
.then((res) => {
if (res.data.code === 1) {
this.$message.success("修改成功!")
this.$router.push('/equipment')
} else {
this.$message.error("res.data.msg")
}
})
}
} else {
console.log('error submit!!');
return false;
}
});
},
handleImageUrlUpdate(newImageUrl) {
this.ruleForm.img = newImageUrl;
}
},
}
</script>
<style scoped>
.form-container {
display: flex;
justify-content: center;
align-items: center;
height: 70vh;
/* 或者你想要的任何高度 */
width: 100%;
max-width: 600px;
/* 限制最大宽度以适应较小的屏幕 */
margin: 0 auto;
/* 水平居中 */
padding: 20px;
/* 内边距 */
background-color: #ffffff;
/* 背景颜色 */
border-radius: 8px;
/* 圆角 */
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
/* 阴影效果 */
}
/* 为提示文字设置样式 */
.img-upload-instructions {
font-size: 12px;
/* 根据需要调整字体大小 */
color: #666;
/* 根据需要调整颜色 */
margin-bottom: 5px;
/* 可选: 添加底部边距 */
}
/* 为整个上传组件设置样式 */
.img-upload-container {
display: flex;
/* 使用Flex布局 */
align-items: center;
/* 垂直居中 */
gap: 10px;
/* 间距 */
}
</style>
测试
界面美化
src/views/equipment/Equipment.vue
<code><template>
<div>
<!-- 导航 -->
<el-form :inline="true">code>
<div style="float: left">code>
<label style="margin-right: 5px">器材名称: </label>code>
<el-input v-model="name" placeholder="请输入器材名称" style="width: 40%"/>code>
<el-button type="primary" style="margin-left: 20px" @click="pageQuery()">查询</el-button>code>
</div>
<div>
<el-button type="primary" style="float: right" @click="handleAddEquipment">+添加器材</el-button>code>
</div>
</el-form>
<br>
<br>
<br>
<!-- 分页查询 -->
<div>
<el-table :data="records" stripe style="width: 100%">code>
<el-table-column prop="name" label="器材名称" width="180" align="center">code>
</el-table-column>
<el-table-column prop="img" label="图片" width="180" align="center">code>
<template #default="scope">code>
<div class="cell-content">code>
<img :src="scope.row.img" alt="图片" style="max-width: 100%; width: 100%;">code>
</div>
</template>
</el-table-column>
<el-table-column prop="number" label="数量" width="180" align="center">code>
</el-table-column>
<el-table-column prop="comment" label="描述" width="180" align="center">code>
</el-table-column>
<el-table-column prop="status" label="器材状态" align="center">code>
<template slot-scope="scope">{ { scope.row.status === 0 ? "禁用" : "启用" }}</template>code>
</el-table-column>
<el-table-column prop="updateTime" label="最后操作时间" align="center"></el-table-column>code>
<el-table-column label="操作" align="center">code>
<template slot-scope="scope">code>
<el-button type="text" @click="handleUpdateEquipment(scope.row)">修改</el-button>code>
<el-button type="text" @click="handleStartOrStop(scope.row)">{ {code>
scope.row.status === 0 ? "启用" :
"禁用"
}}
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<br>
<!-- 分页底部的导航 -->
<div>
<el-pagination class="pageList" @size-change="handleSizeChange" @current-change="handleCurrentChange"code>
:current-page="page" :page-sizes="[10, 20, 30, 40]" :page-size="pageSize"code>
layout="total, sizes, prev, pager, next, jumper" :total="total">code>
</el-pagination>
</div>
</div>
</template>
<script>
import {pageEquipment} from '@/api/Equipment'
import {startOrStopStatus} from '@/api/Equipment'
export default {
data() {
return {
name: '', //器材名称,对应上面的输入框
page: 1, //页码
pageSize: 10, // 每页记录数
total: 0, //总记录数
records: [] //当前页要展示的数据集合
}
},
created() {
this.pageQuery()
},
methods: {
pageQuery() {
//准备参数
const params = {
page: this.page,
pageSize: this.pageSize,
name: this.name
}
pageEquipment(params)
.then(res => {
if (res.data.code === 1) {
this.total = res.data.data.total
this.records = res.data.data.records
}
}).catch(() => {
this.$router.push("/login")
})
},
//每页记录数发生变化时触发
handleSizeChange(pageSize) {
this.pageSize = pageSize
this.pageQuery()
},
//page发生变化时触发
handleCurrentChange(page) {
this.page = page
this.pageQuery()
},
//新增器材
handleAddEquipment() {
this.$router.push('/equipment/addEquipment')
},
//修改器材状态
handleStartOrStop(row) {
this.$confirm('是否确认修改器材状态?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const p = {
id: row.id,
status: !row.status ? 1 : 0
}
startOrStopStatus(p)
.then(res => {
if (res.data.code === 1) {
this.$message.success("状态修改成功!")
this.pageQuery()
}
}).catch(err => {
this.$message.error("请求出错了~");
alert(err);
})
})
},
//修改器材
handleUpdateEquipment(row){
//跳转到修改页面,通过地址栏传递参数
this.$router.push({ path: '/equipment/addEquipment', query: {id: row.id}})
}
}
}
</script>
<style scoped>
/* 使表格单元格内的内容垂直居中 */
.el-table__body td {
display: flex;
align-items: center; /* 垂直居中对齐 */
justify-content: center; /* 水平居中对齐 */
}
/* 使图片容器在单元格内居中 */
.cell-content {
display: flex;
align-items: center; /* 垂直居中对齐 */
justify-content: center; /* 水平居中对齐 */
height: 100%; /* 占满单元格高度 */
}
/* 使图片在容器内居中 */
.cell-content img {
max-width: 100%; /* 确保图片宽度不超过容器宽度 */
width: auto; /* 自动调整宽度 */
height: auto; /* 自动调整高度 */
}
</style>
src/components/img-upload/img-upload.vue
<template>
<div class="upload-item">code>
<el-upload ref="uploadfiles"code>
:accept="type"code>
:class="{ borderNone: imageUrl }"code>
class="avatar-uploader"code>
action="/api/admin/common/upload"code>
:show-file-list="false"code>
:on-success="handleAvatarSuccess"code>
:on-remove="handleRemove"code>
:on-error="handleError"code>
:before-upload="beforeAvatarUpload"code>
:headers="headers">code>
<img v-if="imageUrl" :src="imageUrl" class="avatar" alt="Preview">code>
<i v-else class="el-icon-plus avatar-uploader-icon" />code>
<span v-if="imageUrl" class="el-upload-list__item-actions">code>
<span class="el-upload-span" @click.stop="oploadImgDel">code>
删除图片
</span>
<span class="el-upload-span" @click.stop="reuploadImage"> 重新上传 </span>code>
</span>
</el-upload>
<p class="upload-tips">code>
<slot />
</p>
</div>
</template>
<script>
import { getToken } from '@/utils/cookies'
export default {
name: 'UploadImage',
props: {
type: {
type: String,
default: '.jpg,.jpeg,.png'
},
size: {
type: Number,
default: 2
},
propImageUrl: {
type: String,
default: ''
}
},
data() {
return {
headers: {
token: getToken()
},
imageUrl: ''// 将 prop 的值赋给本地数据属性
};
},
methods: {
handleRemove() {
// 方法实现
this.imageUrl = '';
this.$emit('imageChange', this.imageUrl);
},
oploadImgDel() {
this.handleRemove();
},
reuploadImage() {
this.handleRemove();
},
beforeAvatarUpload(file) {
const isLt2M = file.size / 1024 / 1024 < this.size;
if (!isLt2M) {
this.$message({
message: `上传文件大小不能超过${this.size}M!`,
type: 'error'
});
return false;
}
},
handleError(err, file, fileList) {
console.log(err, file, fileList, 'handleError');
this.$message({
message: '图片上传失败',
type: 'error'
});
},
handleAvatarSuccess(response) {
this.imageUrl = `${response.data}`;
// 发出一个事件,包含新的图片 URL
this.$emit('imageChange', this.imageUrl);
}
},
watch: {
propImageUrl(newVal) {
this.imageUrl = newVal;
}
}
};
</script>
<style scoped lang="scss">code>
.borderNone {
& {
.el-upload {
border: 1px solid #d9d9d9 !important;
}
}
}
.avatar-uploader .el-icon-plus:after {
position: absolute;
display: inline-block;
content: ' ' !important;
left: calc(50% - 20px);
top: calc(50% - 40px);
width: 40px;
height: 40px;
// background: url('./../../assets/icons/icon_upload@2x.png') center center no-repeat;
background-size: 20px;
}
.el-upload-list__item-actions:hover .upload-icon {
display: inline-block;
}
.el-icon-zoom-in:before {
content: '\E626';
}
.el-icon-delete:before {
content: '\E612';
}
.el-upload-list__item-actions:hover {
opacity: 1;
}
.upload-item {
position: relative;
width: 200px; /* 或者你想要的任何宽度 */
height: 200px; /* 或者你想要的任何高度 */
overflow: hidden;
border: 1px dashed #d9d9d9; /* 边框样式可自定义 */
}
.upload-tips {
font-size: 12px;
color: #666666;
display: inline-block;
line-height: 17px;
margin-left: 36px;
}
.el-upload-list__item-actions {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
cursor: default;
text-align: center;
color: #fff;
opacity: 0;
font-size: 20px;
background-color: rgba(0, 0, 0, 0.5);
transition: opacity 0.3s;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader {
display: inline-block;
}
.avatar-uploader .el-upload:hover {
border-color: #ffc200;
}
.el-upload-span {
width: 100px;
height: 30px;
border: 1px solid #ffffff;
border-radius: 4px;
font-size: 14px;
text-align: center;
line-height: 30px;
}
.el-upload-span:first-child {
margin-bottom: 20px;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 200px;
height: 160px;
line-height: 160px;
text-align: center;
}
.avatar {
width: 100%;
height: 100%;
object-fit: cover;
}
</style>
src/views/student/Student.vue
<template>
<div>
<el-form :inline="true" class="demo-form-inline">code>
<div style="float: left">code>
<label style="margin-right: 5px">学生姓名: </label>code>
<el-input v-model="name" placeholder="请输入学生姓名" style="width: 40%" />code>
<el-button type="primary" style="margin-left: 20px" @click="pageQuery()">查询</el-button>code>
</div>
<div>
<el-button type="primary" style="float: right" @click="handleAddStu">+添加学生</el-button>code>
</div>
</el-form>
<br>
<br>
<br>
<div>
<el-table :data="records" stripe style="width: 100%">code>
<el-table-column prop="name" label="学生姓名" width="180" align="center">code>
</el-table-column>
<el-table-column prop="username" label="账号" width="180" align="center">code>
</el-table-column>
<el-table-column prop="phone" label="手机号" align="center">code>
</el-table-column>
<el-table-column prop="status" label="账号状态" align="center">code>
<template slot-scope="scope">{ { scope.row.status === 0 ? "禁用" : "启用" }}</template>code>
</el-table-column>
<el-table-column prop="updateTime" label="最后操作时间" align="center">code>
</el-table-column>
<el-table-column label="操作" align="center">code>
<template slot-scope="scope">code>
<el-button type="text" @click="handleUpdateStu(scope.row)">修改</el-button>code>
<el-button type="text" @click="handleStartOrStop(scope.row)">{ { scope.row.status === 0 ? "启用" :code>
"禁用"
}}</el-button>
</template>
</el-table-column>
</el-table>
</div>
<br>
<div>
<el-pagination class="pageList" @size-change="handleSizeChange" @current-change="handleCurrentChange"code>
:current-page="page" :page-sizes="[10, 20, 30, 40]" :page-size="pageSize"code>
layout="total, sizes, prev, pager, next, jumper" :total="total">code>
</el-pagination>
</div>
</div>
</template>
<script>
// import request from '@/utils/request'
import { page, startOrStopStatus } from '@/api/Student'
export default {
data() {
return {
name: '', //学生姓名,对应上面的输入框
page: 1, //页码
pageSize: 10, // 每页记录数
total: 0, //总记录数
records: [] //当前页要展示的数据集合
}
},
created() {
this.pageQuery()
},
methods: {
pageQuery() {
//准备参数
const params = {
page: this.page,
pageSize: this.pageSize,
name: this.name
}
/* request({
url: "/api/admin/student/page", // 请求地址
method: "get", // 请求方法
params: params,
headers: { // 请求头
"Content-Type": "application/json",
},
}) */
page(params)
.then((res) => {
//解析结果
if (res.data.code === 1) {
this.total = res.data.data.total
this.records = res.data.data.records
}
}).catch(()=> {
this.$router.push("/login");
})
},
//每页记录数发生变化时触发
handleSizeChange(pageSize) {
this.pageSize = pageSize
this.pageQuery()
},
//page发生变化时触发
handleCurrentChange(page) {
this.page = page
this.pageQuery()
},
//新增员工
handleAddStu() {
this.$router.push('/student/addStudent')
},
//启用禁用员工状态
handleStartOrStop(row) {
//判断账号是否是管理员账号,不能更改管理员账号
if (row.username === 'admin') {
this.$message.error("这是管理员账号,不允许更改!")
return
}
this.$confirm('是否确认修改员工状态?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const p = {
id: row.id,
status: !row.status ? 1 : 0
}
startOrStopStatus(p)
.then(res =>{
if(res.data.code === 1){
this.$message.success("状态修改成功!")
this.pageQuery()
}
})
})
},
//修改编辑学生信息
handleUpdateStu(row){
if(row.username === 'admin'){
this.$message.error("这是管理员账号,不允许修改!!")
return
}
//跳转到修改页面,通过地址栏传递参数
this.$router.push({ path: '/student/addStudent', query: {id: row.id}})
}
}
}
</script>
效果展示
处理一个bug
当我从equipment/addEquipment路径跳转到student路径时会自动跳转到404去
问题产生原因:
如果你没有为 <code><router-link> 的 to
属性提供完整的路径(即以 /
开头的路径),那么 Vue Router 会将其视为相对于当前路由的路径。如果你的 <router-link>
位于某个嵌套路由下(例如 /equipment/addEquipment
),那么 to="student"code> 实际上会被解析为
/equipment/student
,而不是你期望的 /student
。
解决措施
src/views/home/Home.vue
在前面加上了一个”/“
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。