This commit is contained in:
2026-03-31 22:08:05 +08:00
parent 648423c177
commit 4138340f53
8 changed files with 740 additions and 35 deletions
@@ -29,7 +29,9 @@ function toggleTheme() {
}
function toggleLocale() {
locale.value = locale.value === "zh-CN" ? "en" : "zh-CN";
const newLocale = locale.value === "zh-CN" ? "en" : "zh-CN";
locale.value = newLocale;
localStorage.setItem('locale', newLocale);
}
function isActive(path) {
@@ -48,12 +48,31 @@ function getsele() {
console.log('Using $toCanvas method')
try {
const result = await cro_canv.value.$toCanvas()
console.log('$toCanvas result:', result ? 'Received data URL' : 'Empty result')
console.log('$toCanvas result type:', typeof result, 'value:', result)
// 检查结果类型,如果是Canvas元素则转换为data URL
if (result) {
emit('crop-data-url', result)
return // 成功,结束函数
let dataUrl
if (result instanceof HTMLCanvasElement) {
// 如果是Canvas对象,转换为data URL
console.log('Converting HTMLCanvasElement to data URL')
dataUrl = result.toDataURL('image/jpeg', 0.9)
} else if (typeof result === 'string' && result.startsWith('data:image/')) {
// 如果已经是data URL,直接使用
dataUrl = result
} else {
// 其他情况,不直接发送
console.warn('$toCanvas returned unexpected type:', typeof result)
throw new Error('Unexpected return type from $toCanvas')
}
if (dataUrl) {
console.log('Generated data URL from $toCanvas, length:', dataUrl.length)
emit('crop-data-url', dataUrl)
return // 成功,结束函数
}
}
console.log('$toCanvas returned empty, falling back to manual crop')
console.log('$toCanvas returned empty or invalid result, falling back to manual crop')
} catch (error) {
console.warn('$toCanvas failed, using manual crop:', error.message)
}
@@ -175,7 +194,14 @@ function getsele() {
// 生成data URLJPEG格式,质量0.9
const dataUrl = outputCanvas.toDataURL('image/jpeg', 0.9)
console.log('Generated crop data URL, length:', dataUrl.length)
emit('crop-data-url', dataUrl)
// 确保我们发送的是有效的data URL字符串
if (typeof dataUrl === 'string' && dataUrl.startsWith('data:image/')) {
emit('crop-data-url', dataUrl)
} else {
console.error('Invalid data URL generated:', typeof dataUrl)
emit('crop-error', '生成的数据URL无效')
}
} catch (error) {
console.error('Crop process error:', error)
+3 -1
View File
@@ -206,7 +206,9 @@
"avatar_unsaved": "Avatar changes not saved",
"optional": "Optional",
"birthday_help": "Select your birthday for personalized services",
"save_notice": "Your personal information will be updated after saving"
"save_notice": "Your personal information will be updated after saving",
"placeholder_name": "Enter your name",
"placeholder_remark": "Personal introduction or remark"
},
"button": {
"submit": "Submit",
+3 -1
View File
@@ -206,7 +206,9 @@
"avatar_unsaved": "头像修改未保存",
"optional": "选填",
"birthday_help": "选择您的生日,用于个性化服务",
"save_notice": "保存后将更新您的个人信息"
"save_notice": "保存后将更新您的个人信息",
"placeholder_name": "请输入您的姓名",
"placeholder_remark": "个人简介或备注"
},
"button": {
"submit": "提交",
+3 -2
View File
@@ -6,8 +6,9 @@ import router from './router'
import './assets/main.css'
// Initialize theme
// Initialize theme and locale from localStorage
const savedTheme = localStorage.getItem('theme') // 改用 'theme' key
const savedLocale = localStorage.getItem('locale')
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
if (savedTheme === 'dark' || (!savedTheme && prefersDark)) {
@@ -21,7 +22,7 @@ import zhCN from './i18n/zh-CN.json'
const i18n = createI18n({
legacy: false,
locale: 'en',
locale: savedLocale || 'en', // 使用已保存的语言或默认英文
fallbackLocale: 'en',
messages: {
en,
@@ -24,15 +24,29 @@ const form = reactive({
const avatarHasChanged = ref(false)
const avatarDataUrl = ref('')
const loading = ref(false)
const birthdayInput = ref(null)
onMounted(() => {
if (userStore.user) {
form.username = userStore.user.Username || ''
form.remark = userStore.user.FirstName || ''
if (userStore.user || userStore.userInfo) {
// 姓名从 userInfo.Username 获取
form.username = userStore.userInfo?.Username || userStore.user?.Name || ''
// 备注从 userInfo.FirstName 获取
form.remark = userStore.userInfo?.FirstName || ''
// 生日从 userStore.birthday getter 获取(已转换格式)
form.birthday = userStore.birthday
}
})
function openDatePicker() {
// 使用showPicker API打开日期选择器
if (birthdayInput.value && birthdayInput.value.showPicker) {
birthdayInput.value.showPicker()
} else {
// 对于不支持showPicker的老浏览器,聚焦输入框
birthdayInput.value?.focus()
}
}
function handleCrop(dataUrl) {
avatarHasChanged.value = true
avatarDataUrl.value = dataUrl
@@ -158,14 +172,14 @@ async function handleSave() {
<span class="ml-1 text-red-500">*</span>
</label>
<div class="relative">
<input
v-model="form.username"
type="text"
placeholder="请输入您的姓名"
class="w-full rounded-lg border bg-white px-4 py-3 text-sm outline-none transition-all focus:ring-2 dark:bg-gray-900 dark:text-white"
:class="errors.username ? 'border-red-500 focus:border-red-500 focus:ring-red-500/20' : 'border-gray-300 focus:border-blue-500 focus:ring-blue-500/20 dark:border-gray-700'"
/>
<div class="absolute right-3 top-3">
<input
v-model="form.username"
type="text"
:placeholder="t('settings.placeholder_name')"
class="w-full rounded-lg border bg-white px-4 py-3 text-sm outline-none transition-all focus:ring-2 dark:bg-gray-900 dark:text-white"
:class="errors.username ? 'border-red-500 focus:border-red-500 focus:ring-red-500/20' : 'border-gray-300 focus:border-blue-500 focus:ring-blue-500/20 dark:border-gray-700'"
/>
<div class="absolute right-3 top-3 pointer-events-none">
<svg class="h-5 w-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</svg>
@@ -177,17 +191,17 @@ async function handleSave() {
<div class="space-y-2">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">
{{ t('settings.remark') }}
<span class="ml-1 text-gray-400">({{ t('settings.optional') }})</span>
<span class="ml-1 text-red-500">*</span>
</label>
<div class="relative">
<input
v-model="form.remark"
type="text"
placeholder="个人简介或备注"
class="w-full rounded-lg border bg-white px-4 py-3 text-sm outline-none transition-all focus:ring-2 dark:bg-gray-900 dark:text-white"
:class="errors.remark ? 'border-red-500 focus:border-red-500 focus:ring-red-500/20' : 'border-gray-300 focus:border-blue-500 focus:ring-blue-500/20 dark:border-gray-700'"
/>
<div class="absolute right-3 top-3">
<input
v-model="form.remark"
type="text"
:placeholder="t('settings.placeholder_remark')"
class="w-full rounded-lg border bg-white px-4 py-3 text-sm outline-none transition-all focus:ring-2 dark:bg-gray-900 dark:text-white"
:class="errors.remark ? 'border-red-500 focus:border-red-500 focus:ring-red-500/20' : 'border-gray-300 focus:border-blue-500 focus:ring-blue-500/20 dark:border-gray-700'"
/>
<div class="absolute right-3 top-3 pointer-events-none">
<svg class="h-5 w-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M7 8h10M7 12h4m1 8l-4-4H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-3l-4 4z" />
</svg>
@@ -207,13 +221,15 @@ async function handleSave() {
<input
v-model="form.birthday"
type="date"
class="w-full rounded-lg border bg-white px-4 py-3 text-sm outline-none transition-all focus:ring-2 dark:bg-gray-900 dark:text-white"
class="w-full cursor-pointer rounded-lg border bg-white px-4 py-3 text-sm outline-none transition-all focus:ring-2 dark:bg-gray-900 dark:text-white"
:class="errors.birthday ? 'border-red-500 focus:border-red-500 focus:ring-red-500/20' : 'border-gray-300 focus:border-blue-500 focus:ring-blue-500/20 dark:border-gray-700'"
@click="openDatePicker"
ref="birthdayInput"
/>
<div class="absolute right-3 top-3">
<svg class="h-5 w-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<div class="absolute right-3 top-3 pointer-events-none">
<!-- <svg class="h-5 w-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
</svg> -->
</div>
</div>
<span v-if="errors.birthday" class="block text-xs text-red-500">{{ errors.birthday }}</span>