清理: 业务域名注释清零与垫片生产隔离
6 处域名注释改语义化描述,src 下业务域名零残留 垫片 PROD 构建零携带,消息纪年对齐 2026-09,补 ai_list_tools 空返 分离窗口错误文案入 i18n
This commit is contained in:
@@ -42,7 +42,7 @@
|
|||||||
@select="selectMention"
|
@select="selectMention"
|
||||||
@update:mention-index="mentionIndex = $event"
|
@update:mention-index="mentionIndex = $event"
|
||||||
/>
|
/>
|
||||||
<!-- 2026-08-06:📎 图片选择按钮(tauri 原生对话框选图 → file.1216.top 上传 → URL 引用) -->
|
<!-- 2026-08-06:📎 图片选择按钮(tauri 原生对话框选图 → 已配置上传端点则上传换 URL,否则本地 base64 引用) -->
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="ai-img-pick-btn"
|
class="ai-img-pick-btn"
|
||||||
@@ -156,9 +156,9 @@ const inputEl = ref<HTMLTextAreaElement>()
|
|||||||
// - 限制单次最多 6 张(防超长上下文/超限请求);超过 toast 提示。
|
// - 限制单次最多 6 张(防超长上下文/超限请求);超过 toast 提示。
|
||||||
// - 限制单张 10MB(纯文本 base64 估算 ≥ 13M 字符;超限 toast 提示跳过)。
|
// - 限制单张 10MB(纯文本 base64 估算 ≥ 13M 字符;超限 toast 提示跳过)。
|
||||||
// - 仅接受 image/* MIME;非图片(文本粘贴/文件拖入)走原生行为不拦。
|
// - 仅接受 image/* MIME;非图片(文本粘贴/文件拖入)走原生行为不拦。
|
||||||
// - 2026-08-06:新增"📎 图片"按钮(tauri dialog 选图)→ 优先上传 file.1216.top 拿 URL
|
// - 2026-08-06:新增"📎 图片"按钮(tauri dialog 选图)→ 已配置上传端点则上传拿 URL
|
||||||
// (走 url 模式,provider 直传/Anthropic 预拉);上传失败回退 base64(dataUrl)。
|
// (走 url 模式,provider 直传/Anthropic 预拉);未配置或上传失败回退 base64(dataUrl)。
|
||||||
// pendingImages 元素 url/dataUrl 二选一:url=file.1216.top 公开地址,dataUrl=base64。
|
// pendingImages 元素 url/dataUrl 二选一:url=上传服务返回的公开地址,dataUrl=base64。
|
||||||
const MAX_PENDING_IMAGES = 6
|
const MAX_PENDING_IMAGES = 6
|
||||||
const MAX_IMAGE_BYTES = 10 * 1024 * 1024 // 10MB(解码后字节上限)
|
const MAX_IMAGE_BYTES = 10 * 1024 * 1024 // 10MB(解码后字节上限)
|
||||||
const pendingImages = ref<{ id: string; dataUrl?: string; url?: string; mediaType: string }[]>([])
|
const pendingImages = ref<{ id: string; dataUrl?: string; url?: string; mediaType: string }[]>([])
|
||||||
@@ -173,7 +173,7 @@ function readImageFile(file: File): Promise<string> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 把 image File 加入 pendingImages;超限/超大小跳过并 toast。优先上传 file.1216.top 拿 URL,失败回退 base64。 */
|
/** 把 image File 加入 pendingImages;超限/超大小跳过并 toast。已配置端点则上传拿 URL,否则回退 base64。 */
|
||||||
async function addImageFile(file: File): Promise<void> {
|
async function addImageFile(file: File): Promise<void> {
|
||||||
if (!file.type.startsWith('image/')) return
|
if (!file.type.startsWith('image/')) return
|
||||||
if (file.size > MAX_IMAGE_BYTES) {
|
if (file.size > MAX_IMAGE_BYTES) {
|
||||||
@@ -186,8 +186,8 @@ async function addImageFile(file: File): Promise<void> {
|
|||||||
}
|
}
|
||||||
const id = `img-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
|
const id = `img-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
|
||||||
try {
|
try {
|
||||||
// 优先上传 file.1216.top → URL 引用(公开可达,OpenAI 直传 / Anthropic 桌面预拉)。
|
// 已配置上传端点则上传 → URL 引用(公开可达,OpenAI 直传 / Anthropic 桌面预拉)。
|
||||||
// 失败回退 base64(dataUrl),不阻断图片输入。
|
// 未配置或失败回退 base64(dataUrl),不阻断图片输入。
|
||||||
const { url } = await uploadFile(file)
|
const { url } = await uploadFile(file)
|
||||||
pendingImages.value.push({ id, url, mediaType: file.type })
|
pendingImages.value.push({ id, url, mediaType: file.type })
|
||||||
} catch {
|
} catch {
|
||||||
@@ -798,7 +798,7 @@ async function handleSend() {
|
|||||||
// 空文本则只发图片片)
|
// 空文本则只发图片片)
|
||||||
...(text ? [{ type: 'text' as const, text }] : []),
|
...(text ? [{ type: 'text' as const, text }] : []),
|
||||||
...snapshotImgs.map(img => {
|
...snapshotImgs.map(img => {
|
||||||
// url 模式(file.1216.top 上传):直传 url,provider 直传 / Anthropic 预拉。
|
// url 模式(已配置上传端点时上传所得):直传 url,provider 直传 / Anthropic 预拉。
|
||||||
if (img.url) {
|
if (img.url) {
|
||||||
return {
|
return {
|
||||||
type: 'image' as const,
|
type: 'image' as const,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export default {
|
|||||||
refreshing: 'Refreshing…',
|
refreshing: 'Refreshing…',
|
||||||
// Detach window
|
// Detach window
|
||||||
detachTitle: 'File Explorer',
|
detachTitle: 'File Explorer',
|
||||||
|
missingProjectId: 'Missing projectId parameter, cannot open the file explorer',
|
||||||
// File tree
|
// File tree
|
||||||
loading: 'Loading…',
|
loading: 'Loading…',
|
||||||
emptyDir: 'Empty directory',
|
emptyDir: 'Empty directory',
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export default {
|
|||||||
refreshing: '刷新中…',
|
refreshing: '刷新中…',
|
||||||
// 分离窗口
|
// 分离窗口
|
||||||
detachTitle: '文件浏览器',
|
detachTitle: '文件浏览器',
|
||||||
|
missingProjectId: '缺少 projectId 参数,无法打开文件浏览器',
|
||||||
// 文件树
|
// 文件树
|
||||||
loading: '加载中…',
|
loading: '加载中…',
|
||||||
emptyDir: '空目录',
|
emptyDir: '空目录',
|
||||||
|
|||||||
+19
-11
@@ -8,7 +8,8 @@
|
|||||||
//! (生产 devflow.db 与开发 devflow-dev.db 均不接触),无文件系统与网络访问。
|
//! (生产 devflow.db 与开发 devflow-dev.db 均不接触),无文件系统与网络访问。
|
||||||
//!
|
//!
|
||||||
//! 桌面壳影响面:Tauri 壳内 __TAURI_INTERNALS__ 已由宿主注入,整个模块立即返回,
|
//! 桌面壳影响面:Tauri 壳内 __TAURI_INTERNALS__ 已由宿主注入,整个模块立即返回,
|
||||||
//! 桌面应用零行为变化。
|
//! 桌面应用零行为变化。生产构建同样零影响:install() 首行判 PROD 直接返回,
|
||||||
|
//! 线上包不携带假数据注入(垫片仅供 dev/e2e 浏览器环境)。
|
||||||
|
|
||||||
// 对齐 @tauri-apps/api v2.11 实际访问面(mocks.js 官方 mock 同款字段集)
|
// 对齐 @tauri-apps/api v2.11 实际访问面(mocks.js 官方 mock 同款字段集)
|
||||||
interface TauriInternals {
|
interface TauriInternals {
|
||||||
@@ -37,6 +38,10 @@ interface AiConversationSummaryFixture {
|
|||||||
updated_at: string
|
updated_at: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 消息时间戳纪年基准,与会话摘要(2026-09/10)对齐;相邻消息以毫秒偏移保持原时序
|
||||||
|
const T_CONV1 = Date.parse('2026-09-30T09:00:00Z')
|
||||||
|
const T_CONV2 = Date.parse('2026-09-29T09:00:00Z')
|
||||||
|
|
||||||
// 会话摘要假数据(新到旧排序,一条置顶,标题区分业务场景便于 UI 截图辨认)
|
// 会话摘要假数据(新到旧排序,一条置顶,标题区分业务场景便于 UI 截图辨认)
|
||||||
const CONVERSATIONS: AiConversationSummaryFixture[] = [
|
const CONVERSATIONS: AiConversationSummaryFixture[] = [
|
||||||
{
|
{
|
||||||
@@ -85,13 +90,13 @@ const CONV1_MESSAGES = [
|
|||||||
id: 'msg-mock-u1',
|
id: 'msg-mock-u1',
|
||||||
role: 'user',
|
role: 'user',
|
||||||
content: '汇总一下进行中的任务,并看看相关项目状态',
|
content: '汇总一下进行中的任务,并看看相关项目状态',
|
||||||
timestamp: 1759274400000,
|
timestamp: T_CONV1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'msg-mock-a1',
|
id: 'msg-mock-a1',
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: '',
|
content: '',
|
||||||
timestamp: 1759274402000,
|
timestamp: T_CONV1 + 2000,
|
||||||
tool_calls: [
|
tool_calls: [
|
||||||
{
|
{
|
||||||
id: 'tc-mock-1',
|
id: 'tc-mock-1',
|
||||||
@@ -115,28 +120,28 @@ const CONV1_MESSAGES = [
|
|||||||
role: 'tool',
|
role: 'tool',
|
||||||
tool_call_id: 'tc-mock-1',
|
tool_call_id: 'tc-mock-1',
|
||||||
content: '[{"id":"task-mock-1","title":"编写无头测试基建","status":"in_progress"}]',
|
content: '[{"id":"task-mock-1","title":"编写无头测试基建","status":"in_progress"}]',
|
||||||
timestamp: 1759274403000,
|
timestamp: T_CONV1 + 3000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'msg-mock-t2',
|
id: 'msg-mock-t2',
|
||||||
role: 'tool',
|
role: 'tool',
|
||||||
tool_call_id: 'tc-mock-2',
|
tool_call_id: 'tc-mock-2',
|
||||||
content: '[{"id":"proj-mock-1","name":"DevFlow","status":"in_progress"}]',
|
content: '[{"id":"proj-mock-1","name":"DevFlow","status":"in_progress"}]',
|
||||||
timestamp: 1759274404000,
|
timestamp: T_CONV1 + 4000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'msg-mock-t3',
|
id: 'msg-mock-t3',
|
||||||
role: 'tool',
|
role: 'tool',
|
||||||
tool_call_id: 'tc-mock-3',
|
tool_call_id: 'tc-mock-3',
|
||||||
content: '3',
|
content: '3',
|
||||||
timestamp: 1759274405000,
|
timestamp: T_CONV1 + 5000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'msg-mock-a2',
|
id: 'msg-mock-a2',
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: '进行中的任务共 3 个,均归属 DevFlow 项目。其中「编写无头测试基建」已进入自验阶段,其余两个阻塞在依赖安装上。',
|
content: '进行中的任务共 3 个,均归属 DevFlow 项目。其中「编写无头测试基建」已进入自验阶段,其余两个阻塞在依赖安装上。',
|
||||||
model: 'mock-model',
|
model: 'mock-model',
|
||||||
timestamp: 1759274410000,
|
timestamp: T_CONV1 + 10000,
|
||||||
prompt_tokens: 128,
|
prompt_tokens: 128,
|
||||||
completion_tokens: 96,
|
completion_tokens: 96,
|
||||||
prompt_cache_hit_tokens: 0,
|
prompt_cache_hit_tokens: 0,
|
||||||
@@ -147,14 +152,14 @@ const CONV1_MESSAGES = [
|
|||||||
id: 'msg-mock-u2',
|
id: 'msg-mock-u2',
|
||||||
role: 'user',
|
role: 'user',
|
||||||
content: '把结论整理成三行以内的摘要',
|
content: '把结论整理成三行以内的摘要',
|
||||||
timestamp: 1759274420000,
|
timestamp: T_CONV1 + 20000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'msg-mock-a3',
|
id: 'msg-mock-a3',
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: '1. 进行中任务 3 个,全部属于 DevFlow。\n2. 测试基建项进展最快。\n3. 其余任务等依赖安装完成即可推进。',
|
content: '1. 进行中任务 3 个,全部属于 DevFlow。\n2. 测试基建项进展最快。\n3. 其余任务等依赖安装完成即可推进。',
|
||||||
model: 'mock-model',
|
model: 'mock-model',
|
||||||
timestamp: 1759274425000,
|
timestamp: T_CONV1 + 25000,
|
||||||
prompt_tokens: 96,
|
prompt_tokens: 96,
|
||||||
completion_tokens: 48,
|
completion_tokens: 48,
|
||||||
prompt_cache_hit_tokens: 64,
|
prompt_cache_hit_tokens: 64,
|
||||||
@@ -168,14 +173,14 @@ const OTHER_CONV_MESSAGES = [
|
|||||||
id: 'msg-mock-b1',
|
id: 'msg-mock-b1',
|
||||||
role: 'user',
|
role: 'user',
|
||||||
content: '这是一条演示用的历史消息',
|
content: '这是一条演示用的历史消息',
|
||||||
timestamp: 1759180000000,
|
timestamp: T_CONV2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'msg-mock-b2',
|
id: 'msg-mock-b2',
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: '收到,这是浏览器测试环境的固定回复。',
|
content: '收到,这是浏览器测试环境的固定回复。',
|
||||||
model: 'mock-model',
|
model: 'mock-model',
|
||||||
timestamp: 1759180005000,
|
timestamp: T_CONV2 + 5000,
|
||||||
prompt_tokens: 32,
|
prompt_tokens: 32,
|
||||||
completion_tokens: 16,
|
completion_tokens: 16,
|
||||||
prompt_cache_hit_tokens: 0,
|
prompt_cache_hit_tokens: 0,
|
||||||
@@ -238,6 +243,7 @@ const LIST_COMMANDS = new Set([
|
|||||||
'knowledge_events',
|
'knowledge_events',
|
||||||
'ai_get_allowed_dirs',
|
'ai_get_allowed_dirs',
|
||||||
'ai_pending_tool_calls',
|
'ai_pending_tool_calls',
|
||||||
|
'ai_list_tools',
|
||||||
])
|
])
|
||||||
|
|
||||||
// 返回固定标量的命令
|
// 返回固定标量的命令
|
||||||
@@ -291,6 +297,8 @@ function buildHandlers(): Record<string, (args: Record<string, unknown>) => unkn
|
|||||||
}
|
}
|
||||||
|
|
||||||
function install(): void {
|
function install(): void {
|
||||||
|
// 生产包不注入:假数据仅服务 dev/e2e 浏览器环境,线上零携带
|
||||||
|
if (import.meta.env.PROD) return
|
||||||
const internals = window as unknown as Record<string, unknown>
|
const internals = window as unknown as Record<string, unknown>
|
||||||
|
|
||||||
// 壳内已有宿主注入,立即退出保证桌面零影响;防重复注入(热更新场景幂等)
|
// 壳内已有宿主注入,立即退出保证桌面零影响;防重复注入(热更新场景幂等)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<FileExplorer v-if="projectId" :project-id="projectId" />
|
<FileExplorer v-if="projectId" :project-id="projectId" />
|
||||||
<div v-else class="fe-detached-error">
|
<div v-else class="fe-detached-error">
|
||||||
<span class="fe-detached-error-icon">⚠️</span>
|
<span class="fe-detached-error-icon">⚠️</span>
|
||||||
<p>缺少 projectId 参数,无法打开文件浏览器</p>
|
<p>{{ $t('fileExplorer.missingProjectId') }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user