feat 搭建架构骨架

This commit is contained in:
Ironsp
2026-09-24 09:09:47 +08:00
parent dd9f6b77a4
commit 7a2efa3fea
180 changed files with 18967 additions and 9 deletions

View File

@@ -0,0 +1,179 @@
<script setup lang="ts">
import { ref, watch } from 'vue'
import type { PayMethod } from '@/types/business/finance'
interface Props {
method: PayMethod
}
const props = defineProps<Props>()
const visible = defineModel<boolean>('visible', { default: false })
const emit = defineEmits<{ confirm: [method: PayMethod] }>()
const selected = ref<PayMethod>(props.method)
watch(
() => props.method,
(value) => {
selected.value = value
},
)
watch(visible, (open) => {
if (open) selected.value = props.method
})
function onConfirm(): void {
emit('confirm', selected.value)
visible.value = false
}
function onCancel(): void {
visible.value = false
}
</script>
<template>
<Teleport to="body">
<div v-if="visible" class="pay-method-dialog" @click.self="onCancel">
<div class="pay-method-dialog__panel">
<h3 class="pay-method-dialog__title">
切换支付方式
</h3>
<label
class="pay-method-dialog__option"
:class="{ 'is-active': selected === 'wechat' }"
>
<input
v-model="selected"
type="radio"
value="wechat"
class="pay-method-dialog__radio"
>
<span class="pay-method-dialog__name">微信支付</span>
<span class="pay-method-dialog__tip text-secondary">推荐使用</span>
</label>
<label
class="pay-method-dialog__option"
:class="{ 'is-active': selected === 'alipay' }"
>
<input
v-model="selected"
type="radio"
value="alipay"
class="pay-method-dialog__radio"
>
<span class="pay-method-dialog__name">支付宝支付</span>
<span class="pay-method-dialog__tip text-secondary">其他用户选择</span>
</label>
<div class="pay-method-dialog__footer">
<button class="pay-method-dialog__btn" @click="onCancel">
取消
</button>
<button class="pay-method-dialog__btn pay-method-dialog__btn--confirm" @click="onConfirm">
确认
</button>
</div>
</div>
</div>
</Teleport>
</template>
<style lang="less" scoped>
.pay-method-dialog {
position: fixed;
inset: 0;
z-index: 1000;
.flex(row, center);
background: rgba(0, 0, 0, 0.45);
&__panel {
width: 420px;
max-width: calc(100vw - 32px);
padding: @spacing-lg;
border-radius: @radius-lg;
background: @white;
box-shadow: @shadow-lg;
}
&__title {
margin-bottom: @spacing-base;
font-size: @font-size-lg;
font-weight: 600;
color: @heading-color;
}
&__option {
.flex(row, flex-start, center);
gap: @spacing-sm;
padding: @spacing-base;
margin-bottom: @spacing-sm;
border: 1px solid @border-color;
border-radius: @radius-base;
cursor: pointer;
transition: all 0.2s;
&:hover {
border-color: @primary-color;
}
&.is-active {
border-color: @primary-color;
background: @primary-light;
}
}
&__radio {
accent-color: @primary-color;
}
&__name {
font-size: @font-size-base;
color: @heading-color;
font-weight: 500;
}
&__tip {
margin-left: auto;
font-size: @font-size-sm;
}
&__footer {
.flex(row, flex-end);
gap: @spacing-sm;
margin-top: @spacing-base;
}
&__btn {
height: 34px;
padding: 0 @spacing-base;
border: 1px solid @border-color-dark;
border-radius: @radius-base;
background: @white;
color: @text-color;
font-size: @font-size-base;
transition: all 0.2s;
&:hover {
border-color: @primary-color;
color: @primary-color;
}
&--confirm {
border-color: @primary-color;
background: @primary-color;
color: @white;
&:hover {
background: @primary-hover;
color: @white;
}
}
}
}
</style>