upload project source code

This commit is contained in:
2026-04-30 18:49:43 +08:00
commit 9b394ba682
2277 changed files with 660945 additions and 0 deletions

View File

@@ -0,0 +1,248 @@
<template>
<view class="userinfo-screen">
<view class="userinfo-bg"></view>
<view class="status-bar-placeholder"></view>
<view class="userinfo-header">
<view class="userinfo-back-btn" @click="handleBack">
<text class="userinfo-back-icon"></text>
</view>
<text class="userinfo-title">我的信息</text>
<view class="userinfo-header-placeholder"></view>
</view>
<scroll-view scroll-y class="userinfo-content">
<view class="userinfo-inner">
<view class="userinfo-section">
<text class="userinfo-label">用户名</text>
<input
v-model="username"
class="userinfo-input"
type="text"
maxlength="32"
placeholder="请输入用户名"
/>
</view>
<view class="userinfo-section userinfo-section-mt">
<text class="userinfo-label">手机号</text>
<input
v-model="mobile"
class="userinfo-input"
type="tel"
maxlength="11"
placeholder="请输入手机号"
/>
</view>
<view class="userinfo-save" @click="handleSave">
<text class="userinfo-save-text">{{ saving ? "保存中…" : "保存" }}</text>
</view>
</view>
</scroll-view>
</view>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { getUserInfo, setUserInfo } from "@/utils/auth";
import { userApi } from "@/api";
declare const uni: any;
const emit = defineEmits<{
back: [];
}>();
const username = ref("");
const mobile = ref("");
const saving = ref(false);
const isValidPhone = (phone: string) => /^1[3-9]\d{9}$/.test(phone);
const loadFromStorage = () => {
const info = getUserInfo();
if (!info || typeof info !== "object") return;
const u = info as Record<string, unknown>;
username.value = String(
u.username ?? u.name ?? ""
).trim();
mobile.value = String(u.mobile ?? u.phone ?? "").trim();
};
onMounted(() => {
loadFromStorage();
});
const handleBack = () => {
emit("back");
};
const handleSave = async () => {
const name = username.value.trim();
const tel = mobile.value.trim();
if (!name) {
uni.showToast({ title: "请输入用户名", icon: "none" });
return;
}
if (!tel) {
uni.showToast({ title: "请输入手机号", icon: "none" });
return;
}
if (!isValidPhone(tel)) {
uni.showToast({ title: "请输入正确的手机号", icon: "none" });
return;
}
if (saving.value) return;
saving.value = true;
try {
await userApi.updateCurrentUserUsernameMobile({
username: name,
mobile: tel,
});
// 仅把表单结果合并进已有 userInfo不把接口 data 整包写入,避免覆盖/清空头像、id 等字段
const prev = getUserInfo();
if (!prev || typeof prev !== "object") {
uni.showToast({ title: "登录状态异常,请重新登录", icon: "none" });
return;
}
setUserInfo({
...prev,
nickname: name,
name: name,
username: name,
mobile: tel,
phone: tel,
});
uni.showToast({ title: "已保存", icon: "success" });
} catch (e: any) {
uni.showToast({
title: e?.msg || e?.message || "保存失败,请稍后重试",
icon: "none",
});
} finally {
saving.value = false;
}
};
</script>
<style scoped>
.userinfo-screen {
height: 100%;
display: flex;
flex-direction: column;
background-color: #f0efe9;
position: relative;
}
.status-bar-placeholder {
height: var(--status-bar-height, 0);
width: 100%;
flex-shrink: 0;
}
.userinfo-bg {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
pointer-events: none;
opacity: 0.3;
background-image: url("https://www.transparenttextures.com/patterns/rice-paper.png");
}
.userinfo-header {
position: relative;
z-index: 10;
height: 88rpx;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 32rpx;
border-bottom: 1rpx solid #dcd3c9;
background-color: rgba(253, 251, 247, 0.8);
backdrop-filter: blur(10rpx);
}
.userinfo-back-btn {
width: 64rpx;
height: 64rpx;
display: flex;
align-items: center;
justify-content: center;
margin-left: -16rpx;
}
.userinfo-back-icon {
font-size: 48rpx;
color: #5a5a5a;
font-weight: 300;
}
.userinfo-title {
font-size: 32rpx;
font-weight: 700;
color: #2c2c2c;
letter-spacing: 0.2em;
}
.userinfo-header-placeholder {
width: 64rpx;
}
.userinfo-content {
flex: 1;
height: 0;
position: relative;
z-index: 10;
}
.userinfo-inner {
padding: 32rpx;
}
.userinfo-section {
background-color: #fffdf9;
border-radius: 24rpx;
border: 1rpx solid #e5e5e5;
padding: 24rpx 32rpx;
}
.userinfo-section-mt {
margin-top: 24rpx;
}
.userinfo-label {
display: block;
font-size: 24rpx;
color: #888;
margin-bottom: 16rpx;
}
.userinfo-input {
width: 100%;
font-size: 30rpx;
color: #2c2c2c;
border: none;
background: transparent;
padding: 0;
}
.userinfo-save {
margin-top: 48rpx;
height: 88rpx;
border-radius: 44rpx;
background: linear-gradient(135deg, #8b7355, #6b5344);
display: flex;
align-items: center;
justify-content: center;
}
.userinfo-save-text {
font-size: 30rpx;
color: #fffdf9;
font-weight: 600;
letter-spacing: 0.15em;
}
</style>