mirror of
https://github.com/hpd840321/craftlabs-authorization-sdk.git
synced 2026-06-09 10:00:30 +08:00
feat(web): add full platform layout mockup with Figma tokens - all business modules interactive
This commit is contained in:
@@ -1,132 +1,248 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="font-family:-apple-system,BlinkMacSystemFont,sans-serif;background:#f0f2f5;min-height:100vh;padding:20px">
|
<div style="height:100vh;overflow:hidden;font-family:-apple-system,BlinkMacSystemFont,sans-serif;font-size:13px;display:flex;flex-direction:column">
|
||||||
<!-- 页面标题 -->
|
<!-- ========== HEADER 60px ========== -->
|
||||||
<div style="max-width:1400px;margin:0 auto 20px">
|
<header style="height:60px;background:#fff;border-bottom:1px solid #E8ECF1;display:flex;align-items:center;padding:0 20px;flex-shrink:0;z-index:10">
|
||||||
<h1 style="font-size:22px;font-weight:700;color:#303133;margin-bottom:6px">布局结构对比审核</h1>
|
<div style="display:flex;align-items:center;gap:32px">
|
||||||
<p style="font-size:13px;color:#909399">Figma「数字资源系统-资源管理」vs delivery-platform-ui「MainLayout」</p>
|
<div style="display:flex;align-items:center;gap:8px">
|
||||||
</div>
|
<div style="width:28px;height:28px;background:linear-gradient(135deg,#2C3E6B,#3D5A99);border-radius:6px"></div>
|
||||||
|
<span style="font-weight:700;font-size:16px;color:#2C3E6B;letter-spacing:.5px">CraftLabs</span>
|
||||||
<!-- 整体布局对比 -->
|
|
||||||
<div style="max-width:1400px;margin:0 auto;display:flex;gap:20px;margin-bottom:20px">
|
|
||||||
<!-- Figma 布局 -->
|
|
||||||
<div style="flex:1;background:#fff;border-radius:8px;box-shadow:0 1px 4px rgba(0,0,0,.06);overflow:hidden">
|
|
||||||
<div style="padding:12px 16px;font-weight:600;font-size:14px;color:#2C3E6B;border-bottom:1px solid #EBEEF5;display:flex;align-items:center;gap:8px">
|
|
||||||
<span style="background:#2C3E6B;color:#fff;padding:2px 8px;border-radius:3px;font-size:11px">Figma</span> 数字资源系统-资源管理
|
|
||||||
</div>
|
</div>
|
||||||
<div style="padding:20px;font-size:13px">
|
<nav style="display:flex;gap:0">
|
||||||
<div style="background:#EAEFFA;border:1px dashed #2C3E6B;border-radius:4px;padding:2px">
|
<div v-for="item in topNav" :key="item" :class="['nav-item', { active: item===activeTopNav }]" @click="activeTopNav=item" style="padding:0 16px;height:60px;line-height:60px;cursor:pointer;color:#606266;font-size:14px;position:relative;transition:all .2s"
|
||||||
<!-- Header -->
|
:style="item===activeTopNav?'color:#2C3E6B;font-weight:600':''">
|
||||||
<div style="background:#fff;height:30px;margin-bottom:2px;display:flex;align-items:center;justify-content:space-between;padding:0 10px;border-bottom:1px solid #EBEEF5;font-size:11px;color:#909399">
|
{{ item }}
|
||||||
<span>headerMenu 顶部菜单导航 <b>1920×60</b></span>
|
<div v-if="item===activeTopNav" style="position:absolute;bottom:0;left:16px;right:16px;height:2px;background:#2C3E6B;border-radius:1px 1px 0 0"></div>
|
||||||
<span style="color:#606266">Logo + 4项菜单 + 搜索框 + 🔔2 + 用户 + 设置</span>
|
|
||||||
</div>
|
|
||||||
<div style="display:flex">
|
|
||||||
<!-- Sidebar -->
|
|
||||||
<div style="background:#fff;width:70px;min-height:280px;border-right:1px solid #EBEEF5;padding:4px 6px;font-size:10px;color:#909399">
|
|
||||||
<div style="font-weight:600;color:#303133;margin-bottom:4px">Menu <b>232×1021</b></div>
|
|
||||||
<div style="background:#F2F5FC;padding:2px 4px;margin:2px 0;border-radius:2px">Logo 232×56</div>
|
|
||||||
<div style="background:#E8EDF5;padding:2px 4px;margin:2px 0;border-radius:2px">菜单1 · 76px</div>
|
|
||||||
<div style="padding:2px 4px;margin:1px 0">菜单2 · 50px</div>
|
|
||||||
<div style="padding:2px 4px;margin:1px 0">菜单3 · 42px</div>
|
|
||||||
<div style="padding:2px 4px;margin:1px 0">菜单4 · 88px</div>
|
|
||||||
<div style="padding:2px 4px;margin:1px 0">… 6 more</div>
|
|
||||||
<div style="margin-top:8px;padding:2px 4px;color:#606266">底部 232×56</div>
|
|
||||||
</div>
|
|
||||||
<!-- Content -->
|
|
||||||
<div style="flex:1;padding:5px 8px">
|
|
||||||
<div style="background:#fff;padding:4px 8px;font-size:10px;color:#606266;margin-bottom:4px;border-radius:2px;border:1px solid #EBEEF5">
|
|
||||||
▸ 面包屑 1648×<b>46px</b> 数字资源 › 资源管理
|
|
||||||
</div>
|
|
||||||
<div style="display:flex;gap:4px">
|
|
||||||
<div style="background:#fff;width:85px;min-height:180px;border:1px solid #EBEEF5;border-radius:2px;padding:4px;font-size:10px">
|
|
||||||
<div style="font-weight:600;color:#303133;margin-bottom:3px">Tree <b>280×909</b></div>
|
|
||||||
<div style="background:#F2F5FC;padding:2px 4px;margin:2px 0;border-radius:2px">🔍 搜索 240×32</div>
|
|
||||||
<div style="padding:2px 4px;color:#909399;margin:1px 0">├ 分类A</div>
|
|
||||||
<div style="padding:2px 4px;color:#909399;margin:1px 0">│ ├ 子类1</div>
|
|
||||||
<div style="padding:2px 4px;color:#909399;margin:1px 0">│ └ 子类2</div>
|
|
||||||
<div style="padding:2px 4px;color:#909399;margin:1px 0">└ 分类B</div>
|
|
||||||
</div>
|
|
||||||
<div style="flex:1;border:1px dashed #D6DFF0;border-radius:2px;padding:4px;font-size:10px">
|
|
||||||
<div style="font-weight:600;color:#303133;margin-bottom:3px">主内容区 <b>1368×959</b></div>
|
|
||||||
<div style="background:#F2F5FC;padding:3px 6px;margin:2px 0;border-radius:2px">工具栏 1368×<b>144px</b>(筛选/操作按钮)</div>
|
|
||||||
<div style="padding:3px 6px;margin:2px 0;color:#909399">表格/内容区 1368×<b>814px</b></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
<div style="margin-left:auto;display:flex;align-items:center;gap:12px">
|
||||||
|
<div style="display:flex;align-items:center;border:1px solid #E0E3E8;border-radius:6px;padding:4px 10px;gap:6px;width:220px;background:#F8F9FB">
|
||||||
|
<span style="color:#C0C4CC;font-size:14px">🔍</span>
|
||||||
|
<input v-model="globalSearch" placeholder="搜索许可证 / 客户 / 合同..." style="border:none;outline:none;flex:1;font-size:13px;background:transparent;color:#303133">
|
||||||
|
</div>
|
||||||
|
<div v-for="icon in ['🌐','🔔','⚙️']" :key="icon" style="width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:6px;cursor:pointer;font-size:14px;position:relative"
|
||||||
|
@mouseenter="hoverIcon=icon" @mouseleave="hoverIcon=''" :style="{background:hoverIcon===icon?'#F2F5FC':''}">
|
||||||
|
{{ icon }}
|
||||||
|
<span v-if="icon==='🔔'" style="position:absolute;top:4px;right:6px;width:16px;height:16px;background:#D54941;border-radius:50%;font-size:10px;color:#fff;line-height:16px;text-align:center">3</span>
|
||||||
|
</div>
|
||||||
|
<div style="display:flex;align-items:center;gap:6px;padding:4px 10px;border-radius:6px;cursor:pointer" @mouseenter="hoverUser=true" @mouseleave="hoverUser=false" :style="{background:hoverUser?'#F2F5FC':''}">
|
||||||
|
<div style="width:28px;height:28px;border-radius:50%;background:#2C3E6B;color:#fff;text-align:center;line-height:28px;font-size:12px;font-weight:600">黄</div>
|
||||||
|
<span style="color:#303133;font-weight:500">huangping</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
<!-- 当前前端布局 -->
|
<!-- ========== BODY ========== -->
|
||||||
<div style="flex:1;background:#fff;border-radius:8px;box-shadow:0 1px 4px rgba(0,0,0,.06);overflow:hidden">
|
<div style="flex:1;display:flex;overflow:hidden;background:#EAEFFA">
|
||||||
<div style="padding:12px 16px;font-weight:600;font-size:14px;color:#409EFF;border-bottom:1px solid #EBEEF5;display:flex;align-items:center;gap:8px">
|
<!-- SIDEBAR 232px -->
|
||||||
<span style="background:#409EFF;color:#fff;padding:2px 8px;border-radius:3px;font-size:11px">NOW</span> delivery-platform-ui MainLayout
|
<aside style="width:232px;background:#fff;border-right:1px solid #E8ECF1;overflow-y:auto;flex-shrink:0;display:flex;flex-direction:column;padding-top:8px">
|
||||||
</div>
|
<div style="padding:4px 20px 12px;font-size:12px;color:#C0C4CC;text-transform:uppercase;letter-spacing:1px;font-weight:600">授权运营</div>
|
||||||
<div style="padding:20px;font-size:13px">
|
<div v-for="group in sidebarGroups" :key="group.label" style="margin-bottom:4px">
|
||||||
<div style="background:#f0f2f5;border:1px dashed #409EFF;border-radius:4px;padding:2px">
|
<div style="padding:4px 20px;font-size:11px;color:#C0C4CC;text-transform:uppercase;font-weight:600" v-if="group.label">{{ group.label }}</div>
|
||||||
<div style="background:#fff;height:30px;margin-bottom:2px;display:flex;align-items:center;justify-content:flex-end;padding:0 10px;border-bottom:1px solid #EBEEF5;font-size:11px;color:#909399">
|
<div v-for="item in group.items" :key="item.key" :class="['menu-item', { active: item.key===activeModule }]" @click="activeModule=item.key"
|
||||||
<span>el-header 自适应高度 <span style="color:#606266">用户名 + 退出按钮</span></span>
|
:style="{display:'flex',alignItems:'center',gap:10,padding:'8px 20px',cursor:'pointer',fontSize:'14px',transition:'all .15s',
|
||||||
</div>
|
color:item.key===activeModule?'#2C3E6B':'#606266',
|
||||||
<div style="display:flex">
|
background:item.key===activeModule?'#F2F5FC':'',
|
||||||
<div style="background:#001529;width:70px;min-height:280px;padding:4px 6px;font-size:10px;color:#fff">
|
borderRight:item.key===activeModule?'3px solid #2C3E6B':'3px solid transparent',
|
||||||
<div style="font-weight:600;margin-bottom:4px">Aside <b>220px</b></div>
|
fontWeight:item.key===activeModule?600:400}">
|
||||||
<div style="background:rgba(255,255,255,.1);padding:2px 4px;margin:2px 0;border-radius:2px">首页</div>
|
<span style="font-size:14px;width:20px;text-align:center">{{ item.icon }}</span>
|
||||||
<div style="background:rgba(255,255,255,.1);padding:2px 4px;margin:2px 0;border-radius:2px">客户管理</div>
|
<span>{{ item.name }}</span>
|
||||||
<div style="padding:2px 4px;margin:1px 0;opacity:.7">项目管理</div>
|
<span v-if="item.badge" style="margin-left:auto;background:#D54941;color:#fff;font-size:10px;padding:1px 6px;border-radius:10px;font-weight:600">{{ item.badge }}</span>
|
||||||
<div style="padding:2px 4px;margin:1px 0;opacity:.7">合同管理</div>
|
|
||||||
<div style="padding:2px 4px;margin:1px 0;opacity:.7">交付管理</div>
|
|
||||||
<div style="padding:2px 4px;margin:1px 0;opacity:.7">许可 SN</div>
|
|
||||||
<div style="padding:2px 4px;margin:1px 0;opacity:.7">Callback</div>
|
|
||||||
<div style="padding:2px 4px;margin:1px 0;opacity:.7">集成环境</div>
|
|
||||||
<div style="padding:2px 4px;margin:1px 0;opacity:.7">产品线</div>
|
|
||||||
</div>
|
|
||||||
<div style="flex:1;padding:5px 8px">
|
|
||||||
<div style="background:#fff;padding:4px 8px;font-size:10px;color:#F56C6C;margin-bottom:4px;border-radius:2px;border:1px solid #FDE2E2">
|
|
||||||
❌ 无面包屑
|
|
||||||
</div>
|
|
||||||
<div style="border:1px dashed #C0C4CC;border-radius:2px;padding:4px;font-size:10px;min-height:180px">
|
|
||||||
<div style="font-weight:600;color:#303133;margin-bottom:3px">el-main 自适应</div>
|
|
||||||
<div style="background:#fff;padding:3px 6px;margin:2px 0;border-radius:2px;border:1px solid #EBEEF5">
|
|
||||||
el-card 列表页 · 全宽
|
|
||||||
</div>
|
|
||||||
<div style="padding:2px 6px;color:#909399;margin:1px 0">搜索栏 + 新建按钮</div>
|
|
||||||
<div style="padding:2px 6px;color:#909399;margin:1px 0">el-table + 分页</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div style="margin-top:auto;padding:12px 20px;border-top:1px solid #F2F5FC;font-size:11px;color:#C0C4CC">CraftLabs Platform v0.1.0</div>
|
||||||
</div>
|
</aside>
|
||||||
|
|
||||||
<!-- 差异分析表 -->
|
<!-- CONTENT -->
|
||||||
<div style="max-width:1400px;margin:0 auto">
|
<div style="flex:1;overflow:hidden;display:flex;flex-direction:column">
|
||||||
<div style="background:#fff;border-radius:8px;box-shadow:0 1px 4px rgba(0,0,0,.06);overflow:hidden">
|
<!-- Breadcrumb 46px -->
|
||||||
<div style="padding:12px 16px;font-weight:600;font-size:14px;color:#303133;border-bottom:1px solid #EBEEF5">📐 逐项差异分析</div>
|
<div style="height:46px;background:#fff;border-bottom:1px solid #E8ECF1;display:flex;align-items:center;padding:0 20px;gap:6px;font-size:13px;flex-shrink:0">
|
||||||
<div style="overflow-x:auto">
|
<span style="color:#909399">授权运营</span>
|
||||||
<table style="width:100%;border-collapse:collapse;font-size:13px">
|
<span style="color:#C0C4CC">›</span>
|
||||||
<thead>
|
<span style="color:#2C3E6B;font-weight:600">{{ activePageName }}</span>
|
||||||
<tr style="background:#F2F5FC">
|
</div>
|
||||||
<th style="padding:10px 14px;text-align:left;width:160px">布局元素</th>
|
|
||||||
<th style="padding:10px 14px;text-align:left;width:200px">Figma 规范</th>
|
<!-- Main area with optional tree -->
|
||||||
<th style="padding:10px 14px;text-align:left;width:200px">当前实现</th>
|
<div style="flex:1;display:flex;overflow:hidden">
|
||||||
<th style="padding:10px 14px;text-align:left;width:80px">状态</th>
|
<!-- Tree Panel 280px (shown for modules with tree) -->
|
||||||
<th style="padding:10px 14px;text-align:left">建议</th>
|
<div v-if="showTree" style="width:280px;background:#fff;border-right:1px solid #E8ECF1;overflow-y:auto;flex-shrink:0;padding:12px 0">
|
||||||
</tr>
|
<div style="padding:0 16px 10px">
|
||||||
</thead>
|
<div style="display:flex;align-items:center;border:1px solid #E0E3E8;border-radius:6px;padding:6px 10px;gap:6px;background:#F8F9FB">
|
||||||
<tbody>
|
<span style="color:#C0C4CC;font-size:12px">🔍</span>
|
||||||
<tr v-for="d in diffs" :key="d.element" style="border-bottom:1px solid #EBEEF5">
|
<input placeholder="搜索..." style="border:none;outline:none;flex:1;font-size:12px;background:transparent">
|
||||||
<td style="padding:10px 14px;font-weight:600;color:#303133">{{ d.element }}</td>
|
</div>
|
||||||
<td style="padding:10px 14px;color:#606266">{{ d.figma }}</td>
|
</div>
|
||||||
<td style="padding:10px 14px;color:#606266">{{ d.current }}</td>
|
<div v-for="t in treeNodes" :key="t.label" style="padding:5px 16px 5px 20px;cursor:pointer;font-size:13px;color:#606266;display:flex;align-items:center;gap:6px;transition:all .1s"
|
||||||
<td style="padding:10px 14px">
|
:style="t.active?{color:'#2C3E6B',fontWeight:600,background:'#F2F5FC',borderRight:'3px solid #2C3E6B'}:{}"
|
||||||
<span :style="{display:'inline-block',padding:'2px 8px',borderRadius:'3px',fontSize:'11px',fontWeight:600,color:'#fff',background:d.gap==='high'?'#F56C6C':d.gap==='med'?'#E6A23C':'#67C23A'}">{{ d.gap==='high'?'缺失':d.gap==='med'?'差异':'一致' }}</span>
|
@click="treeNodes.forEach(n=>n.active=false);t.active=true"
|
||||||
</td>
|
@mouseenter="t.hover=true" @mouseleave="t.hover=false"
|
||||||
<td style="padding:10px 14px;color:#303133">{{ d.suggestion }}</td>
|
:class="{'tree-hover': t.hover && !t.active}">
|
||||||
</tr>
|
<span style="font-size:12px;width:16px;text-align:center">{{ t.expanded ? '▾' : '▸' }}</span>
|
||||||
</tbody>
|
<span>{{ t.icon }}</span>
|
||||||
</table>
|
<span>{{ t.label }}</span>
|
||||||
|
<span v-if="t.count" style="margin-left:auto;font-size:11px;color:#C0C4CC">{{ t.count }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Main content panel -->
|
||||||
|
<div style="flex:1;overflow-y:auto;padding:16px 20px">
|
||||||
|
<!-- Module: Dashboard -->
|
||||||
|
<template v-if="activeModule==='dashboard'">
|
||||||
|
<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-bottom:16px">
|
||||||
|
<div v-for="s in dashboardStats" :key="s.label" class="stat-card" style="background:#fff;border-radius:6px;padding:18px;border:1px solid #E8ECF1;box-shadow:0 1px 2px rgba(0,0,0,.03)">
|
||||||
|
<div style="font-size:12px;color:#909399;margin-bottom:6px">{{ s.label }}</div>
|
||||||
|
<div style="font-size:28px;font-weight:700;color:#303133;margin-bottom:4px">{{ s.value }}</div>
|
||||||
|
<div :style="{fontSize:'12px',color:s.trend>0?'#67C23A':'#F56C6C'}">{{ s.trend > 0 ? '↑' : '↓' }} {{ Math.abs(s.trend) }}% 较上月</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="display:grid;grid-template-columns:2fr 1fr;gap:14px">
|
||||||
|
<div class="card" style="background:#fff;border-radius:6px;padding:16px;border:1px solid #E8ECF1">
|
||||||
|
<div style="font-weight:600;color:#303133;margin-bottom:12px">📊 许可证签发趋势</div>
|
||||||
|
<div style="height:200px;display:flex;align-items:flex-end;gap:12px;padding:0 8px">
|
||||||
|
<div v-for="(v,i) in [45,52,38,60,55,70,65,80]" :key="i" style="flex:1;background:linear-gradient(180deg,#2C3E6B,#3D5A99);border-radius:4px 4px 0 0" :style="{height:v+'px'}"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card" style="background:#fff;border-radius:6px;padding:16px;border:1px solid #E8ECF1">
|
||||||
|
<div style="font-weight:600;color:#303133;margin-bottom:12px">⚠️ 待处理事项</div>
|
||||||
|
<div v-for="a in alerts" :key="a.text" style="padding:8px 0;border-bottom:1px solid #F2F5FC;display:flex;align-items:center;gap:8px">
|
||||||
|
<span :style="{width:6,height:6,borderRadius:'50%',background:a.color}"></span>
|
||||||
|
<span style="flex:1;color:#606266">{{ a.text }}</span>
|
||||||
|
<span style="font-size:11px;color:#C0C4CC">{{ a.time }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Module: List + Table (used for most CRUD pages) -->
|
||||||
|
<template v-else-if="activeModule==='customers'||activeModule==='contracts'||activeModule==='deliveries'||activeModule==='license-sns'">
|
||||||
|
<div class="card" style="background:#fff;border-radius:6px;border:1px solid #E8ECF1;margin-bottom:12px">
|
||||||
|
<div style="padding:12px 16px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:10px">
|
||||||
|
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
|
||||||
|
<div style="border:1px solid #E0E3E8;border-radius:4px;padding:5px 10px;display:flex;align-items:center;gap:6px;background:#F8F9FB;width:200px">
|
||||||
|
<span style="color:#C0C4CC;font-size:12px">🔍</span>
|
||||||
|
<input :placeholder="'搜索'+activePageName+'...'" style="border:none;outline:none;flex:1;font-size:13px;background:transparent">
|
||||||
|
</div>
|
||||||
|
<select style="border:1px solid #E0E3E8;border-radius:4px;padding:5px 10px;font-size:13px;color:#606266;background:#fff">
|
||||||
|
<option>全部状态</option><option>活跃</option><option>已吊销</option>
|
||||||
|
</select>
|
||||||
|
<button style="border:none;background:#2C3E6B;color:#fff;padding:6px 14px;border-radius:4px;font-size:13px;cursor:pointer;font-weight:500">查询</button>
|
||||||
|
</div>
|
||||||
|
<button style="border:none;background:#2C3E6B;color:#fff;padding:7px 16px;border-radius:4px;font-size:13px;cursor:pointer;font-weight:500;box-shadow:0 2px 6px rgba(44,62,107,.2)">+ 新建{{ activePageName }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Table -->
|
||||||
|
<div class="card" style="background:#fff;border-radius:6px;border:1px solid #E8ECF1;overflow:hidden">
|
||||||
|
<table style="width:100%;border-collapse:collapse;font-size:13px">
|
||||||
|
<thead><tr style="background:#F2F5FC;color:#2C3E6B;font-weight:600"><th style="padding:10px 14px;text-align:left;font-size:12px">ID/编号</th><th style="padding:10px 14px;text-align:left;font-size:12px">名称/标题</th><th style="padding:10px 14px;text-align:left;font-size:12px">关联</th><th style="padding:10px 14px;text-align:left;font-size:12px">状态</th><th style="padding:10px 14px;text-align:left;font-size:12px">更新时间</th><th style="padding:10px 14px;text-align:left;font-size:12px;width:120px">操作</th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="i in 5" :key="i" style="border-bottom:1px solid #F2F5FC" @mouseenter="rowHover=i" @mouseleave="rowHover=0" :style="{background:rowHover===i?'#FAFBFC':''}">
|
||||||
|
<td style="padding:10px 14px;font-family:monospace;color:#303133;font-size:12px">{{ 'CT-2026-0'+((i-1)*2+1).toString().padStart(3,'0') }}</td>
|
||||||
|
<td style="padding:10px 14px;color:#303133;font-weight:500">{{ mockNames[i-1] }}</td>
|
||||||
|
<td style="padding:10px 14px;color:#606266">{{ mockRefs[i-1] }}</td>
|
||||||
|
<td style="padding:10px 14px"><span :style="{display:'inline-block',padding:'2px 8px',borderRadius:'3px',fontSize:'11px',fontWeight:500,background:i===3?'#fef0f0':'#E6F7EE',color:i===3?'#F56C6C':'#1A7A3A',border:'1px solid '+(i===3?'#fbc4c4':'#A8E6C1')}">{{ i===3?'已吊销':'活跃' }}</span></td>
|
||||||
|
<td style="padding:10px 14px;color:#909399;font-size:12px">2026-05-{{ (15-i*2).toString().padStart(2,'0') }}</td>
|
||||||
|
<td style="padding:10px 14px"><span style="color:#2C3E6B;cursor:pointer;margin-right:12px">详情</span><span style="color:#F56C6C;cursor:pointer">吊销</span></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div style="padding:10px 16px;display:flex;justify-content:flex-end;align-items:center;gap:8px;font-size:12px;color:#909399;border-top:1px solid #F2F5FC">
|
||||||
|
<span>共 128 条</span><span style="cursor:pointer;color:#606266;font-weight:600">‹</span><span style="color:#2C3E6B;font-weight:600">1</span><span style="cursor:pointer;color:#606266">2</span><span>…</span><span style="cursor:pointer;color:#606266">13</span><span style="cursor:pointer;color:#606266;font-weight:600">›</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Module: License Management (NEW - selfhosted key page) -->
|
||||||
|
<template v-else-if="activeModule==='licenses'">
|
||||||
|
<div class="card" style="background:#fff;border-radius:6px;border:1px solid #E8ECF1;margin-bottom:12px">
|
||||||
|
<div style="padding:12px 16px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:10px">
|
||||||
|
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
|
||||||
|
<div style="border:1px solid #E0E3E8;border-radius:4px;padding:5px 10px;display:flex;align-items:center;gap:6px;background:#F8F9FB;width:200px">
|
||||||
|
<span style="color:#C0C4CC;font-size:12px">🔍</span><input placeholder="搜索许可证ID..." style="border:none;outline:none;flex:1;font-size:13px;background:transparent">
|
||||||
|
</div>
|
||||||
|
<select style="border:1px solid #E0E3E8;border-radius:4px;padding:5px 10px;font-size:13px;color:#606266;background:#fff"><option>全部授权类型</option><option>订阅</option><option>永久</option><option>试用</option></select>
|
||||||
|
<select style="border:1px solid #E0E3E8;border-radius:4px;padding:5px 10px;font-size:13px;color:#606266;background:#fff"><option>全部状态</option><option>活跃</option><option>已吊销</option><option>已过期</option></select>
|
||||||
|
<button style="border:none;background:#2C3E6B;color:#fff;padding:6px 14px;border-radius:4px;font-size:13px;cursor:pointer;font-weight:500">查询</button>
|
||||||
|
</div>
|
||||||
|
<button style="border:none;background:#2C3E6B;color:#fff;padding:7px 16px;border-radius:4px;font-size:13px;cursor:pointer;font-weight:500;box-shadow:0 2px 6px rgba(44,62,107,.2)">+ 签发许可证</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card" style="background:#fff;border-radius:6px;border:1px solid #E8ECF1;overflow:hidden">
|
||||||
|
<table style="width:100%;border-collapse:collapse;font-size:13px">
|
||||||
|
<thead><tr style="background:#F2F5FC;color:#2C3E6B;font-weight:600">
|
||||||
|
<th style="padding:10px 14px;text-align:left;font-size:12px">许可证 ID</th><th style="padding:10px 14px;text-align:left;font-size:12px">租户</th><th style="padding:10px 14px;text-align:left;font-size:12px">产品</th><th style="padding:10px 14px;text-align:left;font-size:12px">类型</th><th style="padding:10px 14px;text-align:left;font-size:12px">终端</th><th style="padding:10px 14px;text-align:left;font-size:12px">宽限</th><th style="padding:10px 14px;text-align:left;font-size:12px">状态</th><th style="padding:10px 14px;text-align:left;font-size:12px">签发时间</th><th style="padding:10px 14px;text-align:left;font-size:12px;width:120px">操作</th>
|
||||||
|
</tr></thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="l in licenseData" :key="l.id" style="border-bottom:1px solid #F2F5FC">
|
||||||
|
<td style="padding:10px 14px;font-family:monospace;color:#303133;font-size:12px">{{ l.id }}</td>
|
||||||
|
<td style="padding:10px 14px;color:#303133">{{ l.tenant }}</td>
|
||||||
|
<td style="padding:10px 14px;color:#606266">{{ l.product }}</td>
|
||||||
|
<td style="padding:10px 14px">{{ l.type }}</td>
|
||||||
|
<td style="padding:10px 14px;color:#606266;text-align:center">{{ l.devices }}</td>
|
||||||
|
<td style="padding:10px 14px;color:#606266;text-align:center">{{ l.grace }}天</td>
|
||||||
|
<td style="padding:10px 14px"><span :style="{display:'inline-block',padding:'2px 8px',borderRadius:'3px',fontSize:'11px',fontWeight:500,background:l.status==='active'?'#E6F7EE':l.status==='revoked'?'#fef0f0':'#f4f4f5',color:l.status==='active'?'#1A7A3A':l.status==='revoked'?'#F56C6C':'#909399',border:'1px solid '+(l.status==='active'?'#A8E6C1':l.status==='revoked'?'#fbc4c4':'#e9e9eb')}">{{ {active:'活跃',revoked:'已吊销',expired:'已过期'}[l.status] }}</span></td>
|
||||||
|
<td style="padding:10px 14px;color:#909399;font-size:12px">{{ l.issued }}</td>
|
||||||
|
<td style="padding:10px 14px"><span style="color:#2C3E6B;cursor:pointer;margin-right:12px">详情</span><span v-if="l.status==='active'" style="color:#F56C6C;cursor:pointer">吊销</span></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div style="padding:10px 16px;display:flex;justify-content:flex-end;align-items:center;gap:8px;font-size:12px;color:#909399;border-top:1px solid #F2F5FC">
|
||||||
|
<span>共 47 条</span><span style="cursor:pointer;color:#606266;font-weight:600">‹</span><span style="color:#2C3E6B;font-weight:600">1</span><span style="cursor:pointer;color:#606266">2</span><span>…</span><span style="cursor:pointer;color:#606266">5</span><span style="cursor:pointer;color:#606266;font-weight:600">›</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Module: Callback Inbox -->
|
||||||
|
<template v-else-if="activeModule==='callbacks'">
|
||||||
|
<div class="card" style="background:#fff;border-radius:6px;border:1px solid #E8ECF1;margin-bottom:12px">
|
||||||
|
<div style="padding:12px 16px;display:flex;gap:8px;align-items:center;flex-wrap:wrap">
|
||||||
|
<select v-for="f in callbackFilters" :key="f.label" style="border:1px solid #E0E3E8;border-radius:4px;padding:5px 10px;font-size:13px;color:#606266;background:#fff"><option>{{ f.label }}</option></select>
|
||||||
|
<button style="border:none;background:#2C3E6B;color:#fff;padding:6px 14px;border-radius:4px;font-size:13px;cursor:pointer;font-weight:500">查询</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card" style="background:#fff;border-radius:6px;border:1px solid #E8ECF1;overflow:hidden">
|
||||||
|
<table style="width:100%;border-collapse:collapse;font-size:13px">
|
||||||
|
<thead><tr style="background:#F2F5FC;color:#2C3E6B;font-weight:600"><th style="padding:10px 14px;text-align:left;font-size:12px">来源</th><th style="padding:10px 14px;text-align:left;font-size:12px">事件类型</th><th style="padding:10px 14px;text-align:left;font-size:12px">SN</th><th style="padding:10px 14px;text-align:left;font-size:12px">状态</th><th style="padding:10px 14px;text-align:left;font-size:12px">收件时间</th><th style="padding:10px 14px;text-align:left;font-size:12px;width:120px">操作</th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="c in callbackData" :key="c.id" style="border-bottom:1px solid #F2F5FC">
|
||||||
|
<td style="padding:10px 14px;color:#303133">{{ c.source }}</td><td style="padding:10px 14px;font-family:monospace;font-size:12px;color:#606266">{{ c.event }}</td>
|
||||||
|
<td style="padding:10px 14px;font-family:monospace;font-size:12px;color:#303133">{{ c.sn }}</td>
|
||||||
|
<td style="padding:10px 14px"><span :style="{display:'inline-block',padding:'2px 8px',borderRadius:'3px',fontSize:'11px',fontWeight:500,background:c.status==='PENDING'?'#FDF6EC':c.status==='PROCESSED'?'#E6F7EE':'#f4f4f5',color:c.status==='PENDING'?'#E6A23C':c.status==='PROCESSED'?'#1A7A3A':'#909399'}">{{ {PENDING:'待处理',PROCESSED:'已处理',IGNORED:'忽略'}[c.status] }}</span></td>
|
||||||
|
<td style="padding:10px 14px;color:#909399;font-size:12px">{{ c.time }}</td>
|
||||||
|
<td style="padding:10px 14px"><span style="color:#2C3E6B;cursor:pointer">详情</span></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Module: Integration -->
|
||||||
|
<template v-else-if="activeModule==='integration-envs'||activeModule==='integration-plines'">
|
||||||
|
<div class="card" style="background:#fff;border-radius:6px;border:1px solid #E8ECF1;overflow:hidden">
|
||||||
|
<table style="width:100%;border-collapse:collapse;font-size:13px">
|
||||||
|
<thead><tr style="background:#F2F5FC;color:#2C3E6B;font-weight:600"><th style="padding:10px 14px;text-align:left;font-size:12px">名称</th><th style="padding:10px 14px;text-align:left;font-size:12px">标识</th><th style="padding:10px 14px;text-align:left;font-size:12px">说明</th><th style="padding:10px 14px;text-align:left;font-size:12px">状态</th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="i in 4" :key="i" style="border-bottom:1px solid #F2F5FC"><td style="padding:10px 14px;color:#303133;font-weight:500">{{ ['生产环境','预发布','测试环境','开发环境'][i-1] }}</td><td style="padding:10px 14px;font-family:monospace;font-size:12px;color:#606266">{{ ['prod','staging','test','dev'][i-1] }}</td><td style="padding:10px 14px;color:#909399">—</td><td style="padding:10px 14px"><span :style="{display:'inline-block',padding:'2px 8px',borderRadius:'3px',fontSize:'11px',fontWeight:500,background:i===1?'#E6F7EE':'#f4f4f5',color:i===1?'#1A7A3A':'#909399'}">{{ i===1?'启用':'维护中' }}</span></td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Module: Settings -->
|
||||||
|
<template v-else-if="activeModule==='settings-keys'">
|
||||||
|
<div class="card" style="background:#fff;border-radius:6px;border:1px solid #E8ECF1;margin-bottom:12px;display:flex;align-items:center;justify-content:space-between;padding:12px 16px">
|
||||||
|
<span style="font-weight:600;color:#303133">RSA 密钥对管理</span>
|
||||||
|
<button style="border:none;background:#2C3E6B;color:#fff;padding:7px 16px;border-radius:4px;font-size:13px;cursor:pointer;font-weight:500">+ 生成密钥对</button>
|
||||||
|
</div>
|
||||||
|
<div class="card" style="background:#fff;border-radius:6px;border:1px solid #E8ECF1;overflow:hidden">
|
||||||
|
<table style="width:100%;border-collapse:collapse;font-size:13px">
|
||||||
|
<thead><tr style="background:#F2F5FC;color:#2C3E6B;font-weight:600"><th style="padding:10px 14px;text-align:left;font-size:12px">Key ID</th><th style="padding:10px 14px;text-align:left;font-size:12px">算法</th><th style="padding:10px 14px;text-align:left;font-size:12px">状态</th><th style="padding:10px 14px;text-align:left;font-size:12px">创建时间</th><th style="padding:10px 14px;text-align:left;font-size:12px;width:120px">操作</th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="k in keyData" :key="k.id" style="border-bottom:1px solid #F2F5FC"><td style="padding:10px 14px;font-family:monospace;font-size:12px;color:#303133">{{ k.id }}</td><td style="padding:10px 14px;color:#606266">{{ k.algo }}</td><td style="padding:10px 14px"><span :style="{display:'inline-block',padding:'2px 8px',borderRadius:'3px',fontSize:'11px',fontWeight:500,background:k.status==='active'?'#E6F7EE':'#f4f4f5',color:k.status==='active'?'#1A7A3A':'#909399'}">{{ k.status==='active'?'活跃':'已轮换' }}</span></td><td style="padding:10px 14px;color:#909399;font-size:12px">{{ k.time }}</td><td style="padding:10px 14px"><span style="color:#2C3E6B;cursor:pointer;margin-right:12px">查看公钥</span><span v-if="k.status==='active'" style="color:#E6A23C;cursor:pointer">轮换</span></td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -134,17 +250,110 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
const diffs = [
|
import { ref, computed } from 'vue'
|
||||||
{ element:'整体框架', figma:'Header(60) + Sidebar(232) + Content', current:'Header(Var) + Sidebar(220) + Content', gap:'low', suggestion:'✅ 结构与 Figma 一致' },
|
|
||||||
{ element:'Header 顶部导航', figma:'Logo(370×28) + 4菜单项(76×32) + 搜索框(240×32) + 通知Badge + 用户下拉', current:'仅「用户名 + 退出按钮」', gap:'high', suggestion:'🔴 需增加:搜索框、通知Badge、顶部菜单导航项' },
|
const activeModule = ref('dashboard')
|
||||||
{ element:'Sidebar 侧边栏', figma:'232px宽 | Logo(56px高) + 11菜单项(42-88px不等高) + 底部信息', current:'220px宽(深色背景) | 9菜单项(等高等间距)', gap:'med', suggestion:'⚠️ 宽度OK但菜单项缺少高度区分(主菜单/子菜单),底部缺少版本信息' },
|
const activeTopNav = ref('授权平台')
|
||||||
{ element:'面包屑 Breadcrumb', figma:'1648×46px | 内容区顶部 | 「数字资源 › 资源管理」', current:'❌ 完全缺失', gap:'high', suggestion:'🔴 各详情页/列表页顶部增加 el-breadcrumb,显示层级路径' },
|
const globalSearch = ref('')
|
||||||
{ element:'内容区左侧树', figma:'Tree面板 280×909px | 搜索框 + 资源分类树', current:'❌ 完全缺失', gap:'high', suggestion:'🔴 许可证管理页增加左侧 el-tree 展示客户/项目层级' },
|
const hoverIcon = ref('')
|
||||||
{ element:'主内容区宽高比', figma:'Tree(280) + 工具栏(144) + 表格(814)', current:'全宽卡片(el-card) + 搜索栏 + 表格', gap:'med', suggestion:'⚠️ 参考 Tree+Main 双栏布局;工具栏可压缩为搜索行' },
|
const hoverUser = ref(false)
|
||||||
{ element:'内容区顶部间距', figma:'面包屑距顶部20px, 面包屑与Tree间距0', current:'卡片直接顶格,无面包屑层', gap:'med', suggestion:'⚠️ 内容区顶部预留 12-16px padding + 面包屑行' },
|
const rowHover = ref(0)
|
||||||
{ element:'搜索栏位置', figma:'Header右侧(header内) + Tree面板内(小搜索)', current:'列表页卡片内(el-card header)', gap:'med', suggestion:'⚠️ 全局搜索放Header,页面内搜索放卡片header OK' },
|
|
||||||
{ element:'通知Badge', figma:'Header 右侧红色圆点 Badge(20×20) + 数字2', current:'❌ 完全缺失', gap:'high', suggestion:'🔴 Header 加 el-badge 显示待处理任务数(Callback)' },
|
const topNav = ['授权平台', '运营分析', '系统设置']
|
||||||
{ element:'菜单选中态', figma:'Instance 组件支持多级高亮', current:'el-menu router default-active OK', gap:'low', suggestion:'✅ Element Plus 原生支持' },
|
|
||||||
{ element:'响应式', figma:'固定 1920px(显示器标准)', current:'Element Plus 响应式 + 最小宽度', gap:'low', suggestion:'✅ 当前已适配' },
|
const sidebarGroups = [
|
||||||
|
{ label:'', items:[
|
||||||
|
{ key:'dashboard', icon:'📊', name:'工作台概览' },
|
||||||
|
]},
|
||||||
|
{ label:'业务管理', items:[
|
||||||
|
{ key:'customers', icon:'👥', name:'客户管理' },
|
||||||
|
{ key:'contracts', icon:'📋', name:'合同管理' },
|
||||||
|
{ key:'deliveries', icon:'📦', name:'交付管理' },
|
||||||
|
{ key:'license-sns', icon:'🔑', name:'许可 SN' },
|
||||||
|
]},
|
||||||
|
{ label:'授权运营', items:[
|
||||||
|
{ key:'licenses', icon:'🛡️', name:'许可证管理', badge:'NEW' },
|
||||||
|
{ key:'callbacks', icon:'📨', name:'Callback 收件箱', badge:'3' },
|
||||||
|
]},
|
||||||
|
{ label:'集成配置', items:[
|
||||||
|
{ key:'integration-envs', icon:'🌐', name:'集成环境' },
|
||||||
|
{ key:'integration-plines', icon:'📱', name:'产品线' },
|
||||||
|
]},
|
||||||
|
{ label:'系统运维', items:[
|
||||||
|
{ key:'settings-keys', icon:'🔐', name:'密钥管理' },
|
||||||
|
]},
|
||||||
|
]
|
||||||
|
|
||||||
|
const modulePageNames = {
|
||||||
|
dashboard:'工作台概览', customers:'客户管理', contracts:'合同管理',
|
||||||
|
deliveries:'交付管理', 'license-sns':'许可 SN', licenses:'许可证管理',
|
||||||
|
callbacks:'Callback 收件箱', 'integration-envs':'集成环境',
|
||||||
|
'integration-plines':'产品线', 'settings-keys':'密钥管理'
|
||||||
|
}
|
||||||
|
|
||||||
|
const activePageName = computed(() => modulePageNames[activeModule.value] || '—')
|
||||||
|
const showTree = computed(() => ['licenses','customers','contracts'].includes(activeModule.value))
|
||||||
|
|
||||||
|
const treeNodes = ref([
|
||||||
|
{ icon:'🏢', label:'创飞码头项目', expanded:true, active:true, count:12 },
|
||||||
|
{ icon:'🏫', label:'学校合作项目', expanded:false, active:false, count:8 },
|
||||||
|
{ icon:'🔬', label:'实验室项目', expanded:false, active:false, count:5 },
|
||||||
|
{ icon:'📐', label:'内部测试', expanded:false, active:false, count:3 },
|
||||||
|
])
|
||||||
|
|
||||||
|
const dashboardStats = [
|
||||||
|
{ label:'总许可证', value:47, trend:12 },
|
||||||
|
{ label:'活跃终端', value:183, trend:8 },
|
||||||
|
{ label:'待处理 Callback', value:3, trend:-25 },
|
||||||
|
{ label:'本月签发', value:15, trend:20 },
|
||||||
|
]
|
||||||
|
|
||||||
|
const alerts = [
|
||||||
|
{ text:'许可证 CT-2026-003 即将到期', time:'2h前', color:'#E6A23C' },
|
||||||
|
{ text:'Callback sn:post_activate 待处理', time:'1h前', color:'#F56C6C' },
|
||||||
|
{ text:'终端限制已达上限 (码头项目)', time:'3h前', color:'#F56C6C' },
|
||||||
|
{ text:'新版本 SDK v0.2.0 已发布', time:'6h前', color:'#409EFF' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const mockNames = ['广州创飞 · 码头检测合同', '深圳教育局 · 学校合同', '实验室设备授权 v2', '内部测试许可', '流动人口项目 042']
|
||||||
|
const mockRefs = ['码头南沙二期', '深圳南山校区', '实验室 A 区', '内部', '项目 042']
|
||||||
|
|
||||||
|
const licenseData = [
|
||||||
|
{ id:'01JQNX...a1b2', tenant:'craftlabs-wharf-prod', product:'wharf-inspection-v2', type:'永久', devices:5, grace:7, status:'active', issued:'2026-05-10' },
|
||||||
|
{ id:'01JQNY...c3d4', tenant:'school-district-west', product:'school-edge-ai', type:'订阅', devices:20, grace:3, status:'active', issued:'2026-05-08' },
|
||||||
|
{ id:'01JQNZ...e5f6', tenant:'floating-project-042', product:'floating-license', type:'试用', devices:2, grace:1, status:'expired', issued:'2026-01-15' },
|
||||||
|
{ id:'01JQPA...g7h8', tenant:'craftlabs-demo', product:'demo-license', type:'订阅', devices:10, grace:7, status:'revoked', issued:'2026-03-20' },
|
||||||
|
{ id:'01JQPB...i9j0', tenant:'internal-test', product:'test-license', type:'永久', devices:1, grace:0, status:'active', issued:'2026-05-15' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const callbackData = [
|
||||||
|
{ source:'BitAnswer', event:'sn:post_activate', sn:'SN-2026-A1B2C', status:'PENDING', time:'2026-05-18 14:30' },
|
||||||
|
{ source:'BitAnswer', event:'device:pre_activate', sn:'SN-2026-D3E4F', status:'PROCESSED', time:'2026-05-18 12:15' },
|
||||||
|
{ source:'SelfHosted', event:'license:heartbeat', sn:'01JQNX...a1b2', status:'PROCESSED', time:'2026-05-18 10:00' },
|
||||||
|
{ source:'BitAnswer', event:'sn:post_activate', sn:'SN-2026-G5H6I', status:'IGNORED', time:'2026-05-17 16:45' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const callbackFilters = [
|
||||||
|
{ label:'全部状态' }, { label:'全部事件类型' }, { label:'全部来源' }
|
||||||
|
]
|
||||||
|
|
||||||
|
const keyData = [
|
||||||
|
{ id:'kp_2026_q2', algo:'RS256', status:'active', time:'2026-04-01' },
|
||||||
|
{ id:'kp_2026_q1', algo:'RS256', status:'rotated', time:'2026-01-05' },
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
||||||
|
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;overflow:hidden}
|
||||||
|
input{font-family:inherit} select{font-family:inherit} button{font-family:inherit}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.nav-item:hover{color:#2C3E6B}
|
||||||
|
.menu-item:hover{background:#F2F5FC}
|
||||||
|
.tree-hover{background:#F2F5FC}
|
||||||
|
.stat-card{transition:transform .15s,box-shadow .15s}
|
||||||
|
.stat-card:hover{transform:translateY(-2px);box-shadow:0 4px 12px rgba(0,0,0,.06)}
|
||||||
|
input::placeholder{color:#C0C4CC}
|
||||||
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user