fix: session persistence, multi-turn memory, OCR pipeline, download UX (v7)
- graph.stream() state fix: agent_state now properly accumulates node updates - atomic session save (tempfile + os.replace) - uploaded_file_path injection for OcrExtractor + annotation_detector - download section always visible; refreshFromApi auto-reloads after generation - node_start/complete unfiltered for full progress visibility - modification_request without status=='pass' check
This commit is contained in:
@@ -98,12 +98,12 @@ async function handleSend(text: string, files: File[]) {
|
||||
}
|
||||
|
||||
// Refresh session sidebar data after a short delay
|
||||
setTimeout(() => session.refreshFromState({}), 500)
|
||||
setTimeout(() => session.refreshFromApi(), 500)
|
||||
},
|
||||
onAgentError(data) {
|
||||
chat.setError(data.error)
|
||||
chat.addMessage({ role: 'assistant', content: `执行异常: ${data.error}`, type: 'error' })
|
||||
setTimeout(() => session.refreshFromState({}), 500)
|
||||
setTimeout(() => session.refreshFromApi(), 500)
|
||||
},
|
||||
})
|
||||
} catch (e: any) {
|
||||
|
||||
@@ -99,7 +99,7 @@ async function handleDelete() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-section" v-if="session.currentJrxml || session.versions.length > 0">
|
||||
<div class="sidebar-section">
|
||||
<div class="section-title">下载</div>
|
||||
<a
|
||||
v-if="session.currentJrxml"
|
||||
@@ -109,6 +109,7 @@ async function handleDelete() {
|
||||
>
|
||||
下载最新 JRXML
|
||||
</a>
|
||||
<div v-else class="btn-download disabled">暂无下载文件</div>
|
||||
<div v-if="session.versions.length > 1" class="version-list">
|
||||
<div class="version-list-title">历史版本</div>
|
||||
<a
|
||||
@@ -181,178 +182,130 @@ async function handleDelete() {
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
line-height: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.btn-icon:hover {
|
||||
background: #45475a;
|
||||
}
|
||||
.btn-icon:hover { background: #45475a; }
|
||||
|
||||
.session-list {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.session-item {
|
||||
padding: 8px 16px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 13px;
|
||||
padding: 8px 8px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
|
||||
.session-item:hover {
|
||||
background: #313244;
|
||||
}
|
||||
|
||||
.session-item.active {
|
||||
background: #45475a;
|
||||
border-left: 3px solid #cba6f7;
|
||||
padding-left: 13px;
|
||||
}
|
||||
.session-item:hover { background: #313244; }
|
||||
.session-item.active { background: #45475a; }
|
||||
|
||||
.session-name {
|
||||
font-size: 13px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 150px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.session-time {
|
||||
font-size: 11px;
|
||||
color: #6c7086;
|
||||
margin-left: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.btn-delete {
|
||||
display: block;
|
||||
width: calc(100% - 32px);
|
||||
margin: 8px 16px 0;
|
||||
padding: 6px 12px;
|
||||
border: 1px solid #f38ba8;
|
||||
background: transparent;
|
||||
width: calc(100% - 16px);
|
||||
margin: 8px 8px 0;
|
||||
padding: 6px 0;
|
||||
border: 1px solid #45475a;
|
||||
background: none;
|
||||
color: #f38ba8;
|
||||
border-radius: 6px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.btn-delete:hover {
|
||||
background: #f38ba8;
|
||||
color: #1e1e2e;
|
||||
}
|
||||
.btn-delete:hover { background: #45475a; }
|
||||
|
||||
.quick-actions {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
gap: 8px;
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.btn-action {
|
||||
flex: 1;
|
||||
padding: 6px 8px;
|
||||
padding: 6px 0;
|
||||
border: 1px solid #45475a;
|
||||
background: #313244;
|
||||
color: #cdd6f4;
|
||||
border-radius: 6px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
transition: background 0.15s, border-color 0.15s;
|
||||
}
|
||||
|
||||
.btn-action:hover:not(:disabled) {
|
||||
background: #45475a;
|
||||
}
|
||||
|
||||
.btn-action:disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.btn-preview {
|
||||
border-color: #89b4fa;
|
||||
}
|
||||
|
||||
.btn-preview:hover:not(:disabled) {
|
||||
background: #89b4fa;
|
||||
color: #1e1e2e;
|
||||
}
|
||||
|
||||
.btn-undo {
|
||||
border-color: #f9e2af;
|
||||
}
|
||||
|
||||
.btn-undo:hover:not(:disabled) {
|
||||
background: #f9e2af;
|
||||
color: #1e1e2e;
|
||||
}
|
||||
|
||||
.btn-reset {
|
||||
border-color: #f38ba8;
|
||||
}
|
||||
|
||||
.btn-reset:hover:not(:disabled) {
|
||||
background: #f38ba8;
|
||||
color: #1e1e2e;
|
||||
color: #cdd6f4;
|
||||
background: none;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
.btn-action:hover:not(:disabled) { background: #45475a; }
|
||||
.btn-action:disabled { opacity: 0.4; cursor: not-allowed; }
|
||||
.btn-preview { border-color: #a6e3a1; color: #a6e3a1; }
|
||||
.btn-undo { border-color: #f9e2af; color: #f9e2af; }
|
||||
.btn-reset { border-color: #f38ba8; color: #f38ba8; }
|
||||
|
||||
.btn-download {
|
||||
display: block;
|
||||
padding: 8px 16px;
|
||||
color: #a6e3a1;
|
||||
margin: 4px 16px;
|
||||
padding: 8px 0;
|
||||
background: #cba6f7;
|
||||
color: #1e1e2e;
|
||||
text-align: center;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-download:hover {
|
||||
.btn-download:hover { background: #b4befe; }
|
||||
.btn-download.disabled {
|
||||
background: #313244;
|
||||
color: #6c7086;
|
||||
cursor: not-allowed;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.version-list {
|
||||
padding: 4px 16px 8px;
|
||||
margin-top: 8px;
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.version-list-title {
|
||||
font-size: 11px;
|
||||
color: #6c7086;
|
||||
margin-bottom: 4px;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid #313244;
|
||||
}
|
||||
|
||||
.version-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 4px 0;
|
||||
font-size: 12px;
|
||||
color: #a6adc8;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.version-item:hover {
|
||||
color: #cdd6f4;
|
||||
}
|
||||
|
||||
.version-label {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.version-time {
|
||||
font-size: 11px;
|
||||
color: #6c7086;
|
||||
flex-shrink: 0;
|
||||
margin-left: 8px;
|
||||
}
|
||||
.version-item:hover { color: #cba6f7; }
|
||||
.version-time { font-size: 11px; color: #6c7086; }
|
||||
|
||||
.sidebar-footer {
|
||||
margin-top: auto;
|
||||
padding: 12px 16px;
|
||||
font-size: 11px;
|
||||
color: #6c7086;
|
||||
color: #585b70;
|
||||
border-top: 1px solid #313244;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -63,6 +63,19 @@ export const useSessionStore = defineStore('session', () => {
|
||||
versions.value = []
|
||||
}
|
||||
|
||||
async function refreshFromApi() {
|
||||
if (!currentId.value) return
|
||||
try {
|
||||
const data = await api.getSession(currentId.value)
|
||||
const state = data.agent_state
|
||||
currentJrxml.value = state.current_jrxml || ''
|
||||
versions.value = state.jrxml_versions || []
|
||||
historyStates.value = state.history_states || []
|
||||
} catch (e) {
|
||||
console.error('刷新会话状态失败:', e)
|
||||
}
|
||||
}
|
||||
|
||||
function refreshFromState(agentState: Record<string, any>) {
|
||||
currentJrxml.value = agentState.current_jrxml || currentJrxml.value
|
||||
versions.value = agentState.jrxml_versions || versions.value
|
||||
@@ -72,6 +85,6 @@ export const useSessionStore = defineStore('session', () => {
|
||||
return {
|
||||
sessions, currentId, currentName, versions, historyStates, currentJrxml,
|
||||
hasJrxml, hasHistory, sortedSessions, currentSession,
|
||||
loadSessions, createSession, switchSession, deleteCurrent, refreshFromState,
|
||||
loadSessions, createSession, switchSession, deleteCurrent, refreshFromState, refreshFromApi,
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user