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"> |
|||
import FtDialog from 'components/common/FTDialog/index.vue' |
|||
import { ref } from 'vue' |
|||
import { useSystemStore } from 'stores/useSystemStore' |
|||
import { nextTick, ref, watch } from 'vue' |
|||
|
|||
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> |
|||
|
|||
<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> |
|||
|
|||
<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> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue