## 安全与性能 - .env 环境变量、debug=False、except 改 mysql.connector.Error+logging - attach_common 批量 IN 查询消除 N+1 - 批量 esc() XSS 转义 ## 架构 - app.js 拆分为 7 模块 + admin.js - .form-ctrl 统一表单控件 ## 经营管理 - 字段改名:客户名称→项目名称、销售人员→商务负责人 - 必填:项目名称/商务负责人/经营负责人/签约月份/签约金额>0 - 视图切换:确收/毛利 ↔ 回款/费用 ## 重点工作与台账 - 统计卡片样式与经营管理统一 - 任务状态简化 3 态 - 优先级点击切换、右键菜单(重命名/副本) - 修复新建任务绑定错误项目 bug ## 用户体系 - 新增工作台:MCN·无界、无界·无界 - 新增账号:mcn/wuji - 账号管理后台(admin 限定) - sidebar 顶部头像+显示名,点击弹菜单 - sidebar sticky 定位 ## 其他 - 登录页样式优化(参考 UOC 平台) - 首页财务趋势拆 3 图 - 业务方案标准资料库双 Tab
141 lines
9.1 KiB
HTML
141 lines
9.1 KiB
HTML
<!doctype html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>科普(慰心斋)OPC 工作台</title>
|
||
<script src="{{ url_for('static', filename='vendor/tailwind.js') }}"></script>
|
||
<script>
|
||
tailwind.config = {
|
||
theme: {
|
||
extend: {
|
||
colors: {
|
||
brand: {
|
||
50: '#eff6ff',
|
||
600: '#2563eb',
|
||
700: '#1d4ed8'
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
|
||
<script src="{{ url_for('static', filename='vendor/chart.js') }}" defer></script>
|
||
<script src="{{ url_for('static', filename='vendor/squire.js') }}" defer></script>
|
||
<script src="{{ url_for('static', filename='vendor/lucide.js') }}" defer></script>
|
||
</head>
|
||
<body class="min-h-screen bg-slate-50 text-slate-950">
|
||
<div class="flex min-h-screen">
|
||
<!-- 左侧工作台切换栏 -->
|
||
<aside class="w-[72px] bg-slate-900 flex flex-col items-center py-6 gap-1 shrink-0 sticky top-0 h-screen overflow-y-auto" id="workspaceSidebar">
|
||
<div class="flex flex-col items-center mb-6 cursor-pointer" onclick="document.getElementById('userAvatar').click()">
|
||
<div class="w-10 h-10 rounded-full bg-slate-700 flex items-center justify-center text-white font-bold text-sm hover:ring-2 hover:ring-blue-400 transition-all" id="userAvatar" title=""></div>
|
||
<span class="text-[10px] text-slate-400 mt-1.5 max-w-[64px] truncate text-center" id="userDisplayName" title=""></span>
|
||
</div>
|
||
<div class="workspace-nav-item active" data-tenant="科普·无界" onclick="switchTenant('科普·无界')" title="科普·无界">
|
||
<svg class="w-6 h-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M8 12h8"/><path d="M12 8v8"/></svg>
|
||
<span class="text-[10px] mt-1">科普</span>
|
||
</div>
|
||
<div class="workspace-nav-item" data-tenant="科研·无界" onclick="switchTenant('科研·无界')" title="科研·无界">
|
||
<svg class="w-6 h-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>
|
||
<span class="text-[10px] mt-1">科研</span>
|
||
</div>
|
||
<div class="workspace-nav-item" data-tenant="医患·无界" onclick="switchTenant('医患·无界')" title="医患·无界">
|
||
<svg class="w-6 h-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 12h-4l-3 9L9 3l-3 9H2"/></svg>
|
||
<span class="text-[10px] mt-1">医患</span>
|
||
</div>
|
||
<div class="workspace-nav-item" data-tenant="MCN·无界" onclick="switchTenant('MCN·无界')" title="MCN·无界">
|
||
<svg class="w-6 h-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="7" width="20" height="15" rx="2"/><path d="M17 2l-5 5-5-5"/></svg>
|
||
<span class="text-[10px] mt-1">MCN</span>
|
||
</div>
|
||
<div class="workspace-nav-item" data-tenant="无界·无界" onclick="switchTenant('无界·无界')" title="无界·无界">
|
||
<svg class="w-6 h-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
|
||
<span class="text-[10px] mt-1">无界</span>
|
||
</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>
|
||
<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">
|
||
<h1 class="text-2xl font-semibold" id="workspaceTitle">科普 OPC 工作台</h1>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<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="finance"><i data-lucide="briefcase-business"></i>经营管理</button>
|
||
<button data-tab="projects"><i data-lucide="file-text"></i>重点工作与台账</button>
|
||
<button data-tab="proposals"><i data-lucide="package"></i>业务方案</button>
|
||
<button data-tab="products"><i data-lucide="wallet-cards"></i>产品迭代</button>
|
||
</nav>
|
||
|
||
<main class="px-8 py-6">
|
||
<section id="home" class="panel active"></section>
|
||
<section id="projects" class="panel"></section>
|
||
<section id="proposals" class="panel"></section>
|
||
<section id="products" class="panel"></section>
|
||
<section id="finance" class="panel"></section>
|
||
</main>
|
||
</div><!-- 关闭主内容区 -->
|
||
</div><!-- 关闭 flex 容器 -->
|
||
<aside id="drawer" class="drawer" aria-hidden="true"></aside>
|
||
<div id="taskModal" class="task-modal"></div>
|
||
<div id="transferModal" class="hidden fixed inset-0 z-50 flex items-center justify-center bg-black/40" onclick="closeTransferModal()">
|
||
<div class="bg-white rounded-2xl shadow-2xl w-full max-w-sm mx-4" onclick="event.stopPropagation()">
|
||
<div class="flex items-center justify-between px-6 py-4 border-b border-slate-100">
|
||
<h3 class="text-lg font-semibold text-slate-800">跨工作台转移</h3>
|
||
<button class="btn btn-ghost btn-sm rounded-full w-8 h-8 p-0" onclick="closeTransferModal()"><i data-lucide="x"></i></button>
|
||
</div>
|
||
<form onsubmit="submitTransfer(event)" class="p-6 grid gap-4">
|
||
<input type="hidden" name="transfer_resource" id="transfer-resource" value="">
|
||
<input type="hidden" name="transfer_id" id="transfer-id" value="">
|
||
<p id="transfer-title-text" class="text-sm text-slate-600"></p>
|
||
<label class="block"><span class="text-xs font-medium text-slate-500">目标工作台</span>
|
||
<select name="transfer_tenant" class="form-ctrl mt-1">
|
||
<option value="科普·无界">科普·无界</option>
|
||
<option value="科研·无界">科研·无界</option>
|
||
<option value="医患·无界">医患·无界</option>
|
||
</select>
|
||
</label>
|
||
<div class="flex justify-end gap-3 pt-3">
|
||
<button type="button" class="btn btn-ghost btn-sm" onclick="closeTransferModal()">取消</button>
|
||
<button type="submit" class="btn btn-primary btn-sm">确认转移</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<!-- 新增项目模态框 -->
|
||
<div id="newProjectModal" class="hidden fixed inset-0 z-50 flex items-center justify-center bg-black/40" onclick="closeNewProjectModal()">
|
||
<div class="bg-white rounded-2xl shadow-2xl w-full max-w-md mx-4" onclick="event.stopPropagation()">
|
||
<div class="flex items-center justify-between px-6 py-4 border-b border-slate-100">
|
||
<h3 class="text-lg font-semibold text-slate-800">新增项目</h3>
|
||
<button class="btn btn-ghost btn-sm rounded-full w-8 h-8 p-0" onclick="closeNewProjectModal()"><i data-lucide="x"></i></button>
|
||
</div>
|
||
<form onsubmit="createOperation(event)" class="p-6 grid gap-4">
|
||
<label class="block"><span class="text-xs font-medium text-slate-500">项目名称</span><input name="project_name" required class="form-ctrl mt-1"></label>
|
||
<label class="block"><span class="text-xs font-medium text-slate-500">项目备注</span><textarea name="notes" rows="3" class="form-ctrl mt-1" placeholder="可选"></textarea></label>
|
||
<div class="flex justify-end gap-3 pt-3 border-t border-slate-100">
|
||
<button type="button" class="btn btn-ghost btn-sm" onclick="closeNewProjectModal()">取消</button>
|
||
<button type="submit" class="btn btn-primary btn-sm">创建</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<script src="{{ url_for('static', filename='modules/utils.js') }}"></script>
|
||
<script src="{{ url_for('static', filename='modules/home.js') }}"></script>
|
||
<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/finance.js') }}"></script>
|
||
<script src="{{ url_for('static', filename='modules/drawer.js') }}"></script>
|
||
<script src="{{ url_for('static', filename='modules/admin.js') }}"></script>
|
||
<script src="{{ url_for('static', filename='app.js') }}"></script>
|
||
</body>
|
||
</html>
|