Files
sales-trainer/frontend/dist/assets/GroupEdit-PGVs7eZc.js
Macky e1d61e1e1e feat(ip): protect persona 'formula' — secret fields only super_admin sees/edits
IP protection so casual copying yields inferior results:
- SECRET_PERSONA_FIELDS (pains/objections/negotiation_levers/opener/tolerance +
  pain rootCause/resolutionConditions): only super_admin can view/edit them.
- list_personas/get_persona/update_persona/get_group strip these for role=admin (and
  hide sales_kit + pain-fit report from admins too).
- update_persona rejects admin attempts to set secret fields (403).
- PersonaForm hides the 'การขาย' recipe section for non-super-admin (shows locked note);
  auth.isSuperAdmin getter added.
Rebuilt dist. Added test_ip_protection.
2026-08-09 07:22:50 +07:00

10 lines
13 KiB
JavaScript

import{c as M,_ as G,G as O,o as r,a as m,b as e,t as a,w as o,v as i,E as N,u as k,h as _,g as A,H as D,r as p,n as J,l as S,p as q,m as y,i as B,f as H,F as P,s as E,I as R,k as K,x as z,y as Q,B as F}from"./index-BCax2GDh.js";import{U as W}from"./users-NPxa3eQ_.js";import{S as X}from"./sparkles-E3Xd6eY7.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 Y=M("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"}]]),Z={class:"persona-form"},h={class:"muted"},ll={class:"sec"},el={class:"row"},tl={class:"f"},nl={class:"f"},sl={class:"f"},ol={class:"row"},il={class:"f"},al={class:"f"},ul={class:"f"},rl={class:"sec"},dl={class:"row"},ml={class:"f"},vl={class:"f"},fl={class:"f"},gl={key:0,class:"sec"},yl={key:1,class:"sec locked"},bl={class:"sec"},kl={class:"row"},pl={class:"f"},xl={class:"f"},Vl={key:0,class:"muted"},wl={class:"row actions"},Ul=["disabled"],$l={__name:"PersonaForm",props:{persona:{type:Object,required:!0}},emits:["save","cancel"],setup(w,{emit:T}){const x=w,U=T,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=p(""),b=p(""),f=p(""),V=p(!1);function $(t){return Array.isArray(t)?t.join(`
`):String(t||"")}function C(t){return t.split(`
`).map(l=>l.trim()).filter(Boolean)}O(()=>x.persona,t=>{Object.assign(n,{name:(t==null?void 0:t.name)||"",difficulty:(t==null?void 0:t.difficulty)??1,tier:(t==null?void 0:t.tier)||"B",profession:(t==null?void 0:t.profession)||"",age_group:(t==null?void 0:t.age_group)||"",location:(t==null?void 0:t.location)||"",income:(t==null?void 0:t.income)||"",budget:(t==null?void 0:t.budget)||"",lifestyle:(t==null?void 0:t.lifestyle)||"",background:(t==null?void 0:t.background)||"",personality:(t==null?void 0:t.personality)||"",communication_style:(t==null?void 0:t.communication_style)||"",goal:(t==null?void 0:t.goal)||"",decision_timeline:(t==null?void 0:t.decision_timeline)||"",opener:(t==null?void 0:t.opener)||"",channel:(t==null?void 0:t.channel)||"line",initiation_mode:(t==null?void 0:t.initiation_mode)||"customer",special:(t==null?void 0:t.special)||""}),v.value=$(t==null?void 0:t.pains),b.value=$(t==null?void 0:t.objections),f.value=$(t==null?void 0:t.negotiation_levers)},{immediate:!0});function j(){U("save",{...n,pains:C(v.value),objections:C(b.value),negotiation_levers:C(f.value)})}return(t,l)=>(r(),m("div",Z,[e("h3",null,a(w.persona.name||"New persona"),1),e("p",h,a(w.persona.profession)+" · "+a(w.persona.personality),1),e("div",ll,[l[30]||(l[30]=e("h4",null,"👤 ข้อมูลพื้นฐาน",-1)),e("div",el,[e("div",tl,[l[23]||(l[23]=e("label",null,"ชื่อ",-1)),o(e("input",{"onUpdate:modelValue":l[0]||(l[0]=s=>n.name=s)},null,512),[[i,n.name]])]),e("div",nl,[l[24]||(l[24]=e("label",null,"ระดับความยาก (1-5)",-1)),o(e("input",{"onUpdate:modelValue":l[1]||(l[1]=s=>n.difficulty=s),type:"number",min:"1",max:"5"},null,512),[[i,n.difficulty,void 0,{number:!0}]])]),e("div",sl,[l[26]||(l[26]=e("label",null,"ระดับลูกค้า",-1)),o(e("select",{"onUpdate:modelValue":l[2]||(l[2]=s=>n.tier=s)},[...l[25]||(l[25]=[e("option",{value:"A"},"A — พร้อมตัดสินใจซื้อ",-1),e("option",{value:"B"},"B — ยังไม่แน่ใจ",-1),e("option",{value:"C"},"C — ไม่สนใจแต่มีปัญหา",-1)])],512),[[N,n.tier]])])]),e("div",ol,[e("div",il,[l[27]||(l[27]=e("label",null,"อาชีพ",-1)),o(e("input",{"onUpdate:modelValue":l[3]||(l[3]=s=>n.profession=s)},null,512),[[i,n.profession]])]),e("div",al,[l[28]||(l[28]=e("label",null,"ช่วงอายุ",-1)),o(e("input",{"onUpdate:modelValue":l[4]||(l[4]=s=>n.age_group=s)},null,512),[[i,n.age_group]])]),e("div",ul,[l[29]||(l[29]=e("label",null,"พื้นที่",-1)),o(e("input",{"onUpdate:modelValue":l[5]||(l[5]=s=>n.location=s)},null,512),[[i,n.location]])])])]),e("div",rl,[l[34]||(l[34]=e("h4",null,"💼 ข้อมูลลูกค้า",-1)),e("div",dl,[e("div",ml,[l[31]||(l[31]=e("label",null,"รายได้/สถานะการเงิน",-1)),o(e("input",{"onUpdate:modelValue":l[6]||(l[6]=s=>n.income=s)},null,512),[[i,n.income]])]),e("div",vl,[l[32]||(l[32]=e("label",null,"งบประมาณ",-1)),o(e("input",{"onUpdate:modelValue":l[7]||(l[7]=s=>n.budget=s)},null,512),[[i,n.budget]])]),e("div",fl,[l[33]||(l[33]=e("label",null,"ไลฟ์สไตล์",-1)),o(e("input",{"onUpdate:modelValue":l[8]||(l[8]=s=>n.lifestyle=s)},null,512),[[i,n.lifestyle]])])]),l[35]||(l[35]=e("label",null,"ภูมิหลัง",-1)),o(e("textarea",{"onUpdate:modelValue":l[9]||(l[9]=s=>n.background=s)},null,512),[[i,n.background]]),l[36]||(l[36]=e("label",null,"บุคลิก / วิธีพูดคุย",-1)),o(e("textarea",{"onUpdate:modelValue":l[10]||(l[10]=s=>n.personality=s)},null,512),[[i,n.personality]]),l[37]||(l[37]=e("label",null,"สไตล์การสื่อสาร",-1)),o(e("textarea",{"onUpdate:modelValue":l[11]||(l[11]=s=>n.communication_style=s)},null,512),[[i,n.communication_style]])]),k(_).isSuperAdmin?(r(),m("div",gl,[l[38]||(l[38]=e("h4",null,"🎯 การขาย",-1)),l[39]||(l[39]=e("label",null,"เป้าหมาย",-1)),o(e("textarea",{"onUpdate:modelValue":l[12]||(l[12]=s=>n.goal=s)},null,512),[[i,n.goal]]),l[40]||(l[40]=e("label",null,"กรอบเวลาในการตัดสินใจ",-1)),o(e("input",{"onUpdate:modelValue":l[13]||(l[13]=s=>n.decision_timeline=s)},null,512),[[i,n.decision_timeline]]),l[41]||(l[41]=e("label",null,"Pain (ปัญหา) แบบ 1 ต่อบรรทัด",-1)),o(e("textarea",{"onUpdate:modelValue":l[14]||(l[14]=s=>v.value=s),placeholder:`เช่น ต้นทุนสูงเกินไป
ระบบล้าสมัย`},null,512),[[i,v.value]]),l[42]||(l[42]=e("label",null,"ข้อโต้แย้ง (Objections) 1 ต่อบรรทัด",-1)),o(e("textarea",{"onUpdate:modelValue":l[15]||(l[15]=s=>b.value=s)},null,512),[[i,b.value]]),l[43]||(l[43]=e("label",null,"สิ่งที่ใช้ต่อรอง (เช่น ส่วนลด, ฟรีติดตั้ง)",-1)),o(e("textarea",{"onUpdate:modelValue":l[16]||(l[16]=s=>f.value=s)},null,512),[[i,f.value]]),l[44]||(l[44]=e("label",null,"ช่องทางสำหรับลูกค้าเปิดบทสนทนา (opener)",-1)),o(e("textarea",{"onUpdate:modelValue":l[17]||(l[17]=s=>n.opener=s)},null,512),[[i,n.opener]])])):(r(),m("div",yl,[l[45]||(l[45]=e("h4",null,"🔒 ส่วนสูตรการขาย",-1)),l[46]||(l[46]=e("p",{class:"muted"},"ปิดการแก้ไข — เฉพาะผู้ดูแลระดับสูงเท่านั้นที่ดู/แก้ได้ (เพื่อรักษาความได้เปรียบ)",-1)),l[47]||(l[47]=e("label",null,"เป้าหมาย",-1)),o(e("textarea",{"onUpdate:modelValue":l[18]||(l[18]=s=>n.goal=s)},null,512),[[i,n.goal]]),l[48]||(l[48]=e("label",null,"กรอบเวลาในการตัดสินใจ",-1)),o(e("input",{"onUpdate:modelValue":l[19]||(l[19]=s=>n.decision_timeline=s)},null,512),[[i,n.decision_timeline]])])),e("div",bl,[l[53]||(l[53]=e("h4",null,"📡 ช่องทาง & โหมด",-1)),e("div",kl,[e("div",pl,[l[50]||(l[50]=e("label",null,"ช่องทาง",-1)),o(e("select",{"onUpdate:modelValue":l[20]||(l[20]=s=>n.channel=s)},[...l[49]||(l[49]=[e("option",{value:"line"},"LINE",-1),e("option",{value:"facebook"},"Facebook",-1)])],512),[[N,n.channel]])]),e("div",xl,[l[52]||(l[52]=e("label",null,"ใครเริ่มคุยก่อน",-1)),o(e("select",{"onUpdate:modelValue":l[21]||(l[21]=s=>n.initiation_mode=s)},[...l[51]||(l[51]=[e("option",{value:"customer"},"ลูกค้าทักก่อน",-1),e("option",{value:"seller"},"เราต้องเริ่มขาย (เชิงรุก)",-1)])],512),[[N,n.initiation_mode]])])]),k(_).isSuperAdmin&&n.special?(r(),m("label",Vl,"พิเศษ: "+a(n.special),1)):A("",!0)]),e("div",wl,[e("button",{class:"primary",onClick:j,disabled:V.value},a(V.value?"กำลังบันทึก…":"💾 บันทึกบุคคลต้นแบบ"),9,Ul),e("button",{onClick:l[22]||(l[22]=s=>t.$emit("cancel"))},"ปิด")])]))}},Cl=G($l,[["__scopeId","data-v-cef61bd8"]]),cl={class:"row",style:{"align-items":"center","margin-bottom":"8px"}},Bl={style:{margin:"0"}},Al={class:"row",style:{"margin-left":"auto",gap:"10px"}},Sl=["disabled"],zl={key:0,class:"spinner"},jl={key:0,class:"muted"},Ll={key:1,class:"error",style:{margin:"12px 0"}},Nl={key:2,class:"card empty-state"},Pl={class:"grid"},El={class:"row",style:{"justify-content":"space-between","align-items":"center"}},Tl={class:"diff"},_l={class:"muted"},Fl={class:"muted"},Gl=["onClick"],Il={class:"modal"},Ml={__name:"GroupEdit",setup(w){const x=K().params.gid,U=p(null),n=p([]),v=p(!1),b=p(""),f=p(null);async function V(){const u=await z.getGroup(x);U.value=u.group,n.value=(await z.listPersonas(x)).personas}function $(u){return n.value.filter(d=>d.tier===u)}function C(u){return B.t(u==="A"?"tierA":u==="B"?"tierB":"tierC")}function j(u){return{A:"tier-a",B:"tier-b",C:"tier-c"}[u]||""}async function t(){v.value=!0,b.value="";try{const u=await z.analyzeGroup(x);n.value=u.personas,await V()}catch(u){b.value=u.message}finally{v.value=!1}}function l(u){f.value=JSON.parse(JSON.stringify(u))}async function s(u){v.value=!0;try{await z.updatePersona(x,f.value.id,u),f.value=null,await V()}catch(d){b.value=d.message}finally{v.value=!1}}return J(V),(u,d)=>{const I=Q("router-link");return r(),m("div",null,[S(I,{to:"/training",class:"btn-back"},{default:q(()=>[y("← "+a(k(B).t("training")),1)]),_:1}),e("div",cl,[e("h2",Bl,[S(k(W),{size:22,"stroke-width":1.8,style:{"vertical-align":"-4px"}}),y(" "+a(k(B).t("managePersonas")),1)]),e("div",Al,[e("button",{onClick:t,disabled:v.value,class:"primary"},[v.value?(r(),m("span",zl)):(r(),H(k(X),{key:1,size:18,"stroke-width":1.8})),y(" "+a(v.value?"กำลังสร้าง…":k(B).t("analyze")),1)],8,Sl)])]),U.value?(r(),m("p",jl,[d[2]||(d[2]=y("สินค้า: ",-1)),e("strong",null,a(U.value.title),1)])):A("",!0),b.value?(r(),m("div",Ll,a(b.value),1)):A("",!0),d[4]||(d[4]=e("div",{class:"card guide"},[e("strong",null,"วิธีใช้หน้านี้"),e("ol",{style:{margin:"8px 0 0","padding-left":"20px","line-height":"1.8"}},[e("li",null,[y("กดปุ่ม "),e("strong",null,"✨ สร้าง/วิเคราะห์บุคคลต้นแบบ"),y(" เพื่อให้ระบบสร้างลูกค้าจำลอง 15 คน (ระดับ A/B/C)")]),e("li",null,[y("แต่ละการ์ดคือลูกค้าจำลอง 1 คน — กด "),e("strong",null,"✏️ แก้ไข"),y(" เพื่อปรับรายละเอียดให้ตรงใจ")]),e("li",null,[y("เมื่อพร้อมให้ผู้ใช้ฝึก กด "),e("strong",null,"เปิดใช้งาน"),y(" (ยังทำในขั้นถัดไป)")])])],-1)),n.value.length===0&&!v.value?(r(),m("div",Nl,[...d[3]||(d[3]=[e("strong",null,"ยังไม่มีบุคคลต้นแบบ",-1),e("span",null,'กด "✨ สร้าง/วิเคราะห์บุคคลต้นแบบ" เพื่อให้ระบบสร้างลูกค้าจำลองให้',-1)])])):A("",!0),(r(),m(P,null,E(["A","B","C"],c=>e("div",{key:c,style:{"margin-bottom":"20px"}},[e("h4",null,a(C(c)),1),e("div",Pl,[(r(!0),m(P,null,E($(c),g=>(r(),m("div",{key:g.id,class:"card pcard"},[e("div",El,[e("strong",null,a(g.name),1),e("span",{class:F(["badge",j(g.tier)])},a(g.tier),3)]),e("div",Tl,[(r(),m(P,null,E(5,L=>e("span",{key:L,class:F(["star",{on:L<=(g.difficulty||1)}])},"★",2)),64))]),e("div",_l,a(g.profession)+" · "+a(g.age_group)+" · "+a(g.location),1),e("div",Fl,a(g.channel)+" · "+a(g.initiation_mode==="seller"?"เริ่มขายเอง":"ลูกค้าทักก่อน"),1),e("button",{class:"edit-btn",onClick:L=>l(g)},[S(k(Y),{size:15,"stroke-width":1.8}),y(" "+a(k(B).t("edit")),1)],8,Gl)]))),128))])])),64)),f.value?(r(),m("div",{key:3,class:"modal-backdrop",onClick:d[1]||(d[1]=R(c=>f.value=null,["self"]))},[e("div",Il,[S(Cl,{persona:f.value,onSave:s,onCancel:d[0]||(d[0]=c=>f.value=null)},null,8,["persona"])])])):A("",!0)])}}},ql=G(Ml,[["__scopeId","data-v-c682ddb6"]]);export{ql as default};