feat: 用户信息完善 + 一起记功能
- users 表添加 nickname、avatar_url 字段 - 用户信息 API(GET/PUT /me)+ 头像上传(multer) - 头像通过 API 路由获取(公开,不经过 auth) - 登录接口返回用户昵称和头像 - 用户信息 Store + 个人资料编辑页面 - 我的页面和首页显示真实用户信息 - 群组表(groups、group_members)+ transactions 添加 group_id - 群组 API(创建/加入/退出/解散) - 交易和统计 API 支持 group_id 视图切换 - 群组客户端 Store + 身份切换 - 群组管理页面 - App 初始化群组 Store - UPLOAD_DIR 配置化 - Node.js 备份替代 mysqldump - 统一前端 BASE_URL(config.ts) - uploads 加入 .gitignore - 修复 trust proxy 警告
This commit is contained in:
@@ -4,7 +4,10 @@
|
||||
<text class="key-text">{{ key }}</text>
|
||||
</view>
|
||||
<view class="key fn" @tap="onDelete">
|
||||
<Icon name="trash" :size="36" color="#FF8C69" />
|
||||
<view class="backspace-icon">
|
||||
<view class="backspace-arrow"></view>
|
||||
<view class="backspace-line"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="key eq" @tap="onConfirm">
|
||||
<Icon name="check" :size="36" color="#FFFFFF" />
|
||||
@@ -13,26 +16,71 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import Icon from '@/components/Icon/Icon.vue'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
/** 金额字符串(v-model) */
|
||||
modelValue?: string
|
||||
/** 最大金额(元) */
|
||||
max?: number
|
||||
}>(), {
|
||||
modelValue: '',
|
||||
max: 9999999.99
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: string): void
|
||||
(e: 'confirm'): void
|
||||
}>()
|
||||
|
||||
const keys = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '0', '00']
|
||||
|
||||
const emit = defineEmits(['input', 'delete', 'confirm'])
|
||||
const amountStr = computed(() => props.modelValue)
|
||||
|
||||
function vibrate() {
|
||||
try {
|
||||
uni.vibrateShort({ type: 'light' })
|
||||
} catch {}
|
||||
try { uni.vibrateShort({ type: 'light' }) } catch {}
|
||||
}
|
||||
|
||||
function emitValue(val: string) {
|
||||
emit('update:modelValue', val)
|
||||
}
|
||||
|
||||
function onKeyTap(key: string) {
|
||||
vibrate()
|
||||
emit('input', key)
|
||||
const current = amountStr.value
|
||||
|
||||
if (key === '.') {
|
||||
if (current.includes('.')) return
|
||||
if (!current) { emitValue('0.'); return }
|
||||
}
|
||||
|
||||
let next: string
|
||||
if (!current || current === '0') {
|
||||
next = (key === '0' || key === '00') ? '0' : key
|
||||
} else {
|
||||
next = current + key
|
||||
}
|
||||
|
||||
if (next.includes('.')) {
|
||||
const decimals = next.split('.')[1]
|
||||
if (decimals && decimals.length > 2) return
|
||||
}
|
||||
if (next.length > 10) return
|
||||
const num = parseFloat(next)
|
||||
if (!isNaN(num) && num > props.max) return
|
||||
|
||||
emitValue(next)
|
||||
}
|
||||
|
||||
function onDelete() {
|
||||
vibrate()
|
||||
emit('delete')
|
||||
const current = amountStr.value
|
||||
if (current.length > 1) {
|
||||
emitValue(current.slice(0, -1))
|
||||
} else {
|
||||
emitValue('')
|
||||
}
|
||||
}
|
||||
|
||||
function onConfirm() {
|
||||
@@ -57,9 +105,7 @@ function onConfirm() {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:active {
|
||||
background: #F0E0D6;
|
||||
}
|
||||
&:active { background: #F0E0D6; }
|
||||
}
|
||||
|
||||
.key-text {
|
||||
@@ -71,18 +117,41 @@ function onConfirm() {
|
||||
|
||||
.key.fn {
|
||||
background: #FFE8E0;
|
||||
|
||||
&:active {
|
||||
background: #FFD0C0;
|
||||
}
|
||||
&:active { background: #FFD0C0; }
|
||||
}
|
||||
|
||||
.key.eq {
|
||||
background: linear-gradient(135deg, #FF8C69, #E67355);
|
||||
box-shadow: 0 4rpx 16rpx rgba(255, 140, 105, 0.3);
|
||||
&:active { background: #E67355; }
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: #E67355;
|
||||
}
|
||||
// 自绘 backspace 图标
|
||||
.backspace-icon {
|
||||
width: 40rpx;
|
||||
height: 28rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.backspace-arrow {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
width: 16rpx;
|
||||
height: 16rpx;
|
||||
border-left: 4rpx solid #FF8C69;
|
||||
border-bottom: 4rpx solid #FF8C69;
|
||||
transform: translateY(-50%) rotate(45deg);
|
||||
}
|
||||
|
||||
.backspace-line {
|
||||
position: absolute;
|
||||
left: 12rpx;
|
||||
top: 50%;
|
||||
width: 26rpx;
|
||||
height: 4rpx;
|
||||
background: #FF8C69;
|
||||
transform: translateY(-50%);
|
||||
border-radius: 2rpx;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user