This commit is contained in:
2025-11-20 14:44:10 +08:00
parent b2984ed4cf
commit b926559a7d
27 changed files with 2790 additions and 756 deletions

View File

@@ -0,0 +1,65 @@
<!--
* @Author: zwq
* @Date: 2023-08-01 15:27:31
* @LastEditors: zwq
* @LastEditTime: 2023-08-01 16:25:54
* @Description:
-->
<template>
<div :class="[className, { 'p-0': noPadding }]">
<slot />
</div>
</template>
<script>
export default {
props: {
size: {
// 取值范围: xl lg md sm
type: String,
default: 'de',
validator: function (val) {
return ['xl', 'lg', 'de', 'md', 'sm'].indexOf(val) !== -1;
},
},
noPadding: {
type: Boolean,
default: false,
},
},
computed: {
className: function () {
return `${this.size}-title`;
},
},
};
</script>
<style lang="scss" scoped>
$pxls: (xl, 28px) (lg, 24px) (de, 20px) (md, 18px) (sm, 16px);
$mgr: 8px;
@each $size, $height in $pxls {
.#{$size}-title {
font-size: $height;
line-height: $height;
color: #000;
font-weight: 500;
font-family: '微软雅黑', 'Microsoft YaHei', Arial, Helvetica, sans-serif;
&::before {
content: '';
display: inline-block;
vertical-align: top;
width: 4px;
height: $height + 2px;
border-radius: 1px;
margin-right: $mgr;
background-color: #0b58ff;
}
}
}
.p-0 {
padding: 0;
}
</style>

View File

@@ -0,0 +1,442 @@
<!--
* @Author: zwq
* @Date: 2025-10-13 15:07:24
* @LastEditors: zwq
* @LastEditTime: 2025-11-07 15:35:14
* @Description:
-->
<template>
<div>
<div class="circle-container">
<div v-for="(item, index) in dotArr" :key="index" class="circle-wrapper">
<div
class="circle"
:style="{
background: stepNum == index + 1 ? '#0B58FF' : '',
}">
{{ index + 1 }}
</div>
<div
class="circle-text"
:style="{
color: stepNum == index + 1 ? '#0B58FF' : '',
}">
{{ item.name }}
</div>
<!-- 圆点后面的虚线 -->
<div v-if="index < 2" class="connector" />
</div>
</div>
<div v-if="stepNum == 1">
<div class="topTip">
1.可选择库区巷道同批次创建任务搬运仅支持同一产品型号
<br />
2.须在本页下方填写搬运数量搬运数量仅支持双数且数量当前可用库存总量
</div>
<small-title style="margin: 16px 0" size="sm" :no-padding="true">
步骤一选择产品及起点
</small-title>
<el-form
:model="dataForm"
:rules="dataRule"
ref="dataForm"
@keyup.enter.native="dataFormSubmit()"
label-position="top"
label-width="80px">
<el-row :gutter="10">
<el-col :span="6">
<el-form-item label="搬运对象" prop="val1">
<el-select
style="width: 100%"
v-model="dataForm.val1"
placeholder="请选择搬运对象">
<el-option
v-for="item in options1"
:key="item.value"
:label="item.label"
:value="item.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6" v-if="dataForm.val1 == 1">
<el-form-item label="产品名称" prop="val1">
<el-select
style="width: 100%"
v-model="dataForm.val2"
placeholder="请选择产品名称">
<el-option
v-for="item in options1"
:key="item.value"
:label="item.label"
:value="item.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6" v-if="dataForm.val1 == 1">
<el-form-item label="规格型号" prop="val1">
<el-select
style="width: 100%"
v-model="dataForm.val2"
placeholder="请选择规格型号">
<el-option
v-for="item in options1"
:key="item.value"
:label="item.label"
:value="item.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="搬运数量" prop="val4">
<el-input
v-model="dataForm.val4"
oninput="value=value.replace(/^(0+)|[^\d]+/g,'')">
<template slot="append"></template>
</el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">
<el-form-item label="起点信息" prop="val5">
<el-radio-group v-model="dataForm.val5">
<el-radio :label="1">按策略自动选择</el-radio>
<el-radio :label="2">指定起点</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div v-if="dataForm.val5 == 2" class="potBG-div">
<div>
<el-row :gutter="10">
<el-col :span="10">
起点库区:
<el-select
style="width: 200px; margin-left: 10px"
v-model="startPot"
size="small"
placeholder="请选择起点库区">
<el-option
v-for="item in options1"
:key="item.value"
:label="item.label"
:value="item.value"></el-option>
</el-select>
</el-col>
<el-col :span="13" style="text-align: right; line-height: 36px">
<span
class="num1-startPot-status"
style="background-color: #5ab45a" />
可选
<span class="num1-startPot-status" />
不可选
<span
class="num1-startPot-status"
style="background-color: #e9b100" />
已选
</el-col>
</el-row>
<div class="potTitleBG">
<div v-for="item in Object.keys(startPotList)" :key="item">
<div class="potTitle">
{{ item }}
</div>
<div class="potList">
<div
class="pot"
v-for="sitem in startPotList[item]"
:key="sitem.id"
:style="{
backgroundColor: potBGcolor[sitem.status],
cursor: sitem.status > 0 ? 'pointer' : '',
}"
@click="sitem.status > 0 && setStartPot(sitem)"
:title="sitem.name">
{{ sitem.name }}
</div>
</div>
</div>
</div>
<el-divider></el-divider>
<div style="text-align: right">可用库存总量 <span style="color:#409EFF;font-size:16px">12</span> </div>
</div>
</div>
</div>
<div v-if="stepNum == 2">
<div class="topTip">
1.指定终点库位下发后会锁定所属巷道仅本批次任务进入
<br />
2.指定终点库位选位规则仅可从巷道最里空对位选位
<br />
3.只选择库区或巷道时该方式下当前终点为候选位置系统将根据策略与现场实际情况自动确定最终终点库位
</div>
<small-title style="margin: 16px 0" size="sm" :no-padding="true">
步骤二选择终点
</small-title>
</div>
<div v-if="stepNum == 3">
<small-title style="margin: 16px 0" size="sm" :no-padding="true">
步骤三预览与下发
</small-title>
</div>
</div>
</template>
<script>
import SmallTitle from './SmallTitle';
export default {
components: {
SmallTitle,
},
data() {
return {
dotArr: [
{
name: '选择起点',
},
{
name: '选择终点',
},
{
name: '预览下发',
},
],
potBGcolor: ['', '#dafadc', '#f8f0c4'],
stepNum: 1, // 当前第几步
//第一步参数
dataForm: {
id: undefined,
val1: undefined,
val2: undefined,
val3: undefined,
val4: undefined,
val5: 1,
},
options1: [
{
label: '产品',
value: 1,
},
{
label: '空盘',
value: 2,
},
],
dataRule: {},
startPot: undefined, //起点库区选择的类型
startPotList: {
//起点库区List
G01: [
{
id: '001',
name: 'L001',
status: 1,
},
{
id: '002',
name: 'R002',
status: 1,
},
{
id: '003',
name: 'L003',
status: 0,
},
{
id: '004',
name: 'R004',
status: 0,
},
],
G02: [
{
id: '005',
name: 'L005',
},
{
id: '006',
name: 'R006',
},
{
id: '007',
name: 'L007',
},
{
id: '008',
name: 'R008',
},
],
},
};
},
methods: {
init(id) {
this.dataForm.id = id || undefined;
this.$nextTick(() => {
if (this.dataForm.id) {
} else {
}
});
},
//上一步
upSubmit() {
if (this.stepNum == 2) {
this.stepNum -= 1;
this.$emit('setSN', this.stepNum);
} else if (this.stepNum == 3) {
this.stepNum -= 1;
this.$emit('setSN', this.stepNum);
}
},
//下一步
nextSubmit() {
if (this.stepNum == 1) {
this.stepNum += 1;
this.$emit('setSN', this.stepNum);
return;
}
if (this.stepNum == 2) {
this.stepNum += 1;
this.$emit('setSN', this.stepNum);
return;
}
if (this.stepNum == 3) {
this.stepNum = 1;
this.$emit('setSN', this.stepNum);
return;
}
},
cancelStep() {},
// 第一步方法
setStartPot(data) {
data.status = data.status == 1 ? 2 : 1;
},
},
};
</script>
<style scoped>
.topTip {
background-color: #ebebeb;
padding: 10px 20px;
border-radius: 5px;
line-height: 25px;
}
</style>
<!-- //库位点的样式 -->
<style scoped>
.potBG-div {
width: 100%;
margin: 10px;
border: 1px solid gainsboro;
box-shadow: 2px 2px 2px gainsboro, -1px -1px 3px gainsboro;
padding: 15px;
}
.num1-startPot-status {
margin-left: 5px;
display: inline-block;
width: 14px;
height: 14px;
border: 1px solid gainsboro;
}
.potTitleBG {
margin-top: 10px;
overflow-x: auto;
display: flex;
}
.potTitle {
width: 82px;
background-color: rgb(169, 235, 249);
border-radius: 3px;
margin-right: 5px;
text-align: center;
color: #000000;
letter-spacing: 1px;
margin-bottom: 10px;
}
.potList {
width: 82px;
display: grid;
grid-template-columns: 40px 40px;
gap: 2px;
}
.pot {
width: 40px;
text-align: center;
border: 1px solid gainsboro;
border-radius: 3px;
padding: 5px 0;
margin-bottom: 5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>
<!-- //序号圆点 -->
<style scoped>
.circle-container {
height: 110px;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
width: 90%;
overflow-x: auto;
margin: auto;
}
.circle-wrapper {
position: relative;
display: flex;
align-items: center;
}
.circle {
width: 52px;
height: 52px;
border-radius: 50%;
background: #8db1ff;
font-weight: 500;
font-size: 31px;
color: #ffffff;
display: flex;
justify-content: center;
align-items: center;
position: relative;
z-index: 2;
cursor: pointer;
}
.circle-text {
position: absolute;
top: 60px;
left: -15px;
color: #8db1ff;
width: 82px;
text-align: center;
}
/* 下半圆虚线边框 */
.circle::after {
content: '';
position: absolute;
bottom: -6px; /* 2px边框 + 2px间隙 */
left: -4px;
right: -4px;
height: 30px; /* 半圆高度 */
border-radius: 0 0 60px 60px;
border: 1px dashed #0b58ff;
border-top: none;
z-index: 1;
}
.connector {
width: 160px; /* 计算连接线长度 */
height: 2px;
border-bottom: 1px dashed rgb(11, 88, 255, 1);
margin: 0 5px;
z-index: 1;
}
</style>

View File

@@ -0,0 +1,273 @@
<!--
* @Author: zwq
* @Date: 2025-11-07 17:01:51
* @LastEditors: zwq
* @LastEditTime: 2025-11-07 22:31:17
* @Description:
-->
<template>
<el-drawer
:visible.sync="visible"
:with-header="false"
size="50%"
@close="closeD"
:show-close="false">
<div class="bgDiv1">
<el-row :gutter="20" style="margin-bottom: 15px">
<el-col :span="8" style="font-size: 20px; font-weight: 600">
TSK202510230001
</el-col>
<el-col :span="8">满盘搬运自动</el-col>
<el-col :span="8">
上次刷新{{ parseTime(Date.now()) }}
<el-button type="text" @click="refresh">刷新</el-button>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">任务状态</el-col>
<el-col :span="8">优先级</el-col>
<el-col :span="8">执行车辆</el-col>
</el-row>
<el-row :gutter="20" style="margin-bottom: 15px">
<el-col :span="8">
<span
:style="{ backgroundColor: statusColor[1].color }"
class="taskStatus">
{{ statusColor[1].label }}
</span>
</el-col>
<el-col :span="8"></el-col>
<el-col :span="8">--</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">执行时长</el-col>
<el-col :span="8">创建人</el-col>
<el-col :span="8">创建时间</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">--</el-col>
<el-col :span="8">系统/张三</el-col>
<el-col :span="8">{{ parseTime(Date.now()) }}</el-col>
</el-row>
</div>
<div class="bgDiv2">
<el-steps
:active="stepNum"
finish-status="success"
:process-status="stepStatus"
align-center>
<el-step title="待下发"></el-step>
<el-step title="待执行"></el-step>
<el-step title="执行中"></el-step>
<el-step title="已完成"></el-step>
</el-steps>
<div class="abnormal">任务异常无效路径</div>
</div>
<div class="bgDiv3">
<small-title style="margin: 0 0 8px 0" size="sm" :no-padding="true">
搬运对象
</small-title>
<el-row :gutter="20">
<el-col :span="12">
<div class="pan-info">
<div class="pan-title">L盘</div>
</div>
</el-col>
<el-col :span="12">
<div class="pan-info">
<div class="pan-title">R盘</div>
</div>
</el-col>
</el-row>
</div>
<div class="bgDiv4">
<small-title style="margin: 0 0 8px 0" size="sm" :no-padding="true">
回收信息
</small-title>
<el-descriptions :column="2" size="medium" border>
<el-descriptions-item label="回收方式">他车回收</el-descriptions-item>
<el-descriptions-item label="回收任务编号">
18100000000
</el-descriptions-item>
<el-descriptions-item label="回收库位">
CK-01-A05-L / R
</el-descriptions-item>
<el-descriptions-item label="执行车辆">AGV-06</el-descriptions-item>
</el-descriptions>
</div>
<div class="bgDiv5">
<small-title style="margin: 0 0 8px 0" size="sm" :no-padding="true">
任务明细
</small-title>
<el-descriptions :column="2" size="medium" border>
<el-descriptions-item label="起点库位(L/R)">
CK-01-A05-L / R
</el-descriptions-item>
<el-descriptions-item label="终点库位(L/R)">
CC-02-B03-L/R (候选 )
</el-descriptions-item>
<el-descriptions-item label="起点策略">--</el-descriptions-item>
<el-descriptions-item label="终点策略">入库策略</el-descriptions-item>
<el-descriptions-item label="FMS任务号">--</el-descriptions-item>
<el-descriptions-item label="车辆位置">--</el-descriptions-item>
<el-descriptions-item label="电量">--</el-descriptions-item>
<el-descriptions-item label="是否载货">--</el-descriptions-item>
<el-descriptions-item label="创建方式">自动/人工</el-descriptions-item>
<el-descriptions-item label="任务来源">
PDA/PC/系统
</el-descriptions-item>
<el-descriptions-item label="关联叫料单">--</el-descriptions-item>
<el-descriptions-item label=""></el-descriptions-item>
</el-descriptions>
</div>
<div class="bgDiv6">
<small-title style="margin: 0 0 8px 0" size="sm" :no-padding="true">
任务日志
</small-title>
<el-timeline style="padding: 0">
<el-timeline-item
v-for="(activity, index) in activities"
:key="index"
:type="activity.type"
:color="activity.color"
size="large"
hide-timestamp>
<span>{{ activity.content }}</span>
<span style="float: right">{{ activity.timestamp }}</span>
</el-timeline-item>
</el-timeline>
</div>
<el-divider></el-divider>
<!-- 底部按钮 -->
<div class="drawer-body__footer">
<el-button @click="closeD"> </el-button>
</div>
</el-drawer>
</template>
<script>
import SmallTitle from './SmallTitle';
export default {
name: '',
data() {
return {
visible: false,
title: '',
statusColor: [
//bgDiv1的任务状态
{ label: '待下发', color: '#fa8c16' },
{ label: '待执行', color: '#1890ff' },
{ label: '执行中', color: '#1890ff' },
{ label: '已完成', color: '#52c41a' },
{ label: '暂停中', color: '#8c8c8c' },
{ label: '已终止', color: '#faad14' },
{ label: '异常', color: '#ff4d4f' },
{ label: '禁用', color: '#d9d9d9' },
],
//bgDiv2的步骤条
stepNum: 2,
stepStatus: 'finish',
//bgDiv6的时间线
activities: [
{
content: 'FMS | 卸货完成,任务完成',
timestamp: '2018-04-12 20:46',
type: 'primary',
},
{
content: 'FMS | 取货完成',
timestamp: '2018-04-03 20:46',
},
{
content: 'FMS | 派车AGV-03前往起点取货',
timestamp: '2018-04-03 20:46',
},
{
content: '张三 | 任务扫码配对完成,进入待下发',
timestamp: '2018-04-03 20:46',
},
],
};
},
components: {
SmallTitle,
},
created() {},
methods: {
init(val) {
this.visible = true;
},
//刷新
refresh() {},
closeD() {
this.visible = false
this.$emit('closeDrawer');
},
},
};
</script>
<style lang="scss" scoped>
.bgDiv1 {
background-color: rgba(242, 242, 242, 0.5);
padding: 20px;
line-height: 25px;
font-size: 15px;
border-bottom: 1px solid rgba(121, 121, 121, 0.5);
.taskStatus {
text-align: center;
border-radius: 3px;
padding: 2px 5px;
color: #fff;
}
}
.bgDiv2 {
border-bottom: 1px solid rgba(121, 121, 121, 0.5);
padding: 18px 0;
.abnormal {
width: 80%;
margin: auto;
border-radius: 5px;
height: 40px;
font-size: 22px;
line-height: 40px;
text-align: center;
background-color: rgba(217, 0, 27, 0.1);
color: rgba(217, 0, 27, 1);
border: 1px solid rgba(217, 0, 27, 1);
}
}
.bgDiv3 {
padding: 20px 20px 0;
.pan-info {
height: 350px;
border: 1px solid rgba(121, 121, 121, 0.8);
border-radius: 5px;
.pan-title {
background-color: rgba(242, 242, 242, 0.5);
height: 35px;
font-size: 20px;
line-height: 35px;
padding: 0 20px;
border-bottom: 1px solid rgba(121, 121, 121, 0.5);
letter-spacing: 2px;
}
}
}
.bgDiv4 {
padding: 20px 20px 0;
}
.bgDiv5 {
padding: 20px 20px 0;
}
.bgDiv6 {
padding: 20px 20px 0;
}
.drawer-body__footer {
display: flex;
justify-content: flex-end;
padding: 0 18px 10px;
}
</style>

View File

@@ -0,0 +1,65 @@
<!--
* @Author: zwq
* @Date: 2025-11-08 17:44:05
* @LastEditors: zwq
* @LastEditTime: 2025-11-08 18:13:25
* @Description:
-->
<template>
<div>
<div>请选择要执行的终止方式系统会根据选择进行处理</div>
<el-radio-group v-model="radio" class="stockRadioDiv">
<el-radio :label="1" border style="margin: 10px 0">
仅终止稍后回收
<div style="font-weight: 400">
任务立即终止车辆保持暂停稍后可在任务列表中手动回收
</div>
</el-radio>
<el-radio :label="2" border style="margin: 10px 0">
终止并立即回收
<div style="font-weight: 400">
任务立即终止立即选择货物回收方式生成任务或更新卸货点
</div>
</el-radio>
</el-radio-group>
<div>
终止原因
<el-input
type="textarea"
:rows="3"
style="margin: 10px 0"
placeholder="请输入终止原因"
v-model="textarea" />
</div>
</div>
</template>
<script>
export default {
data() {
return {
radio: 1,
textarea: '',
};
},
methods: {
init(val) {},
submit() {
if(this.textarea){
}else{
this.$message('请输入终止原因');
}
},
},
};
</script>
<style scoped>
.stockRadioDiv >>> .el-radio--medium.is-bordered {
display: flex;
align-items: center;
height: 70px;
line-height: 20px;
}
</style>

View File

@@ -0,0 +1,32 @@
<!--
* @Author: zwq
* @Date: 2025-10-13 16:18:41
* @LastEditors: zwq
* @LastEditTime: 2025-11-06 15:19:24
* @Description:
-->
<template>
<span>
{{
(injectData.val2
? ['满盘搬运', '空盘搬运', '备料搬运', '临时搬运'][injectData.val2]
: '-')
}}
</span>
</template>
<script>
export default {
props: {
injectData: {
type: Object,
default: () => ({}),
},
},
data() {
return {};
},
created() {},
methods: {},
};
</script>

View File

@@ -0,0 +1,32 @@
<!--
* @Author: zwq
* @Date: 2025-10-13 16:18:41
* @LastEditors: zwq
* @LastEditTime: 2025-11-06 15:20:43
* @Description:
-->
<template>
<span>
{{
(injectData.val3
? ['待下发', '待执行', '执行中', '已完成', '暂停中', '已终止', '异常'][injectData.val3]
: '-')
}}
</span>
</template>
<script>
export default {
props: {
injectData: {
type: Object,
default: () => ({}),
},
},
data() {
return {};
},
created() {},
methods: {},
};
</script>

View File

@@ -0,0 +1,57 @@
<!--
* @Author: zwq
* @Date: 2025-10-13 16:18:41
* @LastEditors: zwq
* @LastEditTime: 2025-11-06 15:37:02
* @Description:
-->
<template>
<div>
<div style="display: flex; align-items: center">
<div
style="
width: 16px;
height: 16px;
border-radius: 5px;
background-color: #e89b24;
color: #fff;
text-align:center;
line-height:16px
">
L
</div>
产品名称+产品规格
</div>
<div style="display: flex; align-items: center">
<div
style="
width: 16px;
height: 16px;
border-radius: 5px;
background-color: #6a96ec;
color: #fff;
text-align:center;
line-height:16px
">
R
</div>
产品名称+产品规格
</div>
</div>
</template>
<script>
export default {
props: {
injectData: {
type: Object,
default: () => ({}),
},
},
data() {
return {};
},
created() {},
methods: {},
};
</script>

View File

@@ -0,0 +1,32 @@
<!--
* @Author: zwq
* @Date: 2025-10-13 16:18:41
* @LastEditors: zwq
* @LastEditTime: 2025-11-06 15:19:24
* @Description:
-->
<template>
<span>
{{
(injectData.val2
? ['满盘搬运', '空盘搬运', '备料搬运', '临时搬运'][injectData.val2]
: '-')
}}
</span>
</template>
<script>
export default {
props: {
injectData: {
type: Object,
default: () => ({}),
},
},
data() {
return {};
},
created() {},
methods: {},
};
</script>

View File

@@ -0,0 +1,35 @@
<template>
<el-switch
@change="changeStatus"
size="small"
v-model="list.enabled"
:active-value="1"
:inactive-value="0"></el-switch>
</template>
<script>
import { updateGroup } from '@/api/group/groupSetting';
export default {
props: {
injectData: {
type: Object,
default: () => ({}),
},
},
data() {
return {
list: this.injectData,
};
},
created() {},
methods: {
changeStatus(val) {
const data = { ...this.injectData, enabled: val };
updateGroup(data).then((res) => {
this.$modal.msgSuccess('修改成功');
this.$emit('emitData');
});
},
},
};
</script>