diff --git a/.claude/commands/frontend-developer.md b/.claude/commands/frontend-developer.md
new file mode 100644
index 00000000..0285b526
--- /dev/null
+++ b/.claude/commands/frontend-developer.md
@@ -0,0 +1,37 @@
+---
+name: frontend-developer
+description: Use this agent when you need assistance with frontend development tasks including Vue.js components, UI implementation, styling, responsive design, state management, or frontend architecture decisions. Examples: Context: User is working on a Vue.js component and needs help with implementing a responsive layout. user: 'I need to create a mobile-friendly chat interface component' assistant: 'I'll use the frontend-developer agent to help design and implement this responsive chat component' Since this involves frontend development work with Vue.js and responsive design, use the frontend-developer agent. Context: User encounters styling issues with Element Plus components. user: 'The Element Plus dialog is not displaying correctly on mobile devices' assistant: 'Let me use the frontend-developer agent to troubleshoot this mobile styling issue' This is a frontend styling problem that requires expertise in Element Plus and responsive design.
+color: purple
+---
+
+You are a Senior Frontend Development Engineer with deep expertise in modern web development technologies, particularly Vue.js 3, Element Plus, Vant, and responsive design patterns. You specialize in creating high-quality, maintainable frontend applications with excellent user experience.
+
+Your core responsibilities include:
+- Developing Vue.js 3 components using Composition API and best practices
+- Implementing responsive designs that work seamlessly across desktop and mobile devices
+- Working with Element Plus for desktop UI and Vant for mobile components
+- Managing application state using Pinia store patterns
+- Styling with Stylus preprocessor and Tailwind CSS utilities
+- Optimizing build processes with Vite and ensuring proper code organization
+- Implementing theme switching (dark/light mode) and accessibility features
+- Follow decoupled development, with HTML, CSS, and JS codes placed in separate files for easier maintenance
+
+When working on frontend tasks, you will:
+1. Analyze requirements and suggest the most appropriate Vue.js patterns and component structures
+2. Ensure responsive design principles are followed, considering both desktop and mobile viewports
+3. Choose appropriate UI components from Element Plus (desktop) or Vant (mobile) libraries
+4. Write clean, maintainable code following Vue.js 3 Composition API best practices
+5. Consider performance implications and suggest optimizations when relevant
+6. Ensure proper state management using Pinia when component state needs to be shared
+7. Follow the project's established patterns for routing, API integration, and component organization
+8. Provide specific code examples and explain the reasoning behind architectural decisions
+
+You have deep knowledge of:
+- Vue.js 3 ecosystem (Vue Router, Pinia, Composition API)
+- Modern CSS techniques and preprocessors (Stylus, Tailwind)
+- Component library integration (Element Plus, Vant)
+- Build tools and development workflow (Vite, npm scripts)
+- Cross-browser compatibility and mobile-first design principles
+- Performance optimization and code splitting strategies
+
+Always consider the user experience, code maintainability, and alignment with modern frontend development standards. When suggesting solutions, provide clear explanations and consider both immediate needs and long-term scalability.
diff --git a/JIMENG_CONFIG_README.md b/JIMENG_CONFIG_README.md
deleted file mode 100644
index 9ac0975c..00000000
--- a/JIMENG_CONFIG_README.md
+++ /dev/null
@@ -1,195 +0,0 @@
-# 即梦 AI 配置功能说明
-
-## 功能概述
-
-即梦 AI 配置功能允许管理员通过 Web 界面配置即梦 AI 的 API 密钥和算力消耗设置,支持动态配置更新,无需重启服务。
-
-## 功能特性
-
-### 1. 秘钥配置
-
-- AccessKey 和 SecretKey 配置
-- 支持密码显示/隐藏
-- 连接测试功能
-
-### 2. 算力配置
-
-- 文生图算力消耗
-- 图生图算力消耗
-- 图片编辑算力消耗
-- 图片特效算力消耗
-- 文生视频算力消耗
-- 图生视频算力消耗
-
-### 3. 动态配置
-
-- 配置实时生效
-- 无需重启服务
-- 支持配置验证
-
-## API 接口
-
-### 获取配置
-
-```
-GET /api/admin/jimeng/config
-```
-
-### 更新配置
-
-```
-POST /api/admin/jimeng/config
-Content-Type: application/json
-
-{
- "config": {
- "access_key": "your_access_key",
- "secret_key": "your_secret_key",
- "power": {
- "text_to_image": 10,
- "image_to_image": 15,
- "image_edit": 20,
- "image_effects": 25,
- "text_to_video": 30,
- "image_to_video": 35
- }
- }
-}
-```
-
-### 测试连接
-
-```
-POST /api/admin/jimeng/config/test
-Content-Type: application/json
-
-{
- "config": {
- "access_key": "your_access_key",
- "secret_key": "your_secret_key"
- }
-}
-```
-
-## 前端页面
-
-### 访问路径
-
-管理后台 -> 即梦 AI -> 配置设置
-
-### 页面功能
-
-1. **秘钥配置标签页**
-
- - AccessKey 输入框(密码模式)
- - SecretKey 输入框(密码模式)
- - 测试连接按钮
-
-2. **算力配置标签页**
-
- - 各种任务类型的算力消耗配置
- - 数字输入框,支持 1-100 范围
- - 提示信息说明
-
-3. **操作按钮**
- - 保存配置
- - 重置配置
-
-## 配置存储
-
-配置存储在数据库的`config`表中:
-
-- 配置键:`jimeng`
-- 配置值:JSON 格式的即梦 AI 配置
-
-## 默认配置
-
-如果配置不存在,系统会使用以下默认值:
-
-```json
-{
- "access_key": "",
- "secret_key": "",
- "power": {
- "text_to_image": 10,
- "image_to_image": 15,
- "image_edit": 20,
- "image_effects": 25,
- "text_to_video": 30,
- "image_to_video": 35
- }
-}
-```
-
-## 使用流程
-
-1. **初始配置**
-
- - 访问管理后台即梦 AI 配置页面
- - 填写 AccessKey 和 SecretKey
- - 点击"测试连接"验证配置
- - 调整各功能算力消耗
- - 保存配置
-
-2. **配置更新**
-
- - 修改需要更新的配置项
- - 保存配置
- - 配置立即生效
-
-3. **故障排查**
- - 使用"测试连接"功能验证 API 密钥
- - 检查配置是否正确保存
- - 查看服务日志
-
-## 注意事项
-
-1. **权限要求**
-
- - 只有管理员可以访问配置页面
- - 需要有效的管理员登录会话
-
-2. **配置验证**
-
- - AccessKey 和 SecretKey 不能为空
- - 算力消耗必须大于 0
- - 建议先测试连接再保存配置
-
-3. **服务影响**
- - 配置更新不会影响正在进行的任务
- - 新任务会使用更新后的配置
- - 客户端配置会在下次请求时更新
-
-## 错误处理
-
-1. **配置加载失败**
-
- - 使用默认配置
- - 记录错误日志
-
-2. **连接测试失败**
-
- - 显示具体错误信息
- - 建议检查 API 密钥
-
-3. **配置保存失败**
- - 显示错误信息
- - 保留原有配置
-
-## 开发说明
-
-### 后端文件
-
-- `api/handler/admin/jimeng_handler.go` - 配置管理 API
-- `api/service/jimeng/service.go` - 配置服务逻辑
-- `api/core/types/jimeng.go` - 配置类型定义
-
-### 前端文件
-
-- `web/src/views/admin/jimeng/JimengSetting.vue` - 配置页面
-
-### 数据库
-
-- `config`表存储配置信息
-- 配置键:`jimeng`
-- 配置值:JSON 格式
diff --git a/api/handler/jimeng_handler.go b/api/handler/jimeng_handler.go
index f095d3c9..9cc0dc68 100644
--- a/api/handler/jimeng_handler.go
+++ b/api/handler/jimeng_handler.go
@@ -181,9 +181,6 @@ func (h *JimengHandler) CreateTask(c *gin.Context) {
taskType = model.JMTaskTypeTextToVideo
reqKey = jimeng.ReqKeyTextToVideo
modelName = "即梦文生视频"
- if req.Seed == 0 {
- req.Seed = -1
- }
if req.AspectRatio == "" {
req.AspectRatio = jimeng.AspectRatio16_9
}
@@ -196,9 +193,6 @@ func (h *JimengHandler) CreateTask(c *gin.Context) {
taskType = model.JMTaskTypeImageToVideo
reqKey = jimeng.ReqKeyImageToVideo
modelName = "即梦图生视频"
- if req.Seed == 0 {
- req.Seed = -1
- }
params = map[string]any{
"seed": req.Seed,
"aspect_ratio": req.AspectRatio,
diff --git a/web/src/assets/css/mobile/jimeng.scss b/web/src/assets/css/mobile/jimeng.scss
index 7134f2c8..382cdff4 100644
--- a/web/src/assets/css/mobile/jimeng.scss
+++ b/web/src/assets/css/mobile/jimeng.scss
@@ -775,6 +775,107 @@
}
}
}
+
+ /* 快捷操作按钮样式 */
+ &__works-item-quick-actions {
+ display: flex;
+ gap: 8px;
+ margin-top: 12px;
+ padding-top: 12px;
+ border-top: 1px solid #f3f4f6;
+ }
+
+ &__works-item-quick-action-btn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 32px;
+ height: 32px;
+ border: none;
+ border-radius: 8px;
+ background: #f9fafb;
+ color: #6b7280;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ font-size: 14px;
+
+ &:hover {
+ background: #e5e7eb;
+ color: #374151;
+ transform: translateY(-1px);
+ }
+
+ &:active {
+ transform: translateY(0);
+ }
+
+ &:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ transform: none;
+ }
+
+ &--danger {
+ color: #ef4444;
+
+ &:hover {
+ background: #fef2f2;
+ color: #dc2626;
+ }
+ }
+
+ i {
+ font-size: 16px;
+ }
+ }
+
+ /* 错误信息样式 */
+ &__works-item-error {
+ margin-top: 8px;
+ padding: 8px 12px;
+ background: #fef2f2;
+ border: 1px solid #fecaca;
+ border-radius: 8px;
+ }
+
+ &__works-item-error-content {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 8px;
+ }
+
+ &__works-item-error-text {
+ flex: 1;
+ font-size: 12px;
+ color: #dc2626;
+ line-height: 1.4;
+ word-break: break-all;
+ }
+
+ &__works-item-error-copy-btn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 24px;
+ height: 24px;
+ border: none;
+ border-radius: 4px;
+ background: #fee2e2;
+ color: #dc2626;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ font-size: 12px;
+
+ &:hover {
+ background: #fecaca;
+ color: #b91c1c;
+ }
+
+ i {
+ font-size: 12px;
+ }
+ }
}
/* 旋转动画 */
diff --git a/web/src/store/mobile/jimeng.js b/web/src/store/mobile/jimeng.js
index e247533b..fcef03fb 100644
--- a/web/src/store/mobile/jimeng.js
+++ b/web/src/store/mobile/jimeng.js
@@ -1,8 +1,8 @@
-import { closeLoading, showLoading, showMessageError, showMessageOK } from '@/utils/dialog'
+import { showMessageError, showMessageOK } from '@/utils/dialog'
import { httpGet, httpPost } from '@/utils/http'
import { defineStore } from 'pinia'
import { showConfirmDialog } from 'vant'
-import { computed, ref } from 'vue'
+import { computed, reactive, ref, watch } from 'vue'
export const useJimengStore = defineStore('mobile-jimeng', () => {
// 响应式数据
@@ -22,6 +22,16 @@ export const useJimengStore = defineStore('mobile-jimeng', () => {
const taskPulling = ref(true)
const tastPullHandler = ref(null)
+ // 新增:算力配置
+ const powerConfig = ref({
+ text_to_image: 20,
+ image_to_image: 30,
+ image_edit: 25,
+ image_effects: 15,
+ text_to_video: 100,
+ image_to_video: 120,
+ })
+
// 功能分类
const categories = ref([
{ key: 'image_generation', name: '图像生成' },
@@ -115,35 +125,45 @@ export const useJimengStore = defineStore('mobile-jimeng', () => {
]
// 功能参数
- const textToImageParams = ref({
- size: '1024x1024',
- scale: 7.5,
- use_pre_llm: false,
+ // 各功能的参数
+ const textToImageParams = reactive({
+ size: '1328x1328',
+ scale: 2.5,
+ seed: -1,
+ use_pre_llm: true,
})
- const imageToImageParams = ref({
- image_input: [],
- size: '1024x1024',
+ const imageToImageParams = reactive({
+ image_input: '',
+ size: '1328x1328',
+ gpen: 0.4,
+ skin: 0.3,
+ skin_unifi: 0,
+ gen_mode: 'creative',
+ seed: -1,
})
- const imageEditParams = ref({
- image_urls: [],
+ const imageEditParams = reactive({
+ image_urls: '',
scale: 0.5,
+ seed: -1,
})
- const imageEffectsParams = ref({
- image_input1: [],
+ const imageEffectsParams = reactive({
+ image_input1: '',
template_id: '',
- size: '1024x1024',
+ size: '1328x1328',
})
- const textToVideoParams = ref({
+ const textToVideoParams = reactive({
aspect_ratio: '16:9',
+ seed: -1,
})
- const imageToVideoParams = ref({
+ const imageToVideoParams = reactive({
image_urls: [],
aspect_ratio: '16:9',
+ seed: -1,
})
// 计算属性
@@ -152,12 +172,29 @@ export const useJimengStore = defineStore('mobile-jimeng', () => {
return useImageInput.value ? 'image_to_image' : 'text_to_image'
} else if (activeCategory.value === 'image_editing') {
return 'image_edit'
+ } else if (activeCategory.value === 'image_effects') {
+ return 'image_effects'
} else if (activeCategory.value === 'video_generation') {
return useImageInput.value ? 'image_to_video' : 'text_to_video'
}
return 'text_to_image'
})
+ // 新增:动态计算当前算力消耗
+ const updateCurrentPowerCost = () => {
+ const functionKey = activeFunction.value
+ currentPowerCost.value = powerConfig.value[functionKey] || 10
+ }
+
+ // 监听任务类型变化,自动更新算力
+ watch(
+ [activeCategory, useImageInput],
+ () => {
+ updateCurrentPowerCost()
+ },
+ { immediate: true }
+ )
+
// Actions
const getCategoryIcon = (category) => {
const iconMap = {
@@ -174,52 +211,17 @@ export const useJimengStore = defineStore('mobile-jimeng', () => {
useImageInput.value = false
}
- const switchInputMode = () => {
- currentPrompt.value = ''
- }
-
- const handleMultipleImageUpload = (event) => {
- const files = Array.from(event.target.files)
- files.forEach((file) => {
- if (imageToVideoParams.value.image_urls.length < 2) {
- onImageUpload({ file, name: file.name })
+ // 新增:获取算力配置
+ const fetchPowerConfig = async () => {
+ try {
+ const res = await httpGet('/api/jimeng/power-config')
+ if (res.data) {
+ powerConfig.value = res.data
+ updateCurrentPowerCost() // 更新当前算力消耗
}
- })
- }
-
- const removeImage = (index) => {
- imageToVideoParams.value.image_urls.splice(index, 1)
- }
-
- const onImageUpload = (file) => {
- const formData = new FormData()
- formData.append('file', file.file, file.name)
- showLoading('正在上传图片...')
-
- return httpPost('/api/upload', formData)
- .then((res) => {
- showMessageOK('图片上传成功')
- const imageData = { url: res.data.url, content: res.data.url }
-
- // 根据当前活动功能添加到相应的参数中
- if (activeFunction.value === 'image_to_image') {
- imageToImageParams.value.image_input = [imageData]
- } else if (activeFunction.value === 'image_edit') {
- imageEditParams.value.image_urls = [imageData]
- } else if (activeFunction.value === 'image_effects') {
- imageEffectsParams.value.image_input1 = [imageData]
- } else if (activeFunction.value === 'image_to_video') {
- imageToVideoParams.value.image_urls.push(imageData)
- }
-
- return res.data.url
- })
- .catch((e) => {
- showMessageError('图片上传失败:' + e.message)
- })
- .finally(() => {
- closeLoading()
- })
+ } catch (error) {
+ console.error('获取算力配置失败:', error)
+ }
}
const submitTask = () => {
@@ -229,27 +231,62 @@ export const useJimengStore = defineStore('mobile-jimeng', () => {
}
submitting.value = true
- const params = {
- type: activeFunction.value,
- prompt: currentPrompt.value,
- }
-
+ let requestData = { task_type: activeFunction.value, prompt: currentPrompt.value }
// 根据功能类型添加相应参数
- if (activeFunction.value === 'text_to_image') {
- Object.assign(params, textToImageParams.value)
- } else if (activeFunction.value === 'image_to_image') {
- Object.assign(params, imageToImageParams.value)
- } else if (activeFunction.value === 'image_edit') {
- Object.assign(params, imageEditParams.value)
- } else if (activeFunction.value === 'image_effects') {
- Object.assign(params, imageEffectsParams.value)
- } else if (activeFunction.value === 'text_to_video') {
- Object.assign(params, textToVideoParams.value)
- } else if (activeFunction.value === 'image_to_video') {
- Object.assign(params, imageToVideoParams.value)
+ switch (activeFunction.value) {
+ case 'text_to_image':
+ Object.assign(requestData, {
+ width: parseInt(textToImageParams.size.split('x')[0]),
+ height: parseInt(textToImageParams.size.split('x')[1]),
+ scale: textToImageParams.scale,
+ seed: textToImageParams.seed,
+ use_pre_llm: textToImageParams.use_pre_llm,
+ })
+ break
+ case 'image_to_image':
+ Object.assign(requestData, {
+ image_input: imageToImageParams.image_input,
+ width: parseInt(imageToImageParams.size.split('x')[0]),
+ height: parseInt(imageToImageParams.size.split('x')[1]),
+ gpen: imageToImageParams.gpen,
+ skin: imageToImageParams.skin,
+ skin_unifi: imageToImageParams.skin_unifi,
+ gen_mode: imageToImageParams.gen_mode,
+ seed: imageToImageParams.seed,
+ })
+ break
+ case 'image_edit':
+ Object.assign(requestData, {
+ image_urls: [imageEditParams.image_urls],
+ scale: imageEditParams.scale,
+ seed: imageEditParams.seed,
+ })
+ break
+ case 'image_effects':
+ Object.assign(requestData, {
+ image_input: imageEffectsParams.image_input1,
+ template_id: imageEffectsParams.template_id,
+ width: parseInt(imageEffectsParams.size.split('x')[0]),
+ height: parseInt(imageEffectsParams.size.split('x')[1]),
+ prompt: imageEffectsParams.prompt,
+ })
+ break
+ case 'text_to_video':
+ Object.assign(requestData, {
+ aspect_ratio: textToVideoParams.aspect_ratio,
+ seed: textToVideoParams.seed,
+ })
+ break
+ case 'image_to_video':
+ Object.assign(requestData, {
+ image_urls: imageToVideoParams.image_urls,
+ aspect_ratio: imageToVideoParams.aspect_ratio,
+ seed: imageToVideoParams.seed,
+ })
+ break
}
- return httpPost('/api/jimeng/create', params)
+ return httpPost('/api/jimeng/task', requestData)
.then(() => {
fetchData(1)
taskPulling.value = true
@@ -333,7 +370,7 @@ export const useJimengStore = defineStore('mobile-jimeng', () => {
})
}
- const removeJob = (item) => {
+ const removeJob = async (item) => {
return showConfirmDialog({
title: '确认删除',
message: '此操作将会删除任务相关文件,继续操作吗?',
@@ -383,39 +420,94 @@ export const useJimengStore = defineStore('mobile-jimeng', () => {
}
}
- const resetParams = () => {
- textToImageParams.value = {
- size: '1024x1024',
- scale: 7.5,
- use_pre_llm: false,
- }
- imageToImageParams.value = {
- image_input: [],
- size: '1024x1024',
- }
- imageEditParams.value = {
- image_urls: [],
- scale: 0.5,
- }
- imageEffectsParams.value = {
- image_input1: [],
- template_id: '',
- size: '1024x1024',
- }
- textToVideoParams.value = {
- aspect_ratio: '16:9',
- }
- imageToVideoParams.value = {
- image_urls: [],
- aspect_ratio: '16:9',
- }
- }
-
const closeMediaDialog = () => {
showMediaDialog.value = false
currentMediaUrl.value = ''
}
+ // 新增:画同款功能
+ const drawSame = (item) => {
+ // 设置当前提示词
+ currentPrompt.value = item.prompt
+
+ // 根据任务类型设置相应的参数
+ switch (item.type) {
+ case 'text_to_image':
+ activeCategory.value = 'image_generation'
+ useImageInput.value = false
+ // 设置图片尺寸(如果有的话)
+ if (item.width && item.height) {
+ textToImageParams.size = `${item.width}x${item.height}`
+ }
+ break
+ case 'image_to_image':
+ activeCategory.value = 'image_generation'
+ useImageInput.value = true
+ // 设置图片尺寸(如果有的话)
+ if (item.width && item.height) {
+ imageToImageParams.size = `${item.width}x${item.height}`
+ }
+ break
+ case 'image_edit':
+ activeCategory.value = 'image_editing'
+ break
+ case 'image_effects':
+ activeCategory.value = 'image_effects'
+ // 设置特效模板(如果有的话)
+ if (item.template_id) {
+ imageEffectsParams.template_id = item.template_id
+ }
+ break
+ case 'text_to_video':
+ activeCategory.value = 'video_generation'
+ useImageInput.value = false
+ // 设置视频比例(如果有的话)
+ if (item.aspect_ratio) {
+ textToVideoParams.aspect_ratio = item.aspect_ratio
+ }
+ break
+ case 'image_to_video':
+ activeCategory.value = 'video_generation'
+ useImageInput.value = true
+ // 设置视频比例(如果有的话)
+ if (item.aspect_ratio) {
+ imageToVideoParams.aspect_ratio = item.aspect_ratio
+ }
+ break
+ }
+
+ showMessageOK('已设置画同款参数')
+ }
+
+ // 新增:复制提示词功能
+ const copyPrompt = (prompt) => {
+ navigator.clipboard
+ .writeText(prompt)
+ .then(() => {
+ showMessageOK('提示词已复制')
+ })
+ .catch(() => {
+ showMessageError('复制失败')
+ })
+ }
+
+ // 新增:复制错误信息功能
+ const copyErrorMsg = (msg) => {
+ navigator.clipboard
+ .writeText(msg)
+ .then(() => {
+ showMessageOK('错误信息已复制')
+ })
+ .catch(() => {
+ showMessageError('复制失败')
+ })
+ }
+
+ // 新增:初始化方法
+ const init = async () => {
+ await fetchPowerConfig()
+ }
+
return {
// State
activeCategory,
@@ -443,6 +535,7 @@ export const useJimengStore = defineStore('mobile-jimeng', () => {
imageEffectsParams,
textToVideoParams,
imageToVideoParams,
+ powerConfig,
// Computed
activeFunction,
@@ -450,10 +543,6 @@ export const useJimengStore = defineStore('mobile-jimeng', () => {
// Actions
getCategoryIcon,
switchCategory,
- switchInputMode,
- handleMultipleImageUpload,
- removeImage,
- onImageUpload,
submitTask,
fetchData,
loadMore,
@@ -465,7 +554,11 @@ export const useJimengStore = defineStore('mobile-jimeng', () => {
getTaskType,
startTaskPolling,
stopTaskPolling,
- resetParams,
closeMediaDialog,
+ fetchPowerConfig,
+ drawSame,
+ copyPrompt,
+ copyErrorMsg,
+ init,
}
})
diff --git a/web/src/store/mobile/suno.js b/web/src/store/mobile/suno.js
index c701f06a..6d10ef9c 100644
--- a/web/src/store/mobile/suno.js
+++ b/web/src/store/mobile/suno.js
@@ -1,10 +1,10 @@
-import { defineStore } from 'pinia'
-import { ref, reactive } from 'vue'
-import { checkSession } from '@/store/cache'
+import { getSystemInfo } from '@/store/cache'
import { closeLoading, showLoading, showToastMessage } from '@/utils/dialog'
import { httpDownload, httpGet, httpPost } from '@/utils/http'
import { replaceImg } from '@/utils/libs'
-import { getSystemInfo } from '@/store/cache'
+import { defineStore } from 'pinia'
+import { showConfirmDialog } from 'vant'
+import { reactive, ref } from 'vue'
export const useSunoStore = defineStore('suno', () => {
// 状态
@@ -35,7 +35,6 @@ export const useSunoStore = defineStore('suno', () => {
const uploadRef = ref(null)
const isGenerating = ref(false)
const deleting = ref(false)
- const deleteItem = ref(null)
const models = ref([
{ label: 'v3.0', value: 'chirp-v3-0' },
{ label: 'v3.5', value: 'chirp-v3-5' },
@@ -287,10 +286,25 @@ export const useSunoStore = defineStore('suno', () => {
item.downloading = false
})
}
- const showDeleteDialog = (item) => {
- deleteItem.value = item
- // 这里建议在页面层处理弹窗,store 只负责数据和业务
+
+ const removeJob = (item) => {
+ showConfirmDialog({
+ title: '确认删除',
+ message: '此操作将会删除任务相关文件,继续操作吗?',
+ confirmButtonText: '确认删除',
+ cancelButtonText: '取消',
+ }).then(() => {
+ httpGet('/api/suno/remove', { id: item.id })
+ .then(() => {
+ showToastMessage('任务删除成功', 'success')
+ fetchData(1)
+ })
+ .catch(() => {
+ showToastMessage('任务删除失败', 'error')
+ })
+ })
}
+
const extend = (item) => {
refSong.value = item
refSong.value.extend_secs = item.duration
@@ -324,7 +338,6 @@ export const useSunoStore = defineStore('suno', () => {
uploadRef,
isGenerating,
deleting,
- deleteItem,
models,
tags,
page,
@@ -346,7 +359,7 @@ export const useSunoStore = defineStore('suno', () => {
refreshFirstPage,
play,
download,
- showDeleteDialog,
+ removeJob,
extend,
removeRefSong,
}
diff --git a/web/src/views/mobile/JimengCreate.vue b/web/src/views/mobile/JimengCreate.vue
index 4523719f..2154dcbd 100644
--- a/web/src/views/mobile/JimengCreate.vue
+++ b/web/src/views/mobile/JimengCreate.vue
@@ -49,11 +49,7 @@
@@ -284,9 +280,9 @@
@@ -294,19 +290,6 @@
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.err_msg }}
-
@@ -515,6 +517,7 @@ const handleTemplateChange = (value) => {
onMounted(() => {
checkSession()
.then(() => {
+ jimengStore.init() // 初始化算力配置
jimengStore.fetchData(1)
jimengStore.startTaskPolling()
})
diff --git a/web/src/views/mobile/SunoCreate.vue b/web/src/views/mobile/SunoCreate.vue
index 00b5a845..b8cc3540 100644
--- a/web/src/views/mobile/SunoCreate.vue
+++ b/web/src/views/mobile/SunoCreate.vue
@@ -388,7 +388,7 @@