feat: 添加预算管理功能,支持分类预算和重置周期设置,优化用户界面

This commit is contained in:
2025-12-02 17:50:26 +08:00
parent fae5a408ff
commit 82fc35b7c9
8 changed files with 517 additions and 58 deletions

View File

@@ -0,0 +1,101 @@
<script setup>
import { computed } from 'vue'
const props = defineProps({
modelValue: {
type: [String, Number],
default: '',
},
label: {
type: String,
default: '',
},
placeholder: {
type: String,
default: '',
},
type: {
type: String,
default: 'text',
},
inputmode: {
type: String,
default: '',
},
step: {
type: [String, Number],
default: undefined,
},
disabled: {
type: Boolean,
default: false,
},
error: {
type: String,
default: '',
},
hint: {
type: String,
default: '',
},
inputClass: {
type: String,
default: '',
},
})
const emit = defineEmits(['update:modelValue', 'blur', 'focus', 'enter'])
const hasError = computed(() => !!props.error)
const handleInput = (event) => {
emit('update:modelValue', event.target.value)
}
const handleKeydown = (event) => {
if (event.key === 'Enter') {
emit('enter', event)
}
}
</script>
<template>
<div class="w-full">
<label v-if="label" class="block">
<span class="text-xs font-bold text-stone-400">{{ label }}</span>
<div
class="mt-2 flex items-center gap-2 rounded-2xl border px-4 py-3 bg-white/80"
:class="
hasError
? 'border-rose-300 shadow-sm shadow-rose-100'
: 'border-stone-200 focus-within:border-stone-400'
"
>
<slot name="prefix" />
<input
:type="type"
:inputmode="inputmode || undefined"
:step="step"
:placeholder="placeholder"
:disabled="disabled"
:value="modelValue"
class="flex-1 bg-transparent text-sm text-stone-800 placeholder:text-stone-300 focus:outline-none"
:class="inputClass"
@input="handleInput"
@blur="$emit('blur', $event)"
@focus="$emit('focus', $event)"
@keydown="handleKeydown"
/>
<slot name="suffix" />
</div>
</label>
<p v-if="hasError" class="mt-1 text-[11px] text-rose-500 font-bold">
{{ error }}
</p>
<p v-else-if="hint" class="mt-1 text-[11px] text-stone-400">
{{ hint }}
</p>
</div>
</template>