/* ============================================================ * 项目后台 · 主入口 * 共享工具 / 状态 / 路由 / 登录 * 模块文件:project_list.js · project_detail.js · project_analysis.js * project_data.js · project_activity.js · project_drill.js * 依赖:core.js、wx.js * ============================================================ */ var $ = function (sel, root) { return (root || document).querySelector(sel); }; var $$ = function (sel, root) { return Array.prototype.slice.call((root || document).querySelectorAll(sel)); }; var ROLE_META = { advicer: { title: "销售维度", cls: "advicer", desc: "方言特征 / 句式习惯 / 语气性格 / 标志对话" }, project: { title: "项目维度", cls: "project", desc: "区域价值 / 竞品对比 / 核心卖点 / 配套 / 开发商背书" }, skill: { title: "聊天技巧维度", cls: "skill", desc: "需求挖掘 / 痛点应对 / 价值塑造 / 促单 / 沟通节奏" }, client: { title: "客户维度", cls: "client", desc: "客户画像(身份 / 动机 / 需求 / 顾虑 / 决策)" } }; var DIM_NAMES = [ ["desc", "行业/项目介绍"], ["advicer_desc", "销售作用说明"], ["client_dimension", "客户维度 模板"], ["project_dimension", "项目维度 模板"], ["advicer_dimension", "销售维度 模板"], ["talk_skill_dimension", "聊天技巧维度 模板"], ["rule_dimension", "风控维度 模板"] ]; // 维度名称列表(供 AI 生成对话框使用,过滤掉非维度字段) var DIMENSIONS = DIM_NAMES.filter(function (d) { return d[0].indexOf("_dimension") > 0; }).map(function (d) { return d[1].replace(" \u6a21\u677f", ""); }); var state = { view: (function () { try { return localStorage.getItem("as_current_view") || "projects"; } catch (e) { return "projects"; } })(), project: null, projects: { list: [], total: 0, page: 1, kw: "" }, detail: null, analysis: { file: null, result: null, running: false }, data: { tab: "advicers", advicerId: 0 }, activity: { list: [] }, drill: { sessionId: null, msgs: [], mission: "", busy: false }, wxMounted: false, wxAdvicer: null // 当前微信工作台归属销售 {advicerId, name} }; var VIEWS = { projects: { title: "项目管理", sub: "创建项目并复制行业模板,上传聊天记录进行 AI 分析", render: function () { renderProjects(); } }, projectDetail: { title: "项目设置", sub: "编辑基础信息与项目维度模板", render: function () { renderProjectDetail(); }, needProject: true }, analysis: { title: "聊天记录分析", sub: "上传销售与客户的聊天记录,AI 提取四大维度", render: function () { renderAnalysis(); }, needProject: true }, data: { title: "数据中心", sub: "管理销售 / 版本 / 技巧 / 客户", render: function () { renderData(); }, needProject: true }, activity: { title: "活动管理", sub: "发布产品活动,AI 按客户等级(熟客/意向/沉睡/非客户)自动推送邀约", render: function () { renderActivity(); }, needProject: true }, smart: { title: "智能策略", sub: "四级回复策略 / 熟客兜底 / 画像迭代 / 主动触达", render: function () { renderSmart(); }, needProject: true }, drill: { title: "AI 演练", sub: "模拟销售与客户对话,验证话术效果", render: function () { renderDrill(); }, needProject: true }, modelsup: { title: "模型配置", sub: "查看与修改当前项目的 AI 模型配置", render: function () { renderModelsup(); }, needProject: true }, wx: { title: "微信工作台", sub: "扫码登录微信 · 通讯录 · 聊天发送 · AI 话术建议", render: function () { renderWx(); }, needProject: true } }; /* ==================== 启动 ==================== */ document.addEventListener("DOMContentLoaded", function () { Core.onAuthFail = function () { Core.toast("登录已过期,请重新登录", "err"); showLogin(); }; $("#loginBtn").onclick = doLogin; $("#loginPwd").addEventListener("keydown", function (e) { if (e.key === "Enter") doLogin(); }); $("#logoutBtn").onclick = function () { Core.logout(); }; $$(".nav-item").forEach(function (item) { item.onclick = function () { if (item.dataset.href) { location.href = item.dataset.href; return; } var v = item.dataset.view; if (VIEWS[v].needProject && (!state.project || !state.project.projectId)) { Core.toast("请先在「项目管理」中进入一个项目", "err"); switchView("projects"); return; } // 数据中心快捷入口:设置 tab 后跳转 if (item.dataset.tab && v === "data") { state.data.tab = item.dataset.tab; } switchView(v); }; }); state.project = Core.store(Core.KEYS.project); console.log("[init] savedView=" + state.view + ", project=" + (state.project ? state.project.projectId : "null") + ", token=" + !!Core.store(Core.KEYS.token) + ", wxApp=" + JSON.stringify(Core.store(Core.KEYS.wxApp))); // 恢复视图:如果视图需要项目但没有项目,回退到 projectDetail var savedView = state.view; if (VIEWS[savedView] && VIEWS[savedView].needProject && (!state.project || !state.project.projectId)) { state.view = "projectDetail"; } // 「聊天记录分析」已从侧边栏隐藏:历史残留视图回退到数据中心 if (state.view === "analysis") state.view = "data"; refreshProjectBadge(); updateNavVisibility(); if (Core.store(Core.KEYS.token)) showApp(); else showLogin(); }); function showLogin() { $("#appView").classList.add("hidden"); $("#loginView").classList.remove("hidden"); } function showApp() { $("#loginView").classList.add("hidden"); $("#appView").classList.remove("hidden"); var admin = Core.store(Core.KEYS.admin) || {}; $("#sideAdmin").textContent = admin.name || "-"; $("#adminBadge").innerHTML = '' + Core.esc(admin.name || ""); switchView(state.view); } function doLogin() { var account = $("#loginAccount").value.trim(); var pwd = $("#loginPwd").value; if (!account || !pwd) { Core.toast("请输入账号和密码", "err"); return; } Core.loading(true, "正在登录…"); Core.api("login", { account: account, pwd: pwd }) .then(function (data) { Core.loading(false); if (!data || !data.token) { Core.toast("登录失败:响应异常", "err"); return; } Core.store(Core.KEYS.token, data.token); Core.store(Core.KEYS.admin, { admin_id: data.admin_id, name: data.name, account: data.account, type: data.type }); Core.toast("欢迎回来," + (data.name || account), "ok"); showApp(); }) .catch(function (e) { Core.loading(false); Core.toast(e.message, "err"); }); } function switchView(view) { console.log("[switchView] -> " + view + ", project=" + (state.project ? state.project.projectId : "null")); if (state.view === "wx" && view !== "wx" && window.Wx) { try { Wx.unmount(); } catch (ex) { } // 离开微信工作台时清除 URL hash if (location.hash) history.replaceState(null, '', location.pathname + location.search); } state.view = view; try { localStorage.setItem("as_current_view", view); } catch (e) { } var conf = VIEWS[view]; if (!conf) { view = "projects"; conf = VIEWS[view]; state.view = view; } // 数据中心根据当前 tab 动态显示标题 var title = conf.title; var sub = conf.sub; if (view === "data") { var tabMeta = { advicers: "销售管理", skills: "聊天技巧", clients: "客户管理", versions: "数字人管理" }; title = tabMeta[state.data.tab] || conf.title; sub = "管理当前项目下的" + (tabMeta[state.data.tab] || "数据"); } var pageTitle = $("#pageTitle"); var pageSub = $("#pageSub"); if (pageTitle) pageTitle.textContent = title; if (pageSub) pageSub.textContent = sub; // 高亮侧边栏 $$(".nav-item").forEach(function (i) { var match = i.dataset.view === view; if (match && i.dataset.tab && state.data.tab !== i.dataset.tab) match = false; if (match && view === "data" && !i.dataset.tab) match = false; i.classList.toggle("active", match); }); // 切换视图可见性 $$(".view").forEach(function (v) { v.classList.add("hidden"); }); var viewEl = $("#view-" + view); if (viewEl) viewEl.classList.remove("hidden"); // 渲染视图内容(保护性调用) try { conf.render(); } catch (e) { console.error("render error [" + view + "]:", e); } } function refreshProjectBadge() { var badge = $("#projectBadge"); if (!badge) return; if (state.project && state.project.projectId) { badge.className = "badge green"; badge.style.cssText = "cursor:pointer;position:relative"; badge.innerHTML = '#' + state.project.projectId + " " + Core.esc(state.project.name || "") + ' \u25bc'; } else { badge.className = "badge yellow"; badge.style.cssText = "cursor:pointer;position:relative"; badge.innerHTML = '\u672a\u9009\u62e9\u9879\u76ee \u25bc'; } // 绑定点击展开下拉 badge.onclick = function (e) { e.stopPropagation(); var existing = $(".pj-dropdown", badge); if (existing) { existing.remove(); return; } // 关闭其他已打开的下拉 var old = $(".pj-dropdown"); if (old) old.remove(); var dd = document.createElement("div"); dd.className = "pj-dropdown"; dd.innerHTML = '
' + '