parent
f61c5c3129
commit
fa82126d87
5 changed files with 1466 additions and 54 deletions
@ -0,0 +1,57 @@ |
||||
import request from '@/axios'; |
||||
|
||||
// 获取列表数据 bsCraftAbility/queryAllCa
|
||||
export const getList = (current, size, params) => { |
||||
return request({ |
||||
url: '/blade-desk/dsSpecialPro/list', |
||||
method: 'get', |
||||
params: { |
||||
...params, |
||||
current, |
||||
size, |
||||
}, |
||||
}); |
||||
}; |
||||
|
||||
// 保存
|
||||
export const add = row => { |
||||
return request({ |
||||
url: '/blade-desk/dsSpecialPro/save', |
||||
method: 'post', |
||||
data: row, |
||||
}); |
||||
}; |
||||
|
||||
|
||||
|
||||
// 修改
|
||||
export const update = row => { |
||||
return request({ |
||||
url: '/blade-desk/dsSpecialPro/update', |
||||
method: 'post', |
||||
data: row, |
||||
}); |
||||
}; |
||||
|
||||
// 删除
|
||||
export const remove = ids => { |
||||
return request({ |
||||
url: '/blade-desk/dsSpecialPro/remove', |
||||
method: 'post', |
||||
params: { |
||||
ids, |
||||
}, |
||||
}); |
||||
}; |
||||
|
||||
|
||||
// // 详情
|
||||
// export const getDetail = Id => {
|
||||
// return request({
|
||||
// url: '/blade-desk/dsProModel/detail',
|
||||
// method: 'get',
|
||||
// params: {
|
||||
// Id,
|
||||
// },
|
||||
// });
|
||||
// };
|
||||
@ -0,0 +1,742 @@ |
||||
<template> |
||||
<basic-container> |
||||
<avue-form :option="option" @submit="submit" @error="error"> |
||||
<template #menu-form> |
||||
<el-button type="primary" icon="el-icon-search" @click="handleSubmit"> 搜索 </el-button> |
||||
<el-button icon="el-icon-delete" @click="handleSubmit"> 清空 </el-button> |
||||
</template> |
||||
</avue-form> |
||||
|
||||
<div class="gantt-container"> |
||||
<!-- 头部标题和图例 --> |
||||
<div class="gantt-header"> |
||||
<!-- <h2>设备生产任务甘特图</h2> --> |
||||
<div class="status-legend"> |
||||
<div class="legend-item"> |
||||
<span class="legend-color completed"></span> |
||||
<span>已完成</span> |
||||
</div> |
||||
<div class="legend-item"> |
||||
<span class="legend-color processing"></span> |
||||
<span>进行中</span> |
||||
</div> |
||||
<div class="legend-item"> |
||||
<span class="legend-color pending"></span> |
||||
<span>未开始</span> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<!-- 甘特图主体 --> |
||||
<div class="gantt-wrapper"> |
||||
<!-- 左侧设备列表 --> |
||||
<div class="device-list"> |
||||
<div class="device-item device-item-title" :style="{ height: '36px' }">设备</div> |
||||
<div |
||||
v-for="(device, index) in devices" |
||||
:key="index" |
||||
class="device-item" |
||||
:style="{ height: rowHeight + 'px' }" |
||||
> |
||||
{{ device }} |
||||
</div> |
||||
</div> |
||||
|
||||
<!-- 右侧时间轴 (时间在上,刻度线在下) --> |
||||
<div class="timeline-container" @wheel.prevent="handleWheel"> |
||||
<!-- 图表X轴区域(时间在上,刻度线在下) --> |
||||
<div class="chart-axis"> |
||||
<!-- 时间标签 --> |
||||
<div class="time-labels" :style="{ width: `${timelineWidth}%` }"> |
||||
<!-- 主刻度标签(小时) --> |
||||
<div |
||||
v-for="(time, index) in majorTickLabels" |
||||
:key="index" |
||||
class="major-label" |
||||
:style="{ left: `${(index / 24) * 100}%` }" |
||||
> |
||||
{{ time }} |
||||
</div> |
||||
|
||||
<!-- 副刻度标签(30分钟,放大后显示) --> |
||||
<div v-if="zoomLevel >= 2" class="minor-labels"> |
||||
<div |
||||
v-for="(time, index) in minorTickLabels" |
||||
:key="index" |
||||
class="minor-label" |
||||
:style="{ left: `${(index / (24 * 2)) * 100}%` }" |
||||
> |
||||
{{ time }} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<!-- 刻度线(在下方) --> |
||||
<div class="tick-lines" :style="{ width: `${timelineWidth}%` }"> |
||||
<!-- 主刻度线(小时) --> |
||||
<div |
||||
v-for="(time, index) in majorTickLabels" |
||||
:key="index" |
||||
class="major-tick-line" |
||||
:style="{ left: `${(index / 24) * 100}%` }" |
||||
:title="time" |
||||
></div> |
||||
|
||||
<!-- 副刻度线(30分钟,放大后显示) --> |
||||
<div v-if="zoomLevel >= 2" class="minor-tick-lines"> |
||||
<div |
||||
v-for="(time, index) in minorTickLabels" |
||||
:key="index" |
||||
class="minor-tick-line" |
||||
:style="{ left: `${(index / (24 * 2)) * 100}%` }" |
||||
:title="time" |
||||
></div> |
||||
</div> |
||||
|
||||
<!-- X轴基线 --> |
||||
<div class="axis-base-line"></div> |
||||
</div> |
||||
</div> |
||||
|
||||
<!-- 甘特图内容区域 --> |
||||
<div class="chart-content" :style="{ width: `${timelineWidth}%` }"> |
||||
<!-- 网格线 --> |
||||
<div class="grid-lines"> |
||||
<div |
||||
v-for="(time, index) in majorTickLabels" |
||||
:key="index" |
||||
class="grid-line" |
||||
:style="{ left: `${(index / 24) * 100}%` }" |
||||
></div> |
||||
</div> |
||||
|
||||
<!-- 任务容器 --> |
||||
<div class="tasks-container"> |
||||
<div |
||||
v-for="(device, devIndex) in devices" |
||||
:key="devIndex" |
||||
class="device-task-row" |
||||
:style="{ height: rowHeight + 'px' }" |
||||
> |
||||
<div |
||||
v-for="(task, taskIndex) in getDeviceTasks(device)" |
||||
:key="taskIndex" |
||||
class="task-bar" |
||||
:style="{ |
||||
left: `${getPositionPercent(task.start)}%`, |
||||
width: `${getWidthPercent(task.start, task.end)}%`, |
||||
backgroundColor: getStatusColor(task.status), |
||||
}" |
||||
@mouseenter="showTooltip($event, task, device)" |
||||
@mouseleave="hideTooltip()" |
||||
> |
||||
<span class="task-label">{{ task.task }}</span> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<!-- 悬浮提示框 --> |
||||
<div |
||||
v-if="tooltipVisible" |
||||
class="tooltip" |
||||
:style="{ |
||||
left: `${tooltipX}px`, |
||||
top: `${tooltipY}px`, |
||||
}" |
||||
> |
||||
<div class="tooltip-content"> |
||||
<div><strong>设备:</strong>{{ tooltipData.device }}</div> |
||||
<div><strong>任务:</strong>{{ tooltipData.task }}</div> |
||||
<div><strong>时间:</strong>{{ tooltipData.start }} - {{ tooltipData.end }}</div> |
||||
<div><strong>状态:</strong>{{ tooltipData.status }}</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</basic-container> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
name: 'GanttChart', |
||||
data() { |
||||
return { |
||||
rowHeight: 36, |
||||
zoomLevel: 1, // 缩放级别 (1-4) |
||||
minZoom: 1, |
||||
maxZoom: 4, |
||||
|
||||
// 设备列表 |
||||
devices: [ |
||||
'铜合金零件化学镀镍线(9652248)', |
||||
'铜合金化学镀镍烤箱(9652248-01)', |
||||
'铜合金化学镀镍烤箱(9652248-02)', |
||||
'铜合金化学镀镍烤箱(9652248-03)', |
||||
'铝合金化学镀镍生产线(9653582)', |
||||
'铝合金化学镀镍烤箱(9653582-01)', |
||||
'铝合金化学镀镍烤箱(9653582-02)', |
||||
'铝合金化学镀镍烤箱(9653582-03)', |
||||
'铝合金化学镀镍烤箱(9653582-04)', |
||||
'镀金生产线(9652249)', |
||||
'热表线烘箱(9652249-01)', |
||||
'热表线烘箱(9652249-02)', |
||||
'热表线烘箱(9652249-03)', |
||||
'热表线烘箱(9652249-04)', |
||||
'喷漆生产线(965396)', |
||||
'喷码机(9652055)', |
||||
'喷漆生产线(965396)', |
||||
'喷码机(9652055)', |
||||
], |
||||
|
||||
// 任务数据 |
||||
taskData: [ |
||||
{ |
||||
device: '铜合金零件化学镀镍线(9652248)', |
||||
task: 'WO-N261026761', |
||||
start: '00:15', |
||||
end: '08:45', |
||||
status: '已完成', |
||||
}, |
||||
{ |
||||
device: '铜合金零件化学镀镍线(9652248)', |
||||
task: 'WO-N261026762', |
||||
start: '09:30', |
||||
end: '12:15', |
||||
status: '已完成', |
||||
}, |
||||
{ |
||||
device: '铜合金零件化学镀镍线(9652248)', |
||||
task: 'WO-N261026764', |
||||
start: '13:20', |
||||
end: '16:50', |
||||
status: '已完成', |
||||
}, |
||||
{ |
||||
device: '铜合金零件化学镀镍线(9652248)', |
||||
task: 'WO-N261026763', |
||||
start: '16:00', |
||||
end: '18:30', |
||||
status: '进行中', |
||||
}, |
||||
{ |
||||
device: '铜合金零件化学镀镍线(9652248)', |
||||
task: 'WO-N2610287265', |
||||
start: '19:10', |
||||
end: '23:45', |
||||
status: '未开始', |
||||
}, |
||||
|
||||
{ |
||||
device: '铜合金化学镀镍烤箱(9652248-01)', |
||||
task: 'WO-N261026727', |
||||
start: '09:15', |
||||
end: '11:30', |
||||
status: '已完成', |
||||
}, |
||||
{ |
||||
device: '铜合金化学镀镍烤箱(9652248-01)', |
||||
task: 'WO-N261026729', |
||||
start: '12:20', |
||||
end: '14:40', |
||||
status: '已完成', |
||||
}, |
||||
{ |
||||
device: '铜合金化学镀镍烤箱(9652248-01)', |
||||
task: 'WO-N261026721', |
||||
start: '15:50', |
||||
end: '17:20', |
||||
status: '进行中', |
||||
}, |
||||
{ |
||||
device: '铜合金化学镀镍烤箱(9652248-01)', |
||||
task: 'WO-N2610287244', |
||||
start: '18:10', |
||||
end: '20:30', |
||||
status: '未开始', |
||||
}, |
||||
{ |
||||
device: '铜合金化学镀镍烤箱(9652248-01)', |
||||
task: 'WO-N261026778', |
||||
start: '21:25', |
||||
end: '23:55', |
||||
status: '未开始', |
||||
}, |
||||
{ |
||||
device: '铜合金化学镀镍烤箱(9652248-01)', |
||||
task: 'WO-N2610287244', |
||||
start: '18:10', |
||||
end: '20:30', |
||||
status: '未开始', |
||||
}, |
||||
{ |
||||
device: '铜合金化学镀镍烤箱(9652248-01)', |
||||
task: 'WO-N261026778', |
||||
start: '21:25', |
||||
end: '23:55', |
||||
status: '未开始', |
||||
}, |
||||
], |
||||
|
||||
// 提示框相关 |
||||
tooltipVisible: false, |
||||
tooltipData: {}, |
||||
tooltipX: 0, |
||||
tooltipY: 0, |
||||
option: { |
||||
menuSpan: 4, |
||||
submitBtn: false, |
||||
emptyBtn: false, |
||||
menuPosition: 'right', |
||||
column: [ |
||||
{ |
||||
label: '设备', |
||||
prop: 'name', |
||||
span: 5, |
||||
type: 'select', |
||||
dicData: [ |
||||
{ |
||||
label: '车间订单', |
||||
value: 1, |
||||
}, |
||||
{ |
||||
label: '设备', |
||||
value: 2, |
||||
}, |
||||
{ |
||||
label: '班组', |
||||
value: 3, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
label: '车间订单号', |
||||
prop: 'name', |
||||
span: 5, |
||||
}, |
||||
{ |
||||
label: '班组', |
||||
prop: 'name', |
||||
span: 5, |
||||
type: 'select', |
||||
dicData: [ |
||||
{ |
||||
label: '班组1', |
||||
value: 1, |
||||
}, |
||||
{ |
||||
label: '班组2', |
||||
value: 2, |
||||
}, |
||||
{ |
||||
label: '班组3', |
||||
value: 3, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
label: '时间', |
||||
prop: 'name', |
||||
span: 5, |
||||
type: 'date', |
||||
}, |
||||
], |
||||
}, |
||||
}; |
||||
}, |
||||
computed: { |
||||
// 时间轴总宽度 |
||||
timelineWidth() { |
||||
return 100 * this.zoomLevel; |
||||
}, |
||||
// 主刻度标签(小时) |
||||
majorTickLabels() { |
||||
return Array.from({ length: 24 }, (_, i) => `${i}:00`); |
||||
}, |
||||
// 副刻度标签(30分钟) |
||||
minorTickLabels() { |
||||
const labels = []; |
||||
for (let hour = 0; hour < 24; hour++) { |
||||
labels.push(''); // 小时位置留空(主刻度已显示) |
||||
labels.push(`${hour}:30`); |
||||
} |
||||
return labels; |
||||
}, |
||||
}, |
||||
methods: { |
||||
// 根据设备筛选任务 |
||||
getDeviceTasks(device) { |
||||
return this.taskData.filter(task => task.device === device); |
||||
}, |
||||
|
||||
// 时间转分钟数 |
||||
timeToMinutes(timeStr) { |
||||
const [hours, minutes] = timeStr.split(':').map(Number); |
||||
return hours * 60 + minutes; |
||||
}, |
||||
|
||||
// 计算任务起始位置百分比 |
||||
getPositionPercent(startTime) { |
||||
const totalMinutes = 24 * 60; |
||||
const startMinutes = this.timeToMinutes(startTime); |
||||
return (startMinutes / totalMinutes) * 100; |
||||
}, |
||||
|
||||
// 计算任务宽度百分比 |
||||
getWidthPercent(startTime, endTime) { |
||||
const startMinutes = this.timeToMinutes(startTime); |
||||
const endMinutes = this.timeToMinutes(endTime); |
||||
const duration = endMinutes - startMinutes; |
||||
return (duration / (24 * 60)) * 100; |
||||
}, |
||||
|
||||
// 根据状态获取颜色 |
||||
getStatusColor(status) { |
||||
switch (status) { |
||||
case '已完成': |
||||
return '#28a745'; |
||||
case '进行中': |
||||
return '#007bff'; |
||||
case '未开始': |
||||
return '#6c757d'; |
||||
default: |
||||
return '#ccc'; |
||||
} |
||||
}, |
||||
|
||||
// 鼠标滚轮缩放 |
||||
handleWheel(e) { |
||||
if (e.deltaY < 0 && this.zoomLevel < this.maxZoom) { |
||||
this.zoomLevel += 0.5; |
||||
} else if (e.deltaY > 0 && this.zoomLevel > this.minZoom) { |
||||
this.zoomLevel -= 0.5; |
||||
} |
||||
}, |
||||
|
||||
// 放大/缩小/重置 |
||||
zoomIn() { |
||||
if (this.zoomLevel < this.maxZoom) this.zoomLevel += 0.5; |
||||
}, |
||||
zoomOut() { |
||||
if (this.zoomLevel > this.minZoom) this.zoomLevel -= 0.5; |
||||
}, |
||||
resetZoom() { |
||||
this.zoomLevel = this.minZoom; |
||||
}, |
||||
|
||||
// 提示框控制 |
||||
showTooltip(e, task, device) { |
||||
this.tooltipData = { ...task, device }; |
||||
this.tooltipX = e.pageX + 10; |
||||
this.tooltipY = e.pageY + 10; |
||||
this.tooltipVisible = true; |
||||
}, |
||||
hideTooltip() { |
||||
this.tooltipVisible = false; |
||||
}, |
||||
}, |
||||
}; |
||||
</script> |
||||
|
||||
<style scoped> |
||||
.gantt-container { |
||||
width: 100%; |
||||
padding: 20px; |
||||
box-sizing: border-box; |
||||
font-family: Arial, sans-serif; |
||||
} |
||||
|
||||
.gantt-header { |
||||
height: 40px; |
||||
} |
||||
|
||||
.zoom-controls { |
||||
display: flex; |
||||
gap: 10px; |
||||
margin-bottom: 15px; |
||||
padding-left: 265px; |
||||
align-items: center; |
||||
} |
||||
|
||||
.zoom-btn { |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 5px; |
||||
padding: 4px 10px; |
||||
background-color: #f1f5f9; |
||||
border: 1px solid #ddd; |
||||
border-radius: 4px; |
||||
cursor: pointer; |
||||
font-size: 12px; |
||||
transition: all 0.2s; |
||||
} |
||||
|
||||
.zoom-btn:hover { |
||||
background-color: #e2e8f0; |
||||
} |
||||
|
||||
.zoom-info { |
||||
font-size: 12px; |
||||
color: #666; |
||||
} |
||||
|
||||
.status-legend { |
||||
display: flex; |
||||
gap: 20px; |
||||
float: right; |
||||
} |
||||
|
||||
.legend-item { |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 5px; |
||||
font-size: 14px; |
||||
} |
||||
|
||||
.legend-color { |
||||
display: inline-block; |
||||
width: 12px; |
||||
height: 12px; |
||||
border-radius: 2px; |
||||
} |
||||
|
||||
.legend-color.completed { |
||||
background-color: #28a745; |
||||
} |
||||
.legend-color.processing { |
||||
background-color: #007bff; |
||||
} |
||||
.legend-color.pending { |
||||
background-color: #6c757d; |
||||
} |
||||
|
||||
.gantt-wrapper { |
||||
display: flex; |
||||
height: calc(100% - 120px); |
||||
border: 1px solid #eee; |
||||
overflow: hidden; |
||||
} |
||||
|
||||
.device-list { |
||||
width: 250px; |
||||
background-color: #f8f9fa; |
||||
border-right: 1px solid #eee; |
||||
/* overflow-y: auto; */ |
||||
flex-shrink: 0; |
||||
} |
||||
|
||||
.device-item { |
||||
font-size: 16px; |
||||
color: #333; |
||||
white-space: nowrap; |
||||
overflow: hidden; |
||||
text-overflow: ellipsis; |
||||
position: relative; |
||||
line-height: 36px; |
||||
padding-left: 15px; |
||||
padding-right: 15px; |
||||
&::after { |
||||
content: ''; |
||||
position: absolute; |
||||
bottom: 0; |
||||
left: 0; |
||||
width: 100%; |
||||
height: 1px; |
||||
background-color: #eee; |
||||
} |
||||
} |
||||
.device-item-title { |
||||
background: var(--el-color-primary); |
||||
text-align: center; |
||||
color: #fff; |
||||
} |
||||
|
||||
.timeline-container { |
||||
flex: 1; |
||||
display: flex; |
||||
flex-direction: column; |
||||
overflow: auto; |
||||
} |
||||
|
||||
/* 图表X轴区域样式(时间在上,刻度线在下) */ |
||||
.chart-axis { |
||||
height: 36px; |
||||
position: relative; |
||||
} |
||||
|
||||
/* 时间标签容器 */ |
||||
.time-labels { |
||||
position: absolute; |
||||
top: 0; |
||||
left: 0; |
||||
width: 100%; |
||||
height: 30px; |
||||
display: flex; |
||||
background-color: var(--el-color-primary); |
||||
} |
||||
|
||||
/* 主刻度标签(小时) */ |
||||
.major-label { |
||||
position: absolute; |
||||
top: 0; |
||||
left: 0; |
||||
/* transform: translateX(-50%); */ |
||||
font-size: 16px; |
||||
color: #fff; |
||||
font-weight: 500; |
||||
white-space: nowrap; |
||||
line-height: 30px; |
||||
} |
||||
|
||||
/* 副刻度标签(30分钟) */ |
||||
.minor-labels { |
||||
position: absolute; |
||||
top: 0; |
||||
left: 0; |
||||
width: 100%; |
||||
height: 100%; |
||||
} |
||||
|
||||
.minor-label { |
||||
position: absolute; |
||||
top: 0; |
||||
left: 0; |
||||
/* transform: translateX(-50%); */ |
||||
font-size: 16px; |
||||
color: #fff; |
||||
white-space: nowrap; |
||||
line-height: 30px; |
||||
padding: 0 2px; |
||||
} |
||||
|
||||
/* 刻度线容器(在下方) */ |
||||
.tick-lines { |
||||
position: absolute; |
||||
bottom: 0; |
||||
left: 0; |
||||
width: 100%; |
||||
height: 6px; |
||||
background-color: var(--el-color-primary); |
||||
} |
||||
|
||||
/* 主刻度线(小时) */ |
||||
.major-tick-line { |
||||
position: absolute; |
||||
bottom: 0; |
||||
width: 1px; |
||||
height: 4px; |
||||
background-color: #fff; |
||||
transform: translateX(-50%); |
||||
} |
||||
|
||||
/* 副刻度线(30分钟) */ |
||||
.minor-tick-lines { |
||||
position: absolute; |
||||
bottom: 0; |
||||
left: 0; |
||||
width: 100%; |
||||
height: 100%; |
||||
} |
||||
|
||||
.minor-tick-line { |
||||
position: absolute; |
||||
bottom: 0; |
||||
width: 1px; |
||||
height: 4px; |
||||
background-color: #fff; |
||||
transform: translateX(-50%); |
||||
} |
||||
|
||||
/* X轴基线 */ |
||||
.axis-base-line { |
||||
position: absolute; |
||||
bottom: 0; |
||||
left: 0; |
||||
width: 100%; |
||||
height: 1px; |
||||
background-color: #dee2e6; |
||||
} |
||||
|
||||
/* 图表内容区域 */ |
||||
.chart-content { |
||||
flex: 1; |
||||
position: relative; |
||||
overflow-y: auto; |
||||
} |
||||
|
||||
/* 网格线样式 */ |
||||
.grid-lines { |
||||
position: absolute; |
||||
top: 0; |
||||
left: 0; |
||||
width: 100%; |
||||
height: 100%; |
||||
pointer-events: none; |
||||
} |
||||
|
||||
.grid-line { |
||||
position: absolute; |
||||
top: 0; |
||||
bottom: 0; |
||||
width: 0px; |
||||
background-color: #e9ecef; |
||||
} |
||||
|
||||
/* 任务容器 */ |
||||
.tasks-container { |
||||
position: relative; |
||||
width: 100%; |
||||
height: 100%; |
||||
} |
||||
|
||||
.device-task-row { |
||||
position: relative; |
||||
border-bottom: 1px solid #e9ecef; |
||||
box-sizing: border-box; |
||||
} |
||||
|
||||
.task-bar { |
||||
position: absolute; |
||||
top: 5px; |
||||
height: 26px; |
||||
border-radius: 4px; |
||||
display: flex; |
||||
align-items: center; |
||||
padding: 0 10px; |
||||
box-sizing: border-box; |
||||
cursor: pointer; |
||||
overflow: hidden; |
||||
transition: all 0.2s; |
||||
} |
||||
|
||||
.task-bar:hover { |
||||
transform: translateY(-2px); |
||||
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.1); |
||||
} |
||||
|
||||
.task-label { |
||||
font-size: 12px; |
||||
color: white; |
||||
white-space: nowrap; |
||||
overflow: hidden; |
||||
text-overflow: ellipsis; |
||||
} |
||||
|
||||
/* 提示框 */ |
||||
.tooltip { |
||||
position: fixed; |
||||
background-color: white; |
||||
border: 1px solid #ddd; |
||||
border-radius: 4px; |
||||
padding: 10px; |
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); |
||||
z-index: 1000; |
||||
font-size: 12px; |
||||
pointer-events: none; |
||||
} |
||||
|
||||
.tooltip-content div { |
||||
margin: 3px 0; |
||||
} |
||||
</style> |
||||
@ -0,0 +1,561 @@ |
||||
|
||||
<template> |
||||
<basic-container> |
||||
<div class="search_box"> |
||||
|
||||
</div> |
||||
<avue-crud :option="option" :table-loading="loading" :data="data" v-model="form" v-model:page="page" ref="crud" |
||||
@row-del="rowDel" @search-change="searchChange" @search-reset="searchReset" |
||||
@selection-change="selectionChange" @current-change="currentChange" @size-change="sizeChange" |
||||
@refresh-change="refreshChange" @on-load="onLoad"> |
||||
<template #menu-left> |
||||
<!-- <el-button type="danger" @click="batchDel()">删除</el-button> --> |
||||
</template> |
||||
<template #menu-right> |
||||
<!-- <el-button type="primary" @click="batchDel()">导入</el-button> --> |
||||
</template> |
||||
<template #menu="{ row }"> |
||||
|
||||
</template> |
||||
|
||||
<template #heatTreat="scope"> |
||||
<!-- <el-tag v-if="scope.row.afterPlating" type="success">是</el-tag> |
||||
<el-tag v-else type="warning">否</el-tag> --> |
||||
</template> |
||||
|
||||
</avue-crud> |
||||
|
||||
|
||||
</basic-container> |
||||
</template> |
||||
|
||||
<script> |
||||
|
||||
import { |
||||
add, |
||||
getRole, |
||||
getRoleAlias, |
||||
getRoleTreeById, |
||||
grant, |
||||
grantTree, |
||||
remove, |
||||
update, |
||||
} from '@/api/system/role'; |
||||
import { mapGetters } from 'vuex'; |
||||
import { validatenull } from '@/utils/validate'; |
||||
|
||||
|
||||
export default { |
||||
components: { |
||||
}, |
||||
data() { |
||||
return { |
||||
inBatchesOpen: false, |
||||
platingSmallOpen: false, |
||||
planOrderArr: [], |
||||
isOpen: false, |
||||
rowItem: {}, |
||||
poId: null, |
||||
form: {}, |
||||
box: false, |
||||
props: { |
||||
label: 'title', |
||||
value: 'key', |
||||
}, |
||||
menuGrantList: [], |
||||
dataScopeGrantList: [], |
||||
apiScopeGrantList: [], |
||||
apiGrantList: [], |
||||
menuTreeObj: [], |
||||
dataScopeTreeObj: [], |
||||
apiScopeTreeObj: [], |
||||
selectionList: [], |
||||
query: {}, |
||||
loading: true, |
||||
page: { |
||||
pageSize: 10, |
||||
currentPage: 1, |
||||
total: 0, |
||||
}, |
||||
option: { |
||||
columnSort: true, |
||||
tip: false, |
||||
height: 'auto', |
||||
calcHeight: 32, |
||||
simplePage: false, |
||||
searchShow: true, |
||||
searchMenuSpan: 6, |
||||
searchIcon: true, |
||||
searchIndex: 3, |
||||
tree: false, |
||||
border: true, |
||||
index: true, |
||||
selection: false, |
||||
addBtn: false, |
||||
editBtn: false, |
||||
viewBtn: false, |
||||
delBtn: false, |
||||
editBtnText: '修改', |
||||
labelWidth: 120, |
||||
menuWidth: 80, |
||||
dialogWidth: 900, |
||||
dialogClickModal: false, |
||||
searchEnter: true, |
||||
excelBtn: false, |
||||
filterBtn: true, |
||||
searchShowBtn: false, |
||||
excelBtn: true, |
||||
showOverflowTooltip: true, |
||||
addBtnIcon: ' ', |
||||
viewBtnIcon: ' ', |
||||
delBtnIcon: ' ', |
||||
editBtnIcon: ' ', |
||||
gridBtn: false, |
||||
searchLabelPosition: 'left', |
||||
searchGutter: 24, |
||||
searchSpan: 6, |
||||
menuAlign: 'left', |
||||
gridBtn: false, |
||||
searchMenuPosition: 'right', |
||||
align: 'center', |
||||
column: [ |
||||
{ |
||||
label: '异常原因', |
||||
prop: 'partCode', |
||||
search: false, |
||||
sortable: true, |
||||
width: 150, |
||||
span: 12, |
||||
|
||||
}, |
||||
{ |
||||
label: '处理方式', |
||||
prop: 'partName', |
||||
search: false, |
||||
sortable: true, |
||||
width: 150, |
||||
span: 12, |
||||
}, |
||||
{ |
||||
label: '调度员', |
||||
prop: 'cycle', |
||||
search: false, |
||||
sortable: true, |
||||
width: 150, |
||||
span: 12, |
||||
}, |
||||
{ |
||||
label: '生产单号', |
||||
prop: 'material', |
||||
search: true, |
||||
sortable: true, |
||||
width: 150, |
||||
span: 12, |
||||
display: false, |
||||
}, |
||||
{ |
||||
label: '计划单号', |
||||
prop: 'plate', |
||||
search: false, |
||||
sortable: true, |
||||
width: 150, |
||||
span: 12, |
||||
display: false, |
||||
}, |
||||
{ |
||||
label: '订单优先级', |
||||
prop: 'craftWay', |
||||
search: false, |
||||
sortable: true, |
||||
width: 150, |
||||
span: 12, |
||||
display: false, |
||||
}, |
||||
{ |
||||
label: '零件号', |
||||
prop: 'chlidPart', |
||||
search: true, |
||||
sortable: true, |
||||
width: 150, |
||||
span: 12, |
||||
}, |
||||
{ |
||||
label: '零件名称', |
||||
prop: 'remindContent', |
||||
search: false, |
||||
sortable: true, |
||||
width: 150, |
||||
span: 12, |
||||
}, |
||||
{ |
||||
label: '产品型号', |
||||
prop: 'parameter', |
||||
search: false, |
||||
sortable: true, |
||||
width: 150, |
||||
span: 12, |
||||
}, |
||||
{ |
||||
label: '批次号', |
||||
prop: 'metalsTest', |
||||
search: true, |
||||
sortable: true, |
||||
width: 150, |
||||
span: 12, |
||||
}, |
||||
{ |
||||
label: '流程卡号', |
||||
prop: 'silverTest', |
||||
search: true, |
||||
sortable: true, |
||||
width: 150, |
||||
span: 12, |
||||
display: false, |
||||
}, |
||||
{ |
||||
label: '流转编码', |
||||
prop: 'heatTreat', |
||||
search: true, |
||||
sortable: true, |
||||
width: 150, |
||||
span: 12, |
||||
type: 'switch', |
||||
|
||||
}, |
||||
{ |
||||
label: '镀种', |
||||
prop: 'afterPlating', |
||||
search: false, |
||||
sortable: true, |
||||
width: 150, |
||||
span: 12, |
||||
|
||||
}, |
||||
{ |
||||
label: '生产标识', |
||||
prop: 'afterPlating', |
||||
search: false, |
||||
sortable: true, |
||||
width: 150, |
||||
span: 12, |
||||
|
||||
}, |
||||
{ |
||||
label: '生产数量', |
||||
prop: 'afterPlating', |
||||
search: false, |
||||
sortable: true, |
||||
width: 150, |
||||
span: 12, |
||||
|
||||
}, |
||||
{ |
||||
label: '面积(d㎡)', |
||||
prop: 'afterPlating', |
||||
search: false, |
||||
sortable: true, |
||||
width: 150, |
||||
span: 12, |
||||
|
||||
}, |
||||
{ |
||||
label: '需求交期', |
||||
prop: 'afterPlating', |
||||
search: false, |
||||
sortable: true, |
||||
width: 150, |
||||
span: 12, |
||||
|
||||
}, |
||||
|
||||
{ |
||||
label: '计划下达时间', |
||||
prop: 'afterPlating', |
||||
search: false, |
||||
sortable: true, |
||||
width: 150, |
||||
span: 12, |
||||
|
||||
}, |
||||
|
||||
{ |
||||
label: '备注', |
||||
prop: 'afterPlating', |
||||
search: false, |
||||
sortable: true, |
||||
width: 150, |
||||
span: 12, |
||||
|
||||
}, |
||||
|
||||
], |
||||
}, |
||||
|
||||
data: [], |
||||
isRushOpen: false,//加急弹框 |
||||
isBatchOpen: false,//分批处理 |
||||
}; |
||||
}, |
||||
methods: { |
||||
// 批量接收 |
||||
batchReceiving() { |
||||
this.$confirm('确定将选择数据批量接收?', { |
||||
confirmButtonText: '确定', |
||||
cancelButtonText: '取消', |
||||
type: 'warning', |
||||
}) |
||||
.then(() => { |
||||
// return remove(row.id); |
||||
}) |
||||
.then(() => { |
||||
// this.onLoad(this.page); |
||||
// this.$message({ |
||||
// type: 'success', |
||||
// message: '操作成功!', |
||||
// }); |
||||
}); |
||||
}, |
||||
// 批量关闭 |
||||
batchDel() { |
||||
this.$confirm('确定将选择数据批量删除?', { |
||||
confirmButtonText: '确定', |
||||
cancelButtonText: '取消', |
||||
type: 'warning', |
||||
}) |
||||
.then(() => { |
||||
// return remove(row.id); |
||||
}) |
||||
.then(() => { |
||||
// this.onLoad(this.page); |
||||
// this.$message({ |
||||
// type: 'success', |
||||
// message: '操作成功!', |
||||
// }); |
||||
}); |
||||
}, |
||||
// 加急 |
||||
rushFn() { |
||||
this.isRushOpen = true |
||||
}, |
||||
closeDialog() { |
||||
this.isRushOpen = false |
||||
this.isBatchOpen = false |
||||
}, |
||||
inBatchesFn(row) { |
||||
this.rowItem = row; |
||||
this.isBatchOpen = true; |
||||
}, |
||||
subclass() { |
||||
this.platingSmallOpen = true; |
||||
}, |
||||
lookProcessRoute(row) { |
||||
this.isOpen = true; |
||||
this.rowItem = row; |
||||
}, |
||||
cancel(refresh) { |
||||
if (refresh) { |
||||
this.$refs.myTable.load(); |
||||
} |
||||
this.inBatchesOpen = false; |
||||
this.isOpen = false; |
||||
this.planFormOpen = false; |
||||
this.platingSmallOpen = false; |
||||
}, |
||||
initData(roleId) { |
||||
getRoleTreeById(roleId).then(res => { |
||||
const column = this.findObject(this.option.column, 'parentId'); |
||||
column.dicData = res.data.data; |
||||
}); |
||||
}, |
||||
submit() { |
||||
const menuList = this.$refs.treeMenu.getCheckedKeys(); |
||||
const dataScopeList = this.$refs.treeDataScope.getCheckedKeys(); |
||||
const apiScopeList = this.$refs.treeApiScope.getCheckedKeys(); |
||||
grant(this.idsArray, menuList, dataScopeList, apiScopeList).then(() => { |
||||
this.box = false; |
||||
this.$message({ |
||||
type: 'success', |
||||
message: '操作成功!', |
||||
}); |
||||
this.selectionList = []; |
||||
this.onLoad(this.page); |
||||
}); |
||||
}, |
||||
rowSave(row, done, loading) { |
||||
add(row).then( |
||||
() => { |
||||
this.onLoad(this.page); |
||||
this.$message({ |
||||
type: 'success', |
||||
message: '操作成功!', |
||||
}); |
||||
done(); |
||||
}, |
||||
error => { |
||||
window.console.log(error); |
||||
loading(); |
||||
} |
||||
); |
||||
}, |
||||
rowUpdate(row, index, done, loading) { |
||||
update(row).then( |
||||
() => { |
||||
this.onLoad(this.page); |
||||
this.$message({ |
||||
type: 'success', |
||||
message: '操作成功!', |
||||
}); |
||||
done(); |
||||
}, |
||||
error => { |
||||
window.console.log(error); |
||||
loading(); |
||||
} |
||||
); |
||||
}, |
||||
rowDel(row) { |
||||
this.$confirm('确定将选择数据删除?', { |
||||
confirmButtonText: '确定', |
||||
cancelButtonText: '取消', |
||||
type: 'warning', |
||||
}) |
||||
.then(() => { |
||||
return remove(row.id); |
||||
}) |
||||
.then(() => { |
||||
this.onLoad(this.page); |
||||
this.$message({ |
||||
type: 'success', |
||||
message: '操作成功!', |
||||
}); |
||||
}); |
||||
}, |
||||
|
||||
searchReset() { |
||||
this.query = {}; |
||||
this.onLoad(this.page); |
||||
}, |
||||
searchChange(params, done) { |
||||
this.query = params; |
||||
this.page.currentPage = 1; |
||||
this.onLoad(this.page, params); |
||||
done(); |
||||
}, |
||||
selectionChange(list) { |
||||
this.selectionList = list; |
||||
}, |
||||
selectionClear() { |
||||
this.selectionList = []; |
||||
this.$refs.crud.toggleSelection(); |
||||
}, |
||||
beforeOpen(done, type) { |
||||
if (['add', 'edit'].includes(type)) { |
||||
this.initData(this.form.id); |
||||
} |
||||
if (['edit', 'view'].includes(type)) { |
||||
if (this.form.parentId === '0') { |
||||
this.form.parentId = ''; |
||||
} |
||||
} |
||||
getRoleAlias().then(res => { |
||||
const column = this.findObject(this.option.column, 'currentAlias'); |
||||
column.dicData = res.data.data; |
||||
}); |
||||
done(); |
||||
}, |
||||
handleRole() { |
||||
if (this.selectionList.length !== 1) { |
||||
this.$message.warning('只能选择一条数据'); |
||||
return; |
||||
} |
||||
this.menuTreeObj = []; |
||||
this.dataScopeTreeObj = []; |
||||
this.apiScopeTreeObj = []; |
||||
grantTree().then(res => { |
||||
this.menuGrantList = res.data.data.menu; |
||||
this.dataScopeGrantList = res.data.data.dataScope; |
||||
this.apiScopeGrantList = res.data.data.apiScope; |
||||
getRole(this.ids).then(res => { |
||||
this.menuTreeObj = res.data.data.menu; |
||||
this.dataScopeTreeObj = res.data.data.dataScope; |
||||
this.apiScopeTreeObj = res.data.data.apiScope; |
||||
this.box = true; |
||||
}); |
||||
}); |
||||
}, |
||||
handleRowRole(row) { |
||||
this.menuTreeObj = []; |
||||
this.dataScopeTreeObj = []; |
||||
this.apiScopeTreeObj = []; |
||||
grantTree().then(res => { |
||||
this.menuGrantList = res.data.data.menu; |
||||
this.dataScopeGrantList = res.data.data.dataScope; |
||||
this.apiScopeGrantList = res.data.data.apiScope; |
||||
getRole(row.id).then(res => { |
||||
this.menuTreeObj = res.data.data.menu; |
||||
this.dataScopeTreeObj = res.data.data.dataScope; |
||||
this.apiScopeTreeObj = res.data.data.apiScope; |
||||
this.selectionList.push(row); |
||||
this.box = true; |
||||
}); |
||||
}); |
||||
}, |
||||
handleDelete() { |
||||
if (this.selectionList.length === 0) { |
||||
this.$message.warning('请选择至少一条数据'); |
||||
return; |
||||
} |
||||
this.$confirm('确定将选择数据删除?', { |
||||
confirmButtonText: '确定', |
||||
cancelButtonText: '取消', |
||||
type: 'warning', |
||||
}) |
||||
.then(() => { |
||||
return remove(this.ids); |
||||
}) |
||||
.then(() => { |
||||
this.onLoad(this.page); |
||||
this.$message({ |
||||
type: 'success', |
||||
message: '操作成功!', |
||||
}); |
||||
this.$refs.crud.toggleSelection(); |
||||
}); |
||||
}, |
||||
currentChange(currentPage) { |
||||
this.page.currentPage = currentPage; |
||||
}, |
||||
sizeChange(pageSize) { |
||||
this.page.pageSize = pageSize; |
||||
}, |
||||
refreshChange() { |
||||
this.onLoad(this.page, this.query); |
||||
}, |
||||
handleChange(file, fileList) { |
||||
// proxy.$Export.xlsx(file.raw).then((data) => { |
||||
// data.value = data.results; |
||||
// }); |
||||
this.$message({ |
||||
type: 'success', |
||||
message: '操作成功!', |
||||
}); |
||||
}, |
||||
|
||||
onLoad(page, params = {}) { |
||||
this.loading = true; |
||||
this.data = [ |
||||
|
||||
] |
||||
this.page.total = this.data.length |
||||
// getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => { |
||||
// this.data = res.data.data.records; |
||||
this.loading = false; |
||||
// this.page.total = res.data.data.total |
||||
// this.selectionClear(); |
||||
// }); |
||||
}, |
||||
}, |
||||
mounted() { |
||||
} |
||||
}; |
||||
</script> |
||||
Loading…
Reference in new issue