refactor(scenario): only 2 scenarios (social / face-to-face); 're-contact' becomes a persona trait

- Scenario picker now has only social + f2f_call (removed recontact) in backend
  _scenarios, start_session validation, and Chat.vue picker.
- 'ลูกค้ากลับมาติดต่อ' is no longer a scenario: it's now a PERSONA trait. Persona prompt
  generates ~1-in-4 personas with recontact=true (asked before, now returns warmer/ready);
  store shape gets recontact field; simulator injects a re-contact note into the persona's
  system prompt so it plays as a returning customer naturally.
- test_scenario updated: unknown scenario defaults to social; recontact shown as a
  generated persona trait.
All 9 backend suites pass. Rebuilt dist.
This commit is contained in:
Macky
2026-08-09 11:21:34 +07:00
parent cb2642a659
commit fd2cae9e62
35 changed files with 54 additions and 48 deletions

View File

@@ -51,16 +51,6 @@ def _scenarios(locale: str = "th"):
else "คุณต้องเป็นฝ่ายเปิดการสนทนาเชิงรุกกับลีด (ผู้ฝึกทักก่อน) โทนเหมือนคุยสด" else "คุณต้องเป็นฝ่ายเปิดการสนทนาเชิงรุกกับลีด (ผู้ฝึกทักก่อน) โทนเหมือนคุยสด"
), ),
}, },
"recontact": {
"label": "Re-contact (1-3 months later)" if not t else "ลูกค้ากลับมาติดต่อ (1-3 เดือน)",
"init": "customer",
"preamble": "⏳ 1-3 months passed... this customer previously got your info, now re-contacts, more ready to decide." if not t else "⏳ 1-3 เดือนผ่านไป... ลูกค้าคนนี้เคยได้รับข้อมูลสินค้าไปแล้ว ตอนนี้กลับมาติดต่อคุณอีกครั้ง (พร้อมตัดสินใจมากขึ้น)",
"adapt": (
"You researched this seller 1-3 months ago and now re-contact, more ready to decide."
if not t
else "เคยได้รับข้อมูลไปแล้ว ตอนนี้กลับมาติดต่อ พร้อมตัดสินใจมากขึ้น"
),
},
} }
@@ -157,7 +147,7 @@ def start_session(gid: str, pid: str):
# Scenario chosen by the trainee at chat start (not baked into the persona). # Scenario chosen by the trainee at chat start (not baked into the persona).
body = request.get_json(silent=True) or {} body = request.get_json(silent=True) or {}
scenario = (body.get("scenario") or "social").strip().lower() scenario = (body.get("scenario") or "social").strip().lower()
if scenario not in ("social", "f2f_call", "recontact"): if scenario not in ("social", "f2f_call"):
scenario = "social" scenario = "social"
locale = (body.get("locale") or "th").strip().lower() locale = (body.get("locale") or "th").strip().lower()
if locale not in ("en", "th"): if locale not in ("en", "th"):

View File

@@ -25,6 +25,10 @@ EACH persona MUST include ALL of these fields:
- tolerance (1-5): how many irritant/poor answers you tolerate before you walk away ("heart"). IMPORTANT: - tolerance (1-5): how many irritant/poor answers you tolerate before you walk away ("heart"). IMPORTANT:
a temperamental/impatient persona has LOW tolerance (1-2, walks away fast after poor answers); a patient a temperamental/impatient persona has LOW tolerance (1-2, walks away fast after poor answers); a patient
one has HIGH (4-5). Avg is 3. Match tolerance to personality (e.g. a busy owner / abrupt personality = low). one has HIGH (4-5). Avg is 3. Match tolerance to personality (e.g. a busy owner / abrupt personality = low).
- recontact (true/false): if true, this persona asked about the product BEFORE (earlier contact, e.g. a few
weeks/months back) and is ONLY NOW coming back / re-opening, more ready to buy and less price-sensitive.
These are already-pre-qualified, warmer leads. Make about 1 in every 4 personas recontact=true, spread across tiers.
A recontact persona opener/small-talk often references "I asked about this before" naturally.
RULES: RULES:
1. DIVERSITY: 15 distinct people across age groups, occupations, incomes, lifestyles, 1. DIVERSITY: 15 distinct people across age groups, occupations, incomes, lifestyles,

View File

@@ -101,8 +101,15 @@ class Simulator:
adapt = scenario_adapt or { adapt = scenario_adapt or {
"social": "Chat style: short, casual, quick social-messaging replies.", "social": "Chat style: short, casual, quick social-messaging replies.",
"f2f_call": "Style: natural, conversational like a live face-to-face or phone talk.", "f2f_call": "Style: natural, conversational like a live face-to-face or phone talk.",
"recontact": "Style: casual messaging; you already know the product from 1-3 months ago.",
}.get(scenario, "") }.get(scenario, "")
# Personality trait: a "recontact" customer asked about this before and is only now
# coming back, already warmer / more ready to buy. Reference it in chat naturally.
if persona.get("recontact"):
adapt += (
"\nYou contacted/interacted with this seller BEFORE (earlier contact) and are now "
"coming back — you already know the product basics, so you're warmer and more ready "
"to decide. Mention this naturally (e.g. 'I asked about this a while back')."
)
tolerance = int(persona.get("tolerance", 3) or 3) tolerance = int(persona.get("tolerance", 3) or 3)
system = CHAT_SYSTEM.format( system = CHAT_SYSTEM.format(
name=persona.get("name", "Customer"), name=persona.get("name", "Customer"),

View File

@@ -43,6 +43,7 @@ def ensure_persona_shape(p: dict[str, Any]) -> dict[str, Any]:
"negotiation_levers": p.get("negotiation_levers", []), "negotiation_levers": p.get("negotiation_levers", []),
"opener": p.get("opener", ""), "opener": p.get("opener", ""),
"special": p.get("special", ""), # e.g. "wrong_text" | "" "special": p.get("special", ""), # e.g. "wrong_text" | ""
"recontact": bool(p.get("recontact")), # returned after researching earlier (pre-qualified, warm)
"difficulty": p.get("difficulty", 1), # 1..5 "difficulty": p.get("difficulty", 1), # 1..5
"tolerance": p.get("tolerance", 3), # misses before this persona walks away (temper) "tolerance": p.get("tolerance", 3), # misses before this persona walks away (temper)
"notes": p.get("notes", ""), "notes": p.get("notes", ""),

View File

@@ -67,13 +67,18 @@ assert not any(m["role"] == "customer" for m in s2["messages"]), "f2f should NOT
assert any(m["role"] == "system" for m in s2["messages"]), "f2f should have a scenario system note" assert any(m["role"] == "system" for m in s2["messages"]), "f2f should have a scenario system note"
print("[ok] f2f_call -> seller must open (system note present)") print("[ok] f2f_call -> seller must open (system note present)")
# recontact -> system preamble about time-lapse + customer opens # unknown scenario -> default to social (customer opens)
pid3 = personas[2]["id"] pid3 = personas[2]["id"]
r = C.post(f"/api/chat/{gid}/personas/{pid3}/chat/start", headers=TH, json={"scenario": "recontact"}) r = C.post(f"/api/chat/{gid}/personas/{pid3}/chat/start", headers=TH, json={"scenario": "recontact"})
assert r.status_code == 200, r.get_json() assert r.status_code == 200, r.get_json()
s3 = r.get_json()["session"] s3 = r.get_json()["session"]
assert any(m["role"] == "customer" for m in s3["messages"]), "recontact should open w/ customer" assert any(m["role"] == "customer" for m in s3["messages"]), "unknown scenario should default to social (customer opens)"
assert any(m["role"] == "system" and "เดือน" in m["text"] for m in s3["messages"]), "recontact system note (months)" print("[ok] unknown scenario defaults to social (customer opens)")
print("[ok] recontact -> time-lapse system note + customer opens")
# recontact is now a persona trait (not a scenario): some personas are flagged recontact
personas_all = C.get(f"/api/groups/{gid}/personas", headers=AH).get_json()["personas"]
recontact_n = sum(1 for p in personas_all if p.get("recontact"))
print(f"[ok] {recontact_n} of {len(personas_all)} generated personas are 'recontact' (warm returning leads)")
# The mock generates deterministic personas; we just assert the shape has the field (default False ok).
print("ALL SCENARIO TESTS PASSED") print("ALL SCENARIO TESTS PASSED")

View File

@@ -1,4 +1,4 @@
import{c as k,_ as h,p as b,a as r,b as e,l as m,u as o,m as l,t as n,i as u,w as p,v,H as U,g as f,F as V,x as C,y as w,r as y,o as i,C as M}from"./index-Dyfiqyex.js";import{U as z}from"./users-B6PgAwnZ.js";/** import{c as k,_ as h,p as b,a as r,b as e,l as m,u as o,m as l,t as n,i as u,w as p,v,H as U,g as f,F as V,x as C,y as w,r as y,o as i,C as M}from"./index-rfeHzF-F.js";import{U as z}from"./users-BgT8ke9W.js";/**
* @license lucide-vue-next v1.0.0 - ISC * @license lucide-vue-next v1.0.0 - ISC
* *
* This source code is licensed under the ISC license. * This source code is licensed under the ISC license.

View File

@@ -1,4 +1,4 @@
import{c as x,_ as L,p as M,a as p,b as s,l as i,u as a,m as c,t as e,i as n,q as w,w as f,v as b,s as U,g as N,F as R,x as j,y as A,z as B,r as m,h as E,o as y}from"./index-Dyfiqyex.js";import{U as P}from"./users-B6PgAwnZ.js";import{P as S}from"./plus-BRv2cnuI.js";/** import{c as x,_ as L,p as M,a as p,b as s,l as i,u as a,m as c,t as e,i as n,q as w,w as f,v as b,s as U,g as N,F as R,x as j,y as A,z as B,r as m,h as E,o as y}from"./index-rfeHzF-F.js";import{U as P}from"./users-BgT8ke9W.js";import{P as S}from"./plus-GGHS2V4y.js";/**
* @license lucide-vue-next v1.0.0 - ISC * @license lucide-vue-next v1.0.0 - ISC
* *
* This source code is licensed under the ISC license. * This source code is licensed under the ISC license.

6
frontend/dist/assets/Chat-CeTQMGNO.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
.thread[data-v-dd1df48f]{background:#eceff4;border:1px solid var(--border);border-radius:var(--radius);padding:16px;min-height:320px;max-height:52vh;overflow-y:auto;display:flex;flex-direction:column;gap:8px}.bubble[data-v-dd1df48f]{max-width:72%;padding:10px 14px;white-space:pre-wrap;word-break:break-word}.msg-system[data-v-dd1df48f]{align-self:center;background:#fef3c7;color:#92400e;font-size:12px;max-width:88%;border-radius:999px}.composer[data-v-dd1df48f]{display:flex;gap:8px;margin-top:12px}.task[data-v-dd1df48f]{margin-bottom:12px;background:#fff7ed;border-color:#fed7aa}.debrief[data-v-dd1df48f]{margin-top:16px}button.danger[data-v-dd1df48f]{background:var(--red);color:#fff;border:none}.guide[data-v-dd1df48f]{background:#eef2ff;border-color:#c7d2fe;margin-bottom:12px}.scenario[data-v-dd1df48f]{border:2px solid var(--border);border-radius:12px;padding:12px 14px;margin:10px 0;cursor:pointer;transition:border-color .15s ease,background .15s ease}.scenario[data-v-dd1df48f]:hover{border-color:var(--accent)}.scenario.sel[data-v-dd1df48f]{border-color:var(--accent);background:#eef2ff}.reveal-grid[data-v-dd1df48f]{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:8px}.rev[data-v-dd1df48f]{display:flex;flex-direction:column;background:#f8fafc;border:1px solid var(--border);border-radius:8px;padding:8px 10px}.rk[data-v-dd1df48f]{font-size:12px;color:var(--muted)}.rv[data-v-dd1df48f]{font-size:13px;color:var(--ink);margin-top:2px}@media (max-width: 640px){.reveal-grid[data-v-dd1df48f]{grid-template-columns:1fr}}

View File

@@ -0,0 +1 @@
.thread[data-v-dd57873b]{background:#eceff4;border:1px solid var(--border);border-radius:var(--radius);padding:16px;min-height:320px;max-height:52vh;overflow-y:auto;display:flex;flex-direction:column;gap:8px}.bubble[data-v-dd57873b]{max-width:72%;padding:10px 14px;white-space:pre-wrap;word-break:break-word}.msg-system[data-v-dd57873b]{align-self:center;background:#fef3c7;color:#92400e;font-size:12px;max-width:88%;border-radius:999px}.composer[data-v-dd57873b]{display:flex;gap:8px;margin-top:12px}.task[data-v-dd57873b]{margin-bottom:12px;background:#fff7ed;border-color:#fed7aa}.debrief[data-v-dd57873b]{margin-top:16px}button.danger[data-v-dd57873b]{background:var(--red);color:#fff;border:none}.guide[data-v-dd57873b]{background:#eef2ff;border-color:#c7d2fe;margin-bottom:12px}.scenario[data-v-dd57873b]{border:2px solid var(--border);border-radius:12px;padding:12px 14px;margin:10px 0;cursor:pointer;transition:border-color .15s ease,background .15s ease}.scenario[data-v-dd57873b]:hover{border-color:var(--accent)}.scenario.sel[data-v-dd57873b]{border-color:var(--accent);background:#eef2ff}.reveal-grid[data-v-dd57873b]{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:8px}.rev[data-v-dd57873b]{display:flex;flex-direction:column;background:#f8fafc;border:1px solid var(--border);border-radius:8px;padding:8px 10px}.rk[data-v-dd57873b]{font-size:12px;color:var(--muted)}.rv[data-v-dd57873b]{font-size:13px;color:var(--ink);margin-top:2px}@media (max-width: 640px){.reveal-grid[data-v-dd57873b]{grid-template-columns:1fr}}

View File

@@ -1,4 +1,4 @@
import{c as v,_ as M,a as k,l as u,q as z,b as e,u as l,m as o,t as r,i,w as g,v as y,H as V,g as C,z as A,r as m,y as x,j as B,o as w}from"./index-Dyfiqyex.js";import{A as q}from"./arrow-left-C95UZZnG.js";/** import{c as v,_ as M,a as k,l as u,q as z,b as e,u as l,m as o,t as r,i,w as g,v as y,H as V,g as C,z as A,r as m,y as x,j as B,o as w}from"./index-rfeHzF-F.js";import{A as q}from"./arrow-left-De8eM538.js";/**
* @license lucide-vue-next v1.0.0 - ISC * @license lucide-vue-next v1.0.0 - ISC
* *
* This source code is licensed under the ISC license. * This source code is licensed under the ISC license.

View File

@@ -1,4 +1,4 @@
import{c as q,_ as E,I as F,o as u,a as m,b as t,t as a,w as o,v as i,H as I,u as y,h as T,g as S,J as D,r as k,p as J,l as w,q as G,m as x,i as B,f as H,G as R,F as N,x as P,D as K,k as Q,y as z,z as W,C as O}from"./index-Dyfiqyex.js";import{U as X}from"./users-B6PgAwnZ.js";import{S as Y}from"./sparkles-x6AFhIMl.js";/** import{c as q,_ as E,I as F,o as u,a as m,b as t,t as a,w as o,v as i,H as I,u as y,h as T,g as S,J as D,r as k,p as J,l as w,q as G,m as x,i as B,f as H,G as R,F as N,x as P,D as K,k as Q,y as z,z as W,C as O}from"./index-rfeHzF-F.js";import{U as X}from"./users-BgT8ke9W.js";import{S as Y}from"./sparkles-DyyL2g7W.js";/**
* @license lucide-vue-next v1.0.0 - ISC * @license lucide-vue-next v1.0.0 - ISC
* *
* This source code is licensed under the ISC license. * This source code is licensed under the ISC license.

View File

@@ -1,4 +1,4 @@
import{c as e,a as o,b as l,l as n,u as i,m as s,t as r,i as a,G as u,o as d}from"./index-Dyfiqyex.js";import{B as g}from"./book-open-BVimbpEo.js";import{L as p}from"./layout-dashboard-BeK4EeBd.js";import{T as m}from"./target-D9jhWfH4.js";import{S as y}from"./sparkles-x6AFhIMl.js";/** import{c as e,a as o,b as l,l as n,u as i,m as s,t as r,i as a,G as u,o as d}from"./index-rfeHzF-F.js";import{B as g}from"./book-open-tl-QQwuW.js";import{L as p}from"./layout-dashboard-DNjo1OkM.js";import{T as m}from"./target-CLzEfHJ7.js";import{S as y}from"./sparkles-DyyL2g7W.js";/**
* @license lucide-vue-next v1.0.0 - ISC * @license lucide-vue-next v1.0.0 - ISC
* *
* This source code is licensed under the ISC license. * This source code is licensed under the ISC license.

View File

@@ -1,4 +1,4 @@
import{c as k,_ as x,a as y,b as e,t as l,u as a,i as n,w as h,v as M,d as w,e as B,f as _,g as E,r,h as f,j as S,k as V,o as s}from"./index-Dyfiqyex.js";/** import{c as k,_ as x,a as y,b as e,t as l,u as a,i as n,w as h,v as M,d as w,e as B,f as _,g as E,r,h as f,j as S,k as V,o as s}from"./index-rfeHzF-F.js";/**
* @license lucide-vue-next v1.0.0 - ISC * @license lucide-vue-next v1.0.0 - ISC
* *
* This source code is licensed under the ISC license. * This source code is licensed under the ISC license.

View File

@@ -1 +1 @@
import{_ as f,p as x,y as v,a as r,b as t,l as b,u as e,m as k,t as s,i as a,g as _,w as B,A as N,F as D,x as S,r as m,B as c,o as i,C as T}from"./index-Dyfiqyex.js";import{L as V}from"./layout-dashboard-BeK4EeBd.js";const C={style:{margin:"0"}},L={key:0,class:"row stat-row"},M={class:"card stat"},z={class:"card stat won"},F={class:"card stat lost"},j={class:"card stat"},A={key:1,class:"card"},E={key:2,class:"card empty-state"},G={class:"card",style:{"margin-top":"20px"}},I={style:{"margin-top":"0"}},q={__name:"MyBoard",setup(H){const o=m([]),u=m([]),p=m(!0),y=c(()=>o.value.length),g=c(()=>o.value.filter(n=>n.my_outcome==="won").length),h=c(()=>o.value.filter(n=>n.my_outcome==="lost").length),w=c(()=>o.value.filter(n=>n.my_outcome==="not_tried").length);return x(async()=>{try{o.value=(await v.myBoard()).board||[],u.value=(await v.mySessions()).sessions||[]}finally{p.value=!1}}),(n,l)=>(i(),r("div",null,[t("div",null,[t("h2",C,[b(e(V),{size:22,"stroke-width":1.8,style:{"vertical-align":"-4px"}}),k(" "+s(e(a).t("myDashboard")),1)]),l[0]||(l[0]=t("div",{class:"muted",style:{"margin-top":"4px","margin-bottom":"16px"}},"สรุปผลการฝึกของตัวคุณเอง — ดูว่าปิดการขายได้กี่ครั้ง ยังฝึกกับใครบ้าง",-1))]),p.value?_("",!0):(i(),r("div",L,[t("div",M,[t("span",null,s(e(a).t("total")),1),t("strong",null,s(y.value),1)]),t("div",z,[t("span",null,s(e(a).t("won")),1),t("strong",null,s(g.value),1)]),t("div",F,[t("span",null,s(e(a).t("lost")),1),t("strong",null,s(h.value),1)]),t("div",j,[t("span",null,s(e(a).t("notTried")),1),t("strong",null,s(w.value),1)])])),p.value?(i(),r("div",A,[...l[1]||(l[1]=[t("div",{class:"skeleton",style:{height:"50px"}},null,-1)])])):o.value.length===0?(i(),r("div",E,[...l[2]||(l[2]=[t("strong",null,"No practice yet",-1),t("span",null,"Go to Training and try closing a sale with a persona.",-1)])])):_("",!0),B(t("div",G,[t("h3",I,s(e(a).t("mySessions")),1),(i(!0),r(D,null,S(u.value,d=>(i(),r("div",{key:d.id,style:{display:"flex","justify-content":"space-between",padding:"8px 0","border-bottom":"1px solid var(--border)"}},[t("span",null,s(d.persona_name),1),t("span",{class:T(["badge",d.outcome])},s(d.outcome==="won"?e(a).t("won"):e(a).t("lost")),3)]))),128))],512),[[N,u.value.length]])]))}},O=f(q,[["__scopeId","data-v-6767b6b8"]]);export{O as default}; import{_ as f,p as x,y as v,a as r,b as t,l as b,u as e,m as k,t as s,i as a,g as _,w as B,A as N,F as D,x as S,r as m,B as c,o as i,C as T}from"./index-rfeHzF-F.js";import{L as V}from"./layout-dashboard-DNjo1OkM.js";const C={style:{margin:"0"}},L={key:0,class:"row stat-row"},M={class:"card stat"},z={class:"card stat won"},F={class:"card stat lost"},j={class:"card stat"},A={key:1,class:"card"},E={key:2,class:"card empty-state"},G={class:"card",style:{"margin-top":"20px"}},I={style:{"margin-top":"0"}},q={__name:"MyBoard",setup(H){const o=m([]),u=m([]),p=m(!0),y=c(()=>o.value.length),g=c(()=>o.value.filter(n=>n.my_outcome==="won").length),h=c(()=>o.value.filter(n=>n.my_outcome==="lost").length),w=c(()=>o.value.filter(n=>n.my_outcome==="not_tried").length);return x(async()=>{try{o.value=(await v.myBoard()).board||[],u.value=(await v.mySessions()).sessions||[]}finally{p.value=!1}}),(n,l)=>(i(),r("div",null,[t("div",null,[t("h2",C,[b(e(V),{size:22,"stroke-width":1.8,style:{"vertical-align":"-4px"}}),k(" "+s(e(a).t("myDashboard")),1)]),l[0]||(l[0]=t("div",{class:"muted",style:{"margin-top":"4px","margin-bottom":"16px"}},"สรุปผลการฝึกของตัวคุณเอง — ดูว่าปิดการขายได้กี่ครั้ง ยังฝึกกับใครบ้าง",-1))]),p.value?_("",!0):(i(),r("div",L,[t("div",M,[t("span",null,s(e(a).t("total")),1),t("strong",null,s(y.value),1)]),t("div",z,[t("span",null,s(e(a).t("won")),1),t("strong",null,s(g.value),1)]),t("div",F,[t("span",null,s(e(a).t("lost")),1),t("strong",null,s(h.value),1)]),t("div",j,[t("span",null,s(e(a).t("notTried")),1),t("strong",null,s(w.value),1)])])),p.value?(i(),r("div",A,[...l[1]||(l[1]=[t("div",{class:"skeleton",style:{height:"50px"}},null,-1)])])):o.value.length===0?(i(),r("div",E,[...l[2]||(l[2]=[t("strong",null,"No practice yet",-1),t("span",null,"Go to Training and try closing a sale with a persona.",-1)])])):_("",!0),B(t("div",G,[t("h3",I,s(e(a).t("mySessions")),1),(i(!0),r(D,null,S(u.value,d=>(i(),r("div",{key:d.id,style:{display:"flex","justify-content":"space-between",padding:"8px 0","border-bottom":"1px solid var(--border)"}},[t("span",null,s(d.persona_name),1),t("span",{class:T(["badge",d.outcome])},s(d.outcome==="won"?e(a).t("won"):e(a).t("lost")),3)]))),128))],512),[[N,u.value.length]])]))}},O=f(q,[["__scopeId","data-v-6767b6b8"]]);export{O as default};

View File

@@ -0,0 +1 @@
import{_ as T,p as $,a as l,l as u,q as _,b as t,t as s,u as e,i as n,h as g,m as d,g as x,F as y,x as p,k as L,y as N,z as V,r as w,o as a,S,C as b,f as A}from"./index-rfeHzF-F.js";import{T as F}from"./target-CLzEfHJ7.js";import{A as j}from"./arrow-left-De8eM538.js";const q={class:"row",style:{"align-items":"center"}},D={style:{margin:"0"}},E={class:"muted",style:{"margin-left":"auto"}},I={key:0,class:"card guide"},M={key:1,class:"row",style:{margin:"12px 0",gap:"10px"}},R={class:"primary"},G={class:"grid"},H={class:"row",style:{"justify-content":"space-between"}},J={class:"diff"},K={class:"muted"},O={class:"muted"},Q={class:"muted"},U={class:"muted",style:{"margin-top":"6px"}},W={class:"primary",style:{width:"100%"}},X={class:"primary",style:{width:"100%"}},Y={key:1,class:"muted",style:{"margin-top":"auto","font-size":"12px"}},Z={__name:"Personas",setup(tt){const c=L().params.gid,h=w([]),C=w(!0);async function B(){try{h.value=(await N.listPersonas(c)).personas}finally{C.value=!1}}function z(r){return h.value.filter(i=>i.tier===r)}function P(r){return n.t(r==="A"?"tierA":r==="B"?"tierB":"tierC")}function k(r){return r==="won"?n.t("won"):r==="lost"?n.t("lost"):n.t("notTried")}return $(B),(r,i)=>{const m=V("router-link");return a(),l("div",null,[u(m,{to:"/training",class:"btn-back"},{default:_(()=>[u(e(j),{size:16,"stroke-width":2}),d(" "+s(e(n).t("training")),1)]),_:1}),t("div",q,[t("h2",D,s(e(n).t("personas")),1),t("span",E,s(e(n).t("selectPersona")),1)]),e(g).isAdmin?x("",!0):(a(),l("div",I,[t("strong",null,[u(e(F),{size:17,"stroke-width":1.8,style:{"vertical-align":"-3px"}}),i[0]||(i[0]=d(" วิธีฝึก",-1))]),i[1]||(i[1]=t("ol",{style:{margin:"8px 0 0","padding-left":"20px","line-height":"1.8"}},[t("li",null,"เลือกลูกค้าจำลอง (บุคคลต้นแบบ) คนหนึ่งที่อยากฝึกด้วย"),t("li",null,"ระดับ A ง่ายสุด → ระดับ C ยากสุด (ดูจากดาว ★ ความยาก)"),t("li",null,[d("กด "),t("strong",null,"แชท"),d(" → เลือกสถานการณ์ (โซเชียล / พบหน้า-โทร) → เริ่มคุยกับลูกค้า")]),t("li",null,"ลูกค้าจะตัดสินใจเองว่าซื้อหรือไม่ซื้อ (ฝึกได้คนละครั้งเท่านั้น)")],-1))])),e(g).isAdmin?(a(),l("div",M,[u(m,{to:`/admin/groups/${e(c)}/edit`},{default:_(()=>[t("button",R,[u(e(S),{size:18,"stroke-width":1.8}),d(" "+s(e(n).t("managePersonas")),1)])]),_:1},8,["to"]),i[2]||(i[2]=t("span",{class:"muted"},"Admin: จัดการรายละเอียดบุคคลต้นแบบได้ที่นี่",-1))])):x("",!0),(a(),l(y,null,p(["A","B","C"],f=>t("div",{key:f,style:{margin:"20px 0"}},[t("h4",null,s(P(f)),1),t("div",G,[(a(!0),l(y,null,p(z(f),o=>(a(),l("div",{key:o.id,class:"card pcard lift"},[t("div",H,[t("strong",null,s(o.name),1),t("span",{class:b(["badge",o.my_outcome])},s(k(o.my_outcome)),3)]),t("div",J,[(a(),l(y,null,p(5,v=>t("span",{key:v,class:b(["star",{on:v<=(o.difficulty||1)}])},"★",2)),64)),t("span",K,s(e(n).t("difficulty"))+" "+s(o.difficulty||1)+"/5",1)]),t("div",O,[d(s(o.profession)+" · "+s(o.age_group)+" · "+s(o.location),1),i[3]||(i[3]=t("br",null,null,-1)),t("span",Q,s(e(n).t("difficulty"))+" "+s(o.difficulty||1)+"/5",1)]),t("div",U,s(o.product_context),1),e(g).isAdmin?(a(),A(m,{key:0,to:`/groups/${e(c)}/chat/${o.id}`,style:{"margin-top":"auto"}},{default:_(()=>[t("button",W,s(e(n).t("chat")),1)]),_:1},8,["to"])):(a(),l(y,{key:1},[o.my_outcome==="not_tried"?(a(),A(m,{key:0,to:`/groups/${e(c)}/chat/${o.id}`,style:{"margin-top":"auto"}},{default:_(()=>[t("button",X,s(e(n).t("chat")),1)]),_:1},8,["to"])):(a(),l("div",Y,"✓ "+s(e(n).t("trained"))+" ("+s(k(o.my_outcome))+")",1))],64))]))),128))])])),64))])}}},at=T(Z,[["__scopeId","data-v-ec851b01"]]);export{at as default};

View File

@@ -1 +0,0 @@
import{_ as T,p as $,a as l,l as u,q as _,b as t,t as s,u as e,i as n,h as g,m as d,g as x,F as y,x as p,k as L,y as N,z as V,r as w,o as a,S,C as b,f as A}from"./index-Dyfiqyex.js";import{T as F}from"./target-D9jhWfH4.js";import{A as j}from"./arrow-left-C95UZZnG.js";const q={class:"row",style:{"align-items":"center"}},D={style:{margin:"0"}},E={class:"muted",style:{"margin-left":"auto"}},I={key:0,class:"card guide"},M={key:1,class:"row",style:{margin:"12px 0",gap:"10px"}},R={class:"primary"},G={class:"grid"},H={class:"row",style:{"justify-content":"space-between"}},J={class:"diff"},K={class:"muted"},O={class:"muted"},Q={class:"muted"},U={class:"muted",style:{"margin-top":"6px"}},W={class:"primary",style:{width:"100%"}},X={class:"primary",style:{width:"100%"}},Y={key:1,class:"muted",style:{"margin-top":"auto","font-size":"12px"}},Z={__name:"Personas",setup(tt){const c=L().params.gid,h=w([]),C=w(!0);async function B(){try{h.value=(await N.listPersonas(c)).personas}finally{C.value=!1}}function z(r){return h.value.filter(i=>i.tier===r)}function P(r){return n.t(r==="A"?"tierA":r==="B"?"tierB":"tierC")}function k(r){return r==="won"?n.t("won"):r==="lost"?n.t("lost"):n.t("notTried")}return $(B),(r,i)=>{const m=V("router-link");return a(),l("div",null,[u(m,{to:"/training",class:"btn-back"},{default:_(()=>[u(e(j),{size:16,"stroke-width":2}),d(" "+s(e(n).t("training")),1)]),_:1}),t("div",q,[t("h2",D,s(e(n).t("personas")),1),t("span",E,s(e(n).t("selectPersona")),1)]),e(g).isAdmin?x("",!0):(a(),l("div",I,[t("strong",null,[u(e(F),{size:17,"stroke-width":1.8,style:{"vertical-align":"-3px"}}),i[0]||(i[0]=d(" วิธีฝึก",-1))]),i[1]||(i[1]=t("ol",{style:{margin:"8px 0 0","padding-left":"20px","line-height":"1.8"}},[t("li",null,"เลือกลูกค้าจำลอง (บุคคลต้นแบบ) คนหนึ่งที่อยากฝึกด้วย"),t("li",null,"ระดับ A ง่ายสุด → ระดับ C ยากสุด (ดูจากดาว ★ ความยาก)"),t("li",null,[d("กด "),t("strong",null,"แชท"),d(" → เลือกสถานการณ์ (โซเชียล / พบหน้า-โทร / กลับมาติดต่อ) → เริ่มคุยกับลูกค้า")]),t("li",null,"ลูกค้าจะตัดสินใจเองว่าซื้อหรือไม่ซื้อ (ฝึกได้คนละครั้งเท่านั้น)")],-1))])),e(g).isAdmin?(a(),l("div",M,[u(m,{to:`/admin/groups/${e(c)}/edit`},{default:_(()=>[t("button",R,[u(e(S),{size:18,"stroke-width":1.8}),d(" "+s(e(n).t("managePersonas")),1)])]),_:1},8,["to"]),i[2]||(i[2]=t("span",{class:"muted"},"Admin: จัดการรายละเอียดบุคคลต้นแบบได้ที่นี่",-1))])):x("",!0),(a(),l(y,null,p(["A","B","C"],f=>t("div",{key:f,style:{margin:"20px 0"}},[t("h4",null,s(P(f)),1),t("div",G,[(a(!0),l(y,null,p(z(f),o=>(a(),l("div",{key:o.id,class:"card pcard lift"},[t("div",H,[t("strong",null,s(o.name),1),t("span",{class:b(["badge",o.my_outcome])},s(k(o.my_outcome)),3)]),t("div",J,[(a(),l(y,null,p(5,v=>t("span",{key:v,class:b(["star",{on:v<=(o.difficulty||1)}])},"★",2)),64)),t("span",K,s(e(n).t("difficulty"))+" "+s(o.difficulty||1)+"/5",1)]),t("div",O,[d(s(o.profession)+" · "+s(o.age_group)+" · "+s(o.location),1),i[3]||(i[3]=t("br",null,null,-1)),t("span",Q,s(e(n).t("difficulty"))+" "+s(o.difficulty||1)+"/5",1)]),t("div",U,s(o.product_context),1),e(g).isAdmin?(a(),A(m,{key:0,to:`/groups/${e(c)}/chat/${o.id}`,style:{"margin-top":"auto"}},{default:_(()=>[t("button",W,s(e(n).t("chat")),1)]),_:1},8,["to"])):(a(),l(y,{key:1},[o.my_outcome==="not_tried"?(a(),A(m,{key:0,to:`/groups/${e(c)}/chat/${o.id}`,style:{"margin-top":"auto"}},{default:_(()=>[t("button",X,s(e(n).t("chat")),1)]),_:1},8,["to"])):(a(),l("div",Y,"✓ "+s(e(n).t("trained"))+" ("+s(k(o.my_outcome))+")",1))],64))]))),128))])])),64))])}}},at=T(Z,[["__scopeId","data-v-eb0948ac"]]);export{at as default};

View File

@@ -0,0 +1 @@
.grid[data-v-ec851b01]{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:14px}.pcard[data-v-ec851b01]{display:flex;flex-direction:column;min-height:190px}.diff[data-v-ec851b01]{margin:8px 0}.star[data-v-ec851b01]{color:#d8dbe3}.star.on[data-v-ec851b01]{color:#f59e0b}.badge.won[data-v-ec851b01]{background:#dcfce7;color:#166534}.badge.lost[data-v-ec851b01]{background:#fee2e2;color:#991b1b}.badge.not_tried[data-v-ec851b01]{background:#eef2ff;color:#4338ca}.guide[data-v-ec851b01]{background:#eef2ff;border-color:#c7d2fe;margin:12px 0 16px}

View File

@@ -1 +0,0 @@
.grid[data-v-eb0948ac]{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:14px}.pcard[data-v-eb0948ac]{display:flex;flex-direction:column;min-height:190px}.diff[data-v-eb0948ac]{margin:8px 0}.star[data-v-eb0948ac]{color:#d8dbe3}.star.on[data-v-eb0948ac]{color:#f59e0b}.badge.won[data-v-eb0948ac]{background:#dcfce7;color:#166534}.badge.lost[data-v-eb0948ac]{background:#fee2e2;color:#991b1b}.badge.not_tried[data-v-eb0948ac]{background:#eef2ff;color:#4338ca}.guide[data-v-eb0948ac]{background:#eef2ff;border-color:#c7d2fe;margin:12px 0 16px}

View File

@@ -1,4 +1,4 @@
import{c as U,_ as T,r as c,h as u,a as h,b as e,l as k,u as a,S as $,m as v,t as o,i as s,w as b,v as x,g as V,C as S,y as M,o as g}from"./index-Dyfiqyex.js";import{L as D}from"./lock-cj79Hj37.js";/** import{c as U,_ as T,r as c,h as u,a as h,b as e,l as k,u as a,S as $,m as v,t as o,i as s,w as b,v as x,g as V,C as S,y as M,o as g}from"./index-rfeHzF-F.js";import{L as D}from"./lock-BhsUQe9Y.js";/**
* @license lucide-vue-next v1.0.0 - ISC * @license lucide-vue-next v1.0.0 - ISC
* *
* This source code is licensed under the ISC license. * This source code is licensed under the ISC license.

View File

@@ -1 +1 @@
import{_ as U,a as v,b as e,l as K,u as s,m,t as a,i as l,h as _,w,v as b,d as h,n as N,g as T,r,j as B,o as f}from"./index-Dyfiqyex.js";import{L as C}from"./lock-cj79Hj37.js";const M={class:"setup-wrap"},D={class:"card setup-card"},L={class:"muted"},P={class:"terms"},j={key:0,class:"error",role:"alert"},z=["disabled"],E={key:0,class:"spinner"},I={key:1},V="/legal",R={__name:"Setup",setup(q){const S=B(),i=r(""),o=r(""),p=r(""),y=r(!1),u=r(""),d=r(!1);async function c(){if(u.value="",o.value.length<4){u.value=l.t("passwordTooShort");return}if(o.value!==p.value){u.value=l.t("passwordMismatch");return}d.value=!0;try{await _.finishSetup(i.value.trim(),o.value,!0),S.push("/")}catch(k){u.value=k.message}finally{d.value=!1}}return(k,t)=>{var g,x;return f(),v("div",M,[e("div",D,[e("h1",null,[K(s(C),{size:22,"stroke-width":1.8,style:{"vertical-align":"-4px"}}),m(" "+a(s(l).t("setupTitle")),1)]),e("p",L,[m(a(s(l).t("setupSubtitle"))+" ",1),e("strong",null,a(((g=s(_).user)==null?void 0:g.name)||((x=s(_).user)==null?void 0:x.username)),1)]),e("label",null,a(s(l).t("email")),1),w(e("input",{"onUpdate:modelValue":t[0]||(t[0]=n=>i.value=n),type:"email",autocomplete:"email",class:"wide",onKeyup:h(c,["enter"])},null,544),[[b,i.value]]),e("label",null,a(s(l).t("newPassword")),1),w(e("input",{"onUpdate:modelValue":t[1]||(t[1]=n=>o.value=n),type:"password",autocomplete:"new-password",class:"wide",onKeyup:h(c,["enter"])},null,544),[[b,o.value]]),e("label",null,a(s(l).t("confirmPassword")),1),w(e("input",{"onUpdate:modelValue":t[2]||(t[2]=n=>p.value=n),type:"password",autocomplete:"new-password",class:"wide",onKeyup:h(c,["enter"])},null,544),[[b,p.value]]),e("label",P,[w(e("input",{"onUpdate:modelValue":t[3]||(t[3]=n=>y.value=n),type:"checkbox"},null,512),[[N,y.value]]),e("span",null,[t[4]||(t[4]=m("ฉันยอมรับ ",-1)),e("a",{href:V,target:"_blank",rel:"noopener"},"ข้อกำหนดการใช้งาน"),t[5]||(t[5]=m(" และ ",-1)),e("a",{href:V,target:"_blank",rel:"noopener"},"นโยบายความเป็นส่วนตัว")])]),u.value?(f(),v("div",j,a(u.value),1)):T("",!0),e("button",{class:"primary",style:{width:"100%","margin-top":"16px"},disabled:d.value||!i.value||!o.value||o.value!==p.value||!y.value,onClick:c},[d.value?(f(),v("span",E)):(f(),v("span",I,a(s(l).t("save")),1))],8,z)])])}}},G=U(R,[["__scopeId","data-v-a3748c0a"]]);export{G as default}; import{_ as U,a as v,b as e,l as K,u as s,m,t as a,i as l,h as _,w,v as b,d as h,n as N,g as T,r,j as B,o as f}from"./index-rfeHzF-F.js";import{L as C}from"./lock-BhsUQe9Y.js";const M={class:"setup-wrap"},D={class:"card setup-card"},L={class:"muted"},P={class:"terms"},j={key:0,class:"error",role:"alert"},z=["disabled"],E={key:0,class:"spinner"},I={key:1},V="/legal",R={__name:"Setup",setup(q){const S=B(),i=r(""),o=r(""),p=r(""),y=r(!1),u=r(""),d=r(!1);async function c(){if(u.value="",o.value.length<4){u.value=l.t("passwordTooShort");return}if(o.value!==p.value){u.value=l.t("passwordMismatch");return}d.value=!0;try{await _.finishSetup(i.value.trim(),o.value,!0),S.push("/")}catch(k){u.value=k.message}finally{d.value=!1}}return(k,t)=>{var g,x;return f(),v("div",M,[e("div",D,[e("h1",null,[K(s(C),{size:22,"stroke-width":1.8,style:{"vertical-align":"-4px"}}),m(" "+a(s(l).t("setupTitle")),1)]),e("p",L,[m(a(s(l).t("setupSubtitle"))+" ",1),e("strong",null,a(((g=s(_).user)==null?void 0:g.name)||((x=s(_).user)==null?void 0:x.username)),1)]),e("label",null,a(s(l).t("email")),1),w(e("input",{"onUpdate:modelValue":t[0]||(t[0]=n=>i.value=n),type:"email",autocomplete:"email",class:"wide",onKeyup:h(c,["enter"])},null,544),[[b,i.value]]),e("label",null,a(s(l).t("newPassword")),1),w(e("input",{"onUpdate:modelValue":t[1]||(t[1]=n=>o.value=n),type:"password",autocomplete:"new-password",class:"wide",onKeyup:h(c,["enter"])},null,544),[[b,o.value]]),e("label",null,a(s(l).t("confirmPassword")),1),w(e("input",{"onUpdate:modelValue":t[2]||(t[2]=n=>p.value=n),type:"password",autocomplete:"new-password",class:"wide",onKeyup:h(c,["enter"])},null,544),[[b,p.value]]),e("label",P,[w(e("input",{"onUpdate:modelValue":t[3]||(t[3]=n=>y.value=n),type:"checkbox"},null,512),[[N,y.value]]),e("span",null,[t[4]||(t[4]=m("ฉันยอมรับ ",-1)),e("a",{href:V,target:"_blank",rel:"noopener"},"ข้อกำหนดการใช้งาน"),t[5]||(t[5]=m(" และ ",-1)),e("a",{href:V,target:"_blank",rel:"noopener"},"นโยบายความเป็นส่วนตัว")])]),u.value?(f(),v("div",j,a(u.value),1)):T("",!0),e("button",{class:"primary",style:{width:"100%","margin-top":"16px"},disabled:d.value||!i.value||!o.value||o.value!==p.value||!y.value,onClick:c},[d.value?(f(),v("span",E)):(f(),v("span",I,a(s(l).t("save")),1))],8,z)])])}}},G=U(R,[["__scopeId","data-v-a3748c0a"]]);export{G as default};

View File

@@ -1,4 +1,4 @@
import{c as x,_ as b,p as C,y as f,h as l,a as d,b as s,l as c,u as t,m,t as o,i as n,q as _,f as A,g as h,F as z,x as M,r as v,z as T,o as r,C as B,D as N}from"./index-Dyfiqyex.js";import{T as P}from"./target-D9jhWfH4.js";import{B as V}from"./book-open-BVimbpEo.js";import{P as $}from"./plus-BRv2cnuI.js";/** import{c as x,_ as b,p as C,y as f,h as l,a as d,b as s,l as c,u as t,m,t as o,i as n,q as _,f as A,g as h,F as z,x as M,r as v,z as T,o as r,C as B,D as N}from"./index-rfeHzF-F.js";import{T as P}from"./target-CLzEfHJ7.js";import{B as V}from"./book-open-tl-QQwuW.js";import{P as $}from"./plus-GGHS2V4y.js";/**
* @license lucide-vue-next v1.0.0 - ISC * @license lucide-vue-next v1.0.0 - ISC
* *
* This source code is licensed under the ISC license. * This source code is licensed under the ISC license.

View File

@@ -1,4 +1,4 @@
import{c as e}from"./index-Dyfiqyex.js";/** import{c as e}from"./index-rfeHzF-F.js";/**
* @license lucide-vue-next v1.0.0 - ISC * @license lucide-vue-next v1.0.0 - ISC
* *
* This source code is licensed under the ISC license. * This source code is licensed under the ISC license.

View File

@@ -1,4 +1,4 @@
import{c as a}from"./index-Dyfiqyex.js";/** import{c as a}from"./index-rfeHzF-F.js";/**
* @license lucide-vue-next v1.0.0 - ISC * @license lucide-vue-next v1.0.0 - ISC
* *
* This source code is licensed under the ISC license. * This source code is licensed under the ISC license.

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
import{c as t}from"./index-Dyfiqyex.js";/** import{c as t}from"./index-rfeHzF-F.js";/**
* @license lucide-vue-next v1.0.0 - ISC * @license lucide-vue-next v1.0.0 - ISC
* *
* This source code is licensed under the ISC license. * This source code is licensed under the ISC license.

View File

@@ -1,4 +1,4 @@
import{c as e}from"./index-Dyfiqyex.js";/** import{c as e}from"./index-rfeHzF-F.js";/**
* @license lucide-vue-next v1.0.0 - ISC * @license lucide-vue-next v1.0.0 - ISC
* *
* This source code is licensed under the ISC license. * This source code is licensed under the ISC license.

View File

@@ -1,4 +1,4 @@
import{c as e}from"./index-Dyfiqyex.js";/** import{c as e}from"./index-rfeHzF-F.js";/**
* @license lucide-vue-next v1.0.0 - ISC * @license lucide-vue-next v1.0.0 - ISC
* *
* This source code is licensed under the ISC license. * This source code is licensed under the ISC license.

View File

@@ -1,4 +1,4 @@
import{c as a}from"./index-Dyfiqyex.js";/** import{c as a}from"./index-rfeHzF-F.js";/**
* @license lucide-vue-next v1.0.0 - ISC * @license lucide-vue-next v1.0.0 - ISC
* *
* This source code is licensed under the ISC license. * This source code is licensed under the ISC license.

View File

@@ -1,4 +1,4 @@
import{c}from"./index-Dyfiqyex.js";/** import{c}from"./index-rfeHzF-F.js";/**
* @license lucide-vue-next v1.0.0 - ISC * @license lucide-vue-next v1.0.0 - ISC
* *
* This source code is licensed under the ISC license. * This source code is licensed under the ISC license.

View File

@@ -1,4 +1,4 @@
import{c as e}from"./index-Dyfiqyex.js";/** import{c as e}from"./index-rfeHzF-F.js";/**
* @license lucide-vue-next v1.0.0 - ISC * @license lucide-vue-next v1.0.0 - ISC
* *
* This source code is licensed under the ISC license. * This source code is licensed under the ISC license.

View File

@@ -4,7 +4,7 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Sales Trainer</title> <title>Sales Trainer</title>
<script type="module" crossorigin src="/assets/index-Dyfiqyex.js"></script> <script type="module" crossorigin src="/assets/index-rfeHzF-F.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-B9WjPRES.css"> <link rel="stylesheet" crossorigin href="/assets/index-B9WjPRES.css">
</head> </head>
<body> <body>

View File

@@ -109,7 +109,6 @@ const scenarios = computed(() => {
return [ return [
{ id: 'social', emoji: '💬', init: 'customer', label: en ? 'Social Media (chat)' : 'Social Media (แชท)', desc: en ? 'The customer messages you first — short, chat-style replies' : 'ลูกค้าทักมาหาคุณก่อน — โทนสั้น ทักๆ ตามสไตล์แชท' }, { id: 'social', emoji: '💬', init: 'customer', label: en ? 'Social Media (chat)' : 'Social Media (แชท)', desc: en ? 'The customer messages you first — short, chat-style replies' : 'ลูกค้าทักมาหาคุณก่อน — โทนสั้น ทักๆ ตามสไตล์แชท' },
{ id: 'f2f_call', emoji: '📞', init: 'seller', label: en ? 'Face-to-face / Phone' : 'พบหน้า / โทรศัพท์', desc: en ? 'You must proactively open the conversation (seller starts)' : 'คุณต้องเป็นฝ่ายเปิดการสนทนาเชิงรุกกับลีด (ผู้ฝึกทักก่อน)' }, { id: 'f2f_call', emoji: '📞', init: 'seller', label: en ? 'Face-to-face / Phone' : 'พบหน้า / โทรศัพท์', desc: en ? 'You must proactively open the conversation (seller starts)' : 'คุณต้องเป็นฝ่ายเปิดการสนทนาเชิงรุกกับลีด (ผู้ฝึกทักก่อน)' },
{ id: 'recontact', emoji: '⏳', init: 'customer', label: en ? 'Re-contact (1-3 months)' : 'ลูกค้ากลับมาติดต่อ (1-3 เดือน)', desc: en ? 'Customer contacted you before, now returns more ready to decide' : 'เคยได้รับข้อมูลไปแล้ว ตอนนี้กลับมาติดต่อ พร้อมตัดสินใจมากขึ้น' },
] ]
}) })

View File

@@ -10,7 +10,7 @@
<ol style="margin:8px 0 0;padding-left:20px;line-height:1.8"> <ol style="margin:8px 0 0;padding-left:20px;line-height:1.8">
<li>เลอกลกคาจำลอง (คคลตนแบบ) คนหนงทอยากฝกดวย</li> <li>เลอกลกคาจำลอง (คคลตนแบบ) คนหนงทอยากฝกดวย</li>
<li>ระด A ายส ระด C ยากส (จากดาว ความยาก)</li> <li>ระด A ายส ระด C ยากส (จากดาว ความยาก)</li>
<li>กด <strong>แชท</strong> เลอกสถานการณ (โซเชยล / พบหน-โทร / กลบมาตดต) เรมคยกบลกค</li> <li>กด <strong>แชท</strong> เลอกสถานการณ (โซเชยล / พบหน-โทร) เรมคยกบลกค</li>
<li>กคาจะตดสนใจเองวาซอหรอไม (กไดคนละครงเทาน)</li> <li>กคาจะตดสนใจเองวาซอหรอไม (กไดคนละครงเทาน)</li>
</ol> </ol>
</div> </div>