update: 添加扩容UI

This commit is contained in:
Kerwin
2025-09-12 18:06:09 +08:00
parent eeeb2aefbb
commit 2a5bf19e7d
12 changed files with 802 additions and 12 deletions

View File

@@ -23,6 +23,7 @@ type TaskType string
const (
TaskTypeBatchTransfer TaskType = "batch_transfer" // 批量转存
TaskTypeExpansion TaskType = "expansion" // 账号扩容
)
// Task 任务表

View File

@@ -58,7 +58,7 @@ func (r *TaskRepositoryImpl) GetList(page, pageSize int, taskType, status string
// 添加过滤条件
if taskType != "" {
query = query.Where("task_type = ?", taskType)
query = query.Where("type = ?", taskType)
}
if status != "" {
query = query.Where("status = ?", status)

View File

@@ -2,6 +2,7 @@ package handlers
import (
"encoding/json"
"fmt"
"net/http"
"strconv"
@@ -387,3 +388,149 @@ func (h *TaskHandler) DeleteTask(c *gin.Context) {
"message": "任务删除成功",
})
}
// CreateExpansionTask 创建扩容任务
func (h *TaskHandler) CreateExpansionTask(c *gin.Context) {
var req struct {
PanAccountID uint `json:"pan_account_id" binding:"required"`
Description string `json:"description"`
}
if err := c.ShouldBindJSON(&req); err != nil {
ErrorResponse(c, "参数错误: "+err.Error(), http.StatusBadRequest)
return
}
utils.Debug("创建扩容任务: 账号ID %d", req.PanAccountID)
// 获取账号信息,用于构建任务标题
cks, err := h.repoMgr.CksRepository.FindByID(req.PanAccountID)
if err != nil {
utils.Error("获取账号信息失败: %v", err)
ErrorResponse(c, "获取账号信息失败: "+err.Error(), http.StatusInternalServerError)
return
}
// 构建账号名称
accountName := cks.Username
if accountName == "" {
accountName = cks.Remark
}
if accountName == "" {
accountName = fmt.Sprintf("账号%d", cks.ID)
}
// 构建任务配置存储账号ID
taskConfig := map[string]interface{}{
"pan_account_id": req.PanAccountID,
}
configJSON, _ := json.Marshal(taskConfig)
// 创建任务标题,包含账号名称
taskTitle := fmt.Sprintf("账号扩容 - %s", accountName)
// 创建任务
newTask := &entity.Task{
Title: taskTitle,
Description: req.Description,
Type: "expansion",
Status: "pending",
TotalItems: 1, // 扩容任务只有一个项目
Config: string(configJSON),
CreatedAt: utils.GetCurrentTime(),
UpdatedAt: utils.GetCurrentTime(),
}
if err := h.repoMgr.TaskRepository.Create(newTask); err != nil {
utils.Error("创建扩容任务失败: %v", err)
ErrorResponse(c, "创建任务失败: "+err.Error(), http.StatusInternalServerError)
return
}
// 创建任务项
expansionInput := task.ExpansionInput{
PanAccountID: req.PanAccountID,
}
inputJSON, _ := json.Marshal(expansionInput)
taskItem := &entity.TaskItem{
TaskID: newTask.ID,
Status: "pending",
InputData: string(inputJSON),
CreatedAt: utils.GetCurrentTime(),
UpdatedAt: utils.GetCurrentTime(),
}
err = h.repoMgr.TaskItemRepository.Create(taskItem)
if err != nil {
utils.Error("创建扩容任务项失败: %v", err)
// 继续处理,不返回错误
}
utils.Debug("扩容任务创建完成: %d", newTask.ID)
SuccessResponse(c, gin.H{
"task_id": newTask.ID,
"total_items": 1,
"message": "扩容任务创建成功",
})
}
// GetExpansionAccounts 获取支持扩容的账号列表
func (h *TaskHandler) GetExpansionAccounts(c *gin.Context) {
// 获取所有有效的账号
cksList, err := h.repoMgr.CksRepository.FindByIsValid(false)
if err != nil {
utils.Error("获取账号列表失败: %v", err)
ErrorResponse(c, "获取账号列表失败: "+err.Error(), http.StatusInternalServerError)
return
}
// 过滤出 quark 账号
var expansionAccounts []gin.H
tasks, _, _ := h.repoMgr.TaskRepository.GetList(1, 1000, "expansion", "completed")
for _, ck := range cksList {
if ck.ServiceType == "quark" {
// 使用 Username 作为账号名称,如果为空则使用 Remark
accountName := ck.Username
if accountName == "" {
accountName = ck.Remark
}
if accountName == "" {
accountName = "账号 " + fmt.Sprintf("%d", ck.ID)
}
// 检查是否已经扩容过
expanded := false
for _, task := range tasks {
if task.Config != "" {
var taskConfig map[string]interface{}
if err := json.Unmarshal([]byte(task.Config), &taskConfig); err == nil {
if configAccountID, ok := taskConfig["pan_account_id"].(float64); ok {
if uint(configAccountID) == ck.ID {
expanded = true
break
}
}
}
}
}
expansionAccounts = append(expansionAccounts, gin.H{
"id": ck.ID,
"name": accountName,
"service_type": ck.ServiceType,
"expanded": expanded,
"created_at": ck.CreatedAt,
"updated_at": ck.UpdatedAt,
})
}
}
SuccessResponse(c, gin.H{
"accounts": expansionAccounts,
"total": len(expansionAccounts),
"message": "获取支持扩容账号列表成功",
})
}

View File

@@ -92,6 +92,10 @@ func main() {
transferProcessor := task.NewTransferProcessor(repoManager)
taskManager.RegisterProcessor(transferProcessor)
// 注册扩容任务处理器
expansionProcessor := task.NewExpansionProcessor(repoManager)
taskManager.RegisterProcessor(expansionProcessor)
// 初始化Meilisearch管理器
meilisearchManager := services.NewMeilisearchManager(repoManager)
if err := meilisearchManager.Initialize(); err != nil {
@@ -285,6 +289,8 @@ func main() {
// 任务管理路由
api.POST("/tasks/transfer", middleware.AuthMiddleware(), middleware.AdminMiddleware(), taskHandler.CreateBatchTransferTask)
api.POST("/tasks/expansion", middleware.AuthMiddleware(), middleware.AdminMiddleware(), taskHandler.CreateExpansionTask)
api.GET("/tasks/expansion/accounts", middleware.AuthMiddleware(), middleware.AdminMiddleware(), taskHandler.GetExpansionAccounts)
api.GET("/tasks", middleware.AuthMiddleware(), middleware.AdminMiddleware(), taskHandler.GetTasks)
api.GET("/tasks/:id", middleware.AuthMiddleware(), middleware.AdminMiddleware(), taskHandler.GetTaskStatus)
api.POST("/tasks/:id/start", middleware.AuthMiddleware(), middleware.AdminMiddleware(), taskHandler.StartTask)

190
task/expansion_processor.go Normal file
View File

@@ -0,0 +1,190 @@
package task
import (
"context"
"encoding/json"
"fmt"
"github.com/ctwj/urldb/db/entity"
"github.com/ctwj/urldb/db/repo"
"github.com/ctwj/urldb/utils"
)
// ExpansionProcessor 扩容任务处理器
type ExpansionProcessor struct {
repoMgr *repo.RepositoryManager
}
// NewExpansionProcessor 创建扩容任务处理器
func NewExpansionProcessor(repoMgr *repo.RepositoryManager) *ExpansionProcessor {
return &ExpansionProcessor{
repoMgr: repoMgr,
}
}
// GetTaskType 获取任务类型
func (ep *ExpansionProcessor) GetTaskType() string {
return "expansion"
}
// ExpansionInput 扩容任务输入数据结构
type ExpansionInput struct {
PanAccountID uint `json:"pan_account_id"`
}
// ExpansionOutput 扩容任务输出数据结构
type ExpansionOutput struct {
Success bool `json:"success"`
Message string `json:"message"`
Error string `json:"error,omitempty"`
Time string `json:"time"`
}
// Process 处理扩容任务项
func (ep *ExpansionProcessor) Process(ctx context.Context, taskID uint, item *entity.TaskItem) error {
utils.Info("开始处理扩容任务项: %d", item.ID)
// 解析输入数据
var input ExpansionInput
if err := json.Unmarshal([]byte(item.InputData), &input); err != nil {
return fmt.Errorf("解析输入数据失败: %v", err)
}
// 验证输入数据
if err := ep.validateInput(&input); err != nil {
return fmt.Errorf("输入数据验证失败: %v", err)
}
// 检查账号是否已经扩容过
exists, err := ep.checkExpansionExists(input.PanAccountID)
if err != nil {
utils.Error("检查扩容记录失败: %v", err)
return fmt.Errorf("检查扩容记录失败: %v", err)
}
if exists {
output := ExpansionOutput{
Success: false,
Message: "账号已扩容过",
Error: "每个账号只能扩容一次",
Time: utils.GetCurrentTimeString(),
}
outputJSON, _ := json.Marshal(output)
item.OutputData = string(outputJSON)
utils.Info("账号已扩容过,跳过扩容: 账号ID %d", input.PanAccountID)
return fmt.Errorf("账号已扩容过")
}
// 检查账号类型只支持quark账号
if err := ep.checkAccountType(input.PanAccountID); err != nil {
output := ExpansionOutput{
Success: false,
Message: "账号类型不支持扩容",
Error: err.Error(),
Time: utils.GetCurrentTimeString(),
}
outputJSON, _ := json.Marshal(output)
item.OutputData = string(outputJSON)
utils.Error("账号类型不支持扩容: %v", err)
return err
}
// 执行扩容操作(这里留空,直接返回成功)
if err := ep.performExpansion(ctx, input.PanAccountID); err != nil {
output := ExpansionOutput{
Success: false,
Message: "扩容失败",
Error: err.Error(),
Time: utils.GetCurrentTimeString(),
}
outputJSON, _ := json.Marshal(output)
item.OutputData = string(outputJSON)
utils.Error("扩容任务项处理失败: %d, 错误: %v", item.ID, err)
return fmt.Errorf("扩容失败: %v", err)
}
// 扩容成功
output := ExpansionOutput{
Success: true,
Message: "扩容成功",
Time: utils.GetCurrentTimeString(),
}
outputJSON, _ := json.Marshal(output)
item.OutputData = string(outputJSON)
utils.Info("扩容任务项处理完成: %d, 账号ID: %d", item.ID, input.PanAccountID)
return nil
}
// validateInput 验证输入数据
func (ep *ExpansionProcessor) validateInput(input *ExpansionInput) error {
if input.PanAccountID == 0 {
return fmt.Errorf("账号ID不能为空")
}
return nil
}
// checkExpansionExists 检查账号是否已经扩容过
func (ep *ExpansionProcessor) checkExpansionExists(panAccountID uint) (bool, error) {
// 查询所有expansion类型的任务
tasks, _, err := ep.repoMgr.TaskRepository.GetList(1, 1000, "expansion", "completed")
if err != nil {
return false, fmt.Errorf("获取扩容任务列表失败: %v", err)
}
// 检查每个任务的配置中是否包含该账号ID
for _, task := range tasks {
if task.Config != "" {
var taskConfig map[string]interface{}
if err := json.Unmarshal([]byte(task.Config), &taskConfig); err == nil {
if configAccountID, ok := taskConfig["pan_account_id"].(float64); ok {
if uint(configAccountID) == panAccountID {
// 找到了该账号的扩容任务,检查任务状态
if task.Status == "completed" {
// 如果任务已完成,说明已经扩容过
return true, nil
}
}
}
}
}
}
return false, nil
}
// checkAccountType 检查账号类型只支持quark账号
func (ep *ExpansionProcessor) checkAccountType(panAccountID uint) error {
// 获取账号信息
cks, err := ep.repoMgr.CksRepository.FindByID(panAccountID)
if err != nil {
return fmt.Errorf("获取账号信息失败: %v", err)
}
// 检查是否为quark账号
if cks.ServiceType != "quark" {
return fmt.Errorf("只支持quark账号扩容当前账号类型: %s", cks.ServiceType)
}
return nil
}
// performExpansion 执行扩容操作
func (ep *ExpansionProcessor) performExpansion(ctx context.Context, panAccountID uint) error {
// 扩容逻辑暂时留空,直接返回成功
// TODO: 实现具体的扩容逻辑
utils.Info("执行扩容操作账号ID: %d", panAccountID)
// 模拟扩容操作延迟
// time.Sleep(2 * time.Second)
return nil
}

4
web/components.d.ts vendored
View File

@@ -15,11 +15,15 @@ declare module 'vue' {
NButtonGroup: typeof import('naive-ui')['NButtonGroup']
NCard: typeof import('naive-ui')['NCard']
NCheckbox: typeof import('naive-ui')['NCheckbox']
NCollapse: typeof import('naive-ui')['NCollapse']
NCollapseItem: typeof import('naive-ui')['NCollapseItem']
NDataTable: typeof import('naive-ui')['NDataTable']
NDatePicker: typeof import('naive-ui')['NDatePicker']
NDescriptions: typeof import('naive-ui')['NDescriptions']
NDescriptionsItem: typeof import('naive-ui')['NDescriptionsItem']
NDialogProvider: typeof import('naive-ui')['NDialogProvider']
NDrawer: typeof import('naive-ui')['NDrawer']
NDrawerContent: typeof import('naive-ui')['NDrawerContent']
NEmpty: typeof import('naive-ui')['NEmpty']
NForm: typeof import('naive-ui')['NForm']
NFormItem: typeof import('naive-ui')['NFormItem']

View File

@@ -244,6 +244,8 @@ export const usePublicSystemConfigApi = () => {
// 任务管理API
export const useTaskApi = () => {
const createBatchTransferTask = (data: any) => useApiFetch('/tasks/transfer', { method: 'POST', body: data }).then(parseApiResponse)
const createExpansionTask = (data: any) => useApiFetch('/tasks/expansion', { method: 'POST', body: data }).then(parseApiResponse)
const getExpansionAccounts = () => useApiFetch('/tasks/expansion/accounts').then(parseApiResponse)
const getTasks = (params?: any) => useApiFetch('/tasks', { params }).then(parseApiResponse)
const getTaskStatus = (id: number) => useApiFetch(`/tasks/${id}`).then(parseApiResponse)
const startTask = (id: number) => useApiFetch(`/tasks/${id}/start`, { method: 'POST' }).then(parseApiResponse)
@@ -251,7 +253,7 @@ export const useTaskApi = () => {
const pauseTask = (id: number) => useApiFetch(`/tasks/${id}/pause`, { method: 'POST' }).then(parseApiResponse)
const deleteTask = (id: number) => useApiFetch(`/tasks/${id}`, { method: 'DELETE' }).then(parseApiResponse)
const getTaskItems = (id: number, params?: any) => useApiFetch(`/tasks/${id}/items`, { params }).then(parseApiResponse)
return { createBatchTransferTask, getTasks, getTaskStatus, startTask, stopTask, pauseTask, deleteTask, getTaskItems }
return { createBatchTransferTask, createExpansionTask, getExpansionAccounts, getTasks, getTaskStatus, startTask, stopTask, pauseTask, deleteTask, getTaskItems }
}
// 日志函数:只在开发环境打印

View File

@@ -0,0 +1,427 @@
<template>
<div class="max-w-7xl mx-auto space-y-6">
<!-- 页面标题 -->
<div class="flex items-center justify-between">
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">账号扩容管理</h1>
<p class="text-gray-600 dark:text-gray-400">管理账号扩容任务和状态</p>
</div>
<!-- 提示信息 -->
<n-alert type="info" :show-icon="false">
<div class="flex items-center space-x-2">
<i class="fas fa-info-circle text-blue-500"></i>
<span class="text-sm">
<strong>20T扩容说明</strong>建议 <span @click="showImageModal = true" style="color:red" class="cursor-pointer">蜂小推</span> quark 账号扩容<span @click="drawActive = true" style="color:blue" class="cursor-pointer">什么推荐蜂小推</span><br>
1. 20T扩容 只支持新号等到蜂小推首次 6T 奖励 到账后进行扩容<br>
2. 账号需要处于关闭状态 开启状态可能会被用于自动转存等任务存咋影响<br>
3. <strong><n-text type="error">扩容完成后并不直接获得容量</n-text>账号将存储大量热门资源<n-text type="error">需要手动推广</n-text></strong><br>
4. 注意 推广获得20T容量删除所有资源 热门资源比较敏感不建议长期推广仅用于扩容
</span>
</div>
</n-alert>
<n-drawer v-model:show="drawActive" :width="502" closable placement="right">
<n-drawer-content title="扩容说明">
<div class="space-y-6 p-4">
<div class="mb-4">
<p class="text-gray-700 text-large dark:text-gray-300 leading-relaxed">
扩容是网盘公司提供给推广用户的<n-text type="success">特权</n-text>需要先注册推广平台并<n-text type="success">达标</n-text>即可获得权益
</p>
</div>
<n-collapse arrow-placement="right">
<n-collapse-item title="达标要求" name="0">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-3 flex items-center">
<i class="fas fa-list-check text-blue-500 mr-2"></i>
达标要求以蜂小推为例
</h3>
<span>首次账号累计7天转存 > 10 拉新 > 5</span>
</n-collapse-item>
<n-collapse-item title="注意事项" name="1">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-3 flex items-center">
<i class="fas fa-exclamation-triangle text-orange-500 mr-2"></i>
注意事项
</h3>
<span>每个人的转存只有当日第一次转存且通过手机转存才算有效转存</span>
</n-collapse-item>
<n-collapse-item title="扩容原理" name="2">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-3 flex items-center">
<i class="fas fa-question-circle text-purple-500 mr-2"></i>
扩容原理
</h3>
<span>大量转存热播资源这样才能尽可能快的达标</span>
</n-collapse-item>
<n-collapse-item title="为什么推荐蜂小推" name="3">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-3 flex items-center">
<i class="fas fa-thumbs-up text-green-500 mr-2"></i>
为什么推荐蜂小推
</h3>
<p class="text-gray-600 dark:text-gray-400 leading-relaxed">
登记后第二天即会发送 <strong class="text-blue-600">6T 空间</strong>满足大量存储资源的前提条件
</p>
</n-collapse-item>
<n-collapse-item title="蜂小推怎么注册" name="3">
<p class="text-gray-600 dark:text-gray-400">
请扫描下方二维码进行注册
</p>
<div class="mt-3 p-4 bg-gray-100 dark:bg-gray-800 rounded-lg text-center">
<n-qr-code :value="qrCode" />
</div>
</n-collapse-item>
</n-collapse>
</div>
</n-drawer-content>
</n-drawer>
<!-- 图片模态框 -->
<n-modal v-model:show="showImageModal" title="蜂小推" size="huge">
<div class="text-center">
<img src="/assets/images/fxt.jpg" alt="蜂小推" class="max-w-full max-h-screen object-contain rounded-lg shadow-lg" />
</div>
</n-modal>
<!-- 账号列表 -->
<n-card>
<template #header>
<div class="flex items-center justify-between">
<span class="text-lg font-semibold">支持扩容的账号列表</span>
<div class="text-sm text-gray-500">
{{ expansionAccounts.length }} 个账号
</div>
</div>
</template>
<!-- 加载状态 -->
<div v-if="loading" class="flex items-center justify-center py-12">
<n-spin size="large">
<template #description>
<span class="text-gray-500">加载中...</span>
</template>
</n-spin>
</div>
<!-- 空状态 -->
<div v-else-if="expansionAccounts.length === 0" class="flex flex-col items-center justify-center py-12">
<n-empty description="暂无可扩容的账号,请先添加有效的 quark 账号">
<template #icon>
<i class="fas fa-user-circle text-4xl text-gray-400"></i>
</template>
</n-empty>
</div>
<!-- 账号列表 -->
<div v-else>
<n-virtual-list :items="expansionAccounts" :item-size="80" style="max-height: 500px">
<template #default="{ item }">
<div class="border-b border-gray-200 dark:border-gray-700 p-4 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors">
<div class="flex items-center justify-between">
<!-- 左侧信息 -->
<div class="flex-1 min-w-0">
<div class="flex items-center space-x-4">
<!-- 平台图标 -->
<span v-html="getPlatformIcon(item.service_type === 'quark' ? '夸克网盘' : '其他')" class="text-lg"></span>
<!-- 账号信息 -->
<div class="flex-1 min-w-0">
<h3 class="text-sm font-medium text-gray-900 dark:text-gray-100 line-clamp-1">
{{ item.name }}
</h3>
<p class="text-xs text-gray-500">
{{ item.service_type === 'quark' ? '夸克网盘' : '其他平台' }}
</p>
</div>
<!-- 扩容状态 -->
<div class="flex items-center space-x-2">
<n-tag v-if="item.expanded" type="success" size="small">
已扩容
</n-tag>
<n-tag v-else type="warning" size="small">
可扩容
</n-tag>
</div>
</div>
<!-- 创建时间 -->
<div class="mt-2">
<span class="text-xs text-gray-600 dark:text-gray-400">
创建时间: {{ formatDate(item.created_at) }}
</span>
</div>
</div>
<!-- 右侧操作按钮 -->
<div class="flex items-center space-x-2 ml-4">
<n-button
size="small"
type="primary"
:disabled="item.expanded"
:loading="expandingAccountId === item.id"
@click="handleExpansion(item)"
>
<template #icon>
<i class="fas fa-expand"></i>
</template>
{{ item.expanded ? '已扩容' : '扩容' }}
</n-button>
</div>
</div>
</div>
</template>
</n-virtual-list>
</div>
</n-card>
<!-- 扩容任务列表 -->
<n-card v-if="expansionTasks.length > 0" title="扩容任务列表">
<n-data-table
:columns="taskColumns"
:data="expansionTasks"
:pagination="false"
max-height="400"
size="small"
/>
</n-card>
</div>
</template>
<script setup lang="ts">
definePageMeta({
layout: 'admin',
middleware: ['auth']
})
import { ref, onMounted, computed, h } from 'vue'
import { useTaskApi } from '~/composables/useApi'
import { useNotification, useDialog } from 'naive-ui'
// 响应式数据
const expansionAccounts = ref([])
const expansionTasks = ref([])
const loading = ref(true)
const expandingAccountId = ref(null)
const drawActive = ref(false) // 侧边栏激活
const qrCode = ref("https://app.fengtuiwl.com/#/pages/login/reg?p=22112503")
const showImageModal = ref(false) // 图片模态框
// API实例
const taskApi = useTaskApi()
const notification = useNotification()
// 表格列配置
const taskColumns = [
{
title: '任务ID',
key: 'id',
width: 80
},
{
title: '标题',
key: 'title',
ellipsis: {
tooltip: true
}
},
{
title: '状态',
key: 'status',
width: 100,
render: (row: any) => {
const statusMap = {
pending: { color: 'warning', text: '等待中', icon: 'fas fa-clock' },
running: { color: 'info', text: '运行中', icon: 'fas fa-spinner fa-spin' },
completed: { color: 'success', text: '已完成', icon: 'fas fa-check' },
failed: { color: 'error', text: '失败', icon: 'fas fa-times' }
}
const status = statusMap[row.status as keyof typeof statusMap] || statusMap.failed
return h('n-tag', { type: status.color }, {
icon: () => h('i', { class: status.icon }),
default: () => status.text
})
}
},
{
title: '创建时间',
key: 'created_at',
width: 150,
render: (row: any) => formatDate(row.created_at)
},
{
title: '操作',
key: 'actions',
width: 150,
render: (row: any) => h('div', { class: 'flex space-x-2' }, [
h('n-button', {
size: 'small',
type: 'primary',
onClick: () => viewTaskDetails(row.id)
}, '详情'),
row.status === 'running' ? h('n-button', {
size: 'small',
type: 'warning',
onClick: () => stopTask(row.id)
}, '停止') : null
].filter(Boolean))
}
]
// 获取支持扩容的账号列表
const fetchExpansionAccounts = async () => {
loading.value = true
try {
const response = await taskApi.getExpansionAccounts()
expansionAccounts.value = response.accounts || []
} catch (error) {
console.error('获取扩容账号列表失败:', error)
notification.error({
title: '失败',
content: '获取扩容账号列表失败',
duration: 3000
})
} finally {
loading.value = false
}
}
// 获取扩容任务列表
const fetchExpansionTasks = async () => {
try {
const response = await taskApi.getTasks({ taskType: 'expansion' })
expansionTasks.value = response.tasks || []
} catch (error) {
console.error('获取扩容任务列表失败:', error)
}
}
// 处理扩容操作
const handleExpansion = async (account) => {
const dialog = useDialog()
dialog.warning({
title: '确认扩容',
content: `确定要对账号 "${account.name}" 进行扩容操作吗?`,
positiveText: '确定',
negativeText: '取消',
draggable: true,
onPositiveClick: async () => {
expandingAccountId.value = account.id
try {
const response = await taskApi.createExpansionTask({
pan_account_id: account.id,
description: `${account.name} 账号进行扩容操作`
})
// 启动任务
await taskApi.startTask(response.task_id)
notification.success({
title: '成功',
content: '扩容任务已创建并启动',
duration: 3000
})
// 刷新数据
await Promise.all([
fetchExpansionAccounts(),
fetchExpansionTasks()
])
} catch (error) {
console.error('创建扩容任务失败:', error)
notification.error({
title: '失败',
content: '创建扩容任务失败: ' + (error.message || '未知错误'),
duration: 3000
})
} finally {
expandingAccountId.value = null
}
}
})
}
// 查看任务详情
const viewTaskDetails = async (taskId) => {
try {
const status = await taskApi.getTaskStatus(taskId)
console.log('任务详情:', status)
// 这里可以展示任务详情的模态框
notification.info({
title: '任务详情',
content: `任务状态: ${status.status}, 总项目数: ${status.total_items}`,
duration: 5000
})
} catch (error) {
console.error('获取任务详情失败:', error)
}
}
// 停止任务
const stopTask = async (taskId) => {
const dialog = useDialog()
dialog.warning({
title: '确认停止',
content: '确定要停止这个扩容任务吗?',
positiveText: '确定',
negativeText: '取消',
onPositiveClick: async () => {
try {
await taskApi.stopTask(taskId)
notification.success({
title: '成功',
content: '任务已停止',
duration: 3000
})
await fetchExpansionTasks()
} catch (error) {
console.error('停止任务失败:', error)
notification.error({
title: '失败',
content: '停止任务失败',
duration: 3000
})
}
}
})
}
// 获取平台图标
const getPlatformIcon = (platformName) => {
const defaultIcons = {
'夸克网盘': '<i class="fas fa-cloud text-blue-600"></i>',
'其他': '<i class="fas fa-cloud text-gray-500"></i>'
}
return defaultIcons[platformName] || defaultIcons['其他']
}
// 格式化日期
const formatDate = (dateString) => {
if (!dateString) return '-'
const date = new Date(dateString)
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
})
}
// 页面加载
onMounted(async () => {
await Promise.all([
fetchExpansionAccounts(),
fetchExpansionTasks()
])
})
</script>
<style scoped>
.line-clamp-1 {
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
</style>

View File

@@ -13,6 +13,12 @@
</template>
添加账号
</n-button>
<n-button @click="goToExpansionManagement" type="warning">
<template #icon>
<i class="fas fa-expand"></i>
</template>
账号扩容
</n-button>
<n-button @click="refreshData" type="info">
<template #icon>
<i class="fas fa-refresh"></i>
@@ -623,6 +629,11 @@ const goToPage = (page) => {
currentPage.value = page
}
// 跳转到扩容管理页面
const goToExpansionManagement = () => {
router.push('/admin/accounts-expansion')
}
// 页面加载
onMounted(async () => {
try {

View File

@@ -78,6 +78,7 @@
import { ref, onMounted, computed, h } from 'vue'
import { NButton } from 'naive-ui'
import { useTaskStore } from '~/stores/task'
import { useTaskApi } from '~/composables/useApi'
import { useMessage, useDialog } from 'naive-ui'
// 任务状态管理
@@ -107,7 +108,8 @@ const statusOptions = [
// 类型选项
const typeOptions = [
{ label: '转存任务', value: 'transfer' }
{ label: '转存任务', value: 'transfer' },
{ label: '扩容任务', value: 'expansion' }
]
// 分页配置
@@ -158,15 +160,16 @@ const taskColumns = [
},
{
title: '类型',
key: 'task_type',
key: 'type',
width: 80,
minWidth: 80,
maxWidth: 80,
render: (row: any) => {
const typeMap: Record<string, { text: string; color: string }> = {
transfer: { text: '转存', color: 'blue' }
transfer: { text: '转存', color: 'blue' },
expansion: { text: '扩容', color: 'orange' }
}
const type = typeMap[row.task_type] || { text: row.task_type, color: 'gray' }
const type = typeMap[row.type] || { text: row.type, color: 'gray' }
return h('n-tag', { type: type.color, size: 'small' }, { default: () => type.text })
}
},
@@ -347,7 +350,6 @@ const getRowClassName = (row: any) => {
const fetchTasks = async () => {
loading.value = true
try {
const { useTaskApi } = await import('~/composables/useApi')
const taskApi = useTaskApi()
const params: any = {
@@ -360,13 +362,13 @@ const fetchTasks = async () => {
params.status = statusFilter.value
}
if (typeFilter.value) {
params.task_type = typeFilter.value
params.taskType = typeFilter.value
}
const response = await taskApi.getTasks(params) as any
if (response && response.items) {
tasks.value = response.items
if (response && response.page) {
tasks.value = response.tasks || []
total.value = response.total || 0
}
} catch (error) {
@@ -391,7 +393,7 @@ const onTypeFilterChange = () => {
// 刷新任务列表
const refreshTasks = async () => {
// 强制刷新任务状态和列表
await taskStore.fetchTaskStats()
// await taskStore.fetchTaskStats()
await fetchTasks()
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

View File

@@ -65,7 +65,7 @@ export const useTaskStore = defineStore('task', () => {
// 获取任务统计信息
const fetchTaskStats = async () => {
try {
const response = await taskApi.getTasks() as any
const response = await taskApi.getTasks({status: 'running'}) as any
// console.log('原始任务API响应:', response)
// 处理API响应格式