|
|
@@ -185,19 +185,16 @@ function renderRawCases(rawCasesObj) {
|
|
|
cd.cases.forEach(c => {
|
|
|
const cId = c.case_id || (c._raw && c._raw.case_id);
|
|
|
const cUrl = c.source_url || c.url;
|
|
|
- const uniqueKey = cId || cUrl || Math.random().toString();
|
|
|
- uniqueCases.add(uniqueKey);
|
|
|
-
|
|
|
- if (c.workflow) uniqueWorkflow.add(uniqueKey);
|
|
|
- if (c.capabilities && c.capabilities.length > 0) uniqueCapabilities.add(uniqueKey);
|
|
|
+ if (c.workflow) calcWorkflow++;
|
|
|
+ if (c.capability && c.capability.length > 0) calcCapabilities++;
|
|
|
|
|
|
if (cId) {
|
|
|
if (c.workflow) detailMap[cId] = { ...detailMap[cId], workflow: c.workflow };
|
|
|
- if (c.capabilities) detailMap[cId] = { ...detailMap[cId], capabilities: c.capabilities };
|
|
|
+ if (c.capability) detailMap[cId] = { ...detailMap[cId], capability: c.capability };
|
|
|
}
|
|
|
if (cUrl) {
|
|
|
if (c.workflow) detailMapByUrl[cUrl] = { ...detailMapByUrl[cUrl], workflow: c.workflow };
|
|
|
- if (c.capabilities) detailMapByUrl[cUrl] = { ...detailMapByUrl[cUrl], capabilities: c.capabilities };
|
|
|
+ if (c.capability) detailMapByUrl[cUrl] = { ...detailMapByUrl[cUrl], capability: c.capability };
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
@@ -1112,7 +1109,7 @@ function renderAggregatedPerCaseData(cases, type) {
|
|
|
if (type === 'workflow') {
|
|
|
items = c.workflow ? [c.workflow] : null;
|
|
|
} else if (type === 'capabilities') {
|
|
|
- items = c.capabilities && Array.isArray(c.capabilities) ? c.capabilities : null;
|
|
|
+ items = c.capability && Array.isArray(c.capability) ? c.capability : null;
|
|
|
}
|
|
|
|
|
|
const targetId = `case-${type}-${idx}`;
|
|
|
@@ -1146,7 +1143,7 @@ function renderAggregatedPerCaseData(cases, type) {
|
|
|
|
|
|
contentHtml += `<div id="${targetId}" class="case-section" style="margin-bottom: 3.5rem; padding-top: 1rem;">`;
|
|
|
|
|
|
- const stepName = type === 'workflow' ? 'workflow-extract' : 'capability-extract';
|
|
|
+ const stepName = 'workflow-extract';
|
|
|
const caseIndexToPass = c.index || (idx + 1);
|
|
|
const btnHtml = `<button class="btn btn-secondary" style="font-size: 0.85em; padding: 0.4rem 0.8rem; border-radius: 4px;" onclick="event.stopPropagation(); triggerSingleCaseRerun('${stepName}', ${caseIndexToPass})">🔄 重跑${typeLabel}</button>`;
|
|
|
|
|
|
@@ -2194,7 +2191,7 @@ window.openCaseDetail = function (p, initialIdx) {
|
|
|
let metaHtml = '';
|
|
|
const wf = ctx.detailMap[cId] || (cUrl ? ctx.detailMapByUrl[cUrl] : null) || c;
|
|
|
if (wf && wf.workflow && wf.workflow.steps) metaHtml += `<span>工序 ${wf.workflow.steps.length}</span>`;
|
|
|
- if (wf && wf.capabilities) metaHtml += `<span>能力 ${wf.capabilities.length}</span>`;
|
|
|
+ if (wf && wf.capability) metaHtml += `<span>能力 ${wf.capability.length}</span>`;
|
|
|
if (!metaHtml) metaHtml = '<span>无提取</span>';
|
|
|
|
|
|
sidebarHtml += `<div class="modal-sidebar-item ${idx === globalInitialIdx ? 'active' : ''}" id="sidebar-item-${idx}" onclick="window.renderSingleCaseDetail(${idx})">
|
|
|
@@ -2390,7 +2387,7 @@ window.renderSingleCaseDetail = function (idx) {
|
|
|
);
|
|
|
const caseIndexToPass = realCaseIndex >= 0 ? (caseJsonCases[realCaseIndex].index || (realCaseIndex + 1)) : -1;
|
|
|
const btnWorkflowHtml = caseIndexToPass !== -1 ? `<button class="btn btn-secondary" style="font-size: 0.8em; padding: 0.3rem 0.6rem; border-radius: 4px;" onclick="event.stopPropagation(); triggerSingleCaseRerun('workflow-extract', ${caseIndexToPass})">🔄 重跑工序</button>` : '';
|
|
|
- const btnCapabilityHtml = caseIndexToPass !== -1 ? `<button class="btn btn-secondary" style="font-size: 0.8em; padding: 0.3rem 0.6rem; border-radius: 4px;" onclick="event.stopPropagation(); triggerSingleCaseRerun('capability-extract', ${caseIndexToPass})">🔄 重跑能力</button>` : '';
|
|
|
+ const btnCapabilityHtml = caseIndexToPass !== -1 ? `<button class="btn btn-secondary" style="font-size: 0.8em; padding: 0.3rem 0.6rem; border-radius: 4px;" onclick="event.stopPropagation(); triggerSingleCaseRerun('workflow-extract', ${caseIndexToPass})">🔄 重跑能力</button>` : '';
|
|
|
|
|
|
mainScrollableHtml += `
|
|
|
<div class="case-section" style="margin-top: 2rem;">
|
|
|
@@ -2415,7 +2412,7 @@ window.renderSingleCaseDetail = function (idx) {
|
|
|
${btnCapabilityHtml}
|
|
|
</div>
|
|
|
<div class="hidden" style="padding-top: 1.2rem;">
|
|
|
- ${window.renderStructuredData(wf && wf.capabilities ? wf.capabilities : null, 'capabilities', wf)}
|
|
|
+ ${window.renderStructuredData(wf && wf.capability ? wf.capability : null, 'capabilities', wf)}
|
|
|
</div>
|
|
|
</div>
|
|
|
`;
|
|
|
@@ -2464,23 +2461,16 @@ window.renderStructuredData = function (items, type, parentItem = null) {
|
|
|
const hasValidIO = (arr) => Array.isArray(arr) && arr.length > 0 && (arr[0].role || arr[0].description);
|
|
|
if (hasValidIO(item.inputs) || hasValidIO(item.outputs) || (item.steps && item.steps.length > 0)) {
|
|
|
let actionStr = '';
|
|
|
- if (item.action && typeof item.action === 'string') {
|
|
|
- actionStr = item.action;
|
|
|
- } else if (item.action && item.action.main_action) {
|
|
|
- actionStr = item.action.main_action;
|
|
|
- } else if (item.body) {
|
|
|
- actionStr = item.body.length > 20 ? item.body.substring(0, 20) + '...' : item.body;
|
|
|
+ if (item.action && item.action.description) {
|
|
|
+ actionStr = item.action.description;
|
|
|
} else if (item.method && !item.method.includes('[')) {
|
|
|
actionStr = item.method;
|
|
|
} else if (item.steps && Array.isArray(item.steps)) {
|
|
|
const hasAnyValidIO = item.steps.some(s => hasValidIO(s.inputs) || hasValidIO(s.outputs) || s.body);
|
|
|
if (hasAnyValidIO) {
|
|
|
actionStr = item.steps.map(s => {
|
|
|
- if (s.action && typeof s.action === 'string') {
|
|
|
- return s.action;
|
|
|
- }
|
|
|
- if (s.action && s.action.main_action) {
|
|
|
- return s.action.mechanism ? `[${s.action.main_action}] ${s.action.mechanism}` : s.action.main_action;
|
|
|
+ if (s.action && s.action.description) {
|
|
|
+ return s.action.description;
|
|
|
}
|
|
|
if (s.body) return s.body.length > 20 ? s.body.substring(0, 20) + '...' : s.body;
|
|
|
if (s.method) return s.method;
|
|
|
@@ -2500,12 +2490,8 @@ window.renderStructuredData = function (items, type, parentItem = null) {
|
|
|
} else {
|
|
|
const escapeHtml = (s) => String(s).replace(/</g, '<').replace(/>/g, '>');
|
|
|
title = escapeHtml(item.method || item.name || '');
|
|
|
- if (!title && item.action && typeof item.action === 'string') {
|
|
|
- title = escapeHtml(item.action);
|
|
|
- }
|
|
|
- if (!title && item.action && item.action.main_action) {
|
|
|
- const actText = item.action.mechanism ? `[${item.action.main_action}] ${item.action.mechanism}` : item.action.main_action;
|
|
|
- title = escapeHtml(actText);
|
|
|
+ if (!title && item.action && item.action.description) {
|
|
|
+ title = escapeHtml(item.action.description);
|
|
|
}
|
|
|
if (!title && item.body) {
|
|
|
const actText = item.body.length > 50 ? item.body.substring(0, 50) + '...' : item.body;
|
|
|
@@ -2643,6 +2629,18 @@ window.renderStructuredData = function (items, type, parentItem = null) {
|
|
|
</div>`;
|
|
|
}
|
|
|
|
|
|
+ if (item.action && typeof item.action === 'object' && (item.action.description || item.action.reasoning)) {
|
|
|
+ const actionDescription = item.action.description ? String(item.action.description).replace(/</g, '<').replace(/>/g, '>') : '';
|
|
|
+ const actionReasoning = item.action.reasoning ? String(item.action.reasoning).replace(/</g, '<').replace(/>/g, '>') : '';
|
|
|
+ html += `<div class="structured-row">
|
|
|
+ <div class="structured-label">action</div>
|
|
|
+ <div class="structured-value">
|
|
|
+ ${actionDescription ? `<span class="data-type-badge" style="background:#e0e7ff;color:#3730a3;font-weight:normal;margin-right:6px;">${actionDescription}</span>` : ''}
|
|
|
+ ${actionReasoning ? `<span style="color:var(--text-secondary);">${actionReasoning}</span>` : ''}
|
|
|
+ </div>
|
|
|
+ </div>`;
|
|
|
+ }
|
|
|
+
|
|
|
// Stage rendering removed per request
|
|
|
// Render effects
|
|
|
if (item.effects && Array.isArray(item.effects) && item.effects.length > 0) {
|
|
|
@@ -2819,21 +2817,15 @@ window.renderStructuredData = function (items, type, parentItem = null) {
|
|
|
|
|
|
// Render steps array specially
|
|
|
if (item.steps && Array.isArray(item.steps)) {
|
|
|
- const allFragments = (parentItem && parentItem.fragments) || [];
|
|
|
+ const allCapabilities = (parentItem && parentItem.capability) || [];
|
|
|
const escapeHtml = (s) => String(s).replace(/</g, '<').replace(/>/g, '>');
|
|
|
const minWidth = 1250;
|
|
|
const renderAction = (src) => {
|
|
|
if (!src) return '-';
|
|
|
- if (src.action && typeof src.action === 'string') {
|
|
|
- return `<span style="font-weight: 600; color: #0f172a; font-size: 1.05em;">${escapeHtml(src.action)}</span>`;
|
|
|
- }
|
|
|
- if (src.action && src.action.main_action) {
|
|
|
- const mainAction = `<span style="font-weight: 600; color: #0f172a; font-size: 1.05em;">${escapeHtml(src.action.main_action)}</span>`;
|
|
|
- const mechanism = src.action.mechanism ? ` <span style="color: #64748b; font-size: 0.9em;">(${escapeHtml(src.action.mechanism)})</span>` : '';
|
|
|
- return `${mainAction}${mechanism}`;
|
|
|
- }
|
|
|
- if (src.body) {
|
|
|
- return `<div class="fragment-text">${escapeHtml(src.body)}</div>`;
|
|
|
+ if (src.action && src.action.description) {
|
|
|
+ const description = escapeHtml(src.action.description);
|
|
|
+ const reasoning = src.action.reasoning ? escapeHtml(src.action.reasoning) : '';
|
|
|
+ return `<span class="data-type-badge" style="background:#e0e7ff;color:#3730a3;font-weight:normal;margin-right:6px;margin-bottom:2px;display:inline-block;">${description}</span>${reasoning ? `<div style="font-size:0.85em;color:#64748b;margin-top:4px;">${reasoning}</div>` : ''}`;
|
|
|
}
|
|
|
if (src.method) return escapeHtml(src.method);
|
|
|
if (src.description) return escapeHtml(src.description);
|
|
|
@@ -2869,33 +2861,34 @@ window.renderStructuredData = function (items, type, parentItem = null) {
|
|
|
</div>`;
|
|
|
}).join('')}</div>`;
|
|
|
};
|
|
|
- const getStepFragments = (step) => {
|
|
|
+ const getStepCapabilities = (step) => {
|
|
|
if (!step || !step.step_id) return [];
|
|
|
- return allFragments.filter(f => {
|
|
|
- const refStepId = f.workflow_step_ref && f.workflow_step_ref.step_id;
|
|
|
+ return allCapabilities.filter(capability => {
|
|
|
+ const refStepId = capability.workflow_step_ref && capability.workflow_step_ref.step_id;
|
|
|
return refStepId === step.step_id || (
|
|
|
- f.fragment_id && (
|
|
|
- f.fragment_id === `f_${step.step_id}` ||
|
|
|
- f.fragment_id.startsWith(`f_${step.step_id}_`)
|
|
|
+ capability.capability_id && (
|
|
|
+ capability.capability_id === `c_${step.step_id}` ||
|
|
|
+ capability.capability_id.startsWith(`c_${step.step_id}_`)
|
|
|
)
|
|
|
);
|
|
|
});
|
|
|
};
|
|
|
- const matchedFragments = new Set();
|
|
|
- const renderFragmentColumns = (fragment) => {
|
|
|
- const applyTo = fragment && (fragment.apply_to_draft || fragment.apply_to_grounding || fragment.apply_to);
|
|
|
- const suggestApplyTo = fragment && fragment.apply_to_draft ? null : fragment && fragment.suggest_apply_to;
|
|
|
+ const matchedCapabilities = new Set();
|
|
|
+ const renderCapabilityColumns = (capability) => {
|
|
|
+ const applyTo = capability && (capability.apply_to_draft || capability.apply_to_grounding || capability.apply_to);
|
|
|
+ const suggestApplyTo = capability && capability.apply_to_draft ? null : capability && capability.suggest_apply_to;
|
|
|
return `
|
|
|
- <td class="fragment-cell" style="font-family: monospace;">
|
|
|
+ <td class="capability-cell" style="font-family: monospace;">
|
|
|
<span class="row-expand-icon">▶</span>
|
|
|
- ${fragment && fragment.fragment_id ? `<span style="display:inline-block; color:#94a3b8; font-size:0.85em; font-weight:400;">${escapeHtml(fragment.fragment_id)}</span>` : '-'}
|
|
|
+ ${capability && capability.capability_id ? `<span style="display:inline-block; color:#94a3b8; font-size:0.85em; font-weight:400;">${escapeHtml(capability.capability_id)}</span>` : '-'}
|
|
|
</td>
|
|
|
- <td class="fragment-cell">${fragment && fragment.inputs && fragment.inputs.length > 0 ? renderDataObjList(fragment.inputs) : '-'}</td>
|
|
|
- <td class="fragment-cell"><div class="fragment-clamp">${renderAction(fragment)}</div></td>
|
|
|
- <td class="fragment-cell">${fragment && fragment.outputs && fragment.outputs.length > 0 ? renderDataObjList(fragment.outputs) : '-'}</td>
|
|
|
- <td class="fragment-cell"><div class="fragment-clamp">${fragment ? renderEffects(fragment.effects) : '-'}</div></td>
|
|
|
- <td class="fragment-cell" style="font-size:0.9em;"><div class="fragment-clamp">${applyTo ? renderApplyToVal(applyTo, suggestApplyTo) : '-'}</div></td>
|
|
|
- <td class="fragment-cell"><div class="fragment-clamp">${fragment ? renderTools(fragment.tools) : '-'}</div></td>
|
|
|
+ <td class="capability-cell">${renderAction(capability)}</td>
|
|
|
+ <td class="capability-cell">${capability && capability.inputs && capability.inputs.length > 0 ? renderDataObjList(capability.inputs) : '-'}</td>
|
|
|
+ <td class="capability-cell">${capability && capability.outputs && capability.outputs.length > 0 ? renderDataObjList(capability.outputs) : '-'}</td>
|
|
|
+ <td class="capability-cell"><div class="capability-clamp">${capability ? renderEffects(capability.effects) : '-'}</div></td>
|
|
|
+ <td class="capability-cell" style="font-size:0.9em;"><div class="capability-clamp">${applyTo ? renderApplyToVal(applyTo, suggestApplyTo) : '-'}</div></td>
|
|
|
+ <td class="capability-cell"><div class="capability-clamp">${capability ? renderTools(capability.tools) : '-'}</div></td>
|
|
|
+ <td class="capability-cell"><div class="capability-clamp capability-text">${capability && capability.body ? escapeHtml(capability.body) : '-'}</div></td>
|
|
|
`;
|
|
|
};
|
|
|
|
|
|
@@ -2907,14 +2900,14 @@ window.renderStructuredData = function (items, type, parentItem = null) {
|
|
|
.steps-table tbody tr:hover { background: rgba(0,0,0,0.02) !important; }
|
|
|
.steps-table td { border-bottom: 1px solid rgba(0,0,0,0.05); }
|
|
|
.steps-table .step-merged-cell { background: #fbfdff; border-right: 1px dashed rgba(0,0,0,0.08); }
|
|
|
- .steps-table .fragment-cell { padding: 12px 10px; vertical-align: top; line-height: 1.5; color: var(--text-main); }
|
|
|
- .steps-table .fragment-clamp { max-height: 72px; overflow: hidden; position: relative; }
|
|
|
- .steps-table .fragment-clamp::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 24px; background: linear-gradient(to bottom, rgba(255,255,255,0), white); pointer-events: none; }
|
|
|
- .steps-table tr.fragment-expanded .fragment-clamp { max-height: none; overflow: visible; }
|
|
|
- .steps-table tr.fragment-expanded .fragment-clamp::after { display: none; }
|
|
|
+ .steps-table .capability-cell { padding: 12px 10px; vertical-align: top; line-height: 1.5; color: var(--text-main); }
|
|
|
+ .steps-table .capability-clamp { max-height: 72px; overflow: hidden; position: relative; }
|
|
|
+ .steps-table .capability-clamp::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 24px; background: linear-gradient(to bottom, rgba(255,255,255,0), white); pointer-events: none; }
|
|
|
+ .steps-table tr.capability-expanded .capability-clamp { max-height: none; overflow: visible; }
|
|
|
+ .steps-table tr.capability-expanded .capability-clamp::after { display: none; }
|
|
|
.steps-table .row-expand-icon { display: inline-block; margin-right: 6px; color: var(--text-muted); font-size: 0.8em; transition: transform 0.2s; }
|
|
|
- .steps-table tr.fragment-expanded .row-expand-icon { transform: rotate(90deg); }
|
|
|
- .steps-table .fragment-text { white-space: pre-wrap; word-break: break-word; }
|
|
|
+ .steps-table tr.capability-expanded .row-expand-icon { transform: rotate(90deg); }
|
|
|
+ .steps-table .capability-text { white-space: pre-wrap; word-break: break-word; }
|
|
|
.steps-table .effect-item { padding-bottom:8px; margin-bottom:8px; border-bottom:1px dashed rgba(0,0,0,0.08); color:var(--text-main); line-height:1.5; }
|
|
|
.steps-table .effect-item:last-child { margin-bottom:0; padding-bottom:0; border-bottom:0; }
|
|
|
.steps-table .effect-content { min-width:0; flex:1; }
|
|
|
@@ -2942,34 +2935,34 @@ window.renderStructuredData = function (items, type, parentItem = null) {
|
|
|
<tbody>`;
|
|
|
|
|
|
item.steps.forEach((step, stepIdx) => {
|
|
|
- const stepFragments = getStepFragments(step);
|
|
|
- stepFragments.forEach(fragment => matchedFragments.add(fragment));
|
|
|
- const fragsToRender = stepFragments.length > 0 ? stepFragments : [null];
|
|
|
- const rowspan = fragsToRender.length;
|
|
|
+ const stepCapabilities = getStepCapabilities(step);
|
|
|
+ stepCapabilities.forEach(capability => matchedCapabilities.add(capability));
|
|
|
+ const capabilitiesToRender = stepCapabilities.length > 0 ? stepCapabilities : [null];
|
|
|
+ const rowspan = capabilitiesToRender.length;
|
|
|
|
|
|
- fragsToRender.forEach((fragment, fragmentIdx) => {
|
|
|
+ capabilitiesToRender.forEach((capability, capabilityIdx) => {
|
|
|
html += `
|
|
|
- <tr style="vertical-align: top;" onclick="this.classList.toggle('fragment-expanded')">
|
|
|
- ${fragmentIdx === 0 ? `
|
|
|
+ <tr style="vertical-align: top;" onclick="this.classList.toggle('capability-expanded')">
|
|
|
+ ${capabilityIdx === 0 ? `
|
|
|
<td class="step-merged-cell" rowspan="${rowspan}" style="padding: 14px 10px; font-weight: 600; color: var(--text-muted); text-align: center;">
|
|
|
${step.order || stepIdx + 1}
|
|
|
</td>
|
|
|
<td class="step-merged-cell" rowspan="${rowspan}" style="padding: 14px 10px;">
|
|
|
${step.phase ? `<span class="structured-badge" style="background:#f1f5f9; color:#475569; font-weight: 500;">${escapeHtml(step.phase)}</span>` : '-'}
|
|
|
</td>` : ''}
|
|
|
- ${renderFragmentColumns(fragment)}
|
|
|
+ ${renderCapabilityColumns(capability)}
|
|
|
</tr>
|
|
|
`;
|
|
|
});
|
|
|
});
|
|
|
- allFragments.filter(fragment => !matchedFragments.has(fragment)).forEach(fragment => {
|
|
|
+ allCapabilities.filter(capability => !matchedCapabilities.has(capability)).forEach(capability => {
|
|
|
html += `
|
|
|
- <tr style="vertical-align: top;" onclick="this.classList.toggle('fragment-expanded')">
|
|
|
+ <tr style="vertical-align: top;" onclick="this.classList.toggle('capability-expanded')">
|
|
|
<td class="step-merged-cell" style="padding: 14px 10px; font-weight: 600; color: var(--text-muted); text-align: center;">-</td>
|
|
|
<td class="step-merged-cell" style="padding: 14px 10px;">
|
|
|
- <span class="structured-badge" style="background:#f8fafc; color:#64748b; font-weight: 500;">独立片段</span>
|
|
|
+ <span class="structured-badge" style="background:#f8fafc; color:#64748b; font-weight: 500;">独立能力</span>
|
|
|
</td>
|
|
|
- ${renderFragmentColumns(fragment)}
|
|
|
+ ${renderCapabilityColumns(capability)}
|
|
|
</tr>
|
|
|
`;
|
|
|
});
|