Files
app/dist/assets/TripsAdmin-Cy0KleKy.js
Simon 4c8a41c107 feat: filemanager - plná cesta na disku, podpora symlinků, oprava stylů
- Backend: listFiles vrací full_path, detekce symlinků/junctions
- Backend: resolveProjectPath povoluje navigaci přes symlinky
- Frontend: zobrazení plné cesty pod breadcrumbem
- Frontend: ikona odkazu u symlinků s tooltipem cíle
- Fix: underline jen na názvu složky, ne na počtu položek

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 14:10:00 +01:00

82 lines
19 KiB
JavaScript

import{j as e,m as p,A as Z}from"./vendor-animation-0s3FMHwK.js";import{r as i,L as J}from"./vendor-react-BVs3cwbi.js";import{a9 as G}from"./vendor-utils-Dyr8OjFr.js";import{a as q,u as Q,c as b,b as X,F as r,A as C,f as l,C as ee}from"./index-c9Us0bor.js";import{F as se}from"./Forbidden-D25jV3Oq.js";import{b as $}from"./attendanceHelpers-D6sLEw0q.js";const N="/api/admin";function de(){const d=q(),{hasPermission:L}=Q(),[k,D]=i.useState(!0),[j,V]=i.useState(()=>{const s=new Date;return`${s.getFullYear()}-${String(s.getMonth()+1).padStart(2,"0")}-01`}),[g,A]=i.useState(()=>{const s=new Date,t=new Date(s.getFullYear(),s.getMonth()+1,0).getDate();return`${s.getFullYear()}-${String(s.getMonth()+1).padStart(2,"0")}-${String(t).padStart(2,"0")}`}),[m,F]=i.useState(""),[h,E]=i.useState(""),[P,B]=i.useState({trips:[],vehicles:[],users:[],totals:{total:0,business:0,count:0}}),[n,I]=i.useState(null),w=i.useRef(null),[T,v]=i.useState(!1),[_,U]=i.useState(null),[a,o]=i.useState({vehicle_id:"",trip_date:"",start_km:"",end_km:"",route_from:"",route_to:"",is_business:1,notes:""}),[u,z]=i.useState({show:!1,trip:null}),y=i.useCallback(async(s=!0)=>{s&&D(!0);try{let t=`${N}/trips.php?action=admin&date_from=${j}&date_to=${g}`;m&&(t+=`&vehicle_id=${m}`),h&&(t+=`&user_id=${h}`);const c=await(await b(t)).json();c.success&&B(c.data)}catch{d.error("Nepodařilo se načíst data")}finally{s&&D(!1)}},[j,g,m,h,d]);if(i.useEffect(()=>{y()},[y]),X(T),!L("trips.admin"))return e.jsx(se,{});const H=s=>{U(s),o({vehicle_id:s.vehicle_id,trip_date:s.trip_date,start_km:s.start_km,end_km:s.end_km,route_from:s.route_from,route_to:s.route_to,is_business:s.is_business,notes:s.notes||""}),v(!0)},O=async()=>{if(parseInt(a.end_km)<=parseInt(a.start_km)){d.error("Konečný stav km musí být větší než počáteční");return}try{const t=await(await b(`${N}/trips.php?id=${_.id}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)})).json();t.success?(v(!1),await y(!1),await new Promise(x=>setTimeout(x,300)),d.success(t.message)):d.error(t.error)}catch{d.error("Chyba připojení")}},W=async()=>{if(u.trip)try{const t=await(await b(`${N}/trips.php?id=${u.trip.id}`,{method:"DELETE"})).json();t.success?(z({show:!1,trip:null}),await y(!1),d.success(t.message)):d.error(t.error)}catch{d.error("Chyba připojení")}},K=async()=>{try{let s=`${N}/trips.php?action=print&date_from=${j}&date_to=${g}`;m&&(s+=`&vehicle_id=${m}`),h&&(s+=`&user_id=${h}`);const x=await(await b(s)).json();x.success&&(I(x.data),setTimeout(()=>{if(w.current){const c=window.open("","_blank");c.document.write(`
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Kniha jízd - ${x.data.period_name}</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 10px;
line-height: 1.4;
color: #000;
background: #fff;
padding: 10mm;
}
.print-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 2px solid #333;
}
.print-header-left {
display: flex;
align-items: center;
gap: 12px;
}
.print-logo {
height: 40px;
width: auto;
}
.print-header-text { text-align: left; }
.print-header-right { text-align: right; }
.print-header h1 { font-size: 18px; font-weight: 700; margin-bottom: 3px; }
.print-header .company { font-size: 11px; color: #666; }
.print-header .period { font-size: 13px; font-weight: 600; color: #333; margin-bottom: 2px; }
.print-header .filters { font-size: 10px; color: #666; }
.print-header .generated { font-size: 9px; color: #888; margin-top: 5px; }
.summary {
display: flex;
justify-content: space-around;
margin-bottom: 15px;
padding: 10px;
background: #f5f5f5;
border: 1px solid #ddd;
}
.summary-item { text-align: center; }
.summary-value { font-size: 14px; font-weight: 700; }
.summary-label { font-size: 9px; color: #666; }
table { width: 100%; border-collapse: collapse; margin-bottom: 15px; }
th, td { border: 1px solid #333; padding: 4px 6px; text-align: left; }
th { background: #333; color: #fff; font-weight: 600; font-size: 9px; text-transform: uppercase; }
td { font-size: 9px; }
tr:nth-child(even) { background: #f9f9f9; }
.text-center { text-align: center; }
.text-right { text-align: right; }
tfoot td { background: #eee; font-weight: 600; }
.badge {
display: inline-block;
padding: 1px 4px;
border-radius: 2px;
font-size: 8px;
font-weight: 500;
}
.badge-success { background: #dcfce7; color: #16a34a; }
.badge-warning { background: #fef3c7; color: #d97706; }
@media print {
body { padding: 5mm; }
@page { size: A4 landscape; margin: 5mm; }
thead { display: table-header-group; }
}
</style>
</head>
<body>
${G.sanitize(w.current.innerHTML)}
</body>
</html>
`),c.document.close(),c.onload=()=>{c.print()}}},100))}catch{d.error("Nepodařilo se připravit tisk")}},R=()=>{const s=parseInt(a.start_km)||0,t=parseInt(a.end_km)||0;return t>s?t-s:0},{trips:f,vehicles:M,users:Y,totals:S}=P;return e.jsxs("div",{children:[e.jsxs(p.div,{className:"admin-page-header",initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{duration:.4},children:[e.jsx("div",{children:e.jsx("h1",{className:"admin-page-title",children:"Správa knihy jízd"})}),e.jsxs("div",{className:"admin-page-actions",children:[f.length>0&&e.jsxs("button",{onClick:K,className:"admin-btn admin-btn-secondary",title:"Tisk knihy jízd",children:[e.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",style:{marginRight:"0.5rem"},children:[e.jsx("polyline",{points:"6 9 6 2 18 2 18 9"}),e.jsx("path",{d:"M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"}),e.jsx("rect",{x:"6",y:"14",width:"12",height:"8"})]}),"Tisk"]}),e.jsx(J,{to:"/vehicles",className:"admin-btn admin-btn-secondary",children:"Vozidla"})]})]}),e.jsx(p.div,{className:"admin-card",initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{duration:.4,delay:.1},children:e.jsx("div",{className:"admin-card-body",children:e.jsxs("div",{className:"admin-form-row admin-form-row-4",children:[e.jsx(r,{label:"Od",style:{marginBottom:0},children:e.jsx(C,{mode:"date",value:j,onChange:s=>V(s)})}),e.jsx(r,{label:"Do",style:{marginBottom:0},children:e.jsx(C,{mode:"date",value:g,onChange:s=>A(s)})}),e.jsx(r,{label:"Vozidlo",style:{marginBottom:0},children:e.jsxs("select",{value:m,onChange:s=>F(s.target.value),className:"admin-form-select",children:[e.jsx("option",{value:"",children:"Všechna vozidla"}),M.map(s=>e.jsxs("option",{value:s.id,children:[s.spz," - ",s.name]},s.id))]})}),e.jsx(r,{label:"Řidič",style:{marginBottom:0},children:e.jsxs("select",{value:h,onChange:s=>E(s.target.value),className:"admin-form-select",children:[e.jsx("option",{value:"",children:"Všichni řidiči"}),Y.map(s=>e.jsx("option",{value:s.id,children:s.name},s.id))]})})]})})}),e.jsxs(p.div,{className:"admin-grid admin-grid-3 mt-6",initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{duration:.4,delay:.15},children:[e.jsxs("div",{className:"admin-stat-card info",children:[e.jsx("div",{className:"admin-stat-icon info",children:e.jsxs("svg",{width:"22",height:"22",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("line",{x1:"12",y1:"20",x2:"12",y2:"10"}),e.jsx("line",{x1:"18",y1:"20",x2:"18",y2:"4"}),e.jsx("line",{x1:"6",y1:"20",x2:"6",y2:"16"})]})}),e.jsxs("div",{className:"admin-stat-content",children:[e.jsx("span",{className:"admin-stat-value",children:S.count}),e.jsx("span",{className:"admin-stat-label",children:"Počet jízd"})]})]}),e.jsxs("div",{className:"admin-stat-card",children:[e.jsx("div",{className:"admin-stat-icon",children:e.jsx("svg",{width:"22",height:"22",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:e.jsx("path",{d:"M22 12h-4l-3 9L9 3l-3 9H2"})})}),e.jsxs("div",{className:"admin-stat-content",children:[e.jsxs("span",{className:"admin-stat-value",children:[l(S.total)," km"]}),e.jsx("span",{className:"admin-stat-label",children:"Celkem naježděno"})]})]}),e.jsxs("div",{className:"admin-stat-card success",children:[e.jsx("div",{className:"admin-stat-icon success",children:e.jsxs("svg",{width:"22",height:"22",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("rect",{x:"1",y:"3",width:"15",height:"13",rx:"2",ry:"2"}),e.jsx("path",{d:"M16 8h2a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-1"}),e.jsx("circle",{cx:"5.5",cy:"18",r:"2"}),e.jsx("circle",{cx:"18.5",cy:"18",r:"2"}),e.jsx("path",{d:"M8 18h8"})]})}),e.jsxs("div",{className:"admin-stat-content",children:[e.jsxs("span",{className:"admin-stat-value",children:[l(S.business)," km"]}),e.jsx("span",{className:"admin-stat-label",children:"Služební km"})]})]})]}),e.jsx(p.div,{className:"admin-card mt-6",initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{duration:.4,delay:.2},children:e.jsxs("div",{className:"admin-card-body",children:[k&&e.jsx("div",{className:"admin-skeleton",style:{gap:"1.25rem"},children:[0,1,2,3,4].map(s=>e.jsxs("div",{className:"admin-skeleton-row",children:[e.jsx("div",{className:"admin-skeleton-line w-1/4"}),e.jsx("div",{className:"admin-skeleton-line w-1/3"}),e.jsx("div",{className:"admin-skeleton-line w-1/4"})]},s))}),!k&&f.length===0&&e.jsx("div",{className:"admin-empty-state",children:e.jsx("p",{children:"Žádné záznamy jízd pro vybrané období."})}),!k&&f.length>0&&e.jsx("div",{className:"admin-table-responsive",children:e.jsxs("table",{className:"admin-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Datum"}),e.jsx("th",{children:"Řidič"}),e.jsx("th",{children:"Vozidlo"}),e.jsx("th",{children:"Trasa"}),e.jsx("th",{children:"Stav km"}),e.jsx("th",{children:"Vzdálenost"}),e.jsx("th",{children:"Typ"}),e.jsx("th",{children:"Akce"})]})}),e.jsx("tbody",{children:f.map(s=>e.jsxs("tr",{children:[e.jsx("td",{className:"admin-mono",children:$(s.trip_date)}),e.jsx("td",{children:s.driver_name}),e.jsx("td",{children:e.jsx("span",{className:"admin-badge",children:s.spz})}),e.jsx("td",{children:e.jsxs("span",{style:{whiteSpace:"nowrap"},children:[s.route_from," → ",s.route_to]})}),e.jsx("td",{className:"admin-mono",children:e.jsxs("span",{style:{whiteSpace:"nowrap"},children:[l(s.start_km)," - ",l(s.end_km)]})}),e.jsx("td",{className:"admin-mono",children:e.jsxs("strong",{children:[l(s.distance)," km"]})}),e.jsx("td",{children:e.jsx("span",{className:`admin-badge ${s.is_business?"admin-badge-success":"admin-badge-warning"}`,children:s.is_business?"Služební":"Soukromá"})}),e.jsx("td",{children:e.jsxs("div",{className:"admin-table-actions",children:[e.jsx("button",{onClick:()=>H(s),className:"admin-btn-icon",title:"Upravit","aria-label":"Upravit",children:e.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("path",{d:"M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"}),e.jsx("path",{d:"M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"})]})}),e.jsx("button",{onClick:()=>z({show:!0,trip:s}),className:"admin-btn-icon danger",title:"Smazat","aria-label":"Smazat",children:e.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("polyline",{points:"3 6 5 6 21 6"}),e.jsx("path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"})]})})]})})]},s.id))})]})})]})}),e.jsx(Z,{children:T&&_&&e.jsxs(p.div,{className:"admin-modal-overlay",initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},transition:{duration:.2},children:[e.jsx("div",{className:"admin-modal-backdrop",onClick:()=>v(!1)}),e.jsxs(p.div,{className:"admin-modal admin-modal-lg",initial:{opacity:0,scale:.95,y:20},animate:{opacity:1,scale:1,y:0},exit:{opacity:0,scale:.95,y:20},transition:{duration:.2},children:[e.jsxs("div",{className:"admin-modal-header",children:[e.jsx("h2",{className:"admin-modal-title",children:"Upravit jízdu"}),e.jsx("p",{style:{color:"var(--text-secondary)",marginTop:"0.25rem"},children:_.driver_name})]}),e.jsx("div",{className:"admin-modal-body",children:e.jsxs("div",{className:"admin-form",children:[e.jsxs("div",{className:"admin-form-row",children:[e.jsx(r,{label:"Vozidlo",children:e.jsx("select",{value:a.vehicle_id,onChange:s=>o({...a,vehicle_id:s.target.value}),className:"admin-form-select",children:M.map(s=>e.jsxs("option",{value:s.id,children:[s.spz," - ",s.name]},s.id))})}),e.jsx(r,{label:"Datum jízdy",children:e.jsx(C,{mode:"date",value:a.trip_date,onChange:s=>o({...a,trip_date:s})})})]}),e.jsxs("div",{className:"admin-form-row",children:[e.jsx(r,{label:"Počáteční stav km",children:e.jsx("input",{type:"number",inputMode:"numeric",value:a.start_km,onChange:s=>o({...a,start_km:s.target.value}),className:"admin-form-input",min:"0"})}),e.jsx(r,{label:"Konečný stav km",children:e.jsx("input",{type:"number",inputMode:"numeric",value:a.end_km,onChange:s=>o({...a,end_km:s.target.value}),className:"admin-form-input",min:"0"})}),e.jsx(r,{label:"Vzdálenost",children:e.jsx("input",{type:"text",value:`${l(R())} km`,className:"admin-form-input",readOnly:!0,disabled:!0})})]}),e.jsxs("div",{className:"admin-form-row",children:[e.jsx(r,{label:"Místo odjezdu",children:e.jsx("input",{type:"text",value:a.route_from,onChange:s=>o({...a,route_from:s.target.value}),className:"admin-form-input"})}),e.jsx(r,{label:"Místo příjezdu",children:e.jsx("input",{type:"text",value:a.route_to,onChange:s=>o({...a,route_to:s.target.value}),className:"admin-form-input"})})]}),e.jsx(r,{label:"Typ jízdy",children:e.jsxs("select",{value:a.is_business,onChange:s=>o({...a,is_business:parseInt(s.target.value)}),className:"admin-form-select",children:[e.jsx("option",{value:1,children:"Služební"}),e.jsx("option",{value:0,children:"Soukromá"})]})}),e.jsx(r,{label:"Poznámky",children:e.jsx("textarea",{value:a.notes,onChange:s=>o({...a,notes:s.target.value}),className:"admin-form-textarea",rows:2})})]})}),e.jsxs("div",{className:"admin-modal-footer",children:[e.jsx("button",{type:"button",onClick:()=>v(!1),className:"admin-btn admin-btn-secondary",children:"Zrušit"}),e.jsx("button",{type:"button",onClick:O,className:"admin-btn admin-btn-primary",children:"Uložit"})]})]})]})}),e.jsx(ee,{isOpen:u.show,onClose:()=>z({show:!1,trip:null}),onConfirm:W,title:"Smazat záznam",message:u.trip?`Opravdu chcete smazat záznam jízdy z ${$(u.trip.trip_date)}?`:"",confirmText:"Smazat",confirmVariant:"danger"}),n&&e.jsxs("div",{ref:w,style:{display:"none"},children:[e.jsxs("div",{className:"print-header",children:[e.jsxs("div",{className:"print-header-left",children:[e.jsx("img",{src:"/images/logo-light.png",alt:"BOHA",className:"print-logo"}),e.jsxs("div",{className:"print-header-text",children:[e.jsx("h1",{children:"KNIHA JÍZD"}),e.jsx("div",{className:"company",children:"BOHA Automation s.r.o."})]})]}),e.jsxs("div",{className:"print-header-right",children:[e.jsx("div",{className:"period",children:n.period_name}),n.selected_vehicle_name&&e.jsxs("div",{className:"filters",children:["Vozidlo: ",n.selected_vehicle_name]}),n.selected_user_name&&e.jsxs("div",{className:"filters",children:["Řidič: ",n.selected_user_name]}),e.jsxs("div",{className:"generated",children:["Vygenerováno: ",new Date().toLocaleString("cs-CZ")]})]})]}),e.jsxs("div",{className:"summary",children:[e.jsxs("div",{className:"summary-item",children:[e.jsx("div",{className:"summary-value",children:n.totals.count}),e.jsx("div",{className:"summary-label",children:"Počet jízd"})]}),e.jsxs("div",{className:"summary-item",children:[e.jsxs("div",{className:"summary-value",children:[l(n.totals.total)," km"]}),e.jsx("div",{className:"summary-label",children:"Celkem"})]}),e.jsxs("div",{className:"summary-item",children:[e.jsxs("div",{className:"summary-value",children:[l(n.totals.business)," km"]}),e.jsx("div",{className:"summary-label",children:"Služební"})]}),e.jsxs("div",{className:"summary-item",children:[e.jsxs("div",{className:"summary-value",children:[l(n.totals.private)," km"]}),e.jsx("div",{className:"summary-label",children:"Soukromé"})]})]}),e.jsxs("table",{children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{style:{width:"70px"},children:"Datum"}),e.jsx("th",{style:{width:"80px"},children:"Řidič"}),e.jsx("th",{style:{width:"70px"},children:"Vozidlo"}),e.jsx("th",{children:"Trasa"}),e.jsx("th",{style:{width:"70px"},className:"text-right",children:"Stav km"}),e.jsx("th",{style:{width:"60px"},className:"text-right",children:"Vzdálenost"}),e.jsx("th",{style:{width:"55px"},className:"text-center",children:"Typ"}),e.jsx("th",{children:"Poznámka"})]})}),e.jsx("tbody",{children:n.trips.map(s=>e.jsxs("tr",{children:[e.jsx("td",{children:$(s.trip_date)}),e.jsx("td",{children:s.driver_name}),e.jsx("td",{children:s.spz}),e.jsxs("td",{children:[s.route_from," → ",s.route_to]}),e.jsxs("td",{className:"text-right",children:[l(s.start_km)," - ",l(s.end_km)]}),e.jsx("td",{className:"text-right",children:e.jsxs("strong",{children:[l(s.distance)," km"]})}),e.jsx("td",{className:"text-center",children:e.jsx("span",{className:`badge ${s.is_business?"badge-success":"badge-warning"}`,children:s.is_business?"Služební":"Soukromá"})}),e.jsx("td",{children:s.notes||""})]},s.id))}),e.jsx("tfoot",{children:e.jsxs("tr",{children:[e.jsx("td",{colSpan:5,className:"text-right",children:"Celkem:"}),e.jsx("td",{className:"text-right",children:e.jsxs("strong",{children:[l(n.totals.total)," km"]})}),e.jsx("td",{colSpan:2})]})})]}),n.trips.length===0&&e.jsx("p",{style:{textAlign:"center",padding:"20px"},children:"Za vybrané období nejsou žádné záznamy."})]})]})}export{de as default};