feat(ai): 创意助手各页下线参考素材上传,图片模式改传 mode(issue 19)
- 聊天页「图片」模式与独立创意助手页都删掉上传入口、上传状态与相关样式;
上游出图工具只做文生图,开始节点的 file-list 变量没有任何节点消费(issue 16)。
- 图片模式请求体改为 { user_content, mode: 'image' },由后端包装意图声明;
独立页不传 mode(通用入口,视频/脚本/图片靠用户文字说明)。
This commit is contained in:
+11
-239
@@ -235,30 +235,6 @@
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 「添加附件」放在最左:它是要点的主操作,不能被滑到屏幕外 -->
|
||||
<scroll-view
|
||||
v-if="activeChatMode === 'image'"
|
||||
scroll-x
|
||||
:show-scrollbar="false"
|
||||
class="option-scroll"
|
||||
>
|
||||
<view class="option-track">
|
||||
<text class="option-label">参考素材</text>
|
||||
<view
|
||||
class="option-chip"
|
||||
:class="{ 'option-chip--disabled': !canPickImageFiles }"
|
||||
@tap="chooseImageFiles"
|
||||
>{{ uploadingFiles ? '上传中...' : '添加附件' }}</view>
|
||||
<text class="option-hint">最多 {{ IMAGE_FILE_LIMIT }} 个</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<view v-if="activeChatMode === 'image' && imageFiles.length" class="attach-list">
|
||||
<view v-for="(item, index) in imageFiles" :key="item.id" class="attach-item">
|
||||
<text class="attach-name">{{ item.name }}</text>
|
||||
<view class="attach-remove" @tap="removeImageFile(index)">移除</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="composer-row">
|
||||
<textarea
|
||||
@@ -334,7 +310,6 @@
|
||||
manuscriptGen,
|
||||
removeAiChatList,
|
||||
sendMessage as sendChatMessage,
|
||||
uploadAiFile
|
||||
} from './chat-service'
|
||||
import {
|
||||
WRITING_DOC_TYPE_FREE,
|
||||
@@ -360,13 +335,7 @@
|
||||
// 图片比例选择器已撤掉:上游创意助手开始节点没有比例变量(实测只有 user_content /
|
||||
// user_files),前端只能把它拼进 user_content —— 那是替上游写 prompt。
|
||||
// 要恢复这个功能,先在上游开始节点加变量,再按变量契约接上来。
|
||||
/** 参考素材上限,与 Dify 开始节点 file-list 变量 user_files 的 max_length 一致 */
|
||||
const IMAGE_FILE_LIMIT = 5
|
||||
/** 单个附件大小上限(与既有 pages/creative-assistant 口径一致) */
|
||||
const MAX_UPLOAD_MB = 100
|
||||
const IMAGE_FILE_EXTS = ['PNG', 'JPG', 'JPEG', 'GIF', 'WEBP', 'BMP', 'SVG']
|
||||
const VIDEO_FILE_EXTS = ['MP4', 'MOV', 'MPEG', 'MPGA', 'AVI', 'M4V']
|
||||
const AUDIO_FILE_EXTS = ['MP3', 'M4A', 'WAV', 'AMR', 'AAC', 'OGG', 'WEBM']
|
||||
// user_files 本身也已不再上传:开始节点挂着这个变量,但没有任何下游节点消费它(issue 16)。
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@@ -376,7 +345,6 @@
|
||||
writingDocTypeOptions: WRITING_DOC_TYPE_OPTIONS,
|
||||
writingWordCountOptions: WRITING_WORD_COUNT_OPTIONS,
|
||||
writingEventTypeOptions: WRITING_EVENT_TYPE_OPTIONS,
|
||||
IMAGE_FILE_LIMIT,
|
||||
// 写作模式:默认「自由创作」——不套模板,原话直接交给 AI 创意助手
|
||||
writingDocType: WRITING_DOC_TYPE_FREE,
|
||||
// 字数只在选了文体后才有意义,默认不下发
|
||||
@@ -391,9 +359,6 @@
|
||||
location: '',
|
||||
participants: ''
|
||||
},
|
||||
// 图片模式的参考素材(Dify 开始节点 file-list 变量 user_files)
|
||||
imageFiles: [],
|
||||
uploadingFiles: false,
|
||||
statusBarHeight: 0,
|
||||
draft: '',
|
||||
activeChatMode: 'chat',
|
||||
@@ -430,7 +395,7 @@
|
||||
return this.statusBarHeight + 44
|
||||
},
|
||||
canSend() {
|
||||
if (!this.currentUser.userId || this.loading || this.uploadingFiles) {
|
||||
if (!this.currentUser.userId || this.loading) {
|
||||
return false
|
||||
}
|
||||
if (this.draft.trim()) {
|
||||
@@ -443,9 +408,6 @@
|
||||
this.writingParamCount > 0
|
||||
)
|
||||
},
|
||||
canPickImageFiles() {
|
||||
return !this.loading && !this.uploadingFiles && this.imageFiles.length < IMAGE_FILE_LIMIT
|
||||
},
|
||||
/** 选中文体 = 套模板走「内容创作与宣传助手」;否则是自由创作走「AI 创意助手」 */
|
||||
writingTemplateMode() {
|
||||
return this.writingDocType !== WRITING_DOC_TYPE_FREE
|
||||
@@ -474,7 +436,7 @@
|
||||
return '默认「自由创作」:说清想写什么就行,由 AI 创意助手直接生成;选了文体则按该体裁生成,并可在下方指定字数。'
|
||||
}
|
||||
if (this.activeChatMode === 'image') {
|
||||
return '描述你要的图片,例如校园活动海报、公众号头图;还可以添加参考素材。'
|
||||
return '描述你要的图片,例如校园活动海报、公众号头图、志愿服务插画。'
|
||||
}
|
||||
return '你可以直接提问团务流程问题,我会通过实时消息回复。'
|
||||
},
|
||||
@@ -1166,60 +1128,22 @@
|
||||
return this.buildFallbackText()
|
||||
},
|
||||
/**
|
||||
* 图片模式入参:`user_content` 就是**用户原话**,外加 `user_files`(Dify file-list 变量)。
|
||||
* 图片模式入参。
|
||||
*
|
||||
* 附件上限 5、类型取 image/video/audio/document —— 都来自上游开始节点的变量定义。
|
||||
* 只下发 `user_content`(用户原话)与 `mode: 'image'`。
|
||||
*
|
||||
* 不往 `user_content` 里追加任何我们自己写的话(如「图片比例:1:1」
|
||||
* 「请直接生成图片…」):上游没有比例变量,拼进去等于替上游写 prompt。
|
||||
* 参考素材(`user_files`)已下线:上游出图工具只做文生图,开始节点虽挂着 file-list
|
||||
* 变量,但没有节点消费它(见 issue 16),传上去只是让用户白等上传。
|
||||
*
|
||||
* `mode` 不进 `user_content`:后端在 image 模式下统一包装成「生成图片」的意图声明,
|
||||
* 让上游「问题分类器」不把画面描述判成文案分支(见 issue 19)。
|
||||
*/
|
||||
buildImagePayload(query) {
|
||||
return {
|
||||
user_content: query,
|
||||
user_files: this.imageFiles.map((item) => ({
|
||||
transfer_method: 'local_file',
|
||||
type: item.type,
|
||||
upload_file_id: item.id,
|
||||
url: ''
|
||||
}))
|
||||
mode: 'image'
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 按 MIME / 扩展名判定 Dify file-list 要求的 type(image/video/audio/document)。
|
||||
*
|
||||
* `pickedType` 是 `uni.chooseMessageFile` 给的微信侧分类(image/video/file),
|
||||
* 只在拿不到 MIME 与扩展名时才作为兜底依据。
|
||||
*/
|
||||
resolveUploadFileType(contentType, fileName, pickedType) {
|
||||
const mime = String(contentType || '').toLowerCase()
|
||||
if (mime.indexOf('image/') === 0) {
|
||||
return 'image'
|
||||
}
|
||||
if (mime.indexOf('video/') === 0) {
|
||||
return 'video'
|
||||
}
|
||||
if (mime.indexOf('audio/') === 0) {
|
||||
return 'audio'
|
||||
}
|
||||
const ext = String(fileName || '').split('.').pop().toUpperCase()
|
||||
if (IMAGE_FILE_EXTS.indexOf(ext) > -1) {
|
||||
return 'image'
|
||||
}
|
||||
if (VIDEO_FILE_EXTS.indexOf(ext) > -1) {
|
||||
return 'video'
|
||||
}
|
||||
if (AUDIO_FILE_EXTS.indexOf(ext) > -1) {
|
||||
return 'audio'
|
||||
}
|
||||
if (pickedType === 'image' || pickedType === 'video') {
|
||||
return pickedType
|
||||
}
|
||||
return 'document'
|
||||
},
|
||||
guessFileName(path, index) {
|
||||
const segment = String(path || '').split(/[\\/]/).pop() || ''
|
||||
return segment || `参考素材${index + 1}`
|
||||
},
|
||||
pickWritingDocType(value) {
|
||||
if (this.loading) {
|
||||
return
|
||||
@@ -1244,122 +1168,6 @@
|
||||
}
|
||||
this.writingParams.eventType = value
|
||||
},
|
||||
/**
|
||||
* 选参考素材。
|
||||
*
|
||||
* 小程序没有 web 那种「一个文件选择器覆盖所有类型」的能力,所以给两个来源:
|
||||
* 相册 / 拍照(图片,最常用)与聊天记录里的文件(可覆盖视频 / 音频 / 文档)。
|
||||
*/
|
||||
chooseImageFiles() {
|
||||
if (!this.canPickImageFiles) {
|
||||
if (!this.loading && !this.uploadingFiles) {
|
||||
this.showToast(`参考素材最多 ${IMAGE_FILE_LIMIT} 个`)
|
||||
}
|
||||
return
|
||||
}
|
||||
uni.showActionSheet({
|
||||
// 支持的类型写在选项里(面板上那行 hint 只留「最多 5 个」,省横向空间)
|
||||
itemList: ['从相册选择图片', '从聊天记录选文件(视频/音频/文档)'],
|
||||
success: (result) => {
|
||||
if (result.tapIndex === 0) {
|
||||
this.pickLocalImages()
|
||||
return
|
||||
}
|
||||
this.pickMessageFiles()
|
||||
}
|
||||
})
|
||||
},
|
||||
pickLocalImages() {
|
||||
const remain = IMAGE_FILE_LIMIT - this.imageFiles.length
|
||||
uni.chooseImage({
|
||||
count: remain > 0 ? remain : 1,
|
||||
sizeType: ['original', 'compressed'],
|
||||
sourceType: ['album', 'camera'],
|
||||
success: (result) => {
|
||||
const paths = result.tempFilePaths || []
|
||||
const tempFiles = result.tempFiles || []
|
||||
const picked = paths.map((path, index) => {
|
||||
const info = tempFiles[index] || {}
|
||||
return {
|
||||
path: info.path || path,
|
||||
name: this.guessFileName(info.path || path, index),
|
||||
size: info.size,
|
||||
type: 'image'
|
||||
}
|
||||
})
|
||||
this.uploadPickedFiles(picked)
|
||||
}
|
||||
})
|
||||
},
|
||||
pickMessageFiles() {
|
||||
const remain = IMAGE_FILE_LIMIT - this.imageFiles.length
|
||||
uni.chooseMessageFile({
|
||||
count: remain > 0 ? remain : 1,
|
||||
type: 'all',
|
||||
success: (result) => {
|
||||
this.uploadPickedFiles(
|
||||
(result.tempFiles || []).map((item) => ({
|
||||
path: item.path,
|
||||
name: item.name,
|
||||
size: item.size,
|
||||
type: item.type
|
||||
}))
|
||||
)
|
||||
}
|
||||
})
|
||||
},
|
||||
async uploadPickedFiles(files) {
|
||||
const picked = (files || []).filter((item) => item && item.path)
|
||||
if (!picked.length) {
|
||||
return
|
||||
}
|
||||
const remain = IMAGE_FILE_LIMIT - this.imageFiles.length
|
||||
if (remain <= 0) {
|
||||
this.showToast(`参考素材最多 ${IMAGE_FILE_LIMIT} 个`)
|
||||
return
|
||||
}
|
||||
const selected = picked.slice(0, remain)
|
||||
if (picked.length > remain) {
|
||||
this.showToast(`参考素材最多 ${IMAGE_FILE_LIMIT} 个,本次只上传前 ${remain} 个`)
|
||||
}
|
||||
this.uploadingFiles = true
|
||||
try {
|
||||
for (let index = 0; index < selected.length; index += 1) {
|
||||
const file = selected[index]
|
||||
if (file.size && file.size / 1024 / 1024 > MAX_UPLOAD_MB) {
|
||||
this.showToast(`单个附件不能超过 ${MAX_UPLOAD_MB}MB`)
|
||||
continue
|
||||
}
|
||||
// app 必须传 creativeAssistant:Dify 的 /files/upload 按应用鉴权,
|
||||
// 用别的应用凭证上传的 file id,工作流会报 Invalid upload file。
|
||||
const record = await uploadAiFile(file, 'creativeAssistant')
|
||||
const name = record.name || file.name || this.guessFileName(file.path, index)
|
||||
this.imageFiles = [
|
||||
...this.imageFiles,
|
||||
{
|
||||
id: String(record.id),
|
||||
name,
|
||||
type: this.resolveUploadFileType(
|
||||
record.contentType,
|
||||
name,
|
||||
file.type
|
||||
)
|
||||
}
|
||||
]
|
||||
}
|
||||
this.showToast('参考素材已上传')
|
||||
} catch (error) {
|
||||
this.showToast((error && error.message) || '参考素材上传失败')
|
||||
} finally {
|
||||
this.uploadingFiles = false
|
||||
}
|
||||
},
|
||||
removeImageFile(index) {
|
||||
if (this.loading) {
|
||||
return
|
||||
}
|
||||
this.imageFiles = this.imageFiles.filter((item, current) => current !== index)
|
||||
},
|
||||
getCreativeOutputs(payload) {
|
||||
if (payload && payload.outputs && typeof payload.outputs === 'object') {
|
||||
return payload.outputs
|
||||
@@ -2113,42 +1921,6 @@
|
||||
color: #b8ada7;
|
||||
}
|
||||
|
||||
.attach-list {
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.attach-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
padding: 8rpx 14rpx;
|
||||
border-radius: 16rpx;
|
||||
background: rgba(20, 150, 242, 0.06);
|
||||
}
|
||||
|
||||
.attach-item + .attach-item {
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.attach-name {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
font-size: 22rpx;
|
||||
color: #4a5560;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.attach-remove {
|
||||
flex-shrink: 0;
|
||||
padding: 6rpx 14rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(20, 150, 242, 0.1);
|
||||
color: #1496f2;
|
||||
font-size: 20rpx;
|
||||
}
|
||||
|
||||
.composer-row {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<view class="hero-card">
|
||||
<view class="hero-title">AI 创意助手</view>
|
||||
<view class="hero-desc">
|
||||
支持文本指令与多类型附件联合驱动工作流,自动返回视频、脚本 Markdown 或图像 / 排版结果。
|
||||
支持文本指令驱动工作流,自动返回视频、脚本 Markdown 或图像 / 排版结果。
|
||||
</view>
|
||||
<view class="hero-actions">
|
||||
<view class="hero-action" @tap="fillExample('video')">短视频创意</view>
|
||||
@@ -21,35 +21,12 @@
|
||||
<textarea
|
||||
v-model="content"
|
||||
class="field-textarea field-textarea--large"
|
||||
placeholder="请输入用户的文本指令或需求描述,例如:根据活动照片和通知文档,生成一条公众号推文封面及 60 秒短视频脚本。"
|
||||
placeholder="请输入用户的文本指令或需求描述,例如:围绕迎新晚会,生成一条公众号推文封面及 60 秒短视频脚本。"
|
||||
placeholder-style="color: #c0c4cc;"
|
||||
maxlength="-1"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="field-item">
|
||||
<view class="field-label">上传附件</view>
|
||||
<view class="upload-bar">
|
||||
<view class="upload-btn" @tap="chooseFiles">{{ uploading ? '上传中...' : '添加附件' }}</view>
|
||||
<view class="upload-tip">支持图片、视频、音频和常见文档类型。</view>
|
||||
</view>
|
||||
<view v-if="uploadedFiles.length" class="file-list">
|
||||
<view
|
||||
v-for="(item, index) in uploadedFiles"
|
||||
:key="`${item.url || item.path || item.name}-${index}`"
|
||||
class="file-item-card"
|
||||
>
|
||||
<view class="file-main">
|
||||
<view class="file-badge">{{ getFileTypeLabel(item) }}</view>
|
||||
<view class="file-text">
|
||||
<view class="file-name">{{ item.name || getFileName(item) }}</view>
|
||||
<view class="file-url">{{ resolveFileUrl(item) || '-' }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="file-remove" @tap="removeUploadedFile(index)">移除</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="submit-bar">
|
||||
@@ -93,7 +70,7 @@
|
||||
</view>
|
||||
|
||||
<view v-else-if="!hasAnyResult" class="result-empty">
|
||||
填写文本指令并上传附件后执行工作流
|
||||
填写文本指令后执行工作流
|
||||
</view>
|
||||
|
||||
<view v-else class="result-body">
|
||||
@@ -170,35 +147,14 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { creativeAssistant, uploadAiFile } from './service'
|
||||
import { creativeAssistant } from './service'
|
||||
|
||||
const DOCUMENT_FILE_EXTS = new Set([
|
||||
'TXT',
|
||||
'MD',
|
||||
'MARKDOWN',
|
||||
'PDF',
|
||||
'HTML',
|
||||
'XLSX',
|
||||
'XLS',
|
||||
'DOCX',
|
||||
'CSV',
|
||||
'EML',
|
||||
'MSG',
|
||||
'PPTX',
|
||||
'PPT',
|
||||
'XML',
|
||||
'EPUB'
|
||||
])
|
||||
const AUDIO_FILE_EXTS = new Set(['MP3', 'M4A', 'WAV', 'WEBM', 'AMR', 'AAC', 'OGG'])
|
||||
const VIDEO_FILE_EXTS = new Set(['MP4', 'MOV', 'MPEG', 'MPGA', 'WEBM', 'AVI', 'M4V'])
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
uploading: false,
|
||||
content: '',
|
||||
uploadedFiles: [],
|
||||
workflowResponse: null,
|
||||
workflowOutputs: null,
|
||||
loadingSteps: [
|
||||
@@ -219,7 +175,7 @@
|
||||
},
|
||||
computed: {
|
||||
canSubmit() {
|
||||
return !!String(this.content || '').trim() || this.uploadedFiles.length > 0
|
||||
return !!String(this.content || '').trim()
|
||||
},
|
||||
videoFiles() {
|
||||
return (this.workflowOutputs && this.workflowOutputs.video_result) || []
|
||||
@@ -271,12 +227,6 @@
|
||||
return String(status || '').trim().toLowerCase() === 'failed'
|
||||
},
|
||||
loadingTitle() {
|
||||
if (this.uploadedFiles.length && String(this.content || '').trim()) {
|
||||
return '正在分析指令并处理附件'
|
||||
}
|
||||
if (this.uploadedFiles.length) {
|
||||
return '正在解析附件并生成结果'
|
||||
}
|
||||
return '正在根据文本指令生成内容'
|
||||
},
|
||||
loadingDescription() {
|
||||
@@ -344,23 +294,6 @@
|
||||
}
|
||||
return ['mp3', 'wav', 'aac', 'm4a', 'ogg', 'amr'].includes(this.getFileExt(file))
|
||||
},
|
||||
getUploadFileType(file) {
|
||||
const contentType = String((file && file.contentType) || '').toLowerCase()
|
||||
const ext = this.getFileExt(file).toUpperCase()
|
||||
if (contentType.startsWith('image/')) {
|
||||
return 'image'
|
||||
}
|
||||
if (AUDIO_FILE_EXTS.has(ext)) {
|
||||
return 'audio'
|
||||
}
|
||||
if (VIDEO_FILE_EXTS.has(ext)) {
|
||||
return 'video'
|
||||
}
|
||||
if (DOCUMENT_FILE_EXTS.has(ext)) {
|
||||
return 'document'
|
||||
}
|
||||
return 'document'
|
||||
},
|
||||
getFileTypeLabel(file) {
|
||||
if (this.isImageFile(file)) {
|
||||
return '图片'
|
||||
@@ -379,84 +312,27 @@
|
||||
},
|
||||
resetAll() {
|
||||
this.content = ''
|
||||
this.uploadedFiles = []
|
||||
this.clearResult()
|
||||
},
|
||||
removeUploadedFile(index) {
|
||||
this.uploadedFiles = this.uploadedFiles.filter((item, current) => current !== index)
|
||||
},
|
||||
async chooseFiles() {
|
||||
if (this.uploading) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
const result = await new Promise((resolve, reject) => {
|
||||
uni.chooseMessageFile({
|
||||
count: 9,
|
||||
type: 'all',
|
||||
success: resolve,
|
||||
fail: reject
|
||||
})
|
||||
})
|
||||
const tempFiles = (result && result.tempFiles) || []
|
||||
if (!tempFiles.length) {
|
||||
return
|
||||
}
|
||||
this.uploading = true
|
||||
uni.showLoading({
|
||||
title: '上传中',
|
||||
mask: true
|
||||
})
|
||||
for (let index = 0; index < tempFiles.length; index += 1) {
|
||||
const file = tempFiles[index]
|
||||
if (file.size && file.size / 1024 / 1024 > 100) {
|
||||
this.showToast('单个附件不能超过 100MB')
|
||||
continue
|
||||
}
|
||||
// app 必须传 creativeAssistant:Dify 的 /files/upload 按应用鉴权,
|
||||
// 用 chat 凭证上传的 file id,工作流会报 Invalid upload file。
|
||||
const uploaded = await uploadAiFile(file, 'creativeAssistant')
|
||||
this.uploadedFiles = [
|
||||
...this.uploadedFiles,
|
||||
{
|
||||
id: uploaded.id,
|
||||
name: uploaded.name || file.name,
|
||||
path: uploaded.path,
|
||||
url: uploaded.url,
|
||||
downloadUrl: uploaded.downloadUrl,
|
||||
contentType: uploaded.contentType
|
||||
}
|
||||
]
|
||||
}
|
||||
this.showToast('附件上传成功')
|
||||
} catch (error) {
|
||||
if (error && error.errMsg && String(error.errMsg).includes('cancel')) {
|
||||
return
|
||||
}
|
||||
this.showToast((error && error.message) || '上传失败')
|
||||
} finally {
|
||||
this.uploading = false
|
||||
uni.hideLoading()
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 请求体。
|
||||
*
|
||||
* 附件已下线:上游出图工具只做文生图,开始节点的 file-list 变量没有节点消费
|
||||
* (见 issue 16),继续传只是让用户白等上传。
|
||||
*
|
||||
* 不传 mode:这是通用创意助手入口,视频/脚本/图片需求都由用户文字说明;
|
||||
* 只有「用户显式选了图片模式」的聊天页才传 mode=image(见 issue 19)。
|
||||
*/
|
||||
buildRequestPayload() {
|
||||
const payload = {
|
||||
user_content: String(this.content || '').trim(),
|
||||
user_contentString: String(this.content || '').trim()
|
||||
const value = String(this.content || '').trim()
|
||||
return {
|
||||
user_content: value,
|
||||
user_contentString: value
|
||||
}
|
||||
if (this.uploadedFiles.length) {
|
||||
payload.user_files = this.uploadedFiles.map((item) => ({
|
||||
transfer_method: 'local_file',
|
||||
type: this.getUploadFileType(item),
|
||||
upload_file_id: item.id,
|
||||
url: ''
|
||||
}))
|
||||
}
|
||||
return payload
|
||||
},
|
||||
async runWorkflow() {
|
||||
if (!this.canSubmit) {
|
||||
this.showToast('请先输入文本指令或上传附件')
|
||||
this.showToast('请先输入文本指令')
|
||||
return
|
||||
}
|
||||
if (this.loading) {
|
||||
@@ -655,54 +531,6 @@
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.upload-bar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.upload-btn {
|
||||
align-self: flex-start;
|
||||
padding: 14rpx 24rpx;
|
||||
border-radius: 20rpx;
|
||||
background: rgba(20, 150, 242, 0.1);
|
||||
color: #1496f2;
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.upload-tip {
|
||||
font-size: 22rpx;
|
||||
line-height: 1.7;
|
||||
color: #88715f;
|
||||
}
|
||||
|
||||
.file-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14rpx;
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
|
||||
.file-item-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12rpx;
|
||||
padding: 18rpx 20rpx;
|
||||
border-radius: 22rpx;
|
||||
background: #f4faff;
|
||||
border: 1rpx solid #d6eafb;
|
||||
}
|
||||
|
||||
.file-main {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.file-badge {
|
||||
flex-shrink: 0;
|
||||
min-width: 72rpx;
|
||||
@@ -715,37 +543,12 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.file-text {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.file-name,
|
||||
.file-url,
|
||||
.result-name {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
color: #3b2c20;
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.file-url {
|
||||
margin-top: 8rpx;
|
||||
color: #8c7462;
|
||||
font-size: 20rpx;
|
||||
}
|
||||
|
||||
.file-remove {
|
||||
flex-shrink: 0;
|
||||
color: #ff4d4f;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
|
||||
.submit-bar,
|
||||
.result-actions {
|
||||
display: grid;
|
||||
|
||||
Reference in New Issue
Block a user