@import '@/src/styles/theme.scss'; @mixin page-shell { height: 100vh; background: $color-bg-page; display: flex; flex-direction: column; overflow: hidden; } @mixin scroll-body { flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 24rpx $page-padding-x 0; } @mixin card { background: $color-card; border-radius: $radius-lg; box-shadow: $shadow-card; } @mixin section-title { font-size: 32rpx; font-weight: 600; color: $color-text; } @mixin icon-box($size: 72rpx) { width: $size; height: $size; border-radius: $radius-md; background: $color-primary-bg; display: flex; align-items: center; justify-content: center; flex-shrink: 0; } // 区块标题行(左侧标题 + 右侧「更多」) @mixin block-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20rpx; } // 应用模块卡片的彩色渐变图标底 @mixin tint-icon($size: 96rpx, $radius: 24rpx) { width: $size; height: $size; border-radius: $radius; display: flex; align-items: center; justify-content: center; flex-shrink: 0; } // 小标签(功能 chip / 状态徽标) @mixin chip($bg: $color-primary-bg, $color: $color-primary) { display: inline-flex; align-items: center; padding: 6rpx 16rpx; border-radius: $radius-full; background: $bg; color: $color; font-size: 22rpx; line-height: 1.6; } // ============ 弹层宽屏自适应(全局约定,新弹层直接复用即可,无需逐页调) ============ // 用法:铺满式遮罩根元素内 `@include mask-responsive;`,其底部面板内 `@include sheet-responsive;` // 手机竖屏(<560px)不命中,行为不变;宽屏下遮罩仍铺满做暗色背景,面板收敛为居中手机列宽。 @mixin mask-responsive { @media (min-width: 560px) { justify-content: center; } } @mixin sheet-responsive($w: 560px) { @media (min-width: 560px) { max-width: $w; } } // ============ 审批流时间线 ============ // 头像(姓名首字)+ 右下状态角标 + 姓名/说明 + 时间 + 意见气泡,节点之间虚线连接。 // 用法:页面 scoped 样式里 `@include flow-timeline;`,根节点用 .timeline-list, // 每个节点用 .tl-item(.tl-rail / .tl-avatar-wrap / .tl-avatar / .tl-badge / .tl-line / .tl-main ...)。 @mixin flow-timeline { .timeline-list { display: flex; flex-direction: column; padding: 4rpx 0 8rpx; } .tl-item { display: flex; gap: 20rpx; &.current .tl-name { color: $color-primary; } &.edge .tl-name { font-weight: 500; } } .tl-rail { width: 76rpx; flex-shrink: 0; display: flex; flex-direction: column; align-items: center; } .tl-avatar-wrap { position: relative; width: 72rpx; height: 72rpx; flex-shrink: 0; } .tl-avatar { width: 72rpx; height: 72rpx; border-radius: 16rpx; background: linear-gradient(135deg, #60a5fa, #2563eb); color: #ffffff; font-size: 30rpx; font-weight: 600; display: flex; align-items: center; justify-content: center; &.avatar-end { background: linear-gradient(135deg, #cbd5e1, #94a3b8); } } .tl-badge { position: absolute; right: -10rpx; bottom: -10rpx; box-sizing: border-box; min-width: 32rpx; height: 32rpx; padding: 0 6rpx; border-radius: 16rpx; border: 4rpx solid #ffffff; display: flex; align-items: center; justify-content: center; font-size: 20rpx; line-height: 1; color: #ffffff; &.badge-pass { background: #16a34a; } &.badge-running { background: #f59e0b; } &.badge-reject { background: #ef4444; } &.badge-skip { background: #94a3b8; } } .tl-line { flex: 1; width: 0; margin-top: 8rpx; border-left: 2rpx dashed #cbd5e1; } .tl-main { flex: 1; min-width: 0; padding-bottom: 36rpx; } .tl-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16rpx; } .tl-title { flex: 1; min-width: 0; } .tl-name { font-size: 30rpx; font-weight: 600; color: $color-text; } .tl-sub { display: block; margin-top: 4rpx; font-size: 24rpx; color: $color-text-muted; } .tl-time { flex-shrink: 0; font-size: 24rpx; color: $color-text-muted; } .tl-comment { margin-top: 16rpx; padding: 20rpx 22rpx; background: #f1f5f9; border-radius: 12rpx; font-size: 26rpx; color: $color-text-secondary; line-height: 1.6; word-break: break-all; } } // 居中弹窗(非贴底):宽屏下把固定定位的遮罩面板限制为列宽并水平+垂直居中 @mixin dialog-responsive($w: 560px) { @media (min-width: 560px) { max-width: $w; left: 50%; transform: translateX(-50%); } }