feat: add batch select and operations for task list
- Add checkbox for each task item - Add select all checkbox in toolbar - Add batch cancel button for selected running/waiting tasks - Add batch delete button for selected completed/failed tasks - Show selected count in toolbar Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
# 我是简体中文用户
|
||||||
|
# 我是简体中文用户
|
||||||
|
# 我是简体中文用户
|
||||||
|
# 这是windows系统,不是linux,也不是wsl
|
||||||
|
# 这是windows系统,不是linux,也不是wsl
|
||||||
|
# 这是windows系统,不是linux,也不是wsl
|
||||||
|
|
||||||
|
# 涉及到各种图的画法,使用`mermaid`
|
||||||
|
|
||||||
|
# 代码注释使用中文。utf-8编码
|
||||||
|
|
||||||
|
@configs/git-commit.md
|
||||||
|
|
||||||
|
@configs/env.md
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# environment
|
||||||
|
|
||||||
|
**The current system is Windows.**
|
||||||
|
|
||||||
|
## go env:
|
||||||
|
|
||||||
|
**C:\Program Files\Go\bin**
|
||||||
|
|
||||||
|
## git env:
|
||||||
|
|
||||||
|
**C:\Program Files\PortableGit\bin**
|
||||||
|
|
||||||
|
## python env:
|
||||||
|
|
||||||
|
**C:\Program Files\Python314**
|
||||||
|
|
||||||
|
**C:\Program Files\Python314\Scripts**
|
||||||
|
|
||||||
|
**Please locate the venv or .venv directory in your project to create a Python virtual environment.**
|
||||||
|
|
||||||
|
## node env
|
||||||
|
|
||||||
|
**C:\Program Files\nodejs**
|
||||||
|
|
||||||
|
## nmap env:
|
||||||
|
|
||||||
|
**C:\Program Files (x86)\Nmap**
|
||||||
|
|
||||||
|
## sqliet3 env:
|
||||||
|
|
||||||
|
**C:\Program Files\sqlite-tools-win-x64-3510300**
|
||||||
|
|
||||||
|
## curl env:
|
||||||
|
|
||||||
|
**C:\Program Files\curl-8.19.0_2-win64-mingw\bin**
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
|
||||||
|
|
||||||
|
# 我是中文简体用户
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Commit Message Format
|
||||||
|
|
||||||
|
We have very precise rules over how our Git commit messages must be formatted.
|
||||||
|
This format leads to **easier to read commit history** and makes it analyzable for changelog generation.
|
||||||
|
|
||||||
|
Each commit message consists of a **header**, a **body**, and a **footer**.
|
||||||
|
|
||||||
|
```
|
||||||
|
<header>
|
||||||
|
<BLANK LINE>
|
||||||
|
<body>
|
||||||
|
<BLANK LINE>
|
||||||
|
<footer>
|
||||||
|
```
|
||||||
|
|
||||||
|
The `header` is mandatory and must conform to the [Commit Message Header](#commit-header) format.
|
||||||
|
|
||||||
|
The `body` is mandatory for all commits except for those of type "docs".
|
||||||
|
When the body is present it must be at least 20 characters long and must conform to the [Commit Message Body](#commit-body) format.
|
||||||
|
|
||||||
|
The `footer` is optional. The [Commit Message Footer](#commit-footer) format describes what the footer is used for and the structure it must have.
|
||||||
|
|
||||||
|
## Commit Message Header
|
||||||
|
|
||||||
|
```
|
||||||
|
<type>(<scope>): <short summary>
|
||||||
|
│ │ │
|
||||||
|
│ │ └─⫸ Summary in present tense. Not capitalized. No period at the end.
|
||||||
|
│ │
|
||||||
|
│ └─⫸ Commit Scope: anything module
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
└─⫸ Commit Type: build|ci|docs|feat|fix|perf|refactor|test
|
||||||
|
```
|
||||||
|
|
||||||
|
The `<type>` and `<summary>` fields are mandatory, the `(<scope>)` field is optional.
|
||||||
|
|
||||||
|
### Type
|
||||||
|
|
||||||
|
Must be one of the following:
|
||||||
|
|
||||||
|
| Type | Description |
|
||||||
|
| ------------ | --------------------------------------------------------------------------------------------------- |
|
||||||
|
| **build** | Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm) |
|
||||||
|
| **ci** | Changes to our CI configuration files and scripts (examples: Github Actions, SauceLabs) |
|
||||||
|
| **docs** | Documentation only changes |
|
||||||
|
| **feat** | A new feature |
|
||||||
|
| **fix** | A bug fix |
|
||||||
|
| **perf** | A code change that improves performance |
|
||||||
|
| **refactor** | A code change that neither fixes a bug nor adds a feature |
|
||||||
|
| **test** | Adding missing tests or correcting existing tests |
|
||||||
|
|
||||||
|
### Scope
|
||||||
|
|
||||||
|
The scope should be the name of the module affected (as perceived by the person reading the changelog generated from commit messages).
|
||||||
|
|
||||||
|
There are currently a few exceptions to the "use package name" rule:
|
||||||
|
|
||||||
|
- `dev-infra`: used for dev-infra related changes within the directories /scripts and /tools
|
||||||
|
- `docs-infra`: used for infrastructure changes to the docs-app (angular.dev) within the `/adev` directory, such as application code, tooling, or configuration. **For modifications to documentation content (e.g., editing a `.md` file), use `docs:` without a scope instead.**
|
||||||
|
- `migrations`: used for changes to the `ng update` migrations.
|
||||||
|
- none/empty string: useful for `test` and `refactor` changes that are done across all packages (e.g. `test: add missing unit tests`) and for docs changes that are not related to a specific package (e.g. `docs: fix typo in tutorial`).
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
|
||||||
|
Use the summary field to provide a succinct description of the change:
|
||||||
|
|
||||||
|
- use the imperative, present tense: "change" not "changed" nor "changes"
|
||||||
|
- don't capitalize the first letter
|
||||||
|
- no dot (.) at the end
|
||||||
|
|
||||||
|
## Commit Message Body
|
||||||
|
|
||||||
|
Just as in the summary, use the imperative, present tense: "fix" not "fixed" nor "fixes".
|
||||||
|
|
||||||
|
Explain the motivation for the change in the commit message body. This commit message should explain _why_ you are making the change.
|
||||||
|
You can include a comparison of the previous behavior with the new behavior in order to illustrate the impact of the change.
|
||||||
|
|
||||||
|
## Commit Message Footer
|
||||||
|
|
||||||
|
The footer can contain information about breaking changes and deprecations and is also the place to reference GitHub issues and other PRs that this commit closes or is related to.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
BREAKING CHANGE: <breaking change summary>
|
||||||
|
<BLANK LINE>
|
||||||
|
<breaking change description + migration instructions>
|
||||||
|
<BLANK LINE>
|
||||||
|
<BLANK LINE>
|
||||||
|
Fixes #<issue number>
|
||||||
|
```
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
```
|
||||||
|
DEPRECATED: <what is deprecated>
|
||||||
|
<BLANK LINE>
|
||||||
|
<deprecation description + recommended update path>
|
||||||
|
<BLANK LINE>
|
||||||
|
<BLANK LINE>
|
||||||
|
Closes #<pr number>
|
||||||
|
```
|
||||||
|
|
||||||
|
Breaking Change section should start with the phrase `BREAKING CHANGE: ` followed by a _brief_ summary of the breaking change, a blank line, and a detailed description of the breaking change that also includes migration instructions.
|
||||||
|
|
||||||
|
Similarly, a Deprecation section should start with `DEPRECATED: ` followed by a short description of what is deprecated, a blank line, and a detailed description of the deprecation that also mentions the recommended update path.
|
||||||
|
|
||||||
|
## Revert commits
|
||||||
|
|
||||||
|
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit.
|
||||||
|
|
||||||
|
The content of the commit message body should contain:
|
||||||
|
|
||||||
|
- information about the SHA of the commit being reverted in the following format: `This reverts commit <SHA>`,
|
||||||
|
- a clear description of the reason for reverting the commit message.
|
||||||
|
|
||||||
|
## 在Body中最后一行添加`Co-Authored-By: AI`
|
||||||
|
|
||||||
|
# 尽可能的使用简体中文
|
||||||
|
|
||||||
+175
-82
@@ -6,18 +6,11 @@ import { TaskInDB, TaskStatus } from '../work/type'
|
|||||||
import { LoadingBox } from '../view'
|
import { LoadingBox } from '../view'
|
||||||
import { PlayerModalComp } from './playerModal'
|
import { PlayerModalComp } from './playerModal'
|
||||||
|
|
||||||
const { div, span } = van.tags
|
const { div, span, input, button } = van.tags
|
||||||
|
|
||||||
const { svg, path } = van.tags('http://www.w3.org/2000/svg')
|
const { svg, path } = van.tags('http://www.w3.org/2000/svg')
|
||||||
|
|
||||||
export class TaskRoute implements VanComponent {
|
type TaskItem = TaskInDB & {
|
||||||
element: HTMLElement
|
|
||||||
/** 包含视频播放器的模态框 */
|
|
||||||
playerModalComp = new PlayerModalComp()
|
|
||||||
|
|
||||||
loading = van.state(false)
|
|
||||||
|
|
||||||
taskList: State<(TaskInDB & {
|
|
||||||
/** 音频下载进度百分比 */
|
/** 音频下载进度百分比 */
|
||||||
audioProgress: State<number>
|
audioProgress: State<number>
|
||||||
/** 视频下载进度百分比 */
|
/** 视频下载进度百分比 */
|
||||||
@@ -30,10 +23,39 @@ export class TaskRoute implements VanComponent {
|
|||||||
opening: State<boolean>
|
opening: State<boolean>
|
||||||
/** 是否正在删除 */
|
/** 是否正在删除 */
|
||||||
deleting: State<boolean>
|
deleting: State<boolean>
|
||||||
})[]> = van.state([])
|
/** 是否选中 */
|
||||||
|
selected: State<boolean>
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TaskRoute implements VanComponent {
|
||||||
|
element: HTMLElement
|
||||||
|
/** 包含视频播放器的模态框 */
|
||||||
|
playerModalComp = new PlayerModalComp()
|
||||||
|
|
||||||
|
loading = van.state(false)
|
||||||
|
|
||||||
|
taskList: State<TaskItem[]> = van.state([])
|
||||||
|
|
||||||
|
/** 是否全选 */
|
||||||
|
allSelected = van.derive(() => {
|
||||||
|
const list = this.taskList.val.filter(t => !t.deleting.val)
|
||||||
|
return list.length > 0 && list.every(t => t.selected.val)
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 选中的任务数量 */
|
||||||
|
selectedCount = van.derive(() => this.taskList.val.filter(t => t.selected.val && !t.deleting.val).length)
|
||||||
|
|
||||||
|
/** 选中的可删除任务 */
|
||||||
|
selectedDeletable = van.derive(() => this.taskList.val.filter(t =>
|
||||||
|
t.selected.val && !t.deleting.val && (t.statusState.val == 'done' || t.statusState.val == 'error')
|
||||||
|
))
|
||||||
|
|
||||||
|
/** 选中的可取消任务 */
|
||||||
|
selectedCancellable = van.derive(() => this.taskList.val.filter(t =>
|
||||||
|
t.selected.val && !t.deleting.val && (t.statusState.val == 'waiting' || t.statusState.val == 'running')
|
||||||
|
))
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
||||||
this.element = this.Root()
|
this.element = this.Root()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,16 +66,143 @@ export class TaskRoute implements VanComponent {
|
|||||||
Loader() {
|
Loader() {
|
||||||
return div(
|
return div(
|
||||||
() => _that.loading.val ? LoadingBox() : '',
|
() => _that.loading.val ? LoadingBox() : '',
|
||||||
() => div({ class: 'list-group', hidden: _that.loading.val },
|
() => div({ class: 'vstack gap-3', hidden: _that.loading.val },
|
||||||
_that.taskList.val.map(task => {
|
// 批量操作工具栏
|
||||||
|
div({ class: 'hstack gap-2', hidden: () => _that.taskList.val.length == 0 },
|
||||||
|
input({
|
||||||
|
class: 'form-check-input',
|
||||||
|
type: 'checkbox',
|
||||||
|
checked: _that.allSelected,
|
||||||
|
onclick() {
|
||||||
|
const checked = !_that.allSelected.val
|
||||||
|
_that.taskList.val.forEach(t => {
|
||||||
|
if (!t.deleting.val) t.selected.val = checked
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
span({ class: 'text-secondary' }, () => `已选择 ${_that.selectedCount.val} 项`),
|
||||||
|
button({
|
||||||
|
class: 'btn btn-sm btn-outline-danger',
|
||||||
|
hidden: () => _that.selectedCancellable.val.length == 0,
|
||||||
|
onclick() {
|
||||||
|
if (!confirm(`确定要取消选中的 ${_that.selectedCancellable.val.length} 个任务吗?`)) return
|
||||||
|
_that.selectedCancellable.val.forEach(t => {
|
||||||
|
cancelTask(t.id).then(() => {
|
||||||
|
t.statusState.val = 'error'
|
||||||
|
t.selected.val = false
|
||||||
|
}).catch(error => {
|
||||||
|
alert(error.message)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, () => `批量取消 (${_that.selectedCancellable.val.length})`),
|
||||||
|
button({
|
||||||
|
class: 'btn btn-sm btn-outline-secondary',
|
||||||
|
hidden: () => _that.selectedDeletable.val.length == 0,
|
||||||
|
onclick() {
|
||||||
|
if (!confirm(`确定要删除选中的 ${_that.selectedDeletable.val.length} 个任务吗?`)) return
|
||||||
|
_that.selectedDeletable.val.forEach(t => {
|
||||||
|
t.deleting.val = true
|
||||||
|
deleteTask(t.id).then(() => {
|
||||||
|
_that.taskList.val = _that.taskList.val.filter(taskInDB => taskInDB.id != t.id)
|
||||||
|
}).catch(error => {
|
||||||
|
t.deleting.val = false
|
||||||
|
alert(error.message)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, () => `批量删除 (${_that.selectedDeletable.val.length})`),
|
||||||
|
),
|
||||||
|
// 任务列表
|
||||||
|
div({ class: 'list-group' },
|
||||||
|
_that.taskList.val.map(task => _that.TaskItem(task))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
async onFirst() {
|
||||||
|
if (!await checkLogin()) return
|
||||||
|
},
|
||||||
|
async onLoad() {
|
||||||
|
if (!GLOBAL_HAS_LOGIN.val) return goto('login')
|
||||||
|
_that.loading.val = true
|
||||||
|
|
||||||
|
getTaskList(0, 360).then(taskList => {
|
||||||
|
if (!taskList) return
|
||||||
|
_that.taskList.val = taskList.map(task => ({
|
||||||
|
...task,
|
||||||
|
audioProgress: van.state(1),
|
||||||
|
videoProgress: van.state(1),
|
||||||
|
mergeProgress: van.state(1),
|
||||||
|
statusState: van.state(task.status),
|
||||||
|
opening: van.state(false),
|
||||||
|
deleting: van.state(false),
|
||||||
|
selected: van.state(false)
|
||||||
|
}))
|
||||||
|
|
||||||
|
const refresh = async () => {
|
||||||
|
const activeTaskList = await getActiveTask()
|
||||||
|
if (!activeTaskList) return false
|
||||||
|
setTimeout(() => {
|
||||||
|
_that.loading.val = false
|
||||||
|
}, 200)
|
||||||
|
|
||||||
|
_that.taskList.val.forEach(taskInDB => {
|
||||||
|
activeTaskList.forEach(task => {
|
||||||
|
if (taskInDB.id == task.id) {
|
||||||
|
taskInDB.audioProgress.val = task.audioProgress
|
||||||
|
taskInDB.videoProgress.val = task.videoProgress
|
||||||
|
taskInDB.mergeProgress.val = task.mergeProgress
|
||||||
|
taskInDB.statusState.val = task.status
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if (activeTaskList.filter(task => task.status == 'running').length == 0) {
|
||||||
|
clearInterval(timer)
|
||||||
|
clearInterval(helper)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh()
|
||||||
|
|
||||||
|
let timer = setInterval(() => {
|
||||||
|
refresh()
|
||||||
|
}, 1000)
|
||||||
|
let helper = setInterval(() => {
|
||||||
|
if (now.val.split('/')[0] != 'task') {
|
||||||
|
clearInterval(helper)
|
||||||
|
clearInterval(timer)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskItem(task: TaskItem) {
|
||||||
|
const _that = this
|
||||||
const ext = task.downloadType === 'audio' ? '.m4a' : '.mp4'
|
const ext = task.downloadType === 'audio' ? '.m4a' : '.mp4'
|
||||||
const filename = `${task.title} ${btoa(task.id.toString()).replace(/=/g, '')}${ext}`
|
const filename = `${task.title} ${btoa(task.id.toString()).replace(/=/g, '')}${ext}`
|
||||||
|
|
||||||
return div({
|
return div({
|
||||||
class: () => `list-group-item p-0 hstack user-select-none ${task.statusState.val != 'done' && task.statusState.val != 'error' || task.opening.val ? 'disabled' : ''}`,
|
class: () => `list-group-item p-0 hstack user-select-none ${task.statusState.val != 'done' && task.statusState.val != 'error' || task.opening.val ? 'disabled' : ''}`,
|
||||||
hidden: task.deleting,
|
hidden: task.deleting,
|
||||||
},
|
},
|
||||||
|
// 复选框
|
||||||
|
div({ class: 'px-3' },
|
||||||
|
input({
|
||||||
|
class: 'form-check-input',
|
||||||
|
type: 'checkbox',
|
||||||
|
checked: task.selected,
|
||||||
|
onclick(event: Event) {
|
||||||
|
event.stopPropagation()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
),
|
||||||
|
// 任务内容
|
||||||
div({
|
div({
|
||||||
class: 'vstack gap-2 py-2 px-3',
|
class: 'vstack gap-2 py-2 px-2 flex-fill',
|
||||||
style: `cursor: pointer;`,
|
style: `cursor: pointer;`,
|
||||||
onclick() {
|
onclick() {
|
||||||
const src = `/api/downloadVideo?path=${encodeURIComponent(
|
const src = `/api/downloadVideo?path=${encodeURIComponent(
|
||||||
@@ -116,15 +265,17 @@ export class TaskRoute implements VanComponent {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
// 操作按钮
|
||||||
div({
|
div({
|
||||||
class: 'me-4',
|
class: 'me-4',
|
||||||
hidden: task.statusState.val != 'done'
|
hidden: task.statusState.val != 'done'
|
||||||
|| task.opening.val // 正在打开文件位置时,不应该显示删除按钮
|
|| task.opening.val
|
||||||
|| task.deleting.val // 正在删除时,不应该显示删除按钮
|
|| task.deleting.val
|
||||||
},
|
},
|
||||||
div({
|
div({
|
||||||
class: 'hover-btn', title: '打开文件位置',
|
class: 'hover-btn', title: '打开文件位置',
|
||||||
onclick() {
|
onclick(event: Event) {
|
||||||
|
event.stopPropagation()
|
||||||
showFile(`${task.folder}\\${filename}`)
|
showFile(`${task.folder}\\${filename}`)
|
||||||
task.opening.val = true
|
task.opening.val = true
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -139,16 +290,18 @@ export class TaskRoute implements VanComponent {
|
|||||||
class: 'me-4',
|
class: 'me-4',
|
||||||
hidden: task.statusState.val != 'done'
|
hidden: task.statusState.val != 'done'
|
||||||
&& task.statusState.val != 'error'
|
&& task.statusState.val != 'error'
|
||||||
|| task.opening.val // 正在打开文件位置时,不应该显示删除按钮
|
|| task.opening.val
|
||||||
|| task.deleting.val // 正在删除时,不应该显示删除按钮
|
|| task.deleting.val
|
||||||
},
|
},
|
||||||
div({
|
div({
|
||||||
class: 'hover-btn', title: '删除视频',
|
class: 'hover-btn', title: '删除视频',
|
||||||
onclick() {
|
onclick(event: Event) {
|
||||||
|
event.stopPropagation()
|
||||||
task.deleting.val = true
|
task.deleting.val = true
|
||||||
deleteTask(task.id).then(() => {
|
deleteTask(task.id).then(() => {
|
||||||
_that.taskList.val = _that.taskList.val.filter(taskInDB => taskInDB.id != task.id)
|
_that.taskList.val = _that.taskList.val.filter(taskInDB => taskInDB.id != task.id)
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
task.deleting.val = false
|
||||||
alert(error.message)
|
alert(error.message)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -162,7 +315,8 @@ export class TaskRoute implements VanComponent {
|
|||||||
},
|
},
|
||||||
div({
|
div({
|
||||||
class: 'hover-btn text-danger', title: '取消任务',
|
class: 'hover-btn text-danger', title: '取消任务',
|
||||||
onclick() {
|
onclick(event: Event) {
|
||||||
|
event.stopPropagation()
|
||||||
if (!confirm('确定要取消该任务吗?')) return
|
if (!confirm('确定要取消该任务吗?')) return
|
||||||
cancelTask(task.id).then(() => {
|
cancelTask(task.id).then(() => {
|
||||||
task.statusState.val = 'error'
|
task.statusState.val = 'error'
|
||||||
@@ -175,67 +329,6 @@ export class TaskRoute implements VanComponent {
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
})
|
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
async onFirst() {
|
|
||||||
if (!await checkLogin()) return
|
|
||||||
},
|
|
||||||
async onLoad() {
|
|
||||||
if (!GLOBAL_HAS_LOGIN.val) return goto('login')
|
|
||||||
_that.loading.val = true
|
|
||||||
|
|
||||||
getTaskList(0, 360).then(taskList => {
|
|
||||||
if (!taskList) return
|
|
||||||
_that.taskList.val = taskList.map(task => ({
|
|
||||||
...task,
|
|
||||||
audioProgress: van.state(1),
|
|
||||||
videoProgress: van.state(1),
|
|
||||||
mergeProgress: van.state(1),
|
|
||||||
statusState: van.state(task.status),
|
|
||||||
opening: van.state(false),
|
|
||||||
deleting: van.state(false)
|
|
||||||
}))
|
|
||||||
|
|
||||||
const refresh = async () => {
|
|
||||||
const activeTaskList = await getActiveTask()
|
|
||||||
if (!activeTaskList) return false
|
|
||||||
setTimeout(() => {
|
|
||||||
_that.loading.val = false
|
|
||||||
}, 200)
|
|
||||||
|
|
||||||
_that.taskList.val.forEach(taskInDB => {
|
|
||||||
activeTaskList.forEach(task => {
|
|
||||||
if (taskInDB.id == task.id) {
|
|
||||||
taskInDB.audioProgress.val = task.audioProgress
|
|
||||||
taskInDB.videoProgress.val = task.videoProgress
|
|
||||||
taskInDB.mergeProgress.val = task.mergeProgress
|
|
||||||
taskInDB.statusState.val = task.status
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
if (activeTaskList.filter(task => task.status == 'running').length == 0) {
|
|
||||||
clearInterval(timer)
|
|
||||||
clearInterval(helper)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
refresh()
|
|
||||||
|
|
||||||
let timer = setInterval(() => {
|
|
||||||
refresh()
|
|
||||||
}, 1000)
|
|
||||||
let helper = setInterval(() => {
|
|
||||||
if (now.val.split('/')[0] != 'task') {
|
|
||||||
clearInterval(helper)
|
|
||||||
clearInterval(timer)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DeleteSVG() {
|
DeleteSVG() {
|
||||||
|
|||||||
Reference in New Issue
Block a user