mirror of
https://github.com/viarotel-org/escrcpy.git
synced 2024-11-12 01:40:52 +01:00
feat: 🚀 Add a scheduled task list
This commit is contained in:
parent
16f953538b
commit
d72202b311
@ -80,6 +80,7 @@
|
||||
"watchEffect": true,
|
||||
"watchPostEffect": true,
|
||||
"watchSyncEffect": true,
|
||||
"ElMessage": true
|
||||
"ElMessage": true,
|
||||
"ElButtonProps": true
|
||||
}
|
||||
}
|
||||
|
58
README-CN.md
58
README-CN.md
@ -13,10 +13,10 @@
|
||||
## 特点
|
||||
|
||||
- 🏃 同步:得益于 Web 技术,将更快速的与 Scrcpy 保持同步
|
||||
- 🤖 自动化:允许自动连接到历史设备并自动执行镜像。
|
||||
- 💡 定制化:支持对多个设备偏好进行独立配置,并且能够添加备注以及导入导出所有配置的功能
|
||||
- 🔗 反向供网:集成了 Gnirehtet 反向供网功能
|
||||
- 🎨 主题:支持浅色模式和深色模式,跟随系统切换
|
||||
- 🤖 自动化:自动连接设备、自动执行镜像、自定义脚本、定时任务
|
||||
- 💡 定制化:多设备管理、独立配置、自定义备注、配置导入导出
|
||||
- 🔗 反向供网:Gnirehtet 反向供网
|
||||
- 🎨 主题:浅色模式、深色模式、跟随系统切换
|
||||
- 😎 轻巧度:本机支持,仅显示设备屏幕
|
||||
- ⚡️ 性能:30~120 帧每秒,取决于设备
|
||||
- 🌟 质量:1920×1080 或更高
|
||||
@ -78,6 +78,7 @@ Windows 及 Linux 端内部集成了 Gnirehtet, 用于提供 PC 到安卓设
|
||||
- 批量安装应用
|
||||
- 批量文件管理
|
||||
- 批量执行脚本
|
||||
- 批量定时任务
|
||||
|
||||
### 控制模式
|
||||
|
||||
@ -101,6 +102,7 @@ Windows 及 Linux 端内部集成了 Gnirehtet, 用于提供 PC 到安卓设
|
||||
- 安装应用
|
||||
- 文件管理
|
||||
- 执行脚本
|
||||
- 定时任务
|
||||
- 反向供网(Gnirehtet)
|
||||
- 多屏协同
|
||||
|
||||
@ -174,12 +176,12 @@ Windows 及 Linux 端内部集成了 Gnirehtet, 用于提供 PC 到安卓设
|
||||
### 输入控制
|
||||
|
||||
- 鼠标模式
|
||||
- 鼠标绑定
|
||||
- 键盘模式
|
||||
- 键盘注入方式
|
||||
|
||||
### 摄像控制
|
||||
|
||||
- 启用摄像
|
||||
- 摄像源
|
||||
- 摄像尺寸
|
||||
- 摄像比例
|
||||
@ -189,29 +191,31 @@ Windows 及 Linux 端内部集成了 Gnirehtet, 用于提供 PC 到安卓设
|
||||
|
||||
> 优先级从高到低
|
||||
|
||||
1. 用户界面进行优化,制作合适的 Logo ✅
|
||||
2. 内置的软件更新功能 ✅
|
||||
1. 更好的标志 ✅
|
||||
2. 软件更新功能 ✅
|
||||
3. 录制和保存音视频 ✅
|
||||
4. 添加设备快捷交互控制栏 ✅
|
||||
5. 支持自定义 Adb 及 Scrcpy 依赖 ✅
|
||||
6. 支持自定义设备名称,以及偏好设置的导出及导入 ✅
|
||||
7. 定制化,支持对单个设备进行独立配置 ✅
|
||||
8. 添加 macOS 及 linux 操作系统的支持 ✅
|
||||
9. 支持国际化 ✅
|
||||
10. 对深色模式的支持 ✅
|
||||
11. 添加 Gnirehtet 反向供网功能 ✅
|
||||
12. 添加新的相机镜像相关功能 ✅
|
||||
13. 更好的多屏协同 ✅
|
||||
14. 设备交互栏添加更多功能:文件推送、旋转屏幕、音频控制等功能 ✅
|
||||
15. 支持批量连接历史设备功能 ✅
|
||||
16. 支持使用内置终端执行自定义命令 ✅
|
||||
17. 支持设备自动执行镜像 ✅
|
||||
18. 支持灵活启动镜像 ✅
|
||||
19. 支持常用批量功能 ✅
|
||||
20. 支持对设备进行分组 🚧
|
||||
21. 添加文件传输助手功能 🚧
|
||||
22. 支持通过界面从设备下载选中的文件 🚧
|
||||
23. 添加对游戏的增强功能,如游戏键位映射 🚧
|
||||
4. 设备快捷交互控制栏 ✅
|
||||
5. 自定义 Adb 及 Scrcpy 依赖 ✅
|
||||
6. 自定义设备名称 ✅
|
||||
7. 偏好设置的导出及导入 ✅
|
||||
8. 对单个设备进行独立配置 ✅
|
||||
9. 添加 macOS 及 linux 操作系统的支持 ✅
|
||||
10. 国际化 ✅
|
||||
11. 深色模式 ✅
|
||||
12. 反向供网(Gnirehtet) ✅
|
||||
13. 相机镜像 ✅
|
||||
14. 多屏协同 ✅
|
||||
15. 文件推送、旋转屏幕、音频控制 ✅
|
||||
16. 批量连接历史设备 ✅
|
||||
17. 内置终端 ✅
|
||||
18. 自动执行镜像 ✅
|
||||
19. 灵活启动镜像 ✅
|
||||
20. 批量处理 ✅
|
||||
21. 定时任务 ✅
|
||||
22. 对设备进行分组 🚧
|
||||
23. 文件传输助手 🚧
|
||||
24. 通过界面管理设备文件 🚧
|
||||
25. 游戏键位映射 🚧
|
||||
|
||||
## 常见问题
|
||||
|
||||
|
58
README.md
58
README.md
@ -13,10 +13,10 @@
|
||||
## Features
|
||||
|
||||
- 🏃 Synchronous: Benefit from web technologies to synchronize with Scrcpy faster
|
||||
- 🤖 Automation: Enables automatic connection to historical devices and automatic execution of mirror.
|
||||
- 💡 Customizable: Support independent configuration for multiple devices and ability to add notes and import/export all configurations
|
||||
- 🎨 Theme: Supports light mode and dark mode, system-wide switching
|
||||
- 🔗 Gnirehtet: Integrated Gnirehtet's reverse tethering functionality
|
||||
- 🤖 Automation: Auto-connect devices, auto-execute images, custom scripts, scheduled tasks
|
||||
- 💡 Customization: Multi-device management, independent configurations, custom notes, config import/export
|
||||
- 🔗 Reverse tethering: Gnirehtet reverse tethering
|
||||
- 🎨 Themes: Light mode, dark mode, system-based switching
|
||||
- 😎 Lightweight: Native support, only display device screen
|
||||
- ⚡️ Performance: 30-120 fps depending on device
|
||||
- 🌟 Quality: 1920×1080 or higher
|
||||
@ -76,6 +76,7 @@ Refer to [scrcpy/doc/shortcuts](https://github.com/Genymobile/scrcpy/blob/master
|
||||
- Batch Installation Application
|
||||
- Batch File Management
|
||||
- Batch Execution Script
|
||||
- Batch Scheduled Task
|
||||
|
||||
### Control Model
|
||||
|
||||
@ -99,6 +100,7 @@ Refer to [scrcpy/doc/shortcuts](https://github.com/Genymobile/scrcpy/blob/master
|
||||
- Install APP
|
||||
- File Manager
|
||||
- Execution Script
|
||||
- Scheduled Task
|
||||
- Gnirehtet
|
||||
- Mirror Group
|
||||
|
||||
@ -172,12 +174,12 @@ Refer to [scrcpy/doc/shortcuts](https://github.com/Genymobile/scrcpy/blob/master
|
||||
### Input Control
|
||||
|
||||
- Mouse mode
|
||||
- Mouse binding
|
||||
- Keyboard mode
|
||||
- Keyboard injection method
|
||||
|
||||
### Camera Control
|
||||
|
||||
- Enable camera
|
||||
- Camera source
|
||||
- Camera resolution
|
||||
- Camera aspect ratio
|
||||
@ -187,29 +189,31 @@ Refer to [scrcpy/doc/shortcuts](https://github.com/Genymobile/scrcpy/blob/master
|
||||
|
||||
> Priority from high to low:
|
||||
|
||||
1. Optimize user interface, design a suitable logo ✅
|
||||
2. Built-in software update function ✅
|
||||
1. Improved logo ✅
|
||||
2. Software update feature ✅
|
||||
3. Record and save audio/video ✅
|
||||
4. Add device quick interaction control bar ✅
|
||||
5. Support customization of Adb and Scrcpy dependencies ✅
|
||||
6. Support custom device name, and import/export of preference settings ✅
|
||||
7. Customization, support independent configuration for individual devices ✅
|
||||
8. Add support for macOS and linux operating systems ✅
|
||||
9. Support internationalization ✅
|
||||
10. Support for dark mode ✅
|
||||
11. Add Gnirehtet reverse network function ✅
|
||||
12. Add new camera mirror related features ✅
|
||||
13. Better multi -screen collaboration ✅
|
||||
14. Add more features to device interaction bar: file push, screen rotation, audio control etc ✅
|
||||
15. Support bulk connecting to historical devices ✅
|
||||
16. Support to use built-in terminals to execute custom commands ✅
|
||||
17. Support automatic execution of mirror on devices ✅
|
||||
18. Support for custom startup mirroring ✅
|
||||
19. Support common batch processing function ✅
|
||||
20. Support the device to group 🚧
|
||||
21. Add file transmission assistant function 🚧
|
||||
22. Support GUI-based selective file downloads from devices 🚧
|
||||
23. Add game enhancement features such as game keyboard mapping 🚧
|
||||
4. Device quick interaction control bar ✅
|
||||
5. Custom Adb and Scrcpy dependencies ✅
|
||||
6. Custom device names ✅
|
||||
7. Export and import preferences ✅
|
||||
8. Individual device configuration ✅
|
||||
9. macOS and Linux support ✅
|
||||
10. Internationalization ✅
|
||||
11. Dark mode ✅
|
||||
12. Reverse tethering (Gnirehtet) ✅
|
||||
13. Camera mirroring ✅
|
||||
14. Multi-screen collaboration ✅
|
||||
15. File push, screen rotation, audio control ✅
|
||||
16. Batch connect historical devices ✅
|
||||
17. Built-in terminal ✅
|
||||
18. Auto-execute mirroring ✅
|
||||
19. Flexible mirroring launch ✅
|
||||
20. Batch processing ✅
|
||||
21. Scheduled tasks ✅
|
||||
22. Device grouping 🚧
|
||||
23. File transfer assistant 🚧
|
||||
24. Manage device files via interface 🚧
|
||||
25. Game key mapping 🚧
|
||||
|
||||
## FAQ
|
||||
|
||||
|
1
auto-imports.d.ts
vendored
1
auto-imports.d.ts
vendored
@ -6,7 +6,6 @@
|
||||
export {}
|
||||
declare global {
|
||||
const EffectScope: typeof import('vue')['EffectScope']
|
||||
const ElMessage: typeof import('element-plus/es')['ElMessage']
|
||||
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
|
||||
const computed: typeof import('vue')['computed']
|
||||
const createApp: typeof import('vue')['createApp']
|
||||
|
3
components.d.ts
vendored
3
components.d.ts
vendored
@ -9,7 +9,6 @@ declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
ElAutocomplete: typeof import('element-plus/es')['ElAutocomplete']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
|
||||
ElCol: typeof import('element-plus/es')['ElCol']
|
||||
ElCollapse: typeof import('element-plus/es')['ElCollapse']
|
||||
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
|
||||
@ -23,12 +22,12 @@ declare module 'vue' {
|
||||
ElForm: typeof import('element-plus/es')['ElForm']
|
||||
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
||||
ElIcon: typeof import('element-plus/es')['ElIcon']
|
||||
ElIconSearch: typeof import('@element-plus/icons-vue')['Search']
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElLink: typeof import('element-plus/es')['ElLink']
|
||||
ElOption: typeof import('element-plus/es')['ElOption']
|
||||
ElPopover: typeof import('element-plus/es')['ElPopover']
|
||||
ElRadio: typeof import('element-plus/es')['ElRadio']
|
||||
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
|
||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
||||
ElRow: typeof import('element-plus/es')['ElRow']
|
||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
|
@ -24,6 +24,7 @@
|
||||
"dependencies": {
|
||||
"electron-in-page-search": "^1.3.2",
|
||||
"nanoid": "^5.0.7",
|
||||
"pinia-plugin-persistedstate": "^3.2.1",
|
||||
"vue": "^3.4.26"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
title="定时任务"
|
||||
width="60%"
|
||||
:title="$t('device.task.name')"
|
||||
width="70%"
|
||||
class="el-dialog-beautify"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
@ -12,13 +12,17 @@
|
||||
ref="formRef"
|
||||
:model="model"
|
||||
:rules="rules"
|
||||
label-width="120px"
|
||||
class="!pr-[120px] !pt-4"
|
||||
label-width="180px"
|
||||
class="!pr-24 !pt-4"
|
||||
>
|
||||
<ele-form-item-col label="任务类型" :span="24" prop="taskType">
|
||||
<ele-form-item-col
|
||||
:label="$t('device.task.type')"
|
||||
:span="24"
|
||||
prop="taskType"
|
||||
>
|
||||
<el-select
|
||||
v-model="model.taskType"
|
||||
placeholder="请选择任务类型"
|
||||
:placeholder="$t('common.select.please')"
|
||||
clearable
|
||||
filterable
|
||||
@change="onTaskChange"
|
||||
@ -32,21 +36,25 @@
|
||||
</el-option>
|
||||
</el-select>
|
||||
</ele-form-item-col>
|
||||
<ele-form-item-col label="执行频率" :span="24" prop="timerType">
|
||||
<ele-form-item-col
|
||||
:label="$t('device.task.frequency')"
|
||||
:span="24"
|
||||
prop="timerType"
|
||||
>
|
||||
<el-radio-group v-model="model.timerType">
|
||||
<el-radio
|
||||
v-for="(item, index) of timerModel"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
>
|
||||
{{ item.label }}
|
||||
{{ $t(item.label) }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</ele-form-item-col>
|
||||
|
||||
<ele-form-item-col
|
||||
v-if="['timeout'].includes(model.timerType)"
|
||||
label="执行时间"
|
||||
:label="$t('device.task.timeout')"
|
||||
:span="24"
|
||||
prop="timeout"
|
||||
>
|
||||
@ -61,7 +69,7 @@
|
||||
|
||||
<ele-form-item-col
|
||||
v-if="['interval'].includes(model.timerType)"
|
||||
label="重复规则"
|
||||
:label="$t('device.task.interval')"
|
||||
:span="24"
|
||||
prop="interval"
|
||||
>
|
||||
@ -74,14 +82,14 @@
|
||||
<template #append>
|
||||
<el-select
|
||||
v-model="model.intervalType"
|
||||
placeholder="请选择时间单位"
|
||||
:placeholder="$t('common.select.please')"
|
||||
filterable
|
||||
class="!w-24"
|
||||
class="!w-36"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, index) of intervalModel"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
:label="$t(item.label)"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
@ -91,7 +99,7 @@
|
||||
|
||||
<ele-form-item-col
|
||||
v-if="['install'].includes(model.taskType)"
|
||||
label="选择应用"
|
||||
:label="$t('device.task.extra.app')"
|
||||
:span="24"
|
||||
prop="extra"
|
||||
>
|
||||
@ -112,7 +120,7 @@
|
||||
|
||||
<ele-form-item-col
|
||||
v-if="['shell'].includes(model.taskType)"
|
||||
label="选择脚本"
|
||||
:label="$t('device.task.extra.shell')"
|
||||
:span="24"
|
||||
prop="extra"
|
||||
>
|
||||
@ -130,14 +138,20 @@
|
||||
}"
|
||||
/>
|
||||
</ele-form-item-col>
|
||||
|
||||
<ele-form-item-col :span="24" label="">
|
||||
<div class="text-red-200 hover:text-red-500 transition-colors">
|
||||
{{ $t('device.task.tips') }}
|
||||
</div>
|
||||
</ele-form-item-col>
|
||||
</ele-form-row>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="close">
|
||||
取消
|
||||
{{ $t('common.cancel') }}
|
||||
</el-button>
|
||||
<el-button :loading type="primary" @click="submit">
|
||||
确定
|
||||
{{ $t('common.confirm') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@ -173,14 +187,16 @@ const model = ref({
|
||||
|
||||
const rules = computed(() =>
|
||||
Object.keys(model.value).reduce((obj, item) => {
|
||||
obj[item] = [{ required: true, message: '该选项不能为空', trigger: 'blur' }]
|
||||
obj[item] = [
|
||||
{ required: true, message: window.t('common.required'), trigger: 'blur' },
|
||||
]
|
||||
|
||||
if (item === 'timeout') {
|
||||
obj[item].push({
|
||||
trigger: 'blur',
|
||||
validator: (rule, value, callback) => {
|
||||
if (value.getTime() <= Date.now()) {
|
||||
callback(new Error('不能小于当前时间'))
|
||||
callback(new Error(window.t('device.task.timeout.tips')))
|
||||
}
|
||||
else {
|
||||
callback()
|
||||
|
@ -16,7 +16,6 @@
|
||||
>
|
||||
<template #default="{ loading = false } = {}">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
:title="$t(item.tips || item.label)"
|
||||
:loading="loading"
|
||||
@ -74,7 +73,7 @@ const actionModel = [
|
||||
component: Shell,
|
||||
},
|
||||
{
|
||||
label: 'device.control.task.name',
|
||||
label: 'device.task.name',
|
||||
elIcon: 'Clock',
|
||||
component: Tasks,
|
||||
},
|
||||
|
@ -160,7 +160,7 @@ export default {
|
||||
tips: 'device.control.shell.tips',
|
||||
},
|
||||
{
|
||||
label: 'device.control.task.name',
|
||||
label: 'device.task.name',
|
||||
elIcon: 'Clock',
|
||||
component: 'Tasks',
|
||||
},
|
||||
|
@ -7,7 +7,7 @@
|
||||
:icon="loading ? '' : 'Monitor'"
|
||||
@click="handleClick(row)"
|
||||
>
|
||||
{{ loading ? $t('common.progress') : $t('device.mirror.start') }}
|
||||
{{ loading ? $t('common.starting') : $t('device.mirror.start') }}
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
<el-icon class="is-loading">
|
||||
<Loading />
|
||||
</el-icon>
|
||||
{{ $t('common.progress') }}
|
||||
{{ $t('common.starting') }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ $t(item.label) }}
|
||||
|
@ -172,7 +172,11 @@ export default {
|
||||
|
||||
handleSave() {
|
||||
this.preferenceStore.setData(this.preferenceData)
|
||||
this.$message.success(this.$t('preferences.config.save.placeholder'))
|
||||
this.$message({
|
||||
message: this.$t('preferences.config.save.placeholder'),
|
||||
type: 'success',
|
||||
grouping: true,
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -0,0 +1,201 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
:title="$t('device.task.list')"
|
||||
width="98%"
|
||||
class="el-dialog-beautify"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
@closed="onClosed"
|
||||
>
|
||||
<div class="flex items-center justify-center absolute top-4 left-center">
|
||||
<el-radio-group
|
||||
v-model="taskStatus"
|
||||
size="small"
|
||||
@change="onTaskStatusChange"
|
||||
>
|
||||
<el-radio-button value="progress" :label="$t('common.progress')" />
|
||||
<el-radio-button value="finished" :label="$t('common.finished')" />
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div v-loading="loading" class="mt-4">
|
||||
<el-table :data="tableData" stripe>
|
||||
<template #empty>
|
||||
<el-empty></el-empty>
|
||||
</template>
|
||||
|
||||
<el-table-column
|
||||
v-slot="{ row }"
|
||||
prop="taskType"
|
||||
:label="$t('device.task.type')"
|
||||
align="center"
|
||||
>
|
||||
{{ $t(getDictLabel(taskModel, row.taskType)) }}
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
v-slot="{ row }"
|
||||
prop="timerType"
|
||||
:label="$t('device.task.frequency')"
|
||||
align="center"
|
||||
>
|
||||
{{ $t(getDictLabel('timerType', row.timerType)) }}
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
v-slot="{ row }"
|
||||
:label="$t('device.task.timeout')"
|
||||
align="center"
|
||||
>
|
||||
{{ row.formatTimeout }}
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
v-slot="{ row }"
|
||||
:label="$t('device.task.interval')"
|
||||
align="center"
|
||||
>
|
||||
<span v-if="['timeout'].includes(row.timerType)" class="">
|
||||
{{ $t('device.task.noRepeat') }}
|
||||
</span>
|
||||
<span v-if="['interval'].includes(row.timerType)" class="">
|
||||
{{ row.interval }}
|
||||
{{ $t(getDictLabel('timeUnit', row.intervalType)) }}
|
||||
</span>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
v-slot="{ row }"
|
||||
prop="devices"
|
||||
:label="$t('device.task.devices')"
|
||||
align="center"
|
||||
>
|
||||
<EleTagCollapse
|
||||
effect="light"
|
||||
borderless
|
||||
:value="row.devices"
|
||||
:label="(item) => item.$remark || `${item.$name} (${item.id})`"
|
||||
class="justify-center"
|
||||
/>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
v-slot="{ row }"
|
||||
:label="$t('device.control.name')"
|
||||
align="center"
|
||||
>
|
||||
<EleTooltipButton
|
||||
v-if="['progress'].includes(taskStatus)"
|
||||
text
|
||||
type="danger"
|
||||
effect="light"
|
||||
:content="$t('common.stop')"
|
||||
icon="CircleClose"
|
||||
circle
|
||||
@click="handleStop(row)"
|
||||
>
|
||||
</EleTooltipButton>
|
||||
|
||||
<EleTooltipButton
|
||||
v-if="['finished'].includes(taskStatus)"
|
||||
text
|
||||
type="primary"
|
||||
effect="light"
|
||||
:content="$t('device.task.restart')"
|
||||
icon="RefreshLeft"
|
||||
circle
|
||||
@click="handleReStart(row)"
|
||||
>
|
||||
</EleTooltipButton>
|
||||
|
||||
<EleTooltipButton
|
||||
text
|
||||
type="info"
|
||||
effect="light"
|
||||
:content="$t('common.remove')"
|
||||
icon="Remove"
|
||||
circle
|
||||
@click="handleRemove(row)"
|
||||
>
|
||||
</EleTooltipButton>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="h-4"></div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
import {
|
||||
timeUnit as intervalModel,
|
||||
timerType as timerModel,
|
||||
} from '$/dicts/index.js'
|
||||
|
||||
import { useTaskStore } from '$/store/index.js'
|
||||
import { sleep } from '$/utils'
|
||||
|
||||
import { getDictLabel } from '$/dicts/helper'
|
||||
|
||||
const taskStore = useTaskStore()
|
||||
|
||||
const visible = ref(false)
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const taskModel = computed(() => taskStore.model)
|
||||
|
||||
const taskStatus = ref('progress')
|
||||
|
||||
const tableData = computed(() => {
|
||||
const value = taskStore.list.filter(
|
||||
item => item.taskStatus === taskStatus.value,
|
||||
)
|
||||
|
||||
return value
|
||||
})
|
||||
|
||||
async function open(args) {
|
||||
visible.value = true
|
||||
}
|
||||
|
||||
function close() {
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
async function onClosed() {
|
||||
taskStatus.value = 'progress'
|
||||
}
|
||||
|
||||
async function onTaskStatusChange() {
|
||||
loading.value = true
|
||||
|
||||
await sleep()
|
||||
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
function handleStop(row) {
|
||||
taskStore.stop(row)
|
||||
}
|
||||
|
||||
function handleReStart(row) {
|
||||
taskStatus.value = 'progress'
|
||||
taskStore.restart(row)
|
||||
}
|
||||
|
||||
function handleRemove(row) {
|
||||
taskStore.remove(row)
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open,
|
||||
close,
|
||||
})
|
||||
</script>
|
||||
|
||||
<style></style>
|
19
src/components/Quick/components/Task/index.vue
Normal file
19
src/components/Quick/components/Task/index.vue
Normal file
@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<div class="" @click="handleClick">
|
||||
<slot />
|
||||
|
||||
<TaskListDialog ref="taskListDialogRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import TaskListDialog from './components/TaskListDialog/index.vue'
|
||||
|
||||
const taskListDialogRef = ref(null)
|
||||
|
||||
function handleClick() {
|
||||
taskListDialogRef.value.open()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="postcss"></style>
|
@ -2,8 +2,8 @@
|
||||
<div class="flex items-center space-x-4 relative z-10">
|
||||
<component
|
||||
:is="item.component || 'div'"
|
||||
v-for="(item, index) in actionModel"
|
||||
:key="index"
|
||||
v-for="item in actionModel"
|
||||
:key="item.label"
|
||||
class="flex-none"
|
||||
v-bind="{
|
||||
...(item.command
|
||||
@ -13,12 +13,16 @@
|
||||
: {}),
|
||||
}"
|
||||
>
|
||||
<template #default="{ loading = false } = {}">
|
||||
<el-button
|
||||
circle
|
||||
size="small"
|
||||
:title="$t(item.tips || item.label)"
|
||||
:loading="loading"
|
||||
<template #default="{ ...slotProps } = {}">
|
||||
<EleTooltipButton
|
||||
v-bind="{
|
||||
text: true,
|
||||
content: $t(item.tips || item.label),
|
||||
circle: true,
|
||||
size: 'small',
|
||||
effect: 'light',
|
||||
...slotProps,
|
||||
}"
|
||||
>
|
||||
<template #icon>
|
||||
<svg-icon
|
||||
@ -30,21 +34,27 @@
|
||||
<component :is="item.elIcon" />
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-button>
|
||||
</EleTooltipButton>
|
||||
</template>
|
||||
</component>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Search from './components/Search/index.vue'
|
||||
import Restart from './components/Restart/index.vue'
|
||||
import Log from './components/Log/index.vue'
|
||||
import Task from './components/Task/index.vue'
|
||||
import Terminal from './components/Terminal/index.vue'
|
||||
import Log from './components/Log/index.vue'
|
||||
import Restart from './components/Restart/index.vue'
|
||||
import Search from './components/Search/index.vue'
|
||||
|
||||
const props = defineProps({})
|
||||
|
||||
const actionModel = [
|
||||
{
|
||||
label: 'device.task.list',
|
||||
elIcon: 'Clock',
|
||||
component: Task,
|
||||
},
|
||||
{
|
||||
label: 'device.terminal.name',
|
||||
svgIcon: 'command',
|
||||
|
21
src/dicts/helper.js
Normal file
21
src/dicts/helper.js
Normal file
@ -0,0 +1,21 @@
|
||||
import * as dicts from '$/dicts/index.js'
|
||||
|
||||
export function getDictLabel(dict, value) {
|
||||
let label = ''
|
||||
|
||||
if (typeof dict === 'function') {
|
||||
label = dict(value)
|
||||
}
|
||||
else if (typeof dict === 'string') {
|
||||
label = dicts?.[dict]?.find(item => item.value == value)?.label
|
||||
}
|
||||
else {
|
||||
label = dict?.find(item => item.value == value)?.label
|
||||
}
|
||||
|
||||
if (!label) {
|
||||
return ''
|
||||
}
|
||||
|
||||
return label
|
||||
}
|
@ -1,41 +1,41 @@
|
||||
export const timerType = [
|
||||
{
|
||||
label: '单次执行',
|
||||
label: 'device.task.frequency.timeout',
|
||||
value: 'timeout',
|
||||
},
|
||||
{
|
||||
label: '周期重复',
|
||||
label: 'device.task.frequency.interval',
|
||||
value: 'interval',
|
||||
},
|
||||
]
|
||||
|
||||
export const timeUnit = [
|
||||
{
|
||||
label: '月',
|
||||
label: 'time.unit.month',
|
||||
value: 'month',
|
||||
},
|
||||
{
|
||||
label: '周',
|
||||
label: 'time.unit.week',
|
||||
value: 'week',
|
||||
},
|
||||
{
|
||||
label: '天',
|
||||
label: 'time.unit.day',
|
||||
value: 'day',
|
||||
},
|
||||
{
|
||||
label: '小时',
|
||||
label: 'time.unit.hour',
|
||||
value: 'hour',
|
||||
},
|
||||
{
|
||||
label: '分钟',
|
||||
label: 'time.unit.minute',
|
||||
value: 'minute',
|
||||
},
|
||||
{
|
||||
label: '秒',
|
||||
label: 'time.unit.second',
|
||||
value: 'second',
|
||||
},
|
||||
{
|
||||
label: '毫秒',
|
||||
label: 'time.unit.millisecond',
|
||||
value: 'millisecond',
|
||||
},
|
||||
]
|
||||
|
@ -8,11 +8,17 @@
|
||||
"common.input.placeholder": "Please input",
|
||||
"common.success": "Operation successful",
|
||||
"common.success.batch": "Batch operation success",
|
||||
"common.progress": "Starting",
|
||||
"common.starting": "Starting",
|
||||
"common.loading": "Loading",
|
||||
"common.search": "Search",
|
||||
"common.batch": "Batch",
|
||||
"common.device": "Device",
|
||||
"common.progress": "In Progress",
|
||||
"common.finished": "Finished",
|
||||
"common.stop": "Stop",
|
||||
"common.remove": "Remove",
|
||||
"common.select.please": "Please Select",
|
||||
"common.required": "This field cannot be empty",
|
||||
|
||||
"common.language.name": "Language",
|
||||
"common.language.placeholder": "Select language",
|
||||
@ -20,6 +26,14 @@
|
||||
"common.language.zh-TW": "繁體中文",
|
||||
"common.language.en-US": "English",
|
||||
|
||||
"time.unit.month": "month",
|
||||
"time.unit.week": "week",
|
||||
"time.unit.day": "day",
|
||||
"time.unit.hour": "hour",
|
||||
"time.unit.minute": "minute",
|
||||
"time.unit.second": "second",
|
||||
"time.unit.millisecond": "millisecond",
|
||||
|
||||
"close.quit": "Quit",
|
||||
"close.quit.cancel": "Cancel quit",
|
||||
"close.minimize": "Minimize to tray",
|
||||
@ -37,6 +51,22 @@
|
||||
"device.permission.error": "Device permission error, please reconnect device and allow USB debugging",
|
||||
"device.terminal.name": "Terminal",
|
||||
|
||||
"device.task.name": "Scheduled Task",
|
||||
"device.task.tips": " Note: Please ensure that your computer stays awake, otherwise scheduled tasks will not be executed properly.",
|
||||
"device.task.list": "Scheduled Task List",
|
||||
"device.task.type": "Task Type",
|
||||
"device.task.frequency": "Execution Frequency",
|
||||
"device.task.frequency.timeout": "Single execution",
|
||||
"device.task.frequency.interval": "Periodic repetition",
|
||||
"device.task.timeout": "Execution Time",
|
||||
"device.task.timeout.tips": "Cannot be earlier than the current time",
|
||||
"device.task.interval": "Repeat Interval",
|
||||
"device.task.devices": "Involved Devices",
|
||||
"device.task.noRepeat": "No Repeat",
|
||||
"device.task.restart": "Execute Again",
|
||||
"device.task.extra.app": "Select Application",
|
||||
"device.task.extra.shell": "Select Script",
|
||||
|
||||
"device.wireless.name": "Wireless",
|
||||
"device.wireless.mode": "Wireless Mode",
|
||||
"device.wireless.mode.error": "Do not get the local area network connection address, please check the network",
|
||||
@ -113,7 +143,6 @@
|
||||
"device.control.shell.push.success": "Push script success",
|
||||
"device.control.shell.enter": "Please enter the Enter key to confirm the execution of the script",
|
||||
"device.control.shell.success": "Script execution successfully",
|
||||
"device.control.task.name": "Timing Task",
|
||||
"device.control.capture": "Screenshot",
|
||||
"device.control.capture.progress": "Capturing screenshot for {deviceName}...",
|
||||
"device.control.capture.success.message": "Open screenshot location?",
|
||||
|
@ -8,11 +8,17 @@
|
||||
"common.input.placeholder": "请填写",
|
||||
"common.success": "操作成功",
|
||||
"common.success.batch": "批量操作成功",
|
||||
"common.progress": "启动中",
|
||||
"common.starting": "启动中",
|
||||
"common.loading": "加载中",
|
||||
"common.search": "搜索",
|
||||
"common.batch": "批量",
|
||||
"common.device": "设备",
|
||||
"common.progress": "进行中",
|
||||
"common.finished": "已结束",
|
||||
"common.stop": "终止",
|
||||
"common.remove": "移除",
|
||||
"common.select.please": "请选择",
|
||||
"common.required": "该选项不能为空",
|
||||
|
||||
"common.language.name": "语言",
|
||||
"common.language.placeholder": "选择你需要的语言",
|
||||
@ -20,6 +26,14 @@
|
||||
"common.language.zh-TW": "繁體中文",
|
||||
"common.language.en-US": "English",
|
||||
|
||||
"time.unit.month": "月",
|
||||
"time.unit.week": "周",
|
||||
"time.unit.day": "天",
|
||||
"time.unit.hour": "小时",
|
||||
"time.unit.minute": "分钟",
|
||||
"time.unit.second": "秒",
|
||||
"time.unit.millisecond": "毫秒",
|
||||
|
||||
"close.quit": "退出",
|
||||
"close.quit.cancel": "取消退出",
|
||||
"close.minimize": "最小化到托盘",
|
||||
@ -37,6 +51,22 @@
|
||||
"device.permission.error": "设备可能未授权成功,请重新插拔设备并点击允许USB调试",
|
||||
"device.terminal.name": "终端调试",
|
||||
|
||||
"device.task.name": "定时任务",
|
||||
"device.task.tips": " 注意:请确保你的计算机保持唤醒状态,否则定时任务将无法被正常执行。",
|
||||
"device.task.list": "定时任务列表",
|
||||
"device.task.type": "任务类型",
|
||||
"device.task.frequency": "执行频率",
|
||||
"device.task.frequency.timeout": "单次执行",
|
||||
"device.task.frequency.interval": "周期重复",
|
||||
"device.task.timeout": "执行时间",
|
||||
"device.task.timeout.tips": "不能小于当前时间",
|
||||
"device.task.interval": "重复间隔",
|
||||
"device.task.devices": "涉及设备",
|
||||
"device.task.noRepeat": "不重复",
|
||||
"device.task.restart": "再次执行",
|
||||
"device.task.extra.app": "选择应用",
|
||||
"device.task.extra.shell": "选择脚本",
|
||||
|
||||
"device.wireless.name": "无线",
|
||||
"device.wireless.mode": "无线模式",
|
||||
"device.wireless.mode.error": "没有获取到局域网连接地址,请检查网络",
|
||||
@ -113,7 +143,6 @@
|
||||
"device.control.shell.push.success": "推送脚本成功",
|
||||
"device.control.shell.enter": "请输入回车键确认执行该脚本",
|
||||
"device.control.shell.success": "脚本执行成功",
|
||||
"device.control.task.name": "定时任务",
|
||||
"device.control.capture": "截取屏幕",
|
||||
"device.control.capture.progress": "正在截取 {deviceName} 的屏幕快照...",
|
||||
"device.control.capture.success.message": "是否前往截屏位置进行查看?",
|
||||
|
@ -8,11 +8,17 @@
|
||||
"common.input.placeholder": "請輸入",
|
||||
"common.success": "操作成功",
|
||||
"common.success.batch": "批量操作成功",
|
||||
"common.progress": "啟動中",
|
||||
"common.starting": "啟動中",
|
||||
"common.loading": "載入中",
|
||||
"common.search": "搜尋",
|
||||
"common.batch": "批量",
|
||||
"common.device": "裝置",
|
||||
"common.progress": "進行中",
|
||||
"common.finished": "已結束",
|
||||
"common.stop": "終止",
|
||||
"common.remove": "移除",
|
||||
"common.select.please": "請選擇",
|
||||
"common.required": "該選項不能為空",
|
||||
|
||||
"common.language.name": "語言",
|
||||
"common.language.placeholder": "選擇你要的語言",
|
||||
@ -20,6 +26,14 @@
|
||||
"common.language.zh-TW": "繁體中文",
|
||||
"common.language.en-US": "English",
|
||||
|
||||
"time.unit.month": "月",
|
||||
"time.unit.week": "週",
|
||||
"time.unit.day": "天",
|
||||
"time.unit.hour": "小時",
|
||||
"time.unit.minute": "分鐘",
|
||||
"time.unit.second": "秒",
|
||||
"time.unit.millisecond": "毫秒",
|
||||
|
||||
"close.quit": "結束",
|
||||
"close.quit.cancel": "取消結束",
|
||||
"close.minimize": "最小化至系統工具列",
|
||||
@ -37,6 +51,22 @@
|
||||
"device.permission.error": "裝置權限錯誤,請重新連接裝置並允許 USB 偵錯",
|
||||
"device.terminal.name": "終端偵錯",
|
||||
|
||||
"device.task.name": "定時任務",
|
||||
"device.task.tips": "注意:請確保您的電腦保持唤醒状态,否則定時任務將無法正常執行。",
|
||||
"device.task.list": "定時任務列表",
|
||||
"device.task.type": "任務類型",
|
||||
"device.task.frequency": "執行頻率",
|
||||
"device.task.frequency.timeout": "單次執行",
|
||||
"device.task.frequency.interval": "週期重複",
|
||||
"device.task.timeout": "執行時間",
|
||||
"device.task.timeout.tips": "不能小於當前時間",
|
||||
"device.task.interval": "重複間隔",
|
||||
"device.task.devices": "涉及設備",
|
||||
"device.task.noRepeat": "不重複",
|
||||
"device.task.restart": "再次執行",
|
||||
"device.task.extra.app": "選擇應用",
|
||||
"device.task.extra.shell": "選擇腳本",
|
||||
|
||||
"device.wireless.name": "無線",
|
||||
"device.wireless.mode": "無線模式",
|
||||
"device.wireless.mode.error": "未取得區域網路連接位址,請檢查網路",
|
||||
@ -113,7 +143,6 @@
|
||||
"device.control.shell.push.success": "推送腳本成功",
|
||||
"device.control.shell.enter": "請輸入回車鍵確認執行該腳本",
|
||||
"device.control.shell.success": "腳本執行成功",
|
||||
"device.control.task.name": "定時任務",
|
||||
"device.control.capture": "擷取螢幕",
|
||||
"device.control.capture.progress": "正在擷取 {deviceName} 的螢幕快照...",
|
||||
"device.control.capture.success.message": "是否前往截圖位置進行檢視?",
|
||||
|
92
src/plugins/element-plus/expands/EleTagCollapse/index.vue
Normal file
92
src/plugins/element-plus/expands/EleTagCollapse/index.vue
Normal file
@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<div class="flex items-center space-x-2">
|
||||
<ElTag
|
||||
v-for="(item, index) of visibleTags"
|
||||
:key="index"
|
||||
v-bind="$props"
|
||||
:class="{
|
||||
'!border-none': borderless,
|
||||
}"
|
||||
>
|
||||
{{ showLabel(item) }}
|
||||
</ElTag>
|
||||
|
||||
<el-dropdown v-if="collapseTags.length">
|
||||
<ElTag v-bind="$props">
|
||||
+ {{ collapseTags.length }}
|
||||
</ElTag>
|
||||
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item
|
||||
v-for="(item, index) of collapseTags"
|
||||
:key="index"
|
||||
:class="{
|
||||
'!border-none': borderless,
|
||||
}"
|
||||
>
|
||||
{{ showLabel(item) }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ElTag } from 'element-plus'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
...ElTag.props,
|
||||
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
|
||||
visibleNumber: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
|
||||
label: {
|
||||
type: [String, Function, Number],
|
||||
default: '',
|
||||
},
|
||||
|
||||
borderless: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
|
||||
const visibleTags = computed(() => {
|
||||
const value = props.value.slice(0, props.visibleNumber)
|
||||
return value
|
||||
})
|
||||
|
||||
const collapseTags = computed(() => {
|
||||
const value = props.value.slice(props.visibleNumber)
|
||||
return value
|
||||
})
|
||||
|
||||
function showLabel(item) {
|
||||
if (!props.label) {
|
||||
return item?.label || ''
|
||||
}
|
||||
|
||||
let value = ''
|
||||
|
||||
if (['number', 'string'].includes(typeof props.label)) {
|
||||
value = item[props.label]
|
||||
}
|
||||
else if (typeof props.label === 'function') {
|
||||
value = props.label(item)
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
43
src/plugins/element-plus/expands/EleTagDict/index.vue
Normal file
43
src/plugins/element-plus/expands/EleTagDict/index.vue
Normal file
@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<el-tag
|
||||
:class="{
|
||||
'!border-none': borderless,
|
||||
}"
|
||||
>
|
||||
{{ label }}
|
||||
</el-tag>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { getDictLabel } from '$/dicts/helper'
|
||||
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: [Number, String],
|
||||
default: '',
|
||||
},
|
||||
dict: {
|
||||
type: [String, Array, Function],
|
||||
},
|
||||
i18n: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
borderless: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
|
||||
const label = computed(() => {
|
||||
const value = getDictLabel(props.dict, props.value)
|
||||
|
||||
if (props.i18n) {
|
||||
return window.t(value)
|
||||
}
|
||||
|
||||
return value
|
||||
})
|
||||
</script>
|
||||
|
||||
<style></style>
|
21
src/plugins/element-plus/expands/EleTooltipButton/index.vue
Normal file
21
src/plugins/element-plus/expands/EleTooltipButton/index.vue
Normal file
@ -0,0 +1,21 @@
|
||||
<template>
|
||||
<el-tooltip>
|
||||
<ElButton v-bind="{ ...$props }" @click="emit('click', $event)">
|
||||
<slot name="icon"></slot>
|
||||
<slot></slot>
|
||||
</ElButton>
|
||||
<slot name="content"></slot>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ElButton } from 'element-plus'
|
||||
|
||||
const props = defineProps({
|
||||
...ElButton.props,
|
||||
})
|
||||
|
||||
const emit = defineEmits(['click'])
|
||||
</script>
|
||||
|
||||
<style></style>
|
@ -10,9 +10,12 @@ import * as ElementPlusIcons from '@element-plus/icons-vue'
|
||||
|
||||
import { ElLoading, ElMessage, ElMessageBox } from 'element-plus'
|
||||
|
||||
import EleIconLoading from './components/EleIconLoading/index.vue'
|
||||
import EleFormRow from './components/EleFormRow/index.vue'
|
||||
import EleFormItemCol from './components/EleFormItemCol/index.vue'
|
||||
import EleIconLoading from './expands/EleIconLoading/index.vue'
|
||||
import EleFormRow from './expands/EleFormRow/index.vue'
|
||||
import EleFormItemCol from './expands/EleFormItemCol/index.vue'
|
||||
import EleTooltipButton from './expands/EleTooltipButton/index.vue'
|
||||
import EleTagDict from './expands/EleTagDict/index.vue'
|
||||
import EleTagCollapse from './expands/EleTagCollapse/index.vue'
|
||||
|
||||
export default {
|
||||
install(app) {
|
||||
@ -34,5 +37,8 @@ export default {
|
||||
|
||||
app.component('EleFormRow', EleFormRow)
|
||||
app.component('EleFormItemCol', EleFormItemCol)
|
||||
app.component('EleTooltipButton', EleTooltipButton)
|
||||
app.component('EleTagDict', EleTagDict)
|
||||
app.component('EleTagCollapse', EleTagCollapse)
|
||||
},
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { createPinia } from 'pinia'
|
||||
import persistedState from 'pinia-plugin-persistedstate'
|
||||
import { useDeviceStore } from './device/index.js'
|
||||
import { usePreferenceStore } from './preference/index.js'
|
||||
import { useThemeStore } from './theme/index.js'
|
||||
@ -10,6 +11,8 @@ export default {
|
||||
install(app) {
|
||||
const store = createPinia()
|
||||
|
||||
store.use(persistedState)
|
||||
|
||||
app.use(store)
|
||||
|
||||
app.config.globalProperties.$store = {
|
||||
|
@ -11,99 +11,146 @@ import { clearTimer, isIPWithPort, replaceIP, setTimer } from '$/utils/index.js'
|
||||
|
||||
dayjs.extend(duration)
|
||||
|
||||
export const useTaskStore = defineStore('app-task', () => {
|
||||
const event = useEventBus('app-task')
|
||||
export const useTaskStore = defineStore(
|
||||
'app-task',
|
||||
() => {
|
||||
const event = useEventBus('app-task')
|
||||
|
||||
const model = ref([
|
||||
{
|
||||
label: 'device.control.install',
|
||||
value: 'install',
|
||||
},
|
||||
{
|
||||
label: 'device.control.capture',
|
||||
value: 'screenshot',
|
||||
},
|
||||
{
|
||||
label: 'device.control.shell.name',
|
||||
value: 'shell',
|
||||
},
|
||||
])
|
||||
|
||||
const list = ref([])
|
||||
|
||||
function add(form) {
|
||||
const task = {
|
||||
...form,
|
||||
timerId: void 0,
|
||||
id: nanoid(),
|
||||
}
|
||||
|
||||
event.emit(task)
|
||||
|
||||
list.value.push(task)
|
||||
}
|
||||
|
||||
function getTimeout(task) {
|
||||
let value = 0
|
||||
|
||||
const { timerType } = task
|
||||
|
||||
if (timerType === 'timeout') {
|
||||
value = dayjs(task.timeout).diff(dayjs())
|
||||
}
|
||||
else if (timerType === 'interval') {
|
||||
value = dayjs.duration(task.interval, task.intervalType).asMilliseconds()
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
function start({ task, handler }) {
|
||||
const { timerType, devices } = task
|
||||
|
||||
const files = task.extra ? task.extra.split(',') : void 0
|
||||
|
||||
const timeout = getTimeout(task)
|
||||
|
||||
task.timerId = setTimer(
|
||||
timerType,
|
||||
() => {
|
||||
handler(devices, { files })
|
||||
|
||||
if (['timeout'].includes(timerType)) {
|
||||
clear(task)
|
||||
}
|
||||
const model = ref([
|
||||
{
|
||||
label: 'device.control.install',
|
||||
value: 'install',
|
||||
},
|
||||
timeout,
|
||||
)
|
||||
}
|
||||
{
|
||||
label: 'device.control.capture',
|
||||
value: 'screenshot',
|
||||
},
|
||||
{
|
||||
label: 'device.control.shell.name',
|
||||
value: 'shell',
|
||||
},
|
||||
])
|
||||
|
||||
function clear(task) {
|
||||
const { timerType, timerId } = task
|
||||
if (timerId) {
|
||||
clearTimer(timerType, timerId)
|
||||
list.value = list.value.filter(item => item.id !== task.id)
|
||||
}
|
||||
}
|
||||
const list = ref([])
|
||||
|
||||
function on(name, callback) {
|
||||
event.on((...args) => {
|
||||
const [{ taskType }] = args
|
||||
|
||||
if (taskType !== name) {
|
||||
return false
|
||||
function add(form) {
|
||||
const task = {
|
||||
...form,
|
||||
timerId: void 0,
|
||||
id: nanoid(),
|
||||
taskStatus: 'start',
|
||||
formatTimeout: dayjs(form.timeout).format('YYYY-MM-DD HH:mm:ss'),
|
||||
}
|
||||
|
||||
callback(...args)
|
||||
})
|
||||
event.emit(task)
|
||||
|
||||
return event
|
||||
}
|
||||
list.value.push(task)
|
||||
}
|
||||
|
||||
function emit(name, args) {
|
||||
event.emit({ taskType: name, ...args })
|
||||
return event
|
||||
}
|
||||
function getTimeout(task) {
|
||||
let value = 0
|
||||
|
||||
return { event, on, emit, list, model, add, start, clear }
|
||||
})
|
||||
const { timerType } = task
|
||||
|
||||
if (timerType === 'timeout') {
|
||||
value = dayjs(task.timeout).diff(dayjs())
|
||||
}
|
||||
else if (timerType === 'interval') {
|
||||
value = dayjs
|
||||
.duration(task.interval, task.intervalType)
|
||||
.asMilliseconds()
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
function start({ task, handler }) {
|
||||
const { timerType, devices } = task
|
||||
|
||||
const files = task.extra ? task.extra.split(',') : void 0
|
||||
|
||||
const timeout = getTimeout(task)
|
||||
|
||||
task.timerId = setTimer(
|
||||
timerType,
|
||||
() => {
|
||||
handler(devices, { files })
|
||||
|
||||
if (['timeout'].includes(timerType)) {
|
||||
stop(task)
|
||||
}
|
||||
},
|
||||
timeout,
|
||||
)
|
||||
|
||||
Object.assign(task, {
|
||||
taskStatus: 'progress',
|
||||
})
|
||||
}
|
||||
|
||||
function stop(task) {
|
||||
const { timerType, timerId } = task
|
||||
if (timerId) {
|
||||
clearTimer(timerType, timerId)
|
||||
Object.assign(task, {
|
||||
id: void 0,
|
||||
taskStatus: 'finished',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function restart(task) {
|
||||
event.emit(task)
|
||||
}
|
||||
|
||||
function remove(task) {
|
||||
stop(task)
|
||||
list.value = list.value.filter(item => item.id !== task.id)
|
||||
}
|
||||
|
||||
function removeAll(tasks) {
|
||||
for (let index = 0; index < tasks.length; index++) {
|
||||
const item = tasks[index]
|
||||
remove(item)
|
||||
}
|
||||
}
|
||||
|
||||
function on(name, callback) {
|
||||
event.on((...args) => {
|
||||
const [{ taskType }] = args
|
||||
|
||||
if (taskType !== name) {
|
||||
return false
|
||||
}
|
||||
|
||||
callback(...args)
|
||||
})
|
||||
|
||||
return event
|
||||
}
|
||||
|
||||
function emit(name, args) {
|
||||
event.emit({ taskType: name, ...args })
|
||||
return event
|
||||
}
|
||||
|
||||
return {
|
||||
event,
|
||||
on,
|
||||
emit,
|
||||
list,
|
||||
model,
|
||||
add,
|
||||
start,
|
||||
stop,
|
||||
restart,
|
||||
remove,
|
||||
removeAll,
|
||||
}
|
||||
},
|
||||
{
|
||||
persist: {
|
||||
paths: ['list'],
|
||||
},
|
||||
},
|
||||
)
|
||||
|
@ -4,7 +4,7 @@ import { camelCase, cloneDeep, keyBy } from 'lodash-es'
|
||||
* @desc 使用async await 进项进行延时操作
|
||||
* @param {*} time
|
||||
*/
|
||||
export function sleep(time = 1000) {
|
||||
export function sleep(time = 500) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => resolve(true), time)
|
||||
})
|
||||
|
@ -27,7 +27,7 @@ export default defineConfig({
|
||||
'inset-0': 'top-0 bottom-0 left-0 right-0',
|
||||
'inset-center':
|
||||
'top-1/2 left-1/2 transform -translate-y-1/2 -translate-x-1/2',
|
||||
'inset-left-center': 'left-1/2 transform -translate-x-1/2',
|
||||
'inset-top-center': 'top-1/2 transform -translate-y-1/2',
|
||||
'top-center': 'top-1/2 transform -translate-y-1/2',
|
||||
'left-center': 'left-1/2 transform -translate-x-1/2',
|
||||
},
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user