29 changed files with 817 additions and 382 deletions
-
3.env.dev
-
3.env.prod
-
3.env.test
-
3.eslintrc-auto-import.json
-
1auto-imports.d.ts
-
17src/apis/system.ts
-
40src/components/common/FTButton/index.vue
-
9src/components/common/FTDialog/index.vue
-
13src/components/common/FTStream/index.vue
-
158src/components/home/Check/index.vue
-
28src/components/home/stop/index.vue
-
17src/components/martixCraft/Edit/index.vue
-
4src/components/point/Edit/index.vue
-
104src/components/spray/startSpray/index.vue
-
19src/components/spray/trayGraph/index.vue
-
1src/env.d.ts
-
10src/libs/http.ts
-
4src/libs/socket.ts
-
183src/libs/utils.ts
-
21src/stores/useSystemStore.ts
-
23src/views/clean/index.vue
-
238src/views/debug/index.vue
-
21src/views/home/index.vue
-
13src/views/login/index.vue
-
54src/views/main/index.vue
-
1src/views/point/index.vue
-
123src/views/spray/index.vue
-
81src/views/spraySet/index.vue
-
4vite.config.ts
@ -0,0 +1,158 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
import FtDialog from 'components/common/FTDialog/index.vue' |
||||
|
import { FtMessage } from 'libs/message' |
||||
|
import { socket } from 'libs/socket' |
||||
|
import { sendControl } from 'libs/utils' |
||||
|
import { nextTick, onMounted, ref } from 'vue' |
||||
|
|
||||
|
const emits = defineEmits(['ok', 'cancel']) |
||||
|
|
||||
|
const okLoading = ref(false) |
||||
|
const okHandle = () => { |
||||
|
okLoading.value = true |
||||
|
|
||||
|
setTimeout(() => { |
||||
|
okLoading.value = false |
||||
|
FtMessage.success('保存成功') |
||||
|
emits('ok') |
||||
|
}, 300) |
||||
|
} |
||||
|
|
||||
|
// const handleButtonClick = (callback: () => void) => { |
||||
|
// okLoading.value = true |
||||
|
// setTimeout(() => { |
||||
|
// okLoading.value = false |
||||
|
// FtMessage.success('操作成功') |
||||
|
// callback() |
||||
|
// }, 300) |
||||
|
// } |
||||
|
|
||||
|
const list = ['x轴是否在原点', 'y轴是否在原点', 'z轴是否在原点'] |
||||
|
onMounted(async () => { |
||||
|
let num = 0 |
||||
|
await nextTick(() => { |
||||
|
buttonCloseRef.value.setLoading(true) |
||||
|
}) |
||||
|
|
||||
|
const interval = async () => { |
||||
|
if (num < list.length) { |
||||
|
await addTextToCheckList(list[num], num) |
||||
|
num++ |
||||
|
await interval() // 递归调用 interval 处理下一条数据 |
||||
|
} |
||||
|
} |
||||
|
await interval() |
||||
|
buttonCloseRef.value.setLoading(false) |
||||
|
closeVisible.value = false |
||||
|
}) |
||||
|
|
||||
|
const cancel = () => { |
||||
|
emits('cancel') |
||||
|
} |
||||
|
|
||||
|
const motorXYZOrigin = async () => { |
||||
|
buttonRef.value.setLoading(true) |
||||
|
const cmdId = Date.now().toString() |
||||
|
const params = { |
||||
|
cmdCode: 'motor_xyz_origin', |
||||
|
cmdId, |
||||
|
params: {}, |
||||
|
} |
||||
|
socket.init((data: any) => { |
||||
|
console.log(data) |
||||
|
if (data.cmdId === cmdId && data.status === 'success') { |
||||
|
buttonRef.value.setLoading(false) |
||||
|
closeVisible.value = true |
||||
|
} |
||||
|
}, 'cmd_response') |
||||
|
await sendControl(params, 'debug') |
||||
|
} |
||||
|
|
||||
|
const checkList = ref<any>([]) |
||||
|
const buttonRef = ref() |
||||
|
const buttonCloseRef = ref() |
||||
|
|
||||
|
const closeVisible = ref(true) |
||||
|
|
||||
|
const addTextToCheckList = async (text: string, id: number) => { |
||||
|
// 检查 checkList 中是否存在该 id 的对象,如果不存在则初始化 |
||||
|
if (!checkList.value.some(item => item.id === id)) { |
||||
|
checkList.value.push({ id, title: '', result: 'padding' }) |
||||
|
} |
||||
|
|
||||
|
let displayedText = '' |
||||
|
return new Promise<void>((resolve) => { |
||||
|
const interval = setInterval(() => { |
||||
|
if (displayedText.length < text.length) { |
||||
|
displayedText += text[displayedText.length] |
||||
|
const itemIndex = checkList.value.findIndex(item => item.id === id) |
||||
|
if (itemIndex !== -1) { |
||||
|
checkList.value[itemIndex].title = displayedText |
||||
|
} |
||||
|
} |
||||
|
else { |
||||
|
clearInterval(interval) |
||||
|
// 文字显示完毕后,设置 result 为 'success' 或 'failed' 以显示成功或失败图标 |
||||
|
const itemIndex = checkList.value.findIndex(item => item.id === id) |
||||
|
if (itemIndex !== -1) { |
||||
|
// 假设通过随机数来决定成功或失败 |
||||
|
setTimeout(() => { |
||||
|
checkList.value[itemIndex].result = 'failed' |
||||
|
resolve() // 解析 Promise,表示当前数据已完全展示 |
||||
|
}, Math.random() * 500) // 修改为随机数延时 |
||||
|
} |
||||
|
} |
||||
|
}, Math.random() * 200) // 修改为随机数延时 |
||||
|
}) |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<FtDialog visible title="自检" width="40%" @ok="okHandle" @cancel="cancel"> |
||||
|
<div v-for="item in checkList" :key="item.id" class="mask-box"> |
||||
|
<el-tag> {{ item.title }}</el-tag> |
||||
|
<el-icon v-show="item.result === 'success'" color="green"> |
||||
|
<SuccessFilled /> |
||||
|
</el-icon> |
||||
|
<el-icon v-show="item.result === 'failed'" color="red"> |
||||
|
<CircleCloseFilled /> |
||||
|
</el-icon> |
||||
|
<el-icon v-show="item.result === 'padding'" color="gray" class="el-icon--loading"> |
||||
|
<Loading /> |
||||
|
</el-icon> |
||||
|
</div> |
||||
|
<template #footer> |
||||
|
<ft-button v-if="closeVisible" ref="buttonCloseRef" @click="cancel"> |
||||
|
关闭 |
||||
|
</ft-button> |
||||
|
<ft-button v-else ref="buttonRef" type="primary" @click="motorXYZOrigin"> |
||||
|
回原点 |
||||
|
</ft-button> |
||||
|
</template> |
||||
|
</FtDialog> |
||||
|
</template> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.mask-box { |
||||
|
display: flex; |
||||
|
font-size: 35px; |
||||
|
.el-tag { |
||||
|
margin: 0 20px 10px 0; |
||||
|
width: 100%; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 添加旋转动画 |
||||
|
@keyframes spin { |
||||
|
0% { |
||||
|
transform: rotate(0deg); |
||||
|
} |
||||
|
100% { |
||||
|
transform: rotate(360deg); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.el-icon.el-icon--loading { |
||||
|
animation: spin 1s linear infinite; // 确保 Loading 图标应用 spin 动画 |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,28 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
|
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<Teleport to="body"> |
||||
|
<div class="mask-box"> |
||||
|
设备急停中 |
||||
|
</div> |
||||
|
</Teleport> |
||||
|
</template> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.mask-box { |
||||
|
position: absolute; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
background: rgba(0, 0, 0, 0.7); |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
color: var(--el-color-danger); |
||||
|
font-size: 100px; |
||||
|
z-index: 10000; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
} |
||||
|
</style> |
@ -1,31 +1,105 @@ |
|||||
<script setup lang="ts"> |
<script setup lang="ts"> |
||||
import FtDialog from 'components/common/FTDialog/index.vue' |
|
||||
import { ref } from 'vue' |
|
||||
|
import { useSystemStore } from 'stores/useSystemStore' |
||||
|
import { nextTick, ref, watch } from 'vue' |
||||
|
|
||||
defineProps({ |
defineProps({ |
||||
sourceData: { |
|
||||
type: Object, |
|
||||
default: () => {}, |
|
||||
|
visible: { |
||||
|
type: Boolean, |
||||
|
default: false, |
||||
}, |
}, |
||||
}) |
}) |
||||
const emits = defineEmits(['ok', 'cancel']) |
|
||||
|
const emits = defineEmits(['close']) |
||||
|
|
||||
const visible = ref(true) |
|
||||
const text = defineModel() |
|
||||
|
const list = defineModel() |
||||
|
|
||||
const cancel = () => { |
|
||||
emits('cancel') |
|
||||
|
const close = () => { |
||||
|
emits('close') |
||||
} |
} |
||||
|
|
||||
|
const systemStore = useSystemStore() |
||||
|
|
||||
|
const maskBodyRef = ref<HTMLElement | null>(null) |
||||
|
|
||||
|
watch( |
||||
|
() => list.value, |
||||
|
async () => { |
||||
|
await nextTick() |
||||
|
if (maskBodyRef.value) { |
||||
|
maskBodyRef.value.scrollTop = maskBodyRef.value.scrollHeight |
||||
|
} |
||||
|
}, |
||||
|
{ deep: true }, |
||||
|
) |
||||
</script> |
</script> |
||||
|
|
||||
<template> |
<template> |
||||
<FtDialog visible title="喷涂" width="80%" @ok="visible = false" @cancel="cancel"> |
|
||||
{{ text }} |
|
||||
</FtDialog> |
|
||||
|
<teleport to="body"> |
||||
|
<!-- 使用 transition 组件包裹 mask111 元素 --> |
||||
|
<transition name="mask-fade"> |
||||
|
<div v-if="visible && systemStore.isDebug" class="mask"> |
||||
|
<div class="mask-header"> |
||||
|
<p>喷涂任务</p> |
||||
|
<el-icon @click="close"> |
||||
|
<Close /> |
||||
|
</el-icon> |
||||
|
</div> |
||||
|
<div ref="maskBodyRef" class="mask-body"> |
||||
|
<el-timeline> |
||||
|
<el-timeline-item |
||||
|
v-for="(item, key) in list" :key |
||||
|
:timestamp="JSON.stringify(item.data.content || item.data)" |
||||
|
> |
||||
|
<el-tag type="primary" class="mask-tag"> |
||||
|
{{ item.data.message || item.data }} |
||||
|
</el-tag> |
||||
|
</el-timeline-item> |
||||
|
</el-timeline> |
||||
|
</div> |
||||
|
</div> |
||||
|
</transition> |
||||
|
</teleport> |
||||
</template> |
</template> |
||||
|
|
||||
<style scoped lang="scss"> |
<style scoped lang="scss"> |
||||
.graph-box { |
|
||||
display: flex; |
|
||||
|
.mask { |
||||
|
width: 800px; |
||||
|
height: 500px; |
||||
|
padding: 20px; |
||||
|
background: #fff; |
||||
|
box-shadow: var(--el-box-shadow-light); |
||||
|
position: absolute; |
||||
|
bottom: 650px; |
||||
|
right: 100px; |
||||
|
border-radius: 10px; |
||||
|
font-size: 30px; |
||||
|
.mask-header { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
height: 50px; |
||||
|
font-size: 30px; |
||||
|
border-bottom: 1px solid #ddd; |
||||
|
.el-icon svg{ |
||||
|
width: 30px; |
||||
|
} |
||||
|
} |
||||
|
.mask-body { |
||||
|
padding: 10px; |
||||
|
height: calc(100% - 41px); |
||||
|
overflow: auto; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* 定义过渡效果 */ |
||||
|
.mask-fade-enter-active, .mask-fade-leave-active { |
||||
|
transition: transform 0.5s ease; |
||||
|
} |
||||
|
|
||||
|
.mask-fade-enter-from { |
||||
|
transform: translateX(100%); |
||||
|
} |
||||
|
|
||||
|
.mask-fade-leave-to { |
||||
|
transform: translateX(100%); |
||||
} |
} |
||||
</style> |
</style> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue