diff --git a/.workbuddy/memory/2026-09-20.md b/.workbuddy/memory/2026-09-20.md index 3a96d67..a3a50e4 100644 --- a/.workbuddy/memory/2026-09-20.md +++ b/.workbuddy/memory/2026-09-20.md @@ -60,3 +60,37 @@ - 定开第一个 tab **「项目明细」→「项目总览」**(chip 与卡片标题「定开项目总览」都改)。 - `customTableHtml` 列序:把**「项目归属」移到「下单时间」之后**(新序:项目名称 / 项目ID / 下单时间 / 项目归属 / 办事处 / …)。项目总览与本周进展两个 tab 共用,故同时生效。 - 后端导出标题仍是「定开项目明细」(未改,用户只说 tab 名)。纯前端改动,无需重启。 + +## 推送到 develop-chezhiqi +- 仓库此前**未配置 git 身份**(唯一提交 e9854eb 作者是 mula.liu )。按用户选择,设**本仓库** `user.name=chezhiqi` / `user.email=chezhiqi@unissense.tech`(邮箱取远端域名 unissense.tech,如不对可 amend)。 +- 提交 **a77cd7b**「定开项目:台账化改造 + 统计/导出/搜索调整,新增本周进展与年度任务 tab」,包含 app/**、web/**、scripts/**(新增 `import_custom_ledger.py`)、README.md、run.sh、`data/board.db`、`.workbuddy/memory/**`(含被 git 跟踪的 `__pycache__/*.pyc`)。 +- 已 push 到 `origin/develop-chezhiqi`(`e9854eb..a77cd7b`),本地与远端一致(远端还提示可发 PR main...develop-chezhiqi)。 +- **有意未提交**:`data/board.db.bak-*` 4 个本地备份(保持 untracked)。 + +## 「项目归属」新签订单 → 华智下单 +- 前端 `web/app.js`:`CUSTOM_ORIGINS` / `CUSTOM_PLACED` 里 `新签订单` → **`华智下单`**(连同新建对话框默认值、统计说明文案,全文替换 6 处,现 app.js 内已无「新签订单」)。 +- **数据迁移**:`UPDATE custom_projects SET origin='华智下单' WHERE origin='新签订单'`(83 行);备份 `data/board.db.bak-before-origin-rename-20260920_213304`。现 origin 分布:华智下单 83 / 存量项目 27 / 汇智直签 10 / 提前交付 2。 +- `scripts/import_custom_ledger.py`:读入行时把 `新签订单` 归一化为 `华智下单`(防再导入回退),并更新文档注释;`app/models.py` 注释同步。 +- 纯前端 + 数据 + 脚本改动,**无需重启**(models.py 仅注释)。**本次未 push**(用户本轮只要求改名)。 + +## 三项改名/调整(项目状态 / 本周卡片 / 归属选项) +1. **项目状态「交付中」→「进行中」**(全量改名): + - `web/app.js` 全文 `交付中`→`进行中`(共 12 处:状态色映射、STATUS_OPTIONS、进度列判定、本周「交付项目」= 进行中+交付完成、新建/编辑 statusOpts、placeholder、注释)。 + - **数据迁移** `UPDATE custom_projects SET project_status='进行中' WHERE project_status='交付中'`(10 行);备份 `data/board.db.bak-before-status-rename-20260920_213707`。现状态:已验收 64 / 待开发 29 / 交付完成 17 / **进行中 10** / 退单 2。 + - `import_custom_ledger.py` 读入时 `交付中`→`进行中` 归一化;`models.py` 注释同步。 +2. **本周进展卡片「本周新增项目」→「新增项目」**(`web/app.js` 卡片标题 + 说明文案)。 +3. **项目归属去掉「其他」选项**:`CUSTOM_ORIGINS = [华智下单, 存量项目, 汇智直签, 提前交付]`(新建/筛选下拉都不再有「其他」);`models.py` / 导入脚本文档注释同步。数据中本来就没有 origin=其他 的行。 +- 纯前端 + 数据 + 脚本改动,**无需重启**;`node --check` / `ast.parse` 通过。**本轮未 push**。 + +## 本周卡片改名 + 清空历史「更新时间」 +1. **本周进展卡片「交付项目」→「进行中项目」**(`web/app.js` 卡片标题/说明/标题栏摘要;口径未变,仍是 本周更新 ∩ 进行中+交付完成)。 +2. **清空早于 2026-09-18 的「更新时间」**:`UPDATE custom_projects SET update_date=NULL WHERE update_date IS NOT NULL AND update_date!='' AND update_date < '2026-09-18'` → 清空 **111** 行;保留 11 行(均为 2026-09-18 及以后编辑的,含 "YYYY-MM-DD HH:MM" 提交时间)。备份 `data/board.db.bak-before-clearing-updatedate-20260920_214254`。 + - 影响:`update_date` 仅剩 11 行有值;「删除本周更新」现在只会命中这 11 行(都在本周)。后续「修改/新建」会按提交时间重新写入。 + +## 表格排序 + 计划筛选 + 列序/按钮调整 +1. **列序**:`customTableHtml` 里把「备注」与「更新时间」**对调**(… 风险值 / **更新时间** / **备注** / 操作)。 +2. **去掉「删除本周更新」按钮**:删除 `renderCustomList` 卡片头里的按钮、`bindCustomList` 里的绑定与整个 `purgeWeek()` 函数(后端 `/custom/weekly-preview`、`/custom/purge-week` 接口保留未删)。 +3. **表头排序**:`下单时间`(sign_date) / `订单金额`(amount, 数值) / `更新时间`(update_date) 三个表头可点击排序,`state.customSort = {key, dir}`;点不同列默认「降序」,再点同列切换升/降;表头显示 ▲/▼,卡片副标题显示当前排序。 +4. **新增「推动验收计划」筛选**:工具栏加 `#cAcceptPlan`(`state.customAcceptPlan`),选项取数据中实际出现过的值(Q3/Q4/27年/-- 等);导出也带 `accept_plan` 参数(后端 `export_custom` 新增 `accept_plan`)。 +- `state` 新增 `customAcceptPlan` / `customSort`,均加入 `UI_FIELDS` 持久化。 +- 后端 `export.py` 改动 → 重启 uvicorn(PID 23436);`node --check` / `ast.parse` 通过。实测导出 `accept_plan=Q3` 生效。**本轮未 push**。 diff --git a/app/models.py b/app/models.py index cb59a27..ac02c35 100644 --- a/app/models.py +++ b/app/models.py @@ -414,7 +414,7 @@ class CustomProject(Base, TimestampMixin): source: Mapped[str] = mapped_column(String(16), default="import", nullable=False) # ---- 市场/销售侧台账字段(来源《定开项目.xlsx》,2026-09 起)---- - origin: Mapped[str | None] = mapped_column(String(32), nullable=True) # 项目归属:新签订单/存量项目/汇智直签 + origin: Mapped[str | None] = mapped_column(String(32), nullable=True) # 项目归属:华智下单/存量项目/汇智直签/提前交付 project_code: Mapped[str | None] = mapped_column( String(64), nullable=True, index=True ) # 项目ID(市场编号,导入时用于去重) @@ -426,7 +426,7 @@ class CustomProject(Base, TimestampMixin): ) # 市场责任人(销售侧;多人用 / 分隔,与花名册无关) project_status: Mapped[str | None] = mapped_column( String(32), nullable=True - ) # 项目状态:已验收/待开发/交付完成/交付中/退单 + ) # 项目状态:已验收/待开发/交付完成/进行中/退单 accept_plan: Mapped[str | None] = mapped_column( String(32), nullable=True ) # 推动验收计划(Q1..Q4 / 27年) diff --git a/app/routers/export.py b/app/routers/export.py index 6912f58..19c7c62 100644 --- a/app/routers/export.py +++ b/app/routers/export.py @@ -48,6 +48,7 @@ def export_custom( region: str | None = None, origin: str | None = None, status: str | None = None, + accept_plan: str | None = None, keyword: str | None = None, archived: str = Query("false", pattern="^(true|false|all)$"), db: Session = Depends(get_db), @@ -63,6 +64,8 @@ def export_custom( q = q.filter(CustomProject.origin == origin) if status: q = q.filter(CustomProject.project_status == status) + if accept_plan: + q = q.filter(CustomProject.accept_plan == accept_plan) if keyword: q = q.filter(CustomProject.name.contains(keyword)) projects = _sort_by_update(q.all()) diff --git a/data/board.db b/data/board.db index 04b2761..c99e0ec 100644 Binary files a/data/board.db and b/data/board.db differ diff --git a/scripts/import_custom_ledger.py b/scripts/import_custom_ledger.py index 17c6817..25506e2 100644 --- a/scripts/import_custom_ledger.py +++ b/scripts/import_custom_ledger.py @@ -4,7 +4,7 @@ | 表格列 | 数据库列 | 说明 | |--------------|-----------------|------| -| 项目归属 | origin | 新签订单 / 存量项目 / 汇智直签 | +| 项目归属 | origin | 华智下单 / 存量项目 / 汇智直签 / 提前交付(「新签订单」自动映射为「华智下单」) | | 项目名称 | name | 匹配键之一 | | 项目ID | project_code | 匹配键(优先) | | 下单时间 | sign_date | 日期取 YYYY-MM-DD,像「2024年3月前」这种文本原样保留 | @@ -13,7 +13,7 @@ | 市场下单人天 | man_days | | | 订单金额 | amount | | | 市场责任人 | market_owner | 销售侧人员,与花名册无关,可「张宁/叶镇」这种多人写法 | -| 项目状态 | project_status | 已验收 / 待开发 / 交付完成 / 交付中 / 退单 | +| 项目状态 | project_status | 已验收 / 待开发 / 交付完成 / 进行中 / 退单(「交付中」自动映射为「进行中」) | | 验收时间 | accept_date | 存的是季度文本(Q1..Q4),不是日期 | | 推动验收计划 | accept_plan | Q1..Q4 / 27年 | | 风险值 | risk_level | 1.高风险 / 2.低风险 | @@ -137,6 +137,11 @@ def read_rows(xlsx: str) -> list[dict]: continue row["region"] = normalize_region(row.get("office")) + # 历史取值改名(2026-09-20):项目归属 新签订单 → 华智下单;项目状态 交付中 → 进行中 + if row.get("origin") == "新签订单": + row["origin"] = "华智下单" + if row.get("project_status") == "交付中": + row["project_status"] = "进行中" # 验收日期(真实日期,区别于 accept_date 季度文本):仅对「已验收」且验收时间为季度文本的项目, # 补一个当年季度末占位,使「本年/本月验收」统计有数可算。用户后续在界面上改了真日期不会被覆盖。 row["accept_date_real"] = None diff --git a/web/app.js b/web/app.js index bb63398..61483d5 100644 --- a/web/app.js +++ b/web/app.js @@ -31,6 +31,8 @@ customStage: "", customStatus: "", customOrigin: "", + customAcceptPlan: "", + customSort: null, // { key: amount | sign_date | update_date, dir: asc | desc } customArchived: "false", customRows: [], intakeType: "general", @@ -1472,12 +1474,12 @@ const CUSTOM_STATUS_COLOR = { 已验收: "#16a34a", 交付完成: "#0891b2", - 交付中: "#2563eb", + 进行中: "#2563eb", 待开发: "#b45309", 退单: "#7a8394", }; - /** 项目状态:已验收/交付完成/交付中/待开发/退单 */ + /** 项目状态:已验收/交付完成/进行中/待开发/退单 */ function statusPill(code) { if (!code) return `—`; const color = CUSTOM_STATUS_COLOR[code] || "#7a8394"; @@ -1496,8 +1498,8 @@ let keywordFocus = false; /** 定开「项目归属」取值:前三项视为「已下单」,提前交付为下单前状态 */ - const CUSTOM_ORIGINS = ["新签订单", "存量项目", "汇智直签", "提前交付", "其他"]; - const CUSTOM_PLACED = ["新签订单", "存量项目", "汇智直签"]; + const CUSTOM_ORIGINS = ["华智下单", "存量项目", "汇智直签", "提前交付"]; + const CUSTOM_PLACED = ["华智下单", "存量项目", "汇智直签"]; const isPlaced = (p) => CUSTOM_PLACED.indexOf(p.origin) >= 0; /** 年度计收目标(万元),来源《年度任务.xlsx》(Q1 35 / Q2 225 / Q3 160 / Q4 260,合计 680) */ const CUSTOM_ANNUAL_TARGETS = { 1: 35, 2: 225, 3: 160, 4: 260 }; @@ -1532,11 +1534,15 @@ ``; } - const STATUS_OPTIONS = ["已验收", "待开发", "交付完成", "交付中", "退单"]; + const STATUS_OPTIONS = ["已验收", "待开发", "交付完成", "进行中", "退单"]; const statusFilterHtml = `` + STATUS_OPTIONS.map((s) => ``).join(""); const originFilterHtml = `` + CUSTOM_ORIGINS.map((o) => ``).join(""); + // 推动验收计划:取数据里实际出现过的值 + const planVals = Array.from(new Set(allRows.map((p) => String(p.accept_plan || "").trim()).filter(Boolean))).sort(); + const planFilterHtml = `` + + planVals.map((v) => ``).join(""); const isList = state.customTab !== "weekly" && state.customTab !== "annual"; const toolbar = ` @@ -1550,6 +1556,7 @@ + 全部 ${allRows.length} 个项目` @@ -1572,6 +1579,8 @@ if (rs) rs.addEventListener("change", () => { state.customRegion = rs.value; renderCustom(); }); const st = $("#cStatus"); if (st) st.addEventListener("change", () => { state.customStatus = st.value; renderCustom(); }); + const ap = $("#cAcceptPlan"); + if (ap) ap.addEventListener("change", () => { state.customAcceptPlan = ap.value; renderCustom(); }); if (isList) bindKeyword("cKeyword", { enter: true }); const bn = $("#btnNewCustom"); if (bn) bn.addEventListener("click", () => openNewCustomDialog(() => afterWrite())); @@ -1582,6 +1591,7 @@ if (state.customOrigin) q.push("origin=" + encodeURIComponent(state.customOrigin)); if (state.customRegion) q.push("region=" + encodeURIComponent(state.customRegion)); if (state.customStatus) q.push("status=" + encodeURIComponent(state.customStatus)); + if (state.customAcceptPlan) q.push("accept_plan=" + encodeURIComponent(state.customAcceptPlan)); if (state.keyword) q.push("keyword=" + encodeURIComponent(state.keyword)); download("/api/export/custom?" + q.join("&")); }); @@ -1589,19 +1599,24 @@ } function renderCustomList(allRows) { - // 列表:按 关键字 + 归属 + 区域 + 状态 在本地筛选;并按「更新时间」倒序 + // 列表:按 关键字 + 归属 + 区域 + 状态 + 推动验收计划 在本地筛选;再按表头排序 const kw = (state.keyword || "").trim(); let list = allRows; if (kw) list = list.filter((p) => String(p.name || "").includes(kw)); if (state.customOrigin) list = list.filter((p) => (p.origin || "") === state.customOrigin); if (state.customRegion) list = list.filter((p) => (p.region || "") === state.customRegion); if (state.customStatus) list = list.filter((p) => (p.project_status || "") === state.customStatus); - const view = list.slice().sort((a, b) => - String(b.update_date || "").localeCompare(String(a.update_date || "")) - ); + if (state.customAcceptPlan) list = list.filter((p) => String(p.accept_plan || "").trim() === state.customAcceptPlan); + const s = state.customSort || { key: "update_date", dir: "desc" }; + const sv = (p, k) => (k === "amount" ? Number(p.amount || 0) : String(p[k] || "")); + const view = list.slice().sort((a, b) => { + const va = sv(a, s.key), vb = sv(b, s.key); + const c = va < vb ? -1 : va > vb ? 1 : 0; + return s.dir === "asc" ? c : -c; + }); // ---- 统计条:基于「全部已下单项目」,不随搜索 / 筛选变化 ---- - const placed = allRows.filter(isPlaced); // 已下单 = 新签订单 / 存量项目 / 汇智直签 + const placed = allRows.filter(isPlaced); // 已下单 = 华智下单 / 存量项目 / 汇智直签 const today = new Date(); const Y = today.getFullYear(); const M = today.getMonth() + 1; @@ -1634,47 +1649,48 @@ ${stat(`本季度验收(${Y}年Q${Q})`, accQuarter.length, sum(accQuarter, "amount"), "var(--amber)")} ${stat(`本年验收项目(${Y}年)`, accYear.length, sum(accYear, "amount"), "var(--amber)")} -
「已下单项目 / 合同额」与「本季度·本年下单」只统计 新签订单 / 存量项目 / 汇智直签(提前交付不计入下单);统计基于全部项目,不受搜索 / 筛选影响。
`; +
「已下单项目 / 合同额」与「本季度·本年下单」只统计 华智下单 / 存量项目 / 汇智直签(提前交付不计入下单);统计基于全部项目,不受搜索 / 筛选影响。
`; const manDays = view.reduce((a, p) => a + Number(p.man_days || 0), 0); const highRisk = view.filter((p) => String(p.risk_level || "").includes("高")).length; const accepted = view.filter((p) => p.project_status === "已验收").length; + const sortLabel = { sign_date: "下单时间", amount: "订单金额", update_date: "更新时间" }[s.key] || "更新时间"; return `
-

定开项目总览按「更新时间」倒序 · 共 ${view.length} 个${state.customStatus ? "(" + esc(state.customStatus) + ")" : ""} · 列表只读,改数据请点「修改」

+

定开项目总览按「${sortLabel}」${s.dir === "asc" ? "升序" : "降序"} · 共 ${view.length} 个${state.customStatus ? "(" + esc(state.customStatus) + ")" : ""} · 点表头(下单时间 / 订单金额 / 更新时间)可排序;列表只读,改数据请点「修改」

人天 ${manDays.toLocaleString()} · 高风险 ${highRisk} 个 · 已验收 ${accepted} 个 -
- -
${statBar} ${view.length ? customTableHtml(view) : `
${state.keyword ? "没有匹配「" + esc(state.keyword) + "」的定开项目" : "当前筛选条件下没有定开项目"}
`}
`; } - /** 定开项目表格(「项目明细」与「本周进展」两个 tab 共用) */ + /** 定开项目表格(「项目总览」与「本周进展」两个 tab 共用);下单时间 / 订单金额 / 更新时间 表头可排序 */ function customTableHtml(view, withOps) { const ops = withOps !== false; + const s = state.customSort || { key: "update_date", dir: "desc" }; + const sth = (label, k, cls) => + `${label}${s.key === k ? (s.dir === "asc" ? " ▲" : " ▼") : ""}`; return `
- + ${sth("下单时间", "sign_date")} - + ${sth("订单金额", "amount", "num")} + ${sth("更新时间", "update_date")} - ${ops ? `` : ""} @@ -1696,12 +1712,12 @@ - + - + ${ops ? `` : ""} `).join("")} @@ -1723,25 +1739,25 @@ const sum = (arr, f) => arr.reduce((a, p) => a + Number(p[f] || 0), 0); const acc = week.filter((p) => p.project_status === "已验收"); - // 本周新增项目:按「下单时间」在本周的新下单 / 提前交付项目(不是「本周更新」) + // 新增项目:按「下单时间」在本周的新下单 / 提前进行中项目(不是「本周更新」) const newDeal = allRows.filter((p) => inWeek(p.sign_date) && (isPlaced(p) || p.origin === "提前交付")); - // 交付项目:本周更新的「交付中 + 交付完成」 - const doing = week.filter((p) => p.project_status === "交付中" || p.project_status === "交付完成"); + // 进行中项目:本周更新的「进行中 + 交付完成」 + const doing = week.filter((p) => p.project_status === "进行中" || p.project_status === "交付完成"); const stat = (label, rows, color) => `
${rows.length}个 · ${fen(sum(rows, "amount"))}万
${label}
`; const statBar = `
${stat("验收情况", acc, "var(--amber)")} - ${stat("本周新增项目", newDeal, "var(--violet)")} - ${stat("交付项目", doing, "var(--primary)")} + ${stat("新增项目", newDeal, "var(--violet)")} + ${stat("进行中项目", doing, "var(--primary)")}
-
本周 = ${start} ~ ${end};本周新增项目 = 按「下单时间」在本周的新下单 / 提前交付项目(已下单 + 提前交付);验收情况 / 交付项目 为「更新时间」在本周的项目(交付项目 = 交付中 + 交付完成)。
`; +
本周 = ${start} ~ ${end};新增项目 = 按「下单时间」在本周的新下单 / 提前进行中项目(已下单 + 提前交付);验收情况 / 进行中项目 为「更新时间」在本周的项目(进行中项目 = 进行中 + 交付完成)。
`; return `

本周进展更新时间在本周(${start} ~ ${end})· 共 ${week.length} 个项目 · 列表只读,改数据请点项目名称

- 验收 ${acc.length} · 新增 ${newDeal.length} · 交付 ${doing.length} + 验收 ${acc.length} · 新增 ${newDeal.length} · 进行中 ${doing.length}
${statBar} ${week.length @@ -1808,11 +1824,11 @@
项目名称 项目ID下单时间项目归属 办事处 行业 市场下单人天订单金额市场责任人 项目状态 进度 验收时间 推动验收计划 风险值备注更新时间操作
${money(p.amount)} ${esc(p.market_owner || "—")} ${statusPill(p.project_status)}${(p.project_status === "交付中" || Number(p.progress || 0) > 0) ? Math.round(p.progress || 0) + "%" : "—"}${(p.project_status === "进行中" || Number(p.progress || 0) > 0) ? Math.round(p.progress || 0) + "%" : "—"} ${p.accept_date ? esc(p.accept_date) : "—"} ${esc(p.accept_plan || "—")} ${riskPill(p.risk_level)}${esc((p.remark || "").slice(0, 40)) || "—"} ${esc(p.update_date || "—")}${esc((p.remark || "").slice(0, 40)) || "—"}
-
计收项目 = 按「验收时间」归属季度的项目;新增签单 = 按「下单时间」归属本年度季度、且项目归属为已下单(新签订单 / 存量项目 / 汇智直签)的项目;金额由「元」换算为「万元」;计收完成率 = 计收项目金额 ÷ 计收目标。
+
计收项目 = 按「验收时间」归属季度的项目;新增签单 = 按「下单时间」归属本年度季度、且项目归属为已下单(华智下单 / 存量项目 / 汇智直签)的项目;金额由「元」换算为「万元」;计收完成率 = 计收项目金额 ÷ 计收目标。
`; } - /** 项目明细表:列表只读,行内只有「修改」;名称可点开详情 */ + /** 项目总览表:列表只读,行内只有「修改」;名称可点开详情;表头(下单时间 / 订单金额 / 更新时间)可排序 */ function bindCustomList(host) { host.querySelectorAll("[data-copen]").forEach((a) => a.addEventListener("click", () => openCustomDrawer(Number(a.dataset.copen), "view")) @@ -1820,44 +1836,14 @@ host.querySelectorAll("[data-cedit]").forEach((b) => b.addEventListener("click", () => openCustomDrawer(Number(b.dataset.cedit), "edit")) ); - const bp = $("#btnPurgeWeek"); - if (bp) bp.addEventListener("click", purgeWeek); - } - - /** 删除本周(周一~周日)更新的定开项目:先预览数量,二次确认后执行。 */ - async function purgeWeek() { - let pv; - try { - pv = await api("/custom/weekly-preview"); - } catch (e) { - return toast("读取本周更新失败:" + e.message); - } - if (!pv.count) { - return toast("本周(" + pv.start + " ~ " + pv.end + ")没有更新的定开项目"); - } - const ok = await confirmDialog({ - title: "删除本周更新的定开项目", - okText: "确认删除 " + pv.count + " 个", - danger: true, - requireText: "删除", - requirePlaceholder: "输入「删除」以确认", - body: - `

将删除更新时间在本周(${esc(pv.start)} ~ ${esc(pv.end)})内的定开项目:` + - `${pv.count} 个,合同额合计 ${fen(pv.amount)} 万。

` + - `
此操作会连同项目的更新记录一起删除,且不可撤销。` + - `若只是想标记,请在详情里改状态。
` + - (pv.names && pv.names.length - ? `
${pv.names.map((n) => esc(n)).join("、")}${pv.count > pv.names.length ? " …" : ""}
` - : ""), - }); - if (!ok) return; - try { - const r = await post("/custom/purge-week", {}); - toast("已删除本周更新的 " + r.deleted + " 个定开项目"); - afterWrite(); - } catch (e) { - toast("删除失败:" + e.message); - } + host.querySelectorAll("[data-sort]").forEach((th) => + th.addEventListener("click", () => { + const k = th.dataset.sort; + const cur = state.customSort || { key: "update_date", dir: "desc" }; + state.customSort = { key: k, dir: cur.key === k && cur.dir === "desc" ? "asc" : "desc" }; + renderCustom(); + }) + ); } /** @@ -1873,9 +1859,9 @@ // 选项直接对齐《定开项目.xlsx》台账字段取值 const opts = (list, sel) => list.map((v) => ``).join(""); - const originOpts = opts(CUSTOM_ORIGINS, "新签订单"); + const originOpts = opts(CUSTOM_ORIGINS, "华智下单"); const industryOpts = opts(["安平", "政府", "企业", "教育", "交通", "医疗", "高速", "行业", "其他"], ""); - const statusOpts = opts(["待开发", "交付中", "交付完成", "已验收", "退单"], "待开发"); + const statusOpts = opts(["待开发", "进行中", "交付完成", "已验收", "退单"], "待开发"); const riskOpts = opts(["1.高风险", "2.低风险"], "2.低风险"); const numVal = (sel) => ($(sel).value === "" ? null : Number($(sel).value)); const txtVal = (sel) => $(sel).value.trim() || null; @@ -1895,7 +1881,7 @@
-
+
@@ -2030,7 +2016,7 @@ const optList = (list, sel) => list.map((v) => ``).join(""); const originOpts = optList(CUSTOM_ORIGINS, p.origin); const industryOpts = optList(["安平", "政府", "企业", "教育", "交通", "医疗", "高速", "行业", "其他"], p.industry); - const statusOpts = optList(["待开发", "交付中", "交付完成", "已验收", "退单"], p.project_status); + const statusOpts = optList(["待开发", "进行中", "交付完成", "已验收", "退单"], p.project_status); const riskOpts = optList(["1.高风险", "2.低风险"], p.risk_level); // 市场台账(来源《定开项目.xlsx》):详情只读,修改模式给输入框 @@ -2065,7 +2051,7 @@ ${ro("市场下单人天", numOrDash(p.man_days))} ${ro("市场责任人", esc(p.market_owner || "—"))} ${ro("项目状态", statusPill(p.project_status))} - ${ro("进度", (p.project_status === "交付中" || Number(p.progress || 0) > 0) ? Math.round(p.progress || 0) + "%" : "—")} + ${ro("进度", (p.project_status === "进行中" || Number(p.progress || 0) > 0) ? Math.round(p.progress || 0) + "%" : "—")} ${ro("验收时间", esc(p.accept_date || "—"))} ${ro("推动验收计划", esc(p.accept_plan || "—"))} ${ro("风险值", riskPill(p.risk_level))} @@ -3342,7 +3328,7 @@ const UI_KEY = "unis.ui.v1"; const UI_FIELDS = ["view", "gran", "weekId", "monthIdx", "categoryId", "keyOnly", "keyword", "projOwner", "projIdleOnly", "showArchived", "focusFilter", "focusArchived", - "customTab", "customArchived", "customRegion", "customOrigin", "staffArchived", "staffGroup"]; + "customTab", "customArchived", "customRegion", "customOrigin", "customAcceptPlan", "customSort", "staffArchived", "staffGroup"]; function saveUI() { const o = {};