2025/4/18团队开发进度报告
完成主页面的基本框架以及用户分角色登录:


lender.vue:
<template>
<div>
<!-- 头部开始 -->
<div style="height: 60px; background-color: #8686e0; display: flex; align-items: center">
<div style="width: 200px; display: flex; align-items: center; padding-left: 15px">
<img width="40px" src="@/assets/logo.png">
<span style=" font-size: 24px; margin-left: 5px ;color: white">这是系统</span>
</div>
<div style="flex: 1"></div>
<div style="width: fit-content; display: flex; align-items: center; padding-right: 20px">
<!-- 使用el-dropdown替换原来的头像和用户名显示 -->
<el-dropdown @command="handleCommand" trigger="click">
<div style="display: flex; align-items: center; cursor: pointer">
<img src="../assets/user.png" alt="" style="width: 40px; height: 40px; border-radius: 50%;">
<span style="color: white; margin-left: 5px">{{ userInfo.username || '用户名' }}</span>
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="logout">
<div style="display: flex; align-items: center;">
<img src="@/assets/logout.png" class="dropdown-icon" alt="" />
退出登录
</div>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
<!-- 头部结束 -->
<!-- 下面部分开始 -->
<div style="display: flex; flex-direction: column">
<!-- 顶部导航 -->
<div>
<el-menu router :default-active="router.currentRoute.value.path" class="el-menu-demo" mode="horizontal">
<!-- 动态生成菜单项,使用自定义图标 -->
<el-menu-item v-for="item in menuItems" :key="item.index" :index="item.index">
<img v-if="item.icon" :src="getIconPath(item.icon)" class="menu-icon" alt="" />
{{ item.title }}
</el-menu-item>
</el-menu>
</div>
<!-- 主体区域开始 -->
<div style="display: flex; justify-content: center; background-color: #f8f8ff; min-height: calc(100vh - 110px)">
<div style="width: 80%; max-width: 1200px; padding: 20px; background-color: white; margin: 20px; border-radius: 8px; box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1)">
<RouterView />
</div>
</div>
<!-- 主体区域结束 -->
</div>
<!-- 下面部分结束 -->
</div>
</template>
<script setup>
import router from "@/router/index.js";
import { ref, onMounted, computed } from 'vue';
// 获取用户信息
const userInfo = ref({});
const userRole = computed(() => userInfo.value.role || '');
// 获取图标路径的函数
const getIconPath = (iconName) => {
return `/src/assets/${iconName}.png`;
};
// 根据用户角色计算菜单项,图标名称改为对应的图片文件名
const menuItems = computed(() => {
const baseMenus = [
{ index: '/lender/home', title: '首页', icon: 'home' }
];
if (userRole.value === 'engineer') {
return [...baseMenus,
{ index: '/lender/work', title: '工作页', icon: 'work' }
];
}
if (userRole.value === 'admin' ) {
return [...baseMenus,
{ index: '/lender/inspect', title: '巡检', icon: 'inspect' },
{ index: '/lender/maintenance', title: '保养', icon: 'maintenance' },
{ index: '/lender/test', title: '检测', icon: 'test' },
{ index: '/lender/device', title: '设备管理', icon: 'device' },
{ index: '/lender/approve', title: '审批', icon: 'approve' },
];
}
if ( userRole.value === 'super_admin') {
return [...baseMenus,
{ index: '/lender/work', title: '工作页', icon: 'work' },
{ index: '/lender/inspect', title: '巡检', icon: 'inspect' },
{ index: '/lender/maintenance', title: '保养', icon: 'maintenance' },
{ index: '/lender/test', title: '检测', icon: 'test' },
{ index: '/lender/device', title: '设备管理', icon: 'device' },
{ index: '/lender/approve', title: '审批', icon: 'approve' },
];
}
return baseMenus;
});
// 处理下拉菜单命令
const handleCommand = (command) => {
if (command === 'logout') {
// 保存当前账号信息到localStorage
const currentAccount = userInfo.value.id || userInfo.value.username || userInfo.value.phone || userInfo.value.email;
localStorage.setItem('lastLoginAccount', currentAccount);
// 清除用户信息
localStorage.removeItem('userInfo');
// 跳转到登录页
router.push('/login');
}
};
onMounted(() => {
// 从localStorage获取用户信息
const storedUserInfo = localStorage.getItem('userInfo');
if (storedUserInfo) {
userInfo.value = JSON.parse(storedUserInfo);
}
});
</script>
<style scoped>
.el-menu .is-active{
background-color: #e6ecf7;
}
/* 添加菜单图标样式 */
.menu-icon {
width: 20px;
height: 20px;
margin-right: 5px;
vertical-align: middle;
}
/* 添加下拉菜单图标样式 */
.dropdown-icon {
width: 16px;
height: 16px;
margin-right: 8px;
vertical-align: middle;
}
</style>
login.vue
<!-- vivy -->
<!-- 05/4/14 -->
<template>
<div class="login-container">
<div class="login-box">
<el-card class="login-card">
<div class="logo-container">
<img src="@/assets/logo.png" alt="Logo" class="logo-image">
<h2 class="login-title">系统登录</h2>
</div>
<el-form :model="loginForm" :rules="loginRules" ref="loginFormRef">
<el-form-item prop="account">
<el-input
v-model="loginForm.account"
placeholder="工号/用户名/手机号/邮箱"
prefix-icon="User"
class="custom-input"
/>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="loginForm.password"
type="password"
placeholder="密码"
prefix-icon="Lock"
show-password
class="custom-input"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" :loading="loading" @click="handleLogin" class="login-button">
登录
</el-button>
</el-form-item>
<div class="register-link">
还没有账号?<el-link type="primary" @click="goToRegister">立即注册</el-link>
</div>
</el-form>
</el-card>
</div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { login } from '@/api/user'
const router = useRouter()
const loading = ref(false)
const loginFormRef = ref(null)
const loginForm = reactive({
account: '',
password: ''
})
const loginRules = {
account: [{ required: true, message: '请输入账号', trigger: 'blur' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
}
const handleLogin = async () => {
if (!loginFormRef.value) return
await loginFormRef.value.validate(async (valid) => {
if (valid) {
loading.value = true
try {
const res = await login(loginForm)
if (res.code === 200) {
ElMessage.success('登录成功')
// 存储用户信息到本地存储
localStorage.setItem('userInfo', JSON.stringify(res.data))
// 所有角色都跳转到同一个首页
router.push('/lender/home')
} else {
ElMessage.error(res.msg || '登录失败')
}
} catch (error) {
console.error('登录错误:', error)
ElMessage.error('登录失败,请稍后重试')
} finally {
loading.value = false
}
}
})
}
const goToRegister = () => {
router.push('/register')
}
onMounted(() => {
// 获取上次登录的账号信息
const lastLoginAccount = localStorage.getItem('lastLoginAccount')
if (lastLoginAccount) {
loginForm.account = lastLoginAccount
}
})
</script>
<style scoped>
.login-container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-image: linear-gradient(to right, #8686e0, #a5a5f3);
background-size: cover;
position: relative;
}
.login-container::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url('@/assets/bg-pattern.png') repeat;
opacity: 0.1;
}
.login-box {
position: relative;
z-index: 1;
width: 100%;
max-width: 450px;
padding: 0 20px;
}
.login-card {
width: 100%;
border-radius: 12px;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
padding: 10px;
background-color: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
transition: all 0.3s ease;
}
.login-card:hover {
transform: translateY(-5px);
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.15);
}
.logo-container {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 30px;
}
.logo-image {
width: 80px;
height: 80px;
margin-bottom: 15px;
}
.login-title {
text-align: center;
color: #8686e0;
font-size: 24px;
font-weight: 600;
margin: 0;
}
.custom-input :deep(.el-input__wrapper) {
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
padding: 4px 12px;
transition: all 0.3s;
}
.custom-input :deep(.el-input__wrapper:hover) {
box-shadow: 0 2px 12px rgba(134, 134, 224, 0.2);
}
.custom-input :deep(.el-input__wrapper.is-focus) {
box-shadow: 0 0 0 1px #8686e0 inset;
}
.login-button {
width: 100%;
height: 44px;
border-radius: 8px;
font-size: 16px;
background-color: #8686e0;
border-color: #8686e0;
transition: all 0.3s;
}
.login-button:hover {
background-color: #7575d0;
border-color: #7575d0;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(134, 134, 224, 0.3);
}
.register-link {
text-align: center;
margin-top: 20px;
font-size: 14px;
}
.register-link .el-link {
color: #8686e0;
font-weight: 500;
}
</style>
home.vue:
<!-- vivy -->
<!-- 05/4/25 统一首页 -->
<template>
<div class="home-container">
<el-row :gutter="20">
<!-- 左侧个人信息卡片 -->
<el-col :span="8">
<el-card class="user-card">
<div class="user-info">
<img src="../assets/user.png" alt="" style="width: 120px; height: 120px; border-radius: 50%;">
<h3>{{ userInfo.username || '用户' }}</h3>
<p>工号: {{ userInfo.id || '-' }}</p>
<p>电话: {{ userInfo.phone || '-' }}</p>
</div>
<el-divider></el-divider>
<div class="stats">
<div class="stat-item">
<h4>待处理任务</h4>
<p class="stat-value">{{ pendingTasks }}</p>
</div>
<div class="stat-item">
<h4>已完成任务</h4>
<p class="stat-value">{{ completedTasks }}</p>
</div>
</div>
</el-card>
</el-col>
<!-- 右侧内容区域 -->
<el-col :span="16">
<!-- Engineer和Super_admin显示待处理任务 -->
<el-card v-if="userRole === 'engineer' || userRole === 'super_admin'" class="task-card">
<template #header>
<div class="card-header">
<span>待接取任务</span>
<el-button
v-if="userRole === 'engineer'"
type="primary"
size="small"
@click="$router.push('/lender/work')"
>
查看全部任务
</el-button>
</div>
</template>
<div class="task-container">
<el-empty v-if="recentTasks.length === 0" description="暂无待处理维修任务"></el-empty>
<div v-else class="task-list">
<div v-for="task in recentTasks" :key="task.taskId" class="task-item">
<div class="task-info">
<h4>维修任务 #{{ task.faultId }}</h4>
<p>设备编号: {{ task.deviceId }}</p>
<p>故障描述: {{ task.faultDesc }}</p>
</div>
<div class="task-action">
<el-tag :type="getStatusType(task.status)">{{ task.status }}</el-tag>
<el-button
size="small"
type="primary"
@click="handleTakeTask(task)"
style="margin-top: 10px;"
>
接取维修任务
</el-button>
</div>
</div>
</div>
</div>
</el-card>
<!-- Admin和Super_admin显示故障列表 -->
<el-card v-if="userRole === 'admin' || userRole === 'super_admin'"
class="fault-card"
:style="userRole === 'super_admin' ? 'margin-top: 20px;' : ''">
<template #header>
<div class="card-header">
<span>设备故障列表</span>
<el-button type="primary" size="small" @click="showAddFaultDialog">添加故障报修</el-button>
</div>
</template>
<div class="table-container">
<el-table :data="faultList" border style="width: 100%" height="350">
<el-table-column prop="faultId" label="故障编号" width="90" />
<el-table-column prop="deviceId" label="设备编号" width="90" />
<el-table-column prop="faultDesc" label="故障描述" min-width="120" show-overflow-tooltip />
<el-table-column prop="reportType" label="报修类型" width="90" />
<el-table-column prop="reportedName" label="报修人" width="80" />
<el-table-column prop="reportedPhone" label="联系电话" width="110" />
<el-table-column prop="status" label="状态" width="80">
<template #default="scope">
<el-tag :type="getStatusType(scope.row.status)">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
</el-table>
</div>
</el-card>
<!-- 设备状态统计 -->
<el-card class="device-card" style="margin-top: 20px;">
<template #header>
<div class="card-header">
<span>设备状态概览</span>
</div>
</template>
<!-- 替换原来的状态框为图表 -->
<div class="chart-container">
<v-chart class="chart" :option="chartOption" autoresize />
</div>
</el-card>
</el-col>
</el-row>
<!-- 添加故障报修对话框 -->
<el-dialog
title="设备故障报修"
v-model="dialogVisible"
width="500px"
>
<el-form :model="faultForm" label-width="80px">
<el-form-item label="设备编号">
<el-select v-model="faultForm.deviceId" style="width: 100%">
<el-option
v-for="device in deviceList"
:key="device.deviceId"
:label="device.deviceId + ' - ' + device.deviceType"
:value="device.deviceId"
:disabled="device.status !== '正常'"
/>
</el-select>
</el-form-item>
<el-form-item label="故障描述">
<el-input type="textarea" v-model="faultForm.faultDesc" rows="3" />
</el-form-item>
<el-form-item label="报修类型">
<el-select v-model="faultForm.reportType" style="width: 100%">
<el-option label="自主报修" value="自主报修" />
<el-option label="电话报修" value="电话报修" />
</el-select>
</el-form-item>
<el-form-item label="报修人">
<el-input v-model="faultForm.reportedName" readonly />
</el-form-item>
<el-form-item label="联系电话">
<el-input v-model="faultForm.reportedPhone" readonly />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSubmit">提交报修</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, onMounted, computed, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { getDeviceList, updateDeviceStatus, getDeviceStats } from '@/api/device'
import { addDeviceFault } from '@/api/deviceFault'
import { createRepairOrder } from '@/api/repairOrder'
// 引入 ECharts 组件
import VChart from 'vue-echarts'
import { use } from 'echarts/core'
import { BarChart } from 'echarts/charts'
import {
TitleComponent,
TooltipComponent,
GridComponent,
LegendComponent
} from 'echarts/components'
import { CanvasRenderer } from 'echarts/renderers'
// 注册 ECharts 组件
use([
BarChart,
TitleComponent,
TooltipComponent,
GridComponent,
LegendComponent,
CanvasRenderer
])
// 用户信息
const userInfo = ref({})
const userRole = computed(() => userInfo.value.role || '')
// 任务统计
const pendingTasks = ref(2)
const completedTasks = ref(5)
// 设备状态统计
const deviceStats = ref({
normal: 0,
fault: 0,
maintenance: 0,
scrapped: 0
})
// 图表配置
const chartOption = computed(() => {
return {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
data: ['正常', '故障', '维护中', '报废'],
axisTick: {
alignWithLabel: true
}
},
yAxis: {
type: 'value',
minInterval: 1 // 确保y轴刻度为整数
},
series: [
{
name: '设备数量',
type: 'bar',
barWidth: '60%',
data: [
{
value: deviceStats.value.normal,
itemStyle: { color: '#67C23A' }
},
{
value: deviceStats.value.fault,
itemStyle: { color: '#F56C6C' }
},
{
value: deviceStats.value.maintenance,
itemStyle: { color: '#E6A23C' }
},
{
value: deviceStats.value.scrapped,
itemStyle: { color: '#909399' }
}
],
label: {
show: true,
position: 'top',
formatter: '{c}'
}
}
]
}
})
// 监听设备统计数据变化,更新图表
watch(deviceStats, () => {
// 数据变化时图表会自动更新
}, { deep: true })
// 获取设备状态统计
const fetchDeviceStats = async () => {
try {
const res = await getDeviceStats()
if (res.code === 200) {
deviceStats.value = res.data || {
normal: 0,
fault: 0,
maintenance: 0,
scrapped: 0
}
} else {
console.error('获取设备统计失败:', res.msg)
}
} catch (error) {
console.error('获取设备统计错误:', error)
}
}
// 最近任务
const recentTasks = ref([])
// 获取待处理故障任务
const fetchPendingFaults = async () => {
try {
const res = await getPendingFaults()
if (res.code === 200) {
recentTasks.value = res.data || []
} else {
ElMessage.error(res.msg || '获取待处理故障任务失败')
}
} catch (error) {
console.error('获取待处理故障任务错误:', error)
ElMessage.error('获取待处理故障任务失败')
}
}
// 故障列表相关
const faultList = ref([])
const deviceList = ref([])
const dialogVisible = ref(false)
const faultForm = ref({
deviceId: '',
faultDesc: '',
reportType: '自主报修',
reportedId: '',
reportedName: '',
reportedPhone: ''
})
// 获取故障列表
const fetchFaultList = async () => {
try {
const res = await getFaultList()
if (res.code === 200) {
faultList.value = res.data || []
} else {
ElMessage.error(res.msg || '获取故障列表失败')
}
} catch (error) {
console.error('获取故障列表错误:', error)
ElMessage.error('获取故障列表失败')
}
}
// 获取设备列表
const fetchDeviceList = async () => {
try {
const res = await getDeviceList()
if (res.code === 200) {
deviceList.value = res.data || []
}
} catch (error) {
console.error('获取设备列表失败:', error)
}
}
// 获取状态标签类型
const getStatusType = (status) => {
const statusMap = {
'待处理': 'info',
'处理中': 'warning',
'进行中': 'warning',
'已解决': 'success',
'已完成': 'success',
'待审批': 'warning',
'已关闭': ''
}
return statusMap[status] || ''
}
// 设置默认用户信息
const setDefaultUserInfo = () => {
const userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}')
faultForm.value.reportedId = userInfo.id || ''
faultForm.value.reportedName = userInfo.username || ''
faultForm.value.reportedPhone = userInfo.phone || ''
}
// 显示添加故障报修对话框
const showAddFaultDialog = () => {
// 重置表单
faultForm.value = {
deviceId: '',
faultDesc: '',
reportType: '自主报修',
reportedId: '',
reportedName: '',
reportedPhone: ''
}
// 设置用户信息
setDefaultUserInfo()
dialogVisible.value = true
}
// 提交报修
const handleSubmit = async () => {
try {
const res = await addDeviceFault(faultForm.value)
if (res.code === 200) {
ElMessage.success('报修成功')
dialogVisible.value = false
// 刷新故障列表
fetchFaultList()
} else {
ElMessage.error(res.msg || '报修失败')
}
} catch (error) {
console.error('报修失败:', error)
ElMessage.error('报修失败')
}
}
// 接取任务
import { getFaultList, getPendingFaults, updateFaultStatus } from '@/api/deviceFault' // 添加 updateFaultStatus
const handleTakeTask = async (task) => {
try {
const userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}')
// 获取安全须知内容
const safetyNotice = `一、安全防护
穿戴防护装备:工作服、手套、安全帽、防护眼镜等。
设备断电锁定:切断电源,锁定设备,挂警示牌。
环境安全:保持工作区域整洁,高处作业系安全带。
二、维修前准备
工具检查:确保工具齐全、绝缘良好。
备件准备:确认规格匹配,准备备用件。
查阅资料:熟悉设备结构和维修要点。
三、维修过程
故障诊断:观察现象,记录症状,逐步排查。
操作规范:按手册操作,标记拆卸部件。
数据备份:备份重要数据,确保安全。
清洁维护:清理灰尘,检查润滑部件。
四、维修后测试
功能测试:启动设备,检查功能是否正常。
性能检查:确认运行参数正常。
安全检查:检查外壳、防护装置是否牢固。
五、记录与总结
记录信息:记录设备信息、维修过程、测试结果。
总结经验:分析故障原因,提出改进措施。
六、其他注意
遵守制度:严格按流程操作,妥善处理废弃物。`
const repairOrderData = {
faultId: task.faultId,
engineerId: userInfo.id,
repairDesc: '',
status: '处理中',
safetyNotice: safetyNotice
}
const res = await createRepairOrder(repairOrderData)
if (res.code === 200) {
// 更新故障状态为处理中
const updateFaultRes = await updateFaultStatus({
faultId: task.faultId,
status: '处理中'
})
if (updateFaultRes.code === 200) {
// 更新设备状态为维护中
try {
const updateDeviceRes = await updateDeviceStatus({
deviceId: task.deviceId,
status: '维护中'
})
if (updateDeviceRes.code === 200) {
ElMessage.success('维修任务接取成功')
// 刷新数据
fetchPendingFaults()
fetchDeviceList()
fetchFaultList()
} else {
ElMessage.warning('任务已接取,但设备状态更新失败')
}
} catch (error) {
console.error('更新设备状态失败:', error)
ElMessage.warning('任务已接取,但设备状态更新失败')
}
} else {
ElMessage.warning('任务已接取,但故障状态更新失败')
}
} else {
ElMessage.error(res.msg || '接取任务失败')
}
} catch (error) {
console.error('接取任务失败:', error)
ElMessage.error('接取任务失败')
}
}
onMounted(() => {
// 从localStorage获取用户信息
const storedUserInfo = localStorage.getItem('userInfo')
if (storedUserInfo) {
userInfo.value = JSON.parse(storedUserInfo)
}
// 获取数据
fetchFaultList()
fetchDeviceList()
fetchPendingFaults()
fetchDeviceStats() // 添加获取设备统计数据
})
</script>
<style scoped>
.home-container {
padding: 20px;
}
.user-card {
height: 100%;
}
.user-info {
text-align: center;
padding: 10px 0;
}
.user-info h3 {
margin: 10px 0 5px;
}
.user-info p {
margin: 5px 0;
color: #666;
}
.stats {
display: flex;
justify-content: space-around;
text-align: center;
}
.stat-item h4 {
margin-bottom: 5px;
font-weight: normal;
color: #666;
}
.stat-value {
font-size: 24px;
font-weight: bold;
color: #409EFF;
margin: 0;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.task-container {
height: 350px;
overflow-y: auto;
}
.task-list {
display: flex;
flex-direction: column;
gap: 15px;
padding-right: 5px;
}
/* 自定义滚动条样式 */
.task-container::-webkit-scrollbar {
width: 6px;
}
.task-container::-webkit-scrollbar-thumb {
background-color: #dcdfe6;
border-radius: 3px;
}
.task-container::-webkit-scrollbar-track {
background-color: #f5f7fa;
}
.task-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
background-color: #f8f9fa;
border-radius: 4px;
}
.task-info h4 {
margin: 0 0 10px 0;
font-size: 16px;
color: #333;
}
.task-info p {
margin: 5px 0;
color: #666;
}
.task-action {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 10px;
}
.task-action .el-button {
margin-left: 0;
}
.status-box {
text-align: center;
padding: 15px;
border-radius: 4px;
color: white;
}
.status-box h3 {
margin: 0 0 10px 0;
font-size: 16px;
}
.status-box p {
margin: 0;
font-size: 24px;
font-weight: bold;
}
.normal {
background-color: #67C23A;
}
.fault {
background-color: #F56C6C;
}
.maintenance {
background-color: #E6A23C;
}
.scrapped {
background-color: #909399;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
}
.table-container {
width: 100%;
overflow: hidden;
}
.el-table {
margin-bottom: 10px;
}
/* 添加图表容器样式 */
.chart-container {
width: 100%;
height: 300px;
}
.chart {
width: 100%;
height: 100%;
}
</style>
DeviceFault:
package com.example.demo.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("device_faults")
public class DeviceFault {
@TableId(type = IdType.AUTO)
private Integer faultId;
private String deviceId;
private String faultDesc;
private String reportType;
private String reportedId;
private String reportedName;
private String reportedPhone;
private String status;
public Integer getFaultId() {
return faultId;
}
public void setFaultId(Integer faultId) {
this.faultId = faultId;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getFaultDesc() {
return faultDesc;
}
public void setFaultDesc(String faultDesc) {
this.faultDesc = faultDesc;
}
public String getReportType() {
return reportType;
}
public void setReportType(String reportType) {
this.reportType = reportType;
}
public String getReportedId() {
return reportedId;
}
public void setReportedId(String reportedId) {
this.reportedId = reportedId;
}
public String getReportedName() {
return reportedName;
}
public void setReportedName(String reportedName) {
this.reportedName = reportedName;
}
public String getReportedPhone() {
return reportedPhone;
}
public void setReportedPhone(String reportedPhone) {
this.reportedPhone = reportedPhone;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
DeviceFaultController:
package com.example.demo.controller;
import com.example.demo.common.Result;
import com.example.demo.entity.DeviceFault;
import com.example.demo.service.DeviceFaultService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/*
* Qi
* 25/4/22
* 设备的报修
* */
@RestController
@RequestMapping("/device-fault")
public class DeviceFaultController {
@Autowired
private DeviceFaultService deviceFaultService;
@GetMapping("/list")
public Result getAllFaults() {
return Result.success(deviceFaultService.getAllFaults());
}
@GetMapping("/pending")
public Result getPendingFaults() {
List<DeviceFault> pendingFaults = deviceFaultService.getPendingFaults();
return Result.success(pendingFaults);
}
@GetMapping("/{faultId}")
public Result getFault(@PathVariable Integer faultId) {
DeviceFault fault = deviceFaultService.getFaultById(faultId);
return fault != null ? Result.success(fault) : Result.fail("故障记录不存在");
}
@PostMapping("/add")
public Result addFault(@RequestBody DeviceFault deviceFault) {
if (deviceFaultService.addFault(deviceFault)) {
return Result.success(deviceFault);
}
return Result.fail("添加故障记录失败,请确认设备是否存在");
}
@PutMapping("/update")
public Result updateFault(@RequestBody DeviceFault deviceFault) {
if (deviceFaultService.updateFault(deviceFault)) {
return Result.success(deviceFault);
}
return Result.fail("更新故障记录失败");
}
@PutMapping("/status")
public Result updateFaultStatus(@RequestBody DeviceFault deviceFault) {
if (deviceFaultService.updateFaultStatus(deviceFault.getFaultId(), deviceFault.getStatus())) {
return Result.success(deviceFault);
}
return Result.fail("更新故障状态失败");
}
}
DeviceFaultMapper:
package com.example.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.DeviceFault;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface DeviceFaultMapper extends BaseMapper<DeviceFault> {
}
DeviceFaultService:
package com.example.demo.service;
import com.example.demo.entity.DeviceFault;
import java.util.List;
/*
* Qi
* 25/4/22
* 设备的报修
* */
public interface DeviceFaultService {
List<DeviceFault> getAllFaults();
DeviceFault getFaultById(Integer faultId);
boolean addFault(DeviceFault deviceFault);
boolean updateFault(DeviceFault deviceFault);
List<DeviceFault> getPendingFaults();
boolean updateFaultStatus(Integer faultId, String status);
}
DeviceFaultServiceImpl:
package com.example.demo.service.impl;
import com.example.demo.entity.Device;
import com.example.demo.entity.DeviceFault;
import com.example.demo.mapper.DeviceFaultMapper;
import com.example.demo.mapper.DeviceMapper;
import com.example.demo.service.DeviceFaultService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/*
* Qi
* 25/4/22
* 设备的报修
* */
@Service
public class DeviceFaultServiceImpl implements DeviceFaultService {
@Autowired
private DeviceFaultMapper deviceFaultMapper;
@Autowired
private DeviceMapper deviceMapper;
@Override
public List<DeviceFault> getAllFaults() {
return deviceFaultMapper.selectList(null);
}
@Override
public DeviceFault getFaultById(Integer faultId) {
return deviceFaultMapper.selectById(faultId);
}
@Override
@Transactional
public boolean addFault(DeviceFault deviceFault) {
// 检查设备是否存在
Device device = deviceMapper.selectById(deviceFault.getDeviceId());
if (device == null) {
return false;
}
// 设置初始状态
deviceFault.setStatus("待处理");
// 添加故障记录
int result = deviceFaultMapper.insert(deviceFault);
if (result > 0) {
// 更新设备状态为故障
device.setStatus("故障");
deviceMapper.updateById(device);
return true;
}
return false;
}
@Override
public boolean updateFault(DeviceFault deviceFault) {
return deviceFaultMapper.updateById(deviceFault) > 0;
}
@Override
public boolean updateFaultStatus(Integer faultId, String status) {
DeviceFault deviceFault = deviceFaultMapper.selectById(faultId);
if (deviceFault != null) {
deviceFault.setStatus(status);
return deviceFaultMapper.updateById(deviceFault) > 0;
}
return false;
}
@Override
public List<DeviceFault> getPendingFaults() {
QueryWrapper<DeviceFault> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("status", "待处理");
return deviceFaultMapper.selectList(queryWrapper);
}
}
deviceFault.js:
import request from '@/utils/request'
export function getFaultList() {
return request({
url: '/device-fault/list',
method: 'get'
})
}
export function getFault(faultId) {
return request({
url: `/device-fault/${faultId}`,
method: 'get'
})
}
export function addDeviceFault(data) {
return request({
url: '/device-fault/add',
method: 'post',
data
})
}
export function updateDeviceFault(data) {
return request({
url: '/device-fault/update',
method: 'put',
data
})
}
export function updateFaultStatus(data) {
return request({
url: '/device-fault/status',
method: 'put',
data
})
}
export function getPendingFaults() {
return request({
url: '/device-fault/pending',
method: 'get'
})
}

浙公网安备 33010602011771号