v1.0.7 — 连修三 bug:表单事件丢失 + Chart 堆积 + 字段重命名

This commit is contained in:
mac
2026-06-04 14:33:21 +08:00
parent 256767ff57
commit c5180cafbd
3 changed files with 30 additions and 12 deletions

View File

@@ -1,5 +1,16 @@
# OPC Manager Version Log
## v1.0.7 — 2026-06-04
- 修复新增表单 async 后 `event.currentTarget` 丢失导致页面不刷新(影响所有新增按钮)
- `createResource` 改用预存 form 引用 + try/catch 错误提示
## v1.0.6 — 2026-06-04
- 修复财务 Tab Chart 无限堆积renderChartOn 缺少旧 chart 销毁 + state 跟踪
- 财务图表容器加固定高度300px避免 resize 循环
## v1.0.5 — 2026-06-04
- "销售管理" Tab 改为"业务机会""目标客户"字段统一改为"业务机会"
## v1.0.4 — 2026-06-04
- CDN 全量本地化Tailwind / Chart.js / Squire / Lucide 下载到 `static/vendor/`,不再依赖外部 CDN

View File

@@ -3,6 +3,7 @@ const state = {
data: null,
opFilter: "all",
chart: null,
chart2: null,
};
const money = (value) => `${Number(value || 0).toLocaleString("zh-CN")}`;
@@ -143,10 +144,15 @@ function formHtml(fields, button) {
async function createResource(event, resource) {
event.preventDefault();
const data = Object.fromEntries(new FormData(event.currentTarget).entries());
await api(`/api/${resource}`, { method: "POST", body: JSON.stringify({ data }) });
event.currentTarget.reset();
await load();
const form = event.currentTarget;
const data = Object.fromEntries(new FormData(form).entries());
try {
await api(`/api/${resource}`, { method: "POST", body: JSON.stringify({ data }) });
form.reset();
await load();
} catch (error) {
alert("创建失败:" + error.message);
}
}
window.createSales = (event) => createResource(event, "sales");
@@ -161,11 +167,11 @@ function renderSales() {
const salesClicks = state.data.sales.map((x) => ({ resource: "sales", id: x.id }));
document.querySelector("#sales").innerHTML = `<div class="grid gap-4">
${card(formHtml([
{ label: "目标客户", input: `<input name="target_customer" required placeholder="客户名称">` },
{ label: "业务机会", input: `<input name="target_customer" required placeholder="客户名称">` },
{ label: "优先级", input: `<select name="priority"><option>P0</option><option selected>P1</option><option>P2</option><option>P3</option></select>` },
{ label: "状态", input: `<select name="status"><option>待跟进</option><option>跟进中</option><option>方案中</option><option>商务谈判</option><option>已签约</option><option>暂缓</option><option>已丢单</option></select>` },
], { handler: "createSales", text: `<i data-lucide="plus"></i>新增客户` }), "p-4")}
${renderTable(["目标客户", "优先级", "状态", "最新跟进记录"], rows, salesClicks)}
], { handler: "createSales", text: `<i data-lucide="plus"></i>新增业务机会` }), "p-4")}
${renderTable(["业务机会", "优先级", "状态", "最新跟进记录"], rows, salesClicks)}
</div>`;
}
@@ -245,7 +251,7 @@ function renderProducts() {
function renderFinance() {
const rows = state.data.finance.map((x) => [x.month, badge(x.record_type === "revenue" ? "收入" : "成本/费用"), x.category, money(x.amount), x.occurred_date, text(x.notes)]);
document.querySelector("#finance").innerHTML = `<div class="grid gap-4">
${card(`<h2 class="mb-4 text-lg font-bold">收入、毛利、成本/费用、净利月度曲线</h2><canvas id="financeChart2" height="105"></canvas>`, "p-5")}
${card(`<h2 class="mb-4 text-lg font-bold">收入、毛利、成本/费用、净利月度曲线</h2><div style="position:relative;height:300px"><canvas id="financeChart2"></canvas></div>`, "p-5")}
${card(formHtml([
{ label: "月份", input: `<input name="month" required placeholder="YYYY-MM" pattern="\\d{4}-\\d{2}">` },
{ label: "类型", input: `<select name="record_type"><option value="revenue">收入</option><option value="cost_expense">/</option></select>` },
@@ -261,7 +267,8 @@ function renderFinance() {
function renderChartOn(id, data) {
const canvas = document.querySelector(`#${id}`);
if (!canvas || !window.Chart) return;
new Chart(canvas, {
if (state.chart2) state.chart2.destroy();
state.chart2 = new Chart(canvas, {
type: "line",
data: {
labels: data.map((x) => x.month),
@@ -292,9 +299,9 @@ function openDrawer(resource, id) {
const item = list.find((x) => x.id === id);
const drawer = document.querySelector("#drawer");
const fields = resource === "sales"
? [["target_customer","目标客户"],["priority","优先级"],["status","状态"]]
? [["target_customer","业务机会"],["priority","优先级"],["status","状态"]]
: resource === "operations"
? [["project_name","项目名称"],["project_version","项目版本"],["project_status","项目状态"],["current_stage","当前阶段"],["target_customer","目标客户"],["customer_need","客户需求"],["expected_contract_amount","预计签约金额"],["expected_sign_date","预计签约时间"],["sign_probability","签约概率"],["sop_stage","SOP 阶段"],["execution_progress","执行进度"],["current_deliverable","当前交付物"],["risks","风险与阻塞"],["next_action","下一步动作"]]
? [["project_name","项目名称"],["project_version","项目版本"],["project_status","项目状态"],["current_stage","当前阶段"],["target_customer","业务机会"],["customer_need","客户需求"],["expected_contract_amount","预计签约金额"],["expected_sign_date","预计签约时间"],["sign_probability","签约概率"],["sop_stage","SOP 阶段"],["execution_progress","执行进度"],["current_deliverable","当前交付物"],["risks","风险与阻塞"],["next_action","下一步动作"]]
: resource === "proposals"
? [["customer_or_project_name","客户/项目"],["version","版本号"],["description","版本说明"],["created_date","创建日期"],["status","状态"]]
: [["product_name","产品名称"],["version","版本号"],["version_goal","版本目标"],["feature_list","核心功能清单"],["launch_date","上线日期"],["status","当前状态"],["notes","备注"]];

View File

@@ -36,7 +36,7 @@
<nav class="tabs border-b border-slate-200 bg-white px-8" id="tabs">
<button class="active" data-tab="home"><i data-lucide="home"></i>首页</button>
<button data-tab="sales"><i data-lucide="briefcase-business"></i>销售管理</button>
<button data-tab="sales"><i data-lucide="briefcase-business"></i>业务机会</button>
<button data-tab="proposals"><i data-lucide="file-text"></i>业务方案</button>
<button data-tab="operations"><i data-lucide="activity"></i>运营管理</button>
<button data-tab="products"><i data-lucide="package"></i>产品研发</button>