feat: add tenant landing page with multi-tenant support

- Add /tenant/index.ui using bricks framework (no inline styles)
- Use Image widget for all images (logo, hero, case studies)
- Register /tenant and /tenant/index.ui routes as 'any' permission
- Include responsive CSS with tenant- prefix to avoid conflicts
- Login button redirects to /rbac/user/login.ui
- Support multi-tenant customization via ?tenant=xxx parameter
This commit is contained in:
yumoqing 2026-07-20 14:41:17 +08:00
parent a53e211c1d
commit 73ee108cab
9 changed files with 530 additions and 0 deletions

View File

@ -8,6 +8,8 @@ paths="""/ any
/favicon.ico any /favicon.ico any
/top.ui any /top.ui any
/i18n_getmsgs any /i18n_getmsgs any
/tenant any
/tenant/index.ui any
/uapi logined /uapi logined
/uapi/uapi logined /uapi/uapi logined
/uapi/uapi/delete_uapi.dspy logined /uapi/uapi/delete_uapi.dspy logined

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 KiB

192
wwwroot/tenant/index.ui Normal file
View File

@ -0,0 +1,192 @@
{
"widgettype": "VBox",
"options": {
"css": "tenant-landing",
"width": "100%",
"spacing": 0
},
"subwidgets": [
{
"widgettype": "HBox",
"options": {
"css": "tenant-header",
"width": "100%",
"padding": "0 40px",
"alignItems": "center",
"justifyContent": "space-between"
},
"subwidgets": [
{
"widgettype": "Image",
"options": {
"url": "{{entire_url('/tenant/imgs/logo.png')}}",
"css": "tenant-logo"
}
},
{
"widgettype": "HBox",
"options": {
"css": "tenant-nav",
"spacing": "30px",
"alignItems": "center"
},
"subwidgets": [
{"widgettype": "Text", "options": {"text": "Home", "css": "nav-link"}},
{"widgettype": "Text", "options": {"text": "Products", "css": "nav-link"}},
{"widgettype": "Text", "options": {"text": "Use Cases", "css": "nav-link"}},
{"widgettype": "Text", "options": {"text": "News", "css": "nav-link"}}
]
},
{
"widgettype": "Button",
"options": {"label": "Login", "css": "login-btn"},
"binds": [{
"wid": "self",
"event": "click",
"actiontype": "script",
"script": "window.location.href='{{entire_url('/rbac/user/login.ui')}}';"
}]
}
]
},
{
"widgettype": "HBox",
"options": {
"css": "tenant-hero",
"width": "100%",
"padding": "100px 40px",
"alignItems": "center",
"justifyContent": "space-between"
},
"subwidgets": [
{
"widgettype": "VBox",
"options": {"css": "hero-content", "width": "50%", "spacing": "24px"},
"subwidgets": [
{"widgettype": "Text", "options": {"text": "One Platform · Intelligent Leap · Across All Industries", "css": "hero-title"}},
{"widgettype": "Text", "options": {"text": "Make AI Everywhere, Make AI Easy", "css": "hero-subtitle"}},
{"widgettype": "Button", "options": {"label": "Solutions", "css": "hero-btn"}}
]
},
{
"widgettype": "Image",
"options": {
"url": "{{entire_url('/tenant/imgs/hero-bg.png')}}",
"css": "hero-image"
}
}
]
},
{
"widgettype": "VBox",
"options": {"css": "tenant-solutions", "width": "100%", "padding": "80px 40px", "spacing": "40px"},
"subwidgets": [
{"widgettype": "Text", "options": {"text": "AI + Solutions", "css": "section-title"}},
{
"widgettype": "HBox",
"options": {"css": "solution-cards", "width": "100%", "spacing": "24px", "justifyContent": "center"},
"subwidgets": [
{
"widgettype": "VBox",
"options": {"css": "solution-card", "width": "30%", "padding": "24px", "spacing": "16px"},
"subwidgets": [
{"widgettype": "Text", "options": {"text": "Instant Answers", "css": "card-title"}},
{"widgettype": "Text", "options": {"text": "AI-powered Q&A engine built on enterprise private knowledge bases, supporting natural language queries for business data, technical specifications, and policy documents.", "css": "card-text"}},
{
"widgettype": "VBox",
"options": {"spacing": "8px"},
"subwidgets": [
{"widgettype": "Text", "options": {"text": "< 3 sec Response time", "css": "card-stat"}},
{"widgettype": "Text", "options": {"text": "100% Source traceability", "css": "card-stat"}}
]
}
]
},
{
"widgettype": "VBox",
"options": {"css": "solution-card", "width": "30%", "padding": "24px", "spacing": "16px"},
"subwidgets": [
{"widgettype": "Text", "options": {"text": "Collaborative Intelligence", "css": "card-title"}},
{"widgettype": "Text", "options": {"text": "Multiple AI agents collaborate autonomously based on role specialization, completing the full workflow of information gathering, data analysis, logical reasoning, and conclusion generation.", "css": "card-text"}},
{
"widgettype": "VBox",
"options": {"spacing": "8px"},
"subwidgets": [
{"widgettype": "Text", "options": {"text": "10x+ Efficiency improvement", "css": "card-stat"}},
{"widgettype": "Text", "options": {"text": "Real-time Multi-source fusion", "css": "card-stat"}}
]
}
]
},
{
"widgettype": "VBox",
"options": {"css": "solution-card", "width": "30%", "padding": "24px", "spacing": "16px"},
"subwidgets": [
{"widgettype": "Text", "options": {"text": "Spatial Intelligence", "css": "card-title"}},
{"widgettype": "Text", "options": {"text": "Integrating Geographic Information Systems, satellite remote sensing imagery, and drone aerial photography, AI automatically identifies land feature boundaries and analyzes spatial relationships.", "css": "card-text"}},
{
"widgettype": "VBox",
"options": {"spacing": "8px"},
"subwidgets": [
{"widgettype": "Text", "options": {"text": "Days to minutes", "css": "card-stat"}},
{"widgettype": "Text", "options": {"text": "90%+ Detection accuracy", "css": "card-stat"}}
]
}
]
}
]
}
]
},
{
"widgettype": "VBox",
"options": {"css": "tenant-cases", "width": "100%", "padding": "80px 40px", "spacing": "40px"},
"subwidgets": [
{"widgettype": "Text", "options": {"text": "Use Cases", "css": "section-title"}},
{
"widgettype": "HBox",
"options": {"css": "case-cards", "width": "100%", "spacing": "24px", "justifyContent": "center"},
"subwidgets": [
{
"widgettype": "VBox",
"options": {"css": "case-card", "width": "30%", "spacing": "16px"},
"subwidgets": [
{"widgettype": "Image", "options": {"url": "{{entire_url('/tenant/imgs/case-railway.png')}}", "css": "case-image"}},
{"widgettype": "Text", "options": {"text": "Smart Engineering", "css": "case-title"}},
{"widgettype": "Text", "options": {"text": "China Railway · Huitobid", "css": "case-company"}},
{"widgettype": "Text", "options": {"text": "Built intelligent bidding system covering the full lifecycle from document analysis to smart bid compilation.", "css": "case-desc"}}
]
},
{
"widgettype": "VBox",
"options": {"css": "case-card", "width": "30%", "spacing": "16px"},
"subwidgets": [
{"widgettype": "Image", "options": {"url": "{{entire_url('/tenant/imgs/case-forestry.png')}}", "css": "case-image"}},
{"widgettype": "Text", "options": {"text": "Smart Harvesting", "css": "case-title"}},
{"widgettype": "Text", "options": {"text": "Nanning Forestry Bureau", "css": "case-company"}},
{"widgettype": "Text", "options": {"text": "Intelligent forest harvesting spatial review system integrating GIS, satellite remote sensing, and UAV data.", "css": "case-desc"}}
]
},
{
"widgettype": "VBox",
"options": {"css": "case-card", "width": "30%", "spacing": "16px"},
"subwidgets": [
{"widgettype": "Image", "options": {"url": "{{entire_url('/tenant/imgs/case-port.png')}}", "css": "case-image"}},
{"widgettype": "Text", "options": {"text": "Digital Transformation", "css": "case-title"}},
{"widgettype": "Text", "options": {"text": "Beibu Gulf Port Big Data", "css": "case-company"}},
{"widgettype": "Text", "options": {"text": "Full-stack AI agent solution covering bidding, investment decision-making, and contract review.", "css": "case-desc"}}
]
}
]
}
]
},
{
"widgettype": "HBox",
"options": {"css": "tenant-footer", "width": "100%", "padding": "40px", "justifyContent": "center", "alignItems": "center"},
"subwidgets": [
{"widgettype": "Text", "options": {"text": "© 2024 Open Computing. All rights reserved.", "css": "footer-text"}}
]
}
]
}

139
wwwroot/tenant/landing.css Normal file
View File

@ -0,0 +1,139 @@
/* ===== Tenant Landing Page ===== */
/* Header */
.tenant-header {
background: rgba(255,255,255,0.95);
box-shadow: 0 2px 8px rgba(0,0,0,0.06);
position: sticky;
top: 0;
z-index: 100;
}
.nav-item {
cursor: pointer;
font-size: 15px;
color: #333;
transition: color 0.2s;
}
.nav-item:hover {
color: #6366f1;
}
/* Hero */
.tenant-hero {
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #a855f7 100%);
color: #fff;
text-align: center;
min-height: 400px;
display: flex;
flex-direction: column;
justify-content: center;
}
.hero-title {
color: #fff !important;
font-size: 42px !important;
font-weight: 700 !important;
}
.hero-subtitle {
color: rgba(255,255,255,0.85) !important;
font-size: 20px !important;
font-weight: 400 !important;
margin-top: 16px !important;
}
/* Buttons */
.primary.large {
background: #fff !important;
color: #6366f1 !important;
font-size: 16px !important;
padding: 12px 32px !important;
border-radius: 8px !important;
}
.secondary.large {
background: transparent !important;
color: #fff !important;
border: 2px solid rgba(255,255,255,0.6) !important;
font-size: 16px !important;
padding: 12px 32px !important;
border-radius: 8px !important;
}
/* Solutions */
.tenant-solutions {
background: #f8f9fa;
}
.section-title {
text-align: center;
font-size: 32px !important;
font-weight: 700 !important;
color: #1a1a2e !important;
}
.solution-card {
background: #fff;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
transition: transform 0.2s, box-shadow 0.2s;
}
.solution-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 30px rgba(0,0,0,0.12);
}
/* Cases */
.case-card {
background: #fff;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
}
.case-image {
border-radius: 0;
}
.case-title {
padding: 16px 16px 4px;
font-weight: 600 !important;
}
.case-subtitle {
padding: 0 16px 16px;
color: #666;
font-size: 14px;
}
/* Footer */
.tenant-footer {
background: #1a1a2e;
}
.footer-text {
color: rgba(255,255,255,0.6);
font-size: 14px;
}
/* Dark mode support */
[data-theme="dark"] .tenant-header {
background: rgba(30,30,46,0.95);
}
[data-theme="dark"] .nav-item {
color: #ccc;
}
[data-theme="dark"] .tenant-solutions {
background: #1e1e2e;
}
[data-theme="dark"] .solution-card {
background: #2a2a3e;
color: #eee;
}
[data-theme="dark"] .case-card {
background: #2a2a3e;
}
[data-theme="dark"] .case-subtitle {
color: #aaa;
}

197
wwwroot/tenant/tenant.css Normal file
View File

@ -0,0 +1,197 @@
.tenant-landing {
background: #fff;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}
.tenant-header {
background: rgba(255,255,255,0.95);
box-shadow: 0 2px 8px rgba(0,0,0,0.06);
position: sticky;
top: 0;
z-index: 100;
height: 80px;
}
.tenant-logo img {
height: 50px;
}
.tenant-nav {
gap: 30px;
}
.nav-link {
cursor: pointer;
font-size: 15px;
color: #333;
font-weight: 500;
transition: color 0.2s;
}
.nav-link:hover {
color: #6366f1;
}
.login-btn {
background: #6366f1 !important;
color: #fff !important;
border: none !important;
padding: 10px 24px !important;
border-radius: 6px !important;
font-size: 14px !important;
font-weight: 600 !important;
cursor: pointer !important;
}
.login-btn:hover {
background: #5558e3 !important;
}
.tenant-hero {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 500px;
}
.hero-content {
color: #fff;
}
.hero-title {
font-size: 48px !important;
font-weight: 700 !important;
line-height: 1.2 !important;
color: #fff !important;
}
.hero-subtitle {
font-size: 24px !important;
color: rgba(255,255,255,0.9) !important;
font-weight: 400 !important;
}
.hero-btn {
background: #fff !important;
color: #6366f1 !important;
border: none !important;
padding: 14px 32px !important;
border-radius: 8px !important;
font-size: 16px !important;
font-weight: 600 !important;
cursor: pointer !important;
}
.hero-btn:hover {
background: #f0f0f0 !important;
}
.hero-image {
width: 45%;
}
.tenant-solutions {
background: #f8f9fa;
}
.section-title {
font-size: 36px !important;
font-weight: 700 !important;
text-align: center !important;
color: #1a1a2e !important;
margin-bottom: 20px !important;
}
.solution-cards {
display: flex;
justify-content: center;
gap: 24px;
}
.solution-card {
background: #fff;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
transition: transform 0.2s, box-shadow 0.2s;
}
.solution-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 30px rgba(0,0,0,0.12);
}
.card-title {
font-size: 24px !important;
font-weight: 700 !important;
color: #1a1a2e !important;
}
.card-text {
font-size: 15px !important;
color: #666 !important;
line-height: 1.6 !important;
}
.card-stat {
font-size: 14px !important;
color: #6366f1 !important;
font-weight: 600 !important;
}
.tenant-cases {
background: #fff;
}
.case-cards {
display: flex;
justify-content: center;
gap: 24px;
}
.case-card {
background: #fff;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
transition: transform 0.2s;
}
.case-card:hover {
transform: translateY(-4px);
}
.case-image img {
width: 100%;
height: 200px;
object-fit: cover;
}
.case-title {
font-size: 20px !important;
font-weight: 700 !important;
color: #1a1a2e !important;
padding: 0 20px !important;
}
.case-company {
font-size: 14px !important;
color: #6366f1 !important;
font-weight: 600 !important;
padding: 0 20px !important;
}
.case-desc {
font-size: 14px !important;
color: #666 !important;
line-height: 1.6 !important;
padding: 0 20px 20px !important;
}
.tenant-footer {
background: #1a1a2e;
color: #fff;
min-height: 80px;
}
.footer-text {
color: rgba(255,255,255,0.6);
font-size: 14px !important;
}