This commit is contained in:
Teo
2025-09-12 19:38:17 +08:00
15 changed files with 3197 additions and 167 deletions

View File

@ -106,6 +106,6 @@ export const getFootNote = (data) => {
return request({
url: 'gps/equipmentSon/getList',
method: 'get',
data: data
params: data
});
};

View File

@ -122,6 +122,11 @@ export interface EquipmentQuery extends PageQuery {
*/
type?: string | number;
/**
* 展示用户/设备数据1=用户数据0=设备数据
*/
gpsType?: string | number;
/**
* 用户id
*/

View File

@ -1,30 +1,31 @@
<template>
<el-row>
<el-col>
<div style="color: rgba(0, 30, 59, 1);;font-family: 'Alibaba-PuHuiTi-Bold';margin: 10px 0 0 0;"
:style="{ fontSize: fontLevelMap[props.fontLevel] }">
{{ props.title }}
</div>
</el-col>
<el-col>
<p style="color: rgba(154, 154, 154, 1);font-size: 14px;">
{{ props.subtitle }}
</p>
</el-col>
</el-row>
<el-row>
<el-col>
<div
style="color: rgba(0, 30, 59, 1); font-family: 'Alibaba-PuHuiTi-Bold'; margin: 10px 0 0 0"
:style="{ fontSize: fontLevelMap[props.fontLevel] }"
>
{{ props.title }}
</div>
</el-col>
<el-col>
<p style="color: rgba(154, 154, 154, 1); font-size: 14px">
{{ props.subtitle }}
</p>
</el-col>
</el-row>
</template>
<script setup>
const props = defineProps({
title: String,
subtitle: String,
fontLevel: {
type: Number,
default: 1
}
})
title: String,
subtitle: String,
fontLevel: {
type: Number,
default: 1
}
});
const fontLevelMap = {
1: "24px",
2: "18px"
}
</script>
1: '24px',
2: '18px'
};
</script>

View File

@ -0,0 +1,756 @@
<template>
<div>
<div class="operation-inspection">
<div class="navigation-tabs">
<div class="nav-tab" @click="handleInspection1">待办事项</div>
<div class="nav-tab active" @click="handleInspection2">巡检管理</div>
<div class="nav-tab">试验管理</div>
<div class="nav-tab">报修管理</div>
<div class="nav-tab">抢修管理</div>
<div class="nav-tab">工单管理</div>
</div>
<TitleComponent title="运维巡检管理" subtitle="制定巡检计划,安排巡检任务,跟进巡检记录"></TitleComponent>
<!-- 选项卡和按钮组合 -->
<div class="tabs-wrapper">
<div style="display: flex; align-items: center; gap: 10px">
<el-button type="primary" @click="handleInspectionManagement1">巡检计划</el-button>
<el-button type="primary" @click="handleInspectionManagement2">巡检任务</el-button>
<el-button type="primary" @click="handleInspectionManagement3">巡检记录</el-button>
</div>
</div>
<!-- 筛选栏 -->
<div class="filter-bar">
<div class="filter-item">
<el-select v-model="planType" placeholder="计划类型" clearable>
<el-option label="全部类型" value="all"></el-option>
<el-option label="每日巡检" value="daily"></el-option>
<el-option label="每周巡检" value="weekly"></el-option>
<el-option label="每月巡检" value="monthly"></el-option>
<el-option label="每季度巡检" value="quarterly"></el-option>
</el-select>
</div>
<div class="filter-item">
<el-select v-model="status" placeholder="全部状态" clearable>
<el-option label="全部状态" value="all"></el-option>
<el-option label="启用中" value="enabled"></el-option>
<el-option label="已停用" value="disabled"></el-option>
</el-select>
</div>
<div class="filter-item">
<el-select v-model="inspectionObject" placeholder="巡检对象" clearable>
<el-option label="全部对象" value="all"></el-option>
<el-option label="服务器" value="server"></el-option>
<el-option label="网络设备" value="network"></el-option>
<el-option label="应用系统" value="application"></el-option>
<el-option label="基础设施" value="infrastructure"></el-option>
</el-select>
</div>
<div class="filter-actions">
<el-button type="primary" class="search-btn">搜索</el-button>
<el-button type="primary" icon="el-icon-plus" class="create-btn" @click="handleCreate">手动创建计划</el-button>
</div>
</div>
<!-- 表格 -->
<div class="table-wrapper">
<el-table :data="pagedTableData" stripe style="width: 100%" highlight-current-row class="custom-table">
<el-table-column align="center" prop="name" label="计划名称" style="width: 14.2%"></el-table-column>
<el-table-column align="center" prop="type" label="类型" style="width: 14.2%"></el-table-column>
<el-table-column align="center" prop="object" label="巡检对象" style="width: 14.2%"></el-table-column>
<el-table-column align="center" prop="frequency" label="频率" style="width: 14.2%"></el-table-column>
<el-table-column align="center" prop="status" label="状态" style="width: 14.2%">
<template #default="scope">
<el-tag :type="scope.row.status === 'enabled' ? 'success' : 'info'" class="status-tag">
{{ scope.row.status === 'enabled' ? '启用中' : '已停用' }}
</el-tag>
</template>
</el-table-column>
<el-table-column align="center" prop="responsible" label="负责人" style="width: 14.2%"></el-table-column>
<el-table-column align="center" label="操作" style="width: 14.2%" fixed="right">
<template #default="scope">
<el-button type="text" @click="handleEdit(scope.row)" size="small" class="action-btn">编辑</el-button>
<el-button type="text" @click="handleDetail(scope.row)" size="small" class="action-btn">详情</el-button>
<el-button
type="text"
:disabled="scope.row.status === 'disabled'"
@click="handleEnable(scope.row)"
size="small"
class="action-btn"
:class="{ 'text-success': scope.row.status === 'disabled' }"
>
{{ scope.row.status === 'enabled' ? '停用' : '启用' }}
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页区域 -->
<div class="pagination-section">
<div class="pagination-info">
显示第{{ (currentPage - 1) * pageSize + 1 }}{{ Math.min(currentPage * pageSize, total) }}共有{{ total }}条记录
</div>
<div class="pagination-controls">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[10, 20, 30, 40]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
background
>
</el-pagination>
</div>
</div>
</div>
<!-- 创建计划弹窗 -->
<el-dialog v-model="dialogVisible" title="新建巡检计划" width="700px" class="create-plan-dialog" center :show-close="true">
<el-form :model="createForm" :rules="createFormRules" ref="createFormRef" label-width="150px" class="custom-form">
<el-form-item label="计划名称*" prop="planName" class="form-item-large">
<el-input v-model="createForm.planName" placeholder="请输入计划名称" class="custom-input" />
</el-form-item>
<div class="form-row">
<el-form-item label="计划类型*" prop="planType" class="form-item-half">
<el-select v-model="createForm.planType" placeholder="请选择计划类型" class="custom-select">
<el-option label="每日巡检" value="daily" />
<el-option label="每周巡检" value="weekly" />
<el-option label="每月巡检" value="monthly" />
<el-option label="每季度巡检" value="quarterly" />
</el-select>
</el-form-item>
<el-form-item label="巡检对象类型*" prop="objectType" class="form-item-half">
<el-select v-model="createForm.objectType" placeholder="请选择对象类型" class="custom-select">
<el-option label="服务器" value="server" />
<el-option label="网络设备" value="network" />
<el-option label="应用系统" value="application" />
<el-option label="基础设施" value="infrastructure" />
</el-select>
</el-form-item>
</div>
<div class="form-row">
<el-form-item label="开始日期*" prop="startDate" class="form-item-half">
<el-date-picker
v-model="createForm.startDate"
type="date"
placeholder="选择日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
class="custom-date-picker"
/>
</el-form-item>
<el-form-item label="结束日期*" prop="endDate" class="form-item-half">
<el-date-picker
v-model="createForm.endDate"
type="date"
placeholder="选择日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
class="custom-date-picker"
/>
</el-form-item>
</div>
<el-form-item label="巡检频率*" class="form-item-large">
<div style="display: flex; align-items: center; gap: 20px">
<el-radio-group v-model="createForm.frequencyType" class="frequency-radio-group">
<el-radio label="daily">每天</el-radio>
<el-radio label="weekly">每周</el-radio>
<el-radio label="monthly">每月</el-radio>
</el-radio-group>
<!-- 每周选择框 - 变小并排在单选框后面 -->
<el-select
v-if="createForm.frequencyType === 'weekly'"
v-model="createForm.weekday"
placeholder="选择周几"
class="custom-select-small"
style="width: 100px"
>
<el-option label="周一" value="1" />
<el-option label="周二" value="2" />
<el-option label="周三" value="3" />
<el-option label="周四" value="4" />
<el-option label="周五" value="5" />
<el-option label="周六" value="6" />
<el-option label="周日" value="0" />
</el-select>
<!-- 每月选择框 - 变小并排在单选框后面 -->
<el-select
v-if="createForm.frequencyType === 'monthly'"
v-model="createForm.monthday"
placeholder="选择几号"
class="custom-select-small"
style="width: 100px"
>
<template v-for="day in 31" :key="day">
<el-option :label="day + '号'" :value="day" />
</template>
</el-select>
</div>
</el-form-item>
<div class="form-row" s>
<el-form-item label="计划开始时间*" prop="startTime" class="form-item-half">
<el-time-picker v-model="createForm.startTime" placeholder="选择时间" format="HH:mm" value-format="HH:mm" class="custom-time-picker" />
</el-form-item>
<el-form-item label="预计时长(分钟)" class="form-item-half">
<el-input v-model.number="createForm.estimatedDuration" class="custom-input" />
</el-form-item>
</div>
<el-form-item label="负责人*" prop="responsiblePerson" class="form-item-large">
<el-select v-model="createForm.responsiblePerson" placeholder="请选择负责人" class="custom-select">
<el-option label="张明" value="zhangming" />
<el-option label="李华" value="lihua" />
<el-option label="王强" value="wangqiang" />
</el-select>
</el-form-item>
<el-form-item label="巡检项*" class="form-item-large">
<el-checkbox-group v-model="createForm.inspectionItems" style="border: 0.1 solid black; padding: 5px">
<el-checkbox label="CPU使用率检查" />
<el-checkbox label="内存使用情况" />
<el-checkbox label="磁盘空间检查" />
<el-checkbox label="网络连接状态" />
<el-checkbox label="系统日志检查" />
</el-checkbox-group>
</el-form-item>
<el-form-item label="备注说明" prop="remarks" class="form-item-large">
<el-input v-model="createForm.remarks" type="textarea" placeholder="请输入备注" rows="3" class="custom-textarea" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="cancelCreatePlan">取消</el-button>
<el-button type="primary" @click="submitCreatePlan">新增任务</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
// 表单引用
const createFormRef = ref(null);
import { ref, computed, reactive } from 'vue';
import router from '@/router';
import TitleComponent from '@/views/demo/components/TitleComponent.vue';
// 激活的选项卡
const activeTab = ref('plan');
// 计划类型
const planType = ref('all');
// 状态
const status = ref('all');
// 巡检对象
const inspectionObject = ref('all');
// 原始表格数据
const rawTableData = ref([
{
name: '生产服务器每日巡检 2025-05-14',
type: '每日巡检',
object: '服务器',
frequency: '每天8:30',
status: 'enabled',
responsible: '张明'
},
{
name: '网络设备安全巡检 2025-04-15',
type: '每周巡检',
object: '网络设备',
frequency: '每天10:30',
status: 'enabled',
responsible: '张明'
},
{
name: '数据库性能巡检 2025-03-03',
type: '每月巡检',
object: '应用系统',
frequency: '每月1日14:00',
status: 'disabled',
responsible: '张明'
},
{
name: '机房环境季度检查',
type: '每季度巡检',
object: '基础设备',
frequency: '每季度第一个月5号',
status: 'enabled',
responsible: '张明'
},
{
name: '生产服务器每日巡检 2025-05-14',
type: '每日巡检',
object: '服务器',
frequency: '每天8:30',
status: 'enabled',
responsible: '张明'
},
{
name: '生产服务器每日巡检 2025-05-14',
type: '每日巡检',
object: '服务器',
frequency: '每天8:30',
status: 'enabled',
responsible: '张明'
},
{
name: '生产服务器每日巡检 2025-05-14',
type: '每日巡检',
object: '服务器',
frequency: '每天8:30',
status: 'enabled',
responsible: '张明'
},
{
name: '生产服务器每日巡检 2025-05-14',
type: '每日巡检',
object: '服务器',
frequency: '每天8:30',
status: 'enabled',
responsible: '张明'
},
{
name: '生产服务器每日巡检 2025-05-14',
type: '每日巡检',
object: '服务器',
frequency: '每天8:30',
status: 'enabled',
responsible: '张明'
},
{
name: '生产服务器每日巡检 2025-05-14',
type: '每日巡检',
object: '服务器',
frequency: '每天8:30',
status: 'enabled',
responsible: '张明'
},
{
name: '生产服务器每日巡检 2025-05-14',
type: '每日巡检',
object: '服务器',
frequency: '每天8:30',
status: 'enabled',
responsible: '张明'
},
// 增加更多数据用于测试分页
{
name: '应用系统安全检查',
type: '每周巡检',
object: '应用系统',
frequency: '每周五16:00',
status: 'enabled',
responsible: '李华'
},
{
name: '网络带宽监控',
type: '每日巡检',
object: '网络设备',
frequency: '每天12:00',
status: 'enabled',
responsible: '王强'
}
]);
// 当前页码
const currentPage = ref(1);
// 每页条数 - 与分页控件默认值保持一致
const pageSize = ref(10);
// 总条数 - 从原始数据计算得出
const total = ref(rawTableData.value.length);
// 计算属性:根据当前页码和每页条数获取分页后的数据
const pagedTableData = computed(() => {
const startIndex = (currentPage.value - 1) * pageSize.value;
const endIndex = startIndex + pageSize.value;
return rawTableData.value.slice(startIndex, endIndex);
});
// 每页条数改变
const handleSizeChange = (val) => {
pageSize.value = val;
currentPage.value = 1; // 重置到第一页
};
// 当前页码改变
const handleCurrentChange = (val) => {
currentPage.value = val;
};
// 编辑
const handleEdit = (row) => {
console.log('编辑', row);
};
// 详情
const handleDetail = (row) => {
console.log('详情', row);
};
// 启用/停用
const handleEnable = (row) => {
row.status = row.status === 'enabled' ? 'disabled' : 'enabled';
};
// 选项卡切换
const handleTabChange = (newTab, oldTab) => {
// 可以在这里添加选项卡切换时的逻辑
console.log('选项卡切换:', newTab, oldTab);
return true;
};
// 创建计划弹窗相关
const dialogVisible = ref(false);
const createForm = reactive({
planName: '',
planType: '',
objectType: '',
startDate: '',
endDate: '',
frequencyType: 'daily',
frequencyValue: '',
weekday: '', // 存储周几
monthday: '', // 存储几号
startTime: '',
estimatedDuration: 60,
responsiblePerson: '',
inspectionItems: [],
remarks: ''
});
// 创建计划表单验证规则
const createFormRules = computed(() => ({
planName: [{ required: true, message: '请输入计划名称', trigger: 'blur' }],
planType: [{ required: true, message: '请选择计划类型', trigger: 'change' }],
objectType: [{ required: true, message: '请选择对象类型', trigger: 'change' }],
startDate: [{ required: true, message: '请选择开始日期', trigger: 'change' }],
endDate: [{ required: true, message: '请选择结束日期', trigger: 'change' }],
startTime: [{ required: true, message: '请选择开始时间', trigger: 'change' }],
responsiblePerson: [{ required: true, message: '请选择负责人', trigger: 'change' }],
weekday: createForm.frequencyType === 'weekly' ? [{ required: true, message: '请选择周几', trigger: 'change' }] : [],
monthday: createForm.frequencyType === 'monthly' ? [{ required: true, message: '请选择几号', trigger: 'change' }] : []
}));
// 打开创建计划弹窗
const handleCreate = () => {
dialogVisible.value = true;
};
// 提交创建计划
const submitCreatePlan = () => {
console.log('提交创建计划:', createForm);
// 这里可以添加实际的创建计划逻辑
dialogVisible.value = false;
// 重置表单
Object.keys(createForm).forEach((key) => {
if (Array.isArray(createForm[key])) {
createForm[key] = [];
} else if (key === 'estimatedDuration') {
createForm[key] = 60;
} else if (key === 'frequencyType') {
createForm[key] = 'daily';
} else {
createForm[key] = '';
}
});
};
// 取消创建计划
const cancelCreatePlan = () => {
dialogVisible.value = false;
// 重置表单
Object.keys(createForm).forEach((key) => {
if (Array.isArray(createForm[key])) {
createForm[key] = [];
} else if (key === 'estimatedDuration') {
createForm[key] = 60;
} else if (key === 'frequencyType') {
createForm[key] = 'daily';
} else {
createForm[key] = '';
}
});
};
const handleInspection1 = () => {
router.push('/rili/rili');
};
const handleInspection2 = () => {
router.push('/rili/InspectionManagement');
};
const handleInspectionManagement1 = () => {
router.push('/rili/InspectionManagement');
};
const handleInspectionManagement2 = () => {
router.push('/rili/xunjianrenwu');
};
const handleInspectionManagement3 = () => {
router.push('/rili/xunjianjihua');
};
</script>
<style scoped>
/* 样式保持不变 */
.operation-inspection {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
/* 标题区域样式 */
.title-section {
background-color: #fff;
padding: 20px;
border-radius: 8px;
margin-bottom: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.page-title {
font-size: 24px;
font-weight: 600;
color: #303133;
margin: 0 0 8px 0;
}
.page-subtitle {
font-size: 14px;
color: #909399;
margin: 0;
}
/* 选项卡样式 */
.tabs-wrapper {
background-color: #fff;
padding: 20px;
border-radius: 8px;
margin-bottom: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.custom-tabs {
border-bottom: none;
padding-top: 20px;
}
.custom-tabs .el-tabs__header {
margin: 0 -20px 0 -20px;
padding: 0 20px;
border-bottom: 1px solid #e4e7ed;
}
.custom-tabs .el-tabs__nav-wrap::after {
height: 0;
}
.custom-tabs .el-tabs__item {
font-size: 14px;
color: #606266;
padding: 12px 20px;
margin-right: 20px;
border-bottom: 2px solid transparent;
}
.custom-tabs .el-tabs__item.is-active {
color: #409eff;
border-bottom-color: #409eff;
}
.custom-tabs .el-tabs__item:hover {
color: #409eff;
}
/* 筛选栏样式 */
.filter-bar {
background-color: #fff;
padding: 20px;
border-radius: 8px;
margin-bottom: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 16px;
}
.filter-item {
flex-shrink: 0;
}
.filter-bar .el-select {
width: 150px;
height: 36px;
}
.filter-actions {
margin-left: auto;
display: flex;
gap: 10px;
}
.search-btn,
.create-btn {
height: 36px;
border-radius: 4px;
}
/* 表格样式 */
.table-wrapper {
background-color: #fff;
padding: 20px;
border-radius: 8px;
margin-bottom: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.custom-table {
border: 1px solid #ebeef5;
border-radius: 4px;
overflow: hidden;
}
.custom-table th {
background-color: #fafafa;
font-weight: 500;
color: #606266;
text-align: left;
padding: 12px 16px;
border-bottom: 1px solid #ebeef5;
}
.custom-table td {
padding: 12px 16px;
border-bottom: 1px solid #ebeef5;
color: #303133;
}
.custom-table tr:hover {
background-color: #f5f7fa;
}
.custom-table tr.current-row {
background-color: #ecf5ff;
}
.status-tag {
padding: 4px 8px;
font-size: 12px;
border-radius: 4px;
}
.action-btn {
color: #409eff;
font-size: 12px;
padding: 4px 8px;
}
.action-btn:hover {
color: #66b1ff;
background-color: #ecf5ff;
}
/* 分页区域样式 */
.pagination-section {
background-color: #fff;
padding: 16px 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
display: flex;
justify-content: space-between;
align-items: center;
}
.pagination-info {
font-size: 14px;
color: #606266;
}
.pagination-controls .el-pagination {
margin: 0;
}
.pagination-controls .el-pagination__sizes {
margin-right: 20px;
}
.pagination-controls .el-pagination button {
min-width: 32px;
height: 32px;
line-height: 32px;
border-radius: 4px;
}
.pagination-controls .el-pagination .el-pager li {
min-width: 32px;
height: 32px;
line-height: 32px;
border-radius: 4px;
}
.pagination-controls .el-pagination .el-pager li.active {
background-color: #409eff;
color: #fff;
}
/* 导航栏样式 */
.navigation-tabs {
display: flex;
margin-bottom: 20px;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
padding: 2px;
}
.nav-tab {
padding: 12px 24px;
cursor: pointer;
transition: all 0.3s ease;
border-radius: 4px;
font-size: 14px;
color: #606266;
border-right: 1px solid #f0f0f0;
flex: 1;
text-align: center;
}
.nav-tab:last-child {
border-right: none;
}
.nav-tab:hover {
color: #409eff;
background-color: #ecf5ff;
}
.nav-tab.active {
background-color: #409eff;
color: #fff;
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
}
.nav-tab {
cursor: pointer;
user-select: none;
}
/* 响应式设计 */
@media (max-width: 1200px) {
.filter-bar {
flex-direction: column;
align-items: stretch;
}
.filter-actions {
margin-left: 0;
justify-content: flex-end;
}
}
</style>

View File

@ -0,0 +1,700 @@
<template>
<div class="container">
<!-- 导航栏 -->
<div class="navigation-tabs">
<div class="nav-tab active" @click="handleInspection1">待办事项</div>
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
<div class="nav-tab">试验管理</div>
<div class="nav-tab">报修管理</div>
<div class="nav-tab">抢修管理</div>
<div class="nav-tab">工单管理</div>
</div>
<!-- 标题栏 -->
<div class="header">
<TitleComponent title="运维待办事项" subtitle="管理每日、每周等的运维工作任务"></TitleComponent>
</div>
<div class="main-content">
<!-- 左侧日历区域 -->
<div class="calendar-container">
<div class="calendar-header">
<div class="calendar-title">待办月视图</div>
<div class="calendar-controls">
<!-- 年份月份选择 -->
<el-select v-model="selectedYear" placeholder="选择年份" size="small" style="width: 80px; margin-right: 5px">
<el-option v-for="year in years" :key="year" :label="year.toString()" :value="year"></el-option>
</el-select>
<el-select v-model="selectedMonth" placeholder="选择月份" size="small" style="width: 80px; margin-right: 10px">
<el-option v-for="month in 12" :key="month" :label="month.toString()" :value="month"></el-option>
</el-select>
<!-- 月份切换按钮 -->
<el-button type="text" icon="el-icon-arrow-left" @click="decreaseMonth"></el-button>
<el-button type="text" icon="el-icon-arrow-right" @click="increaseMonth"></el-button>
<el-button type="primary" size="small">添加</el-button>
<el-button type="primary" size="small" @click="goToToday">今日</el-button>
<el-button type="text" icon="el-icon-plus"></el-button>
</div>
</div>
<!-- 使用 Element Plus 的日历组件 -->
<el-calendar v-model="currentDate">
<template #date-cell="{ date, data }">
<div class="custom-date-cell" :class="getCellClass(data.day)">
<div class="date-day">{{ data.day.split('-').slice(2).join('-') }}</div>
<div class="date-events">
<div v-for="event in getDayEvents(data.day)" :key="event.id" class="event-item" :class="'event-' + event.type">
<div class="event-title">{{ event.title }}</div>
<div class="event-description">{{ event.description }}</div>
</div>
</div>
</div>
</template>
</el-calendar>
</div>
<!-- 右侧表单区域 -->
<div class="form-container">
<div class="form-header">
<h2>今日待办</h2>
<el-button type="primary" size="small" icon="el-icon-plus" @click="openAddTaskDialog">添加</el-button>
</div>
<!-- 待办事项列表 -->
<div class="todo-list">
<!-- 待办项1 - 常规维护 -->
<div class="todo-item">
<div class="todo-color-indicator normal"></div>
<el-checkbox class="todo-checkbox"></el-checkbox>
<div class="todo-content">
<div class="todo-main">
<div class="todo-title">服务器例行检查</div>
<div class="todo-time">09:00-10:00 AM</div>
</div>
<div class="todo-description">检查所有生产服务器的CPU内存磁盘使用率确保正常运行</div>
</div>
</div>
<!-- 待办项2 - 重要 -->
<div class="todo-item important">
<div class="todo-color-indicator important"></div>
<el-checkbox class="todo-checkbox"></el-checkbox>
<div class="todo-content">
<div class="todo-main">
<div class="todo-title">数据库备份</div>
<div class="todo-time">14:00-15:00 PM</div>
</div>
<div class="todo-description">主要数据库全备份并验证备份文件完整性</div>
</div>
<div class="todo-actions">
<el-button type="text" icon="el-icon-edit"></el-button>
<el-button type="text" icon="el-icon-delete"></el-button>
</div>
</div>
<!-- 待办项3 - 紧急 -->
<div class="todo-item">
<div class="todo-color-indicator urgent"></div>
<el-checkbox class="todo-checkbox"></el-checkbox>
<div class="todo-content">
<div class="todo-main">
<div class="todo-title">网络设备固件更新</div>
<div class="todo-time">18:00-20:00 PM</div>
</div>
<div class="todo-description">更新核心交换机和防火墙固件需安排在业务低峰期</div>
</div>
</div>
<!-- 待办项4 - 常规维护 -->
<div class="todo-item">
<div class="todo-color-indicator normal"></div>
<el-checkbox class="todo-checkbox"></el-checkbox>
<div class="todo-content">
<div class="todo-main">
<div class="todo-title">服务器例行检查</div>
<div class="todo-time">08:00-09:00 AM</div>
</div>
<div class="todo-description">检查所有生产服务器的CPU内存磁盘使用率确保正常运行</div>
</div>
</div>
<!-- 待办项5 - 常规维护 -->
<div class="todo-item">
<div class="todo-color-indicator normal"></div>
<el-checkbox class="todo-checkbox"></el-checkbox>
<div class="todo-content">
<div class="todo-main">
<div class="todo-title">服务器例行检查</div>
<div class="todo-time">06:00-07:00 AM</div>
</div>
<div class="todo-description">检查所有生产服务器的CPU内存磁盘使用率确保正常运行</div>
</div>
</div>
</div>
<!-- 状态图例 - 标签形式 -->
<div class="status-legend">
<span class="status-tag normal">常规维护</span>
<span class="status-tag important">重要</span>
<span class="status-tag urgent">紧急</span>
</div>
</div>
</div>
<el-dialog v-model="dialogVisible" title="新增任务" width="480px" class="custom-dialog" :before-close="closeDialog">
<el-form :model="taskForm" label-width="80px" class="task-form">
<el-form-item label="任务名称" prop="name">
<el-input v-model="taskForm.name" placeholder="输入任务名称" class="form-input"></el-input>
</el-form-item>
<el-form-item label="任务描述" prop="description">
<el-input v-model="taskForm.description" placeholder="输入任务描述" class="form-input"></el-input>
</el-form-item>
<el-form-item label="时间" prop="timeRange">
<el-date-picker
v-model="taskForm.timeRange"
type="datetimerange"
start-placeholder="开始时间"
end-placeholder="结束时间"
class="form-input"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="优先级" prop="priority">
<el-select v-model="taskForm.priority" placeholder="选择优先级" class="form-input">
<el-option label="常规项" value="常规项"></el-option>
<el-option label="重要" value="重要"></el-option>
<el-option label="紧急" value="紧急"></el-option>
</el-select>
</el-form-item>
<el-form-item label="任务类型" prop="taskType">
<el-select v-model="taskForm.taskType" placeholder="选择任务类型" class="form-input">
<el-option label="常规维护" value="常规维护"></el-option>
<el-option label="安全巡检" value="安全巡检"></el-option>
<el-option label="系统升级" value="系统升级"></el-option>
<el-option label="数据备份" value="数据备份"></el-option>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="closeDialog">取消</el-button>
<el-button type="primary" @click="saveTask">保存任务</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, computed, watch } from 'vue';
import router from '@/router';
import TitleComponent from '../demo/components/TitleComponent.vue';
// 生成年份选项生成2020-2029年的年份范围
const targetYear = 2025;
const years = ref(Array.from({ length: 10 }, (_, index) => 2020 + index));
const selectedYear = ref(targetYear);
const selectedMonth = ref(9);
// 默认显示2025年9月
const currentDate = ref(new Date(targetYear, 8, 1));
// 减少月份
const decreaseMonth = () => {
const date = new Date(currentDate.value);
date.setMonth(date.getMonth() - 1);
currentDate.value = date;
updateYearAndMonth();
};
// 增加月份
const increaseMonth = () => {
const date = new Date(currentDate.value);
date.setMonth(date.getMonth() + 1);
currentDate.value = date;
updateYearAndMonth();
};
// 回到今天
const goToToday = () => {
currentDate.value = new Date();
updateYearAndMonth();
};
// 日历事件数据 - 2025年9月的随机事件
const calendarEvents = ref([
// 服务维护事件
{ id: 1, date: '2025-09-11', title: '服务维护', description: '维护公司内部服务器', type: 'service' },
{ id: 2, date: '2025-09-28', title: '服务维护', description: '先所有旧服务器部署新内存', type: 'service' },
// 数据库管理事件
{ id: 3, date: '2025-09-21', title: '数据库管理', description: '定期执行数据库优化', type: 'database' },
{ id: 4, date: '2025-09-30', title: '数据库管理', description: '大型数据库备份策略', type: 'database' },
// 网络维护事件
{ id: 5, date: '2025-09-05', title: '网络维护', description: '网络设备例行检查', type: 'network' },
{ id: 6, date: '2025-09-15', title: '网络维护', description: '更新网络安全策略', type: 'network' },
// 系统升级事件
{ id: 7, date: '2025-09-18', title: '系统升级', description: '核心系统版本升级', type: 'upgrade' },
{ id: 8, date: '2025-09-25', title: '系统升级', description: '应用服务升级部署', type: 'upgrade' }
]);
// 获取指定日期的事件
const getDayEvents = (dateStr) => {
return calendarEvents.value.filter((event) => event.date === dateStr);
};
// 根据事件类型获取单元格样式
const getCellClass = (date) => {
const events = getDayEvents(date);
if (events.length > 0) {
const eventType = events[0].type;
return `date-cell-${eventType}`;
}
return '';
};
// 更新年份和月份选择器的值
const updateYearAndMonth = () => {
selectedYear.value = currentDate.value.getFullYear();
selectedMonth.value = currentDate.value.getMonth() + 1;
};
// 监听年份和月份变化,更新日历显示
watch([selectedYear, selectedMonth], ([newYear, newMonth]) => {
const date = new Date(currentDate.value);
date.setFullYear(newYear);
date.setMonth(newMonth - 1);
currentDate.value = date;
});
// 初始化年份和月份选择器
updateYearAndMonth();
// 弹窗相关状态管理
const dialogVisible = ref(false);
const taskForm = ref({
name: '',
description: '',
timeRange: '',
priority: '常规项',
taskType: '常规维护'
});
// 打开添加任务弹窗
const openAddTaskDialog = () => {
dialogVisible.value = true;
};
// 关闭弹窗
const closeDialog = () => {
dialogVisible.value = false;
};
// 保存任务
const saveTask = () => {
// 这里可以添加表单验证和保存逻辑
console.log('保存任务:', taskForm.value);
// 重置表单
taskForm.value = {
name: '',
description: '',
timeRange: '',
priority: '常规项',
taskType: '常规维护'
};
// 关闭弹窗
closeDialog();
};
const handleInspection1 = () => {
router.push('/rili/rili');
};
const handleInspection2 = () => {
router.push('/rili/InspectionManagement');
};
</script>
<style scoped>
.container {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
/* 导航栏样式 */
.navigation-tabs {
display: flex;
margin-bottom: 20px;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
padding: 2px;
}
.nav-tab {
padding: 12px 24px;
cursor: pointer;
transition: all 0.3s ease;
border-radius: 4px;
font-size: 14px;
color: #606266;
border-right: 1px solid #f0f0f0;
flex: 1;
text-align: center;
}
.nav-tab:last-child {
border-right: none;
}
.nav-tab:hover {
color: #409eff;
background-color: #ecf5ff;
}
.nav-tab.active {
background-color: #409eff;
color: #fff;
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
}
.nav-tab {
cursor: pointer;
user-select: none;
}
.header {
margin-bottom: 20px;
}
.header h1 {
font-size: 24px;
font-weight: 600;
color: #303133;
margin: 0;
}
.header p {
font-size: 14px;
color: #606266;
margin: 5px 0 0 0;
}
.main-content {
display: flex;
gap: 20px;
}
/* 日历区域样式 */
.calendar-container {
flex: 1;
background-color: #fff;
border-radius: 4px;
padding: 20px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
/* 自定义弹窗样式 */
.custom-dialog {
border-radius: 8px;
overflow: hidden;
}
.custom-dialog .el-dialog__header {
background-color: #f5f7fa;
border-bottom: 1px solid #e4e7ed;
padding: 15px 20px;
}
.custom-dialog .el-dialog__title {
font-size: 16px;
color: #303133;
}
.custom-dialog .el-dialog__body {
padding: 20px;
}
/* 确保所有输入框长度相等 */
.task-form .form-input {
height: 30px;
width: 100%;
}
/* 时间选择器样式调整 */
.task-form .el-date-editor {
width: 100%;
height: 30px;
}
.calendar-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.calendar-title {
font-size: 16px;
font-weight: 600;
color: #303133;
}
.calendar-controls {
display: flex;
align-items: center;
gap: 10px;
}
.el-select {
margin-right: 5px;
}
/* 表单区域样式 */
.form-container {
width: 400px;
background-color: #fff;
border-radius: 4px;
padding: 20px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.form-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 1px solid #f0f0f0;
}
.form-header h2 {
font-size: 16px;
font-weight: 600;
color: #303133;
margin: 0;
}
.todo-list {
display: flex;
flex-direction: column;
gap: 10px;
margin-bottom: 20px;
max-height: 400px;
overflow-y: auto;
}
.todo-item {
display: flex;
align-items: flex-start;
gap: 10px;
padding: 12px 12px 12px 20px;
background-color: #fafafa;
border-radius: 4px;
position: relative;
transition: all 0.3s ease;
}
/* 重要任务的背景色 */
.todo-item.important {
background-color: #e6f7ff;
}
.todo-checkbox {
margin-top: 2px;
flex-shrink: 0;
}
.todo-content {
flex: 1;
}
.todo-main {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 4px;
}
.todo-title {
font-size: 14px;
font-weight: 500;
color: #303133;
}
.todo-time {
font-size: 12px;
color: #909399;
}
.todo-description {
font-size: 12px;
color: #606266;
line-height: 1.4;
}
.todo-actions {
position: absolute;
right: 10px;
bottom: 10px;
display: flex;
gap: 5px;
}
.todo-actions .el-button {
padding: 4px 8px;
min-width: auto;
}
/* 状态图例 - 标签形式 */
.status-legend {
display: flex;
gap: 10px;
padding-top: 15px;
border-top: 1px solid #ebeef5;
}
.status-tag {
display: inline-block;
padding: 4px 12px;
border-radius: 16px;
font-size: 12px;
color: #fff;
}
.status-tag.normal {
background-color: #52c41a;
}
.status-tag.important {
background-color: #faad14;
}
.status-tag.urgent {
background-color: #ff4d4f;
}
.todo-color-indicator {
width: 8px;
height: 100%;
border-radius: 0 4px 4px 0;
position: absolute;
left: 0;
top: 0;
flex-shrink: 0;
}
.todo-color-indicator.normal {
background-color: #52c41a;
}
.todo-color-indicator.important {
background-color: #faad14;
}
.todo-color-indicator.urgent {
background-color: #ff4d4f;
}
/* 自定义日历单元格样式 */
.custom-date-cell {
padding: 5px;
text-align: center;
}
/* 系统升级事件样式 */
.event-upgrade {
background-color: #fff1f0;
color: #f5222d;
}
/* 日期单元格背景色 - 按事件类型 */
.date-cell-service {
background-color: #e6f7ff;
}
.date-cell-database {
background-color: #f0f9ff;
}
.date-cell-network {
background-color: #fffbe6;
}
.date-cell-upgrade {
background-color: #fff1f0;
}
/* 日历样式优化 */
.el-calendar {
width: 100%;
}
.el-calendar-table {
width: 100%;
}
.el-calendar-table td {
padding: 2px;
vertical-align: top;
}
.el-calendar-day {
height: 120px;
border-radius: 4px;
overflow: hidden;
}
.date-day {
font-weight: bold;
margin-bottom: 5px;
}
.date-events {
flex: 1;
overflow: hidden;
}
.event-item {
padding: 3px;
margin-bottom: 2px;
border-radius: 3px;
font-size: 12px;
}
.event-title {
font-weight: bold;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.event-description {
font-size: 11px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* 服务维护事件样式 */
.event-service {
background-color: #e6f7ff;
color: #1890ff;
}
/* 数据库管理事件样式 */
.event-database {
background-color: #f0f9ff;
color: #36cfc9;
}
/* 网络维护事件样式 */
.event-network {
background-color: #fffbe6;
color: #faad14;
}
/* 系统升级事件样式 */
.event-upgrade {
background-color: #fff1f0;
color: #f5222d;
}
</style>

View File

@ -0,0 +1,672 @@
<template>
<div class="operation-inspection">
<div class="navigation-tabs">
<div class="nav-tab" @click="handleInspection1">待办事项</div>
<div class="nav-tab active" @click="handleInspection2">巡检管理</div>
<div class="nav-tab">试验管理</div>
<div class="nav-tab">报修管理</div>
<div class="nav-tab">抢修管理</div>
<div class="nav-tab">工单管理</div>
</div>
<div style="display: flex; align-items: center; gap: 1200px">
<TitleComponent title="运维巡检管理" subtitle="制定巡检计划,安排巡检任务,跟进巡检记录"></TitleComponent>
<div style="display: flex; align-items: center; gap: 10px">
<el-button type="primary" class="export-btn">筛选</el-button>
<el-button type="primary" class="create-btn">导入数据</el-button>
</div>
</div>
<!-- 选项卡和按钮组合 -->
<div class="tabs-wrapper">
<div style="display: flex; align-items: center; gap: 10px">
<el-button type="primary" @click="handleInspectionManagement1">巡检计划</el-button>
<el-button type="primary" @click="handleInspectionManagement2">巡检任务</el-button>
<el-button type="primary" @click="handleInspectionManagement3">巡检记录</el-button>
</div>
</div>
<!-- 筛选栏 -->
<div class="filter-bar">
<div class="filter-item">
<el-select v-model="filterStatus" placeholder="状态" clearable>
<el-option label="全部状态" value="all"></el-option>
<el-option label="正常" value="normal"></el-option>
<el-option label="需关注" value="attention"></el-option>
<el-option label="有问题" value="problem"></el-option>
</el-select>
</div>
<div class="filter-item">
<el-select v-model="filterType" placeholder="巡检类型" clearable>
<el-option label="全部类型" value="all"></el-option>
<el-option label="数据库" value="database"></el-option>
<el-option label="服务器" value="server"></el-option>
<el-option label="网络设备" value="network"></el-option>
</el-select>
</div>
<div class="filter-item">
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
></el-date-picker>
</div>
<div class="filter-actions">
<el-button type="primary" class="search-btn">搜索</el-button>
</div>
</div>
<!-- 主内容区 -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6" style="grid-auto-rows: 1fr">
<!-- 左侧和中间内容区 -->
<div class="lg:col-span-2 space-y-6">
<!-- 巡检记录与报告卡片 -->
<div class="content-card">
<div class="card-header">
<h2 class="card-title">巡检记录与报告</h2>
<div class="flex space-x-2">
<button
class="px-3 py-1 text-sm rounded-md hover:bg-gray-200 transition"
:class="{ 'bg-gray-100 text-gray-700': timeRange === 'month', 'bg-white text-gray-500': timeRange !== 'month' }"
@click="handleTimeRangeChange('month')"
>
</button>
<button
class="px-3 py-1 text-sm rounded-md hover:bg-gray-100 transition"
:class="{ 'bg-gray-100 text-gray-700': timeRange === 'week', 'bg-white text-gray-500': timeRange !== 'week' }"
@click="handleTimeRangeChange('week')"
>
</button>
<button
class="px-3 py-1 text-sm rounded-md hover:bg-gray-100 transition"
:class="{ 'bg-gray-100 text-gray-700': timeRange === 'day', 'bg-white text-gray-500': timeRange !== 'day' }"
@click="handleTimeRangeChange('day')"
>
</button>
</div>
</div>
<!-- 数据卡片 -->
<div class="card-body">
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="stat-card">
<p class="stat-label">本月完成巡检</p>
<p class="stat-value">42</p>
</div>
<div class="stat-card">
<p class="stat-label">发现问题数</p>
<p class="stat-value">7</p>
</div>
<div class="stat-card">
<p class="stat-label">已解决问题</p>
<p class="stat-value">5</p>
</div>
<div class="stat-card">
<p class="stat-label">平均完成时间</p>
<p class="stat-value">45分钟</p>
</div>
</div>
<div class="divider"></div>
<!-- 图表区域 -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 py-4">
<!-- 饼图 - 本月巡检完成情况 -->
<div class="md:col-span-1">
<p class="chart-title">本月完成巡检</p>
<div class="relative w-32 h-32 mx-auto">
<!-- 饼图使用SVG绘制 - 显示本月巡检完成情况 -->
<svg class="w-full h-full" viewBox="0 0 100 100">
<!-- 背景圆环 -->
<circle cx="50" cy="50" r="45" fill="none" stroke="#f3f4f6" stroke-width="10" />
<!-- 已完成部分 (72%) -->
<circle
cx="50"
cy="50"
r="45"
fill="none"
stroke="#10b981"
stroke-width="10"
stroke-dasharray="282.74"
stroke-dashoffset="113.1"
transform="rotate(-90 50 50)"
/>
<!-- 未完成部分 (28%) -->
<circle
cx="50"
cy="50"
r="45"
fill="none"
stroke="#f97316"
stroke-width="10"
stroke-dasharray="113.1"
stroke-dashoffset="0"
transform="rotate(-90 50 50)"
/>
</svg>
<!-- 饼图中心显示 -->
<div class="absolute inset-0 flex flex-col items-center justify-center">
<p class="text-sm text-gray-500">已解决问题</p>
<p class="text-lg font-bold text-gray-800">72%</p>
</div>
</div>
<!-- 饼图图例 -->
<div class="mt-3 flex justify-center space-x-4">
<div class="flex items-center">
<div class="w-3 h-3 rounded-full bg-green-500 mr-1"></div>
<span class="text-xs text-gray-600">已解决</span>
</div>
<div class="flex items-center">
<div class="w-3 h-3 rounded-full bg-orange-500 mr-1"></div>
<span class="text-xs text-gray-600">未解决</span>
</div>
</div>
</div>
<!-- 进度条 -->
<div class="md:col-span-2 flex flex-col justify-center">
<div class="space-y-4">
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-600">完成率</span>
<span class="font-medium text-gray-800">68%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-red-500 h-2 rounded-full" style="width: 68%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-600">解决率</span>
<span class="font-medium text-gray-800">72%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-green-500 h-2 rounded-full" style="width: 72%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-600">及时率</span>
<span class="font-medium text-gray-800">60%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-gray-500 h-2 rounded-full" style="width: 60%"></div>
</div>
</div>
</div>
</div>
</div>
<div class="divider"></div>
<!-- 发现问题种类 -->
<div class="py-4">
<h3 class="section-title">发现问题种类</h3>
<div class="space-y-4">
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-600">温度异常率</span>
<span class="text-gray-500">85%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-blue-500 h-2 rounded-full" style="width: 85%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-600">内存使用率</span>
<span class="text-gray-500">62%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-blue-500 h-2 rounded-full" style="width: 62%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-600">CPU负载</span>
<span class="text-gray-500">45%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-blue-500 h-2 rounded-full" style="width: 45%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-600">响应时间</span>
<span class="text-gray-500">30%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-blue-500 h-2 rounded-full" style="width: 30%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-600">磁盘空间状态</span>
<span class="text-gray-500">15%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-blue-500 h-2 rounded-full" style="width: 15%"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 右侧最近巡检结果 -->
<div class="lg:col-span-1" style="display: flex; flex-direction: column; height: 100%">
<div class="content-card" style="flex: 1; display: flex; flex-direction: column">
<div class="card-header">
<h2 class="card-title">最近巡检结果</h2>
</div>
<!-- 巡检结果列表 -->
<div class="card-body" style="flex: 1; overflow-y: auto">
<div class="inspection-results space-y-4">
<!-- 结果1正常 -->
<div class="inspection-card bg-white border border-gray-200 rounded-lg p-4 shadow-sm">
<div class="flex justify-between items-start mb-4">
<h3 class="text-lg font-medium text-gray-800">数据库性能巡检</h3>
<span class="status-tag status-normal px-3 py-1 text-xs">正常</span>
</div>
<p class="text-sm text-gray-500 mb-3">2025-06-15 14:00-16:45 张明</p>
<div class="flex justify-between items-center mb-4">
<div class="flex flex-col items-center">
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">系统连接量</span>
<span class="text-sm font-medium">128<500</span>
</div>
<div class="flex flex-col items-center">
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">查询响应时间</span>
<span class="text-sm font-medium">平均0.3S</span>
</div>
<div class="flex flex-col items-center">
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">表空间使用率</span>
<span class="text-sm font-medium">75%</span>
</div>
<div class="flex flex-col items-center">
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">日志文件</span>
<span class="text-sm font-medium">正常轮转</span>
</div>
</div>
<div class="flex justify-end gap-2">
<el-button size="small" class="text-sm border-gray-300 text-gray-600">查看详情</el-button>
<el-button type="primary" size="small" class="text-sm">生成报告</el-button>
</div>
</div>
<!-- 结果2需关注 -->
<div class="inspection-card bg-white border border-gray-200 rounded-lg p-4 shadow-sm">
<div class="flex justify-between items-start mb-4">
<h3 class="text-lg font-medium text-gray-800">生产服务器日常巡检</h3>
<span class="status-tag status-attention px-3 py-1 text-xs">需关注</span>
</div>
<p class="text-sm text-gray-500 mb-3">2025-06-15 14:00-16:45 张明</p>
<div class="flex justify-between items-center mb-4">
<div class="flex flex-col items-center">
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">CPU使用率</span>
<span class="text-sm font-medium">平均35%峰值59%</span>
</div>
<div class="flex flex-col items-center">
<i class="fas fa-exclamation-circle text-yellow-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">内存使用率</span>
<span class="text-sm font-medium">85%</span>
</div>
<div class="flex flex-col items-center">
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">磁盘空间</span>
<span class="text-sm font-medium">62%</span>
</div>
<div class="flex flex-col items-center">
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">服务状态</span>
<span class="text-sm font-medium">正常运行</span>
</div>
</div>
<div class="bg-yellow-50 border border-yellow-200 rounded-md p-3 mb-4">
<div class="flex items-start">
<i class="fas fa-info-circle text-yellow-500 mt-0.5 mr-2"></i>
<p class="text-xs text-yellow-800">已创建问题单 #PRB-2023061501计划于今晚进行内存扩容</p>
</div>
</div>
<div class="flex justify-end gap-2">
<el-button size="small" class="text-sm border-gray-300 text-gray-600">查看详情</el-button>
<el-button type="primary" size="small" class="text-sm">生成报告</el-button>
</div>
</div>
<!-- 结果3有问题 -->
<div class="inspection-card bg-white border border-gray-200 rounded-lg p-4 shadow-sm">
<div class="flex justify-between items-start mb-4">
<h3 class="text-lg font-medium text-gray-800">网络设备安全巡检</h3>
<span class="status-tag status-problem px-3 py-1 text-xs">有问题</span>
</div>
<p class="text-sm text-gray-500 mb-3">2025-06-14 10:00-11:30 李华</p>
<div class="grid grid-cols-2 gap-2 mb-4">
<div class="flex flex-col items-center">
<i class="fas fa-times-circle text-red-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">防火墙规则</span>
<span class="text-sm font-medium">部分规则异常</span>
</div>
<div class="flex flex-col items-center">
<i class="fas fa-exclamation-circle text-yellow-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">安全补丁</span>
<span class="text-sm font-medium">需更新</span>
</div>
<div class="flex flex-col items-center">
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">访问控制</span>
<span class="text-sm font-medium">正常</span>
</div>
<div class="flex flex-col items-center">
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">流量监控</span>
<span class="text-sm font-medium">正常</span>
</div>
</div>
<div class="flex justify-end gap-2">
<el-button size="small" class="text-sm border-gray-300 text-gray-600">查看详情</el-button>
<el-button type="primary" size="small" class="text-sm">生成报告</el-button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
import router from '@/router';
import TitleComponent from '@/views/demo/components/TitleComponent.vue';
// 筛选条件
const filterStatus = ref('all');
const filterType = ref('all');
const dateRange = ref([]);
// 时间范围选择
const timeRange = ref('month'); // 默认选中"月"
// 时间范围切换函数
const handleTimeRangeChange = (range) => {
timeRange.value = range;
// 在实际应用中,这里应该根据选择的时间范围重新获取数据
console.log(`切换到${range}视图`);
};
// 导航方法
const handleInspection1 = () => {
router.push('/rili/rili');
};
const handleInspection2 = () => {
router.push('/rili/InspectionManagement');
};
const handleInspectionManagement1 = () => {
router.push('/rili/InspectionManagement');
};
const handleInspectionManagement2 = () => {
router.push('/rili/xunjianrenwu');
};
const handleInspectionManagement3 = () => {
router.push('/rili/xunjianjihua');
};
</script>
<style scoped>
/* 主容器样式 */
.operation-inspection {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
/* 导航栏样式 */
.navigation-tabs {
display: flex;
margin-bottom: 20px;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
padding: 2px;
}
.nav-tab {
padding: 12px 24px;
cursor: pointer;
transition: all 0.3s ease;
border-radius: 4px;
font-size: 14px;
color: #606266;
border-right: 1px solid #f0f0f0;
flex: 1;
text-align: center;
}
.nav-tab:last-child {
border-right: none;
}
.nav-tab:hover {
color: #409eff;
background-color: #ecf5ff;
}
.nav-tab.active {
background-color: #409eff;
color: #fff;
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
}
.nav-tab {
cursor: pointer;
user-select: none;
}
/* 选项卡样式 */
.tabs-wrapper {
background-color: #fff;
padding: 20px;
border-radius: 8px;
margin-bottom: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
/* 筛选栏样式 */
.filter-bar {
background-color: #fff;
padding: 20px;
border-radius: 8px;
margin-bottom: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 16px;
}
.filter-item {
flex-shrink: 0;
}
.filter-bar .el-select,
.filter-bar .el-date-picker {
width: 150px;
height: 36px;
}
.filter-actions {
margin-left: auto;
display: flex;
gap: 10px;
}
.search-btn,
.export-btn,
.create-btn {
height: 36px;
border-radius: 4px;
}
/* 内容卡片样式 */
.content-card {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
overflow: hidden;
}
.card-header {
padding: 20px;
border-bottom: 1px solid #e4e7ed;
display: flex;
justify-content: space-between;
align-items: center;
}
.card-title {
font-size: 16px;
font-weight: 500;
color: #303133;
margin: 0;
}
.card-body {
padding: 0 20px;
}
/* 统计卡片样式 */
.stat-card {
background-color: #f5f7fa;
border-radius: 6px;
padding: 16px;
}
.stat-label {
font-size: 14px;
color: #606266;
margin: 0 0 8px 0;
}
.stat-value {
font-size: 24px;
font-weight: 600;
color: #303133;
margin: 0;
}
/* 分隔线 */
.divider {
height: 1px;
background-color: #e4e7ed;
margin: 16px 0;
}
/* 图表标题 */
.chart-title {
font-size: 14px;
color: #606266;
margin: 0 0 8px 0;
}
/* 区域标题 */
.section-title {
font-size: 14px;
font-weight: 500;
color: #303133;
margin: 0 0 12px 0;
}
/* 记录列表样式 */
.record-list {
margin: 0;
padding: 0;
}
.record-item {
padding: 16px 0;
}
.record-title {
font-size: 14px;
font-weight: 500;
color: #303133;
margin: 0;
}
.record-time,
.record-type {
font-size: 12px;
color: #909399;
margin: 4px 0 0 0;
}
/* 状态标签 */
.status-tag {
font-size: 12px;
padding: 2px 8px;
border-radius: 4px;
}
.status-normal {
background-color: #f0f9eb;
color: #52c41a;
border: 1px solid #e1f3d8;
}
.status-attention {
background-color: #fffbe6;
color: #faad14;
border: 1px solid #fff1b8;
}
.status-problem {
background-color: #fff2f0;
color: #f5222d;
border: 1px solid #ffe3e0;
}
/* 操作按钮 */
.action-btn {
color: #409eff;
font-size: 12px;
padding: 4px 8px;
}
.action-btn:hover {
color: #66b1ff;
background-color: #ecf5ff;
}
/* 响应式设计 */
@media (max-width: 1200px) {
.filter-bar {
flex-direction: column;
align-items: stretch;
}
.filter-actions {
margin-left: 0;
justify-content: flex-end;
}
}
</style>

View File

@ -0,0 +1,892 @@
<template>
<div>
<div class="inspection-tasks">
<div class="navigation-tabs">
<div class="nav-tab" @click="handleInspection1">待办事项</div>
<div class="nav-tab active" @click="handleInspection2">巡检管理</div>
<div class="nav-tab">试验管理</div>
<div class="nav-tab">报修管理</div>
<div class="nav-tab">抢修管理</div>
<div class="nav-tab">工单管理</div>
</div>
<!-- 页面标题 -->
<TitleComponent title="运维巡检管理" subtitle="制定巡检计划,安排巡检任务,跟进巡检记录"></TitleComponent>
<!-- 选项卡 -->
<div class="tabs-wrapper">
<div style="display: flex; align-items: center; gap: 10px">
<el-button type="primary" @click="handleInspectionManagement1">巡检计划</el-button>
<el-button type="primary" @click="handleInspectionManagement2">巡检任务</el-button>
<el-button type="primary" @click="handleInspectionManagement3">巡检记录</el-button>
</div>
</div>
<!-- 筛选栏 -->
<div class="filter-bar">
<div class="filter-container">
<div class="filter-item">
<el-select v-model="taskStatus" placeholder="任务状态">
<el-option label="待执行" value="pending"></el-option>
<el-option label="执行中" value="executing"></el-option>
<el-option label="已延期" value="delayed"></el-option>
<el-option label="已完成" value="completed"></el-option>
</el-select>
</div>
<div class="filter-item">
<el-select v-model="planType" placeholder="全部计划">
<el-option label="每日巡检计划" value="daily"></el-option>
<el-option label="每周巡检计划" value="weekly"></el-option>
<el-option label="每月巡检计划" value="monthly"></el-option>
<el-option label="每季度巡检计划" value="quarterly"></el-option>
</el-select>
</div>
<div class="filter-item">
<el-select v-model="executor" placeholder="执行人">
<el-option label="全部人员" value="all"></el-option>
<el-option label="张明" value="zhangming"></el-option>
<el-option label="李华" value="lihua"></el-option>
<el-option label="王强" value="wangqiang"></el-option>
</el-select>
</div>
<div class="filter-actions">
<el-button type="primary" class="search-btn" @click="handleSearch"> <i class="el-icon-search mr-1"></i>搜索 </el-button>
<el-button type="primary" icon="el-icon-plus" class="create-btn" @click="handleCreateTask"> 手动创建任务 </el-button>
</div>
</div>
</div>
<!-- 任务卡片列表 -->
<div class="task-cards">
<div class="task-card" v-for="(task, index) in pagedTasks" :key="index">
<div class="task-header">
<div class="task-title">
{{ task.title }}
</div>
<div class="task-status" :class="task.statusClass">
{{ task.statusText }}
</div>
</div>
<div class="task-details">
<div class="detail-item">
<span class="detail-label">计划时间</span>
<span class="detail-value">{{ task.planTime }}</span>
</div>
<div class="detail-item">
<span class="detail-label">巡检对象</span>
<span class="detail-value">{{ task.target }}</span>
</div>
<div class="detail-item">
<span class="detail-label">执行人</span>
<span class="detail-value">{{ task.executor }}</span>
</div>
<div class="detail-item">
<span class="detail-label">关联计划</span>
<span class="detail-value">{{ task.relatedPlan }}</span>
</div>
<!-- 特定状态的额外信息 -->
<div v-if="task.status === 'delayed'" class="delay-reason">
<span class="detail-label">延期原因</span>
<span class="detail-value">{{ task.delayReason }}</span>
</div>
<div v-if="task.status === 'executing'" class="progress-container">
<span class="detail-label">完成进度</span>
<div class="progress-bar">
<el-progress :percentage="task.progress" stroke-width="6" :stroke-color="task.progressColor"></el-progress>
</div>
</div>
<div v-if="task.status === 'completed'" class="task-result">
<span class="detail-label">结果</span>
<span class="detail-value" :class="task.resultClass">{{ task.result }}</span>
</div>
</div>
<div class="task-actions">
<el-button type="text" size="small" class="action-btn view-btn" @click="handleView(task)"> 详情 </el-button>
<el-button type="primary" size="small" :class="task.actionClass" @click="handleAction(task)">
{{ task.actionText }}
</el-button>
</div>
</div>
</div>
<!-- 分页区域 -->
<div class="pagination-section">
<div class="pagination-controls">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[8, 12, 16, 20]"
:page-size="pageSize"
layout="prev, pager, next, jumper"
:total="total"
background
>
</el-pagination>
</div>
</div>
<!-- 添加新任务弹窗 -->
<el-dialog v-model="createTaskDialogVisible" title="添加新任务" width="500px" :before-close="handleCancelCreateTask">
<el-form ref="createTaskFormRef" :model="createTaskForm" :rules="createTaskRules" label-width="80px">
<el-form-item label="任务名称" prop="taskName">
<el-input v-model="createTaskForm.taskName" placeholder="输入任务名称" />
</el-form-item>
<el-form-item label="巡检对象" prop="inspectionTarget">
<el-input v-model="createTaskForm.inspectionTarget" placeholder="输入巡检内容" />
</el-form-item>
<el-form-item label="时间" prop="timeRange">
<el-date-picker
v-model="createTaskForm.timeRange"
type="datetimerange"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD HH:mm"
value-format="YYYY-MM-DD HH:mm"
placeholder="选择时间范围"
/>
</el-form-item>
<el-form-item label="关联计划">
<el-select v-model="createTaskForm.relatedPlan" placeholder="选择关联计划">
<el-option label="全部计划" value="all" />
<el-option label="每日巡检计划" value="daily" />
<el-option label="每周巡检计划" value="weekly" />
<el-option label="每月巡检计划" value="monthly" />
<el-option label="每季度巡检计划" value="quarterly" />
</el-select>
</el-form-item>
<el-form-item label="执行人">
<el-select v-model="createTaskForm.executor" placeholder="选择执行人">
<el-option label="全部人员" value="all" />
<el-option label="张明" value="zhangming" />
<el-option label="李华" value="lihua" />
<el-option label="王强" value="wangqiang" />
<el-option label="赵伟" value="zhaowei" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCancelCreateTask">取消</el-button>
<el-button type="primary" @click="handleSaveTask">保存任务</el-button>
</span>
</template>
</el-dialog>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
import router from '@/router';
import TitleComponent from '@/views/demo/components/TitleComponent.vue';
// 激活的选项卡
const activeTab = ref('task');
// 筛选条件
const taskStatus = ref('');
const planType = ref('');
const executor = ref('');
// 任务数据
const tasks = ref([
{
title: '生产服务器日常巡检',
status: 'pending',
statusText: '待执行',
statusClass: 'status-pending',
planTime: '2025-06-16 08:30',
target: '生产服务器集群(12台)',
executor: '张明',
relatedPlan: '每日巡检计划',
actionText: '开始执行',
actionClass: 'start-btn'
},
{
title: '机房环境检查',
status: 'delayed',
statusText: '已延期',
statusClass: 'status-delayed',
planTime: '2025-06-16 08:30',
target: '机房温度、湿度、电源',
executor: '李华',
relatedPlan: '每周巡检计划',
delayReason: '设备维修处理中',
actionText: '重新安排',
actionClass: 'reschedule-btn'
},
{
title: '网络设备安全巡检',
status: 'executing',
statusText: '执行中',
statusClass: 'status-executing',
planTime: '2025-06-16 09:30',
target: '核心交换机、防火墙',
executor: '王强',
relatedPlan: '每周巡检计划',
progress: 60,
progressColor: '#FF7D00',
actionText: '完成',
actionClass: 'complete-btn'
},
{
title: '数据库性能巡检',
status: 'completed',
statusText: '已完成',
statusClass: 'status-completed',
planTime: '2025-06-16 10:30',
target: '生产数据库集群(2组)',
executor: '赵伟',
relatedPlan: '每月巡检计划',
result: '正常',
resultClass: 'result-normal',
actionText: '查看报告',
actionClass: 'report-btn'
},
{
title: '生产服务器日常巡检',
status: 'pending',
statusText: '待执行',
statusClass: 'status-pending',
planTime: '2025-06-16 13:30',
target: '生产服务器集群(12台)',
executor: '张明',
relatedPlan: '每日巡检计划',
actionText: '开始执行',
actionClass: 'start-btn'
},
{
title: '机房环境检查',
status: 'delayed',
statusText: '已延期',
statusClass: 'status-delayed',
planTime: '2025-06-16 14:00',
target: '机房温度、湿度、电源',
executor: '李华',
relatedPlan: '每周巡检计划',
delayReason: '设备维修处理中',
actionText: '重新安排',
actionClass: 'reschedule-btn'
},
{
title: '网络设备安全巡检',
status: 'executing',
statusText: '执行中',
statusClass: 'status-executing',
planTime: '2025-06-16 15:00',
target: '核心交换机、防火墙',
executor: '王强',
relatedPlan: '每周巡检计划',
progress: 35,
progressColor: '#FF7D00',
actionText: '完成',
actionClass: 'complete-btn'
},
{
title: '数据库性能巡检',
status: 'completed',
statusText: '已完成',
statusClass: 'status-completed',
planTime: '2025-06-16 16:00',
target: '生产数据库集群(2组)',
executor: '赵伟',
relatedPlan: '每月巡检计划',
result: '正常',
resultClass: 'result-normal',
actionText: '查看报告',
actionClass: 'report-btn'
}
]);
// 分页相关
const currentPage = ref(1);
const pageSize = ref(8);
const total = ref(tasks.value.length);
// 状态排序映射
const statusOrder = {
pending: 0, // 待完成
delayed: 1, // 已延期
executing: 2, // 执行中
completed: 3 // 已完成
};
// 分页处理后的数据(含排序)
const pagedTasks = computed(() => {
// 先按状态排序
const sortedTasks = [...tasks.value].sort((a, b) => {
return statusOrder[a.status] - statusOrder[b.status];
});
// 再进行分页
const startIndex = (currentPage.value - 1) * pageSize.value;
const endIndex = startIndex + pageSize.value;
return sortedTasks.slice(startIndex, endIndex);
});
// 搜索处理
const handleSearch = () => {
currentPage.value = 1; // 重置到第一页
// 实际应用中这里会根据筛选条件过滤数据
};
// 创建任务弹窗相关
const createTaskDialogVisible = ref(false);
const createTaskForm = ref({
taskName: '',
inspectionTarget: '',
timeRange: [],
relatedPlan: 'all',
executor: 'all'
});
const createTaskRules = {
taskName: [{ required: true, message: '请输入任务名称', trigger: 'blur' }],
inspectionTarget: [{ required: true, message: '请输入巡检对象', trigger: 'blur' }],
timeRange: [{ required: true, message: '请选择时间范围', trigger: 'change' }]
};
// 创建任务
const handleCreateTask = () => {
createTaskDialogVisible.value = true;
};
// 保存任务
const handleSaveTask = () => {
// 模拟保存任务逻辑
console.log('保存任务:', createTaskForm.value);
// 关闭弹窗
createTaskDialogVisible.value = false;
// 重置表单
createTaskForm.value = {
taskName: '',
inspectionTarget: '',
timeRange: [],
relatedPlan: 'all',
executor: 'all'
};
// 这里可以添加成功提示和刷新任务列表的逻辑
};
// 取消创建任务
const handleCancelCreateTask = () => {
createTaskDialogVisible.value = false;
// 重置表单
createTaskForm.value = {
taskName: '',
inspectionTarget: '',
timeRange: [],
relatedPlan: 'all',
executor: 'all'
};
};
// 分页事件
const handleSizeChange = (val) => {
pageSize.value = val;
currentPage.value = 1;
};
const handleCurrentChange = (val) => {
currentPage.value = val;
};
// 查看任务详情
const handleView = (task) => {
console.log('查看任务详情:', task);
};
const handleInspectionManagement1 = () => {
router.push('/rili/InspectionManagement');
};
const handleInspectionManagement2 = () => {
router.push('/rili/xunjianrenwu');
};
const handleInspectionManagement3 = () => {
router.push('/rili/xunjianjihua');
};
const handleInspection1 = () => {
router.push('/rili/rili');
};
const handleInspection2 = () => {
router.push('/rili/InspectionManagement');
};
</script>
<style scoped>
.inspection-tasks {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
/* 选项卡样式 */
.tabs-wrapper {
background-color: #fff;
padding: 20px;
border-radius: 8px;
margin-bottom: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.custom-tabs {
border-bottom: none;
padding-top: 20px;
}
.custom-tabs .el-tabs__header {
margin: 0 -20px 0 -20px;
padding: 0 20px;
border-bottom: 1px solid #e4e7ed;
}
.custom-tabs .el-tabs__nav-wrap::after {
height: 0;
}
.custom-tabs .el-tabs__item {
font-size: 14px;
color: #606266;
padding: 12px 20px;
margin-right: 20px;
border-bottom: 2px solid transparent;
}
.custom-tabs .el-tabs__item.is-active {
color: #409eff;
border-bottom-color: #409eff;
}
.custom-tabs .el-tabs__item:hover {
color: #409eff;
}
/* 筛选栏样式 */
.filter-bar {
background-color: #fff;
border-radius: 8px;
margin-bottom: 24px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
padding: 16px 24px;
}
.filter-container {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 16px;
width: 100%;
}
.filter-item {
flex-shrink: 0;
}
.filter-bar .el-select {
width: 180px;
height: 36px;
}
.filter-bar .el-select .el-input__inner {
border-radius: 4px;
border-color: #dcdfe6;
transition: all 0.2s ease;
}
.filter-bar .el-select .el-input__inner:focus {
border-color: #165dff;
box-shadow: 0 0 0 2px rgba(22, 93, 255, 0.1);
}
.filter-actions {
margin-left: auto;
display: flex;
gap: 12px;
flex-shrink: 0;
}
.search-btn {
background-color: #f2f3f5;
color: #303133;
border-color: #f2f3f5;
transition: all 0.2s ease;
}
.search-btn:hover {
background-color: #e5e6eb;
color: #303133;
border-color: #e5e6eb;
}
.create-btn {
background-color: #165dff;
border-color: #165dff;
transition: all 0.2s ease;
}
.create-btn:hover {
background-color: #0e42d2;
border-color: #0e42d2;
}
/* 任务卡片样式 */
.task-cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.task-card {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
padding: 16px 16px 60px 16px; /* 底部留出更多空间给按钮 */
transition: box-shadow 0.2s ease;
position: relative;
overflow: hidden;
min-height: 280px; /* 确保有足够高度显示所有内容 */
}
.task-actions {
display: flex;
justify-content: flex-end;
align-items: center;
padding-top: 12px;
border-top: 1px solid #f0f2f5;
position: absolute;
bottom: 16px;
right: 16px;
left: 16px;
background-color: #fff;
padding: 12px 0 0 0;
z-index: 10;
}
.task-card::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 4px;
}
.task-card.status-pending::before {
background-color: #1677ff;
}
.task-card.status-delayed::before {
background-color: #ff4d4f;
}
.task-card.status-executing::before {
background-color: #fa8c16;
}
.task-card.status-completed::before {
background-color: #52c41a;
}
.task-card:hover {
transform: translateY(-3px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
}
.task-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 16px;
padding-bottom: 12px;
border-bottom: 1px solid #f0f2f5;
}
.task-title {
font-size: 16px;
font-weight: 500;
color: #1d2129;
line-height: 1.4;
}
.task-status {
padding: 4px 10px;
border-radius: 6px;
font-size: 12px;
font-weight: 500;
border: 1px solid transparent;
}
/* 待执行状态 - 蓝色 */
.status-pending {
background-color: #e6f7ff;
color: #1677ff;
border-color: #91d5ff;
}
/* 已延期状态 - 红色 */
.status-delayed {
background-color: #fff2f0;
color: #ff4d4f;
border-color: #ffccc7;
}
/* 执行中状态 - 黄色 */
.status-executing {
background-color: #fffbe6;
color: #fa8c16;
border-color: #ffe58f;
}
/* 已完成状态 - 绿色 */
.status-completed {
background-color: #f6ffed;
color: #52c41a;
border-color: #b7eb8f;
}
.task-details {
margin-bottom: 16px;
}
.detail-item {
display: flex;
margin-bottom: 10px;
font-size: 13px;
}
.detail-label {
flex: 0 0 80px;
color: #86909c;
}
.detail-value {
flex: 1;
color: #4e5969;
word-break: break-all;
}
.delay-reason {
display: flex;
margin: 10px 0;
font-size: 13px;
padding-top: 8px;
border-top: 1px dashed #f0f2f5;
}
.progress-container {
display: flex;
flex-direction: column;
margin: 10px 0;
padding-top: 8px;
border-top: 1px dashed #f0f2f5;
z-index: 1;
}
.progress-bar {
flex: 1;
padding-left: 80px;
margin-top: 4px;
position: relative;
z-index: 1;
}
.progress-text {
position: absolute;
right: 0;
top: 0;
font-size: 12px;
color: #86909c;
}
.task-result {
display: flex;
margin: 10px 0;
font-size: 13px;
padding-top: 8px;
border-top: 1px dashed #f0f2f5;
}
.result-normal {
color: #00b42a;
}
.result-abnormal {
color: #f53f3f;
}
.task-actions {
display: flex;
justify-content: flex-end;
align-items: center;
padding-top: 12px;
border-top: 1px solid #f0f2f5;
position: absolute;
bottom: 16px;
right: 16px;
left: 16px;
background-color: #fff;
padding: 12px 0 0 0;
z-index: 10;
}
.action-btn {
font-size: 13px;
padding: 4px 10px;
}
.view-btn {
color: #165dff;
}
.view-btn:hover {
color: #0e42d2;
background-color: #e8f3ff;
}
.start-btn {
background-color: #165dff;
border-color: #165dff;
}
.start-btn:hover {
background-color: #0e42d2;
border-color: #0e42d2;
}
.reschedule-btn {
background-color: #ff7d00;
border-color: #ff7d00;
}
.reschedule-btn:hover {
background-color: #e86a00;
border-color: #e86a00;
}
.complete-btn {
background-color: #00b42a;
border-color: #00b42a;
}
.complete-btn:hover {
background-color: #008718;
border-color: #008718;
}
.report-btn {
background-color: #86909c;
border-color: #86909c;
}
.report-btn:hover {
background-color: #6b7785;
border-color: #6b7785;
}
/* 分页区域样式 */
.pagination-section {
display: flex;
justify-content: center;
margin-top: 20px;
}
.pagination-controls .el-pagination {
margin: 0;
}
.pagination-controls .el-pagination button,
.pagination-controls .el-pagination .el-pager li {
min-width: 36px;
height: 36px;
line-height: 36px;
border-radius: 4px;
}
.pagination-controls .el-pagination .el-pager li.active {
background-color: #165dff;
color: #fff;
}
/* 响应式设计 */
@media (max-width: 1200px) {
.task-cards {
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}
}
@media (max-width: 768px) {
.inspection-tasks {
padding: 16px;
}
.filter-container {
flex-direction: column;
align-items: stretch;
}
.filter-actions {
margin-left: 0;
justify-content: flex-end;
}
.filter-bar .el-select {
width: 100%;
}
.task-cards {
grid-template-columns: 1fr;
}
}
/* 导航栏样式 */
.navigation-tabs {
display: flex;
margin-bottom: 20px;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
padding: 2px;
}
.nav-tab {
padding: 12px 24px;
cursor: pointer;
transition: all 0.3s ease;
border-radius: 4px;
font-size: 14px;
color: #606266;
border-right: 1px solid #f0f0f0;
flex: 1;
text-align: center;
}
.nav-tab:last-child {
border-right: none;
}
.nav-tab:hover {
color: #409eff;
background-color: #ecf5ff;
}
.nav-tab.active {
background-color: #409eff;
color: #fff;
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
}
.nav-tab {
cursor: pointer;
user-select: none;
}
</style>

View File

@ -1,7 +1,7 @@
<template>
<div class="leftPage">
<div class="topPage">
<Title style="font-size: 22px" title="企业关键指标" />
<Title title="企业关键指标" />
<div class="indicators">
<div class="indicator-card" v-for="indicator in indicators" :key="indicator.id">
<div style="display: flex; align-items: baseline; gap: 4px; margin-bottom: 5px">
@ -17,7 +17,7 @@
</div>
<div class="endPage">
<Title style="font-size: 22px" title="人员情况" />
<Title title="人员情况" />
<!-- 人员总览区域 -->
<div class="people_overview">
<div class="people_overview_content">
@ -80,7 +80,7 @@
<!-- 项目出勤率柱状图 -->
<div class="project_attendance_chart">
<Title style="font-size: 22px" title="项目出勤率统计" />
<Title title="项目出勤率统计" />
<div class="chart_content" ref="attendanceChartRef"></div>
</div>
@ -108,31 +108,31 @@ const mapChartRef = ref<HTMLDivElement | null>(null);
const indicators = ref([
{
id: '1',
name: '在建项目',
name: '光伏项目',
value: '28',
unit: '个',
iconPath: '/assets/demo/beUnder.png'
},
{
id: '2',
name: '合同总额',
name: '风电项目',
value: '288.88',
unit: '亿元',
iconPath: '/assets/demo/contract.png'
unit: '',
iconPath: '/src/assets/images/contract.png'
},
{
id: '3',
name: '总容量',
name: '光伏系统总容量',
value: '158.88',
unit: '',
iconPath: '/assets/demo/totalCapacity.png'
unit: 'MW',
iconPath: '/src/assets/images/totalCapacity.png'
},
{
id: '4',
name: '今日施工',
name: '风电项目总容量',
value: '18',
unit: '',
iconPath: '/assets/demo/todayConstruction.png'
unit: 'MW',
iconPath: '/src/assets/images/todayConstruction.png'
}
]);
@ -255,7 +255,7 @@ const scrollToProject = (index: number) => {
// 计算滚动条应该移动到的位置
// 确保当前项目居中显示
const totalProjects = projectAttendanceData.value.length;
const visiblePercentage = 15; // 与dataZoom的end值保持一致
const visiblePercentage = 20; // 与dataZoom的end值保持一致
const itemPercentage = 100 / totalProjects; // 每个项目所占总宽度的百分比
// 计算新的start值使当前项目尽量居中显示
@ -273,28 +273,6 @@ const scrollToProject = (index: number) => {
}
};
/**
* 开始自动滚动
*/
const startScroll = () => {
if (scrollInterval.value) return;
scrollInterval.value = window.setInterval(() => {
currentScrollIndex.value++;
scrollToProject(currentScrollIndex.value);
}, scrollSpeed);
};
/**
* 停止自动滚动
*/
const stopScroll = () => {
if (scrollInterval.value) {
clearInterval(scrollInterval.value);
scrollInterval.value = null;
}
};
/**
* 获取项目出勤率统计数据 - 保持项目出勤率图表功能
*/
@ -367,10 +345,10 @@ const getKeyIndexData = async () => {
const { data, code } = res;
if (code === 200) {
// 更新指标数据,使用接口返回的指定字段
indicators.value[0].value = data.ongoingProject || 0;
indicators.value[1].value = data.totalContractAmount || 0;
indicators.value[2].value = data.totalCapacity || 0;
indicators.value[3].value = data.todayProject || 0;
indicators.value[0].value = data.photovoltaicCount || 0;
indicators.value[1].value = data.windElectricityCount || 0;
indicators.value[2].value = data.photovoltaicTotalCapacity || 0;
indicators.value[3].value = data.windElectricityTotalCapacity || 0;
}
};
@ -593,17 +571,9 @@ const initAttendanceChart = () => {
attendanceChart.setOption(option);
// 添加鼠标悬浮事件监听
// 移除自动滚动功能,保留其他事件监听
if (attendanceChartRef.value) {
// 鼠标进入图表区域时停止滚动
attendanceChartRef.value.addEventListener('mouseenter', () => {
stopScroll();
});
// 鼠标离开图表区域时重新开始滚动
attendanceChartRef.value.addEventListener('mouseleave', () => {
startScroll();
});
// 保留其他可能需要的事件监听器
}
// 添加窗口大小变化时的图表更新
@ -619,11 +589,7 @@ const initAttendanceChart = () => {
onUnmounted(() => {
window.removeEventListener('resize', handleResize);
// 移除鼠标事件监听
if (attendanceChartRef.value) {
attendanceChartRef.value.removeEventListener('mouseenter', stopScroll);
attendanceChartRef.value.removeEventListener('mouseleave', startScroll);
}
// 移除鼠标事件监听(已在上面移除添加的事件监听)
});
};
@ -652,9 +618,6 @@ onMounted(async () => {
// 再初始化图表
initAttendanceChart();
// 图表初始化后自动开始滚动
startScroll();
});
onUnmounted(() => {
@ -667,9 +630,6 @@ onUnmounted(() => {
attendanceChart.dispose();
attendanceChart = null;
}
// 清理滚动计时器
stopScroll();
});
</script>
@ -879,10 +839,8 @@ onUnmounted(() => {
text-shadow: 0px 1.24px 6.21px rgba(0, 200, 83, 0.5);
}
/* 点阵地图样式 */
.people_map {
width: 100%;
height: 120px;
margin-top: 8px;
background: rgba(10, 24, 45, 0.5);
border: 1px solid rgba(29, 214, 255, 0.1);

View File

@ -71,15 +71,17 @@ let data = [
const getTrajectoryData = async () => {
try {
// 从URL参数中获取clientId、projectId和userId
const { clientId, projectId, userId } = route.query;
const { clientId, projectId, userId, gpsType } = route.query;
if (!clientId || !projectId || !userId) {
if (!projectId || !userId || !gpsType) {
ElMessage.warning('缺少必要参数,请检查传入的参数');
return;
}
loading.value = true;
const res = await getFootNote({ clientId, projectId, userId });
// 确保gpsType转换为数字类型以便正确传递给后端
const gpsTypeNum = parseInt(gpsType, 10);
const res = await getFootNote({ clientId, projectId, userId, gpsType: gpsTypeNum });
if (res && res.code === 200 && res.data && res.data.length > 0) {
data = res.data;

View File

@ -22,7 +22,7 @@
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-row :gutter="20" class="mb8">
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['gps:equipment:edit']"
>修改</el-button
@ -39,7 +39,12 @@
>
</el-col>
<el-col :span="2">
<el-button type="primary" plain @click="handleViewAll">{{ viewAllButtonText }}</el-button>
<el-button type="primary" plain @click="toggleGpsType">
{{ currentGpsType === 0 ? '显示用户数据' : '显示设备数据' }}
</el-button>
</el-col>
<el-col :span="2">
<el-button type="primary" v-if="queryParams.gpsType !== 1" plain @click="handleViewAll">{{ viewAllButtonText }}</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
@ -102,7 +107,7 @@
type="primary"
icon="Location"
v-hasPermi="['gps:equipmentSon:getList']"
@click="handleGoToEmptyPage(scope.row.userId, scope.row.projectId, scope.row.clientId)"
@click="handleGoToEmptyPage(scope.row.userId, scope.row.projectId, scope.row.clientId, scope.row.gpsType)"
:disabled="!scope.row.userId || !scope.row.projectId"
></el-button>
</el-tooltip>
@ -189,7 +194,7 @@
type="primary"
icon="Location"
v-hasPermi="['gps:equipmentSon:getList']"
@click="handleGoToEmptyPage(scope.row.userId, scope.row.projectId, currentHistoryClientId)"
@click="handleGoToEmptyPage(scope.row.userId, scope.row.projectId, currentHistoryClientId, currentGpsType)"
></el-button>
</el-tooltip>
</template>
@ -301,6 +306,9 @@ const initFormData: EquipmentForm = {
remark: undefined
};
// 当前GPS类型 (0:设备数据, 1:用户数据)
const currentGpsType = ref(0);
// 页面数据
const data = reactive<PageData<EquipmentForm, EquipmentQuery>>({
form: { ...initFormData },
@ -317,6 +325,7 @@ const data = reactive<PageData<EquipmentForm, EquipmentQuery>>({
creationTime: undefined,
lastAccessedTime: undefined,
registered: undefined,
gpsType: 0, // 默认显示设备数据
params: {}
},
rules: {
@ -385,6 +394,15 @@ const formatDateTime = (timestamp: any): string => {
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
};
/** 切换GPS数据类型 */
const toggleGpsType = () => {
currentGpsType.value = currentGpsType.value === 0 ? 1 : 0;
queryParams.value.gpsType = currentGpsType.value;
queryParams.value.pageNum = 1;
getList();
proxy?.$modal.msgSuccess(`已切换到${currentGpsType.value === 0 ? '设备数据' : '用户数据'}模式`);
};
/** 获取设备列表 */
const getList = async () => {
loading.value = true;
@ -397,6 +415,9 @@ const getList = async () => {
queryParams.value.projectId = undefined;
}
// 确保gpsType参数正确设置
queryParams.value.gpsType = currentGpsType.value;
const res = await listEquipment(queryParams.value);
equipmentList.value = res.rows as ExtendedEquipmentVO[];
total.value = res.total;
@ -490,16 +511,24 @@ const handleViewAll = () => {
getList();
};
const handleGoToEmptyPage = (userId: any, projectId: any, clientId: any) => {
console.log('userId:', userId, 'projectId:', projectId, 'clientId:', clientId);
const handleGoToEmptyPage = (userId: any, projectId: any, clientId: any, gpsType: number) => {
console.log('userId:', userId, 'projectId:', projectId, 'clientId:', clientId, 'gpsType:', gpsType);
const queryParams: any = {
userId: userId,
projectId: projectId,
gpsType: gpsType,
clientId: clientId
};
// 当gpsType为0时传入clientId为1时不传入
if (gpsType === 1 && clientId) {
queryParams.clientId = '';
}
router.push({
path: './equipmentGPS',
query: {
userId: userId,
projectId: projectId,
clientId: clientId
}
query: queryParams
});
};

View File

@ -1,4 +1,4 @@
ID<template>
<template>
<div class="large-screen">
<Header />
<div class="nav">
@ -21,7 +21,6 @@ import leftPage from './components/leftPage.vue';
import centerPage from './components/centerPage.vue';
import rightPage from './components/rightPage.vue';
// import '@/assets/styles/element.scss';
</script>
<style scoped lang="scss">

View File

@ -101,10 +101,10 @@
<el-table-column label="操作" align="center" fixed="right" width="200">
<template #default="scope">
<!-- 查看子项按钮 -->
<el-tooltip content="查看子项" placement="top">
<!-- 查看流转台账按钮 -->
<el-tooltip content="查看流转台账" placement="top">
<el-button link type="primary" @click="handleViewSons(scope.row)" v-hasPermi="['land:landTransferLedger:childrenList']">
查看子项
查看流转台账
</el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
@ -162,7 +162,7 @@
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAddSon" v-hasPermi="['land:landTransferLedger:childrenAdd']">
新增子项
新增流转台账
</el-button>
</el-col>
</el-row>
@ -397,9 +397,7 @@
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button v-hasPermi="['land:landTransferLedger:addSon']" :loading="sonButtonLoading" type="primary" @click="submitSonForm"
> </el-button
>
<el-button :loading="sonButtonLoading" type="primary" @click="submitSonForm"> </el-button>
<el-button @click="cancelSonForm"> </el-button>
</div>
</template>
@ -1026,7 +1024,7 @@ const handleAdd = () => {
dialog.visible = true;
};
/** 查看子项按钮操作(打开子项弹窗时) */
/** 新增流转台账按钮操作(打开子项弹窗时) */
const handleViewSons = async (row: LandTransferLedgerVO) => {
if (!row?.id) return;
@ -1093,7 +1091,7 @@ const handleAddSon = async () => {
await getListRoad();
// 5. 打开弹窗
sonFormDialog.title = '添加子项(继承父项数据)';
sonFormDialog.title = '新增流转台账';
sonFormDialog.visible = true;
};

View File

@ -2,13 +2,18 @@
<div class="leftPage">
<div class="topPage">
<Title title="项目公告" />
<div class="content" ref="contentRef" id="event_scroll" @mouseenter="pauseScroll" @mouseleave="resumeScroll">
<div class="content_item" v-for="item in news" :key="item.id" @click="showNewsDetail(item)">
<img src="@/assets/projectLarge/round.svg" alt="">
<div
class="content"
ref="contentRef"
id="event_scroll"
@mouseenter.native="autoScrollTable(true, false)"
@mouseleave.native="autoScrollTable(false, true)"
>
<div class="content_item" v-for="item in news" :key="item.id">
<img src="@/assets/projectLarge/round.svg" alt="" />
<div class="ellipsis">
{{ item.title }}
<span style="color: rgba(138, 149, 165, 1);">{{ item.id === newId ? '关闭' :
'查看' }}</span>
<span @click="showNewsDetail(item)" style="color: rgba(138, 149, 165, 1)">{{ item.id === newId ? '关闭' : '查看' }}</span>
</div>
</div>
</div>
@ -18,40 +23,40 @@
<!-- <div class="detail_title">{{ newDetail.title }}</div> -->
<div class="detail_content" v-html="newDetail.content"></div>
<div class="close" @click="newId = ''">
<CircleClose style="width: 1.2em; height: 1.2em;" />
<CircleClose style="width: 1.2em; height: 1.2em" />
</div>
</div>
<div class="endPage">
<Title title="人员情况" />
<div class="map">
<img src="@/assets/projectLarge/map.svg" alt="">
<img src="@/assets/projectLarge/map.svg" alt="" />
<!-- <div ref="mapChartRef"></div> -->
</div>
<div class="attendance_tag">
<div class="tag_item">
<img src="@/assets/projectLarge/people.svg" alt="">
<img src="@/assets/projectLarge/people.svg" alt="" />
<div class="tag_title">出勤人</div>
<div class="tag_info">
{{ attendanceCount }}
<span style="font-size: 14px;"></span>
<span style="font-size: 14px"></span>
</div>
</div>
<div class="tag_item">
<img src="@/assets/projectLarge/people.svg" alt="">
<img src="@/assets/projectLarge/people.svg" alt="" />
<div class="tag_title">在岗人</div>
<div class="tag_info">
{{ peopleCount }}
<span style="font-size: 14px;"></span>
<span style="font-size: 14px"></span>
</div>
</div>
<div class="tag_item">
<img src="@/assets/projectLarge/people.svg" alt="">
<img src="@/assets/projectLarge/people.svg" alt="" />
<div class="tag_title">出勤率</div>
<div class="tag_info">
{{ attendanceRate }}
<span style="font-size: 14px;">%</span>
<span style="font-size: 14px">%</span>
</div>
</div>
</div>
@ -65,8 +70,9 @@
</div>
<div v-for="item in teamAttendanceList" :key="item.id" class="attendance_item">
<div class="attendance_item_title">{{ item.teamName }}</div>
<div class="attendance_item_number">{{ item.attendanceNumber }} <span class="subfont">/{{ item.allNumber
}}</span></div>
<div class="attendance_item_number">
{{ item.attendanceNumber }} <span class="subfont">/{{ item.allNumber }}</span>
</div>
<div class="attendance_item_rate">{{ item.attendanceRate }} %</div>
<div class="attendance_item_date subfont">{{ item.attendanceTime }}</div>
</div>
@ -76,71 +82,80 @@
</template>
<script setup lang="ts">
import { ref } from "vue"
import Title from './title.vue'
import { getScreenNews, getScreenPeople } from '@/api/projectScreen';
import { ref } from 'vue';
import Title from './title.vue';
import { getScreenNews, getScreenPeople } from '@/api/projectScreen/index';
import { mapOption } from './optionList';
import * as echarts from 'echarts';
const props = defineProps({
projectId: {
type: String,
default: ''
}
})
});
let mapChart = null;
const mapChartRef = ref<HTMLDivElement | null>(null);
const contentRef = ref<HTMLDivElement | null>(null);
const news = ref([])
const news = ref([]);
const newDetail = ref({
title: '',
content: ''
})
const newId = ref('')
const attendanceCount = ref(0)
const attendanceRate = ref(0)
const peopleCount = ref(0)
const teamAttendanceList = ref([
{ id: "", teamName: "", attendanceNumber: 0, allNumber: 0, attendanceRate: 0, attendanceTime: "" },
])
});
const newId = ref('');
const attendanceCount = ref(0);
const attendanceRate = ref(0);
const peopleCount = ref(0);
const teamAttendanceList = ref([{ id: '', teamName: '', attendanceNumber: 0, allNumber: 0, attendanceRate: 0, attendanceTime: '' }]);
/**
* 显示新闻详情
*/
const showNewsDetail = (item: any) => {
if (newId.value === item.id) {
newId.value = ''
return
newId.value = '';
return;
}
newDetail.value = item
newId.value = item.id
}
newDetail.value = item;
newId.value = item.id;
};
/**
* 获取项目人员出勤数据
*/
const getPeopleData = async () => {
const res = await getScreenPeople(props.projectId);
const { data, code } = res
const { data, code } = res;
if (code === 200) {
attendanceCount.value = data.attendanceCount
attendanceRate.value = data.attendanceRate
peopleCount.value = data.peopleCount
teamAttendanceList.value = data.teamAttendanceList
attendanceCount.value = data.attendanceCount;
attendanceRate.value = data.attendanceRate;
peopleCount.value = data.peopleCount;
teamAttendanceList.value = data.teamAttendanceList;
}
}
};
/**
* 获取项目新闻数据
*/
const getNewsData = async () => {
const res = await getScreenNews(props.projectId);
const { data, code } = res
const { data, code } = res;
if (code === 200) {
news.value = data
requestAnimationFrame((timestamp) => autoScrollTable(timestamp));
news.value = data;
autoScrollTable(5);
}
}
};
var lastTime = 0;
var scrolltimerTable = null
const state = reactive({
events: [],
outputList: [],
detialInfoShow: false,
notShowPro: [{ id: 37 }, { id: 44 }, { id: 48 }], //模块内容区域不展示的项目(中煤科工 广东户用光伏项目 兴隆光伏)
scrolltimerTable: null,
flagPause: true //滚动继续滚动
});
const autoScrollTable = (time: number) => {
const divData = document.getElementById('event_scroll');
@ -175,13 +190,14 @@ const resumeScroll = () => {
};
onMounted(() => {
getPeopleData()
getNewsData()
})
onUnmounted(() => {
// nextTick(() => {
// initMapChart();
// });
getPeopleData();
getNewsData();
});
onUnmounted(() => {});
</script>
<style scoped lang="scss">

View File

@ -35,7 +35,9 @@
<el-button type="warning" plain icon="Upload" @click="handleImport" v-hasPermi="['supplierInput:supplierInput:import']">导入</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['supplierInput:supplierInput:export']">导出模板</el-button>
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['supplierInput:supplierInput:export']"
>导出模板</el-button
>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
@ -703,7 +705,7 @@ const handleExport = () => {
try {
// 创建a标签并直接下载public目录下的静态文件
const link = document.createElement('a');
link.href = '/assets/files/供应商导入模板.xlsx'; // 使用public目录下现有的Excel文件作为模板
link.href = '/xx.xlsx';
link.download = '供应商导入模板.xlsx';
document.body.appendChild(link);
link.click();
@ -746,7 +748,7 @@ const handleImport = () => {
loading.value = true;
// 调用导入接口
const res = await leadingIn(formData, queryParams.value.projectId);
console.log("111111111111",queryParams.value.projectId);
console.log('111111111111', queryParams.value.projectId);
if (res.code === 200) {
proxy?.$modal.msgSuccess('导入成功');