chore: polish remaining workbench copy
This commit is contained in:
12
CHANGELOG.md
12
CHANGELOG.md
@@ -341,3 +341,15 @@
|
|||||||
- `额度` 页和租户额度编辑弹层新增了 `套餐档位` 与 `预算预警阈值`,现在能直接按试用、增长、规模、自定义四档去配置项目套餐。
|
- `额度` 页和租户额度编辑弹层新增了 `套餐档位` 与 `预算预警阈值`,现在能直接按试用、增长、规模、自定义四档去配置项目套餐。
|
||||||
- 租户额度面板会直接展示当前套餐档位和预警阈值,便于把预算和动作池表达成正式产品能力,而不是只看裸配额数字。
|
- 租户额度面板会直接展示当前套餐档位和预警阈值,便于把预算和动作池表达成正式产品能力,而不是只看裸配额数字。
|
||||||
- 不可自动恢复的失败任务现在会打开站内“处理建议”面板,直接给出补信息、查看详情或交给主 Agent 的下一步,而不是只停在失败提示。
|
- 不可自动恢复的失败任务现在会打开站内“处理建议”面板,直接给出补信息、查看详情或交给主 Agent 的下一步,而不是只停在失败提示。
|
||||||
|
|
||||||
|
### 项目切换入口统一
|
||||||
|
|
||||||
|
- 所有 `select-project` 入口现在都统一走 `applySelectedProject()`,不再一部分入口回到项目总台、一部分入口只原地刷新。
|
||||||
|
- 项目卡、项目 sheet 和其他项目切换入口都会在切换后回到 `项目总台` 主工作区,保证切完项目就能直接继续当前项目推进。
|
||||||
|
|
||||||
|
### 页面口径继续去掉半成品表达
|
||||||
|
|
||||||
|
- `Agent`、模型设置、跟踪、对标关系、复盘这些页面里的“后续再补”口径继续改成当前就能执行的表达,页面语气更像正式产品。
|
||||||
|
- `创建 Agent / 编辑 Agent` 里的系统提示词占位改成“可先留空,后面随时补充”,减少半成品感。
|
||||||
|
- `作品与成片`、Agent 执行项默认说明里的“再补”字眼也一起收掉,统一成当前可直接推进的表达。
|
||||||
|
- 前端回归新增了这批文案断言,避免旧的占位口径再回流到主工作台。
|
||||||
|
|||||||
@@ -4547,7 +4547,7 @@ function renderPlatformAgentPanel() {
|
|||||||
return `
|
return `
|
||||||
<div class="entity-card pad">
|
<div class="entity-card pad">
|
||||||
<div class="cell-title">${escapeHtml(item.name || item.platform_label)}</div>
|
<div class="cell-title">${escapeHtml(item.name || item.platform_label)}</div>
|
||||||
<div class="cell-desc">${escapeHtml(item.mission || item.notes || "先绑定执行 Agent,再补任务目标和方法论。")}</div>
|
<div class="cell-desc">${escapeHtml(item.mission || item.notes || "先绑定执行 Agent,再完善任务目标和方法论。")}</div>
|
||||||
<div class="entity-meta">
|
<div class="entity-meta">
|
||||||
<span class="tag ${item.status === "active" ? "green" : "blue"}">${escapeHtml(item.status || "draft")}</span>
|
<span class="tag ${item.status === "active" ? "green" : "blue"}">${escapeHtml(item.status || "draft")}</span>
|
||||||
${item.readiness_label ? `<span class="tag ${item.readiness_score >= 75 ? "green" : item.readiness_score >= 50 ? "blue" : "orange"}">${escapeHtml(item.readiness_label)} ${escapeHtml(formatNumber(item.readiness_score || 0))}</span>` : ""}
|
${item.readiness_label ? `<span class="tag ${item.readiness_score >= 75 ? "green" : item.readiness_score >= 50 ? "blue" : "orange"}">${escapeHtml(item.readiness_label)} ${escapeHtml(formatNumber(item.readiness_score || 0))}</span>` : ""}
|
||||||
@@ -6685,7 +6685,7 @@ function renderPlaybookScreen() {
|
|||||||
<div class="panel-head">
|
<div class="panel-head">
|
||||||
<div>
|
<div>
|
||||||
<h3>当前 Agent</h3>
|
<h3>当前 Agent</h3>
|
||||||
<div class="panel-subtitle">后续文案生成、对标绑定和复盘默认都会优先使用这里选中的 Agent。</div>
|
<div class="panel-subtitle">文案生成、对标绑定和复盘都会优先使用这里选中的 Agent。</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="task-meta">
|
<div class="task-meta">
|
||||||
${currentAssistant ? `<span class="tag blue">已选</span>` : `<span class="tag red">未选</span>`}
|
${currentAssistant ? `<span class="tag blue">已选</span>` : `<span class="tag red">未选</span>`}
|
||||||
@@ -7089,7 +7089,7 @@ function renderProductionScreen() {
|
|||||||
<div class="layout-grid grid-main">
|
<div class="layout-grid grid-main">
|
||||||
<div class="side-stack">
|
<div class="side-stack">
|
||||||
<div class="panel pad" style="box-shadow:none;">
|
<div class="panel pad" style="box-shadow:none;">
|
||||||
<div class="panel-head"><div><h3>作品与成片</h3><div class="panel-subtitle">先看真实作品,再补文档与成片</div></div></div>
|
<div class="panel-head"><div><h3>作品与成片</h3><div class="panel-subtitle">先看真实作品,再继续整理文档与成片</div></div></div>
|
||||||
<div class="list">
|
<div class="list">
|
||||||
${works.map((video) => `
|
${works.map((video) => `
|
||||||
<div class="review-card compact">
|
<div class="review-card compact">
|
||||||
@@ -7865,7 +7865,7 @@ function openPreferredModelAction() {
|
|||||||
const gatewayModels = safeArray(localCatalog.models).map((item) => item.id).filter(Boolean);
|
const gatewayModels = safeArray(localCatalog.models).map((item) => item.id).filter(Boolean);
|
||||||
openActionModal({
|
openActionModal({
|
||||||
title: "设置分析主模型",
|
title: "设置分析主模型",
|
||||||
description: "后续导入分析、市场调研和风格学习会优先使用这里设置的模型。",
|
description: "导入分析、市场调研和风格学习都会优先使用这里设置的模型。",
|
||||||
submitLabel: "保存模型",
|
submitLabel: "保存模型",
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
@@ -8762,7 +8762,7 @@ function openTrackSelectedAccountAction() {
|
|||||||
title: trackedItem ? "更新跟踪账号" : "加入跟踪",
|
title: trackedItem ? "更新跟踪账号" : "加入跟踪",
|
||||||
description: trackedItem
|
description: trackedItem
|
||||||
? "这个账号已经在跟踪中,可以切换负责 Agent 或补充备注。"
|
? "这个账号已经在跟踪中,可以切换负责 Agent 或补充备注。"
|
||||||
: "把当前对标账号加入每日跟踪,后续自动生成更新日报。",
|
: "把当前对标账号加入每日跟踪,系统会自动生成更新日报。",
|
||||||
submitLabel: trackedItem ? "保存跟踪" : "开始跟踪",
|
submitLabel: trackedItem ? "保存跟踪" : "开始跟踪",
|
||||||
fields: [
|
fields: [
|
||||||
{ name: "accountName", label: "账号", type: "html", html: `<div class="sheet-html"><strong>${escapeHtml(getAccountName(account) || "未命名账号")}</strong><p>${escapeHtml(getAccountProfileUrl(account) || account.signature || "")}</p></div>` },
|
{ name: "accountName", label: "账号", type: "html", html: `<div class="sheet-html"><strong>${escapeHtml(getAccountName(account) || "未命名账号")}</strong><p>${escapeHtml(getAccountProfileUrl(account) || account.signature || "")}</p></div>` },
|
||||||
@@ -9343,7 +9343,7 @@ function openSystemMainPolicyAction() {
|
|||||||
const current = bundle.current_version || {};
|
const current = bundle.current_version || {};
|
||||||
openActionModal({
|
openActionModal({
|
||||||
title: "编辑系统主 Agent 策略",
|
title: "编辑系统主 Agent 策略",
|
||||||
description: "这是所有用户共享的系统级主 Agent 基座能力,后续用户层和管理员覆盖都会叠加在它上面。",
|
description: "这是所有用户共享的系统级主 Agent 基座能力,用户层和管理员覆盖都会叠加在它上面。",
|
||||||
submitLabel: "保存系统策略",
|
submitLabel: "保存系统策略",
|
||||||
fields: [
|
fields: [
|
||||||
{ type: "html", label: "当前版本", html: renderPolicyVersionSummary(bundle, "系统主 Agent 还没有系统默认策略。") },
|
{ type: "html", label: "当前版本", html: renderPolicyVersionSummary(bundle, "系统主 Agent 还没有系统默认策略。") },
|
||||||
@@ -10098,7 +10098,7 @@ function openCreateAssistantAction() {
|
|||||||
{ name: "name", label: "名称", placeholder: "例如:创业成交助手" },
|
{ name: "name", label: "名称", placeholder: "例如:创业成交助手" },
|
||||||
{ name: "description", label: "说明", placeholder: "例如:服务创业 IP 与成交型短视频" },
|
{ name: "description", label: "说明", placeholder: "例如:服务创业 IP 与成交型短视频" },
|
||||||
{ name: "goal", label: "生成目标", placeholder: "例如:输出创业口播、对标拆解和成交文案" },
|
{ name: "goal", label: "生成目标", placeholder: "例如:输出创业口播、对标拆解和成交文案" },
|
||||||
{ name: "systemPrompt", label: "系统提示词", type: "textarea", rows: 5, placeholder: "可选,不填则后续再补" },
|
{ name: "systemPrompt", label: "系统提示词", type: "textarea", rows: 5, placeholder: "可选,可先留空,后面随时补充" },
|
||||||
{ name: "knowledgeBaseId", label: "默认知识库", type: "select", value: kbOptions[0]?.value || "", options: [{ value: "", label: "暂不绑定" }, ...kbOptions] },
|
{ name: "knowledgeBaseId", label: "默认知识库", type: "select", value: kbOptions[0]?.value || "", options: [{ value: "", label: "暂不绑定" }, ...kbOptions] },
|
||||||
{ name: "modelProfileId", label: "主模型", type: "select", value: modelOptions.find((item) => item.value === safeArray(appState.dashboard?.model_profiles).find((m) => m.is_default)?.id)?.value || modelOptions[0]?.value || "", options: modelOptions }
|
{ name: "modelProfileId", label: "主模型", type: "select", value: modelOptions.find((item) => item.value === safeArray(appState.dashboard?.model_profiles).find((m) => m.is_default)?.id)?.value || modelOptions[0]?.value || "", options: modelOptions }
|
||||||
],
|
],
|
||||||
@@ -10141,7 +10141,7 @@ function openEditAssistantAction(assistantId = "") {
|
|||||||
{ name: "name", label: "名称", value: assistant.name || "", placeholder: "例如:创业成交助手" },
|
{ name: "name", label: "名称", value: assistant.name || "", placeholder: "例如:创业成交助手" },
|
||||||
{ name: "description", label: "说明", value: assistant.description || "", placeholder: "例如:服务创业 IP 与成交型短视频" },
|
{ name: "description", label: "说明", value: assistant.description || "", placeholder: "例如:服务创业 IP 与成交型短视频" },
|
||||||
{ name: "goal", label: "生成目标", value: assistant.generation_goal || "", placeholder: "例如:输出创业口播、对标拆解和成交文案" },
|
{ name: "goal", label: "生成目标", value: assistant.generation_goal || "", placeholder: "例如:输出创业口播、对标拆解和成交文案" },
|
||||||
{ name: "systemPrompt", label: "系统提示词", type: "textarea", rows: 5, value: assistant.system_prompt || "", placeholder: "可选,不填则后续再补" },
|
{ name: "systemPrompt", label: "系统提示词", type: "textarea", rows: 5, value: assistant.system_prompt || "", placeholder: "可选,可先留空,后面随时补充" },
|
||||||
{ name: "modelProfileId", label: "主模型", type: "select", value: assistant.model_profile_id || modelOptions[0]?.value || "", options: modelOptions }
|
{ name: "modelProfileId", label: "主模型", type: "select", value: assistant.model_profile_id || modelOptions[0]?.value || "", options: modelOptions }
|
||||||
],
|
],
|
||||||
onSubmit: async (values) => {
|
onSubmit: async (values) => {
|
||||||
@@ -10289,7 +10289,7 @@ function openBenchmarkLinkAction(defaults = {}) {
|
|||||||
: null;
|
: null;
|
||||||
openActionModal({
|
openActionModal({
|
||||||
title: "保存对标关系",
|
title: "保存对标关系",
|
||||||
description: "把当前账号和另一个账号关联成对标关系,便于后续持续跟踪。",
|
description: "把当前账号和另一个账号关联成对标关系,便于持续跟踪。",
|
||||||
submitLabel: "保存关系",
|
submitLabel: "保存关系",
|
||||||
fields: [
|
fields: [
|
||||||
{ name: "targetAccountId", label: "目标账号", type: "select", value: defaults.targetAccountId || candidate?.candidate_account_id || options[0]?.value || "", options: [{ value: "", label: "仅保存主页链接" }, ...options] },
|
{ name: "targetAccountId", label: "目标账号", type: "select", value: defaults.targetAccountId || candidate?.candidate_account_id || options[0]?.value || "", options: [{ value: "", label: "仅保存主页链接" }, ...options] },
|
||||||
@@ -11220,7 +11220,7 @@ function openReviewAction(defaults = {}) {
|
|||||||
title: existingReview ? "编辑复盘" : "写复盘",
|
title: existingReview ? "编辑复盘" : "写复盘",
|
||||||
description: existingReview
|
description: existingReview
|
||||||
? "补充表现数据、判断和下一步动作,持续迭代项目策略。"
|
? "补充表现数据、判断和下一步动作,持续迭代项目策略。"
|
||||||
: "把完成任务写成一条可追踪复盘,后续可按项目累计。",
|
: "把完成任务写成一条可追踪复盘,可按项目累计。",
|
||||||
submitLabel: existingReview ? "保存复盘" : "创建复盘",
|
submitLabel: existingReview ? "保存复盘" : "创建复盘",
|
||||||
fields: [
|
fields: [
|
||||||
{ name: "title", label: "标题", value: existingReview?.title || defaults.title || sourceJob?.title || "", placeholder: "例如:创业口播 3 月 22 日复盘" },
|
{ name: "title", label: "标题", value: existingReview?.title || defaults.title || sourceJob?.title || "", placeholder: "例如:创业口播 3 月 22 日复盘" },
|
||||||
@@ -11891,20 +11891,11 @@ document.addEventListener("click", async (event) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (name === "select-project") {
|
if (name === "select-project") {
|
||||||
appState.selectedProjectId = action.dataset.projectId || "";
|
|
||||||
setBusy(true, "正在切换项目视图...");
|
|
||||||
try {
|
try {
|
||||||
await loadStorageStatus(appState.selectedProjectId || "");
|
await applySelectedProject(action.dataset.projectId || "");
|
||||||
await loadAgentControlSurfaces(appState.selectedProjectId || "");
|
} catch (error) {
|
||||||
if (appState.selectedOnelinerSessionId) {
|
presentActionFailure(error, "切换项目失败");
|
||||||
await loadOneLinerMessages(appState.selectedOnelinerSessionId);
|
|
||||||
} else {
|
|
||||||
appState.onelinerMessages = [];
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
setBusy(false, "");
|
|
||||||
}
|
}
|
||||||
renderAll();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (name === "select-platform") {
|
if (name === "select-platform") {
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ test("project creation and switching use in-app sheets instead of browser prompt
|
|||||||
test("mobile project sheets support direct project picking and zoom-safe form controls", () => {
|
test("mobile project sheets support direct project picking and zoom-safe form controls", () => {
|
||||||
const projectSwitcher = extractBetween(APP, "function openDashboardProjectSwitcher()", "function openDashboardActionReasonAction(");
|
const projectSwitcher = extractBetween(APP, "function openDashboardProjectSwitcher()", "function openDashboardActionReasonAction(");
|
||||||
const applySelectedProject = extractBetween(APP, "async function applySelectedProject(projectId = \"\")", "function openDashboardProjectSwitcher()");
|
const applySelectedProject = extractBetween(APP, "async function applySelectedProject(projectId = \"\")", "function openDashboardProjectSwitcher()");
|
||||||
|
const clickHandler = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||||||
const createProject = extractBetween(APP, "async function createProject()", "function openPreferredModelAction()");
|
const createProject = extractBetween(APP, "async function createProject()", "function openPreferredModelAction()");
|
||||||
assert.match(APP, /async function applySelectedProject\(projectId = ""\)/);
|
assert.match(APP, /async function applySelectedProject\(projectId = ""\)/);
|
||||||
assert.match(APP, /function focusDashboardWorkspace\(anchorId = "dashboard-workspace-anchor"\)/);
|
assert.match(APP, /function focusDashboardWorkspace\(anchorId = "dashboard-workspace-anchor"\)/);
|
||||||
@@ -150,6 +151,7 @@ test("mobile project sheets support direct project picking and zoom-safe form co
|
|||||||
assert.match(applySelectedProject, /loadStorageStatus\(appState\.selectedProjectId \|\| ""\)/);
|
assert.match(applySelectedProject, /loadStorageStatus\(appState\.selectedProjectId \|\| ""\)/);
|
||||||
assert.match(applySelectedProject, /loadAgentControlSurfaces\(appState\.selectedProjectId \|\| ""\)/);
|
assert.match(applySelectedProject, /loadAgentControlSurfaces\(appState\.selectedProjectId \|\| ""\)/);
|
||||||
assert.match(applySelectedProject, /focusDashboardWorkspace\("dashboard-workspace-anchor"\)/);
|
assert.match(applySelectedProject, /focusDashboardWorkspace\("dashboard-workspace-anchor"\)/);
|
||||||
|
assert.match(clickHandler, /name === "select-project"[\s\S]*await applySelectedProject\(action\.dataset\.projectId \|\| ""\)/);
|
||||||
assert.match(APP, /id="dashboard-workspace-anchor"/);
|
assert.match(APP, /id="dashboard-workspace-anchor"/);
|
||||||
assert.match(createProject, /onOpen:\s*\(/);
|
assert.match(createProject, /onOpen:\s*\(/);
|
||||||
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.field-stack input,\s*[\s\S]*\.field-stack textarea,\s*[\s\S]*\.field-stack select\s*\{[\s\S]*min-height:\s*46px/);
|
assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.field-stack input,\s*[\s\S]*\.field-stack textarea,\s*[\s\S]*\.field-stack select\s*\{[\s\S]*min-height:\s*46px/);
|
||||||
@@ -385,6 +387,17 @@ test("discovery and production screens expose compact mobile flow summaries", ()
|
|||||||
assert.match(production, /失败/);
|
assert.match(production, /失败/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("workbench copy uses direct live language instead of future-placeholder wording", () => {
|
||||||
|
assert.doesNotMatch(APP, /可选,不填则后续再补/);
|
||||||
|
assert.match(APP, /可选,可先留空,后面随时补充/);
|
||||||
|
assert.match(APP, /文案生成、对标绑定和复盘都会优先使用这里选中的 Agent/);
|
||||||
|
assert.match(APP, /导入分析、市场调研和风格学习都会优先使用这里设置的模型/);
|
||||||
|
assert.match(APP, /系统会自动生成更新日报/);
|
||||||
|
assert.match(APP, /把完成任务写成一条可追踪复盘,可按项目累计/);
|
||||||
|
assert.match(APP, /先绑定执行 Agent,再完善任务目标和方法论/);
|
||||||
|
assert.match(APP, /先看真实作品,再继续整理文档与成片/);
|
||||||
|
});
|
||||||
|
|
||||||
test("discovery and production screens expose mobile focus cards with next-step actions", () => {
|
test("discovery and production screens expose mobile focus cards with next-step actions", () => {
|
||||||
const discovery = extractBetween(APP, "function renderDiscoveryScreen()", "function renderTrackingScreen()");
|
const discovery = extractBetween(APP, "function renderDiscoveryScreen()", "function renderTrackingScreen()");
|
||||||
const production = extractBetween(APP, "function renderProductionScreen()", "function renderReviewScreen()");
|
const production = extractBetween(APP, "function renderProductionScreen()", "function renderReviewScreen()");
|
||||||
|
|||||||
Reference in New Issue
Block a user