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