243 lines
7.1 KiB
TypeScript
243 lines
7.1 KiB
TypeScript
import { defineStore } from 'pinia'
|
||
import { computed, ref } from 'vue'
|
||
import type { Router } from 'vue-router'
|
||
import axios from 'axios'
|
||
import { t } from '../i18n'
|
||
import { registerToolRoute, unregisterToolRoute, registerAllToolRoutes, ensureToolRoutes } from '../utils/dynamicRoutes'
|
||
import { get_session_api_headers } from '../api/auth'
|
||
|
||
export interface Tool {
|
||
id: string
|
||
name: string
|
||
description?: string
|
||
category?: string
|
||
icon?: string
|
||
color?: string
|
||
type?: 'route' | 'url'
|
||
routeName?: string
|
||
url?: string
|
||
order?: number
|
||
isDefault?: boolean
|
||
hidden?: boolean
|
||
// 市场工具相关
|
||
fromMarketplace?: boolean
|
||
marketplaceId?: string // 市场的唯一ID(用于识别)
|
||
toolName?: string // 实际的 tool_name(用于删除文件系统)
|
||
version?: string
|
||
author?: string
|
||
rating?: number
|
||
downloads?: number
|
||
// 路由相关(可选,用于动态路由注册)
|
||
componentPath?: string // 组件路径(相对于 src/views)
|
||
routePath?: string // 路由路径(如 'tools/my-tool')
|
||
}
|
||
|
||
const STORAGE_KEY = 'tools.userItems'
|
||
const DELETED_DEFAULT_TOOLS_KEY = 'tools.deletedDefaultTools'
|
||
|
||
// 默认工具列表(硬编码,一行一个,方便添加)
|
||
function getDefaultTools(): Tool[] {
|
||
return [
|
||
{
|
||
id: 'remove-background',
|
||
name: t('Remove Background'),
|
||
description: t('Remove background from images using AI technology'),
|
||
category: 'Image Processing',
|
||
icon: 'photo-edit',
|
||
color: '#e5e7eb',
|
||
type: 'route',
|
||
routeName: 'RemoveBackground',
|
||
order: 1,
|
||
isDefault: true,
|
||
toolName: 'remove_background'
|
||
},
|
||
// 在这里添加更多默认工具,每行一个:
|
||
// {
|
||
// id: 'tool-id-2',
|
||
// name: t('Tool Name'),
|
||
// description: t('Tool description'),
|
||
// category: 'Category',
|
||
// icon: 'icon-name',
|
||
// color: '#e5e7eb',
|
||
// type: 'route',
|
||
// routeName: 'RouteName',
|
||
// order: 2,
|
||
// isDefault: true,
|
||
// toolName: 'tool_name'
|
||
// },
|
||
]
|
||
}
|
||
|
||
function loadUserTools(): Tool[] {
|
||
try {
|
||
const raw = localStorage.getItem(STORAGE_KEY)
|
||
if (!raw) return []
|
||
const parsed = JSON.parse(raw)
|
||
if (Array.isArray(parsed)) return parsed
|
||
return []
|
||
} catch {
|
||
return []
|
||
}
|
||
}
|
||
|
||
function saveUserTools(tools: Tool[]) {
|
||
const userTools = tools.filter(t => !t.isDefault)
|
||
localStorage.setItem(STORAGE_KEY, JSON.stringify(userTools))
|
||
}
|
||
|
||
function loadDeletedDefaultTools(): string[] {
|
||
try {
|
||
const raw = localStorage.getItem(DELETED_DEFAULT_TOOLS_KEY)
|
||
if (!raw) return []
|
||
return JSON.parse(raw)
|
||
} catch {
|
||
return []
|
||
}
|
||
}
|
||
|
||
function saveDeletedDefaultTools(deletedIds: string[]) {
|
||
localStorage.setItem(DELETED_DEFAULT_TOOLS_KEY, JSON.stringify(deletedIds))
|
||
}
|
||
|
||
export const useToolsStore = defineStore('tools', () => {
|
||
const userTools = ref<Tool[]>(loadUserTools())
|
||
const deletedDefaultToolIds = ref<string[]>(loadDeletedDefaultTools())
|
||
|
||
const allTools = computed(() => {
|
||
const defaultTools = getDefaultTools()
|
||
.filter(tool => !deletedDefaultToolIds.value.includes(tool.id))
|
||
.map(tool => ({ ...tool, isDefault: true }))
|
||
|
||
const userToolsList = [...userTools.value]
|
||
.map(tool => ({ ...tool, isDefault: false }))
|
||
|
||
return [
|
||
...defaultTools.sort((a, b) => (a.order ?? 0) - (b.order ?? 0)),
|
||
...userToolsList.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
|
||
]
|
||
})
|
||
|
||
// 添加用户工具
|
||
function addUserTool(tool: Tool, router?: Router, componentPath?: string) {
|
||
const defaultToolsCount = getDefaultTools().filter(
|
||
t => !deletedDefaultToolIds.value.includes(t.id)
|
||
).length
|
||
|
||
// 确保工具具有 routeName 和 routePath(如果缺失则自动生成)
|
||
// 这样保存到 localStorage 的数据也会包含这些字段
|
||
const toolWithRoutes = ensureToolRoutes({ ...tool })
|
||
|
||
toolWithRoutes.order = defaultToolsCount + userTools.value.length + 1
|
||
toolWithRoutes.isDefault = false
|
||
userTools.value.push(toolWithRoutes)
|
||
saveUserTools(userTools.value)
|
||
|
||
// 注册路由(如果提供了 router)
|
||
if (router) {
|
||
registerToolRoute(router, toolWithRoutes, componentPath)
|
||
}
|
||
}
|
||
|
||
function updateUserTool(toolId: string, updates: Partial<Tool>) {
|
||
const index = userTools.value.findIndex(t => t.id === toolId)
|
||
if (index >= 0) {
|
||
userTools.value[index] = { ...userTools.value[index], ...updates, isDefault: false }
|
||
saveUserTools(userTools.value)
|
||
}
|
||
}
|
||
|
||
// 删除工具(支持用户工具和默认工具)
|
||
async function deleteUserTool(toolId: string, router?: Router) {
|
||
// 查找用户工具
|
||
let tool = userTools.value.find(t => t.id === toolId)
|
||
let isDefaultTool = false
|
||
|
||
// 如果不是用户工具,查找默认工具
|
||
if (!tool) {
|
||
tool = getDefaultTools().find(t => t.id === toolId)
|
||
isDefaultTool = true
|
||
}
|
||
|
||
let toolName: string | null = null
|
||
|
||
if (tool) {
|
||
if (tool.toolName) {
|
||
toolName = tool.toolName
|
||
} else if (tool.componentPath) {
|
||
const match = tool.componentPath.match(/tools\/([^\/]+)\//)
|
||
if (match && match[1]) {
|
||
toolName = match[1]
|
||
}
|
||
}
|
||
}
|
||
|
||
if (toolName) {
|
||
try {
|
||
await axios.post(`/jingrow/uninstall-tool/${toolName}`, {}, {
|
||
headers: {
|
||
...get_session_api_headers()
|
||
}
|
||
})
|
||
} catch (error: any) {
|
||
console.error('删除工具文件失败:', error.response?.data || error.message || '未知错误')
|
||
}
|
||
}
|
||
|
||
if (isDefaultTool) {
|
||
// 删除默认工具:添加到已删除列表
|
||
if (!deletedDefaultToolIds.value.includes(toolId)) {
|
||
deletedDefaultToolIds.value.push(toolId)
|
||
saveDeletedDefaultTools(deletedDefaultToolIds.value)
|
||
}
|
||
} else {
|
||
// 删除用户工具:从列表中移除
|
||
userTools.value = userTools.value.filter(t => t.id !== toolId)
|
||
const defaultToolsCount = getDefaultTools().filter(
|
||
t => !deletedDefaultToolIds.value.includes(t.id)
|
||
).length
|
||
userTools.value.forEach((t, index) => {
|
||
t.order = defaultToolsCount + index + 1
|
||
})
|
||
saveUserTools(userTools.value)
|
||
}
|
||
|
||
if (tool && tool.routeName && router) {
|
||
unregisterToolRoute(router, tool.routeName)
|
||
}
|
||
}
|
||
|
||
function updateUserToolsOrder(newOrder: Tool[]) {
|
||
const defaultToolsCount = getDefaultTools().filter(
|
||
t => !deletedDefaultToolIds.value.includes(t.id)
|
||
).length
|
||
|
||
newOrder.forEach((tool, index) => {
|
||
tool.order = defaultToolsCount + index + 1
|
||
})
|
||
|
||
userTools.value = newOrder
|
||
saveUserTools(userTools.value)
|
||
}
|
||
|
||
function initToolRoutes(router: Router) {
|
||
const defaultTools = getDefaultTools()
|
||
.filter(tool => !deletedDefaultToolIds.value.includes(tool.id))
|
||
.map(tool => ({ ...tool, isDefault: true }))
|
||
|
||
const allToolsToRegister = [...defaultTools, ...userTools.value]
|
||
registerAllToolRoutes(router, allToolsToRegister)
|
||
}
|
||
|
||
return {
|
||
userTools,
|
||
allTools,
|
||
addUserTool,
|
||
updateUserTool,
|
||
deleteUserTool,
|
||
updateUserToolsOrder,
|
||
getDefaultTools,
|
||
initToolRoutes
|
||
}
|
||
})
|
||
|