feat: 运营模块 + 全局 Slogan + 模板热加载

- 新增运营模块(侧边栏/panel/render,7条运营思考)
- 全局 Slogan 置于顶部品牌区(蓝白 pill 标签)
- flask_app.py 启用 TEMPLATES_AUTO_RELOAD
- 项目模块状态筛选改为 Tab(已签约/待签约)
This commit is contained in:
mac
2026-07-07 13:15:54 +08:00
parent b1e404af30
commit c12389fb89
4 changed files with 35 additions and 2 deletions

View File

@@ -20,6 +20,7 @@ app = Flask(
static_folder=str(ROOT / "static"),
)
app.secret_key = os.environ.get("SECRET_KEY", "opc-dev-secret-2026")
app.config["TEMPLATES_AUTO_RELOAD"] = True
app.register_blueprint(bp)
# 模块级执行迁移(保留 gunicorn --preload 行为:导入即触发)

View File

@@ -0,0 +1,20 @@
// operations.js — 运营模块
window.renderOperations = () => {
document.querySelector("#operations").innerHTML = `<div class="grid gap-4">
<section class="card p-6 max-w-4xl">
<h2 class="text-lg font-bold text-slate-800 mb-4">运营思考</h2>
<p class="text-slate-700 leading-relaxed mb-4"><strong>和内部联动,真正快速做实交付很重要</strong></p>
<ol class="list-decimal list-inside space-y-3 text-slate-600 leading-relaxed">
<li>门店的大屏幕,要上,一个视频拍摄出来,然后在几百家门店同步轮巡播放,还是很震撼的</li>
<li>拍摄的内容,按病种整理成不同的专区,然后以 H5 或者小程序的形式,在门店科普教育,患者群,企业微信推送下去</li>
<li>同理,在保险的理赔环节,报案环节推送下去,而不是只是挂一个 H5 的专区</li>
<li>和门店、医生联动,把患者群都建立起来,把群的数量建起来</li>
<li>用源泉把患者的档案都建立起来真正的有档案沉淀AI 推送沉淀</li>
<li>用 AI + 人工,把随访量也都弄起来</li>
<li>对应的运营活动,还有排行版,在有一定量以后,要逐步的做起来,包括科普的排行版,科普的明星医生等等</li>
</ol>
<hr class="my-6 border-slate-200">
<p class="text-slate-700 font-semibold leading-relaxed">要形成一份专门的报告,真正的证明我们科普和患者管理的价值</p>
</section>
</div>`;
};

View File

@@ -151,6 +151,7 @@ function render() {
renderProjects();
renderProposals();
renderProducts();
renderOperations();
renderFinance();
renderExpense();
if (window.lucide) window.lucide.createIcons();
@@ -163,6 +164,7 @@ function renderActive() {
else if (tab === "projects") renderProjects();
else if (tab === "proposals") renderProposals();
else if (tab === "products") renderProducts();
else if (tab === "operations") renderOperations();
else if (tab === "finance") renderFinance();
if (window.lucide) window.lucide.createIcons();
}

View File

@@ -69,16 +69,24 @@
<i data-lucide="wallet-cards" style="width:20px;height:20px"></i>
<span class="text-[10px] mt-1">产品</span>
</div>
<div class="sidebar-tab" data-tab="operations" onclick="switchTab('operations')" title="运营">
<i data-lucide="trending-up" style="width:20px;height:20px"></i>
<span class="text-[10px] mt-1">运营</span>
</div>
</div>
</aside>
<!-- 主内容区 -->
<div class="flex-1 min-w-0">
<header class="topbar border-b border-slate-200 bg-white px-8 py-5">
<div class="flex items-center gap-3">
<div class="flex items-center justify-between gap-3">
<div>
<p class="eyebrow text-xs font-semibold uppercase tracking-[0.18em] text-blue-700">OPC Manager</p>
<div class="flex items-center gap-3 mt-1">
<div class="flex items-center gap-4 mt-1">
<h1 class="text-2xl font-semibold" id="workspaceTitle">科普 OPC 工作台</h1>
<div class="hidden sm:flex items-center gap-1.5 bg-gradient-to-r from-blue-50 to-indigo-50 border border-blue-100 rounded-full px-4 py-1.5">
<i data-lucide="sparkles" class="text-blue-500" style="width:14px;height:14px"></i>
<span class="text-xs text-blue-700 font-medium tracking-wide">真看病,看真病,用学术会议,科普,科研,患者管理,帮助医生与患者提升临床治疗</span>
</div>
</div>
</div>
</div>
@@ -89,6 +97,7 @@
<section id="projects" class="panel"></section>
<section id="proposals" class="panel"></section>
<section id="products" class="panel"></section>
<section id="operations" class="panel"></section>
<section id="finance" class="panel"></section>
<section id="expense" class="panel"></section>
</main>
@@ -118,6 +127,7 @@
<script src="{{ url_for('static', filename='modules/projects.js') }}"></script>
<script src="{{ url_for('static', filename='modules/proposals.js') }}"></script>
<script src="{{ url_for('static', filename='modules/products.js') }}"></script>
<script src="{{ url_for('static', filename='modules/operations.js') }}"></script>
<script src="{{ url_for('static', filename='modules/finance.js') }}"></script>
<script src="{{ url_for('static', filename='modules/expense.js') }}"></script>
<script src="{{ url_for('static', filename='modules/drawer.js') }}"></script>