Vue平台开发三——项目管理页面

前言

对于多个项目的使用,可能需要进行项目切换管理,所以这里创建一个项目管理页面,登录成功后跳转这个页面,进行选择项目,再进入Home页面展示对应项目的内容。

一、实现效果图预览

在这里插入图片描述

二、页面内容

功能1、项目列表展示

这里使用element-plus的走马灯效果来实现

elment-plus走马灯效果

在这里插入图片描述
走马灯数据从接口获取。有多少项目,就展示多少
在这里插入图片描述

1、封装接口

2、在setup中请求后端数据,并赋值

//首先获取项目数据,接口定义
<script setup>
	import {ref} from 'vue'
	import http  from '@/api/index'
 
	let proList = ref([])
	console.log('1::',proList.value)
	async function getProList(){
		const resposne = await http.pro.getProListApi()
		if(resposne.status == 200){
			console.log(resposne.data)
			proList.value = resposne.data
		}
	}
	getProList()

</script>

在这里插入图片描述

3、通过循环展示

<template>
  <el-carousel :interval="4000" type="card" height="200px" motion-blur>
    <el-carousel-item v-for="item in proList" :key="item.id">
      <h3 text="2xl" justify="center">{{ item.name }}</h3>
    </el-carousel-item>
  </el-carousel>
</template>

在这里插入图片描述
剩下的内容就是把这些换成自己喜欢的图片,再加亿点点css样式美化一下页面。
在这里插入图片描述

功能2、创建新项目

在右上角新增一个按钮,点击展示添加项目的表单界面,填写内容,再提交(注意封装api接口),提交完成后,再刷新一下列表数据,展示到页面。

1. 界面增加按钮和添加弹窗

<el-button icon="CirclePlus" size="small" @click='showDlg'>添加项目</el-button>
...
<!-- 添加项目的弹框 -->
<el-dialog v-model="isDlgShow" title="添加项目">
	<el-form :model="fromData" label-width="80">
		<el-form-item label="项目名称">
			<el-input v-model="fromData.name" autocomplete="off" />
		</el-form-item>
		<el-form-item label="负责人">
			<el-select v-model="fromData.leader" placeholder="选择负责人" >
				<el-option v-for="item in users" :key="item.id" :value="item.id" :label="item.nickname">
				</el-option>
			</el-select>
		</el-form-item>
	</el-form>
	<template #footer>
		<span class="dialog-footer">
			<el-button @click="isDlgShow = false">取消</el-button>
			<el-button type="primary" @click="creatPro">确认</el-button>
		</span>
	</template>
</el-dialog>

在这里插入图片描述

在这里插入图片描述

2. 添加函数功能

import {ref,reactive} from 'vue'
import {ElNotification} from 'element-plus'
import http  from '@/api/index'
...
// ===================实现项目添加的功能=================
let isDlgShow = ref(false)
let users = ref([])
let fromData = reactive({
	name: "",
	leader: ""
})

// 加载用户
async function getUserList(){
	const response = await http.user.getUserListApi()
	users.value = response.data
	console.log(users.value)
}
// 显示添加窗口
function showDlg() {
	isDlgShow.value = true
}
// 发送请求添加项目
async function creatPro() {
	const response = await api.createProApi(fromData)
	if (response.status === 201) {
		// 弹出提示
		ElNotification({
			title: '项目创建成功',
			type: 'success',
		})
		// 关闭窗口
		isDlgShow.value = false
		// 刷新页面数据
		getProList()
	}
}

在这里插入图片描述

功能3、编辑和删除项目

再新增两个按钮,编辑和删除

	<!-- 按钮 -->
<div class="btn_box1">
	<el-button @click='clickEdit(item)' plain icon='Edit' type="primary" size="small"></el-button>
</div>
<div class="btn_box2">
	<el-button @click='clickDelete(item.id)' plain icon='Delete' type="danger" size="small"></el-button>
</div>

在这里插入图片描述

编辑

// api/module/ProjectApi.js
editProApi(pro_id,data){
	return request.patch(`/api/testPro/editProject/${pro_id}`,data)
}
// ProView.vue
// ===========实现项目修改的功能===================
	let isUpdateDlgShow = ref(false)
	let fromUpdateData = ref({
		name: "",
		leader: ""
	})
	// 点击编辑按钮时调用的方法
	function clickEdit(pro) {
		getUserList()
		isUpdateDlgShow.value = true
		fromUpdateData.value = { ...pro }
		// console.log("edit::",pro,{ ...pro })
	}
	// 发送请求修改项目信息
	async function updatePro() {
		let pro_id = fromUpdateData.value.id
		const response = await http.pro.editProApi(pro_id, fromUpdateData.value)
		if (response.status === 200) {
			ElNotification({
				title: '项目修改成功',
				type: 'success',
				duration: 3000
			})
			// 关闭窗口
			isUpdateDlgShow.value = false
			// 刷新页面上的数据
			getProList()
		}
	}

在这里插入图片描述

删除

// ==============实现项目删除的功能=====================
function clickDelete(pro_id) {
	// 调用后端的接口进行删除
	ElMessageBox.confirm(
			'删除操作不可恢复,请确认是否要删除该项目?',
			'提示', {
				confirmButtonText: '确认',
				cancelButtonText: '取消',
				type: 'warning',
			}
		)
		.then(async () => {
			// 调用接口进行删除
			const response = await http.pro.deleteProApi(pro_id)
			if (response.status === 204) {
				ElMessage({
					type: 'success',
					message: '已成功删除该项目',
				})
				// 刷新页面数据
				getProList()
			}
		})
		.catch(() => {
			ElMessage({
				type: 'info',
				message: '已取消删除操作',
			})
		})
}

功能4、进入Home页面

1.新建一个用于存储项目数据的pinia

// stores/moudel/ProStore.js
import {defineStore} from "pinia"
import http from '@/api/index'

export const ProjectStore = defineStore('proStore',{
	state:() => {
		return {
			pro : {},
		}
	},
	
	persist:{
		enabled:true,
		strategies:[
			{
				key:'proInfo',
				storage:localStorage
			}
		]
	}
})

2. 选择项目点击跳转到home页

同时将选择的项目信息持久化储存到pinia中,以便后续使用

	// ===================点击进入选择的项目=================
	function enterProject(pro){
		console.log('enterclick')
		const proStore = ProjectStore()
		// 保存项目信息
		proStore.pro = pro
		router.push('home')
	}

在这里插入图片描述

三、总结

  • elment-plus走马灯数据展示
  • el-select 下拉选择器
  • ElNotification,ElMessage 消息反馈
  • pinia持久化存储

部分页面代码

ProjectApi.js

import request from "@/api/request";

//导出请求方法
export default {
	//获取项目列表
	getProListApi(){
		return request.get('/api/testPro/projects')
	},
	createProApi(data){
		return request.post('/api/testPro/projects',data)
	},
	editProApi(pro_id,data){
		return request.patch(`/api/testPro/editProject/${pro_id}`,data)
	},
	deleteProApi(pro_id){
		return request.delete(`/api/testPro/Projects/${pro_id}`)
	}
	
}

ProView.vue

<template>
	<div class="pro_page">
		<div class="pro_box">
			<div class="welcome">
				<span>欢迎使用自动化测试平台</span>
				<el-button icon="CirclePlus" size="small" @click='showDlg'>添加项目</el-button>
			</div>
			<div class="pro_list">			
				<el-carousel :interval="4000" type="card" height="400px" motion-blur>
					<el-carousel-item v-for="(item,index) in proList" :key="index">
						<div class="pro">
							<div @click='enterProject(item)'>
								<!-- 图片 -->
								<img src="@/assets/procard.jpg">
								<!-- 名称 -->
								<div class="name">
									{{item.name}}
								</div>
							</div>
							<!-- 按钮 -->
							<div class="btn_box1">
								<el-button @click='clickEdit(item)' plain icon='Edit' type="primary" size="small"></el-button>
							</div>
							<div class="btn_box2">
								<el-button @click='clickDelete(item.id)' plain icon='Delete' type="danger" size="small"></el-button>
							</div>
						</div>
					</el-carousel-item>
				</el-carousel>
		</div>
		<div class="iod">
			我觉得该写点什么,但是又不知道写点什么。
		</div>
		<div class="iod">
			只是觉得这样看起来这里很空旷,随便写点东西占个位置
		</div>
	</div>
	
	<!-- 添加项目的弹框 -->
	<el-dialog v-model="isDlgShow" title="添加项目">
		<el-form :model="fromData" label-width="80">
			<el-form-item label="项目名称">
				<el-input v-model="fromData.name" autocomplete="off" />
			</el-form-item>
			<el-form-item label="负责人">
				<el-select v-model="fromData.leader" placeholder="选择负责人" >
					<el-option v-for="item in users" :key="item.id" :value="item.id" :label="item.nickname"></el-option>
				</el-select>
			</el-form-item>
		</el-form>
		<template #footer>
			<span class="dialog-footer">
				<el-button @click="isDlgShow = false">取消</el-button>
				<el-button type="primary" @click="creatPro">确认</el-button>
			</span>
		</template>
	</el-dialog>
	
	<!-- 修改项目的弹框 -->
	<el-dialog v-model="isUpdateDlgShow" title="编辑项目">
		<el-form :model="fromUpdateData" label-width="80">
			<el-form-item label="项目名称">
				<el-input v-model="fromUpdateData.name" autocomplete="off" />
			</el-form-item>
			<el-form-item label="负责人">
				<el-select v-model="fromUpdateData.leader" placeholder="选择负责人" >
									<el-option v-for="item in users" :key="item.id" :value="item.nickname" :label="item.nickname"></el-option>
				</el-select>
			</el-form-item>
		</el-form>
		<template #footer>
			<span class="dialog-footer">
				<el-button @click="isUpdateDlgShow = false">取消</el-button>
				<el-button type="primary" @click="updatePro">确认</el-button>
			</span>
		</template>
	</el-dialog>

	

</div>
</template>



<script setup> 

	import {ref,reactive} from 'vue'
	import {ElNotification,ElMessageBox,ElMessage} from 'element-plus'
	import http  from '@/api/index'
 
	let proList = ref([])
	async function getProList(){
		const resposne = await http.pro.getProListApi()
		if(resposne.status == 200){
			// console.log(resposne.data)
			proList.value = resposne.data
		}
	}
	getProList()
	
	
	// ===================实现项目添加的功能=================
	let isDlgShow = ref(false)
	let users = ref([])
	let fromData = reactive({
		name: "",
		leader: ""
	})
	
	// 加载用户
	async function getUserList(){
		const response = await http.user.getUserListApi()
		users.value = response.data
		// console.log(users.value)
	}
	
	// 显示添加窗口
	function showDlg() {
		getUserList()
		isDlgShow.value = true
	}
	// 发送请求添加项目
	async function creatPro() {
		const response = await http.pro.createProApi(fromData)
		if (response.status === 201) {
			// 弹出提示
			ElNotification({
				title: '项目创建成功',
				type: 'success',
				duration: 3000
			})
			// 关闭窗口
			isDlgShow.value = false
			// 刷新页面数据
			getProList()
		}
	}
	
	// ===========实现项目修改的功能===================
	let isUpdateDlgShow = ref(false)
	let fromUpdateData = ref({
		name: "",
		leader: ""
	})
	// 点击编辑按钮时调用的方法
	function clickEdit(pro) {
		getUserList()
		isUpdateDlgShow.value = true
		fromUpdateData.value = { ...pro }
		// console.log("edit::",pro,{ ...pro })
	}
	// 发送请求修改项目信息
	async function updatePro() {
		let pro_id = fromUpdateData.value.id
		
		const response = await http.pro.editProApi(pro_id, fromUpdateData.value)
		if (response.status === 200) {
			ElNotification({
				title: '项目修改成功',
				type: 'success',
				duration: 3000
			})
			// 关闭窗口
			isUpdateDlgShow.value = false
			// 刷新页面上的数据
			getProList()
		}
	}
	// ==============实现项目删除的功能=====================
	function clickDelete(pro_id) {
		// 调用后端的接口进行删除
		ElMessageBox.confirm(
				'删除操作不可恢复,请确认是否要删除该项目?',
				'提示', {
					confirmButtonText: '确认',
					cancelButtonText: '取消',
					type: 'warning',
				}
			)
			.then(async () => {
				// 调用后端接口进行删除
				const response = await http.pro.deleteProApi(pro_id)
				if (response.status === 204) {
					ElMessage({
						type: 'success',
						message: '已成功删除该项目',
					})
					// 刷新页面数据
					getProList()
				}
			})
			.catch(() => {
				ElMessage({
					type: 'info',
					message: '已取消删除操作',
				})
			})
	}

</script>

<style lang='scss' scoped>
	@use './pro.scss';
</style>

pro.scss

.pro_page{
	background-color: aliceblue;
	background-image:url('@/assets/bg.jpeg') ;
	height: 100vh;
	min-height: 700px;
	background-size: cover;
	.pro_box{
		height: 94%;
		width: 96%;
		background-color: rgba(255, 255, 255, 0.8);
		border-radius: 10px;
		position: relative;
		left: 2%;
		top: 3%;
		.el-button{
			position: absolute; // 设置绝对定位
			top: 10px;
			right: 10px;
		}
		.iod{
			margin-top: 20px;
			display: flex; // 使用 Flexbox 布局
			justify-content: center; // 水平居中
			align-items: center; // 垂直居中
			color: #2a2a2a;
			font-size: 24px;
			font-weight: bold;
			height: 80px;
			line-height: 80px;
		}
		// 顶部内容
		.welcome{
			display: flex; // 使用 Flexbox 布局
			justify-content: center; // 水平居中
			align-items: center; // 垂直居中
			color: #2a2a2a;
			font-size: 24px;
			font-weight: bold;
			height: 80px;
			line-height: 80px;
			
		}
		// 项目卡片
		.pro_list{
			.pro{
				position: relative;
				height: 400px;
				background: #00aaff;
				text-align: center;
				img{
					height: 400px; 
					width: 100%; // 使图片宽度占满 .pro 容器
					object-fit: cover; // 保持图片比例并裁剪以填满容器
				}
				.name {
				      position: absolute; // 设置绝对定位
				      top: 50%;
				      left: 50%;
				      transform: translate(-50%, -50%); // 将文字居中
				      color: #000; // 文字颜色
				      font: bold 28px/80px '微软雅黑';
				      background: rgba(0, 0, 0, 0.1); // 可选:背景色以提高可读性
				      padding: 10px; // 可选:内边距
				      border-radius: 5px; // 可选:圆角
				}
				.btn_box1{
					position: absolute; // 设置绝对定位
					left: 50%;
					bottom: 20%;
					transform: translate(-50%, -50%); // 将文字居中
					bottom: 55px;
				}
				.btn_box2{
					position: absolute; // 设置绝对定位
					left: 56%;
					bottom: 40px;
					transform: translate(-50%, -50%); // 将文字居中
					bottom: 55px;
				}
			}
			
		}
	}
		
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

WPS计算机二级•幻灯片的基础操作

听说这是目录哦 PPT的正确制作步骤&#x1f6e3;️认识PPT界面布局&#x1f3dc;️PPT基础操作 快捷键&#x1f3de;️制作PPT时 常用的快捷技巧&#x1f3d9;️快速替换PPT的 文本字体&#x1f303;快速替换PPT 指定文本内容&#x1f305;能量站&#x1f61a; PPT的正确制作步…

安装 docker 详解

在平常的开发工作中&#xff0c;我们经常需要部署项目。随着 Docker 容器的出现&#xff0c;大大提高了部署效率。Docker 容器包含了应用程序运行所需的所有依赖&#xff0c;避免了换环境运行问题。可以在短时间内创建、启动和停止容器&#xff0c;大大提高了应用的部署速度&am…

Spring Boot 整合 ShedLock 处理定时任务重复执行的问题

&#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Micro麦可乐的博客 &#x1f425;《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程&#xff0c;入门到实战 &#x1f33a;《RabbitMQ》…

BLE透传方案,IoT短距无线通信的“中坚力量”

在物联网&#xff08;IoT&#xff09;短距无线通信生态系统中&#xff0c;低功耗蓝牙&#xff08;BLE&#xff09;数据透传是一种无需任何网络或基础设施即可完成双向通信的技术。其主要通过简单操作串口的方式进行无线数据传输&#xff0c;最高能满足2Mbps的数据传输速率&…

32、【OS】【Nuttx】OSTest分析(1):stdio测试(二)

背景 接上篇wiki 31、【OS】【Nuttx】OSTest分析&#xff08;1&#xff09;&#xff1a;stdio测试&#xff08;一&#xff09; 继续stdio测试的分析&#xff0c;上篇讲到标准IO端口初始化&#xff0c;单从测试内容来说其实很简单&#xff0c;没啥可分析的&#xff0c;但这几篇…

设计新的 Kibana 仪表板布局以支持可折叠部分等

作者&#xff1a;来自 Elastic Teresa Alvarez Soler, Hannah Mudge 及 Nathaniel Reese 在 Kibana 中构建可折叠仪表板部分需要彻底改造嵌入式系统并创建自定义布局引擎。这些更新改进了状态管理、层次结构和性能&#xff0c;同时为新的高级仪表板功能奠定了基础。 我们正在开…

uni-app 程序打包 Android apk、安卓夜神模拟器调试运行

1、打包思路 云端打包方案&#xff08;每天免费次数限制5&#xff0c;最简单&#xff0c;可以先打包尝试一下你的程序打包后是否能用&#xff09;&#xff1a; HBuilderX 发行App-Android云打包 选择Android、使用云端证书、快速安心打包本地打包&#xff1a; HBuilderX …

Jetpack Compose 和 Compose Multiplatform 还有 KMP 的关系

今天刚好看到官方发布了一篇文章&#xff0c;用于讨论 Compose Multiplatform 和 Jetpack Compose 之间的区别&#xff0c;突然想起之前评论区经常看到说 “Flutter 和 CMP 对于 Google 来说项目重叠的问题”&#xff0c;刚好可以放一起聊一聊。 最近写的几篇内容写的太干&…

第38周:猫狗识别 (Tensorflow实战第八周)

目录 前言 一、前期工作 1.1 设置GPU 1.2 导入数据 输出 二、数据预处理 2.1 加载数据 2.2 再次检查数据 2.3 配置数据集 2.4 可视化数据 三、构建VGG-16网络 3.1 VGG-16网络介绍 3.2 搭建VGG-16模型 四、编译 五、训练模型 六、模型评估 七、预测 总结 前言…

python生成图片和pdf,快速

1、下载安装 pip install imgkit pip install pdfkit2、wkhtmltopdf工具包&#xff0c;下载安装 下载地址&#xff1a;https://wkhtmltopdf.org/downloads.html 3、生成图片 import imgkit path_wkimg rD:\app\wkhtmltopdf\bin\wkhtmltoimage.exe # 工具路径&#xff0c;安…

详解:TCP/IP五层(四层)协议模型

一.五层&#xff08;四层&#xff09;模型 1.概念 TCP/IP协议模型分为五层&#xff1a;物理层、数据链路层、网络层、传输层和应用层。这五层每一层都依赖于其下一层给它提供的网络去实现需求。 1&#xff09;物理层&#xff1a;这是最基本的一层&#xff0c;也是最接近硬件…

DeepSeek-R1:将强化学习用于激励大型语言模型的推理能力

目录 引言 一、DeepSeek-R1的贡献 二、DeepSeek-R1的方法 2.1、DeepSeek-R1-Zero&#xff1a;基础模型上的强化学习 2.2、DeepSeek-R1&#xff1a;冷启动强化学习 2.3、蒸馏&#xff1a;赋予小模型推理能力 三、DeepSeek-R1实验结果 3.1、模型优点 3.2、模型缺点 四、…

分布式微服务系统简述

distributed microservice 分布式与微服务的定义及关系&#xff1b;分布式微服务架构里的各组件&#xff0c;如&#xff1a;配置中心、服务注册/发现、服务网关、负载均衡器、限流降级、断路器、服务调用、分布式事务等&#xff1b;spring cloud 介绍及实现案例&#xff0c;如…

从Spring请求处理到分层架构与IOC:注解详解与演进实战

引言 在Spring开发中&#xff0c;请求参数处理、统一响应格式、分层架构设计以及依赖管理是构建可维护应用的核心要素。然而&#xff0c;许多开发者在实践中常面临以下问题&#xff1a; 如何规范接收不同格式的请求参数&#xff1f; 为何要引入分层架构&#xff1f; 什么是控…

神经网络|(三)线性回归基础知识

【1】引言 前序学习进程中&#xff0c;已经对简单神经元的工作模式有所了解&#xff0c;这种二元分类的工作机制&#xff0c;进一步使用sigmoid()函数进行了平滑表达。相关学习链接为&#xff1a; 神经网络|(一)加权平均法&#xff0c;感知机和神经元-CSDN博客 神经网络|(二…

2024年博客之星主题创作|猫头虎分享AI技术洞察:2025年AI发展趋势前瞻与展望

2025年AI发展趋势前瞻&#xff1a;猫头虎深度解析未来科技与商业机遇 摘要 2024年&#xff0c;AI技术迎来爆发式增长&#xff0c;AIGC、智能体、AIRPA、AI搜索、推理模型等技术不断突破&#xff0c;AI应用场景持续扩展。2025年&#xff0c;AI将进入全新发展阶段&#xff0c;W…

Android多语言开发自动化生成工具

在做 Android 开发的过程中&#xff0c;经常会遇到多语言开发的场景&#xff0c;尤其在车载项目中&#xff0c;多语言开发更为常见。对应多语言开发&#xff0c;通常都是在中文版本的基础上开发其他国家语言&#xff0c;这里我们会拿到中-外语言对照表&#xff0c;这里的工作难…

【Maui】提示消息的扩展

文章目录 前言一、问题描述二、解决方案三、软件开发&#xff08;源码&#xff09;3.1 消息扩展库3.2 消息提示框使用3.3 错误消息提示使用3.4 问题选择框使用 四、项目展示 前言 .NET 多平台应用 UI (.NET MAUI) 是一个跨平台框架&#xff0c;用于使用 C# 和 XAML 创建本机移…

AI导航工具我开源了利用node爬取了几百条数据

序言 别因今天的懒惰&#xff0c;让明天的您后悔。输出文章的本意并不是为了得到赞美&#xff0c;而是为了让自己能够学会总结思考&#xff1b;当然&#xff0c;如果有幸能够给到你一点点灵感或者思考&#xff0c;那么我这篇文章的意义将无限放大。 背景 随着AI的发展市面上…

pycharm 运行远程环境问题 Error:Failed to prepare environment.

问题排查 拿到更详细的报错信息&#xff1a; Help > Diagnostic Tools > Debug Log Settings section: 添加下面的配置 com.intellij.execution.configurations.GeneralCommandLine 重显报错&#xff0c;我这里是再次运行代码打开 Help | Collect Logs and Diagnosti…