优化: 图片上传默认本地化,业务域名出代码
- 默认上传端点清空,未配置即本地base64内嵌,不再默认传业务文件服务 - 高级设置新增文件上传端点配置行,配置后启用上传(自定义服务协议不变) - 同步清理注释内域名残留;小程序端同款硬编码已报备待后续处理
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
//! 图片输入预览 — 待发送图片缩略图列表,从 ChatInput.vue 提取
|
//! 图片输入预览 — 待发送图片缩略图列表,从 ChatInput.vue 提取
|
||||||
//!
|
//!
|
||||||
//! 职责:显示待发送图片缩略图、移除按钮。不含图片读取/粘贴/拖拽逻辑。
|
//! 职责:显示待发送图片缩略图、移除按钮。不含图片读取/粘贴/拖拽逻辑。
|
||||||
//! 2026-08-06:支持 url 模式(file.1216.top 上传)与 dataUrl 模式(base64)双预览。
|
//! 2026-08-06:支持 url 模式(文件服务上传)与 dataUrl 模式(base64)双预览。
|
||||||
|
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<span class="setting-desc">{{ $t('settings.descApprovalTimeout') }}</span>
|
<span class="setting-desc">{{ $t('settings.descApprovalTimeout') }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 文件上传服务端点:配置后聊天图片上传到用户自己的文件服务转公开 URL;留空则图片本地 base64 内嵌。
|
||||||
|
与 fileUpload.ts 的读取约定同 key(df-file-upload-base),blur/enter 提交即落库生效 -->
|
||||||
|
<SettingRow ref="rowUploadBase" :label="$t('settings.labelFileUploadBase')" :desc="$t('settings.descFileUploadBase')">
|
||||||
|
<input
|
||||||
|
v-model="fileUploadBase"
|
||||||
|
class="setting-input upload-base-input"
|
||||||
|
:placeholder="$t('settings.placeholderFileUploadBase')"
|
||||||
|
@change="onUploadBaseChange"
|
||||||
|
/>
|
||||||
|
</SettingRow>
|
||||||
|
|
||||||
<!-- 自定义提示词:注入到 AI 系统 prompt 末尾,用户可自定义 AI 行为偏好 -->
|
<!-- 自定义提示词:注入到 AI 系统 prompt 末尾,用户可自定义 AI 行为偏好 -->
|
||||||
<!-- 布局:整行堆叠——label/desc 在上,textarea 独立一行从左到右拉满(而非 label 左 + 框右) -->
|
<!-- 布局:整行堆叠——label/desc 在上,textarea 独立一行从左到右拉满(而非 label 左 + 框右) -->
|
||||||
<SettingRow ref="rowCustomPrompt" class="prompt-row" :label="$t('settings.labelCustomPrompt')" :desc="$t('settings.descCustomPrompt')">
|
<SettingRow ref="rowCustomPrompt" class="prompt-row" :label="$t('settings.labelCustomPrompt')" :desc="$t('settings.descCustomPrompt')">
|
||||||
@@ -156,6 +167,17 @@ const customPrompt = ref(appSettings.get<string>('custom_prompt', ''))
|
|||||||
// 三个 select 行改为自定义布局(不复用 SettingRow),saved-hint 由本地 savedVisible 状态驱动
|
// 三个 select 行改为自定义布局(不复用 SettingRow),saved-hint 由本地 savedVisible 状态驱动
|
||||||
const rowCustomPrompt = useTemplateRef<InstanceType<typeof SettingRow>>('rowCustomPrompt')
|
const rowCustomPrompt = useTemplateRef<InstanceType<typeof SettingRow>>('rowCustomPrompt')
|
||||||
|
|
||||||
|
// 文件上传服务端点:与 fileUpload.ts 同 key(df-file-upload-base)。留空即不上传(图片本地 base64),
|
||||||
|
// 配置后下次发图即走该服务;trim 提交防空格误配
|
||||||
|
const rowUploadBase = useTemplateRef<InstanceType<typeof SettingRow>>('rowUploadBase')
|
||||||
|
const fileUploadBase = ref(appSettings.get<string>('df-file-upload-base', ''))
|
||||||
|
|
||||||
|
function onUploadBaseChange() {
|
||||||
|
fileUploadBase.value = fileUploadBase.value.trim()
|
||||||
|
appSettings.set('df-file-upload-base', fileUploadBase.value)
|
||||||
|
rowUploadBase.value?.markSaved()
|
||||||
|
}
|
||||||
|
|
||||||
// 「已保存」提示可见性(2s 自动隐藏),key 对齐模板三行
|
// 「已保存」提示可见性(2s 自动隐藏),key 对齐模板三行
|
||||||
const savedVisible = reactive<Record<string, boolean>>({
|
const savedVisible = reactive<Record<string, boolean>>({
|
||||||
autoExecute: false,
|
autoExecute: false,
|
||||||
@@ -242,6 +264,11 @@ function onApprovalTimeoutChange() {
|
|||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
/* 端点输入走等宽字体(URL 逐字符核对更易读),对齐 AllowedDirsPanel 路径输入风格 */
|
||||||
|
.upload-base-input {
|
||||||
|
min-width: 280px;
|
||||||
|
font-family: var(--df-font-mono, monospace);
|
||||||
|
}
|
||||||
/* 自定义提示词行:整行堆叠,textarea 独立一行从左到右拉满。
|
/* 自定义提示词行:整行堆叠,textarea 独立一行从左到右拉满。
|
||||||
覆盖 SettingRow 默认横排(label 左 + control 右)。 */
|
覆盖 SettingRow 默认横排(label 左 + control 右)。 */
|
||||||
.prompt-row {
|
.prompt-row {
|
||||||
|
|||||||
@@ -90,5 +90,6 @@ export const SETTINGS_INDEX: SettingIndexEntry[] = [
|
|||||||
{ category: 'advanced', key: 'autoExecuteMode', labelKey: 'settings.labelAutoExecute', descKey: 'settings.descAutoExecute' },
|
{ category: 'advanced', key: 'autoExecuteMode', labelKey: 'settings.labelAutoExecute', descKey: 'settings.descAutoExecute' },
|
||||||
{ category: 'advanced', key: 'logLevel', labelKey: 'settings.labelLogLevel', descKey: 'settings.descLogLevel' },
|
{ category: 'advanced', key: 'logLevel', labelKey: 'settings.labelLogLevel', descKey: 'settings.descLogLevel' },
|
||||||
{ category: 'advanced', key: 'approvalTimeout', labelKey: 'settings.labelApprovalTimeout', descKey: 'settings.descApprovalTimeout' },
|
{ category: 'advanced', key: 'approvalTimeout', labelKey: 'settings.labelApprovalTimeout', descKey: 'settings.descApprovalTimeout' },
|
||||||
|
{ category: 'advanced', key: 'fileUploadBase', labelKey: 'settings.labelFileUploadBase', descKey: 'settings.descFileUploadBase' },
|
||||||
{ category: 'advanced', key: 'connection', labelKey: 'settings.panelConnection', descKey: 'settings.emptyConnection' },
|
{ category: 'advanced', key: 'connection', labelKey: 'settings.panelConnection', descKey: 'settings.emptyConnection' },
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
//! 桌面端文件服务上传(file.1216.top)— 图片/文件 → 公开 URL
|
//! 桌面端文件服务上传:可配置端点 POST /upload(multipart 'file' + X-Source 头),图片/文件转公开 URL。
|
||||||
|
//! 默认不配置上传服务,图片走本地引用(base64);在设置页配置端点后启用上传。
|
||||||
|
//! 未配置时 uploadFile 直接 reject,调用方(ChatInput)catch 后回退本地 base64,不阻断图片输入。
|
||||||
//!
|
//!
|
||||||
//! 与小程序端 `apps/df-miniapp/src/utils/fileUpload.ts` 对称:复用 file.1216.top 的
|
//! 与小程序端 `apps/df-miniapp/src/utils/fileUpload.ts` 对称:桌面端是浏览器环境,
|
||||||
//! `POST /upload`(multipart 'file' + X-Source 头)→ 返回公开 URL。
|
//! 用 fetch + FormData(区别于小程序 uni.uploadFile)。端点需支持 CORS 与该响应结构:
|
||||||
//! 桌面端是浏览器环境,用 fetch + FormData(区别于小程序 uni.uploadFile)。
|
//! `{"result":{"url":"..."},"retcode":0,"success":true}`。
|
||||||
//! file.1216.top 已确认 CORS 支持(`Access-Control-Allow-Origin: *`,X-Source 在 allow-headers)。
|
|
||||||
|
|
||||||
/** file.1216.top 上传地址(可经 appSettings 'df-file-upload-base' 覆盖) */
|
import { useAppSettingsStore } from '../../stores/appSettings'
|
||||||
export const DEFAULT_FILE_UPLOAD_BASE = 'https://file.1216.top'
|
|
||||||
/** X-Source 项目标识(文件存 file.1216.top 对应目录,项目隔离) */
|
/** 上传服务根地址,默认空串:不配置上传服务,图片走本地引用;设置页 df-file-upload-base 可覆盖 */
|
||||||
|
export const DEFAULT_FILE_UPLOAD_BASE = ''
|
||||||
|
/** X-Source 项目标识(服务端按来源目录隔离文件) */
|
||||||
export const FILE_UPLOAD_SOURCE = 'devflow-desktop'
|
export const FILE_UPLOAD_SOURCE = 'devflow-desktop'
|
||||||
|
|
||||||
export interface UploadResult {
|
export interface UploadResult {
|
||||||
@@ -15,11 +18,15 @@ export interface UploadResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传文件到 file.1216.top,返回公开 URL。失败 reject(调用方回退 base64)。
|
* 上传文件到文件服务,返回公开 URL。未配置端点或上传失败时 reject,调用方回退 base64。
|
||||||
* 响应结构:`{"result":{"url":"https://..."},"retcode":0,"success":true}`
|
* 端点取值:入参 base 优先,其次设置项 df-file-upload-base,最后 DEFAULT_FILE_UPLOAD_BASE(空)。
|
||||||
*/
|
*/
|
||||||
export async function uploadFile(file: File, base?: string): Promise<UploadResult> {
|
export async function uploadFile(file: File, base?: string): Promise<UploadResult> {
|
||||||
const uploadBase = base || DEFAULT_FILE_UPLOAD_BASE
|
const configured = useAppSettingsStore().get<string>('df-file-upload-base', '')
|
||||||
|
const uploadBase = (base || configured || DEFAULT_FILE_UPLOAD_BASE).trim()
|
||||||
|
if (!uploadBase) {
|
||||||
|
throw new Error('未配置文件上传服务端点')
|
||||||
|
}
|
||||||
const form = new FormData()
|
const form = new FormData()
|
||||||
form.append('file', file, file.name)
|
form.append('file', file, file.name)
|
||||||
const res = await fetch(`${uploadBase}/upload`, {
|
const res = await fetch(`${uploadBase}/upload`, {
|
||||||
|
|||||||
@@ -162,6 +162,11 @@ export default {
|
|||||||
descCustomPrompt: 'Appended to the AI system prompt to customize AI behavior',
|
descCustomPrompt: 'Appended to the AI system prompt to customize AI behavior',
|
||||||
placeholderCustomPrompt: 'e.g.: You specialize in Rust development questions...',
|
placeholderCustomPrompt: 'e.g.: You specialize in Rust development questions...',
|
||||||
|
|
||||||
|
// File upload endpoint
|
||||||
|
labelFileUploadBase: 'File upload endpoint',
|
||||||
|
descFileUploadBase: 'When set, chat images are uploaded to your own file service and turned into public URLs; leave empty to embed images locally (base64)',
|
||||||
|
placeholderFileUploadBase: 'e.g.: https://your-file-service.example.com',
|
||||||
|
|
||||||
labelStreamingMd: 'Streaming Markdown rendering',
|
labelStreamingMd: 'Streaming Markdown rendering',
|
||||||
descStreamingMd: 'Render code blocks/lists/headings during streaming (unclosed code blocks degrade to plain text to avoid flicker); when off, only plain text is shown during streaming and full formatting applies after generation completes',
|
descStreamingMd: 'Render code blocks/lists/headings during streaming (unclosed code blocks degrade to plain text to avoid flicker); when off, only plain text is shown during streaming and full formatting applies after generation completes',
|
||||||
|
|
||||||
|
|||||||
@@ -161,6 +161,11 @@ export default {
|
|||||||
descCustomPrompt: '追加到 AI 系统提示词末尾,可自定义 AI 行为偏好',
|
descCustomPrompt: '追加到 AI 系统提示词末尾,可自定义 AI 行为偏好',
|
||||||
placeholderCustomPrompt: '例如:你擅长回答 Rust 开发问题...',
|
placeholderCustomPrompt: '例如:你擅长回答 Rust 开发问题...',
|
||||||
|
|
||||||
|
// 文件上传服务端点
|
||||||
|
labelFileUploadBase: '文件上传服务端点',
|
||||||
|
descFileUploadBase: '配置后聊天图片上传到你的文件服务并转为公开 URL;留空则图片以本地方式内嵌(base64)',
|
||||||
|
placeholderFileUploadBase: '例如:https://your-file-service.example.com',
|
||||||
|
|
||||||
labelStreamingMd: '流式 Markdown 渲染',
|
labelStreamingMd: '流式 Markdown 渲染',
|
||||||
descStreamingMd: '流式生成过程中渲染代码块/列表/标题格式(未闭合代码块降级纯文本防闪烁);关闭后流式期间仅显纯文本,生成完成后才渲染完整格式',
|
descStreamingMd: '流式生成过程中渲染代码块/列表/标题格式(未闭合代码块降级纯文本防闪烁);关闭后流式期间仅显纯文本,生成完成后才渲染完整格式',
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user