mirror of
https://github.com/hpd840321/craftlabs-authorization-sdk.git
synced 2026-06-09 01:50:30 +08:00
feat(web): add Figma vs Element Plus license management theme comparison page
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "安徽地质博物馆v2.0",
|
||||
"fileId": "TdU1qb5xVYDLOssDOQxQqv",
|
||||
"nodeId": "0-38499",
|
||||
"url": "https://www.figma.com/design/TdU1qb5xVYDLOssDOQxQqv/",
|
||||
"fetchedAt": "2026-05-18T00:00:00Z"
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"file": {
|
||||
"name": "安徽地质博物馆v2.0",
|
||||
"fileId": "TdU1qb5xVYDLOssDOQxQqv",
|
||||
"lastModified": "2026-05-18T14:45:48Z",
|
||||
"frame": "数字资源系统-资源管理",
|
||||
"frameSize": "1920x1080"
|
||||
},
|
||||
"colors": {
|
||||
"pageBackground": "rgba(234,239,250,1.0)",
|
||||
"cardBackground": "rgba(255,255,255,1.0)",
|
||||
"textPrimary": "rgba(0,0,0,1.0)",
|
||||
"textSecondary": "rgba(49,49,49,1.0)",
|
||||
"textOnPrimary": "rgba(255,255,255,1.0)",
|
||||
"badgeRed": "rgba(213,73,65,1.0)",
|
||||
"decorativeBlue": "rgba(207,209,255,1.0)",
|
||||
"decorativeTeal": "rgba(217,248,255,1.0)"
|
||||
},
|
||||
"typography": {
|
||||
"body": { "fontSize": "14px", "color": "rgba(0,0,0,1.0)" },
|
||||
"badge": { "fontSize": "12px", "color": "rgba(255,255,255,1.0)" },
|
||||
"placeholder": { "fontSize": "14px", "color": "rgba(49,49,49,1.0)" }
|
||||
},
|
||||
"layout": {
|
||||
"frameWidth": 1920,
|
||||
"frameHeight": 1080,
|
||||
"headerHeight": 60,
|
||||
"sidebarWidth": 232,
|
||||
"contentWidth": 1688,
|
||||
"contentPaddingX": 20,
|
||||
"treePanelWidth": 280,
|
||||
"mainPanelWidth": 1368,
|
||||
"breadcrumbHeight": 46
|
||||
},
|
||||
"components": {
|
||||
"header": "headerMenu 顶部菜单导航",
|
||||
"sidebar": "Menu - 侧边菜单",
|
||||
"breadcrumb": "Breadcrumb 面包屑 (数字资源 > 资源管理)",
|
||||
"tree": "Tree 树结构 - 资源分类树",
|
||||
"search": "search 搜索框",
|
||||
"menuItems": [
|
||||
"item/menuLogo/baseLogo-light",
|
||||
"item/normalMenu/1st-light (x11 菜单项)",
|
||||
"Button"
|
||||
],
|
||||
"headerItems": [
|
||||
"icon-search-w/text - 资源快速搜索",
|
||||
"icon-internet",
|
||||
"icon-view-module",
|
||||
"icon-mail + Badge (红点通知 2)",
|
||||
"logo-github",
|
||||
"icon-user w/ TD Admin",
|
||||
"icon-setting"
|
||||
]
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -104,9 +104,16 @@ const routes = [
|
||||
component: () => import("../views/ContractsView.vue"),
|
||||
meta: { roles: ["SYS_ADMIN", "DEVELOPER"], title: "合同管理" },
|
||||
},
|
||||
{
|
||||
path: "license-compare",
|
||||
name: "license-compare",
|
||||
component: () => import("../views/LicenseCompareView.vue"),
|
||||
meta: { roles: ["SYS_ADMIN", "DEVELOPER"] },
|
||||
},
|
||||
],
|
||||
},
|
||||
{ path: "/403", name: "forbidden", component: () => import("../views/ForbiddenView.vue") },
|
||||
{ path: "/license-compare-public", name: "license-compare-public", component: () => import("../views/LicenseCompareView.vue") },
|
||||
{ path: "/:pathMatch(.*)*", name: "notfound", component: () => import("../views/NotFoundView.vue") },
|
||||
];
|
||||
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<div style="display:flex; height:100vh; overflow:hidden; min-width:1400px">
|
||||
<div v-for="theme in themes" :key="theme.name" :class="['half', theme.cssClass]" :style="{background:theme.bg}">
|
||||
<div :style="{position:'sticky',top:0,zIndex:10,padding:'6px 16px',fontSize:'13px',fontWeight:600,textAlign:'center',color:'#fff',background:theme.brand}">{{ theme.label }}</div>
|
||||
<div style="padding:14px 20px; display:flex; flex-direction:column; gap:12px">
|
||||
<!-- 统计卡片行 -->
|
||||
<div style="display:flex; gap:12px">
|
||||
<div v-for="s in stats" :key="s.label" :style="{flex:1,background:'#fff',borderRadius:theme.radius+'px',padding:'16px',textAlign:'center',boxShadow:'0 1px 3px rgba(0,0,0,.06)',border:theme.border}">
|
||||
<div style="font-size:28px; font-weight:700; margin-bottom:4px">{{ s.value }}</div>
|
||||
<div style="font-size:13px; color:#909399">{{ s.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 搜索 + 操作栏 -->
|
||||
<div :style="{background:'#fff',borderRadius:theme.radius+'px',padding:'14px 16px',boxShadow:'0 1px 3px rgba(0,0,0,.06)',border:theme.border}">
|
||||
<div style="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 #dcdfe6',borderRadius:'4px',padding:'6px 12px',width:'200px',display:'flex',alignItems:'center',gap:'6px'}">
|
||||
<span style="color:#c0c4cc; font-size:14px">🔍</span>
|
||||
<input v-model="keyword" placeholder="搜索许可证ID" style="border:none;outline:none;flex:1;font-size:14px;color:#606266" />
|
||||
</div>
|
||||
<select v-model="filterStatus" :style="{border:'1px solid #dcdfe6',borderRadius:'4px',padding:'6px 10px',fontSize:'14px',color:'#606266',background:'#fff'}">
|
||||
<option value="">全部状态</option>
|
||||
<option value="active">活跃</option>
|
||||
<option value="revoked">已吊销</option>
|
||||
<option value="expired">已过期</option>
|
||||
</select>
|
||||
<button :style="{background:theme.brand,color:'#fff',border:'none',borderRadius:'4px',padding:'7px 16px',fontSize:'14px',cursor:'pointer',fontWeight:500}" @click="search">{{ theme.btnText }}</button>
|
||||
</div>
|
||||
<button :style="{background:theme.brand,color:'#fff',border:'none',borderRadius:'4px',padding:'7px 16px',fontSize:'14px',cursor:'pointer'}" @click="create">+ 签发许可证</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 表格 -->
|
||||
<div :style="{background:'#fff',borderRadius:theme.radius+'px',padding:'0',overflow:'hidden',boxShadow:'0 1px 3px rgba(0,0,0,.06)',border:theme.border}">
|
||||
<table style="width:100%; border-collapse:collapse; font-size:14px">
|
||||
<thead>
|
||||
<tr :style="{background:theme.thBg, color:theme.thColor}">
|
||||
<th style="padding:10px 12px; text-align:left; font-weight:600; min-width:150px">许可证 ID</th>
|
||||
<th style="padding:10px 12px; text-align:left; font-weight:600; min-width:100px">租户</th>
|
||||
<th style="padding:10px 12px; text-align:left; font-weight:600; width:80px">类型</th>
|
||||
<th style="padding:10px 12px; text-align:left; font-weight:600; width:70px">终端</th>
|
||||
<th style="padding:10px 12px; text-align:left; font-weight:600; width:80px">宽限</th>
|
||||
<th style="padding:10px 12px; text-align:left; font-weight:600; width:80px">状态</th>
|
||||
<th style="padding:10px 12px; text-align:left; font-weight:600; width:120px">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="r in list" :key="r.licenseId" style="border-bottom:1px solid #ebeef5">
|
||||
<td style="padding:10px 12px; color:#303133">{{ r.licenseId }}</td>
|
||||
<td style="padding:10px 12px; color:#606266">{{ r.tenantId }}</td>
|
||||
<td style="padding:10px 12px">{{ typeLabel(r.grantType) }}</td>
|
||||
<td style="padding:10px 12px; color:#606266">{{ r.maxDevices }}</td>
|
||||
<td style="padding:10px 12px; color:#606266">{{ r.offlineGraceDays }}天</td>
|
||||
<td style="padding:10px 12px">
|
||||
<span :style="{display:'inline-block',padding:'2px 8px',borderRadius:'3px',fontSize:'12px',fontWeight:500,...statusStyle(r.status,theme)}">{{ r.status }}</span>
|
||||
</td>
|
||||
<td style="padding:10px 12px">
|
||||
<span :style="{color:theme.brand,cursor:'pointer',marginRight:12}" @click="detail(r)">详情</span>
|
||||
<span v-if="r.status==='active'" style="color:#f56c6c;cursor:pointer" @click="revoke(r)">吊销</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div style="padding:10px 16px; display:flex; justify-content:flex-end; align-items:center; gap:8px; font-size:13px; color:#909399; border-top:1px solid #ebeef5">
|
||||
<span>共 {{ total }} 条</span>
|
||||
<span style="cursor:pointer" @click="page = Math.max(1, page-1)">‹</span>
|
||||
<span>{{ page }}</span>
|
||||
<span style="cursor:pointer" @click="page = Math.min(Math.ceil(total/10), page+1)">›</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, reactive } from 'vue'
|
||||
|
||||
const themes = [
|
||||
{ name:'figma', cssClass:'figma', label:'Figama · 安徽地质博物馆 色彩', bg:'#EAEFFA', brand:'#2C3E6B', radius:6, border:'1px solid #D6DFF0', thBg:'#F2F5FC', thColor:'#2C3E6B', btnText:'查询' },
|
||||
{ name:'elplus', cssClass:'elplus', label:'Element Plus 默认主题', bg:'#f0f2f5', brand:'#409EFF', radius:4, border:'none', thBg:'#f5f7fa', thColor:'#303133', btnText:'查询' }
|
||||
]
|
||||
|
||||
const MOCK = [
|
||||
{ licenseId:'01JQNX...a1b2', tenantId:'craftlabs-wharf-prod', grantType:'perpetual', maxDevices:5, offlineGraceDays:7, status:'active' },
|
||||
{ licenseId:'01JQNY...c3d4', tenantId:'school-district-west', grantType:'subscription', maxDevices:20, offlineGraceDays:3, status:'active' },
|
||||
{ licenseId:'01JQNZ...e5f6', tenantId:'floating-project-042', grantType:'trial', maxDevices:2, offlineGraceDays:1, status:'expired' },
|
||||
{ licenseId:'01JQPA...g7h8', tenantId:'craftlabs-demo', grantType:'subscription', maxDevices:10, offlineGraceDays:7, status:'revoked' },
|
||||
{ licenseId:'01JQPB...i9j0', tenantId:'internal-test', grantType:'perpetual', maxDevices:1, offlineGraceDays:0, status:'active' },
|
||||
]
|
||||
|
||||
const rows = ref([...MOCK])
|
||||
const total = ref(5), page = ref(1)
|
||||
const keyword = ref(''), filterStatus = ref('')
|
||||
const stats = reactive([{label:'总许可证',value:5},{label:'活跃',value:3},{label:'已吊销',value:1},{label:'已过期',value:1}])
|
||||
|
||||
const list = computed(() => {
|
||||
let r = [...rows.value]
|
||||
if (keyword.value) r = r.filter(x=>x.licenseId.includes(keyword.value)||x.tenantId.includes(keyword.value))
|
||||
if (filterStatus.value) r = r.filter(x=>x.status===filterStatus.value)
|
||||
return r
|
||||
})
|
||||
|
||||
function search() {}
|
||||
function create() { alert('Demo: 签发许可证\n\n此对比页不含后端交互,仅展示 UI 主题差异。') }
|
||||
function detail(r) { alert(`许可证详情\nID: ${r.licenseId}\n租户: ${r.tenantId}\n状态: ${r.status}`) }
|
||||
function revoke(r) { if(confirm(`确定吊销 ${r.licenseId}?`)){ r.status='revoked' } }
|
||||
|
||||
function typeLabel(t) { return ({subscription:'订阅',perpetual:'永久',trial:'试用'})[t]||t }
|
||||
function statusStyle(s, t) {
|
||||
const m = { active:{bg:t.name==='figma'?'#E6F7EE':'#f0f9eb',color:t.name==='figma'?'#1A7A3A':'#67c23a',border:'1px solid '+ (t.name==='figma'?'#A8E6C1':'#e1f3d8')},
|
||||
revoked:{bg:'#fef0f0',color:'#f56c6c',border:'1px solid #fbc4c4'},
|
||||
expired:{bg:'#f4f4f5',color:'#909399',border:'1px solid #e9e9eb'} }
|
||||
return m[s]||{bg:'#f4f4f5',color:'#909399'}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.half { flex:1; overflow-y:auto; position:relative; min-width:680px }
|
||||
input:focus, select:focus { border-color: #409EFF !important; outline: none }
|
||||
.figma input:focus, .figma select:focus { border-color: #2C3E6B !important }
|
||||
</style>
|
||||
Reference in New Issue
Block a user