ux(ui): beginner-friendly guidance across trainee/admin flows + fix AdminUsers to username

- Chat: add 'How to practice' guide card; render revealed persona as readable
  label:value grid instead of JSON.
- AdminUsers: switch create form to username (matches username login), add step guide,
  role explanation (user=ฝึก, admin=ดูแลระบบ).
- Analytics (admin overview) + MyBoard (personal): add plain-Thai explainer subtitle.
- Rebuild dist. Verified user create with username -> 201.
This commit is contained in:
Macky
2026-08-08 10:34:24 +07:00
parent 39d1aa04e4
commit 22d3e51980
29 changed files with 103 additions and 38 deletions

View File

@@ -1,23 +1,38 @@
<template>
<div>
<h2>{{ i18n.t('users') }}</h2>
<h2>👥 {{ i18n.t('users') }}</h2>
<div class="card guide">
<strong>📋 เพมผใชงาน</strong>
<ol style="margin:8px 0 0;padding-left:20px;line-height:1.8">
<li>กรอก <strong>อผใช (สำหรบเขาสระบบ)</strong>, , และรหสผานเรมต</li>
<li>เลอกสทธ: <strong>user</strong> = เขาฝกขาย, <strong>admin</strong> = ดการระบบ</li>
<li>กด <strong>สราง</strong> นำชอผใช + รหสผานไปแจงใหใชนเขาสระบบไดเลย</li>
</ol>
</div>
<div class="card" style="margin-bottom:16px">
<h4>+ {{ i18n.t('create') }} user</h4>
<h4 style="margin-top:0"> {{ i18n.t('create') }} {{ i18n.t('users').toLowerCase() }}</h4>
<div class="row">
<input v-model="form.name" placeholder="Name" style="flex:1" />
<input v-model="form.email" placeholder="Email" style="flex:1" />
<input v-model="form.password" type="password" placeholder="Temp password" style="flex:1" />
<input v-model="form.username" placeholder="ชื่อผู้ใช้ (เข้าสู่ระบบ)" style="flex:1" />
<input v-model="form.name" placeholder="ชื่อจริง" style="flex:1" />
<input v-model="form.password" type="password" placeholder="รหัสผ่านเริ่มต้น" style="flex:1" />
</div>
<div class="row" style="margin-top:10px">
<select v-model="form.role" style="flex:1">
<option value="user">user</option>
<option value="admin">admin</option>
<option value="user">🙂 user เขาฝ</option>
<option value="admin">🛠 admin แลระบบ</option>
</select>
<button class="primary" @click="create">{{ i18n.t('create') }}</button>
<button class="primary" @click="create" :disabled="!form.username || !form.password"> {{ i18n.t('create') }}</button>
</div>
<div class="error" v-if="error">{{ error }}</div>
</div>
<div v-if="users.length === 0" class="card empty-state">
<strong>งไมใชงาน</strong><span>สรางผใชงานคนแรกดวยฟอรมดานบน</span>
</div>
<div class="card" v-for="u in users" :key="u.id" style="margin-bottom:8px;display:flex;align-items:center;gap:12px">
<strong style="flex:1">{{ u.name }} ({{ u.email }})</strong>
<strong style="flex:1">{{ u.name }} ({{ u.username }})</strong>
<span class="badge">{{ u.role }}</span>
<span class="badge" :class="u.active ? 'won' : 'lost'">{{ u.active ? 'active' : 'inactive' }}</span>
</div>
@@ -31,16 +46,20 @@ import { i18n } from '../i18n'
const users = ref([])
const error = ref('')
const form = ref({ name: '', email: '', password: '', role: 'user' })
const form = ref({ username: '', name: '', password: '', role: 'user' })
async function load() { users.value = (await api.adminListUsers()).users }
async function create() {
error.value = ''
try {
await api.adminCreateUser({ ...form.value })
form.value = { name: '', email: '', password: '', role: 'user' }
form.value = { username: '', name: '', password: '', role: 'user' }
await load()
} catch (e) { error.value = e.message }
}
onMounted(load)
</script>
<style scoped>
.guide { background: #eef2ff; border-color: #c7d2fe; margin-bottom: 16px; }
</style>