- 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.
15 lines
13 KiB
JavaScript
15 lines
13 KiB
JavaScript
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
|
|
*
|
|
* This source code is licensed under the ISC license.
|
|
* See the LICENSE file in the root directory of this source tree.
|
|
*/const Z=q("message-square",[["path",{d:"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z",key:"18887p"}]]);/**
|
|
* @license lucide-vue-next v1.0.0 - ISC
|
|
*
|
|
* This source code is licensed under the ISC license.
|
|
* See the LICENSE file in the root directory of this source tree.
|
|
*/const h=q("pencil",[["path",{d:"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",key:"1a8usu"}],["path",{d:"m15 5 4 4",key:"1mk7zo"}]]),ee={class:"persona-form"},te={class:"muted"},le={class:"sec"},ne={class:"row"},se={class:"f"},oe={class:"f"},ie={class:"f"},ae={class:"row"},re={class:"f"},ue={class:"f"},de={class:"f"},me={class:"sec"},ve={class:"row"},fe={class:"f"},ge={class:"f"},ye={class:"f"},be={key:0,class:"sec"},ke={key:1,class:"sec locked"},ce={key:2,class:"sec"},pe={class:"muted"},we={class:"row actions"},xe=["disabled"],Ve={__name:"PersonaForm",props:{persona:{type:Object,required:!0}},emits:["save","cancel"],setup(V,{emit:L}){const c=V,$=L,n=D({name:"",difficulty:1,tier:"B",profession:"",age_group:"",location:"",income:"",budget:"",lifestyle:"",background:"",personality:"",communication_style:"",goal:"",decision_timeline:"",opener:"",channel:"line",initiation_mode:"customer",special:""}),v=k(""),b=k(""),f=k(""),p=k(!1);function U(l){return l?Array.isArray(l)?l.map(e=>typeof e=="string"?e:e&&e.description||e&&e.text||"").filter(Boolean).join(`
|
|
`):String(l):""}function C(l){return l.split(`
|
|
`).map(e=>e.trim()).filter(Boolean)}F(()=>c.persona,l=>{Object.assign(n,{name:(l==null?void 0:l.name)||"",difficulty:(l==null?void 0:l.difficulty)??1,tier:(l==null?void 0:l.tier)||"B",profession:(l==null?void 0:l.profession)||"",age_group:(l==null?void 0:l.age_group)||"",location:(l==null?void 0:l.location)||"",income:(l==null?void 0:l.income)||"",budget:(l==null?void 0:l.budget)||"",lifestyle:(l==null?void 0:l.lifestyle)||"",background:(l==null?void 0:l.background)||"",personality:(l==null?void 0:l.personality)||"",communication_style:(l==null?void 0:l.communication_style)||"",goal:(l==null?void 0:l.goal)||"",decision_timeline:(l==null?void 0:l.decision_timeline)||"",opener:(l==null?void 0:l.opener)||"",channel:(l==null?void 0:l.channel)||"line",initiation_mode:(l==null?void 0:l.initiation_mode)||"customer",special:(l==null?void 0:l.special)||""}),v.value=U(l==null?void 0:l.pains),b.value=U(l==null?void 0:l.objections),f.value=U(l==null?void 0:l.negotiation_levers)},{immediate:!0});function A(){$("save",{...n,pains:C(v.value).map(l=>({description:l})),objections:C(b.value),negotiation_levers:C(f.value)})}return(l,e)=>(u(),m("div",ee,[t("h3",null,a(V.persona.name||"New persona"),1),t("p",te,a(V.persona.profession)+" · "+a(V.persona.personality),1),t("div",le,[e[28]||(e[28]=t("h4",null,"👤 ข้อมูลพื้นฐาน",-1)),t("div",ne,[t("div",se,[e[21]||(e[21]=t("label",null,"ชื่อ",-1)),o(t("input",{"onUpdate:modelValue":e[0]||(e[0]=s=>n.name=s)},null,512),[[i,n.name]])]),t("div",oe,[e[22]||(e[22]=t("label",null,"ระดับความยาก (1-5)",-1)),o(t("input",{"onUpdate:modelValue":e[1]||(e[1]=s=>n.difficulty=s),type:"number",min:"1",max:"5"},null,512),[[i,n.difficulty,void 0,{number:!0}]])]),t("div",ie,[e[24]||(e[24]=t("label",null,"ระดับลูกค้า",-1)),o(t("select",{"onUpdate:modelValue":e[2]||(e[2]=s=>n.tier=s)},[...e[23]||(e[23]=[t("option",{value:"A"},"A — พร้อมตัดสินใจซื้อ",-1),t("option",{value:"B"},"B — ยังไม่แน่ใจ",-1),t("option",{value:"C"},"C — ไม่สนใจแต่มีปัญหา",-1)])],512),[[I,n.tier]])])]),t("div",ae,[t("div",re,[e[25]||(e[25]=t("label",null,"อาชีพ",-1)),o(t("input",{"onUpdate:modelValue":e[3]||(e[3]=s=>n.profession=s)},null,512),[[i,n.profession]])]),t("div",ue,[e[26]||(e[26]=t("label",null,"ช่วงอายุ",-1)),o(t("input",{"onUpdate:modelValue":e[4]||(e[4]=s=>n.age_group=s)},null,512),[[i,n.age_group]])]),t("div",de,[e[27]||(e[27]=t("label",null,"พื้นที่",-1)),o(t("input",{"onUpdate:modelValue":e[5]||(e[5]=s=>n.location=s)},null,512),[[i,n.location]])])])]),t("div",me,[e[32]||(e[32]=t("h4",null,"💼 ข้อมูลลูกค้า",-1)),t("div",ve,[t("div",fe,[e[29]||(e[29]=t("label",null,"รายได้/สถานะการเงิน",-1)),o(t("input",{"onUpdate:modelValue":e[6]||(e[6]=s=>n.income=s)},null,512),[[i,n.income]])]),t("div",ge,[e[30]||(e[30]=t("label",null,"งบประมาณ",-1)),o(t("input",{"onUpdate:modelValue":e[7]||(e[7]=s=>n.budget=s)},null,512),[[i,n.budget]])]),t("div",ye,[e[31]||(e[31]=t("label",null,"ไลฟ์สไตล์",-1)),o(t("input",{"onUpdate:modelValue":e[8]||(e[8]=s=>n.lifestyle=s)},null,512),[[i,n.lifestyle]])])]),e[33]||(e[33]=t("label",null,"ภูมิหลัง",-1)),o(t("textarea",{"onUpdate:modelValue":e[9]||(e[9]=s=>n.background=s)},null,512),[[i,n.background]]),e[34]||(e[34]=t("label",null,"บุคลิก / วิธีพูดคุย",-1)),o(t("textarea",{"onUpdate:modelValue":e[10]||(e[10]=s=>n.personality=s)},null,512),[[i,n.personality]]),e[35]||(e[35]=t("label",null,"สไตล์การสื่อสาร",-1)),o(t("textarea",{"onUpdate:modelValue":e[11]||(e[11]=s=>n.communication_style=s)},null,512),[[i,n.communication_style]])]),y(T).isSuperAdmin?(u(),m("div",be,[e[36]||(e[36]=t("h4",null,"🎯 การขาย",-1)),e[37]||(e[37]=t("label",null,"เป้าหมาย",-1)),o(t("textarea",{"onUpdate:modelValue":e[12]||(e[12]=s=>n.goal=s)},null,512),[[i,n.goal]]),e[38]||(e[38]=t("label",null,"กรอบเวลาในการตัดสินใจ",-1)),o(t("input",{"onUpdate:modelValue":e[13]||(e[13]=s=>n.decision_timeline=s)},null,512),[[i,n.decision_timeline]]),e[39]||(e[39]=t("label",null,"Pain (ปัญหา) แบบ 1 ต่อบรรทัด",-1)),o(t("textarea",{"onUpdate:modelValue":e[14]||(e[14]=s=>v.value=s),placeholder:`เช่น ต้นทุนสูงเกินไป
|
|
ระบบล้าสมัย`},null,512),[[i,v.value]]),e[40]||(e[40]=t("label",null,"ข้อโต้แย้ง (Objections) 1 ต่อบรรทัด",-1)),o(t("textarea",{"onUpdate:modelValue":e[15]||(e[15]=s=>b.value=s)},null,512),[[i,b.value]]),e[41]||(e[41]=t("label",null,"สิ่งที่ใช้ต่อรอง (เช่น ส่วนลด, ฟรีติดตั้ง)",-1)),o(t("textarea",{"onUpdate:modelValue":e[16]||(e[16]=s=>f.value=s)},null,512),[[i,f.value]]),e[42]||(e[42]=t("label",null,"ช่องทางสำหรับลูกค้าเปิดบทสนทนา (opener)",-1)),o(t("textarea",{"onUpdate:modelValue":e[17]||(e[17]=s=>n.opener=s)},null,512),[[i,n.opener]])])):(u(),m("div",ke,[e[43]||(e[43]=t("h4",null,"🔒 ส่วนสูตรการขาย",-1)),e[44]||(e[44]=t("p",{class:"muted"},"ปิดการแก้ไข — เฉพาะผู้ดูแลระดับสูงเท่านั้นที่ดู/แก้ได้ (เพื่อรักษาความได้เปรียบ)",-1)),e[45]||(e[45]=t("label",null,"เป้าหมาย",-1)),o(t("textarea",{"onUpdate:modelValue":e[18]||(e[18]=s=>n.goal=s)},null,512),[[i,n.goal]]),e[46]||(e[46]=t("label",null,"กรอบเวลาในการตัดสินใจ",-1)),o(t("input",{"onUpdate:modelValue":e[19]||(e[19]=s=>n.decision_timeline=s)},null,512),[[i,n.decision_timeline]])])),y(T).isSuperAdmin&&n.special?(u(),m("div",ce,[t("label",pe,"พิเศษ: "+a(n.special),1)])):S("",!0),t("div",we,[t("button",{class:"primary",onClick:A,disabled:p.value},a(p.value?"กำลังบันทึก…":"💾 บันทึกบุคคลต้นแบบ"),9,xe),t("button",{onClick:e[20]||(e[20]=s=>l.$emit("cancel"))},"ปิด")])]))}},$e=E(Ve,[["__scopeId","data-v-59429170"]]),Ue={class:"row",style:{"align-items":"center","margin-bottom":"8px"}},Ce={style:{margin:"0"}},_e={class:"row",style:{"margin-left":"auto",gap:"10px"}},Be=["disabled"],Se={key:0,class:"spinner"},ze={key:0,class:"muted"},Ae={key:1,class:"error",style:{margin:"12px 0"}},je={key:2,class:"card empty-state"},Ne={class:"grid"},Pe={class:"row",style:{"justify-content":"space-between","align-items":"center"}},Le={class:"diff"},Me={class:"muted"},Te={class:"muted"},Ge={class:"row",style:{gap:"8px","margin-top":"auto"}},Oe={class:"primary",style:{width:"100%"}},qe=["onClick"],Ee={class:"modal"},Fe={__name:"GroupEdit",setup(V){const c=Q().params.gid,$=k(null),n=k([]),v=k(!1),b=k(""),f=k(null);async function p(){const r=await z.getGroup(c);$.value=r.group,n.value=(await z.listPersonas(c)).personas}function U(r){return n.value.filter(d=>d.tier===r)}function C(r){return B.t(r==="A"?"tierA":r==="B"?"tierB":"tierC")}function A(r){return{A:"tier-a",B:"tier-b",C:"tier-c"}[r]||""}async function l(){v.value=!0,b.value="";try{const r=await z.analyzeGroup(c,{append:!0});n.value=r.personas,await p()}catch(r){b.value=r.message}finally{v.value=!1}}function e(r){f.value=JSON.parse(JSON.stringify(r))}async function s(r){v.value=!0;try{await z.updatePersona(c,f.value.id,r),f.value=null,await p()}catch(d){b.value=d.message}finally{v.value=!1}}return J(p),(r,d)=>{const M=W("router-link");return u(),m("div",null,[w(M,{to:"/training",class:"btn-back"},{default:G(()=>[x("← "+a(y(B).t("training")),1)]),_:1}),t("div",Ue,[t("h2",Ce,[w(y(X),{size:22,"stroke-width":1.8,style:{"vertical-align":"-4px"}}),x(" "+a(y(B).t("managePersonas")),1)]),t("div",_e,[t("button",{onClick:l,disabled:v.value,class:"primary"},[v.value?(u(),m("span",Se)):(u(),H(y(Y),{key:1,size:18,"stroke-width":1.8})),x(" "+a(v.value?"กำลังสร้าง…":"สร้างบุคคลต้นแบบเพิ่มเติม"),1)],8,Be)])]),$.value?(u(),m("p",ze,[d[2]||(d[2]=x("สินค้า: ",-1)),t("strong",null,a($.value.title),1)])):S("",!0),b.value?(u(),m("div",Ae,a(b.value),1)):S("",!0),d[4]||(d[4]=R('<div class="card guide" data-v-255f109f><strong data-v-255f109f>วิธีใช้หน้านี้</strong><ol style="margin:8px 0 0;padding-left:20px;line-height:1.8;" data-v-255f109f><li data-v-255f109f>ระบบสร้างบุคคลต้นแบบ (ลูกค้าจำลอง) ให้อัตโนมัติแล้ว หลังกดสร้าง</li><li data-v-255f109f>แต่ละการ์ดคือลูกค้าจำลอง 1 คน — กด <strong data-v-255f109f>✏️ แก้ไข</strong> เพื่อปรับรายละเอียดให้ตรงใจ</li><li data-v-255f109f>อยากได้ลูกค้าจำลองเพิ่ม กด <strong data-v-255f109f>สร้างบุคคลต้นแบบเพิ่มเติม</strong></li><li data-v-255f109f><strong data-v-255f109f>วิธีเริ่มฝึก:</strong> ไปที่แท็บ <strong data-v-255f109f>การฝึก</strong> → เลือกสินค้านี้ → เลือกลูกค้าจำลอง 1 คน → กด <strong data-v-255f109f>แชท</strong> → เลือกสถานการณ์ → เริ่มคุย</li></ol></div>',1)),n.value.length===0&&!v.value?(u(),m("div",je,[...d[3]||(d[3]=[t("strong",null,"ยังไม่มีบุคคลต้นแบบ",-1),t("span",null,'กด "สร้างบุคคลต้นแบบเพิ่มเติม" เพื่อให้ระบบสร้างลูกค้าจำลองให้',-1)])])):S("",!0),(u(),m(N,null,P(["A","B","C"],_=>t("div",{key:_,style:{"margin-bottom":"20px"}},[t("h4",null,a(C(_)),1),t("div",Ne,[(u(!0),m(N,null,P(U(_),g=>(u(),m("div",{key:g.id,class:"card pcard"},[t("div",Pe,[t("strong",null,a(g.name),1),t("span",{class:O(["badge",A(g.tier)])},a(g.tier),3)]),t("div",Le,[(u(),m(N,null,P(5,j=>t("span",{key:j,class:O(["star",{on:j<=(g.difficulty||1)}])},"★",2)),64))]),t("div",Me,a(g.profession)+" · "+a(g.age_group)+" · "+a(g.location),1),t("div",Te,a(g.personality),1),t("div",Ge,[w(M,{to:`/groups/${y(c)}/chat/${g.id}`,style:{flex:"1","text-decoration":"none"}},{default:G(()=>[t("button",Oe,[w(y(Z),{size:16,"stroke-width":1.8}),x(" "+a(y(B).t("chat")),1)])]),_:1},8,["to"]),t("button",{class:"edit-btn",onClick:j=>e(g)},[w(y(h),{size:15,"stroke-width":1.8}),x(" "+a(y(B).t("edit")),1)],8,qe)])]))),128))])])),64)),f.value?(u(),m("div",{key:3,class:"modal-backdrop",onClick:d[1]||(d[1]=K(_=>f.value=null,["self"]))},[t("div",Ee,[w($e,{persona:f.value,onSave:s,onCancel:d[0]||(d[0]=_=>f.value=null)},null,8,["persona"])])])):S("",!0)])}}},He=E(Fe,[["__scopeId","data-v-255f109f"]]);export{He as default};
|