refactor: AppStack极简化为direction+gap,响应式方向由使用页传入
This commit is contained in:
parent
6cfb3b2f93
commit
bf5e826bbe
@ -3,27 +3,17 @@ import { computed } from 'vue'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
/** 主轴方向;默认纵向 */
|
||||
/** 单行横向 / 单列纵向;默认纵向。响应式由使用处自行决定传 row 还是 column */
|
||||
direction?: 'row' | 'column'
|
||||
/**
|
||||
* 子项间距。兼容三种写法:
|
||||
* - token 名:space-3 / space-4 / space-5 …
|
||||
* - 纯数字字符串:'12' → 12px
|
||||
* - 其它 CSS 值:'12px 16px'、'var(--space-3)' 等原样透传
|
||||
* 缺省:纵向 space-5(20px),横向 space-4(16px)
|
||||
* 子项间距:token 名(space-3…)或纯数字字符串('12' → 12px)。
|
||||
* 缺省:纵向 space-5(20px)、横向 space-4(16px)。
|
||||
*/
|
||||
gap?: string
|
||||
/** 交叉轴对齐 */
|
||||
align?: 'start' | 'center' | 'end' | 'stretch' | 'baseline'
|
||||
/** 主轴对齐 */
|
||||
justify?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'
|
||||
/** 是否允许换行(横向时使用) */
|
||||
wrap?: boolean
|
||||
}>(),
|
||||
{ direction: 'column', gap: '', align: 'stretch', justify: 'start', wrap: false }
|
||||
{ direction: 'column', gap: '' }
|
||||
)
|
||||
|
||||
/** token 名 / 纯数字 → 兼容的 CSS gap;其它原样透传 */
|
||||
const gapStyle = computed(() => {
|
||||
const raw = props.gap.trim()
|
||||
if (!raw) return props.direction === 'row' ? 'var(--space-4)' : 'var(--space-5)'
|
||||
@ -36,12 +26,7 @@ const gapStyle = computed(() => {
|
||||
<template>
|
||||
<div
|
||||
class="app-stack"
|
||||
:class="{
|
||||
'app-stack--row': direction === 'row',
|
||||
'app-stack--wrap': wrap,
|
||||
[`app-stack--align-${align}`]: align !== 'stretch',
|
||||
[`app-stack--justify-${justify}`]: justify !== 'start'
|
||||
}"
|
||||
:class="{ 'app-stack--row': direction === 'row' }"
|
||||
:style="{ '--stack-gap': gapStyle }"
|
||||
>
|
||||
<slot />
|
||||
@ -49,6 +34,7 @@ const gapStyle = computed(() => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* 默认样式:纵向、stretch、start;特殊布局由使用页绑 class 覆盖 */
|
||||
.app-stack {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -60,34 +46,4 @@ const gapStyle = computed(() => {
|
||||
.app-stack--row {
|
||||
flex-direction: row;
|
||||
}
|
||||
.app-stack--wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.app-stack--align-center {
|
||||
align-items: center;
|
||||
}
|
||||
.app-stack--align-start {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.app-stack--align-end {
|
||||
align-items: flex-end;
|
||||
}
|
||||
.app-stack--align-baseline {
|
||||
align-items: baseline;
|
||||
}
|
||||
.app-stack--justify-center {
|
||||
justify-content: center;
|
||||
}
|
||||
.app-stack--justify-end {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.app-stack--justify-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.app-stack--justify-around {
|
||||
justify-content: space-around;
|
||||
}
|
||||
.app-stack--justify-evenly {
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -120,7 +120,12 @@ async function confirmRemove() {
|
||||
|
||||
<template v-else>
|
||||
<!-- 最近成绩 / 目标分差 / 较上次变化 -->
|
||||
<section class="mock-page__stats">
|
||||
<AppStack
|
||||
class="mock-page__stats"
|
||||
:class="{ 'is-col': isMobile }"
|
||||
:direction="isMobile ? 'column' : 'row'"
|
||||
gap="space-4"
|
||||
>
|
||||
<StatCard
|
||||
label="最近成绩"
|
||||
:value="`${latest?.total ?? 0} 分`"
|
||||
@ -143,7 +148,7 @@ async function confirmRemove() {
|
||||
:tone="deltaTone"
|
||||
:sub-tone="deltaTone"
|
||||
/>
|
||||
</section>
|
||||
</AppStack>
|
||||
|
||||
<!-- 成绩趋势 -->
|
||||
<AppCard title="行测成绩趋势" icon="chart">
|
||||
@ -158,10 +163,10 @@ async function confirmRemove() {
|
||||
<AppCard title="模块均分对比" icon="chart">
|
||||
<ul class="mock-page__modules">
|
||||
<li v-for="m in moduleAverages" :key="m.module" class="mock-page__module">
|
||||
<div class="mock-page__module-head">
|
||||
<AppStack direction="row" class="mock-page__module-head">
|
||||
<span class="mock-page__module-name">{{ m.module }}</span>
|
||||
<strong class="mock-page__module-value">{{ m.average }}<small> 分</small></strong>
|
||||
</div>
|
||||
</AppStack>
|
||||
<div class="mock-page__module-track">
|
||||
<span class="mock-page__module-fill" :style="{ width: `${Math.min(100, m.average)}%` }" />
|
||||
</div>
|
||||
@ -186,14 +191,14 @@ async function confirmRemove() {
|
||||
</div>
|
||||
<p v-if="r.note" class="mock-page__record-note">{{ r.note }}</p>
|
||||
</div>
|
||||
<div class="mock-page__record-actions">
|
||||
<AppStack direction="row" gap="space-1" class="mock-page__record-actions">
|
||||
<AppButton variant="ghost" size="md" @click="goEdit(r)">
|
||||
<AppIcon name="pen" :size="15" />编辑
|
||||
</AppButton>
|
||||
<AppButton variant="ghost" size="md" class="is-danger" @click="removing = r">
|
||||
<AppIcon name="close" :size="15" />删除
|
||||
</AppButton>
|
||||
</div>
|
||||
</AppStack>
|
||||
</li>
|
||||
</ul>
|
||||
</AppCard>
|
||||
@ -206,22 +211,22 @@ async function confirmRemove() {
|
||||
确定要删除「{{ removing.name }}({{ formatDateShort(removing.date) }},{{ removing.total }} 分)」吗?删除后趋势与模块分析将同步更新,且不可恢复。
|
||||
</p>
|
||||
<template #footer>
|
||||
<div class="mock-page__confirm-actions">
|
||||
<AppStack direction="row" gap="space-3" class="mock-page__confirm-actions">
|
||||
<AppButton variant="ghost" @click="removing = null">取消</AppButton>
|
||||
<AppButton variant="danger" :loading="deleting" @click="confirmRemove">
|
||||
{{ deleting ? '删除中…' : '确认删除' }}
|
||||
</AppButton>
|
||||
</div>
|
||||
</AppStack>
|
||||
</template>
|
||||
</AppModal>
|
||||
</AppStack>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.mock-page__stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--space-4);
|
||||
/* PC 横向等宽(移动端 is-col 时自然撑满不限制高度) */
|
||||
.mock-page__stats:not(.is-col) > :deep(*) {
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
}
|
||||
.mock-page__sub {
|
||||
margin: 0 0 var(--space-3);
|
||||
@ -245,7 +250,6 @@ async function confirmRemove() {
|
||||
gap: var(--space-4);
|
||||
}
|
||||
.mock-page__module-head {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
margin-bottom: var(--space-2);
|
||||
@ -335,8 +339,6 @@ async function confirmRemove() {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.mock-page__record-actions {
|
||||
display: flex;
|
||||
gap: var(--space-1);
|
||||
flex: none;
|
||||
}
|
||||
.mock-page__record-actions .is-danger {
|
||||
@ -349,15 +351,10 @@ async function confirmRemove() {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.mock-page__confirm-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.mock-page__stats {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.mock-page__record {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user