开始尝试从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

在前面加上了一个”/“



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。