refactor: migrate wechat to user attributes and enhance users list

Migrate the hardcoded wechat field to the new extensible user
attributes system and improve the users management UI.

Migration:
- Add migration 019 to move wechat data to user_attribute_values
- Remove wechat field from User entity, DTOs, and API contracts
- Clean up wechat-related code from backend and frontend

UsersView enhancements:
- Add text labels to action buttons (Filter Settings, Column Settings,
  Attributes Config) for better UX
- Change status column to show colored dot + Chinese text instead of
  English text
- Add dynamic attribute columns support with batch loading
- Add column visibility settings with localStorage persistence
- Add filter settings modal for search and filter preferences
- Update i18n translations

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Edric Li
2026-01-01 18:59:38 +08:00
parent f44cf642bc
commit 404bf0f8d2
30 changed files with 1390 additions and 462 deletions

View File

@@ -89,25 +89,6 @@
</svg>
<span class="truncate">{{ user.username }}</span>
</div>
<div
v-if="user?.wechat"
class="flex items-center gap-3 text-sm text-gray-600 dark:text-gray-400"
>
<svg
class="h-4 w-4 text-gray-400 dark:text-gray-500"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="1.5"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M8.625 12a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0H8.25m4.125 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0H12m4.125 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0h-.375M21 12c0 4.556-4.03 8.25-9 8.25a9.764 9.764 0 01-2.555-.337A5.972 5.972 0 015.41 20.97a5.969 5.969 0 01-.474-.065 4.48 4.48 0 00.978-2.025c.09-.457-.133-.901-.467-1.226C3.93 16.178 3 14.189 3 12c0-4.556 4.03-8.25 9-8.25s9 3.694 9 8.25z"
/>
</svg>
<span class="truncate">{{ user.wechat }}</span>
</div>
</div>
</div>
</div>
@@ -170,19 +151,6 @@
/>
</div>
<div>
<label for="wechat" class="input-label">
{{ t('profile.wechat') }}
</label>
<input
id="wechat"
v-model="profileForm.wechat"
type="text"
class="input"
:placeholder="t('profile.enterWechat')"
/>
</div>
<div class="flex justify-end pt-4">
<button type="submit" :disabled="updatingProfile" class="btn btn-primary">
{{ updatingProfile ? t('profile.updating') : t('profile.updateProfile') }}
@@ -338,8 +306,7 @@ const passwordForm = ref({
})
const profileForm = ref({
username: '',
wechat: ''
username: ''
})
const changingPassword = ref(false)
@@ -354,7 +321,6 @@ onMounted(async () => {
// Initialize profile form with current user data
if (user.value) {
profileForm.value.username = user.value.username || ''
profileForm.value.wechat = user.value.wechat || ''
}
} catch (error) {
console.error('Failed to load contact info:', error)
@@ -407,8 +373,7 @@ const handleUpdateProfile = async () => {
updatingProfile.value = true
try {
const updatedUser = await userAPI.updateProfile({
username: profileForm.value.username,
wechat: profileForm.value.wechat
username: profileForm.value.username
})
// Update auth store with new user data