feat: 全站视觉焕新与悬浮玻璃 TabBar 迁移

This commit is contained in:
2026-08-07 23:29:19 +08:00
parent 19408e5a8c
commit 61f1217384
97 changed files with 4007 additions and 2024 deletions
+5 -7
View File
@@ -834,11 +834,11 @@
.mini-tabbar {
display: flex;
align-items: center;
height: 56px;
height: 58px;
padding: 4px 4px calc(4px + env(safe-area-inset-bottom, 0px));
background: rgba(255, 255, 255, 0.55);
border: 1px solid var(--glass-line);
border-radius: var(--radius-lg);
border-radius: 32px;
box-shadow: 0 -2px 12px rgba(46, 38, 34, 0.1);
backdrop-filter: blur(32px) saturate(1.2);
-webkit-backdrop-filter: blur(32px) saturate(1.2);
@@ -970,7 +970,7 @@
}
.phone-screen .mini-tabbar {
margin: 0 12px 12px;
margin: 0 18px 18px;
}
.phone-content {
@@ -1756,7 +1756,7 @@
</div>
<div class="empty-title">暂无设计任务</div>
<div class="empty-desc">创建第一个任务,把想法变成可预览的方案。</div>
<button class="btn btn-md btn-primary" type="button" id="toast-trigger">创建任务</button>
<button class="btn btn-lg btn-primary" type="button" id="toast-trigger" style="min-width:140px">创建任务</button>
</div>
</div>
</div>
@@ -2011,9 +2011,7 @@
<div class="mock-topbar">
<div class="mock-status"><span>11:18</span><span class="mini-capsule"><i></i><i></i><i></i></span></div>
<div class="mock-header">
<span class="icon-button" style="width:32px;height:32px;min-width:32px;border-radius:50%" type="button" aria-label="返回">
<span class="icon" style="width:16px;height:16px"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M19 12H5"/><path d="m12 5-7 7 7 7"/></svg></span>
</span>
<span style="width:32px"></span>
<span class="mock-title" style="flex:1;text-align:center">我的设计清单</span>
<span style="font-size:13px;color:var(--accent-secondary);width:32px;text-align:center">管理</span>
</div>
+1
View File
@@ -0,0 +1 @@
.theme-light{background-color:var(--bg-page,#fff);-webkit-box-sizing:border-box;box-sizing:border-box;min-height:100vh}.theme-dark{background-color:var(--bg-page,#191919);-webkit-box-sizing:border-box;box-sizing:border-box;min-height:100vh}.theme-light{--bg-page:#faf7f2;--bg-card:#fff;--bg-muted:#f3eee7;--bg-input:#f5f1eb;--text-primary:#2e2622;--text-secondary:#8a7e76;--text-muted:#b3a89e;--accent-primary:#d96c6a;--accent-primary-strong:#c75b59;--accent-primary-soft:#f6e0dc;--accent-secondary:#6c7bdb;--accent-secondary-soft:rgba(108,123,219,.12);--success:#4fa477;--success-soft:rgba(79,164,119,.14);--warning:#d99a4e;--warning-soft:rgba(217,154,78,.14);--danger:#d85d5d;--danger-soft:rgba(216,93,93,.14);--border:#ede5dc;--border-strong:#e0d5c8;--glass:hsla(0,0%,100%,.72);--glass-line:hsla(0,0%,100%,.55);--shadow-card:0 8rpx 24rpx rgba(46,38,34,.08);--shadow-elevated:0 12rpx 40rpx rgba(46,38,34,.12)}.theme-dark{--bg-page:#191919;--bg-card:#23201d;--bg-muted:#2b2622;--bg-input:#2b2622;--text-primary:#f5efe8;--text-secondary:#b3a79c;--text-muted:#82766c;--accent-primary:#f09198;--accent-primary-strong:#ffa7ad;--accent-primary-soft:rgba(240,145,152,.14);--accent-secondary:#8e97e8;--accent-secondary-soft:rgba(142,151,232,.14);--success:#67c58e;--success-soft:rgba(103,197,142,.16);--warning:#e0ad68;--warning-soft:hsla(35,66%,64%,.16);--danger:#ef7a7a;--danger-soft:hsla(0,79%,71%,.16);--border:#37312c;--border-strong:#463e37;--glass:rgba(25,25,25,.72);--glass-line:hsla(0,0%,100%,.14);--shadow-card:0 8rpx 24rpx rgba(0,0,0,.32);--shadow-elevated:0 12rpx 40rpx rgba(0,0,0,.48)}page{font-family:-apple-system,BlinkMacSystemFont,PingFang SC,Hiragino Sans GB,Noto Sans SC,Microsoft YaHei,Segoe UI,sans-serif}.surface-card{background:var(--bg-card);border:1rpx solid var(--border);border-radius:24rpx;-webkit-box-shadow:var(--shadow-card);box-shadow:var(--shadow-card)}.container{padding:48rpx}.flex{display:-webkit-flex;display:-ms-flexbox;display:flex}.flex-center{-ms-flex-align:center;-ms-flex-pack:center;-webkit-align-items:center;align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-justify-content:center;justify-content:center}.flex-between{-ms-flex-align:center;-ms-flex-pack:justify;-webkit-align-items:center;align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-justify-content:space-between;justify-content:space-between}.flex-column{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column}.text-center{text-align:center}.mt-10{margin-top:20rpx}.mt-20{margin-top:40rpx}.mb-10{margin-bottom:20rpx}.mb-20{margin-bottom:40rpx}.btn-primary{background:var(--accent-primary);border-radius:999rpx;color:#fff}.btn-secondary{background:var(--bg-card);border:1rpx solid var(--border-strong);border-radius:999rpx;color:var(--text-primary)}.btn-ghost{background:transparent;color:var(--accent-primary)}.btn-danger{background:var(--danger);border-radius:999rpx;color:#fff}.page-title{color:var(--text-primary);display:block;font-size:80rpx;font-weight:800}.section-title{color:var(--text-primary);display:block;font-size:72rpx;font-weight:700;margin-bottom:48rpx}.badge{border-radius:100rpx;display:inline-block;font-size:44rpx;font-weight:500;padding:16rpx 40rpx}.badge-pink{background:var(--accent-primary-soft);color:var(--accent-primary)}.badge-blue{background:var(--accent-secondary-soft);color:var(--accent-secondary)}.badge-green{background:var(--success-soft);color:var(--success)}.badge-warning{background:var(--warning-soft);color:var(--warning)}.badge-danger{background:var(--danger-soft);color:var(--danger)}.badge-gray{background:var(--bg-muted);color:var(--text-secondary)}.safe-bottom{height:constant(safe-area-inset-bottom);height:env(safe-area-inset-bottom)}.safe-bottom-placeholder{height:400rpx}.page-header{padding-top:calc(env(safe-area-inset-top, 20rpx) + 96rpx)}.back-btn,.edit-back{display:inline-block}.modal-overlay{-ms-flex-align:end;-ms-flex-pack:center;-webkit-align-items:flex-end;align-items:flex-end;background:rgba(0,0,0,.5);bottom:0;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-justify-content:center;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:600}.addr-picker-sheet{background:var(--bg-card);border-radius:48rpx 48rpx 0 0;border-top:1rpx solid var(--border);-webkit-box-sizing:border-box;box-sizing:border-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;max-height:70vh;padding:48rpx 48rpx calc(48rpx + env(safe-area-inset-bottom));width:100%}.system-theme-detector{height:1rpx;left:-9999rpx;opacity:0;pointer-events:none;position:fixed;top:0;width:1rpx}@media (prefers-color-scheme:dark){.system-theme-detector{opacity:1}}
Vendored
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
{"darkmode":true,"themeLocation":"theme.json","pages":["pages/index/index","pages/shop/index","pages/shop/detail/index","pages/product/index","pages/diy/index","pages/diy/stickerEdit/index","pages/checkout/index","pages/designList/index","pages/orders/index","pages/profile/index","pages/service/index","pages/wordcloud/index","pages/orderDetail/index","pages/address/index","pages/settings/index","pages/agreement/index","pages/userDatabase/index"],"window":{"backgroundTextStyle":"dark","navigationStyle":"custom","navigationBarBackgroundColor":"#ffffff","backgroundColor":"#ffffff","backgroundColorTop":"#ffffff","backgroundColorBottom":"#ffffff","navigationBarTextStyle":"black"},"tabBar":{"custom":true,"list":[{"pagePath":"pages/index/index","text":"首页"},{"pagePath":"pages/shop/index","text":"商品"},{"pagePath":"pages/designList/index","text":"设计清单"},{"pagePath":"pages/orders/index","text":"订单"},{"pagePath":"pages/profile/index","text":"我的"}]}}
{"darkmode":true,"themeLocation":"theme.json","pages":["pages/index/index","pages/shop/index","pages/shop/detail/index","pages/product/index","pages/diy/index","pages/diy/stickerEdit/index","pages/checkout/index","pages/designList/index","pages/orders/index","pages/profile/index","pages/service/index","pages/wordcloud/index","pages/orderDetail/index","pages/address/index","pages/settings/index","pages/agreement/index","pages/userDatabase/index"],"window":{"backgroundTextStyle":"dark","navigationStyle":"custom","navigationBarBackgroundColor":"#faf7f2","backgroundColor":"#faf7f2","backgroundColorTop":"#faf7f2","backgroundColorBottom":"#faf7f2","navigationBarTextStyle":"black"},"tabBar":{"custom":true,"list":[{"pagePath":"pages/index/index","text":"首页"},{"pagePath":"pages/shop/index","text":"商品"},{"pagePath":"pages/designList/index","text":"设计清单"},{"pagePath":"pages/orders/index","text":"订单"},{"pagePath":"pages/profile/index","text":"我的"}]}}
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
.bottom-action-bar{-ms-flex-align:center;-webkit-align-items:center;align-items:center;backdrop-filter:blur(32rpx) saturate(1.2);-webkit-backdrop-filter:blur(32rpx) saturate(1.2);background:hsla(0,0%,100%,.55);border:1rpx solid hsla(0,0%,100%,.55);border-radius:64rpx;bottom:36rpx;-webkit-box-shadow:0 12rpx 40rpx rgba(46,34,34,.18),0 4rpx 12rpx rgba(46,34,34,.08);box-shadow:0 12rpx 40rpx rgba(46,34,34,.18),0 4rpx 12rpx rgba(46,34,34,.08);-webkit-box-sizing:border-box;box-sizing:border-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:24rpx;left:36rpx;padding:24rpx 24rpx calc(24rpx + env(safe-area-inset-bottom));position:fixed;right:36rpx;z-index:500}.theme-dark .bottom-action-bar{background:rgba(25,25,25,.55);border-color:hsla(0,0%,100%,.14);-webkit-box-shadow:0 12rpx 40rpx rgba(0,0,0,.5),0 4rpx 12rpx rgba(0,0,0,.3);box-shadow:0 12rpx 40rpx rgba(0,0,0,.5),0 4rpx 12rpx rgba(0,0,0,.3)}
+1 -1
View File
@@ -1 +1 @@
"use strict";(wx["webpackJsonp"]=wx["webpackJsonp"]||[]).push([[777],{653:function(n,e,t){var a=t(7842),i=t(5544),c=t(118),o=t(758),r=t.n(o),u=t(6540),s=t(8594),l=t(9703),v=t(6606),g=t(8199),f=t(4848),p=[{pagePath:"/pages/index/index",label:"\u9996\u9875",icon:(0,g.uq)("/icon/\u9996\u9875.svg"),iconActive:(0,g.uq)("/icon/\u9996\u9875-fill.svg")},{pagePath:"/pages/shop/index",label:"\u5546\u54c1",icon:(0,g.uq)("/icon/\u5546\u54c1.svg"),iconActive:(0,g.uq)("/icon/\u5546\u54c1-fill.svg")},{pagePath:"/pages/designList/index",label:"\u8bbe\u8ba1\u6e05\u5355",icon:(0,g.uq)("/icon/\u8c03\u8272\u76d8.svg"),iconActive:(0,g.uq)("/icon/\u8c03\u8272\u76d8-fill.svg")},{pagePath:"/pages/orders/index",label:"\u8ba2\u5355",icon:(0,g.uq)("/icon/\u5305\u88f9.svg"),iconActive:(0,g.uq)("/icon/\u5305\u88f9-fill.svg")},{pagePath:"/pages/profile/index",label:"\u6211\u7684",icon:(0,g.uq)("/icon/\u4e2a\u4eba.svg"),iconActive:(0,g.uq)("/icon/\u4e2a\u4eba-fill.svg")}];function d(n){var e=p.findIndex(function(e){return n.endsWith(e.pagePath)});return p[e>=0?e:0].pagePath}function h(){var n,e=(null===(n=r().getCurrentInstance().router)||void 0===n?void 0:n.path)||"pages/index/index";return d(e)}function b(){var n=(0,u.useState)((0,s.eW)((0,s.O4)())),e=(0,i.A)(n,2),t=e[0],a=e[1],o=(0,u.useState)(h),g=(0,i.A)(o,2),b=g[0],x=g[1];(0,u.useEffect)(function(){var n=function(n){return a(n)};return r().eventCenter.on(l.Wo,n),function(){r().eventCenter.off(l.Wo,n)}},[]),(0,u.useEffect)(function(){var n=function(n){var e;x(d(n||(null===(e=r().getCurrentInstance().router)||void 0===e?void 0:e.path)||"pages/index/index"))};return r().eventCenter.on("tabBarChange",n),function(){r().eventCenter.off("tabBarChange",n)}},[]),(0,u.useEffect)(function(){(0,v.G)(t)},[t]);var m=function(n){var e;x(d(n)),r().switchTab({url:n}),null===(e=r().eventCenter)||void 0===e||e.trigger("tabBarChange",n)};return(0,f.jsx)(c.Ss,{className:"custom-tab-bar theme-".concat(t),children:p.map(function(n){var e=n.pagePath===b;return(0,f.jsxs)(c.Ss,{className:"tab-item ".concat(e?"active":""),onTap:function(){return m(n.pagePath)},children:[(0,f.jsx)(c._V,{className:"tab-icon-img ".concat(e?"active":""),src:e?n.iconActive:n.icon,mode:"aspectFit"}),(0,f.jsx)(c.EY,{className:"tab-label",children:n.label})]},n.pagePath)})})}Component((0,a.createComponentConfig)(b,"custom-tab-bar/index"))}},function(n){var e=function(e){return n(n.s=e)};n.O(0,[907,96,76],function(){return e(653)});n.O()}]);
"use strict";(wx["webpackJsonp"]=wx["webpackJsonp"]||[]).push([[777],{653:function(e,n,t){var a=t(7842),i=t(5544),c=t(118),o=t(758),r=t.n(o),s=t(6540),u=t(8594),f=t(9703),g=t(6606),h=t(8199),l=t(4848),v=[{pagePath:"/pages/index/index",label:"\u9996\u9875",icon:(0,h.uq)("/icon/\u9996\u9875.svg"),iconActive:(0,h.uq)("/icon/\u9996\u9875-fill.svg")},{pagePath:"/pages/shop/index",label:"\u5546\u54c1",icon:(0,h.uq)("/icon/\u5546\u54c1.svg"),iconActive:(0,h.uq)("/icon/\u5546\u54c1-fill.svg")},{pagePath:"/pages/designList/index",label:"\u8bbe\u8ba1\u6e05\u5355",icon:(0,h.uq)("/icon/\u8c03\u8272\u76d8.svg"),iconActive:(0,h.uq)("/icon/\u8c03\u8272\u76d8-fill.svg")},{pagePath:"/pages/orders/index",label:"\u8ba2\u5355",icon:(0,h.uq)("/icon/\u5305\u88f9.svg"),iconActive:(0,h.uq)("/icon/\u5305\u88f9-fill.svg")},{pagePath:"/pages/profile/index",label:"\u6211\u7684",icon:(0,h.uq)("/icon/\u4e2a\u4eba.svg"),iconActive:(0,h.uq)("/icon/\u4e2a\u4eba-fill.svg")}];function p(e){var n=v.findIndex(function(n){return e.endsWith(n.pagePath)});return v[n>=0?n:0].pagePath}function b(){var e=r().getCurrentInstance().router,n=e&&e.path?e.path:"pages/index/index";return p(n)}function m(){var e=(0,s.useState)((0,u.eW)((0,u.O4)())),n=(0,i.A)(e,2),t=n[0],a=n[1],o=(0,s.useState)(b),h=(0,i.A)(o,2),m=h[0],d=h[1];(0,s.useEffect)(function(){var e=function(e){return a(e)};return r().eventCenter.on(f.Wo,e),function(){r().eventCenter.off(f.Wo,e)}},[]),(0,s.useEffect)(function(){var e=function(e){!e||"dark"!==e.theme&&"light"!==e.theme||((0,u.Rq)(e.theme),"auto"===(0,u.O4)()&&a(e.theme))},n=r();return n.onThemeChange&&n.onThemeChange(e),function(){n.offThemeChange&&n.offThemeChange(e)}},[]),(0,s.useEffect)(function(){var e=function(e){var n=r().getCurrentInstance().router,t=n&&n.path?n.path:"pages/index/index";d(p(e||t))};return r().eventCenter.on("tabBarChange",e),function(){r().eventCenter.off("tabBarChange",e)}},[]),(0,s.useEffect)(function(){(0,g.G)(t)},[t]);var x=function(e){d(p(e)),r().switchTab({url:e}),r().eventCenter.trigger("tabBarChange",e)};return(0,l.jsxs)(c.Ss,{className:"tab-bar-root theme-".concat(t),children:[(0,l.jsx)(c.Ss,{className:"tab-bar-gradient"}),(0,l.jsx)(c.Ss,{className:"custom-tab-bar theme-".concat(t),children:v.map(function(e){var n=e.pagePath===m;return(0,l.jsxs)(c.Ss,{className:"tab-item ".concat(n?"active":""),onTap:function(){return x(e.pagePath)},children:[n&&(0,l.jsx)(c.Ss,{className:"tab-indicator"}),(0,l.jsx)(c._V,{className:"tab-icon-img ".concat(n?"active":""),src:n?e.iconActive:e.icon,mode:"aspectFit"}),(0,l.jsx)(c.EY,{className:"tab-label",children:e.label})]},e.pagePath)})})]})}Component((0,a.createComponentConfig)(m,"custom-tab-bar/index"))}},function(e){var n=function(n){return e(e.s=n)};e.O(0,[907,96,76],function(){return n(653)});e.O()}]);
+1 -1
View File
@@ -1 +1 @@
.custom-tab-bar{-ms-flex-pack:distribute;-ms-flex-align:center;-webkit-align-items:center;align-items:center;backdrop-filter:blur(20rpx);-webkit-backdrop-filter:blur(20rpx);background:hsla(0,0%,100%,.78);bottom:0;-webkit-box-shadow:0 -8rpx 20rpx rgba(0,0,0,.08);box-shadow:0 -8rpx 20rpx rgba(0,0,0,.08);-webkit-box-sizing:border-box;box-sizing:border-box;display:-webkit-flex;display:-ms-flexbox;display:flex;height:calc(96rpx + constant(safe-area-inset-bottom));height:calc(96rpx + env(safe-area-inset-bottom));-webkit-justify-content:space-around;justify-content:space-around;left:0;padding-bottom:env(safe-area-inset-bottom);position:fixed;right:0;z-index:1000}.custom-tab-bar.theme-dark{backdrop-filter:blur(20rpx);-webkit-backdrop-filter:blur(20rpx);background:rgba(25,25,25,.78);-webkit-box-shadow:0 -8rpx 20rpx rgba(0,0,0,.45);box-shadow:0 -8rpx 20rpx rgba(0,0,0,.45)}.tab-item{-ms-flex-align:center;-ms-flex-pack:center;-webkit-align-items:center;align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex:1;-ms-flex:1;flex:1;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-justify-content:center;justify-content:center;max-width:160rpx;padding:0 12rpx;position:relative}.tab-icon-img{height:40rpx;margin-bottom:2rpx;opacity:.8;-webkit-transition:-webkit-transform .2s;transition:-webkit-transform .2s;transition:transform .2s;transition:transform .2s,-webkit-transform .2s;width:40rpx}.tab-item.active .tab-icon-img{opacity:1;-webkit-transform:scale(1.08);-ms-transform:scale(1.08);transform:scale(1.08)}.tab-label{color:#b08d8d;font-size:20rpx;font-weight:700;line-height:22rpx;-webkit-transition:color .2s;transition:color .2s}.custom-tab-bar.theme-dark .tab-label{color:#999}.tab-item.active .tab-label{color:#ff9a9e}.custom-tab-bar.theme-dark .tab-item.active .tab-label{color:#ff7eb3}
.tab-bar-root{bottom:0;height:160rpx;left:0;pointer-events:none;position:fixed;right:0;z-index:999}.tab-bar-gradient{bottom:0;height:100%;left:0;position:absolute;right:0}.tab-bar-root.theme-light .tab-bar-gradient{background:-webkit-gradient(linear,left bottom,left top,from(hsla(38,44%,96%,.5)),color-stop(50%,hsla(38,44%,96%,.1)),color-stop(86%,hsla(38,44%,96%,0)));background:-webkit-linear-gradient(bottom,hsla(38,44%,96%,.5),hsla(38,44%,96%,.1) 50%,hsla(38,44%,96%,0) 86%);background:linear-gradient(0deg,hsla(38,44%,96%,.5) 0,hsla(38,44%,96%,.1) 50%,hsla(38,44%,96%,0) 86%)}.tab-bar-root.theme-dark .tab-bar-gradient{background:-webkit-gradient(linear,left bottom,left top,from(rgba(25,25,25,.5)),color-stop(50%,rgba(25,25,25,.1)),color-stop(86%,rgba(25,25,25,0)));background:-webkit-linear-gradient(bottom,rgba(25,25,25,.5),rgba(25,25,25,.1) 50%,rgba(25,25,25,0) 86%);background:linear-gradient(0deg,rgba(25,25,25,.5) 0,rgba(25,25,25,.1) 50%,rgba(25,25,25,0) 86%)}.custom-tab-bar{-ms-flex-pack:distribute;-ms-flex-align:center;-webkit-align-items:center;align-items:center;backdrop-filter:blur(32rpx) saturate(1.2);-webkit-backdrop-filter:blur(32rpx) saturate(1.2);background:hsla(0,0%,100%,.55);border:1rpx solid hsla(0,0%,100%,.55);border-radius:64rpx;bottom:36rpx;-webkit-box-shadow:0 12rpx 40rpx rgba(0,0,0,.18),0 4rpx 12rpx rgba(0,0,0,.08);box-shadow:0 12rpx 40rpx rgba(0,0,0,.18),0 4rpx 12rpx rgba(0,0,0,.08);-webkit-box-sizing:border-box;box-sizing:border-box;display:-webkit-flex;display:-ms-flexbox;display:flex;height:116rpx;-webkit-justify-content:space-around;justify-content:space-around;left:36rpx;pointer-events:auto;position:absolute;right:36rpx;z-index:1000}.custom-tab-bar.theme-dark{backdrop-filter:blur(32rpx) saturate(1.2);-webkit-backdrop-filter:blur(32rpx) saturate(1.2);background:rgba(25,25,25,.55);border-color:hsla(0,0%,100%,.14);-webkit-box-shadow:0 12rpx 40rpx rgba(0,0,0,.5),0 4rpx 12rpx rgba(0,0,0,.3);box-shadow:0 12rpx 40rpx rgba(0,0,0,.5),0 4rpx 12rpx rgba(0,0,0,.3)}.tab-item{-ms-flex-align:center;-ms-flex-pack:center;-webkit-align-items:center;align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex:1;-ms-flex:1;flex:1;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;height:100%;-webkit-justify-content:center;justify-content:center;max-width:160rpx;padding:0 12rpx;position:relative}.tab-indicator{background:rgba(0,0,0,.14);border-radius:50rpx;bottom:6rpx;-webkit-box-shadow:0 0 6rpx rgba(0,0,0,.07);box-shadow:0 0 6rpx rgba(0,0,0,.07);height:100rpx;left:50%;position:absolute;-webkit-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%);width:120rpx}.custom-tab-bar.theme-dark .tab-indicator{background:hsla(0,0%,100%,.14);-webkit-box-shadow:0 0 6rpx hsla(0,0%,100%,.07);box-shadow:0 0 6rpx hsla(0,0%,100%,.07)}.tab-icon-img{height:40rpx;margin-bottom:2rpx;opacity:.8;position:relative;-webkit-transition:-webkit-transform .2s;transition:-webkit-transform .2s;transition:transform .2s;transition:transform .2s,-webkit-transform .2s;width:40rpx;z-index:1}.tab-item.active .tab-icon-img{opacity:1;-webkit-transform:scale(1.08);-ms-transform:scale(1.08);transform:scale(1.08)}.tab-label{color:#8a7e76;font-size:20rpx;font-weight:700;line-height:22rpx;position:relative;-webkit-transition:color .2s;transition:color .2s;z-index:1}.custom-tab-bar.theme-dark .tab-label{color:#b3a79c}.tab-item.active .tab-label{color:#d96c6a}.custom-tab-bar.theme-dark .tab-item.active .tab-label{color:#f09198}
+1 -1
View File
@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#ff9a9e"><path d="M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8z"/><path d="M5.5 20c.8-3 3.4-4.5 6.5-4.5s5.7 1.5 6.5 4.5"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#d96c6a"><path d="M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8z"/><path d="M5.5 20c.8-3 3.4-4.5 6.5-4.5s5.7 1.5 6.5 4.5"/></svg>

Before

Width:  |  Height:  |  Size: 185 B

After

Width:  |  Height:  |  Size: 185 B

+1 -1
View File
@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#ff9a9e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8z"/><path d="M5.5 20c.8-3 3.4-4.5 6.5-4.5s5.7 1.5 6.5 4.5"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#d96c6a" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8z"/><path d="M5.5 20c.8-3 3.4-4.5 6.5-4.5s5.7 1.5 6.5 4.5"/></svg>

Before

Width:  |  Height:  |  Size: 263 B

After

Width:  |  Height:  |  Size: 263 B

+1 -1
View File
@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M7 3.5h10A1.5 1.5 0 0 1 18.5 5v14A1.5 1.5 0 0 1 17 20.5H7A1.5 1.5 0 0 1 5.5 19V5A1.5 1.5 0 0 1 7 3.5z" fill="#ff9a9e"/><path d="M9 8h6M9 12h6M9 16h3" stroke="#fff" stroke-width="1.6" stroke-linecap="round"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M7 3.5h10A1.5 1.5 0 0 1 18.5 5v14A1.5 1.5 0 0 1 17 20.5H7A1.5 1.5 0 0 1 5.5 19V5A1.5 1.5 0 0 1 7 3.5z" fill="#d96c6a"/><path d="M9 8h6M9 12h6M9 16h3" stroke="#fff" stroke-width="1.6" stroke-linecap="round"/></svg>

Before

Width:  |  Height:  |  Size: 283 B

After

Width:  |  Height:  |  Size: 283 B

+1 -1
View File
@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#ff9a9e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 3.5h10A1.5 1.5 0 0 1 18.5 5v14A1.5 1.5 0 0 1 17 20.5H7A1.5 1.5 0 0 1 5.5 19V5A1.5 1.5 0 0 1 7 3.5z"/><path d="M9 8h6M9 12h6M9 16h3"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#d96c6a" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 3.5h10A1.5 1.5 0 0 1 18.5 5v14A1.5 1.5 0 0 1 17 20.5H7A1.5 1.5 0 0 1 5.5 19V5A1.5 1.5 0 0 1 7 3.5z"/><path d="M9 8h6M9 12h6M9 16h3"/></svg>

Before

Width:  |  Height:  |  Size: 305 B

After

Width:  |  Height:  |  Size: 305 B

+1 -1
View File
@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#ff9a9e"><path d="M5 8h14l-1.2 12H6.2L5 8z"/><path d="M9 8V6a3 3 0 0 1 6 0v2" fill="none" stroke="#ff9a9e" stroke-width="2" stroke-linecap="round"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#d96c6a"><path d="M5 8h14l-1.2 12H6.2L5 8z"/><path d="M9 8V6a3 3 0 0 1 6 0v2" fill="none" stroke="#d96c6a" stroke-width="2" stroke-linecap="round"/></svg>

Before

Width:  |  Height:  |  Size: 221 B

After

Width:  |  Height:  |  Size: 221 B

+1 -1
View File
@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#ff9a9e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 8h14l-1.2 12H6.2L5 8z"/><path d="M9 8V6a3 3 0 0 1 6 0v2"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#d96c6a" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 8h14l-1.2 12H6.2L5 8z"/><path d="M9 8V6a3 3 0 0 1 6 0v2"/></svg>

Before

Width:  |  Height:  |  Size: 230 B

After

Width:  |  Height:  |  Size: 230 B

+1 -1
View File
@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#ff9a9e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2.5L14.8 9.2 21.5 12 14.8 14.8 12 21.5 9.2 14.8 2.5 12 9.2 9.2z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#d96c6a" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2.5L14.8 9.2 21.5 12 14.8 14.8 12 21.5 9.2 14.8 2.5 12 9.2 9.2z"/></svg>

Before

Width:  |  Height:  |  Size: 239 B

After

Width:  |  Height:  |  Size: 239 B

+1 -1
View File
@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#ff9a9e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="10.5" cy="10.5" r="6.5"/><path d="M15.5 15.5l4.5 4.5"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#d96c6a" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="10.5" cy="10.5" r="6.5"/><path d="M15.5 15.5l4.5 4.5"/></svg>

Before

Width:  |  Height:  |  Size: 227 B

After

Width:  |  Height:  |  Size: 227 B

+1 -1
View File
@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#ff9a9e"><path fill-rule="evenodd" d="M12 4a8 8 0 1 1 0 16 8 8 0 0 1 0-16zm-3 6a1.4 1.4 0 1 0 0 2.8 1.4 1.4 0 0 0 0-2.8zm6 0a1.4 1.4 0 1 0 0 2.8 1.4 1.4 0 0 0 0-2.8zM12 13.6a1.4 1.4 0 1 0 0 2.8 1.4 1.4 0 0 0 0-2.8z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#d96c6a"><path fill-rule="evenodd" d="M12 4a8 8 0 1 1 0 16 8 8 0 0 1 0-16zm-3 6a1.4 1.4 0 1 0 0 2.8 1.4 1.4 0 0 0 0-2.8zm6 0a1.4 1.4 0 1 0 0 2.8 1.4 1.4 0 0 0 0-2.8zM12 13.6a1.4 1.4 0 1 0 0 2.8 1.4 1.4 0 0 0 0-2.8z"/></svg>

Before

Width:  |  Height:  |  Size: 290 B

After

Width:  |  Height:  |  Size: 290 B

+1 -1
View File
@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#ff9a9e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="8"/><circle cx="9" cy="10" r="1.2" fill="#ff9a9e"/><circle cx="15" cy="10" r="1.2" fill="#ff9a9e"/><circle cx="12" cy="15" r="1.2" fill="#ff9a9e"/><path d="M12 12v3"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#d96c6a" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="8"/><circle cx="9" cy="10" r="1.2" fill="#d96c6a"/><circle cx="15" cy="10" r="1.2" fill="#d96c6a"/><circle cx="12" cy="15" r="1.2" fill="#d96c6a"/><path d="M12 12v3"/></svg>

Before

Width:  |  Height:  |  Size: 354 B

After

Width:  |  Height:  |  Size: 354 B

+1 -1
View File
@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#ff9a9e"><path d="M4 11l8-7 8 7v8a1 1 0 0 1-1 1h-4.5v-6h-5v6H5a1 1 0 0 1-1-1z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#d96c6a"><path d="M4 11l8-7 8 7v8a1 1 0 0 1-1 1h-4.5v-6h-5v6H5a1 1 0 0 1-1-1z"/></svg>

Before

Width:  |  Height:  |  Size: 153 B

After

Width:  |  Height:  |  Size: 153 B

+1 -1
View File
@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#ff9a9e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 11l8-7 8 7"/><path d="M6 9.5V20h12V9.5"/><path d="M10 20v-6h4v6"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#d96c6a" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 11l8-7 8 7"/><path d="M6 9.5V20h12V9.5"/><path d="M10 20v-6h4v6"/></svg>

Before

Width:  |  Height:  |  Size: 238 B

After

Width:  |  Height:  |  Size: 238 B

+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
"use strict";(wx["webpackJsonp"]=wx["webpackJsonp"]||[]).push([[301],{6855:function(e,n,t){var a=t(7842),s=t(118),c=t(9703),r=t(9201),i=t(5414),l=t(9674),o=t(4848);function m(){var e=(0,c.wR)(),n=(e.theme,e.resolvedTheme),t=(0,r.c)();(0,i.l)(n);var a=[{title:"\u4e00\u3001\u7528\u6237\u6743\u8d23",content:"\u7528\u6237\u786e\u8ba4\u63d0\u4ea4\u7684\u8bbe\u8ba1\u5185\u5bb9\u4e0d\u4fb5\u72af\u7b2c\u4e09\u65b9\u77e5\u8bc6\u4ea7\u6743\uff0c\u5b9a\u5236\u5546\u54c1\u4e00\u7ecf\u786e\u8ba4\u4e0b\u5355\u5373\u8fdb\u5165\u751f\u4ea7\u6d41\u7a0b\uff0c\u975e\u8d28\u91cf\u95ee\u9898\u4e0d\u652f\u6301\u9000\u6362\u3002"},{title:"\u4e8c\u3001\u9690\u79c1\u4fdd\u62a4",content:"\u6211\u4eec\u4e25\u683c\u4fdd\u62a4\u7528\u6237\u4e2a\u4eba\u4fe1\u606f\uff0c\u5934\u50cf\u4e0e\u6635\u79f0\u4ec5\u7528\u4e8e\u63d0\u5347\u670d\u52a1\u4f53\u9a8c\uff0c\u4e0d\u4e0e\u7b2c\u4e09\u65b9\u5206\u4eab\u3002"},{title:"\u4e09\u3001\u552e\u540e\u8bf4\u660e",content:"\u6536\u5230\u5546\u54c1\u540e\u5982\u6709\u8d28\u91cf\u95ee\u9898\uff0c\u8bf7\u57287\u5929\u5185\u8054\u7cfb\u5ba2\u670d\uff0c\u6211\u4eec\u5c06\u4e3a\u60a8\u514d\u8d39\u91cd\u505a\u6216\u9000\u6b3e\u3002"},{title:"\u56db\u3001\u5b9a\u5236\u6d41\u7a0b",content:"1. \u9009\u62e9\u5546\u54c1\u54c1\u7c7b\u5e76\u52a0\u5165\u8bbe\u8ba1\u6e05\u5355\n2. \u5728DIY\u5de5\u4f5c\u53f0\u4e0a\u4f20\u56fe\u7247\u6216\u8f93\u5165\u6587\u5b57\n3. \u786e\u8ba4\u8bbe\u8ba1\u6548\u679c\u5e76\u63d0\u4ea4\u8ba2\u5355\n4. \u652f\u4ed8\u540e\u8fdb\u5165\u751f\u4ea7\uff0c\u7ea63-7\u4e2a\u5de5\u4f5c\u65e5\u53d1\u8d27\n5. \u7269\u6d41\u8ddf\u8e2a\u81f3\u786e\u8ba4\u6536\u8d27"}];return(0,o.jsxs)(s.Ss,{className:"theme-".concat(n),children:[(0,o.jsx)(l.A,{}),(0,o.jsx)(s.Ss,{className:"agreement-page",children:(0,o.jsxs)(s.Ss,{className:"agreement-content",style:{marginTop:"".concat(t.headerPaddingTop,"px")},children:[(0,o.jsx)(s.EY,{className:"agreement-title",children:"\u5b9a\u5236\u534f\u8bae"}),a.map(function(e,n){return(0,o.jsxs)(s.Ss,{className:"agreement-section",children:[(0,o.jsx)(s.EY,{className:"agreement-h3",children:e.title}),(0,o.jsx)(s.EY,{className:"agreement-p",children:e.content})]},n)})]})})]})}var g={navigationStyle:"custom",enablePageMeta:!0,navigationBarTitleText:"\u5b9a\u5236\u534f\u8bae"};Page((0,a.createPageConfig)(m,"pages/agreement/index",{root:{cn:[]}},g||{}))}},function(e){var n=function(n){return e(e.s=n)};e.O(0,[907,96,76],function(){return n(6855)});e.O()}]);
"use strict";(wx["webpackJsonp"]=wx["webpackJsonp"]||[]).push([[301],{6855:function(e,n,t){var a=t(7842),s=t(118),c=t(9703),r=t(9201),i=t(5414),l=t(9674),o=t(4848);function m(){var e=(0,c.wR)(),n=(e.theme,e.resolvedTheme),t=(0,r.c)();(0,i.l)(n);var a=[{title:"\u4e00\u3001\u7528\u6237\u6743\u8d23",content:"\u7528\u6237\u786e\u8ba4\u63d0\u4ea4\u7684\u8bbe\u8ba1\u5185\u5bb9\u4e0d\u4fb5\u72af\u7b2c\u4e09\u65b9\u77e5\u8bc6\u4ea7\u6743\uff0c\u5b9a\u5236\u5546\u54c1\u4e00\u7ecf\u786e\u8ba4\u4e0b\u5355\u5373\u8fdb\u5165\u751f\u4ea7\u6d41\u7a0b\uff0c\u975e\u8d28\u91cf\u95ee\u9898\u4e0d\u652f\u6301\u9000\u6362\u3002"},{title:"\u4e8c\u3001\u9690\u79c1\u4fdd\u62a4",content:"\u6211\u4eec\u4e25\u683c\u4fdd\u62a4\u7528\u6237\u4e2a\u4eba\u4fe1\u606f\uff0c\u5934\u50cf\u4e0e\u6635\u79f0\u4ec5\u7528\u4e8e\u63d0\u5347\u670d\u52a1\u4f53\u9a8c\uff0c\u4e0d\u4e0e\u7b2c\u4e09\u65b9\u5206\u4eab\u3002"},{title:"\u4e09\u3001\u552e\u540e\u8bf4\u660e",content:"\u6536\u5230\u5546\u54c1\u540e\u5982\u6709\u8d28\u91cf\u95ee\u9898\uff0c\u8bf7\u57287\u5929\u5185\u8054\u7cfb\u5ba2\u670d\uff0c\u6211\u4eec\u5c06\u4e3a\u60a8\u514d\u8d39\u91cd\u505a\u6216\u9000\u6b3e\u3002"},{title:"\u56db\u3001\u5b9a\u5236\u6d41\u7a0b",content:"1. \u9009\u62e9\u5546\u54c1\u54c1\u7c7b\u5e76\u52a0\u5165\u8bbe\u8ba1\u6e05\u5355\n2. \u5728DIY\u5de5\u4f5c\u53f0\u4e0a\u4f20\u56fe\u7247\u6216\u8f93\u5165\u6587\u5b57\n3. \u786e\u8ba4\u8bbe\u8ba1\u6548\u679c\u5e76\u63d0\u4ea4\u8ba2\u5355\n4. \u652f\u4ed8\u540e\u8fdb\u5165\u751f\u4ea7\uff0c\u7ea63-7\u4e2a\u5de5\u4f5c\u65e5\u53d1\u8d27\n5. \u7269\u6d41\u8ddf\u8e2a\u81f3\u786e\u8ba4\u6536\u8d27"}];return(0,o.jsxs)(s.Ss,{className:"theme-".concat(n),children:[(0,o.jsx)(l.A,{}),(0,o.jsx)(s.Ss,{className:"agreement-page",children:(0,o.jsxs)(s.Ss,{className:"agreement-content",style:{marginTop:"".concat(t.headerPaddingTop,"px")},children:[(0,o.jsx)(s.EY,{className:"agreement-title",children:"\u5b9a\u5236\u534f\u8bae"}),a.map(function(e,n){return(0,o.jsxs)(s.Ss,{className:"agreement-section surface-card",children:[(0,o.jsx)(s.EY,{className:"agreement-h3",children:e.title}),(0,o.jsx)(s.EY,{className:"agreement-p",children:e.content})]},n)})]})})]})}var g={navigationStyle:"custom",enablePageMeta:!0,navigationBarTitleText:"\u5b9a\u5236\u534f\u8bae"};Page((0,a.createPageConfig)(m,"pages/agreement/index",{root:{cn:[]}},g||{}))}},function(e){var n=function(n){return e(e.s=n)};e.O(0,[907,96,76],function(){return n(6855)});e.O()}]);
+1 -1
View File
@@ -1 +1 @@
.agreement-page{padding:0 24rpx 24rpx}.agreement-title{color:var(--text-primary);display:block;font-size:40rpx;font-weight:800;margin-bottom:32rpx;padding-top:24rpx}.agreement-content{line-height:1.8;padding:40rpx 32rpx}.agreement-section{margin-bottom:32rpx}.agreement-h3{color:var(--text-primary);display:block;font-size:32rpx;font-weight:700;margin-bottom:16rpx}.agreement-p{color:var(--text-secondary);display:block;font-size:28rpx;line-height:1.8}
.agreement-page{-webkit-box-sizing:border-box;box-sizing:border-box;min-height:100vh;padding:0 32rpx calc(24rpx + env(safe-area-inset-bottom))}.agreement-content{line-height:1.8;padding:32rpx 0 48rpx}.agreement-title{color:var(--text-primary);display:block;font-size:44rpx;font-weight:700;letter-spacing:0;line-height:1.2;margin-bottom:32rpx}.agreement-section{display:block;margin-bottom:24rpx;padding:32rpx}.agreement-section:last-child{margin-bottom:0}.agreement-h3{color:var(--text-primary);display:block;font-size:32rpx;font-weight:700;letter-spacing:0;line-height:1.3;margin-bottom:16rpx}.agreement-p{color:var(--text-secondary);display:block;font-size:28rpx;line-height:1.8;white-space:pre-line}
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
.service-page{min-height:100vh;padding:0 24rpx 24rpx}.page-header{margin:20rpx 0 0;padding:32rpx 32rpx 24rpx}.service-hero{-ms-flex-align:center;-webkit-align-items:center;align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:50rpx 40rpx;text-align:center}.service-hero-icon{height:56rpx;margin-bottom:20rpx;width:56rpx}.service-title{color:var(--text-primary);display:block;font-size:36rpx;font-weight:700;margin-bottom:12rpx}.service-desc{color:var(--text-secondary);display:block;font-size:24rpx;margin-bottom:32rpx}.service-btn{border-radius:50rpx!important;font-size:30rpx!important;padding:24rpx 56rpx!important}.contact-list{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;gap:20rpx}.contact-item{-ms-flex-align:center;-webkit-align-items:center;align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:28rpx 32rpx}.contact-icon{font-size:48rpx;margin-right:24rpx}.contact-icon-img{-ms-flex-negative:0;-webkit-flex-shrink:0;flex-shrink:0;height:32rpx;margin-right:24rpx;width:32rpx}.contact-info{-webkit-flex:1;-ms-flex:1;flex:1}.contact-label{color:var(--text-secondary);display:block;font-size:24rpx;margin-bottom:4rpx}.contact-value{color:var(--text-primary);font-size:30rpx;font-weight:600}.faq-card{margin-bottom:20rpx;padding:28rpx 32rpx}.faq-q{color:var(--text-primary);display:block;font-size:30rpx;font-weight:700;margin-bottom:12rpx}.faq-a{color:var(--text-secondary);font-size:26rpx;line-height:1.6}.enterprise-service{padding:32rpx}.enterprise-icon{height:28rpx;margin-right:12rpx;width:28rpx}.enterprise-title{color:var(--text-primary);display:block;font-size:30rpx;font-weight:700;margin-bottom:8rpx}.enterprise-desc{color:var(--text-secondary);display:block;font-size:24rpx;margin-bottom:24rpx}
.service-page{-webkit-box-sizing:border-box;box-sizing:border-box;min-height:100vh;padding:0 32rpx calc(24rpx + env(safe-area-inset-bottom))}.service-page .page-header.service-header{margin:0;padding-bottom:32rpx;padding-left:0;padding-right:0;text-align:center}.service-header .page-title{color:var(--text-primary);font-size:44rpx;font-weight:700;letter-spacing:0;line-height:1.2}.service-hero{-ms-flex-align:center;-webkit-align-items:center;align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:56rpx 40rpx;text-align:center}.service-hero-icon{height:88rpx;margin-bottom:24rpx;width:88rpx}.service-title{color:var(--text-primary);display:block;font-size:36rpx;font-weight:700;letter-spacing:0;margin-bottom:12rpx}.service-desc{color:var(--text-secondary);display:block;font-size:24rpx;line-height:1.5;margin-bottom:32rpx}.service-btn{-ms-flex-align:center;-ms-flex-pack:center;-webkit-align-items:center;align-items:center;-webkit-box-sizing:border-box;box-sizing:border-box;display:-webkit-flex;display:-ms-flexbox;display:flex;font-size:28rpx;font-weight:600;height:80rpx;-webkit-justify-content:center;justify-content:center;min-width:280rpx;padding:0 48rpx}.service-page .section-title{color:var(--text-primary);display:block;font-size:32rpx;font-weight:700;letter-spacing:0;margin-bottom:24rpx}.contact-list.surface-card{overflow:hidden;padding:0 32rpx}.contact-item{-ms-flex-align:center;-webkit-align-items:center;align-items:center;border-bottom:1rpx solid var(--border);display:-webkit-flex;display:-ms-flexbox;display:flex;min-height:112rpx;padding:24rpx 0}.contact-item:last-child{border-bottom:none}.contact-item-link{-webkit-transition:background .16s ease;transition:background .16s ease}.contact-item-link:active{background:var(--bg-muted)}.contact-icon-img{-ms-flex-negative:0;-webkit-flex-shrink:0;flex-shrink:0;height:48rpx;margin-right:24rpx;width:48rpx}.contact-info{-webkit-flex:1;-ms-flex:1;flex:1;min-width:0}.contact-label{color:var(--text-secondary);display:block;font-size:24rpx;line-height:1.4;margin-bottom:4rpx}.contact-value{color:var(--text-primary);display:block;font-size:28rpx;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.contact-arrow{-ms-flex-negative:0;color:var(--text-muted);-webkit-flex-shrink:0;flex-shrink:0;font-size:32rpx;line-height:1;margin-left:16rpx}.faq-card{display:block;margin-bottom:24rpx;padding:32rpx}.faq-q{color:var(--text-primary);display:block;font-size:30rpx;font-weight:700;letter-spacing:0;line-height:1.45;margin-bottom:12rpx}.faq-a{color:var(--text-secondary);display:block;font-size:26rpx;line-height:1.7}.enterprise-service{padding:32rpx}.enterprise-service .flex-center{-ms-flex-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;margin-bottom:12rpx}.enterprise-icon{-ms-flex-negative:0;-webkit-flex-shrink:0;flex-shrink:0;height:40rpx;margin-right:12rpx;width:40rpx}.enterprise-title{color:var(--text-primary);display:block;font-size:30rpx;font-weight:700;letter-spacing:0}.enterprise-desc{color:var(--text-secondary);display:block;font-size:24rpx;line-height:1.6;margin-bottom:24rpx}.enterprise-btn{-ms-flex-align:center;-ms-flex-pack:center;-webkit-align-items:center;align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;font-size:28rpx;font-weight:600;height:80rpx;-webkit-justify-content:center;justify-content:center}
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
"use strict";(wx["webpackJsonp"]=wx["webpackJsonp"]||[]).push([[205],{6296:function(s,e,a){var n=a(7842),c=a(118),o=a(758),i=a.n(o),r=a(9703),l=a(9201),d=a(5414),t=a(9674),h=a(5234),p=a(4848);function m(){var s=(0,r.wR)(),e=s.resolvedTheme,a=(0,l.c)();(0,d.l)(e);var n=function(s){i().navigateTo({url:"/pages/shop/detail/index?id=".concat(s)})};return(0,p.jsxs)(c.Ss,{className:"shop-page theme-".concat(e),children:[(0,p.jsx)(t.A,{}),(0,p.jsxs)(c.Ss,{className:"shop-list",children:[(0,p.jsxs)(c.Ss,{className:"shop-header",style:{paddingTop:"".concat(a.headerPaddingTop,"px")},children:[(0,p.jsx)(c.EY,{className:"shop-header-title",children:"\u667a\u7ed8\u7cbe\u9009"}),(0,p.jsx)(c.EY,{className:"shop-header-sub",children:"\u6fc0\u5149\u5fae\u96d5\u5b9a\u5236\u597d\u7269"})]}),(0,p.jsx)(c.Ss,{className:"shop-grid",children:h.zv.map(function(s){var e,a,o,i;return(0,p.jsxs)(c.Ss,{className:"shop-card",onTap:function(){return n(s.id)},children:[(0,p.jsx)(c.Ss,{className:"shop-card-img-wrap",children:(0,p.jsx)(c._V,{className:"shop-card-img",src:(null===(e=s.images)||void 0===e?void 0:e[0])||s.iconImg||"",mode:"aspectFill",lazyLoad:!0})}),(0,p.jsxs)(c.Ss,{className:"shop-card-info",style:{backgroundColor:"rgba(".concat((null===(a=s.tone)||void 0===a?void 0:a[0])||28,", ").concat((null===(o=s.tone)||void 0===o?void 0:o[1])||22,", ").concat((null===(i=s.tone)||void 0===i?void 0:i[2])||18,", 0.92)")},children:[(0,p.jsx)(c.EY,{className:"shop-card-name",children:s.name}),(0,p.jsxs)(c.EY,{className:"shop-card-price",children:["\xa5",s.price]})]})]},s.id)})}),(0,p.jsx)(c.Ss,{style:{height:"160px"}})]})]})}var u={navigationStyle:"custom",enablePageMeta:!0};Page((0,n.createPageConfig)(m,"pages/shop/index",{root:{cn:[]}},u||{}))}},function(s){var e=function(e){return s(s.s=e)};s.O(0,[907,96,76],function(){return e(6296)});s.O()}]);
"use strict";(wx["webpackJsonp"]=wx["webpackJsonp"]||[]).push([[205],{6296:function(s,e,a){var c=a(7842),n=a(118),r=a(758),i=a.n(r),o=a(9703),d=a(9201),l=a(5414),h=a(9674),p=a(5234),t=a(4848);function m(){var s=(0,o.wR)(),e=s.resolvedTheme,a=(0,d.c)();(0,l.l)(e);var c=function(s){i().navigateTo({url:"/pages/shop/detail/index?id=".concat(s)})};return(0,t.jsxs)(n.Ss,{className:"shop-page theme-".concat(e),children:[(0,t.jsx)(h.A,{}),(0,t.jsxs)(n.Ss,{className:"shop-list",children:[(0,t.jsxs)(n.Ss,{className:"shop-header",style:{paddingTop:"".concat(a.headerPaddingTop,"px")},children:[(0,t.jsx)(n.EY,{className:"shop-header-title",children:"\u667a\u7ed8\u7cbe\u9009"}),(0,t.jsx)(n.EY,{className:"shop-header-sub",children:"\u6fc0\u5149\u5fae\u96d5\u5b9a\u5236\u597d\u7269"})]}),(0,t.jsx)(n.Ss,{className:"shop-grid",children:p.zv.map(function(s){var e=s.images[0]||s.iconImg||"";return(0,t.jsxs)(n.Ss,{className:"shop-card",onTap:function(){return c(s.id)},children:[(0,t.jsx)(n.Ss,{className:"shop-card-img-wrap",children:(0,t.jsx)(n._V,{className:"shop-card-img",src:e,mode:"aspectFill",lazyLoad:!0})}),(0,t.jsxs)(n.Ss,{className:"shop-card-body",children:[(0,t.jsx)(n.EY,{className:"shop-card-name",children:s.name}),(0,t.jsx)(n.EY,{className:"shop-card-desc",children:s.desc||""}),(0,t.jsxs)(n.EY,{className:"shop-card-price",children:["\xa5",s.price]})]})]},s.id)})})]})]})}var x={navigationStyle:"custom",enablePageMeta:!0};Page((0,c.createPageConfig)(m,"pages/shop/index",{root:{cn:[]}},x||{}))}},function(s){var e=function(e){return s(s.s=e)};s.O(0,[907,96,76],function(){return e(6296)});s.O()}]);
+1 -1
View File
@@ -1 +1 @@
.shop-list{padding:0 24rpx 24rpx}.shop-header{padding:40rpx 0 24rpx;text-align:center}.shop-header-title{color:var(--text-primary);display:block;font-size:40rpx;font-weight:800;letter-spacing:4rpx}.shop-header-sub{color:var(--text-secondary);display:block;font-size:24rpx;margin-top:8rpx}.shop-grid{display:grid;gap:20rpx;grid-template-columns:1fr 1fr}.shop-card{background:var(--bg-card);border-radius:24rpx;-webkit-box-shadow:var(--shadow-card);box-shadow:var(--shadow-card);overflow:hidden;-webkit-transition:-webkit-transform .15s ease;transition:-webkit-transform .15s ease;transition:transform .15s ease;transition:transform .15s ease,-webkit-transform .15s ease}.shop-card:active{-webkit-transform:scale(.97);-ms-transform:scale(.97);transform:scale(.97)}.shop-card-img-wrap{aspect-ratio:3/4;background:#2a2218;overflow:hidden}.shop-card-img{height:100%;-o-object-fit:cover;object-fit:cover;-webkit-transition:-webkit-transform .4s ease;transition:-webkit-transform .4s ease;transition:transform .4s ease;transition:transform .4s ease,-webkit-transform .4s ease;width:100%}.shop-card-info{padding:16rpx 20rpx 20rpx}.shop-card-name{-webkit-line-clamp:2;-webkit-box-orient:vertical;color:#e8e0d6;display:-webkit-box;font-size:26rpx;line-height:1.4;min-height:74rpx;overflow:hidden}.shop-card-price{color:#ff9a9e;display:block;font-size:30rpx;font-weight:700;margin-top:10rpx}@media (min-width:750rpx){.shop-page{-ms-flex-pack:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-justify-content:center;justify-content:center}}
.shop-list{padding:0 32rpx 24rpx}.shop-header{padding:48rpx 0 32rpx;text-align:center}.shop-header-title{color:var(--text-primary);display:block;font-size:44rpx;font-weight:700;letter-spacing:0}.shop-header-sub{color:var(--text-secondary);display:block;font-size:24rpx;margin-top:8rpx}.shop-grid{display:grid;gap:24rpx;grid-template-columns:1fr 1fr}.shop-card{background:var(--bg-card);border:1rpx solid var(--border);border-radius:24rpx;-webkit-box-shadow:var(--shadow-card);box-shadow:var(--shadow-card);overflow:hidden;-webkit-transition:-webkit-transform .15s ease;transition:-webkit-transform .15s ease;transition:transform .15s ease;transition:transform .15s ease,-webkit-transform .15s ease}.shop-card:active{-webkit-transform:scale(.98);-ms-transform:scale(.98);transform:scale(.98)}.shop-card-img-wrap{aspect-ratio:1/1;background:var(--bg-muted);overflow:hidden}.shop-card-img{height:100%;-o-object-fit:cover;object-fit:cover;-webkit-transition:-webkit-transform .4s ease;transition:-webkit-transform .4s ease;transition:transform .4s ease;transition:transform .4s ease,-webkit-transform .4s ease;width:100%}.shop-card-body{padding:20rpx 24rpx 24rpx}.shop-card-name{-webkit-line-clamp:2;-webkit-box-orient:vertical;color:var(--text-primary);display:-webkit-box;font-size:28rpx;font-weight:700;line-height:1.4;overflow:hidden}.shop-card-desc{-webkit-line-clamp:2;-webkit-box-orient:vertical;color:var(--text-secondary);display:-webkit-box;font-size:24rpx;line-height:1.4;margin-top:8rpx;overflow:hidden}.shop-card-price{color:var(--accent-primary);display:block;font-size:32rpx;font-variant:tabular-nums;font-weight:700;margin-top:12rpx}@media (min-width:750rpx){.shop-page{-ms-flex-pack:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-justify-content:center;justify-content:center}}
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+9 -9
View File
@@ -1,14 +1,14 @@
{
"light": {
"navBgColor": "#ffffff",
"navBgColor": "#faf7f2",
"navTxtStyle": "black",
"bgColor": "#ffffff",
"bgColor": "#faf7f2",
"bgTxtStyle": "dark",
"bgColorTop": "#ffffff",
"bgColorBottom": "#ffffff",
"tabBarColor": "#b08d8d",
"tabBarSelectedColor": "#ff9a9e",
"tabBarBgColor": "#ffffff",
"bgColorTop": "#faf7f2",
"bgColorBottom": "#faf7f2",
"tabBarColor": "#8a7e76",
"tabBarSelectedColor": "#d96c6a",
"tabBarBgColor": "#faf7f2",
"tabBarBorderStyle": "black"
},
"dark": {
@@ -18,8 +18,8 @@
"bgTxtStyle": "light",
"bgColorTop": "#191919",
"bgColorBottom": "#191919",
"tabBarColor": "#999999",
"tabBarSelectedColor": "#ff7eb3",
"tabBarColor": "#b3a79c",
"tabBarSelectedColor": "#f09198",
"tabBarBgColor": "#191919",
"tabBarBorderStyle": "white"
}
-25
View File
@@ -129,31 +129,6 @@ page {
border-radius: 999rpx;
}
/* 固定底部操作栏 */
.action-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
align-items: center;
justify-content: space-between;
gap: 48rpx;
padding: 40rpx 64rpx calc(40rpx + env(safe-area-inset-bottom));
background: rgba(255, 255, 255, 0.55);
backdrop-filter: blur(32px) saturate(1.2);
-webkit-backdrop-filter: blur(32px) saturate(1.2);
border-top: 1rpx solid var(--glass-line);
z-index: 500;
}
.theme-dark .action-bar {
background: rgba(25, 25, 25, 0.55);
backdrop-filter: blur(32px) saturate(1.2);
-webkit-backdrop-filter: blur(32px) saturate(1.2);
border-top: 1rpx solid var(--glass-line);
}
/* === 标题文字 === */
.page-title {
font-size: 80rpx;
+25
View File
@@ -0,0 +1,25 @@
.bottom-action-bar {
position: fixed;
left: 36rpx;
right: 36rpx;
bottom: 36rpx;
z-index: 500;
box-sizing: border-box;
display: flex;
align-items: center;
gap: 24rpx;
padding: 24rpx;
padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
border-radius: 64rpx;
background: rgba(255, 255, 255, 0.55);
backdrop-filter: blur(32px) saturate(1.2);
-webkit-backdrop-filter: blur(32px) saturate(1.2);
border: 1rpx solid rgba(255, 255, 255, 0.55);
box-shadow: 0 12rpx 40rpx rgba(46, 34, 34, 0.18), 0 4rpx 12rpx rgba(46, 34, 34, 0.08);
}
.theme-dark .bottom-action-bar {
background: rgba(25, 25, 25, 0.55);
border-color: rgba(255, 255, 255, 0.14);
box-shadow: 0 12rpx 40rpx rgba(0, 0, 0, 0.5), 0 4rpx 12rpx rgba(0, 0, 0, 0.3);
}
+17
View File
@@ -0,0 +1,17 @@
import { View } from '@tarojs/components'
import type { CSSProperties, ReactNode } from 'react'
import './index.scss'
export interface BottomActionBarProps {
children?: ReactNode
className?: string
style?: CSSProperties
}
export default function BottomActionBar({ children, className, style }: BottomActionBarProps) {
return (
<View className={`bottom-action-bar ${className || ''}`} style={style}>
{children}
</View>
)
}
+15 -11
View File
@@ -36,17 +36,6 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) {
setResolved(resolveTheme(mode))
}, [])
const setTheme = useCallback((t: ThemeMode) => {
saveTheme(t)
set(t)
updateResolved(t)
}, [updateResolved])
const toggleTheme = useCallback(() => {
const next = resolvedTheme === 'light' ? 'dark' : 'light'
setTheme(next)
}, [resolvedTheme, setTheme])
/**
* darkmode 只作为系统主题探测通道;选中“跟随系统”时才跟着系统切换,
* 固定浅色/深色时由 setTheme 直接决定,不被动绑定系统。
@@ -80,6 +69,21 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) {
}
}, [updateFromSystem])
const setTheme = useCallback((t: ThemeMode) => {
saveTheme(t)
set(t)
if (t === 'auto') {
detectSystemTheme()
} else {
updateResolved(t)
}
}, [detectSystemTheme, updateResolved])
const toggleTheme = useCallback(() => {
const next = resolvedTheme === 'light' ? 'dark' : 'light'
setTheme(next)
}, [resolvedTheme, setTheme])
useEffect(() => {
detectSystemTheme()
}, [detectSystemTheme])
+59 -11
View File
@@ -1,11 +1,36 @@
.custom-tab-bar {
.tab-bar-root {
position: fixed;
bottom: 12px;
left: 12px;
right: 12px;
border-radius: 24px;
height: calc(96px + constant(safe-area-inset-bottom));
height: calc(96px + env(safe-area-inset-bottom));
left: 0;
right: 0;
bottom: 0;
height: 160rpx;
pointer-events: none;
z-index: 999;
}
.tab-bar-gradient {
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 100%;
}
.tab-bar-root.theme-light .tab-bar-gradient {
background: linear-gradient(to top, rgba(250, 247, 242, 0.5) 0%, rgba(250, 247, 242, 0.1) 50%, rgba(250, 247, 242, 0) 86%);
}
.tab-bar-root.theme-dark .tab-bar-gradient {
background: linear-gradient(to top, rgba(25, 25, 25, 0.5) 0%, rgba(25, 25, 25, 0.1) 50%, rgba(25, 25, 25, 0) 86%);
}
.custom-tab-bar {
position: absolute;
bottom: 36rpx;
left: 36rpx;
right: 36rpx;
border-radius: 64rpx;
height: 116rpx;
box-sizing: border-box;
background: rgba(255, 255, 255, 0.55);
backdrop-filter: blur(32px) saturate(1.2);
@@ -13,9 +38,9 @@
display: flex;
justify-content: space-around;
align-items: center;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
border: 1rpx solid rgba(255, 255, 255, 0.55);
box-shadow: 0 12rpx 40rpx rgba(0, 0, 0, 0.18), 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
pointer-events: auto;
z-index: 1000;
}
@@ -24,7 +49,8 @@
background: rgba(25, 25, 25, 0.55);
backdrop-filter: blur(32px) saturate(1.2);
-webkit-backdrop-filter: blur(32px) saturate(1.2);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
border-color: rgba(255, 255, 255, 0.14);
box-shadow: 0 12rpx 40rpx rgba(0, 0, 0, 0.5), 0 4rpx 12rpx rgba(0, 0, 0, 0.3);
}
.tab-item {
@@ -35,10 +61,30 @@
padding: 0 12px;
position: relative;
flex: 1;
height: 100%;
max-width: 160px;
}
.tab-indicator {
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 6rpx;
width: 120rpx;
height: 100rpx;
border-radius: 50rpx;
background: rgba(0, 0, 0, 0.14);
box-shadow: 0 0 6rpx rgba(0, 0, 0, 0.07);
}
.custom-tab-bar.theme-dark .tab-indicator {
background: rgba(255, 255, 255, 0.14);
box-shadow: 0 0 6rpx rgba(255, 255, 255, 0.07);
}
.tab-icon-img {
position: relative;
z-index: 1;
width: 40rpx;
height: 40rpx;
margin-bottom: 2px;
@@ -52,6 +98,8 @@
}
.tab-label {
position: relative;
z-index: 1;
font-size: 20px;
color: #8a7e76;
font-weight: 700;
+45 -15
View File
@@ -1,7 +1,7 @@
import { View, Text, Image } from '@tarojs/components'
import Taro from '@tarojs/taro'
import { useEffect, useState } from 'react'
import { getTheme, resolveTheme } from '../utils/store'
import { getTheme, resolveTheme, setDetectedSystemTheme } from '../utils/store'
import { THEME_CHANGE_EVENT } from '../context/ThemeContext'
import { applyPageBackground } from '../utils/themeBackground'
import { assetUrl } from '../utils/asset'
@@ -26,6 +26,11 @@ function currentTabPath(): string {
return matchTab(path)
}
type ThemeChangeApi = {
onThemeChange?: (listener: (res: { theme?: string }) => void) => void
offThemeChange?: (listener: (res: { theme?: string }) => void) => void
}
export default function CustomTabBar() {
const [resolvedTheme, setResolvedTheme] = useState<'light' | 'dark'>(resolveTheme(getTheme()))
@@ -40,6 +45,27 @@ export default function CustomTabBar() {
}
}, [])
// 自定义 tabBar 不处在 React Tree 里,额外直接监听系统主题,保证“跟随系统”时也即时切换
useEffect(() => {
const handler = (res: { theme?: string }) => {
if (res && (res.theme === 'dark' || res.theme === 'light')) {
setDetectedSystemTheme(res.theme)
if (getTheme() === 'auto') {
setResolvedTheme(res.theme)
}
}
}
const themeApi = Taro as typeof Taro & ThemeChangeApi
if (themeApi.onThemeChange) {
themeApi.onThemeChange(handler)
}
return () => {
if (themeApi.offThemeChange) {
themeApi.offThemeChange(handler)
}
}
}, [])
// 其它入口(如页面内部调用 switchTab)也会回到 tabBar,收到事件后重新同步选中态
useEffect(() => {
const handler = (path?: string) => {
@@ -66,20 +92,24 @@ export default function CustomTabBar() {
}
return (
<View className={`custom-tab-bar theme-${resolvedTheme}`}>
{TABS.map((tab) => {
const isActive = tab.pagePath === activeTab
return (
<View
key={tab.pagePath}
className={`tab-item ${isActive ? 'active' : ''}`}
onTap={() => switchTab(tab.pagePath)}
>
<Image className={`tab-icon-img ${isActive ? 'active' : ''}`} src={isActive ? tab.iconActive : tab.icon} mode='aspectFit' />
<Text className='tab-label'>{tab.label}</Text>
</View>
)
})}
<View className={`tab-bar-root theme-${resolvedTheme}`}>
<View className='tab-bar-gradient' />
<View className={`custom-tab-bar theme-${resolvedTheme}`}>
{TABS.map((tab) => {
const isActive = tab.pagePath === activeTab
return (
<View
key={tab.pagePath}
className={`tab-item ${isActive ? 'active' : ''}`}
onTap={() => switchTab(tab.pagePath)}
>
{isActive && <View className='tab-indicator' />}
<Image className={`tab-icon-img ${isActive ? 'active' : ''}`} src={isActive ? tab.iconActive : tab.icon} mode='aspectFit' />
<Text className='tab-label'>{tab.label}</Text>
</View>
)
})}
</View>
</View>
)
}
+188 -77
View File
@@ -1,135 +1,268 @@
/* ============================================================
Address Page — 收货地址
============================================================ */
.address-page {
padding: 0 24px 24px;
padding: 0 32rpx;
padding-bottom: calc(48rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
}
/* --- Page Header --- */
.page-header {
margin-bottom: 24rpx;
padding: 0;
}
.page-header-inner {
display: flex;
align-items: center;
gap: 16rpx;
min-height: 88rpx;
}
.back-btn {
font-size: 40px;
padding: 10px;
display: flex;
align-items: center;
justify-content: center;
width: 88rpx;
height: 88rpx;
flex: 0 0 auto;
border-radius: 50%;
background: var(--bg-card);
border: 1rpx solid var(--border-strong);
box-shadow: var(--shadow-card);
}
.back-btn:active {
transform: scale(0.96);
}
.back-arrow {
font-size: 36rpx;
line-height: 1;
color: var(--text-primary);
}
.nav-title {
flex: 1;
text-align: center;
font-size: 34rpx;
font-weight: 700;
color: var(--text-primary);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.nav-placeholder {
width: 88rpx;
flex: 0 0 auto;
}
/* --- 地址列表 --- */
.address-list {
margin-top: 20px;
display: flex;
flex-direction: column;
gap: 24rpx;
}
.address-card {
padding: 24px;
margin-bottom: 20px;
padding: 32rpx;
}
.address-header {
margin-bottom: 20px;
margin-bottom: 8rpx;
}
.address-user {
display: flex;
flex-wrap: wrap;
align-items: center;
margin-bottom: 12px;
gap: 16rpx;
margin-bottom: 12rpx;
}
.address-name {
font-size: 32px;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
margin-right: 16px;
}
.address-phone {
font-size: 28px;
font-size: 24rpx;
color: var(--text-secondary);
}
.default-tag {
margin-left: 12px;
display: inline-flex;
align-items: center;
height: 40rpx;
padding: 0 16rpx;
border-radius: 999rpx;
background: var(--accent-primary);
color: #fff;
font-size: 20px;
padding: 2px 10px;
border-radius: 8px;
color: var(--bg-page);
font-size: 20rpx;
font-weight: 600;
}
.address-full {
font-size: 28px;
display: block;
font-size: 26rpx;
color: var(--text-secondary);
line-height: 1.5;
line-height: 1.6;
}
.address-actions {
display: flex;
justify-content: flex-end;
gap: 24px;
padding-top: 16px;
gap: 16rpx;
margin-top: 20rpx;
padding-top: 24rpx;
border-top: 1rpx solid var(--border);
}
.address-act {
font-size: 26px;
display: flex;
align-items: center;
min-height: 56rpx;
padding: 0 24rpx;
border-radius: 999rpx;
background: var(--accent-secondary-soft);
color: var(--accent-secondary);
font-size: 24rpx;
font-weight: 500;
}
.address-act.delete {
background: var(--danger-soft);
color: var(--danger);
}
/* 表单弹窗 */
/* --- 空状态 --- */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
padding: 96rpx 40rpx;
text-align: center;
}
.empty-icon-img {
width: 88rpx;
height: 88rpx;
margin-bottom: 24rpx;
}
.empty-text {
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 12rpx;
}
.empty-sub {
font-size: 26rpx;
color: var(--text-secondary);
}
/* --- 底部操作栏 --- */
.bottom-action-bar .btn-primary {
display: flex;
align-items: center;
justify-content: center;
flex: 1;
min-height: 96rpx;
padding: 0;
font-size: 30rpx;
font-weight: 600;
}
/* --- 新增 / 编辑弹窗 --- */
.modal-overlay {
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
padding: 48rpx;
}
.address-form {
width: 100%;
max-width: 600px;
padding: 40px;
max-width: 640rpx;
padding: 40rpx;
box-sizing: border-box;
}
.modal-title {
display: block;
text-align: center;
margin-bottom: 32rpx;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
}
.form-input {
width: 100%;
height: 80px;
background: var(--bg-input);
border: 1rpx solid var(--border);
border-radius: 16px;
padding: 0 24px;
font-size: 28px;
color: var(--text-primary);
margin-bottom: 20px;
height: 88rpx;
margin-bottom: 20rpx;
padding: 0 24rpx;
box-sizing: border-box;
border: 1rpx solid var(--border);
border-radius: 16rpx;
background: var(--bg-input);
font-size: 28rpx;
color: var(--text-primary);
}
.form-input:focus {
border-color: var(--accent-primary);
background: var(--bg-card);
}
.form-picker {
width: 100%;
height: 80px;
background: var(--bg-input);
border: 1rpx solid var(--border);
border-radius: 16px;
display: flex;
align-items: center;
padding: 0 24px;
margin-bottom: 20px;
width: 100%;
height: 88rpx;
margin-bottom: 20rpx;
padding: 0 24rpx;
box-sizing: border-box;
border: 1rpx solid var(--border);
border-radius: 16rpx;
background: var(--bg-input);
}
.form-picker-val {
font-size: 28px;
font-size: 28rpx;
color: var(--text-primary);
}
.form-picker-ph {
font-size: 28px;
color: var(--text-secondary);
font-size: 28rpx;
color: var(--text-muted);
}
.form-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 32px;
gap: 24rpx;
margin-bottom: 32rpx;
}
.form-label {
font-size: 28px;
font-size: 28rpx;
color: var(--text-primary);
}
.checkbox {
width: 44px;
height: 44px;
border: 1rpx solid var(--border);
border-radius: 10px;
width: 44rpx;
height: 44rpx;
border: 2rpx solid var(--border-strong);
border-radius: 12rpx;
background: var(--bg-card);
transition: background 160ms ease, border-color 160ms ease;
}
.checkbox.checked {
@@ -139,39 +272,17 @@
.form-actions {
display: flex;
gap: 20px;
gap: 20rpx;
}
.form-actions .btn-secondary,
.form-actions .btn-primary {
flex: 1;
padding: 20px 0;
text-align: center;
}
/* 空状态(主题适配) */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
padding: 120px 40px;
text-align: center;
}
.empty-icon-img {
width: 48px;
height: 48px;
margin-bottom: 24px;
}
.empty-text {
font-size: 32px;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 12px;
}
.empty-sub {
font-size: 26px;
color: var(--text-secondary);
justify-content: center;
flex: 1;
min-height: 96rpx;
padding: 0;
font-size: 28rpx;
font-weight: 600;
}
+10 -7
View File
@@ -8,6 +8,7 @@ import { useThemeContext } from '../../context/ThemeContext'
import { useSafeArea } from '../../hooks/useSafeArea'
import { useStatusBar } from '../../hooks/useStatusBar'
import ThemedPageMeta from '../../components/ThemedPageMeta'
import BottomActionBar from '../../components/BottomActionBar'
import { assetUrl } from '../../utils/asset'
export default function AddressPage() {
@@ -98,11 +99,13 @@ export default function AddressPage() {
<ThemedPageMeta />
<View className='address-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='flex-between' style={{ width: '100%' }}>
<Text className='back-btn' onTap={() => Taro.navigateBack()}></Text>
<Text className='page-title'></Text>
<View style={{ width: '60px' }} />
<View className='page-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header-inner'>
<View className='back-btn' onTap={() => Taro.navigateBack()}>
<Text className='back-arrow'></Text>
</View>
<Text className='nav-title'></Text>
<View className='nav-placeholder' />
</View>
</View>
@@ -142,11 +145,11 @@ export default function AddressPage() {
<View className='safe-bottom-placeholder' />
{/* 底部添加按钮 */}
<View className='action-bar'>
<BottomActionBar>
<View className='btn-primary' onTap={openAdd}>
<Text></Text>
</View>
</View>
</BottomActionBar>
{/* 新增/编辑弹窗 */}
{showForm && (
+35 -18
View File
@@ -1,35 +1,52 @@
.agreement-page {
padding: 0 32px 32px;
}
/* ============================================================
Agreement Page — 定制协议
============================================================ */
.agreement-title {
font-size: 40px;
font-weight: 800;
color: var(--text-primary);
display: block;
margin-bottom: 32px;
.agreement-page {
padding: 0 32rpx calc(24rpx + env(safe-area-inset-bottom));
min-height: 100vh;
box-sizing: border-box;
}
.agreement-content {
padding: 40px 0;
padding: 32rpx 0 48rpx;
line-height: 1.8;
}
.agreement-title {
display: block;
font-size: 44rpx;
font-weight: 700;
line-height: 1.2;
color: var(--text-primary);
margin-bottom: 32rpx;
letter-spacing: 0;
}
.agreement-section {
margin-bottom: 32px;
display: block;
margin-bottom: 24rpx;
padding: 32rpx;
}
.agreement-section:last-child {
margin-bottom: 0;
}
.agreement-h3 {
font-size: 32px;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 16px;
font-size: 32rpx;
font-weight: 700;
line-height: 1.3;
color: var(--text-primary);
margin-bottom: 16rpx;
letter-spacing: 0;
}
.agreement-p {
font-size: 28px;
color: var(--text-secondary);
line-height: 1.8;
display: block;
font-size: 28rpx;
line-height: 1.8;
color: var(--text-secondary);
white-space: pre-line;
}
+1 -1
View File
@@ -40,7 +40,7 @@ export default function AgreementPage() {
<View className='agreement-content' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<Text className='agreement-title'></Text>
{SECTIONS.map((sec, idx) => (
<View key={idx} className='agreement-section'>
<View key={idx} className='agreement-section surface-card'>
<Text className='agreement-h3'>{sec.title}</Text>
<Text className='agreement-p'>{sec.content}</Text>
</View>
+167 -65
View File
@@ -1,27 +1,80 @@
/* ============================================================
Checkout Page — 确认下单
============================================================ */
.checkout-page {
padding: 0 24px 24px;
padding: 0 32rpx;
padding-bottom: calc(48rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
}
/* --- Page Header --- */
.page-header {
margin-bottom: 24rpx;
padding: 0;
}
.page-header-inner {
display: flex;
align-items: center;
gap: 16rpx;
min-height: 88rpx;
}
.back-btn {
font-size: 40px;
padding: 10px;
display: flex;
align-items: center;
justify-content: center;
width: 88rpx;
height: 88rpx;
flex: 0 0 auto;
border-radius: 50%;
background: var(--bg-card);
border: 1rpx solid var(--border-strong);
box-shadow: var(--shadow-card);
}
/* 画布展示区 */
.back-btn:active {
transform: scale(0.96);
}
.back-arrow {
font-size: 36rpx;
line-height: 1;
color: var(--text-primary);
}
.nav-title {
flex: 1;
text-align: center;
font-size: 34rpx;
font-weight: 700;
color: var(--text-primary);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.nav-placeholder {
width: 88rpx;
flex: 0 0 auto;
}
/* --- 设计预览 --- */
.checkout-canvas {
display: flex;
align-items: center;
justify-content: center;
padding: 40px;
margin-bottom: 24rpx;
padding: 32rpx;
}
.canvas-area {
position: relative;
overflow: hidden;
background: rgba(0,0,0,0.03);
border: 1rpx solid var(--border-strong);
max-width: 100%;
box-sizing: border-box;
background: var(--bg-input);
border: 1rpx solid var(--border-strong);
}
.checkout-image {
@@ -32,125 +85,153 @@
max-height: 100%;
}
/* 商品信息 */
.checkout-info {
padding: 24px;
/* --- 商品信息 --- */
.checkout-info,
.checkout-address-card {
margin-bottom: 24rpx;
padding: 32rpx;
}
.card-title {
display: block;
margin-bottom: 24rpx;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 0;
}
.info-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px 0;
gap: 24rpx;
padding: 24rpx 0;
border-bottom: 1rpx solid var(--border);
}
.info-row:last-child {
border-bottom: none;
padding-bottom: 0;
}
.info-label {
font-size: 28px;
flex: 0 0 auto;
font-size: 28rpx;
color: var(--text-secondary);
}
.info-value {
font-size: 28px;
color: var(--text-primary);
flex: 1;
text-align: right;
font-size: 28rpx;
font-weight: 500;
color: var(--text-primary);
word-break: break-all;
}
.total-row {
padding-top: 24px;
margin-top: 8px;
padding-top: 24rpx;
margin-top: 8rpx;
}
.info-total {
font-size: 40px;
font-size: 40rpx;
font-weight: 800;
color: var(--accent-primary);
font-variant-numeric: tabular-nums;
}
/* 地址卡片 */
.checkout-address-card {
padding: 24px;
}
/* --- 收货地址 --- */
.checkout-address-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
gap: 24rpx;
margin-bottom: 16rpx;
}
.checkout-address-header .card-title {
margin-bottom: 0;
}
.address-change {
padding: 6px 16px;
border-radius: 8px;
display: flex;
align-items: center;
height: 56rpx;
padding: 0 24rpx;
border-radius: 999rpx;
background: var(--accent-secondary-soft);
}
.change-text {
font-size: 24px;
font-size: 24rpx;
font-weight: 500;
color: var(--accent-secondary);
}
.checkout-address-body {
padding-top: 8px;
padding-top: 8rpx;
}
.addr-row {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 8px;
gap: 16rpx;
margin-bottom: 8rpx;
}
.addr-name {
font-size: 28px;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
}
.addr-phone {
font-size: 26px;
font-size: 24rpx;
color: var(--text-secondary);
}
.addr-detail {
font-size: 26px;
font-size: 26rpx;
color: var(--text-secondary);
line-height: 1.5;
line-height: 1.6;
}
.checkout-address-empty {
padding: 32px 0;
padding: 32rpx 0;
text-align: center;
}
.empty-text {
font-size: 26px;
font-size: 28rpx;
color: var(--text-secondary);
}
/* 底部弹窗 — 地址选择(样式复用 app.scss 全局定义,移除非必要覆写) */
/* --- 地址选择弹层 --- */
.addr-picker-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
margin-bottom: 24rpx;
}
.addr-picker-title {
font-size: 32px;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
}
.addr-picker-close {
font-size: 28px;
display: flex;
align-items: center;
justify-content: center;
width: 64rpx;
height: 64rpx;
border-radius: 50%;
background: var(--bg-muted);
color: var(--text-secondary);
padding: 8px;
font-size: 28rpx;
}
.addr-picker-list {
@@ -159,69 +240,90 @@
}
.addr-picker-item {
padding: 20px 16px;
border-bottom: 1rpx solid var(--border);
padding: 24rpx;
border: 1rpx solid transparent;
border-radius: 16rpx;
transition: background 160ms ease, border-color 160ms ease;
}
.addr-picker-item + .addr-picker-item {
margin-top: 16rpx;
}
.addr-picker-item.active {
background: var(--accent-secondary-soft);
border-radius: 12px;
background: var(--accent-primary-soft);
border-color: var(--accent-primary);
}
.addr-picker-row {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 8px;
gap: 16rpx;
margin-bottom: 8rpx;
}
.addr-picker-name {
font-size: 28px;
font-size: 30rpx;
font-weight: 700;
color: var(--text-primary);
}
.addr-picker-phone {
font-size: 26px;
font-size: 24rpx;
color: var(--text-secondary);
}
.addr-picker-default {
font-size: 22px;
display: inline-flex;
align-items: center;
height: 40rpx;
padding: 0 16rpx;
border-radius: 999rpx;
font-size: 20rpx;
font-weight: 600;
color: var(--accent-primary);
border: 1px solid var(--accent-primary);
padding: 2px 8px;
border-radius: 6px;
background: var(--accent-primary-soft);
}
.addr-picker-detail {
font-size: 26px;
font-size: 26rpx;
color: var(--text-secondary);
line-height: 1.6;
}
.addr-picker-empty {
padding: 40px;
padding: 48rpx 32rpx;
text-align: center;
font-size: 28rpx;
color: var(--text-secondary);
font-size: 28px;
}
.addr-picker-add {
margin-top: 16px;
padding: 20px;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
height: 96rpx;
margin-top: 24rpx;
border: 1rpx solid var(--border-strong);
border-radius: 12px;
border-radius: 999rpx;
background: var(--bg-card);
}
.addr-picker-add-text {
font-size: 28px;
font-size: 28rpx;
font-weight: 600;
color: var(--accent-secondary);
}
/* 底部操作 — 毛玻璃规则由全局 .action-bar 提供 */
.action-bar .btn-secondary,
.action-bar .btn-primary {
/* --- 底部操作栏 --- */
.bottom-action-bar .btn-secondary,
.bottom-action-bar .btn-primary {
display: flex;
align-items: center;
justify-content: center;
flex: 1;
text-align: center;
min-height: 96rpx;
padding: 0;
font-size: 30rpx;
font-weight: 600;
}
+26 -16
View File
@@ -7,6 +7,7 @@ import { useThemeContext } from '../../context/ThemeContext'
import { useSafeArea } from '../../hooks/useSafeArea'
import { useStatusBar } from '../../hooks/useStatusBar'
import ThemedPageMeta from '../../components/ThemedPageMeta'
import BottomActionBar from '../../components/BottomActionBar'
export default function CheckoutPage() {
const { theme, resolvedTheme } = useThemeContext()
@@ -67,8 +68,14 @@ export default function CheckoutPage() {
<View className={`theme-${resolvedTheme}`}>
<ThemedPageMeta />
<View className='checkout-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<Text className='page-title'></Text>
<View className='page-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header-inner'>
<View className='back-btn' onTap={() => Taro.navigateBack()}>
<Text className='back-arrow'></Text>
</View>
<Text className='nav-title'></Text>
<View className='nav-placeholder' />
</View>
</View>
</View>
</View>
@@ -85,20 +92,22 @@ export default function CheckoutPage() {
}
return (
<View className={`theme-${resolvedTheme}`}>
<ThemedPageMeta />
<View className='checkout-page'>
<View className={`theme-${resolvedTheme}`}>
<ThemedPageMeta />
<View className='checkout-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='flex-between' style={{ width: '100%' }}>
<Text className='back-btn' onTap={() => Taro.navigateBack()}></Text>
<Text className='page-title'></Text>
<View style={{ width: '60px' }} />
<View className='page-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header-inner'>
<View className='back-btn' onTap={() => Taro.navigateBack()}>
<Text className='back-arrow'></Text>
</View>
<Text className='nav-title'></Text>
<View className='nav-placeholder' />
</View>
</View>
{/* 效果展示区 */}
<View className='checkout-canvas surface-card mt-20'>
<View className='checkout-canvas surface-card'>
<View className='canvas-area' style={maskStyle}>
{hasStickers ? (
design.designData.stickers.map((s: any) => (
@@ -128,7 +137,8 @@ export default function CheckoutPage() {
</View>
{/* 商品信息 */}
<View className='checkout-info surface-card mt-20'>
<View className='checkout-info surface-card'>
<Text className='card-title'></Text>
<View className='info-row'>
<Text className='info-label'></Text>
<Text className='info-value'>{design.productName}</Text>
@@ -148,9 +158,9 @@ export default function CheckoutPage() {
</View>
{/* 收货地址 */}
<View className='checkout-address-card surface-card mt-20'>
<View className='checkout-address-card surface-card'>
<View className='checkout-address-header'>
<Text className='info-label'></Text>
<Text className='card-title'></Text>
<View className='address-change' onTap={() => setShowAddrPicker(true)}>
<Text className='change-text'></Text>
</View>
@@ -173,14 +183,14 @@ export default function CheckoutPage() {
</View>
{/* 底部操作 */}
<View className='action-bar'>
<BottomActionBar>
<View className='btn-secondary' onTap={() => Taro.navigateBack()}>
<Text></Text>
</View>
<View className='btn-primary' onTap={handleConfirm}>
<Text></Text>
</View>
</View>
</BottomActionBar>
<View className='safe-bottom-placeholder' />
+131 -71
View File
@@ -1,76 +1,95 @@
.design-page {
padding: 0 24px 24px;
padding: 0 32rpx 24rpx;
min-height: 100vh;
}
.manage-btn {
font-size: 28px;
color: var(--accent-secondary);
font-weight: 500;
.page-header.design-header {
display: flex;
align-items: center;
min-height: 88rpx;
padding-bottom: 16rpx;
}
/* 状态 Tab */
.header-spacer {
width: 88rpx;
height: 88rpx;
flex-shrink: 0;
}
.header-title {
flex: 1;
text-align: center;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
}
.header-manage {
width: 88rpx;
text-align: center;
font-size: 28rpx;
font-weight: 500;
color: var(--accent-secondary);
}
/* 状态筛选 chip-row */
.status-tabs {
margin: 20px 0;
background: var(--bg-card);
border: 1rpx solid var(--border);
border-radius: 16px;
padding: 8px 0;
margin: 8rpx 0 24rpx;
}
.tabs-scroll {
white-space: nowrap;
}
.tab-item {
display: inline-block;
padding: 20px 32px;
position: relative;
}
.tab-label {
font-size: 28px;
.chip {
display: inline-flex;
align-items: center;
justify-content: center;
height: 64rpx;
padding: 0 32rpx;
margin-right: 16rpx;
border-radius: 999rpx;
background: var(--bg-card);
border: 1rpx solid var(--border);
color: var(--text-secondary);
font-size: 26rpx;
font-weight: 500;
}
.tab-item.active .tab-label {
color: var(--accent-primary);
font-weight: 700;
.chip.active {
background: var(--accent-primary);
border-color: var(--accent-primary);
color: var(--bg-page);
font-weight: 600;
}
.tab-underline {
position: absolute;
bottom: 8px;
left: 50%;
transform: translateX(-50%);
width: 40px;
height: 4px;
background: var(--accent-primary);
border-radius: 2px;
.chip .tab-label {
color: inherit;
}
/* 批量管理工具栏 */
.batch-bar {
padding: 20px 24px;
margin-bottom: 16px;
display: flex;
align-items: center;
margin-bottom: 24rpx;
padding: 24rpx;
background: var(--bg-card);
border-radius: 24rpx;
box-shadow: var(--shadow-card);
}
.batch-select-all {
display: flex;
align-items: center;
gap: 16px;
}
.batch-checkbox {
width: 36px;
height: 36px;
width: 40rpx;
height: 40rpx;
border-radius: 50%;
border: 2rpx solid var(--border-strong);
flex-shrink: 0;
transition: all 0.2s;
transition: background 160ms ease, border-color 160ms ease;
}
.batch-checkbox.checked {
@@ -79,14 +98,15 @@
}
.batch-text {
font-size: 26px;
margin-left: 16rpx;
font-size: 26rpx;
color: var(--text-primary);
}
.batch-delete {
font-size: 26px;
font-size: 26rpx;
color: var(--text-secondary);
padding: 10px 24px;
padding: 12rpx 24rpx;
}
.batch-delete.active {
@@ -94,15 +114,19 @@
font-weight: 600;
}
/* 设计卡片列表 */
/* 设计清单 detail-card */
.design-list {
padding-bottom: 24px;
padding-bottom: 24rpx;
}
.design-card {
margin-bottom: 20px;
padding: 28px;
transition: all 0.2s ease;
margin-bottom: 24rpx;
padding: 24rpx;
background: var(--bg-card);
border: 1rpx solid transparent;
border-radius: 24rpx;
box-shadow: var(--shadow-card);
transition: background 160ms ease, border-color 160ms ease;
}
.design-card.selected {
@@ -112,48 +136,65 @@
.design-body {
display: flex;
align-items: flex-start;
gap: 20px;
margin-bottom: 20px;
}
.design-icon {
font-size: 56px;
flex-shrink: 0;
align-items: center;
gap: 20rpx;
}
.design-icon-img {
width: 56px;
height: 56px;
width: 48rpx;
height: 48rpx;
flex-shrink: 0;
border-radius: 12rpx;
background: var(--bg-input);
}
.design-info {
flex: 1;
min-width: 0;
}
.design-title-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
gap: 16rpx;
margin-bottom: 8rpx;
}
.design-name {
font-size: 32px;
flex: 1;
min-width: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 30rpx;
font-weight: 700;
color: var(--text-primary);
}
.design-card .badge {
display: inline-flex;
align-items: center;
justify-content: center;
height: 40rpx;
padding: 0 16rpx;
border-radius: 999rpx;
font-size: 22rpx;
font-weight: 600;
line-height: 1;
flex-shrink: 0;
}
.design-meta {
font-size: 24px;
color: var(--text-secondary);
display: block;
margin-bottom: 8px;
font-size: 24rpx;
color: var(--text-secondary);
margin-bottom: 4rpx;
}
.design-total {
font-size: 26px;
display: block;
font-size: 24rpx;
font-weight: 600;
color: var(--accent-primary);
}
@@ -161,11 +202,18 @@
.design-actions {
display: flex;
justify-content: flex-end;
margin-top: 24rpx;
}
.design-btn {
padding: 16px 40px;
font-size: 26px;
display: flex;
align-items: center;
justify-content: center;
height: 64rpx;
padding: 0 32rpx;
font-size: 26rpx;
font-weight: 600;
border-radius: 999rpx;
}
/* 空状态 */
@@ -173,25 +221,37 @@
display: flex;
flex-direction: column;
align-items: center;
padding: 100px 40px;
padding: 100rpx 40rpx;
text-align: center;
}
.empty-icon-img {
width: 56px;
height: 56px;
margin-bottom: 24px;
width: 88rpx;
height: 88rpx;
margin-bottom: 24rpx;
}
.empty-text {
font-size: 32px;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 12px;
margin-bottom: 12rpx;
}
.empty-sub {
font-size: 26px;
font-size: 28rpx;
color: var(--text-secondary);
margin-bottom: 32px;
margin-bottom: 32rpx;
}
.empty-state .btn-primary {
display: flex;
align-items: center;
justify-content: center;
min-width: 320rpx;
height: 88rpx;
padding: 0 48rpx;
border-radius: 999rpx;
font-size: 30rpx;
font-weight: 600;
}
+11 -13
View File
@@ -19,6 +19,8 @@ const STATUS_TABS = [
{ code: 'ordered', label: '已下单' }
]
const VISIBLE_STATUS_TABS = STATUS_TABS.filter(tab => tab.code !== 'undesigned')
const STATUS_STYLE: Record<string, { label: string; cls: string }> = {
undesigned: { label: '未设计', cls: 'badge-pink' },
designing: { label: '设计中', cls: 'badge-blue' },
@@ -120,27 +122,24 @@ export default function DesignListPage() {
<ThemedPageMeta />
<LoginGuard>
<View className='design-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='flex-between' style={{ width: '100%' }}>
<Text className='back-btn' onTap={() => Taro.navigateBack()}></Text>
<Text className='page-title'></Text>
<Text className='manage-btn' onTap={handleManage}>
{managing ? '完成' : '管理'}
</Text>
<View className='page-header design-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<View className='header-spacer' />
<Text className='header-title'></Text>
<View className='header-manage' onTap={handleManage}>
<Text>{managing ? '完成' : '管理'}</Text>
</View>
</View>
{/* 状态筛选 */}
<View className='status-tabs'>
<ScrollView className='tabs-scroll' scrollX>
{STATUS_TABS.map(tab => (
{VISIBLE_STATUS_TABS.map(tab => (
<View
key={tab.code}
className={`tab-item ${activeTab === tab.code ? 'active' : ''}`}
className={`chip ${activeTab === tab.code ? 'active' : ''}`}
onTap={() => setActiveTab(tab.code)}
>
<Text className='tab-label'>{tab.label}</Text>
{activeTab === tab.code && <View className='tab-underline' />}
</View>
))}
</ScrollView>
@@ -148,7 +147,7 @@ export default function DesignListPage() {
{/* 批量管理工具栏 */}
{managing && (
<View className='batch-bar surface-card'>
<View className='batch-bar'>
<View className='flex-between' style={{ width: '100%' }}>
<View className='batch-select-all' onTap={toggleSelectAll}>
<View className={`batch-checkbox ${selected.size === filtered.length && filtered.length > 0 ? 'checked' : ''}`} />
@@ -173,7 +172,7 @@ export default function DesignListPage() {
return (
<View
key={item.id}
className={`design-card surface-card ${isSelected ? 'selected' : ''}`}
className={`design-card ${isSelected ? 'selected' : ''}`}
onTap={() => managing ? toggleSelect(item.id) : undefined}
>
<View className='design-body'>
@@ -220,7 +219,6 @@ export default function DesignListPage() {
)}
</ScrollView>
<View style={{ height: '40px' }} />
</View>
</LoginGuard>
</View>
+270 -145
View File
@@ -1,24 +1,91 @@
.diy-page {
padding: 0 24px 24px;
padding: 0 32rpx calc(48rpx + env(safe-area-inset-bottom));
min-height: 100vh;
box-sizing: border-box;
}
/* 顶部标题区 */
.diy-page .page-header {
display: flex;
align-items: center;
margin: 0 0 24rpx;
padding-top: 0;
padding-bottom: 16rpx;
background: transparent;
border: none;
box-shadow: none;
}
.diy-page .page-header.surface-card {
background: transparent;
border: none;
box-shadow: none;
}
.diy-page .page-header .flex-between {
min-height: 88rpx;
}
.back-btn {
display: flex;
align-items: center;
justify-content: center;
width: 80rpx;
height: 80rpx;
flex-shrink: 0;
border-radius: 50%;
background: var(--bg-card);
border: 1rpx solid var(--border-strong);
box-shadow: var(--shadow-card);
font-size: 36rpx;
line-height: 1;
color: var(--text-primary);
}
.back-btn:active {
transform: scale(0.96);
}
.diy-page .page-title {
flex: 1;
min-width: 0;
padding: 0 16rpx;
text-align: center;
font-size: 34rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 0;
line-height: 1.2;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.header-spacer {
width: 80rpx;
height: 80rpx;
flex-shrink: 0;
}
/* 画布区域 */
.canvas-wrapper {
padding: 40px;
padding: 24rpx;
display: flex;
justify-content: center;
align-items: center;
border-radius: 24rpx;
}
.canvas-area {
position: relative;
background: var(--bg-input);
overflow: hidden;
border-radius: 16px;
min-width: 200px;
min-height: 200px;
border-radius: 24rpx;
min-width: 300rpx;
min-height: 400rpx;
max-width: 100%;
box-sizing: border-box;
box-shadow: inset 0 0 0 1rpx var(--border-strong);
}
.mask-border {
@@ -37,46 +104,59 @@
max-width: 100%;
max-height: 100%;
z-index: 5;
border: 2px solid transparent;
border: 2rpx solid transparent;
border-radius: 8rpx;
}
.canvas-image.active {
border-color: var(--accent-primary);
box-shadow: 0 0 0 8rpx var(--accent-primary-soft);
}
.canvas-image.overlap {
border-color: var(--danger);
box-shadow: 0 0 12px var(--danger-soft);
box-shadow: 0 0 0 8rpx var(--danger-soft);
}
/* 贴纸面板 */
.sticker-panel {
padding: 28px;
padding: 24rpx;
}
.sticker-panel .section-title {
display: block;
margin-bottom: 20rpx;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 0;
}
.sticker-list {
display: flex;
flex-wrap: wrap;
gap: 16px;
gap: 16rpx;
}
.sticker-thumb {
position: relative;
width: 120px;
height: 120px;
width: 164rpx;
height: 164rpx;
border: 1rpx solid var(--border);
border-radius: 12px;
border-radius: 20rpx;
overflow: hidden;
background: var(--bg-input);
box-shadow: var(--shadow-card);
}
.sticker-thumb.active {
border-color: var(--accent-primary);
border-width: 2rpx;
box-shadow: 0 0 0 6rpx var(--accent-primary-soft);
}
.sticker-thumb.overlap {
border-color: var(--danger);
box-shadow: 0 0 0 6rpx var(--danger-soft);
}
.sticker-thumb-img {
@@ -86,52 +166,59 @@
.sticker-del {
position: absolute;
top: 4px;
right: 4px;
width: 36px;
height: 36px;
top: 8rpx;
right: 8rpx;
width: 44rpx;
height: 44rpx;
background: var(--danger);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
z-index: 10;
box-shadow: var(--shadow-card);
}
.del-icon {
color: #fff;
font-size: 24px;
font-size: 28rpx;
font-weight: 700;
line-height: 1;
}
.sticker-add-btn {
width: 120px;
height: 120px;
border: 1rpx solid var(--border);
border-radius: 12px;
width: 164rpx;
height: 164rpx;
border: 1rpx solid var(--border-strong);
border-radius: 20rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: var(--bg-input);
background: var(--bg-muted);
}
.sticker-add-btn:active {
transform: scale(0.97);
}
.add-icon {
font-size: 48px;
font-size: 44rpx;
color: var(--accent-primary);
line-height: 1;
font-weight: 600;
}
.add-label {
font-size: 22px;
font-size: 22rpx;
color: var(--text-secondary);
margin-top: 8px;
margin-top: 8rpx;
}
.overlap-hint {
display: block;
margin-top: 16px;
font-size: 26px;
margin-top: 16rpx;
font-size: 24rpx;
color: var(--danger);
font-weight: 600;
text-align: center;
@@ -139,153 +226,78 @@
/* 工具栏 */
.toolbar {
padding: 28px 32px;
padding: 24rpx;
}
.tool-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
gap: 16rpx;
padding: 8rpx 0;
}
.tool-row:last-child {
margin-bottom: 0;
.tool-row + .tool-row {
border-top: 1rpx solid var(--border);
margin-top: 8rpx;
padding-top: 16rpx;
}
.tool-label {
font-size: 28px;
font-size: 26rpx;
font-weight: 600;
color: var(--text-primary);
}
.tool-btn {
width: 56px;
height: 56px;
width: 64rpx;
height: 64rpx;
background: var(--bg-input);
border: 1rpx solid var(--border-strong);
border-radius: 50%;
border: 1rpx solid var(--border);
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32px;
font-size: 32rpx;
color: var(--text-primary);
font-weight: 700;
font-weight: 600;
}
.tool-btn:active {
transform: scale(0.96);
background: var(--bg-muted);
}
.tool-value {
font-size: 28px;
font-size: 26rpx;
font-weight: 600;
color: var(--accent-primary);
min-width: 80px;
min-width: 88rpx;
text-align: center;
font-variant-numeric: tabular-nums;
}
.tool-hint {
font-size: 24px;
font-size: 24rpx;
color: var(--text-secondary);
}
/* 预览弹窗 */
.preview-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
padding: 40px;
}
.preview-card {
background: var(--bg-card);
width: 100%;
max-height: 80vh;
overflow-y: auto;
padding: 40px;
}
.preview-title {
font-size: 36px;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 24px;
text-align: center;
}
.preview-canvas {
background: var(--bg-input);
border-radius: 16px;
overflow: hidden;
margin: 0 auto 24px;
border: 1rpx solid var(--border-strong);
position: relative;
min-width: 200px;
min-height: 200px;
max-width: 100%;
box-sizing: border-box;
}
.preview-image {
position: absolute;
max-width: 100%;
max-height: 100%;
z-index: 5;
}
.preview-image.overlap {
border: 2px solid var(--danger);
}
.product-info {
text-align: center;
margin-bottom: 32px;
}
.product-name {
font-size: 30px;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 8px;
}
.product-size {
font-size: 24px;
color: var(--text-secondary);
}
.preview-actions {
display: flex;
gap: 20px;
}
.preview-actions .btn-secondary,
.preview-actions .btn-primary {
flex: 1;
text-align: center;
}
.preview-actions .btn-primary.disabled {
opacity: 0.5;
pointer-events: none;
}
/* 常驻编辑按钮 */
.edit-btn-bar {
display: flex;
justify-content: flex-end;
margin-top: 24rpx;
}
.edit-btn {
padding: 16px 48px;
border-radius: 50px;
font-size: 28px;
display: flex;
align-items: center;
justify-content: center;
min-width: 176rpx;
height: 88rpx;
padding: 0 40rpx;
border-radius: 999rpx;
font-size: 28rpx;
font-weight: 600;
text-align: center;
background: var(--bg-input);
@@ -301,19 +313,132 @@
}
.edit-btn.disabled {
opacity: 0.45;
pointer-events: none;
}
/* 底部操作栏 — 毛玻璃由 BottomActionBar 提供 */
.bottom-action-bar .btn-primary,
.bottom-action-bar .btn-secondary {
flex: 1;
text-align: center;
padding: 28rpx 0;
font-size: 28rpx;
font-weight: 600;
line-height: 1.2;
}
/* 预览弹层 */
.preview-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.45);
display: flex;
align-items: flex-end;
justify-content: center;
z-index: 1000;
}
.preview-card {
width: 100%;
max-height: 88vh;
overflow-y: auto;
padding: 40rpx 32rpx calc(32rpx + env(safe-area-inset-bottom));
background: var(--bg-card);
border-radius: 32rpx 32rpx 0 0;
border: 1rpx solid var(--border);
box-shadow: var(--shadow-elevated);
box-sizing: border-box;
}
.preview-card::before {
content: '';
display: block;
width: 64rpx;
height: 8rpx;
margin: 0 auto 32rpx;
border-radius: 999rpx;
background: var(--bg-muted);
}
.preview-title {
font-size: 34rpx;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 24rpx;
text-align: center;
letter-spacing: 0;
}
.preview-canvas {
background: var(--bg-input);
border-radius: 24rpx;
overflow: hidden;
margin: 0 auto 24rpx;
border: 1rpx solid var(--border-strong);
position: relative;
min-width: 300rpx;
min-height: 400rpx;
max-width: 100%;
box-sizing: border-box;
}
.preview-image {
position: absolute;
max-width: 100%;
max-height: 100%;
z-index: 5;
}
.preview-image.overlap {
border: 2rpx solid var(--danger);
border-radius: 8rpx;
}
.product-info {
text-align: center;
margin-bottom: 28rpx;
}
.product-name {
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 8rpx;
letter-spacing: 0;
}
.product-size {
font-size: 24rpx;
color: var(--text-secondary);
}
.preview-actions {
display: flex;
gap: 16rpx;
}
.preview-actions .btn-secondary,
.preview-actions .btn-primary {
flex: 1;
text-align: center;
padding: 28rpx 0;
font-size: 28rpx;
font-weight: 600;
line-height: 1.2;
}
.preview-actions .btn-primary.disabled {
opacity: 0.5;
pointer-events: none;
}
/* 底部操作栏 — 毛玻璃规则由全局 .action-bar 提供 */
.action-bar .btn-primary,
.action-bar .btn-secondary {
flex: 1;
text-align: center;
padding: 24px 0;
font-size: 28px;
}
/* 局部间距 */
.mt-20 {
margin-top: 20px;
margin-top: 24rpx;
}
+5 -4
View File
@@ -8,6 +8,7 @@ import { useThemeContext } from '../../context/ThemeContext'
import { useSafeArea } from '../../hooks/useSafeArea'
import { useStatusBar } from '../../hooks/useStatusBar'
import ThemedPageMeta from '../../components/ThemedPageMeta'
import BottomActionBar from '../../components/BottomActionBar'
export default function DIYPage() {
const { theme, resolvedTheme } = useThemeContext()
@@ -275,11 +276,11 @@ export default function DIYPage() {
<ThemedPageMeta />
<View className='diy-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header surface-card mt-20' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<View className='flex-between' style={{ width: '100%' }}>
<Text className='back-btn' onTap={goBack}></Text>
<Text className='page-title'></Text>
<View style={{ width: '60px' }} />
<View className='header-spacer' />
</View>
</View>
@@ -358,14 +359,14 @@ export default function DIYPage() {
</View>
{/* 底部操作按钮 */}
<View className='action-bar'>
<BottomActionBar>
<View className='btn-primary' onTap={() => setPreviewMode(true)}>
<Text></Text>
</View>
<View className='btn-secondary' onTap={addSticker}>
<Text></Text>
</View>
</View>
</BottomActionBar>
{/* 预览弹层 */}
{previewMode && (
+126 -76
View File
@@ -1,37 +1,65 @@
.sticker-edit-page {
padding: 0 24px 24px;
padding: 0 32rpx calc(48rpx + env(safe-area-inset-bottom));
min-height: 100vh;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
/* 顶部导航 */
.edit-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: calc(env(safe-area-inset-top, 0px) + 24px) 0 24px;
gap: 16rpx;
padding-bottom: 24rpx;
}
.edit-back {
font-size: 36px;
display: flex;
align-items: center;
justify-content: center;
width: 80rpx;
height: 80rpx;
flex-shrink: 0;
border-radius: 50%;
background: var(--bg-card);
border: 1rpx solid var(--border-strong);
box-shadow: var(--shadow-card);
font-size: 36rpx;
line-height: 1;
color: var(--text-primary);
width: 60px;
}
.edit-back:active {
transform: scale(0.96);
}
.edit-title {
font-size: 34px;
flex: 1;
min-width: 0;
text-align: center;
font-size: 34rpx;
font-weight: 700;
color: var(--text-primary);
text-align: center;
flex: 1;
letter-spacing: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.edit-save {
font-size: 28px;
color: var(--accent-primary);
display: flex;
align-items: center;
justify-content: flex-end;
min-width: 80rpx;
font-size: 26rpx;
font-weight: 600;
width: 60px;
text-align: right;
color: var(--accent-primary);
}
.edit-save:active {
opacity: 0.85;
}
/* 画布区域 */
@@ -40,27 +68,30 @@
display: flex;
align-items: center;
justify-content: center;
padding: 20px 0;
min-height: 400px;
padding: 8rpx 0 24rpx;
min-height: 480rpx;
}
.edit-canvas {
width: 100%;
height: 500px;
height: 480rpx;
background: var(--bg-input);
border-radius: 16px;
border-radius: 24rpx;
border: 1rpx solid var(--border-strong);
box-shadow: var(--shadow-card);
}
/* 工具面板 */
.edit-tools {
padding: 32px;
padding: 24rpx;
}
.edit-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 32px;
gap: 24rpx;
margin-bottom: 24rpx;
}
.edit-row:last-child {
@@ -68,76 +99,36 @@
}
.edit-label {
font-size: 28px;
font-weight: 500;
font-size: 26rpx;
font-weight: 600;
color: var(--text-primary);
width: 120px;
width: 96rpx;
flex-shrink: 0;
}
.slider-wrap {
flex: 1;
display: flex;
align-items: center;
gap: 16px;
}
.slider-track {
flex: 1;
height: 8px;
border-radius: 4px;
background: var(--bg-input);
position: relative;
}
.slider-fill {
height: 100%;
border-radius: 4px;
background: linear-gradient(90deg, var(--accent-primary), var(--accent-primary-soft));
position: absolute;
left: 0;
top: 0;
}
.slider-thumb {
width: 32px;
height: 32px;
border-radius: 50%;
background: #fff;
border: 4px solid var(--accent-primary);
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}
.slider-value {
font-size: 24px;
color: var(--text-secondary);
min-width: 60px;
text-align: right;
}
/* 快速操作按钮 */
.edit-quick-actions {
display: flex;
gap: 16px;
gap: 16rpx;
flex-wrap: wrap;
}
.quick-btn {
padding: 16px 28px;
border-radius: 40px;
font-size: 24px;
display: flex;
align-items: center;
justify-content: center;
height: 64rpx;
padding: 0 28rpx;
border-radius: 999rpx;
font-size: 24rpx;
font-weight: 500;
background: var(--bg-input);
color: var(--text-primary);
border: 1rpx solid var(--border);
transition: all 0.2s;
transition: all 0.2s ease;
}
.quick-btn:active {
opacity: 0.8;
opacity: 0.85;
transform: scale(0.97);
}
@@ -147,13 +138,67 @@
color: var(--accent-primary);
}
/* 底部操作栏 — 毛玻璃规则由全局 .action-bar 提供 */
/* 滑块 */
.slider-wrap {
flex: 1;
display: flex;
align-items: center;
gap: 12rpx;
min-width: 0;
}
.slider-track {
flex: 1;
height: 8rpx;
border-radius: 999rpx;
background: var(--bg-input);
border: 1rpx solid var(--border);
position: relative;
min-width: 0;
}
.slider-fill {
height: 100%;
border-radius: 999rpx;
background: linear-gradient(90deg, var(--accent-primary), var(--accent-primary-soft));
position: absolute;
left: 0;
top: 0;
}
.slider-thumb {
width: 32rpx;
height: 32rpx;
border-radius: 50%;
background: var(--bg-card);
border: 4rpx solid var(--accent-primary);
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
box-shadow: var(--shadow-card);
}
.slider-thumb.dragging {
transform: translate(-50%, -50%) scale(1.12);
}
.slider-value {
font-size: 22rpx;
color: var(--text-secondary);
min-width: 80rpx;
text-align: right;
font-variant-numeric: tabular-nums;
}
/* 底部操作栏 — 毛玻璃由 BottomActionBar 提供 */
.edit-footer .btn-primary,
.edit-footer .btn-secondary {
flex: 1;
text-align: center;
padding: 24px 0;
font-size: 28px;
padding: 28rpx 0;
font-size: 28rpx;
font-weight: 600;
line-height: 1.2;
}
/* 加载遮罩 */
@@ -163,7 +208,7 @@
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.4);
background: rgba(0, 0, 0, 0.45);
z-index: 1000;
display: flex;
align-items: center;
@@ -172,7 +217,12 @@
}
.edit-loading-text {
font-size: 28px;
font-size: 28rpx;
color: #fff;
margin-top: 20px;
margin-top: 20rpx;
}
/* 局部间距 */
.mt-20 {
margin-top: 24rpx;
}
+4 -3
View File
@@ -8,6 +8,7 @@ import { useThemeContext } from '../../../context/ThemeContext'
import { useSafeArea } from '../../../hooks/useSafeArea'
import { useStatusBar } from '../../../hooks/useStatusBar'
import ThemedPageMeta from '../../../components/ThemedPageMeta'
import BottomActionBar from '../../../components/BottomActionBar'
/* ============================================================
使用 Canvas 实现贴纸编辑(亮度/色相/线稿)
@@ -324,7 +325,7 @@ export default function StickerEditPage() {
id='editCanvas'
type='2d'
className='edit-canvas'
style={{ width: '100%', height: '400px' }}
style={{ width: '100%', height: '480rpx' }}
/>
</View>
@@ -415,14 +416,14 @@ export default function StickerEditPage() {
<View style={{ flex: 1 }} />
<View className='action-bar edit-footer'>
<BottomActionBar className='edit-footer'>
<View className='btn-secondary' onTap={() => Taro.navigateBack()}>
<Text></Text>
</View>
<View className='btn-primary' onTap={handleSave}>
<Text></Text>
</View>
</View>
</BottomActionBar>
<View className='safe-bottom-placeholder' />
+157 -146
View File
@@ -1,49 +1,52 @@
.index-page {
padding: 0 24px 24px;
padding: 0 32rpx 24rpx;
box-sizing: border-box;
}
/* 顶部标题栏 */
.header-bar {
padding: 20px 0 16px;
/* 页头 */
.home-header {
display: flex;
align-items: center;
align-items: flex-end;
padding-bottom: 32rpx;
}
.header-title {
font-size: 48px;
.home-title {
font-size: 56rpx;
font-weight: 800;
color: var(--text-primary);
letter-spacing: 4px;
letter-spacing: 0;
line-height: 1.15;
}
/* 搜索框卡片 */
.search-card {
padding: 20px 24px;
}
.search-inner {
/* 搜索框 */
.searchbox {
display: flex;
align-items: center;
height: 88rpx;
padding: 0 24rpx;
border-radius: 999rpx;
background: var(--bg-input);
border: 1rpx solid var(--border);
border-radius: 40px;
padding: 16px 24px;
border: 1rpx solid transparent;
transition: border-color 160ms ease, box-shadow 160ms ease, background 160ms ease;
}
.search-icon {
font-size: 28px;
margin-right: 16px;
.searchbox:focus-within {
border-color: var(--accent-primary);
box-shadow: 0 0 0 6rpx var(--accent-primary-soft);
background: var(--bg-card);
}
.search-icon-img {
width: 28px;
height: 28px;
margin-right: 16px;
width: 36rpx;
height: 36rpx;
margin-right: 12rpx;
flex-shrink: 0;
}
.search-input {
flex: 1;
font-size: 28px;
height: 88rpx;
font-size: 28rpx;
color: var(--text-primary);
background: transparent;
border: none;
@@ -51,163 +54,173 @@
}
.search-input::placeholder {
color: var(--text-secondary);
font-size: 26px;
color: var(--text-muted);
font-size: 26rpx;
}
.search-result-hint {
margin-top: 16px;
padding-top: 16px;
border-top: 1rpx solid var(--border);
margin: 16rpx 8rpx 0;
font-size: 24rpx;
color: var(--text-secondary);
}
.hint-text {
font-size: 24px;
color: var(--text-secondary);
display: block;
}
/* 成品展示轮播 */
.showcase-section {
margin-top: 20px;
/* 区块标题 */
.home-section-title {
display: block;
margin: 48rpx 0 24rpx;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 0;
}
/* 定制成品 hero 轮播 */
.showcase-swiper {
height: 520rpx;
width: 100%;
height: 360rpx;
}
.showcase-swiper-item {
display: flex;
align-items: center;
justify-content: center;
padding: 0 10rpx;
box-sizing: border-box;
height: 360rpx;
overflow: hidden;
border-radius: 24rpx;
}
.showcase-swiper-card {
.hero-block {
position: relative;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
border-radius: 24px;
overflow: hidden;
box-shadow: var(--shadow-card);
box-sizing: border-box;
border-radius: 24rpx;
background: linear-gradient(150deg, rgba(217, 108, 106, 0.42), rgba(108, 123, 219, 0.18)), var(--bg-muted);
}
.showcase-image-wrapper {
width: 100%;
height: 320rpx;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
flex-shrink: 0;
position: relative;
}
.showcase-real-img {
width: 100%;
height: 100%;
object-fit: cover;
}
.showcase-text-area {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
background: var(--bg-card);
padding: 16px 20px;
position: relative;
}
.showcase-info .showcase-title {
font-size: 32px;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 8px;
}
.showcase-info .showcase-desc {
font-size: 24px;
color: var(--text-secondary);
display: block;
}
.showcase-tag {
.hero-media {
position: absolute;
top: 16px;
right: 16px;
background: var(--accent-primary);
color: #ffffff;
font-size: 20px;
padding: 4px 16px;
border-radius: 20px;
font-weight: 600;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.glass-overlay {
position: absolute;
left: 24rpx;
bottom: 24rpx;
z-index: 2;
display: flex;
flex-direction: column;
align-items: flex-start;
max-width: 78%;
padding: 16rpx 24rpx;
border-radius: 24rpx;
background: rgba(255, 255, 255, 0.72);
backdrop-filter: blur(24rpx);
-webkit-backdrop-filter: blur(24rpx);
border: 1rpx solid rgba(255, 255, 255, 0.6);
box-shadow: var(--shadow-card);
}
/* 热门品类 */
.category-section {
margin-top: 20px;
.hero-title {
display: block;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 0;
line-height: 1.25;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.category-grid {
.hero-desc {
display: block;
margin-top: 8rpx;
font-size: 24rpx;
color: var(--text-secondary);
letter-spacing: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* 两列 media-card */
.home-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 24rpx;
}
.category-item {
.media-card {
overflow: hidden;
border-radius: 24rpx;
background: var(--bg-card);
border: 1rpx solid var(--border);
box-shadow: var(--shadow-card);
transition: transform 200ms ease;
}
.media-card:active {
transform: scale(0.98);
}
.media-card-image {
position: relative;
aspect-ratio: 1 / 1;
overflow: hidden;
background: var(--bg-muted);
}
.media-card-img {
display: block;
width: 100%;
height: 100%;
}
.media-card-body {
display: flex;
flex-direction: column;
align-items: center;
padding: 20rpx 16rpx 24rpx;
text-align: center;
padding: 0 0 24px;
overflow: hidden;
transition: transform 0.2s;
}
.category-item:active {
transform: scale(0.96);
}
/* 品类顶部实物照片 */
.category-img-wrapper {
.media-card-title {
display: block;
width: 100%;
height: 180rpx;
overflow: hidden;
border-radius: 16px;
margin-bottom: 16px;
position: relative;
}
.category-img-real {
width: 100%;
height: 100%;
object-fit: cover;
}
.category-name {
font-size: 28px;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 28rpx;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 8px;
letter-spacing: 0;
}
.category-desc {
font-size: 22px;
.media-card-desc {
display: block;
width: 100%;
margin-top: 8rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 22rpx;
color: var(--text-secondary);
letter-spacing: 0;
}
.category-price {
font-size: 30px;
.media-card-price {
display: block;
margin-top: 12rpx;
font-size: 28rpx;
font-weight: 700;
color: var(--accent-primary);
margin-top: 8px;
letter-spacing: 0;
font-variant-numeric: tabular-nums;
}
/* 空状态 */
@@ -215,29 +228,27 @@
display: flex;
flex-direction: column;
align-items: center;
padding: 60px 40px;
margin-top: 24rpx;
padding: 48rpx 32rpx;
border-radius: 24rpx;
background: var(--bg-muted);
text-align: center;
}
.empty-icon-img {
width: 48px;
height: 48px;
margin-bottom: 16px;
width: 64rpx;
height: 64rpx;
margin-bottom: 16rpx;
}
.empty-text {
font-size: 30px;
font-size: 30rpx;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 8px;
margin-bottom: 8rpx;
}
.empty-sub {
font-size: 24px;
font-size: 24rpx;
color: var(--text-secondary);
}
/* 底部安全区 */
.safe-bottom-placeholder {
height: 200px;
}
+128 -68
View File
@@ -11,12 +11,48 @@ import ThemedPageMeta from '../../components/ThemedPageMeta'
// 成品展示配图(从 img 里取对应实物图)
const SHOWCASE_LIST = [
{ title: '毕业纪念笔记本', desc: '全班名字组成校徽', image: assetUrl('/img/book_small/The1.jpg') },
{ title: '铜质杯垫', desc: '金属质感桌面艺术', image: assetUrl('/img/cup/The1.jpg') },
{ title: '竹制笔盒', desc: '自然竹纹文房雅器', image: assetUrl('/img/penbox/The1.jpg') },
{ title: '书本型灯', desc: '温暖光影点亮心意', image: assetUrl('/img/booklight/The1.jpg') },
{ title: '情侣定制礼', desc: '两个人的名字交织', image: assetUrl('/img/book_big/The1.jpg') },
{ title: '企业年会礼', desc: '员工名字组成Logo', image: assetUrl('/img/penbox/The2.jpg') }
{
title: '毕业纪念笔记本',
desc: '全班名字组成校徽',
priceText: '¥45 起',
categoryId: 'notebook-large',
image: assetUrl('/img/book_small/The1.jpg')
},
{
title: '铜质杯垫',
desc: '金属质感桌面艺术',
priceText: '¥25 起',
categoryId: 'coaster',
image: assetUrl('/img/cup/The1.jpg')
},
{
title: '竹制笔盒',
desc: '自然竹纹文房雅器',
priceText: '¥75 起',
categoryId: 'penbox',
image: assetUrl('/img/penbox/The1.jpg')
},
{
title: '书本型灯',
desc: '温暖光影点亮心意',
priceText: '¥45 起',
categoryId: 'booklamp',
image: assetUrl('/img/booklight/The1.jpg')
},
{
title: '情侣定制礼',
desc: '两个人的名字交织',
priceText: '¥45 起',
categoryId: 'notebook-large',
image: assetUrl('/img/book_big/The1.jpg')
},
{
title: '企业年会礼',
desc: '员工名字组成Logo',
priceText: '¥75 起',
categoryId: 'penbox',
image: assetUrl('/img/penbox/The2.jpg')
}
]
// 品类对应的实物照片映射(首页卡片顶部大图)
@@ -38,6 +74,17 @@ export default function Index() {
Taro.navigateTo({ url: `/pages/product/index?id=${categoryId}` })
}
const navigateFromShowcase = (item: { categoryId?: string; title: string }) => {
if (item.categoryId) {
navigateToProduct(item.categoryId)
return
}
Taro.showToast({
title: `${item.title}”定制通道即将开放`,
icon: 'none'
})
}
const filteredCategories = searchKey.trim()
? CATEGORIES.filter(
(c) => c.name.includes(searchKey) || c.desc.includes(searchKey)
@@ -53,62 +100,51 @@ export default function Index() {
<ThemedPageMeta />
<View className='index-page'>
{/* 顶部标题栏 */}
<View className='header-bar' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<Text className='header-title'></Text>
{/* 页头 */}
<View className='home-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<Text className='home-title'></Text>
</View>
{/* 搜索 */}
<View className='search-card surface-card'>
<View className='search-inner'>
<Image className='search-icon-img' src={assetUrl('/icon/搜索.svg')} mode='aspectFit' />
<Input
className='search-input'
type='text'
placeholder='搜索定制品类:笔记本、杯垫、书灯...'
value={searchKey}
onInput={handleSearch}
confirmType='search'
/>
{/* 搜索 */}
<View className='searchbox'>
<Image className='search-icon-img' src={assetUrl('/icon/搜索.svg')} mode='aspectFit' />
<Input
className='search-input'
type='text'
placeholder='搜索定制品类:笔记本、杯垫、书灯...'
value={searchKey}
onInput={handleSearch}
confirmType='search'
/>
</View>
{searchKey.trim() && (
<View className='search-result-hint'>
<Text className='hint-text'>
{filteredCategories.length > 0
? `找到 ${filteredCategories.length} 个相关品类`
: '没有找到相关品类,试试看其他关键词'}
</Text>
</View>
{searchKey.trim() && (
<View className='search-result-hint'>
<Text className='hint-text'>
{filteredCategories.length > 0
? `找到 ${filteredCategories.length} 个相关品类`
: '没有找到相关品类,试试看其他关键词'}
</Text>
</View>
)}
</View>
)}
{/* 成品展示轮播 */}
<View className='showcase-section mt-20'>
<Text className='section-title'></Text>
{/* 定制成品展示 */}
<View className='showcase-section'>
<Text className='home-section-title'></Text>
<Swiper
className='showcase-swiper'
indicatorColor='#e0d5c8'
indicatorActiveColor='#d96c6a'
circular
autoplay
interval={3000}
duration={500}
previousMargin='40rpx'
nextMargin='40rpx'
indicatorDots
>
{SHOWCASE_LIST.map((item, idx) => (
<SwiperItem key={idx} className='showcase-swiper-item'>
<View className='showcase-swiper-card surface-card'>
<View className='showcase-image-wrapper'>
<Image className='showcase-real-img' src={item.image} mode='aspectFill' />
</View>
<View className='showcase-text-area'>
<View className='showcase-info'>
<Text className='showcase-title'>{item.title}</Text>
<Text className='showcase-desc'>{item.desc}</Text>
</View>
<View className='showcase-tag'></View>
<View className='hero-block'>
<Image className='hero-media' src={item.image} mode='aspectFill' />
<View className='glass-overlay'>
<Text className='hero-title'>{item.title}</Text>
<Text className='hero-desc'>{item.desc}</Text>
</View>
</View>
</SwiperItem>
@@ -117,30 +153,32 @@ export default function Index() {
</View>
{/* 热门品类 */}
<View className='category-section mt-20'>
<Text className='section-title'></Text>
<View className='category-grid'>
<View className='category-section'>
<Text className='home-section-title'></Text>
<View className='home-grid'>
{filteredCategories.map((cat) => (
<View
key={cat.id}
className='category-item surface-card'
onTap={() => navigateToProduct(cat.id)}
>
<View className='category-img-wrapper'>
<Image
className='category-img-real'
src={PRODUCT_IMG_MAP[cat.id] || assetUrl('/icon/四角星.svg')}
mode='aspectFill'
/>
</View>
<Text className='category-name'>{cat.name}</Text>
<Text className='category-desc'>{cat.desc}</Text>
<Text className='category-price'>¥{cat.price} </Text>
<View
key={cat.id}
className='media-card'
onTap={() => navigateToProduct(cat.id)}
>
<View className='media-card-image'>
<Image
className='media-card-img'
src={PRODUCT_IMG_MAP[cat.id] || assetUrl('/icon/四角星.svg')}
mode='aspectFill'
/>
</View>
<View className='media-card-body'>
<Text className='media-card-title'>{cat.name}</Text>
<Text className='media-card-desc'>{cat.desc}</Text>
<Text className='media-card-price'>¥{cat.price} </Text>
</View>
</View>
))}
</View>
{filteredCategories.length === 0 && (
<View className='empty-category surface-card'>
<View className='empty-category'>
<Image className='empty-icon-img' src={assetUrl('/icon/搜索.svg')} mode='aspectFit' />
<Text className='empty-text'></Text>
<Text className='empty-sub'></Text>
@@ -148,7 +186,29 @@ export default function Index() {
)}
</View>
<View className='safe-bottom-placeholder' />
{/* 为你推荐 */}
<View className='recommend-section'>
<Text className='home-section-title'></Text>
<View className='home-grid'>
{SHOWCASE_LIST.slice(0, 4).map((item, idx) => (
<View
key={idx}
className='media-card'
onTap={() => navigateFromShowcase(item)}
>
<View className='media-card-image'>
<Image className='media-card-img' src={item.image} mode='aspectFill' />
</View>
<View className='media-card-body'>
<Text className='media-card-title'>{item.title}</Text>
<Text className='media-card-desc'>{item.desc}</Text>
<Text className='media-card-price'>{item.priceText}</Text>
</View>
</View>
))}
</View>
</View>
</View>
</View>
)
+324 -329
View File
@@ -1,56 +1,148 @@
/* ============================================================
Order Detail Page — 订单详情
============================================================ */
.order-detail-page {
padding: 0 24px 24px;
min-height: 100vh;
padding: 0 32rpx;
padding-bottom: calc(64rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
}
/* 返回按钮 */
.back-btn {
font-size: 40px;
padding: 10px;
/* --- Page Header --- */
.page-header {
margin-bottom: 24rpx;
padding: 0;
}
/* 状态卡片 */
.status-card {
padding: 32px;
}
.status-top {
.page-header-inner {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 32px;
gap: 16rpx;
min-height: 88rpx;
}
.status-badge {
font-size: 26px;
.back-btn {
display: flex;
align-items: center;
justify-content: center;
width: 88rpx;
height: 88rpx;
flex: 0 0 auto;
border-radius: 50%;
background: var(--bg-card);
border: 1rpx solid var(--border-strong);
box-shadow: var(--shadow-card);
}
.back-btn:active {
transform: scale(0.96);
}
.back-arrow {
font-size: 36rpx;
line-height: 1;
color: var(--text-primary);
}
.nav-title {
flex: 1;
text-align: center;
font-size: 34rpx;
font-weight: 700;
color: var(--text-primary);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.nav-placeholder {
width: 88rpx;
flex: 0 0 auto;
}
/* --- 状态横幅 --- */
.status-banner {
margin-bottom: 24rpx;
padding: 32rpx;
background: var(--accent-primary-soft);
border-color: transparent;
}
.status-text {
display: block;
font-size: 40rpx;
font-weight: 800;
color: var(--accent-primary);
letter-spacing: 0;
}
.status-desc {
font-size: 26px;
display: block;
margin-top: 8rpx;
font-size: 26rpx;
color: var(--text-secondary);
}
/* 物流时间轴 */
.logistics-timeline {
position: relative;
padding-left: 20px;
/* --- 通用卡片 --- */
.detail-card {
margin-bottom: 24rpx;
padding: 32rpx;
}
.logistics-timeline::before {
.card-icon-img {
width: 40rpx;
height: 40rpx;
margin-right: 12rpx;
}
/* --- 物流信息 --- */
.logistics-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16rpx;
padding-bottom: 24rpx;
margin-bottom: 24rpx;
border-bottom: 1rpx solid var(--border);
}
.logistics-header .flex-center {
display: flex;
align-items: center;
min-width: 0;
}
.logistics-title {
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
}
.logistics-num {
flex: 0 0 auto;
font-size: 22rpx;
color: var(--text-secondary);
}
.timeline {
position: relative;
padding-left: 20rpx;
}
.timeline::before {
content: '';
position: absolute;
left: 8px;
top: 8px;
bottom: 8px;
width: 2px;
left: 8rpx;
top: 12rpx;
bottom: 12rpx;
width: 2rpx;
background: var(--border);
opacity: 0.3;
opacity: 0.5;
}
.timeline-item {
display: flex;
align-items: flex-start;
margin-bottom: 24px;
margin-bottom: 32rpx;
position: relative;
}
@@ -59,14 +151,14 @@
}
.timeline-dot {
width: 18px;
height: 18px;
width: 20rpx;
height: 20rpx;
border-radius: 50%;
background: var(--bg-card);
border: 2rpx solid var(--border-strong);
margin-right: 20px;
margin-right: 24rpx;
margin-left: -30rpx;
flex-shrink: 0;
margin-left: -20px;
z-index: 2;
}
@@ -77,101 +169,236 @@
.timeline-content {
flex: 1;
min-width: 0;
}
.timeline-title {
font-size: 28px;
color: var(--text-primary);
.timeline-status {
display: block;
margin-bottom: 6px;
margin-bottom: 8rpx;
font-size: 30rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 0;
}
.timeline-time {
font-size: 24px;
display: block;
margin-bottom: 8rpx;
font-size: 22rpx;
color: var(--text-secondary);
}
/* 地址卡片 */
.address-card {
padding: 32px;
.timeline-desc {
display: block;
font-size: 26rpx;
color: var(--text-secondary);
line-height: 1.6;
}
/* --- 商品信息 --- */
.product-row {
display: flex;
align-items: center;
gap: 24rpx;
padding-bottom: 24rpx;
border-bottom: 1rpx solid var(--border);
}
.product-icon-wrapper {
display: flex;
align-items: center;
justify-content: center;
width: 88rpx;
height: 88rpx;
flex: 0 0 auto;
border-radius: 16rpx;
background: var(--bg-input);
overflow: hidden;
}
.product-icon-img {
width: 52rpx;
height: 52rpx;
}
.product-info {
flex: 1;
min-width: 0;
}
.product-name {
display: block;
margin-bottom: 8rpx;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
line-height: 1.3;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.product-sku {
display: block;
font-size: 24rpx;
color: var(--text-secondary);
}
.price-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 24rpx;
padding-top: 24rpx;
}
.price-label {
font-size: 28rpx;
color: var(--text-secondary);
}
.price-value {
font-size: 32rpx;
font-weight: 700;
color: var(--accent-primary);
font-variant-numeric: tabular-nums;
}
/* --- 收货地址 --- */
.address-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
gap: 16rpx;
margin-bottom: 16rpx;
}
.address-header .flex-center {
display: flex;
align-items: center;
flex: 1;
min-width: 0;
}
.address-title {
font-size: 30px;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
}
.address-change {
padding: 6px 16px;
border-radius: 8px;
display: flex;
align-items: center;
height: 56rpx;
padding: 0 24rpx;
border-radius: 999rpx;
background: var(--accent-secondary-soft);
}
.change-text {
font-size: 24px;
font-size: 24rpx;
font-weight: 500;
color: var(--accent-secondary);
}
.address-body {
padding-top: 8px;
padding-top: 8rpx;
}
.address-row {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 8px;
gap: 16rpx;
margin-bottom: 8rpx;
}
.address-name {
font-size: 28px;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
}
.address-phone {
font-size: 26px;
font-size: 24rpx;
color: var(--text-secondary);
}
.address-detail {
font-size: 26px;
font-size: 26rpx;
color: var(--text-secondary);
line-height: 1.5;
line-height: 1.6;
}
.address-empty {
padding: 32px 0;
padding: 32rpx 0;
text-align: center;
font-size: 28rpx;
color: var(--text-secondary);
}
/* 底部弹窗 — 地址选择(样式复用 app.scss 全局定义,移除非必要覆写) */
/* --- 订单信息 --- */
.meta-title {
display: block;
margin-bottom: 8rpx;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 0;
}
.meta-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 24rpx;
padding: 20rpx 0;
border-bottom: 1rpx solid var(--border);
}
.meta-row:last-child {
border-bottom: none;
padding-bottom: 0;
}
.meta-label {
flex: 0 0 auto;
font-size: 26rpx;
color: var(--text-secondary);
}
.meta-value {
flex: 1;
text-align: right;
font-size: 26rpx;
font-weight: 500;
color: var(--text-primary);
word-break: break-all;
}
/* --- 地址选择弹层 --- */
.addr-picker-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
margin-bottom: 24rpx;
}
.addr-picker-title {
font-size: 32px;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
}
.addr-picker-close {
font-size: 28px;
display: flex;
align-items: center;
justify-content: center;
width: 64rpx;
height: 64rpx;
border-radius: 50%;
background: var(--bg-muted);
color: var(--text-secondary);
padding: 8px;
font-size: 28rpx;
}
.addr-picker-list {
@@ -180,314 +407,82 @@
}
.addr-picker-item {
padding: 20px 16px;
border-bottom: 1rpx solid var(--border);
padding: 24rpx;
border: 1rpx solid transparent;
border-radius: 16rpx;
transition: background 160ms ease, border-color 160ms ease;
}
.addr-picker-item + .addr-picker-item {
margin-top: 16rpx;
}
.addr-picker-item.active {
background: var(--accent-secondary-soft);
border-radius: 12px;
background: var(--accent-primary-soft);
border-color: var(--accent-primary);
}
.addr-picker-row {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 8px;
gap: 16rpx;
margin-bottom: 8rpx;
}
.addr-picker-name {
font-size: 28px;
font-size: 30rpx;
font-weight: 700;
color: var(--text-primary);
}
.addr-picker-phone {
font-size: 26px;
font-size: 24rpx;
color: var(--text-secondary);
}
.addr-picker-default {
font-size: 22px;
display: inline-flex;
align-items: center;
height: 40rpx;
padding: 0 16rpx;
border-radius: 999rpx;
font-size: 20rpx;
font-weight: 600;
color: var(--accent-primary);
border: 1rpx solid var(--accent-primary);
padding: 2px 8px;
border-radius: 6px;
background: var(--accent-primary-soft);
}
.addr-picker-detail {
font-size: 26px;
font-size: 26rpx;
color: var(--text-secondary);
line-height: 1.6;
}
.addr-picker-empty {
padding: 40px;
padding: 48rpx 32rpx;
text-align: center;
font-size: 28rpx;
color: var(--text-secondary);
font-size: 28px;
}
.addr-picker-add {
margin-top: 16px;
padding: 20px;
text-align: center;
border: 1rpx solid var(--border-strong);
border-radius: 12px;
}
.addr-picker-add-text {
font-size: 28px;
color: var(--accent-secondary);
}
/* 卡片标题 icon(物流/地址) */
.card-icon-img {
width: 32px;
height: 32px;
margin-right: 10px;
}
/* 商品卡片 */
.product-card {
padding: 32px;
}
.product-row {
display: flex;
align-items: center;
margin-bottom: 24px;
}
.product-icon-wrapper {
width: 100px;
height: 100px;
background: var(--bg-input);
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 20px;
overflow: hidden;
padding: 8px;
box-sizing: border-box;
}
.product-icon-img {
width: 64px;
height: 64px;
}
.product-info {
flex: 1;
}
.product-name {
font-size: 30px;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 8px;
}
.product-sku {
font-size: 24px;
color: var(--text-secondary);
}
.price-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 0;
border-top: 1rpx solid var(--border);
}
.price-label {
font-size: 26px;
color: var(--text-secondary);
}
.price-value {
font-size: 28px;
color: var(--text-primary);
}
.price-row.total {
padding-top: 20px;
}
.total-label {
font-size: 28px;
font-weight: 700;
}
.total-value {
font-size: 36px;
font-weight: 800;
color: var(--accent-primary);
}
/* 信息卡片 */
.info-card {
padding: 32px;
}
.info-card .info-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 0;
}
.info-card .info-label {
font-size: 26px;
color: var(--text-secondary);
}
.info-card .info-value {
font-size: 26px;
color: var(--text-primary);
}
/* 状态横幅 */
.status-text {
font-size: 48px;
font-weight: 800;
color: var(--text-primary);
display: block;
margin-bottom: 10px;
}
/* 物流信息 */
.logistics-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 24px;
padding-bottom: 16px;
border-bottom: 1rpx solid var(--border);
}
.logistics-title {
font-size: 30px;
font-weight: 700;
color: var(--text-primary);
}
.logistics-num {
font-size: 24px;
color: var(--text-secondary);
}
.timeline {
position: relative;
padding-left: 20px;
}
.timeline::before {
content: '';
position: absolute;
left: 8px;
top: 8px;
bottom: 8px;
width: 2px;
background: var(--border);
opacity: 0.3;
}
.timeline-item {
display: flex;
align-items: flex-start;
margin-bottom: 24px;
position: relative;
}
.timeline-item:last-child {
margin-bottom: 0;
}
.timeline-dot {
width: 18px;
height: 18px;
border-radius: 50%;
background: var(--bg-card);
border: 2rpx solid var(--border-strong);
margin-right: 20px;
flex-shrink: 0;
margin-left: -20px;
z-index: 2;
}
.timeline-item.active .timeline-dot {
background: var(--accent-primary);
border-color: var(--accent-primary);
}
.timeline-content {
flex: 1;
}
.timeline-status {
font-size: 28px;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 6px;
}
.timeline-time {
font-size: 24px;
color: var(--text-secondary);
display: block;
margin-bottom: 4px;
}
.timeline-desc {
font-size: 26px;
color: var(--text-secondary);
line-height: 1.4;
}
/* 订单信息 */
.meta-title {
font-size: 30px;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 16px;
}
.meta-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 0;
}
.meta-label {
font-size: 26px;
color: var(--text-secondary);
}
.meta-value {
font-size: 26px;
color: var(--text-primary);
}
.preview-card {
padding: 32px;
}
.design-preview {
position: relative;
background: var(--bg-input);
border-radius: 16px;
overflow: hidden;
height: 96rpx;
margin-top: 24rpx;
border: 1rpx solid var(--border-strong);
margin: 0 auto;
border-radius: 999rpx;
background: var(--bg-card);
}
.preview-sticker {
position: absolute;
max-width: 100%;
max-height: 100%;
.addr-picker-add-text {
font-size: 28rpx;
font-weight: 600;
color: var(--accent-secondary);
}
/* --- 底部留白 --- */
.page-bottom-spacer {
height: 48rpx;
}
+24 -16
View File
@@ -56,8 +56,14 @@ export default function OrderDetailPage() {
<View className={`theme-${resolvedTheme}`}>
<ThemedPageMeta />
<View className='order-detail-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<Text className='page-title'></Text>
<View className='page-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header-inner'>
<View className='back-btn' onTap={() => Taro.navigateBack()}>
<Text className='back-arrow'></Text>
</View>
<Text className='nav-title'></Text>
<View className='nav-placeholder' />
</View>
</View>
</View>
</View>
@@ -65,20 +71,22 @@ export default function OrderDetailPage() {
}
return (
<View className={`theme-${resolvedTheme}`}>
<ThemedPageMeta />
<View className='order-detail-page'>
<View className={`theme-${resolvedTheme}`}>
<ThemedPageMeta />
<View className='order-detail-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='flex-between' style={{ width: '100%' }}>
<Text className='back-btn' onTap={() => Taro.navigateBack()}></Text>
<Text className='page-title'></Text>
<View style={{ width: '60px' }} />
<View className='page-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header-inner'>
<View className='back-btn' onTap={() => Taro.navigateBack()}>
<Text className='back-arrow'></Text>
</View>
<Text className='nav-title'></Text>
<View className='nav-placeholder' />
</View>
</View>
{/* 状态横幅 */}
<View className='status-banner surface-card mt-20'>
<View className='status-banner surface-card'>
<Text className='status-text'>
{order.statusCode === 'pending' && '待付款'}
{order.statusCode === 'paid' && '待发货'}
@@ -95,7 +103,7 @@ export default function OrderDetailPage() {
{/* 物流信息(仅 shipping/done */}
{(order.statusCode === 'shipping' || order.statusCode === 'done') && (
<View className='logistics-card surface-card mt-20'>
<View className='logistics-card detail-card surface-card'>
<View className='logistics-header'>
<View className='flex-center'>
<Image className='card-icon-img' src={assetUrl('/icon/包裹.png')} mode='aspectFit' />
@@ -133,7 +141,7 @@ export default function OrderDetailPage() {
)}
{/* 商品信息 */}
<View className='product-card surface-card mt-20'>
<View className='product-card detail-card surface-card'>
<View className='product-row'>
<View className='product-icon-wrapper'>
<Image
@@ -154,7 +162,7 @@ export default function OrderDetailPage() {
</View>
{/* 收货地址 */}
<View className='address-card surface-card mt-20'>
<View className='address-card detail-card surface-card'>
<View className='address-header'>
<View className='flex-center'>
<Image className='card-icon-img' src={assetUrl('/icon/地址.png')} mode='aspectFit' />
@@ -182,7 +190,7 @@ export default function OrderDetailPage() {
</View>
{/* 订单信息 */}
<View className='meta-card surface-card mt-20'>
<View className='meta-card detail-card surface-card'>
<Text className='meta-title'></Text>
<View className='meta-row'>
<Text className='meta-label'></Text>
@@ -198,7 +206,7 @@ export default function OrderDetailPage() {
</View>
</View>
<View style={{ height: '40px' }} />
<View className='page-bottom-spacer' />
{/* 地址选择底部弹窗 */}
{showAddrPicker && (
+202 -105
View File
@@ -1,163 +1,260 @@
.orders-page {
padding: 0 24px 24px;
padding: 0 32rpx 48rpx;
min-height: 100vh;
box-sizing: border-box;
}
.page-header {
padding: 32px 32px 24px;
margin: 20px 0 0;
/* 页面主标题 */
.orders-page .page-header {
display: flex;
align-items: flex-end;
padding-bottom: 32rpx;
margin: 0;
}
/* 状态Tab */
.status-tabs {
margin: 20px 0;
.orders-page .page-title {
display: block;
font-size: 44rpx;
font-weight: 700;
line-height: 1.2;
color: var(--text-primary);
letter-spacing: 0;
}
.tabs-scroll {
/* 状态筛选 chip */
.orders-page .status-tabs {
margin: 8rpx 0 32rpx;
}
.orders-page .tabs-scroll {
white-space: nowrap;
}
.tab-item {
display: inline-block;
padding: 20px 32px;
position: relative;
}
.tab-label {
font-size: 28px;
.orders-page .tab-item {
display: inline-flex;
align-items: center;
justify-content: center;
height: 64rpx;
padding: 0 32rpx;
margin-right: 16rpx;
border-radius: 999rpx;
background: var(--bg-card);
border: 1rpx solid var(--border);
color: var(--text-secondary);
font-size: 26rpx;
font-weight: 500;
}
.tab-item.active .tab-label {
color: var(--accent-primary);
font-weight: 700;
}
.tab-underline {
position: absolute;
bottom: 8px;
left: 50%;
transform: translateX(-50%);
width: 40px;
height: 4px;
.orders-page .tab-item.active {
background: var(--accent-primary);
border-radius: 4px;
border-color: var(--accent-primary);
color: var(--bg-page);
font-weight: 600;
}
/* 订单卡片 */
.orders-list {
padding: 0;
}
.order-card {
margin-bottom: 24px;
padding: 28px;
.orders-page .tab-label {
color: inherit;
}
.order-header {
.orders-page .tab-underline {
display: none;
}
/* 订单列表 */
.orders-page .orders-list {
padding: 0 0 8rpx;
}
.orders-page .order-card {
margin-bottom: 24rpx;
padding: 28rpx;
border-radius: 24rpx;
box-shadow: var(--shadow-card);
transition: transform 0.2s ease;
}
.orders-page .order-card:active {
transform: scale(0.98);
}
.orders-page .order-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 20px;
justify-content: space-between;
gap: 24rpx;
padding-bottom: 20rpx;
border-bottom: 1rpx solid var(--border);
margin-bottom: 20px;
margin-bottom: 24rpx;
}
.order-date {
font-size: 24px;
.orders-page .order-date {
display: block;
min-width: 0;
font-size: 24rpx;
color: var(--text-secondary);
}
.order-body {
display: flex;
align-items: flex-start;
margin-bottom: 20px;
.orders-page .order-card .badge {
display: inline-flex;
align-items: center;
justify-content: center;
height: 40rpx;
padding: 0 16rpx;
border-radius: 999rpx;
font-size: 22rpx;
font-weight: 600;
line-height: 1;
flex-shrink: 0;
}
.order-icon-wrapper {
width: 120px;
height: 120px;
background: var(--bg-input);
border-radius: 16px;
.orders-page .order-body {
display: flex;
align-items: center;
gap: 24rpx;
margin-bottom: 24rpx;
}
.orders-page .order-icon-wrapper {
width: 96rpx;
height: 96rpx;
border-radius: 24rpx;
background: var(--bg-muted);
display: flex;
align-items: center;
justify-content: center;
margin-right: 20px;
flex-shrink: 0;
}
.order-icon {
font-size: 56px;
}
.order-icon-img {
width: 56px;
height: 56px;
}
.order-info {
flex: 1;
}
.order-product {
font-size: 30px;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 8px;
}
.order-sku {
font-size: 24px;
color: var(--text-secondary);
display: block;
margin-bottom: 8px;
}
.order-meta {
font-size: 22px;
color: var(--text-muted);
display: block;
.orders-page .order-icon-img {
width: 56rpx;
height: 56rpx;
}
.order-footer {
padding-top: 16px;
.orders-page .order-info {
flex: 1;
min-width: 0;
}
.orders-page .order-product {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 30rpx;
font-weight: 700;
line-height: 1.3;
color: var(--text-primary);
margin-bottom: 8rpx;
}
.orders-page .order-sku {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 24rpx;
line-height: 1.4;
color: var(--text-secondary);
margin-bottom: 6rpx;
}
.orders-page .order-meta {
display: block;
font-size: 22rpx;
line-height: 1.4;
color: var(--text-muted);
font-variant-numeric: tabular-nums;
}
.orders-page .order-footer {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 16rpx;
padding-top: 20rpx;
border-top: 1rpx solid var(--border);
}
.order-price-bar {
.orders-page .order-price-bar {
display: flex;
align-items: baseline;
justify-content: flex-end;
margin-bottom: 20px;
flex-shrink: 0;
}
.price-label {
font-size: 24px;
.orders-page .price-label {
font-size: 24rpx;
color: var(--text-secondary);
margin-right: 8px;
margin-right: 8rpx;
}
.price-value {
font-size: 36px;
.orders-page .price-value {
font-size: 34rpx;
font-weight: 800;
line-height: 1.2;
color: var(--accent-primary);
font-variant-numeric: tabular-nums;
}
.order-actions {
.orders-page .order-actions {
display: flex;
justify-content: flex-end;
gap: 16px;
flex-wrap: wrap;
gap: 12rpx;
}
.order-btn {
padding: 14px 28px !important;
font-size: 26px !important;
border-radius: 999rpx !important;
.orders-page .order-btn {
display: flex;
align-items: center;
justify-content: center;
height: 64rpx;
padding: 0 28rpx;
font-size: 26rpx;
font-weight: 600;
line-height: 1.2;
border-radius: 999rpx;
}
/* 空状态 */
.empty-state {
.orders-page .empty-state {
display: flex;
flex-direction: column;
align-items: center;
padding: 120px 40px;
padding: 80rpx 32rpx;
text-align: center;
background: var(--bg-muted);
border-radius: 24rpx;
}
.empty-icon-img {
width: 56px;
height: 56px;
margin-bottom: 24px;
.orders-page .empty-icon-img {
width: 88rpx;
height: 88rpx;
margin-bottom: 24rpx;
}
.empty-text {
font-size: 36px;
.orders-page .empty-text {
display: block;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 12px;
margin-bottom: 12rpx;
}
.empty-sub {
font-size: 28px;
.orders-page .empty-sub {
display: block;
font-size: 26rpx;
color: var(--text-secondary);
margin-bottom: 40px;
margin-bottom: 32rpx;
}
.orders-page .empty-state .btn-primary {
display: flex;
align-items: center;
justify-content: center;
min-width: 280rpx;
height: 88rpx;
padding: 0 48rpx;
border-radius: 999rpx;
font-size: 30rpx;
font-weight: 600;
}
+1 -2
View File
@@ -87,7 +87,7 @@ export default function OrdersPage() {
<LoginGuard>
<View className='orders-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<Text className='page-title'></Text>
</View>
@@ -188,7 +188,6 @@ export default function OrdersPage() {
)}
</ScrollView>
<View style={{ height: '40px' }} />
</View>
</LoginGuard>
</View>
+223 -104
View File
@@ -1,237 +1,356 @@
.product-page {
padding: 0 24px 24px;
padding-bottom: calc(24px + 200px); /* 为底部毛玻璃 action-bar 留空 */
padding: 0 32rpx 32rpx;
padding-bottom: calc(32rpx + 480rpx);
}
/* 通栏页头 */
.page-header {
position: relative;
z-index: 10;
padding: 0 24rpx 24rpx;
margin-bottom: 24rpx;
}
.page-header-inner {
display: flex;
align-items: center;
gap: 16rpx;
min-height: 88rpx;
}
/* 返回按钮 */
.back-btn {
font-size: 40px;
padding: 10px;
width: 88rpx;
height: 88rpx;
flex: 0 0 auto;
border-radius: 50%;
background: var(--bg-card);
border: 1rpx solid var(--border-strong);
box-shadow: var(--shadow-card);
display: flex;
align-items: center;
justify-content: center;
}
.back-btn:active {
transform: scale(0.96);
}
.back-arrow {
font-size: 36rpx;
line-height: 1;
color: var(--text-primary);
}
.nav-title {
flex: 1;
text-align: center;
font-size: 34rpx;
font-weight: 600;
color: var(--text-primary);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.nav-placeholder {
width: 88rpx;
flex: 0 0 auto;
}
/* Hero 轮播 */
.hero-section {
margin-top: 20px;
width: 100%;
}
.hero-swiper {
height: 400rpx;
height: 560rpx;
}
.hero-card {
.hero-block {
position: relative;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
box-sizing: border-box;
}
.hero-icon {
font-size: 100px;
margin-bottom: 16px;
}
.hero-icon-img {
width: 100px;
height: 100px;
margin-bottom: 16px;
}
.hero-name {
font-size: 36px;
font-weight: 700;
color: var(--text-primary);
overflow: hidden;
border-radius: 24rpx;
background: var(--bg-muted);
box-shadow: var(--shadow-card);
}
.hero-image {
width: 100%;
height: 100%;
object-fit: contain;
}
/* 基本信息 */
.info-section {
padding: 24px;
}
.info-row {
.hero-block-fallback {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: linear-gradient(160deg, var(--accent-primary-strong), var(--accent-secondary));
}
.hero-fallback-icon {
width: 140rpx;
height: 140rpx;
margin-bottom: 24rpx;
}
/* detail-card 版式 */
.detail-card {
padding: 32rpx;
margin-top: 24rpx;
}
.price-line {
display: flex;
align-items: flex-end;
justify-content: space-between;
padding: 20px 0;
border-bottom: 1rpx solid var(--border);
gap: 24rpx;
}
.info-row:last-child {
border-bottom: none;
.price-left {
flex: 1;
min-width: 0;
}
.info-label {
font-size: 28px;
color: var(--text-secondary);
}
.info-price {
font-size: 40px;
font-weight: 800;
color: var(--accent-primary);
}
.info-value {
font-size: 28px;
.detail-title {
display: block;
font-size: 36rpx;
font-weight: 700;
line-height: 1.3;
color: var(--text-primary);
}
/* 详细介绍 */
.detail-section {
padding: 24px;
.detail-desc {
display: block;
margin-top: 8rpx;
font-size: 24rpx;
line-height: 1.4;
color: var(--text-secondary);
}
.price-right {
flex: 0 0 auto;
text-align: right;
}
.price {
display: block;
font-size: 40rpx;
font-weight: 800;
line-height: 1.2;
color: var(--accent-primary);
font-variant-numeric: tabular-nums;
}
.price-old {
display: block;
margin-top: 6rpx;
font-size: 24rpx;
color: var(--text-muted);
text-decoration: line-through;
font-variant-numeric: tabular-nums;
}
.spec-row {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 24rpx;
padding: 24rpx 0;
border-bottom: 1rpx solid var(--border);
}
.spec-row:last-child {
border-bottom: none;
padding-bottom: 0;
}
.spec-key {
flex: 0 0 auto;
font-size: 26rpx;
color: var(--text-secondary);
}
.spec-value {
flex: 1;
text-align: right;
font-size: 26rpx;
font-weight: 600;
color: var(--text-primary);
word-break: break-all;
}
.detail-card .section-title {
font-size: 32rpx;
font-weight: 700;
margin-bottom: 24rpx;
}
.detail-text {
font-size: 28px;
color: var(--text-secondary);
display: block;
font-size: 28rpx;
line-height: 1.8;
color: var(--text-secondary);
}
/* 底部操作栏 */
.action-bar .price-summary {
.bottom-action-bar {
gap: 20rpx;
padding-left: 32rpx;
padding-right: 32rpx;
}
.bottom-action-bar .price-summary {
flex-shrink: 0;
}
.summary-label {
font-size: 22px;
color: var(--text-secondary);
display: block;
font-size: 22rpx;
color: var(--text-secondary);
}
.summary-price {
font-size: 36px;
display: block;
font-size: 36rpx;
font-weight: 700;
color: var(--accent-primary);
font-variant-numeric: tabular-nums;
}
.summary-original {
display: block;
margin-top: 2rpx;
font-size: 22rpx;
color: var(--text-muted);
text-decoration: line-through;
font-variant-numeric: tabular-nums;
}
.bottom-action-bar .btn-secondary,
.bottom-action-bar .btn-primary {
flex: 1;
text-align: center;
padding: 28rpx 0;
font-size: 28rpx;
font-weight: 600;
line-height: 1.2;
}
/* 弹窗 */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
padding: 48px;
padding: 48rpx;
}
.modal-card {
width: 100%;
max-width: 600px;
padding: 40px;
max-width: 640rpx;
padding: 40rpx;
}
.modal-title {
font-size: 36px;
display: block;
text-align: center;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
text-align: center;
margin-bottom: 24px;
display: block;
margin-bottom: 24rpx;
}
.modal-product {
display: flex;
align-items: center;
justify-content: center;
gap: 16px;
margin-bottom: 32px;
}
.modal-icon {
font-size: 48px;
gap: 16rpx;
margin-bottom: 32rpx;
}
.modal-icon-img {
width: 48px;
height: 48px;
width: 48rpx;
height: 48rpx;
}
.modal-name {
font-size: 32px;
color: var(--text-primary);
font-size: 32rpx;
font-weight: 600;
color: var(--text-primary);
}
.quantity-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 32px;
margin-bottom: 32rpx;
}
.qty-label {
font-size: 28px;
font-size: 28rpx;
color: var(--text-secondary);
}
.qty-control {
display: flex;
align-items: center;
gap: 24px;
gap: 24rpx;
}
.qty-btn {
width: 60px;
height: 60px;
border-radius: 12px;
width: 60rpx;
height: 60rpx;
border-radius: 16rpx;
background: var(--bg-input);
border: 1rpx solid var(--border);
display: flex;
align-items: center;
justify-content: center;
font-size: 32px;
color: var(--text-primary);
font-size: 32rpx;
font-weight: 600;
color: var(--text-primary);
}
.qty-num {
font-size: 32px;
min-width: 48rpx;
text-align: center;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
min-width: 48px;
text-align: center;
}
.modal-total {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 32px;
padding-top: 24px;
margin-bottom: 32rpx;
padding-top: 24rpx;
border-top: 1rpx solid var(--border);
}
.total-label {
font-size: 28px;
font-size: 28rpx;
color: var(--text-secondary);
}
.total-price {
font-size: 36px;
font-size: 36rpx;
font-weight: 800;
color: var(--accent-primary);
font-variant-numeric: tabular-nums;
}
.modal-actions {
display: flex;
gap: 20px;
gap: 20rpx;
}
.modal-actions .btn-secondary,
.modal-actions .btn-primary {
flex: 1;
padding: 20px 0;
text-align: center;
padding: 24rpx 0;
font-size: 28rpx;
font-weight: 600;
}
+66 -37
View File
@@ -8,10 +8,9 @@ import { useThemeContext } from '../../context/ThemeContext'
import { useSafeArea } from '../../hooks/useSafeArea'
import { useStatusBar } from '../../hooks/useStatusBar'
import ThemedPageMeta from '../../components/ThemedPageMeta'
import BottomActionBar from '../../components/BottomActionBar'
import { getProductIconImg } from '../../utils/productConfig'
const HERO_COLORS = ['var(--accent-primary-soft)', 'var(--bg-muted)', 'var(--accent-secondary-soft)']
export default function ProductPage() {
const { theme, resolvedTheme } = useThemeContext()
const safe = useSafeArea()
@@ -21,7 +20,7 @@ export default function ProductPage() {
const router = Taro.getCurrentInstance().router
const params = router ? router.params : undefined
const productId = params ? params.id : ''
const productId = params && params.id ? params.id : ''
const product = getProductById(productId)
if (!product) {
@@ -29,14 +28,25 @@ export default function ProductPage() {
<View className={`theme-${resolvedTheme}`}>
<ThemedPageMeta />
<View className='product-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<Text className='page-title'></Text>
<View className='page-header' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header-inner'>
<View className='back-btn' onTap={() => Taro.navigateBack()}>
<Text className='back-arrow'></Text>
</View>
<Text className='nav-title'></Text>
<View className='nav-placeholder' />
</View>
</View>
</View>
</View>
)
}
const craftSpec = product.specs && product.specs.length > 0
? product.specs.find(item => item[0].indexOf('工艺') >= 0)
: undefined
const craftValue = craftSpec ? craftSpec[1] : '激光微雕'
const handleAddToList = () => {
setQuantity(1)
setShowModal(true)
@@ -64,16 +74,18 @@ export default function ProductPage() {
<ThemedPageMeta />
<View className='product-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='flex-between'>
<Text className='back-btn' onTap={() => Taro.navigateBack()}></Text>
<Text className='page-title'></Text>
<View style={{ width: '60px' }} />
<View className='page-header' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header-inner'>
<View className='back-btn' onTap={() => Taro.navigateBack()}>
<Text className='back-arrow'></Text>
</View>
<Text className='nav-title'></Text>
<View className='nav-placeholder' />
</View>
</View>
{/* 轮播 Hero */}
<View className='hero-section mt-20'>
<View className='hero-section'>
<Swiper
className='hero-swiper'
circular
@@ -81,54 +93,71 @@ export default function ProductPage() {
interval={3000}
duration={500}
indicatorDots
indicatorColor='#e0d5c8'
indicatorActiveColor='#d96c6a'
indicatorColor='var(--border-strong)'
indicatorActiveColor='var(--accent-primary)'
>
{product.images && product.images.length > 0 ? (
product.images.map((img, idx) => (
<SwiperItem key={idx}>
<View className='hero-card surface-card'>
<Image className='hero-image' src={img} mode='aspectFit' />
<View className='hero-block'>
<Image className='hero-image' src={img} mode='aspectFill' />
</View>
</SwiperItem>
))
) : (
HERO_COLORS.map((color, idx) => (
<SwiperItem key={idx}>
<View className='hero-card surface-card' style={{ background: color }}>
<Image className='hero-icon-img' src={getProductIconImg(product)} mode='aspectFit' />
<Text className='hero-name'>{product.name}</Text>
</View>
</SwiperItem>
))
<SwiperItem>
<View className='hero-block hero-block-fallback'>
<Image className='hero-fallback-icon' src={getProductIconImg(product)} mode='aspectFit' />
</View>
</SwiperItem>
)}
</Swiper>
</View>
{/* 基本信息 */}
<View className='info-section surface-card mt-20'>
<View className='info-row'>
<Text className='info-label'></Text>
<Text className='info-price'>¥{product.price}</Text>
{/* 商品信息 */}
<View className='detail-card surface-card'>
<View className='price-line'>
<View className='price-left'>
<Text className='detail-title'>{product.name}</Text>
<Text className='detail-desc'>{product.desc}</Text>
</View>
<View className='price-right'>
<Text className='price'>¥{product.price}</Text>
{product.originalPrice && product.originalPrice > product.price && (
<Text className='price-old'>¥{product.originalPrice}</Text>
)}
</View>
</View>
<View className='info-row'>
<Text className='info-label'></Text>
<Text className='info-value'>{product.leadTime}</Text>
</View>
{/* 规格信息 */}
<View className='detail-card surface-card'>
<View className='spec-row'>
<Text className='spec-key'></Text>
<Text className='spec-value'>¥{product.price}</Text>
</View>
<View className='info-row'>
<Text className='info-label'></Text>
<Text className='info-value'>{product.mask.width} × {product.mask.height} px</Text>
<View className='spec-row'>
<Text className='spec-key'></Text>
<Text className='spec-value'>{product.leadTime}</Text>
</View>
<View className='spec-row'>
<Text className='spec-key'></Text>
<Text className='spec-value'>{product.mask.width} × {product.mask.height} px</Text>
</View>
<View className='spec-row'>
<Text className='spec-key'></Text>
<Text className='spec-value'>{craftValue}</Text>
</View>
</View>
{/* 详细介绍 */}
<View className='detail-section surface-card mt-20'>
<View className='detail-card surface-card'>
<Text className='section-title'></Text>
<Text className='detail-text'>{product.description}</Text>
</View>
{/* 底部操作栏 */}
<View className='action-bar'>
<BottomActionBar>
<View className='price-summary'>
<Text className='summary-label'></Text>
<Text className='summary-price'>¥{product.price}</Text>
@@ -139,7 +168,7 @@ export default function ProductPage() {
<View className='btn-primary' onTap={goToDIY}>
<Text></Text>
</View>
</View>
</BottomActionBar>
{/* 安全区占位(防止内容被 action-bar 遮挡) */}
<View className='safe-bottom-placeholder' />
+197 -162
View File
@@ -1,244 +1,272 @@
.profile-page {
padding: 0 24px 24px;
padding: 0 32rpx 48rpx;
min-height: 100vh;
box-sizing: border-box;
}
/* 用户头部 */
.profile-header {
padding: 40px 32px 32px;
margin: 20px 0 0;
.profile-page .profile-header {
padding: 32rpx 32rpx 16rpx;
margin: 0 0 32rpx;
}
.user-info {
.profile-page .user-info {
display: flex;
align-items: center;
margin-bottom: 32px;
gap: 24rpx;
margin-bottom: 24rpx;
}
.avatar {
width: 120px;
height: 120px;
.profile-page .avatar,
.profile-page .avatar-placeholder {
width: 112rpx;
height: 112rpx;
border-radius: 50%;
border: 1rpx solid var(--border);
margin-right: 24px;
flex-shrink: 0;
}
.avatar-placeholder {
width: 120px;
height: 120px;
border-radius: 50%;
background: var(--bg-muted);
display: flex;
align-items: center;
justify-content: center;
margin-right: 24px;
border: 1rpx solid var(--border);
margin-right: 0;
flex-shrink: 0;
}
.avatar-icon {
font-size: 56px;
}
.user-name {
font-size: 40px;
font-weight: 800;
color: var(--text-primary);
display: block;
margin-bottom: 8px;
}
.user-level {
font-size: 24px;
color: var(--text-secondary);
display: block;
}
/* 5状态快捷入口 - 2+3布局 */
.status-grid {
background: var(--bg-card);
border: 1rpx solid var(--border);
border-radius: 20px;
overflow: hidden;
}
.status-row {
.profile-page .avatar-icon-img {
width: 44rpx;
height: 44rpx;
}
.profile-page .user-meta {
flex: 1;
min-width: 0;
}
.profile-page .user-name {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 36rpx;
font-weight: 700;
line-height: 1.2;
color: var(--text-primary);
margin-bottom: 8rpx;
}
.profile-page .user-level {
display: block;
font-size: 24rpx;
line-height: 1.4;
color: var(--text-secondary);
}
/* 5 状态快捷入口 */
.profile-page .status-grid {
display: flex;
flex-direction: column;
border-top: 1rpx solid var(--border);
padding-top: 16rpx;
}
.profile-page .status-row {
display: flex;
align-items: center;
justify-content: space-around;
padding: 20px 0;
}
/* 每组(item + divider)作为一个 flex 单元 */
.status-group {
.profile-page .status-group {
flex: 1;
min-width: 0;
display: flex;
align-items: center;
justify-content: center;
}
.status-item {
.profile-page .status-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 8px 0;
justify-content: center;
flex: 1;
min-height: 112rpx;
padding: 8rpx 0;
transition: transform 0.18s ease;
}
.status-num {
font-size: 36px;
.profile-page .status-item:active {
transform: scale(0.97);
}
.profile-page .status-icon-img {
width: 32rpx;
height: 32rpx;
margin-bottom: 10rpx;
}
.profile-page .status-num {
font-size: 32rpx;
font-weight: 800;
line-height: 1.2;
color: var(--accent-primary);
margin-bottom: 8px;
margin-bottom: 6rpx;
font-variant-numeric: tabular-nums;
}
.status-label {
font-size: 24px;
.profile-page .status-label {
font-size: 24rpx;
line-height: 1.2;
color: var(--text-secondary);
}
.status-divider {
width: 2px;
height: 48px;
.profile-page .status-divider {
width: 1rpx;
height: 56rpx;
background: var(--border);
opacity: 0.25;
flex-shrink: 0;
}
.status-divider-h {
height: 2px;
.profile-page .status-divider-h {
height: 1rpx;
background: var(--border);
opacity: 0.15;
margin: 0 16px;
margin: 4rpx 16rpx 12rpx;
}
/* 菜单网格 */
.menu-grid {
/* 区块标题 */
.profile-page .section-title {
display: block;
margin: 0 0 24rpx;
font-size: 32rpx;
font-weight: 700;
line-height: 1.25;
color: var(--text-primary);
}
/* 功能菜单 */
.profile-page .menu-grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 20px;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 16rpx;
}
.menu-card {
.profile-page .menu-card {
display: flex;
flex-direction: column;
align-items: center;
padding: 32px 16px;
transition: transform 0.2s;
justify-content: center;
min-height: 148rpx;
padding: 28rpx 16rpx;
border-radius: 24rpx;
box-shadow: var(--shadow-card);
transition: transform 0.2s ease;
}
.menu-card:active {
transform: scale(0.96);
.profile-page .menu-card:active {
transform: scale(0.97);
}
.menu-icon {
font-size: 48px;
margin-bottom: 12px;
.profile-page .menu-icon-img {
width: 44rpx;
height: 44rpx;
margin-bottom: 16rpx;
}
.menu-label {
font-size: 26px;
color: var(--text-primary);
font-weight: 500;
}
/* 企业定制 */
.enterprise-section {
padding: 32px;
}
.enterprise-title {
font-size: 30px;
font-weight: 700;
color: var(--text-primary);
.profile-page .menu-label {
display: block;
margin-bottom: 8px;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 26rpx;
font-weight: 600;
line-height: 1.2;
color: var(--text-primary);
}
.enterprise-desc {
font-size: 24px;
/* 企业定制入口 */
.profile-page .enterprise-section {
padding: 28rpx 32rpx;
margin: 0 0 48rpx;
}
.profile-page .enterprise-icon {
width: 32rpx;
height: 32rpx;
margin-right: 12rpx;
flex-shrink: 0;
}
.profile-page .enterprise-title {
display: block;
font-size: 30rpx;
font-weight: 700;
line-height: 1.3;
color: var(--text-primary);
margin-bottom: 6rpx;
}
.profile-page .enterprise-desc {
display: block;
font-size: 24rpx;
line-height: 1.4;
color: var(--text-secondary);
}
.enterprise-btn {
padding: 16px 32px !important;
font-size: 26px !important;
border-radius: 40px !important;
.profile-page .enterprise-btn {
display: flex;
align-items: center;
justify-content: center;
height: 80rpx;
padding: 0 32rpx;
font-size: 26rpx;
font-weight: 600;
line-height: 1.2;
border-radius: 999rpx;
flex-shrink: 0;
}
.menu-icon-img {
width: 36px;
height: 36px;
margin-bottom: 12px;
}
/* 状态 icon 图片 */
.status-icon-img {
width: 28px;
height: 28px;
margin-bottom: 4px;
}
/* 企业定制icon */
.enterprise-icon {
width: 28px;
height: 28px;
margin-right: 12px;
}
/* 头像占位图 */
.avatar-icon-img {
width: 36px;
height: 36px;
}
/* 登录弹窗头像占位 */
.avatar-placeholder-img {
width: 56px;
height: 56px;
}
.modal-overlay {
/* 登录弹窗 */
.profile-page .modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
padding: 48px;
padding: 48rpx;
}
.login-card {
.profile-page .login-card {
width: 100%;
max-width: 600px;
padding: 40px;
max-width: 640rpx;
padding: 40rpx;
text-align: center;
border-radius: 32rpx;
}
.login-title {
font-size: 36px;
.profile-page .login-title {
display: block;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 12px;
margin-bottom: 12rpx;
}
.login-desc {
font-size: 26px;
.profile-page .login-desc {
display: block;
font-size: 26rpx;
color: var(--text-secondary);
display: block;
margin-bottom: 32px;
margin-bottom: 32rpx;
}
.avatar-btn {
width: 160px;
height: 160px;
.profile-page .avatar-btn {
width: 160rpx;
height: 160rpx;
border-radius: 50%;
margin: 0 auto 24px;
margin: 0 auto 24rpx;
background: var(--bg-input);
border: 1rpx solid var(--border);
display: flex;
@@ -250,39 +278,46 @@
font-size: 0;
}
.avatar-img {
.profile-page .avatar-img {
width: 100%;
height: 100%;
border-radius: 50%;
}
.avatar-placeholder {
font-size: 24px;
color: var(--text-secondary);
.profile-page .avatar-placeholder-img {
width: 64rpx;
height: 64rpx;
}
.nickname-input {
.profile-page .nickname-input {
width: 100%;
height: 80px;
height: 88rpx;
background: var(--bg-input);
border: 1rpx solid var(--border);
border-radius: 16px;
padding: 0 24px;
font-size: 28px;
border-radius: 16rpx;
padding: 0 24rpx;
font-size: 28rpx;
color: var(--text-primary);
margin-bottom: 32px;
margin-bottom: 32rpx;
text-align: center;
box-sizing: border-box;
}
.login-actions {
.profile-page .login-actions {
display: flex;
gap: 20px;
gap: 20rpx;
}
.login-actions .btn-secondary,
.login-actions .btn-primary {
.profile-page .login-actions .btn-secondary,
.profile-page .login-actions .btn-primary {
flex: 1;
padding: 20px 0;
display: flex;
align-items: center;
justify-content: center;
height: 88rpx;
padding: 0;
font-size: 28rpx;
font-weight: 600;
text-align: center;
border-radius: 999rpx;
}
+1 -3
View File
@@ -282,7 +282,7 @@ export default function ProfilePage() {
<View className='profile-page'>
{/* 用户信息头部 */}
<View className='profile-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='profile-header surface-card' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='user-info'>
{isLoggedIn && userInfo.avatarUrl ? (
<Image className='avatar' src={userInfo.avatarUrl} mode='aspectFill' />
@@ -360,8 +360,6 @@ export default function ProfilePage() {
</View>
</View>
<View style={{ height: '40px' }} />
{/* 登录弹窗 */}
{showLogin && (
<View className='modal-overlay'>
+149 -62
View File
@@ -1,121 +1,208 @@
/* ============================================================
Service Page — 客服中心
============================================================ */
.service-page {
padding: 0 24px 24px;
padding: 0 32rpx calc(24rpx + env(safe-area-inset-bottom));
min-height: 100vh;
box-sizing: border-box;
}
.page-header {
padding: 32px 32px 24px;
margin: 20px 0 0;
.service-page .page-header.service-header {
margin: 0;
padding-left: 0;
padding-right: 0;
padding-bottom: 32rpx;
text-align: center;
}
/* 客服英雄区 */
.service-header .page-title {
font-size: 44rpx;
font-weight: 700;
line-height: 1.2;
color: var(--text-primary);
letter-spacing: 0;
}
/* 客服主入口 */
.service-hero {
display: flex;
flex-direction: column;
align-items: center;
padding: 56rpx 40rpx;
text-align: center;
padding: 50px 40px;
}
.service-hero-icon {
width: 56px;
height: 56px;
margin-bottom: 20px;
width: 88rpx;
height: 88rpx;
margin-bottom: 24rpx;
}
.service-title {
font-size: 36px;
display: block;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 12px;
margin-bottom: 12rpx;
letter-spacing: 0;
}
.service-desc {
font-size: 24px;
color: var(--text-secondary);
display: block;
margin-bottom: 32px;
font-size: 24rpx;
line-height: 1.5;
color: var(--text-secondary);
margin-bottom: 32rpx;
}
.service-btn {
padding: 24px 56px !important;
font-size: 30px !important;
border-radius: 50px !important;
display: flex;
align-items: center;
justify-content: center;
min-width: 280rpx;
height: 80rpx;
padding: 0 48rpx;
box-sizing: border-box;
font-size: 28rpx;
font-weight: 600;
}
/* 联系方式 */
.contact-list {
display: flex;
flex-direction: column;
gap: 20px;
.service-page .section-title {
display: block;
margin-bottom: 24rpx;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 0;
}
.contact-list.surface-card {
padding: 0 32rpx;
overflow: hidden;
}
.contact-item {
display: flex;
align-items: center;
padding: 28px 32px;
min-height: 112rpx;
padding: 24rpx 0;
border-bottom: 1rpx solid var(--border);
}
.contact-icon {
font-size: 48px;
margin-right: 24px;
.contact-item:last-child {
border-bottom: none;
}
.contact-item-link {
transition: background 160ms ease;
}
.contact-item-link:active {
background: var(--bg-muted);
}
.contact-icon-img {
width: 32px;
height: 32px;
margin-right: 24px;
width: 48rpx;
height: 48rpx;
margin-right: 24rpx;
flex-shrink: 0;
}
.contact-info {
flex: 1;
}
.contact-label {
font-size: 24px;
color: var(--text-secondary);
display: block;
margin-bottom: 4px;
}
.contact-value {
font-size: 30px;
font-weight: 600;
color: var(--text-primary);
min-width: 0;
}
/* FAQ */
.faq-card {
margin-bottom: 20px;
padding: 28px 32px;
}
.faq-q {
font-size: 30px;
font-weight: 700;
color: var(--text-primary);
.contact-label {
display: block;
margin-bottom: 12px;
font-size: 24rpx;
line-height: 1.4;
color: var(--text-secondary);
margin-bottom: 4rpx;
}
.contact-value {
display: block;
font-size: 28rpx;
font-weight: 600;
color: var(--text-primary);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.contact-arrow {
flex-shrink: 0;
margin-left: 16rpx;
font-size: 32rpx;
line-height: 1;
color: var(--text-muted);
}
/* 常见问题 */
.faq-card {
display: block;
margin-bottom: 24rpx;
padding: 32rpx;
}
.faq-q {
display: block;
font-size: 30rpx;
font-weight: 700;
line-height: 1.45;
color: var(--text-primary);
margin-bottom: 12rpx;
letter-spacing: 0;
}
.faq-a {
font-size: 26px;
display: block;
font-size: 26rpx;
line-height: 1.7;
color: var(--text-secondary);
line-height: 1.6;
}
/* 企业专属 */
.enterprise-service {
padding: 32px;
padding: 32rpx;
}
.enterprise-service .flex-center {
justify-content: flex-start;
margin-bottom: 12rpx;
}
.enterprise-icon {
width: 28px;
height: 28px;
margin-right: 12px;
width: 40rpx;
height: 40rpx;
margin-right: 12rpx;
flex-shrink: 0;
}
.enterprise-title {
font-size: 30px;
display: block;
font-size: 30rpx;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 8px;
letter-spacing: 0;
}
.enterprise-desc {
font-size: 24px;
color: var(--text-secondary);
margin-bottom: 24px;
display: block;
font-size: 24rpx;
line-height: 1.6;
color: var(--text-secondary);
margin-bottom: 24rpx;
}
.enterprise-btn {
display: flex;
align-items: center;
justify-content: center;
height: 80rpx;
font-size: 28rpx;
font-weight: 600;
}
+8 -7
View File
@@ -23,12 +23,12 @@ export default function ServicePage() {
<View className={`theme-${resolvedTheme}`} style={{ minHeight: '100vh' }}>
<ThemedPageMeta />
<View className='service-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header service-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<Text className='page-title'></Text>
</View>
{/* 客服入口 */}
<View className='service-hero surface-card mt-20'>
<View className='service-hero surface-card'>
<Image className='service-hero-icon' src={assetUrl('/icon/电话.png')} mode='aspectFit' />
<Text className='service-title'></Text>
<Text className='service-desc'> 09:00 - 18:00 线</Text>
@@ -40,22 +40,23 @@ export default function ServicePage() {
{/* 联系方式 */}
<View className='mt-20'>
<Text className='section-title'></Text>
<View className='contact-list'>
<View className='contact-item surface-card'>
<View className='contact-list surface-card'>
<View className='contact-item'>
<Image className='contact-icon-img' src={assetUrl('/icon/电话.png')} mode='aspectFit' />
<View className='contact-info'>
<Text className='contact-label'></Text>
<Text className='contact-value'>400-XXX-XXXX</Text>
</View>
</View>
<View className='contact-item surface-card' onTap={() => Taro.setClipboardData({ data: 'smart_engraving' })}>
<View className='contact-item contact-item-link' onTap={() => Taro.setClipboardData({ data: 'smart_engraving' })}>
<Image className='contact-icon-img' src={assetUrl('/icon/词云生成.png')} mode='aspectFit' />
<View className='contact-info'>
<Text className='contact-label'></Text>
<Text className='contact-value'>smart_engraving</Text>
</View>
<Text className='contact-arrow'></Text>
</View>
<View className='contact-item surface-card'>
<View className='contact-item'>
<Image className='contact-icon-img' src={assetUrl('/icon/使用帮助.png')} mode='aspectFit' />
<View className='contact-info'>
<Text className='contact-label'></Text>
@@ -88,7 +89,7 @@ export default function ServicePage() {
</View>
</View>
<View style={{ height: '40px' }} />
<View style={{ height: '80rpx' }} />
</View>
</View>
)
+271 -76
View File
@@ -1,60 +1,223 @@
/* ============================================================
Settings Page — 设置
============================================================ */
.settings-page {
padding: 0 24px 24px;
}
.settings-area {
padding-top: calc(env(safe-area-inset-top, 0px));
padding: 0 32rpx calc(24rpx + env(safe-area-inset-bottom));
min-height: 100vh;
box-sizing: border-box;
}
/* 顶部导航 */
.page-header.settings-header {
display: flex;
align-items: center;
gap: 16rpx;
min-height: 88rpx;
padding-left: 0;
padding-right: 0;
padding-bottom: 24rpx;
margin: 0;
}
.settings-header .back-btn {
display: flex;
align-items: center;
justify-content: center;
width: 88rpx;
height: 88rpx;
flex: 0 0 auto;
border-radius: 50%;
background: var(--bg-card);
border: 1rpx solid var(--border-strong);
box-shadow: var(--shadow-card);
box-sizing: border-box;
}
.settings-header .back-btn:active {
transform: scale(0.96);
}
.settings-header .back-arrow {
font-size: 36rpx;
line-height: 1;
color: var(--text-primary);
}
.settings-header .page-title {
flex: 1;
min-width: 0;
text-align: center;
font-size: 34rpx;
font-weight: 600;
color: var(--text-primary);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
letter-spacing: 0;
}
.header-spacer {
width: 88rpx;
flex: 0 0 auto;
}
/* 用户卡片 */
.settings-user {
padding: 24px;
padding: 32rpx;
margin-top: 24rpx;
}
.settings-user .flex-center {
flex: 1;
min-width: 0;
justify-content: flex-start;
}
.settings-avatar {
width: 100px;
height: 100px;
width: 112rpx;
height: 112rpx;
border-radius: 50%;
border: 1rpx solid var(--border);
background: var(--bg-input);
flex-shrink: 0;
}
.settings-avatar-placeholder {
width: 100px;
height: 100px;
width: 112rpx;
height: 112rpx;
border-radius: 50%;
background: var(--bg-input);
border: 1rpx solid var(--border);
display: flex;
align-items: center;
justify-content: center;
padding: 30px;
padding: 24rpx;
box-sizing: border-box;
flex-shrink: 0;
}
.settings-avatar-icon {
width: 64rpx;
height: 64rpx;
}
.settings-meta {
flex: 1;
min-width: 0;
margin-left: 24rpx;
}
.settings-name {
font-size: 32px;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 8px;
font-size: 32rpx;
font-weight: 700;
line-height: 1.3;
color: var(--text-primary);
margin-bottom: 8rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.settings-id {
font-size: 24px;
display: block;
font-size: 24rpx;
line-height: 1.4;
color: var(--text-secondary);
}
.arrow {
font-size: 36px;
flex-shrink: 0;
font-size: 36rpx;
line-height: 1;
color: var(--text-muted);
}
/* 外观设置 */
.settings-section {
padding: 32rpx;
margin-top: 24rpx;
}
.section-label {
display: block;
font-size: 28rpx;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 24rpx;
letter-spacing: 0;
}
.theme-options {
display: flex;
gap: 8rpx;
padding: 8rpx;
border-radius: 999rpx;
background: var(--bg-muted);
box-sizing: border-box;
}
.theme-option {
flex: 1;
min-width: 0;
height: 80rpx;
padding: 0 16rpx;
border-radius: 999rpx;
background: transparent;
border: 1rpx solid transparent;
display: flex;
align-items: center;
justify-content: center;
gap: 12rpx;
color: var(--text-secondary);
font-size: 26rpx;
font-weight: 500;
transition: background 160ms ease, border-color 160ms ease, color 160ms ease, box-shadow 160ms ease;
box-sizing: border-box;
}
.theme-option.active {
background: var(--bg-card);
border-color: var(--border-strong);
color: var(--text-primary);
font-weight: 600;
box-shadow: var(--shadow-card);
}
.theme-option-text {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.theme-check {
width: 16rpx;
height: 16rpx;
border-radius: 50%;
background: var(--accent-primary);
flex-shrink: 0;
}
.theme-hint {
display: block;
text-align: center;
margin-top: 24rpx;
font-size: 24rpx;
color: var(--text-secondary);
}
/* 菜单列表 */
.settings-list {
padding: 0 24px;
padding: 0 32rpx;
margin-top: 24rpx;
}
.settings-item {
display: flex;
align-items: center;
padding: 28px 0;
min-height: 112rpx;
padding: 24rpx 0;
}
.settings-item.bordered {
@@ -62,83 +225,115 @@
}
.settings-item-icon-img {
width: 32px;
height: 32px;
margin-right: 16px;
width: 48rpx;
height: 48rpx;
margin-right: 24rpx;
flex-shrink: 0;
}
.settings-item-label {
flex: 1;
font-size: 30px;
color: var(--text-primary);
}
.logout-btn {
text-align: center;
padding: 24px 0;
color: var(--danger);
border: 1rpx solid var(--danger);
}
/* --- 主题选择 --- */
.settings-section {
padding: 32px;
}
.section-label {
font-size: 30px;
min-width: 0;
font-size: 30rpx;
font-weight: 600;
color: var(--text-primary);
display: block;
margin-bottom: 24px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.theme-options {
display: flex;
gap: 16px;
flex-wrap: wrap;
}
.theme-option {
flex: 1;
min-width: 160px;
padding: 24px 16px;
border-radius: 20px;
background: var(--bg-input);
border: 1rpx solid transparent;
/* 退出登录 */
.logout-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
transition: all 0.2s ease;
height: 88rpx;
font-size: 28rpx;
font-weight: 600;
color: var(--danger);
border: 1rpx solid var(--danger);
background: transparent;
box-sizing: border-box;
}
.theme-option.active {
border-color: var(--accent-primary);
background: var(--accent-primary-soft);
/* 编辑弹窗 */
.settings-page .modal-overlay {
align-items: center;
justify-content: center;
padding: 48rpx;
z-index: 1000;
}
.theme-option-text {
font-size: 28px;
color: var(--text-primary);
font-weight: 500;
.settings-page .modal-card {
width: 100%;
max-width: 640rpx;
padding: 40rpx;
border-radius: 32rpx;
background: var(--bg-card);
border: 1rpx solid var(--border);
box-shadow: var(--shadow-elevated);
box-sizing: border-box;
}
.theme-check {
width: 16px;
height: 16px;
border-radius: 50%;
background: var(--accent-primary);
}
.theme-hint {
font-size: 24px;
color: var(--text-secondary);
margin-top: 20px;
.settings-page .modal-title {
display: block;
text-align: center;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 32rpx;
letter-spacing: 0;
}
/* 弹窗复用 address 弹窗和 profile 弹窗样式 */
.avatar-btn {
width: 128rpx;
height: 128rpx;
margin: 0 auto 32rpx;
padding: 0;
border-radius: 50%;
border: 1rpx solid var(--border);
background: var(--bg-input);
line-height: 1;
overflow: hidden;
}
.avatar-img,
.avatar-placeholder-img {
width: 100%;
height: 100%;
}
.nickname-input {
width: 100%;
height: 88rpx;
background: var(--bg-input);
border: 1rpx solid var(--border);
border-radius: 16rpx;
padding: 0 24rpx;
font-size: 28rpx;
color: var(--text-primary);
box-sizing: border-box;
}
.nickname-input::placeholder {
color: var(--text-muted);
font-size: 26rpx;
}
.form-actions {
display: flex;
gap: 20rpx;
margin-top: 32rpx;
}
.form-actions .btn-secondary,
.form-actions .btn-primary {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
height: 80rpx;
font-size: 28rpx;
font-weight: 600;
box-sizing: border-box;
}
+7 -7
View File
@@ -72,12 +72,12 @@ export default function SettingsPage() {
<View className='settings-page'>
<View className='settings-area'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='flex-between' style={{ width: '100%' }}>
<Text className='back-btn' onTap={() => Taro.navigateBack()}></Text>
<Text className='page-title'></Text>
<View style={{ width: '60px' }} />
<View className='page-header settings-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<View className='back-btn' onTap={() => Taro.navigateBack()}>
<Text className='back-arrow'></Text>
</View>
<Text className='page-title'></Text>
<View className='header-spacer' />
</View>
{/* 用户卡片 */}
@@ -91,7 +91,7 @@ export default function SettingsPage() {
<Image className='settings-avatar-icon' src={assetUrl('/icon/个人.png')} mode='aspectFit' />
</View>
)}
<View style={{ marginLeft: '20px' }}>
<View className='settings-meta'>
<Text className='settings-name'>{user.nickName || '未登录'}</Text>
<Text className='settings-id'>ID: {user.openid ? user.openid.slice(-8) : '---'}</Text>
</View>
@@ -140,7 +140,7 @@ export default function SettingsPage() {
</View>
)}
<View style={{ height: '40px' }} />
<View style={{ height: '80rpx' }} />
{/* 编辑弹窗 */}
{showEdit && (
+73 -45
View File
@@ -9,7 +9,7 @@
left: 0;
right: 0;
bottom: 0;
background: rgb(28, 22, 18);
background: var(--bg-page);
}
/* --- Fixed Hero Area --- */
@@ -18,7 +18,7 @@
top: 0;
left: 0;
width: 100%;
height: 65vh; /* hero takes 65% viewport height */
height: 65vh;
z-index: 0;
overflow: hidden;
}
@@ -56,22 +56,22 @@
left: 0;
right: 0;
z-index: 2;
padding: 80rpx 40rpx 24rpx;
padding: 96rpx 40rpx calc(24rpx + env(safe-area-inset-bottom));
display: flex;
flex-direction: column;
gap: 8rpx;
}
.shop-hero-title {
font-size: 40rpx;
font-size: 44rpx;
font-weight: 700;
line-height: 1.3;
color: #f0e6d8;
color: var(--text-primary);
}
.shop-hero-subtitle {
font-size: 22rpx;
color: #b0a395;
font-size: 24rpx;
color: var(--text-secondary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -92,7 +92,7 @@
.shop-hero-original {
font-size: 26rpx;
color: #8a7e72;
color: var(--text-muted);
text-decoration: line-through;
}
@@ -103,7 +103,7 @@
}
.shop-content {
min-height: 100vh; /* ensure scrollability */
min-height: 100vh;
will-change: transform;
}
@@ -113,7 +113,7 @@
position: sticky;
top: 0;
z-index: 4;
padding: 40rpx 40rpx 32rpx;
padding: 24rpx 40rpx 24rpx;
display: flex;
flex-direction: column;
gap: 10rpx;
@@ -122,15 +122,15 @@
}
.shop-band-title {
font-size: 44rpx;
font-size: 40rpx;
font-weight: 700;
line-height: 1.3;
color: #f0e6d8;
color: var(--text-primary);
}
.shop-band-subtitle {
font-size: 24rpx;
color: #b0a395;
color: var(--text-secondary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -144,59 +144,74 @@
}
.shop-band-price {
font-size: 48rpx;
font-size: 40rpx;
font-weight: 700;
color: var(--accent-primary);
}
.shop-band-original {
font-size: 26rpx;
color: #8a7e72;
color: var(--text-muted);
text-decoration: line-through;
}
/* --- Detail Body --- */
.shop-detail-body {
padding: 32rpx 40rpx 60rpx;
padding: 0 32rpx calc(48rpx + env(safe-area-inset-bottom));
will-change: opacity, transform;
box-sizing: border-box;
}
.shop-content-card {
padding: 32rpx;
background: var(--bg-card);
border: 1rpx solid var(--border);
border-radius: 32rpx;
box-shadow: var(--shadow-card);
box-sizing: border-box;
}
.shop-section {
margin-bottom: 32rpx;
}
.shop-section:last-child {
margin-bottom: 0;
}
.shop-section-title {
font-size: 34rpx;
font-weight: 700;
color: #f0e6d8;
margin: 28rpx 0 20rpx;
color: var(--text-primary);
margin: 0 0 20rpx;
display: block;
position: relative;
padding-left: 20rpx;
letter-spacing: 0;
}
.shop-section-title::before {
content: '';
position: absolute;
left: 0;
top: 6rpx;
bottom: 6rpx;
top: 8rpx;
bottom: 8rpx;
width: 6rpx;
border-radius: 4rpx;
background: linear-gradient(180deg, var(--accent-primary), var(--accent-primary-soft));
border-radius: 999rpx;
background: var(--accent-primary);
}
.shop-section-text {
font-size: 28rpx;
color: #c4b8a8;
line-height: 1.75;
color: var(--text-secondary);
line-height: 1.8;
display: block;
}
.shop-divider {
height: 2rpx;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.08), transparent);
margin: 40rpx 0;
height: 1rpx;
background: var(--border);
margin: 32rpx 0;
}
/* --- Tags --- */
@@ -208,10 +223,11 @@
}
.shop-tag {
padding: 10rpx 28rpx;
border-radius: 40rpx;
height: 56rpx;
padding: 0 28rpx;
border-radius: 999rpx;
font-size: 22rpx;
font-weight: 500;
font-weight: 600;
background: var(--accent-primary-soft);
border: 1rpx solid var(--accent-primary);
display: inline-flex;
@@ -226,16 +242,16 @@
/* --- Spec Table --- */
.shop-spec-table {
width: 100%;
border-collapse: collapse;
border-radius: 16rpx;
border: 1rpx solid var(--border);
border-radius: 20rpx;
overflow: hidden;
font-size: 26rpx;
background: var(--bg-muted);
}
.shop-spec-row {
display: flex;
padding: 20rpx 24rpx;
border-bottom: 1rpx solid rgba(255,255,255,0.06);
padding: 24rpx 28rpx;
border-bottom: 1rpx solid var(--border);
}
.shop-spec-row:last-child {
@@ -244,14 +260,16 @@
.shop-spec-key {
width: 35%;
color: #8a7e72;
color: var(--text-muted);
font-weight: 500;
font-size: 24rpx;
}
.shop-spec-val {
flex: 1;
color: #e8e0d6;
color: var(--text-primary);
font-size: 26rpx;
font-weight: 500;
word-break: break-all;
}
@@ -268,11 +286,11 @@
width: 88rpx;
height: 88rpx;
border-radius: 50%;
background: rgba(0, 0, 0, 0.35);
backdrop-filter: blur(16rpx) saturate(1.4);
-webkit-backdrop-filter: blur(16rpx) saturate(1.4);
border: 1rpx solid rgba(255,255,255,0.12);
box-shadow: var(--shadow-card);
background: rgba(40, 35, 32, 0.5);
backdrop-filter: blur(16px) saturate(1.4);
-webkit-backdrop-filter: blur(16px) saturate(1.4);
border: 1rpx solid var(--glass-line);
box-shadow: var(--shadow-elevated);
display: flex;
align-items: center;
justify-content: center;
@@ -285,15 +303,25 @@
.shop-back-arrow {
font-size: 36rpx;
color: rgba(255,255,255,0.85);
color: var(--text-primary);
line-height: 1;
}
/* --- Bottom Action Bar — 样式由全局 .action-bar 提供,本地只补充价格摘要 --- */
.action-bar .price-summary {
/* --- Bottom Action Bar — 毛玻璃由 BottomActionBar 提供,本地只补充价格摘要 --- */
.bottom-action-bar .price-summary {
flex-shrink: 0;
}
.bottom-action-bar .btn-primary,
.bottom-action-bar .btn-secondary {
flex: 1;
text-align: center;
padding: 28rpx 0;
font-size: 28rpx;
font-weight: 600;
line-height: 1.2;
}
.summary-label {
font-size: 22rpx;
color: var(--text-secondary);
+53 -42
View File
@@ -8,6 +8,7 @@ import { useSafeArea } from '../../../hooks/useSafeArea'
import { useStatusBar } from '../../../hooks/useStatusBar'
import { useThemeContext } from '../../../context/ThemeContext'
import ThemedPageMeta from '../../../components/ThemedPageMeta'
import BottomActionBar from '../../../components/BottomActionBar'
const clamp = (v: number, min: number, max: number) => Math.min(Math.max(v, min), max)
const lerp = (a: number, b: number, t: number) => a + (b - a) * t
@@ -210,49 +211,59 @@ export default function ShopDetailPage() {
transform: `translateY(${heroStyles.contentOffset}px)`
}}
>
{product.story && (
<View className="shop-section">
<Text className="shop-section-title"></Text>
<Text className="shop-section-text">{product.story}</Text>
</View>
)}
<View className="shop-divider" />
{product.scene && (
<View className="shop-section">
<Text className="shop-section-title">使</Text>
<Text className="shop-section-text">{product.scene}</Text>
</View>
)}
{product.tags && product.tags.length > 0 && (
<View className="shop-section">
<View className="shop-tag-row">
{product.tags.map(tag => (
<View key={tag} className="shop-tag">
<Text className="shop-tag-text">{tag}</Text>
</View>
))}
<View className="shop-content-card">
{product.story && (
<View className="shop-section">
<Text className="shop-section-title"></Text>
<Text className="shop-section-text">{product.story}</Text>
</View>
</View>
)}
)}
<View className="shop-divider" />
{(product.story && product.scene) && (
<View className="shop-divider" />
)}
{product.specs && product.specs.length > 0 && (
<View className="shop-section">
<Text className="shop-section-title"></Text>
<View className="shop-spec-table">
{product.specs.map(([k, v]) => (
<View key={k} className="shop-spec-row">
<Text className="shop-spec-key">{k}</Text>
<Text className="shop-spec-val">{v}</Text>
</View>
))}
{product.scene && (
<View className="shop-section">
<Text className="shop-section-title">使</Text>
<Text className="shop-section-text">{product.scene}</Text>
</View>
</View>
)}
)}
{product.tags && product.tags.length > 0 && (
<View className="shop-section">
<View className="shop-tag-row">
{product.tags.map(tag => (
<View key={tag} className="shop-tag">
<Text className="shop-tag-text">{tag}</Text>
</View>
))}
</View>
</View>
)}
{((product.story || product.scene) && product.tags && product.tags.length > 0) && (
<View className="shop-divider" />
)}
{((product.story || product.scene || (product.tags && product.tags.length > 0)) && product.specs && product.specs.length > 0) && (
<View className="shop-divider" />
)}
{product.specs && product.specs.length > 0 && (
<View className="shop-section">
<Text className="shop-section-title"></Text>
<View className="shop-spec-table">
{product.specs.map(([k, v]) => (
<View key={k} className="shop-spec-row">
<Text className="shop-spec-key">{k}</Text>
<Text className="shop-spec-val">{v}</Text>
</View>
))}
</View>
</View>
)}
</View>
<View className="shop-bottom-spacer" />
</View>
@@ -268,8 +279,8 @@ export default function ShopDetailPage() {
<Text className="shop-back-arrow"></Text>
</View>
{/* Bottom CTA — 全局毛玻璃 action-bar,沿用 product/checkout 模式 */}
<View className="action-bar">
{/* Bottom CTA — 复用毛玻璃 BottomActionBar */}
<BottomActionBar>
<View className="price-summary">
<Text className="summary-label"></Text>
<Text className="summary-price">¥{product.price}</Text>
@@ -283,7 +294,7 @@ export default function ShopDetailPage() {
<View className="btn-primary" onTap={() => Taro.navigateTo({ url: `/pages/product/index?id=${product.id}` })}>
<Text></Text>
</View>
</View>
</BottomActionBar>
<View className="safe-bottom-placeholder" />
</View>
)
+29 -16
View File
@@ -4,19 +4,19 @@
/* --- List Layer --- */
.shop-list {
padding: 0 24rpx 24rpx;
padding: 0 32rpx 24rpx;
}
.shop-header {
text-align: center;
padding: 40rpx 0 24rpx;
padding: 48rpx 0 32rpx;
}
.shop-header-title {
font-size: 40rpx;
font-weight: 800;
font-size: 44rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 4rpx;
letter-spacing: 0;
display: block;
}
@@ -31,10 +31,11 @@
.shop-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20rpx;
gap: 24rpx;
}
.shop-card {
border: 1rpx solid var(--border);
border-radius: 24rpx;
overflow: hidden;
background: var(--bg-card);
@@ -43,13 +44,13 @@
}
.shop-card:active {
transform: scale(0.97);
transform: scale(0.98);
}
.shop-card-img-wrap {
aspect-ratio: 3 / 4;
aspect-ratio: 1 / 1;
overflow: hidden;
background: #2a2218;
background: var(--bg-muted);
}
.shop-card-img {
@@ -59,27 +60,39 @@
transition: transform 0.4s ease;
}
.shop-card-info {
padding: 16rpx 20rpx 20rpx;
.shop-card-body {
padding: 20rpx 24rpx 24rpx;
}
.shop-card-name {
font-size: 26rpx;
color: #e8e0d6;
font-size: 28rpx;
font-weight: 700;
color: var(--text-primary);
line-height: 1.4;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
min-height: 74rpx;
}
.shop-card-desc {
font-size: 24rpx;
color: var(--text-secondary);
line-height: 1.4;
margin-top: 8rpx;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.shop-card-price {
font-size: 30rpx;
font-size: 32rpx;
font-weight: 700;
color: var(--accent-primary);
margin-top: 10rpx;
margin-top: 12rpx;
display: block;
font-variant: tabular-nums;
}
/* ============================================================
+2 -9
View File
@@ -27,7 +27,6 @@ export default function ShopPage() {
<View className="shop-grid">
{PRODUCTS.map(product => {
const tone = product.tone || [28, 22, 18]
const imageSrc = product.images[0] || product.iconImg || ''
return (
<View
@@ -43,13 +42,9 @@ export default function ShopPage() {
lazyLoad
/>
</View>
<View
className="shop-card-info"
style={{
backgroundColor: `rgba(${tone[0]}, ${tone[1]}, ${tone[2]}, 0.92)`
}}
>
<View className="shop-card-body">
<Text className="shop-card-name">{product.name}</Text>
<Text className="shop-card-desc">{product.desc || ''}</Text>
<Text className="shop-card-price">¥{product.price}</Text>
</View>
</View>
@@ -57,8 +52,6 @@ export default function ShopPage() {
})}
</View>
{/* TabBar spacer so list isn't obscured */}
<View style={{ height: '200px' }} />
</View>
</View>
)
+134 -57
View File
@@ -1,90 +1,140 @@
/* ============================================================
UserDatabase Page — 本地用户数据库
============================================================ */
.udb-page {
padding: 0 24px 40px;
padding: 0 32rpx calc(24rpx + env(safe-area-inset-bottom));
min-height: 100vh;
box-sizing: border-box;
}
/* 锁屏验证 */
.udb-lock-page {
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.udb-lock-card {
display: flex;
flex-direction: column;
align-items: center;
padding: 60px 40px;
padding: 64rpx 40rpx;
text-align: center;
margin-top: 48rpx;
}
.udb-lock-icon {
width: 80px;
height: 80px;
margin-bottom: 24px;
width: 96rpx;
height: 96rpx;
margin-bottom: 24rpx;
}
.udb-lock-title {
font-size: 36px;
display: block;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 12px;
display: block;
margin-bottom: 12rpx;
letter-spacing: 0;
}
.udb-lock-desc {
font-size: 26px;
color: var(--text-secondary);
margin-bottom: 32px;
display: block;
font-size: 26rpx;
line-height: 1.6;
color: var(--text-secondary);
margin-bottom: 32rpx;
}
.udb-password-input {
width: 100%;
height: 80px;
height: 88rpx;
background: var(--bg-input);
border: 1rpx solid var(--border);
border-radius: 16px;
padding: 0 24px;
font-size: 30px;
border-radius: 16rpx;
padding: 0 24rpx;
box-sizing: border-box;
font-size: 30rpx;
color: var(--text-primary);
text-align: center;
margin-bottom: 24px;
box-sizing: border-box;
margin-bottom: 24rpx;
}
.udb-password-input::placeholder {
color: var(--text-muted);
}
.udb-error {
font-size: 24px;
color: var(--danger);
margin-bottom: 20px;
display: block;
font-size: 24rpx;
line-height: 1.5;
color: var(--danger);
margin-bottom: 20rpx;
}
.udb-btn {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 20px 0;
font-size: 30px;
height: 96rpx;
box-sizing: border-box;
font-size: 30rpx;
font-weight: 600;
}
/* 顶部标题 */
.page-header.udb-header {
min-height: 88rpx;
padding-left: 0;
padding-right: 0;
padding-bottom: 24rpx;
margin: 0;
}
.udb-header .page-title {
text-align: center;
font-size: 44rpx;
font-weight: 700;
color: var(--text-primary);
letter-spacing: 0;
}
/* 工具栏 */
.udb-toolbar {
margin: 20px 0;
display: flex;
justify-content: flex-end;
margin: 8rpx 0 24rpx;
}
.udb-add-btn {
padding: 14px 28px;
font-size: 26px;
display: flex;
align-items: center;
justify-content: center;
height: 80rpx;
padding: 0 32rpx;
box-sizing: border-box;
font-size: 26rpx;
font-weight: 600;
}
/* 数据表格 */
.udb-table {
background: var(--bg-card);
border: 1rpx solid var(--border);
border-radius: 24px;
border-radius: 24rpx;
overflow: hidden;
box-shadow: var(--shadow-card);
}
.udb-row {
display: flex;
align-items: center;
padding: 20px 16px;
min-height: 112rpx;
padding: 16rpx 24rpx;
border-bottom: 1rpx solid var(--border);
box-sizing: border-box;
}
.udb-row:last-child {
@@ -93,31 +143,31 @@
.udb-header {
background: var(--bg-input);
padding: 16px;
min-height: 80rpx;
}
.udb-header .udb-col {
font-weight: 700;
font-size: 24px;
font-size: 24rpx;
color: var(--text-primary);
}
.udb-col {
font-size: 24px;
font-size: 24rpx;
color: var(--text-secondary);
flex-shrink: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding: 0 6px;
padding: 0 8rpx;
}
.col-nick {
flex: 0 0 22%;
flex: 0 0 24%;
}
.col-id {
flex: 0 0 36%;
flex: 0 0 32%;
}
.col-stats {
@@ -127,10 +177,12 @@
.col-action {
flex: 1;
min-width: 0;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
gap: 12rpx;
flex-wrap: wrap;
}
.udb-row.active {
@@ -138,11 +190,13 @@
}
.udb-link {
padding: 6px 14px;
border-radius: 8px;
font-size: 22px;
padding: 10rpx 20rpx;
border-radius: 999rpx;
font-size: 22rpx;
line-height: 1.2;
color: var(--accent-secondary);
background: var(--accent-secondary-soft);
font-weight: 600;
}
.udb-danger {
@@ -151,55 +205,78 @@
}
.udb-current {
font-size: 22px;
font-size: 22rpx;
color: var(--accent-secondary);
font-weight: 600;
font-weight: 700;
}
.udb-empty {
padding: 40px;
padding: 80rpx 24rpx;
text-align: center;
color: var(--text-secondary);
font-size: 28px;
font-size: 28rpx;
}
/* 新建账号弹窗 */
.udb-page .modal-overlay {
align-items: center;
justify-content: center;
padding: 48rpx;
z-index: 1000;
}
/* 弹窗 */
.udb-add-card {
padding: 48px 36px;
width: 80%;
width: 100%;
max-width: 640rpx;
padding: 40rpx;
border-radius: 32rpx;
background: var(--bg-card);
border: 1rpx solid var(--border);
box-shadow: var(--shadow-elevated);
box-sizing: border-box;
}
.udb-add-title {
font-size: 32px;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 24px;
display: block;
text-align: center;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 32rpx;
letter-spacing: 0;
}
.udb-add-input {
width: 100%;
height: 80px;
height: 88rpx;
background: var(--bg-input);
border: 1rpx solid var(--border);
border-radius: 16px;
padding: 0 24px;
font-size: 28px;
color: var(--text-primary);
margin-bottom: 32px;
border-radius: 16rpx;
padding: 0 24rpx;
box-sizing: border-box;
font-size: 28rpx;
color: var(--text-primary);
margin-bottom: 32rpx;
}
.udb-add-input::placeholder {
color: var(--text-muted);
}
.udb-add-actions {
display: flex;
align-items: center;
gap: 20px;
gap: 20rpx;
}
.udb-add-actions .btn-secondary,
.udb-add-actions .btn-primary {
flex: 1;
padding: 18px 0;
text-align: center;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
font-weight: 600;
box-sizing: border-box;
}
+3 -3
View File
@@ -86,8 +86,8 @@ export default function UserDatabasePage() {
return (
<View className={`theme-${resolvedTheme}`}>
<ThemedPageMeta />
<View className='udb-page'>
<View className='udb-lock-card surface-card mt-20'>
<View className='udb-page udb-lock-page' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<View className='udb-lock-card surface-card'>
<Image className='udb-lock-icon' src={assetUrl('/icon/账号管理.png')} mode='aspectFit' />
<Text className='udb-lock-title'></Text>
<Text className='udb-lock-desc'>访</Text>
@@ -116,7 +116,7 @@ export default function UserDatabasePage() {
<ThemedPageMeta />
<View className='udb-page'>
<View className='page-header surface-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='page-header udb-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<Text className='page-title'></Text>
</View>
+218 -99
View File
@@ -1,68 +1,125 @@
/* ============================================================
WordCloud Page — AI 词云生成
============================================================ */
.wordcloud-page {
min-height: 100vh;
padding: 0 24px 24px;
padding: 0 32rpx calc(24rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
}
/* 顶部导航 */
.page-header {
padding: calc(env(safe-area-inset-top, 0px) + 44px) 32px 24px;
margin: 20px 0 0;
.page-header.cloud-header {
display: flex;
align-items: center;
gap: 16rpx;
min-height: 88rpx;
padding-left: 0;
padding-right: 0;
padding-bottom: 24rpx;
margin: 0;
background: transparent;
}
.back-btn {
font-size: 40px;
.cloud-header .back-btn {
display: flex;
align-items: center;
justify-content: center;
width: 88rpx;
height: 88rpx;
flex: 0 0 auto;
border-radius: 50%;
background: var(--bg-card);
border: 1rpx solid var(--border-strong);
box-shadow: var(--shadow-card);
box-sizing: border-box;
}
.cloud-header .back-btn:active {
transform: scale(0.96);
}
.cloud-header .back-arrow {
font-size: 36rpx;
line-height: 1;
color: var(--text-primary);
padding: 10px;
}
.cloud-header .page-title {
flex: 1;
min-width: 0;
text-align: center;
font-size: 34rpx;
font-weight: 600;
color: var(--text-primary);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
letter-spacing: 0;
}
.header-spacer {
width: 88rpx;
flex: 0 0 auto;
}
/* 步骤指示器 */
.step-indicator {
display: flex;
align-items: center;
align-items: stretch;
justify-content: center;
padding: 32px;
margin: 0 24px;
padding: 32rpx 16rpx;
margin-bottom: 24rpx;
}
.step-item {
position: relative;
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
flex: 1;
min-width: 0;
}
.step-circle {
width: 64px;
height: 64px;
border-radius: 50%;
background: var(--bg-input);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 12px;
width: 64rpx;
height: 64rpx;
border-radius: 50%;
background: var(--bg-muted);
border: 1rpx solid var(--border);
box-sizing: border-box;
margin-bottom: 12rpx;
transition: background 160ms ease, border-color 160ms ease, box-shadow 160ms ease;
}
.step-circle.active {
background: var(--accent-primary);
border-color: var(--accent-primary);
box-shadow: 0 0 0 8rpx var(--accent-primary-soft);
}
.step-num {
font-size: 28px;
font-size: 28rpx;
font-weight: 700;
line-height: 1;
color: var(--text-muted);
}
.step-circle.active .step-num {
color: #fff;
color: var(--bg-page);
}
.step-label {
font-size: 24px;
max-width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 24rpx;
color: var(--text-secondary);
text-align: center;
}
.step-label.active {
@@ -72,11 +129,12 @@
.step-line {
position: absolute;
top: 30px;
top: 31rpx;
left: 60%;
width: 100%;
height: 4px;
height: 4rpx;
background: var(--bg-input);
border-radius: 999rpx;
}
.step-line.active {
@@ -85,105 +143,144 @@
/* 步骤内容 */
.step-content {
padding: 32px;
padding: 0 0 32rpx;
}
/* 上传区域 */
/* 上传底图 */
.upload-area {
min-height: 400px;
min-height: 420rpx;
display: flex;
align-items: center;
justify-content: center;
border: 1rpx solid var(--border);
border-radius: 24rpx;
overflow: hidden;
}
.upload-placeholder {
display: flex;
flex-direction: column;
align-items: center;
padding: 60px;
padding: 64rpx 48rpx;
text-align: center;
}
.upload-icon {
width: 80px;
height: 80px;
margin-bottom: 24px;
width: 80rpx;
height: 80rpx;
margin-bottom: 24rpx;
}
.upload-title {
font-size: 32px;
font-size: 32rpx;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 12px;
margin-bottom: 12rpx;
letter-spacing: 0;
}
.upload-desc {
font-size: 26px;
font-size: 26rpx;
color: var(--text-secondary);
margin-bottom: 16px;
margin-bottom: 24rpx;
}
.upload-tip {
font-size: 22px;
font-size: 22rpx;
line-height: 1.5;
color: var(--accent-secondary);
background: var(--accent-secondary-soft);
padding: 8px 20px;
padding: 12rpx 24rpx;
border-radius: 999rpx;
border: 1rpx solid var(--border);
}
.preview-image {
width: 100%;
height: 400px;
border-radius: 24px;
height: 420rpx;
border-radius: 24rpx;
}
/* 按钮 */
/* 按钮 */
.action-btns {
display: flex;
flex-direction: column;
gap: 20px;
margin-top: 40px;
gap: 20rpx;
margin-top: 32rpx;
}
/* 输入区域 */
.action-btns .btn-primary,
.action-btns .btn-secondary {
display: flex;
align-items: center;
justify-content: center;
height: 96rpx;
font-size: 30rpx;
font-weight: 600;
box-sizing: border-box;
}
/* 输入名单 */
.input-section {
padding: 32px;
border: 1rpx solid var(--border);
border-radius: 24rpx;
padding: 32rpx;
}
.input-section .section-title {
display: block;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 0;
letter-spacing: 0;
}
.names-input {
width: 100%;
min-height: 300px;
min-height: 320rpx;
background: var(--bg-input);
border-radius: 16px;
padding: 24px;
font-size: 28px;
line-height: 1.6;
box-sizing: border-box;
border: 1rpx solid var(--border);
border-radius: 16rpx;
padding: 24rpx;
margin-top: 24rpx;
box-sizing: border-box;
font-size: 28rpx;
line-height: 1.6;
color: var(--text-primary);
transition: border-color 160ms ease, background 160ms ease, box-shadow 160ms ease;
}
.names-input:focus {
border-color: var(--accent-primary);
background: var(--bg-card);
box-shadow: 0 0 0 6rpx var(--accent-primary-soft);
}
.names-input::placeholder {
color: var(--text-muted);
}
.input-stats {
display: block;
text-align: right;
font-size: 24px;
font-size: 24rpx;
color: var(--text-secondary);
margin-top: 12px;
margin-top: 12rpx;
}
.input-tips {
margin-top: 24px;
margin-top: 24rpx;
padding: 24rpx;
border-radius: 16rpx;
background: var(--bg-muted);
}
.tip-item {
display: block;
font-size: 24px;
font-size: 24rpx;
line-height: 1.6;
color: var(--text-secondary);
margin-bottom: 8px;
margin-bottom: 8rpx;
}
.tip-item:last-child {
margin-bottom: 0;
}
/* 生成中 */
@@ -191,133 +288,155 @@
display: flex;
flex-direction: column;
align-items: center;
padding: 80px 40px;
padding: 96rpx 48rpx;
background: var(--bg-card);
border: 1rpx solid var(--border);
border-radius: 24rpx;
box-shadow: var(--shadow-card);
}
.generating-icon {
width: 120px;
height: 120px;
width: 104rpx;
height: 104rpx;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.2); opacity: 0.7; }
50% { transform: scale(1.12); opacity: 0.72; }
}
.generating-title {
font-size: 40px;
font-size: 36rpx;
font-weight: 700;
color: var(--text-primary);
margin-top: 40px;
margin-top: 32rpx;
letter-spacing: 0;
}
.generating-subtitle {
font-size: 28px;
font-size: 26rpx;
color: var(--text-secondary);
margin-top: 16px;
margin-bottom: 40px;
margin-top: 12rpx;
margin-bottom: 40rpx;
}
.progress-bar {
width: 80%;
height: 16px;
background: var(--accent-primary-soft);
border-radius: 8px;
width: 100%;
height: 12rpx;
background: var(--bg-muted);
border-radius: 999rpx;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: var(--accent-primary);
border-radius: 8px;
border-radius: 999rpx;
transition: width 0.5s ease;
}
.progress-text {
font-size: 32px;
font-size: 30rpx;
font-weight: 700;
color: var(--accent-primary);
margin-top: 16px;
margin-top: 16rpx;
font-variant: tabular-nums;
}
/* 结果面板 */
/* 结果预览 */
.result-panel {
padding: 20px 0;
padding: 0;
}
.result-image-wrapper {
overflow: hidden;
position: relative;
border: 1rpx solid var(--border);
overflow: hidden;
border-radius: 24rpx;
}
.result-image {
width: 100%;
height: 500px;
background: linear-gradient(135deg, var(--accent-primary-soft) 0%, var(--accent-secondary-soft) 100%);
height: 520rpx;
background: var(--bg-muted);
}
.watermark-badge {
position: absolute;
bottom: 20px;
right: 20px;
right: 24rpx;
bottom: 24rpx;
padding: 10rpx 20rpx;
border-radius: 999rpx;
background: var(--glass);
border: 1rpx solid var(--glass-line);
font-size: 22rpx;
color: var(--text-primary);
padding: 8px 20px;
border-radius: 8px;
font-size: 22px;
border: 1rpx solid var(--border);
backdrop-filter: blur(24rpx);
-webkit-backdrop-filter: blur(24rpx);
}
.result-actions {
display: flex;
justify-content: space-around;
margin: 32px 0;
gap: 16rpx;
margin: 24rpx 0 0;
}
.action-btn {
flex: 1;
min-width: 0;
padding: 24rpx 8rpx;
border-radius: 24rpx;
background: var(--bg-card);
border: 1rpx solid var(--border);
box-shadow: var(--shadow-card);
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
gap: 10rpx;
box-sizing: border-box;
}
.action-btn:active {
transform: scale(0.98);
}
.action-icon {
width: 48px;
height: 48px;
margin-bottom: 8px;
width: 44rpx;
height: 44rpx;
}
.action-label {
font-size: 24px;
max-width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 22rpx;
color: var(--text-secondary);
}
/* 跳转DIY卡片 */
/* 跳转DIY卡片(保留旧样式,便于后续扩展) */
.diy-jump-card {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 32px;
margin-bottom: 32rpx;
}
.diy-jump-title {
font-size: 32px;
font-size: 32rpx;
font-weight: 700;
color: var(--text-primary);
display: block;
margin-bottom: 8px;
margin-bottom: 8rpx;
}
.diy-jump-desc {
font-size: 24px;
font-size: 24rpx;
color: var(--text-secondary);
display: block;
}
.diy-jump-arrow {
font-size: 40px;
font-size: 40rpx;
color: var(--accent-primary);
}
+5 -3
View File
@@ -66,10 +66,12 @@ export default function WordCloudPage() {
<ThemedPageMeta />
<View className='wordcloud-page'>
<View className='page-header flex-between' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<Text className='back-btn' onTap={goBack}></Text>
<View className='page-header cloud-header' style={{ paddingTop: `${safe.headerPaddingTop}px` }}>
<View className='back-btn' onTap={goBack}>
<Text className='back-arrow'></Text>
</View>
<Text className='page-title'>AI词云生成</Text>
<View style={{ width: '60px' }} />
<View className='header-spacer' />
</View>
{/* 步骤指示器 */}
+529
View File
@@ -0,0 +1,529 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>TabBar 指示器调试器</title>
<style>
:root {
--bg-page: #faf7f2;
--bg-card: #ffffff;
--text: #2e2622;
--text-2: #8a7e76;
--border: #ede5dc;
--accent: #d96c6a;
--glass: rgba(255, 255, 255, 0.55);
--glass-line: rgba(255, 255, 255, 0.55);
--shadow: rgba(46, 38, 34, 0.18);
--ind: rgba(0, 0, 0, 0.12);
}
html.theme-dark {
--bg-page: #191919;
--bg-card: #23201d;
--text: #f5efe8;
--text-2: #b3a79c;
--border: #37312c;
--accent: #f09198;
--glass: rgba(25, 25, 25, 0.55);
--glass-line: rgba(255, 255, 255, 0.14);
--shadow: rgba(0, 0, 0, 0.5);
--ind: rgba(255, 255, 255, 0.16);
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
background: var(--bg-page);
color: var(--text);
min-height: 100vh;
transition: background .2s, color .2s;
}
.appbar {
position: sticky;
top: 0;
z-index: 5;
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
flex-wrap: wrap;
padding: 16px 24px;
background: var(--bg-card);
border-bottom: 1px solid var(--border);
}
.appbar h1 { margin: 0; font-size: 18px; font-weight: 700; letter-spacing: 0; }
.actions { display: flex; gap: 8px; flex-wrap: wrap; }
button {
font: inherit;
border: 1px solid var(--border);
background: var(--bg-card);
color: var(--text);
border-radius: 999px;
padding: 8px 16px;
cursor: pointer;
font-size: 13px;
}
button.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
button:active { transform: scale(0.98); }
.layout {
display: grid;
grid-template-columns: minmax(280px, 380px) 1fr;
gap: 24px;
max-width: 1080px;
margin: 0 auto;
padding: 24px;
}
.controls {
display: flex;
flex-direction: column;
gap: 12px;
align-self: start;
padding: 18px;
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 16px;
}
.group-title { font-size: 13px; font-weight: 700; margin: 4px 0 8px; letter-spacing: 0; }
.group { border-top: 1px solid var(--border); padding-top: 12px; }
.field { margin-bottom: 12px; }
.field label {
display: flex;
justify-content: space-between;
font-size: 13px;
color: var(--text-2);
margin-bottom: 6px;
}
.field output { color: var(--accent); font-variant-numeric: tabular-nums; }
input[type=range] { width: 100%; accent-color: var(--accent); }
.output { margin-top: 4px; }
.output .group-title { display: flex; justify-content: space-between; align-items: center; }
.output textarea {
width: 100%;
min-height: 118px;
resize: vertical;
font: 11px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
border: 1px solid var(--border);
border-radius: 10px;
padding: 10px;
background: var(--bg-page);
color: var(--text);
}
.hint { font-size: 12px; color: var(--text-2); margin: 6px 0 0; line-height: 1.5; }
.preview { display: flex; align-items: center; justify-content: center; }
.phone {
width: min(100%, 380px);
aspect-ratio: 9 / 18.5;
border-radius: 44px;
background: var(--bg-card);
box-shadow: 0 24px 60px var(--shadow);
padding: 12px;
}
.screen {
position: relative;
width: 100%;
height: 100%;
border-radius: 34px;
overflow: hidden;
background: var(--bg-page);
}
.feed {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: flex;
flex-direction: column;
gap: 12px;
padding: 52px 24px 220px;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
touch-action: pan-y;
scrollbar-width: none;
-ms-overflow-style: none;
}
.feed::-webkit-scrollbar { display: none; }
.card {
flex: 0 0 auto;
padding: 10px;
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 14px;
display: flex;
flex-direction: column;
gap: 7px;
}
.img { height: 86px; border-radius: 10px; }
.g1 { background: linear-gradient(145deg, #e08e8b, #7c8bd6); }
.g2 { background: linear-gradient(205deg, #67c58e, #d9a35e); }
.g3 { background: linear-gradient(120deg, #d96c6a, #e6c08a); }
.g4 { background: linear-gradient(160deg, #8e97e8, #5faa8a); }
.ln {
height: 9px;
border-radius: 6px;
background: var(--text-2);
opacity: 0.35;
}
.w90 { width: 90%; }
.w85 { width: 85%; }
.w80 { width: 80%; }
.w75 { width: 75%; }
.w70 { width: 70%; }
.w65 { width: 65%; }
.w60 { width: 60%; }
.w55 { width: 55%; }
.w50 { width: 50%; }
.w45 { width: 45%; }
.w40 { width: 40%; }
.tiles { display: flex; gap: 8px; }
.t { width: 44px; height: 44px; border-radius: 12px; flex: 0 0 auto; }
.t1 { background: #e07a72; }
.t2 { background: #6c7bdb; }
.t3 { background: #4fa477; }
.t4 { background: #d9a35e; }
.t5 { background: #8e97e8; }
.gradient {
position: absolute;
left: 0;
right: 0;
bottom: 0;
pointer-events: none;
}
.pill {
position: absolute;
display: flex;
align-items: center;
justify-content: space-around;
border-radius: 28px;
background: var(--glass);
border: 1px solid var(--glass-line);
backdrop-filter: blur(32px) saturate(1.2);
-webkit-backdrop-filter: blur(32px) saturate(1.2);
box-shadow: 0 12px 40px var(--shadow);
}
.tab {
position: relative;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 2px;
min-width: 0;
color: var(--text-2);
font-size: 10px;
}
.tab.active { color: var(--accent); font-weight: 700; }
.tab svg, .tab > span { position: relative; z-index: 1; }
.tab svg { width: 22px; height: 22px; }
.ind {
position: absolute;
background: var(--ind);
}
@media (max-width: 760px) {
.layout { grid-template-columns: 1fr; }
}
</style>
</head>
<body class="theme-light">
<header class="appbar">
<h1>TabBar 指示器调试器</h1>
<div class="actions">
<button id="themeBtn">切换到深色</button>
<button id="copyCss" type="button">复制 SCSS</button>
<button id="copyJson" class="primary" type="button">复制参数</button>
</div>
</header>
<main class="layout">
<section class="controls" aria-label="参数调节">
<div class="group">
<div class="group-title">选中指示器</div>
<div class="field">
<label>高度 <output id="vIndHeight">50</output> px</label>
<input id="indHeight" type="range" min="8" max="64" step="1" value="50">
</div>
<div class="field">
<label>左右贴边 <output id="vIndSide">-18</output> px</label>
<input id="indSide" type="range" min="-20" max="30" step="1" value="-18">
</div>
<div class="field">
<label>底部贴边 <output id="vIndBottom">3</output> px</label>
<input id="indBottom" type="range" min="-20" max="20" step="1" value="3">
</div>
<div class="field">
<label>圆角 <output id="vIndRadius">25</output> px</label>
<input id="indRadius" type="range" min="0" max="40" step="1" value="25">
</div>
<div class="field">
<label>宽度 <output id="vIndWidth">60</output> px</label>
<input id="indWidth" type="range" min="0" max="160" step="1" value="60">
</div>
<div class="field">
<label>不透明度 <output id="vIndOpacity">14</output> %</label>
<input id="indOpacity" type="range" min="0" max="100" step="1" value="14">
</div>
<div class="field">
<label>阴影模糊 <output id="vIndBlur">3</output> px</label>
<input id="indBlur" type="range" min="0" max="30" step="1" value="3">
</div>
<div class="field">
<label>底色 <output id="vIndColor">#000000</output></label>
<input id="indColor" type="color" value="#000000">
</div>
</div>
<div class="output">
<div class="group">
<div class="group-title">导出的参数</div>
<textarea id="jsonOut" readonly aria-label="导出的参数"></textarea>
</div>
<p class="hint">点「复制参数」把 JSON 发给我;点「复制 SCSS」得到可直接落地的样式代码。</p>
</div>
</section>
<section class="preview" aria-label="预览">
<div class="phone">
<div class="screen">
<div class="feed">
<div class="card"><div class="img g1"></div><div class="ln w80"></div><div class="ln w55"></div></div>
<div class="card"><div class="img g2"></div><div class="ln w70"></div><div class="ln w45"></div></div>
<div class="card">
<div class="ln w90"></div><div class="ln w60"></div><div class="ln w75"></div>
</div>
<div class="card">
<div class="tiles"><i class="t t1"></i><i class="t t2"></i><i class="t t3"></i></div>
<div class="ln w65"></div>
</div>
<div class="card"><div class="img g3"></div><div class="ln w80"></div><div class="ln w50"></div></div>
<div class="card">
<div class="ln w85"></div><div class="ln w60"></div><div class="ln w40"></div>
</div>
<div class="card"><div class="img g4"></div><div class="ln w75"></div></div>
<div class="card">
<div class="tiles"><i class="t t4"></i><i class="t t5"></i></div>
<div class="ln w70"></div>
</div>
</div>
<div class="gradient" id="gradient"></div>
<div class="pill" id="pill"></div>
</div>
</div>
</section>
</main>
<script>
const TABS = [
['首页', '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="m3 10 9-7 9 7"/><path d="M5 9v11h14V9"/><path d="M9 20v-6h6v6"/></svg>'],
['商品', '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8 12 3 3 8v8l9 5 9-5Z"/><path d="M3.5 7.5 12 12l8.5-4.5"/><path d="M12 22V12"/></svg>'],
['设计', '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22a10 10 0 1 1 10-10c0 2.21-1.79 4-4 4h-2a2 2 0 0 0-2 2c0 .53.2 1 .54 1.36C14.78 21.4 13.5 22 12 22Z"/><circle cx="7.5" cy="10.5" r="1"/><circle cx="12" cy="7.5" r="1"/><circle cx="16.5" cy="10.5" r="1"/></svg>'],
['订单', '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z"/><path d="M3 6h18"/><path d="M16 10a4 4 0 0 1-8 0"/></svg>'],
['我的', '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="8" r="4"/><path d="M4 21s1-5 8-5 8 5 8 5"/></svg>']
]
const ids = {
indHeight: document.getElementById('indHeight'),
indSide: document.getElementById('indSide'),
indBottom: document.getElementById('indBottom'),
indRadius: document.getElementById('indRadius'),
indWidth: document.getElementById('indWidth'),
indOpacity: document.getElementById('indOpacity'),
indBlur: document.getElementById('indBlur'),
indColor: document.getElementById('indColor'),
gradient: document.getElementById('gradient'),
pill: document.getElementById('pill'),
indicator: document.getElementById('indicator')
}
const val = (el) => Number(el.value)
function hexToRgb(hex) {
const h = hex.replace('#', '')
return {
r: parseInt(h.substring(0, 2), 16),
g: parseInt(h.substring(2, 4), 16),
b: parseInt(h.substring(4, 6), 16)
}
}
function themeColors() {
return document.body.classList.contains('theme-dark')
? { r: 25, g: 25, b: 25, label: 'dark' }
: { r: 250, g: 247, b: 242, label: 'light' }
}
function buildPill() {
ids.pill.innerHTML = TABS.map((t, i) =>
'<div class="tab' + (i === 0 ? ' active' : '') + '">' +
(i === 0 ? '<div class="ind" id="indicator"></div>' : '') +
t[1] + '<span>' + t[0] + '</span></div>'
).join('')
ids.indicator = document.getElementById('indicator')
}
function currentParams() {
const c = themeColors()
return {
theme: c.label,
gradient: {
height: 80,
bottomOpacity: 50,
midStop: 50,
midOpacity: 10,
endStop: 86
},
tabBar: {
bottom: 18,
sideMargin: 18,
height: 58,
radius: 32
},
indicator: {
width: val(ids.indWidth),
height: val(ids.indHeight),
sideInset: val(ids.indSide),
bottomInset: val(ids.indBottom),
radius: val(ids.indRadius),
opacity: val(ids.indOpacity),
blur: val(ids.indBlur),
color: ids.indColor.value
}
}
}
function render() {
const c = themeColors()
const p = currentParams()
const g = p.gradient
const tb = p.tabBar
const ind = p.indicator
const mid = Math.max(g.midStop, 1)
const end = Math.max(g.endStop, mid + 1)
const arr = [
'rgba(' + c.r + ',' + c.g + ',' + c.b + ',' + (g.bottomOpacity / 100).toFixed(3) + ') 0%',
'rgba(' + c.r + ',' + c.g + ',' + c.b + ',' + (g.midOpacity / 100).toFixed(3) + ') ' + mid + '%',
'rgba(' + c.r + ',' + c.g + ',' + c.b + ',0) ' + end + '%'
]
ids.gradient.style.height = g.height + 'px'
ids.gradient.style.background = 'linear-gradient(to top, ' + arr.join(', ') + ')'
ids.pill.style.bottom = tb.bottom + 'px'
ids.pill.style.left = tb.sideMargin + 'px'
ids.pill.style.right = tb.sideMargin + 'px'
ids.pill.style.height = tb.height + 'px'
ids.pill.style.borderRadius = tb.radius + 'px'
const rgb = hexToRgb(ind.color)
const alpha = (ind.opacity / 100).toFixed(3)
ids.indicator.style.bottom = ind.bottomInset + 'px'
ids.indicator.style.height = ind.height + 'px'
ids.indicator.style.borderRadius = ind.radius + 'px'
ids.indicator.style.background = 'rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', ' + alpha + ')'
ids.indicator.style.boxShadow = ind.blur > 0
? '0 0 ' + ind.blur + 'px rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', ' + (alpha / 2) + ')'
: 'none'
if (ind.width > 0) {
ids.indicator.style.width = ind.width + 'px'
ids.indicator.style.left = '50%'
ids.indicator.style.right = 'auto'
ids.indicator.style.transform = 'translateX(-50%)'
} else {
ids.indicator.style.width = 'auto'
ids.indicator.style.left = ind.sideInset + 'px'
ids.indicator.style.right = ind.sideInset + 'px'
ids.indicator.style.transform = 'none'
}
document.getElementById('vIndHeight').textContent = ind.height
document.getElementById('vIndSide').textContent = ind.sideInset
document.getElementById('vIndBottom').textContent = ind.bottomInset
document.getElementById('vIndRadius').textContent = ind.radius
document.getElementById('vIndWidth').textContent = ind.width
document.getElementById('vIndOpacity').textContent = ind.opacity
document.getElementById('vIndBlur').textContent = ind.blur
document.getElementById('vIndColor').textContent = ind.color
document.getElementById('jsonOut').value = JSON.stringify(p, null, 2)
}
function scssSnippet() {
const c = themeColors()
const p = currentParams()
const col = c.label === 'dark' ? '25, 25, 25' : '250, 247, 242'
const rpx = (v) => Math.round(v * 2)
const ind = p.indicator
const irgb = hexToRgb(ind.color)
const indLines = []
if (ind.width > 0) {
indLines.push(' width: ' + rpx(ind.width) + 'rpx;')
indLines.push(' left: 50%;')
indLines.push(' transform: translateX(-50%);')
} else {
indLines.push(' left: ' + rpx(ind.sideInset) + 'rpx;')
indLines.push(' right: ' + rpx(ind.sideInset) + 'rpx;')
}
indLines.push(' bottom: ' + rpx(ind.bottomInset) + 'rpx;')
indLines.push(' height: ' + rpx(ind.height) + 'rpx;')
indLines.push(' border-radius: ' + rpx(ind.radius) + 'rpx;')
indLines.push(' background: rgba(' + irgb.r + ', ' + irgb.g + ', ' + irgb.b + ', ' + (ind.opacity / 100).toFixed(2) + ');')
if (ind.blur > 0) {
indLines.push(' box-shadow: 0 0 ' + rpx(ind.blur) + 'rpx rgba(' + irgb.r + ', ' + irgb.g + ', ' + irgb.b + ', ' + ((ind.opacity / 100) / 2).toFixed(2) + ');')
}
return [
'/* ' + c.label + ' theme */',
'.tab-bar-root.' + c.label + ' .tab-bar-gradient {',
' height: ' + rpx(p.gradient.height) + 'rpx;',
' background: linear-gradient(to top,',
' rgba(' + col + ', ' + (p.gradient.bottomOpacity / 100).toFixed(2) + ') 0%,',
' rgba(' + col + ', ' + (p.gradient.midOpacity / 100).toFixed(2) + ') ' + p.gradient.midStop + '%,',
' rgba(' + col + ', 0) ' + p.gradient.endStop + '%',
' );',
'}',
'.custom-tab-bar {',
' bottom: ' + rpx(p.tabBar.bottom) + 'rpx;',
' left: ' + rpx(p.tabBar.sideMargin) + 'rpx;',
' right: ' + rpx(p.tabBar.sideMargin) + 'rpx;',
' height: ' + rpx(p.tabBar.height) + 'rpx;',
' border-radius: ' + rpx(p.tabBar.radius) + 'rpx;',
'}',
'.tab-indicator {',
indLines.join('\n'),
'}'
].join('\n')
}
function copy(text) {
if (navigator.clipboard && navigator.clipboard.writeText) {
return navigator.clipboard.writeText(text)
}
const ta = document.createElement('textarea')
ta.value = text
document.body.appendChild(ta)
ta.select()
document.execCommand('copy')
document.body.removeChild(ta)
return Promise.resolve()
}
document.getElementById('themeBtn').addEventListener('click', () => {
const dark = document.body.classList.toggle('theme-dark')
document.getElementById('themeBtn').textContent = dark ? '切换到浅色' : '切换到深色'
render()
})
document.getElementById('copyJson').addEventListener('click', () => {
copy(JSON.stringify(currentParams(), null, 2)).then(() => { alert('参数已复制') })
})
document.getElementById('copyCss').addEventListener('click', () => {
copy(scssSnippet()).then(() => { alert('SCSS 已复制') })
})
Object.keys(ids).forEach((k) => {
if (k === 'gradient' || k === 'pill' || k === 'indicator') return
ids[k].addEventListener('input', render)
})
buildPill()
render()
</script>
</body>
</html>