2 lines
No EOL
19 KiB
JavaScript
2 lines
No EOL
19 KiB
JavaScript
import{f as e,h as t,i as n,l as r,r as i,s as a,t as o}from"./useToast-CS8pZhce.js";import{l as s}from"./indexedDb-DZ-aRPMs.js";import{t as c}from"./arrow-up-down--M136cK3.js";import{t as l}from"./download-ByGeM7La.js";import{t as u}from"./eye-CkF1gwUX.js";import{t as d}from"./save-D8euL60I.js";import{t as f}from"./table-_fqSCPRE.js";import{B as p,C as m,H as h,Y as g,a as _,et as v,r as y,tt as b,u as x}from"./index-CyHCRa3Z.js";import{t as S}from"./currency-DdDs82F5.js";var C={name:`columns-2`,size:24,node:[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`M12 3v18`,key:`108xh3`}]],aliases:[`columns`]};C.node;var w=r(C),T={name:`funnel`,size:24,node:[[`path`,{d:`M10 20a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341L21.74 4.67A1 1 0 0 0 21 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14z`,key:`sc7q7i`}]],aliases:[`filter`]};T.node;var E=r(T),D={name:`move-right`,size:24,node:[[`path`,{d:`M18 8L22 12L18 16`,key:`1r0oui`}],[`path`,{d:`M2 12H22`,key:`1m8cig`}]]};D.node;var O=r(D),k={name:`move-left`,size:24,node:[[`path`,{d:`M6 8L2 12L6 16`,key:`kyvwex`}],[`path`,{d:`M2 12H22`,key:`1m8cig`}]]};k.node;var A=r(k),j=t(e(),1);function M({currentView:e,setCurrentView:t,setIsDirty:n,showToast:r}){return{handleToggleColumn:(0,j.useCallback)(i=>{if(!e)return;let a=e.visibleFieldKeys||[],o;if(a.includes(i)){if(a.length<=1){r({type:`error`,title:`В представлении должна быть минимум 1 колонка`});return}o=a.filter(e=>e!==i)}else o=[...a,i];t({...e,visibleFieldKeys:o}),n(!0)},[e,t,n,r]),handleMoveColumn:(0,j.useCallback)((r,i)=>{if(!e)return;let a=[...e.visibleFieldKeys],[o]=a.splice(r,1);a.splice(i,0,o),t({...e,visibleFieldKeys:a}),n(!0)},[e,t,n])}}var N=a(),P=()=>{let{entityCode:e}=b(),t=v(),{currentEntity:r,views:a,saveView:C,deleteView:T}=h(e),{showToast:D}=o(),k=(0,j.useMemo)(()=>r?.fields||[],[r]),P=(0,j.useMemo)(()=>{let e=new Map;return k.forEach(t=>e.set(t.key,t)),e},[k]),[F,I]=(0,j.useState)(``),[L,R]=(0,j.useState)(null),[z,B]=(0,j.useState)(!1),[V,H]=(0,j.useState)(!1),[U,W]=(0,j.useState)(``),[G,K]=(0,j.useState)([]);(0,j.useEffect)(()=>{Promise.resolve().then(()=>{if(r&&r.fields&&r.fields.length!==0){if(!a||a.length===0){if(e){let t={id:`view_${e}_default`,entityCode:e,name:`Все записи`,type:`table`,isDefault:!0,visibleFieldKeys:r.fields.slice(0,6).map(e=>e.key),filters:[],filterConjunction:`AND`,sortBy:`updatedAt`,sortOrder:`desc`};R(t),I(t.id)}return}if(F){let e=a.find(e=>e.id===F);if(e&&!z){let t=e.visibleFieldKeys&&e.visibleFieldKeys.length>0?e.visibleFieldKeys:r.fields.slice(0,6).map(e=>e.key);R({...e,visibleFieldKeys:t})}}else{let e=a.find(e=>e.isDefault)||a[0],t=e.visibleFieldKeys&&e.visibleFieldKeys.length>0?e.visibleFieldKeys:r.fields.slice(0,6).map(e=>e.key);I(e.id),R({...e,visibleFieldKeys:t})}}})},[a,F,e,r,z]);let q=(0,j.useCallback)(async()=>{if(!e)return;let t=await s(e,{pageSize:50});K(t.items)},[e]);(0,j.useEffect)(()=>{Promise.resolve().then(()=>{q()})},[q]);let J=(0,j.useMemo)(()=>{if(!L)return G;let e=[...G];if(L.filters&&L.filters.length>0){let t=L.filterConjunction||`AND`;e=e.filter(e=>{let n=L.filters.map(t=>{let n=e[t.field],r=t.value;switch(t.operator){case`eq`:return String(n??``).toLowerCase()===String(r??``).toLowerCase();case`neq`:return String(n??``).toLowerCase()!==String(r??``).toLowerCase();case`contains`:return String(n??``).toLowerCase().includes(String(r??``).toLowerCase());case`gt`:return Number(n)>Number(r);case`lt`:return Number(n)<Number(r);case`is_empty`:return n==null||n===``;case`is_not_empty`:return n!=null&&n!==``;default:return!0}});return t===`AND`?n.every(Boolean):n.some(Boolean)})}if(L.sortBy){let{sortBy:t,sortOrder:n=`asc`}=L;e.sort((e,r)=>{let i=e[t],a=r[t];if(i===a)return 0;if(i==null)return 1;if(a==null)return-1;let o=i>a?1:-1;return n===`desc`?-o:o})}return e},[G,L]),{handleToggleColumn:Y,handleMoveColumn:X}=M({currentView:L,setCurrentView:R,setIsDirty:B,showToast:D}),Z=()=>{if(!L)return;let e={field:k[0]?.key||`name`,operator:`contains`,value:``};R({...L,filters:[...L.filters||[],e]}),B(!0)},Q=(e,t)=>{if(!L)return;let n=[...L.filters||[]];n[e]={...n[e],...t},R({...L,filters:n}),B(!0)},$=e=>{L&&(R({...L,filters:L.filters.filter((t,n)=>n!==e)}),B(!0))};return(0,N.jsxs)(`div`,{className:`space-y-4 animate-fade-in`,children:[(0,N.jsxs)(`div`,{className:`flex flex-col md:flex-row md:items-center justify-between gap-3 p-4 bg-krona-surface border border-krona-border rounded-xl shadow-krona-soft`,children:[(0,N.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,N.jsxs)(n,{variant:`ghost`,size:`sm`,onClick:()=>t(`/settings/entities`),className:`p-1.5`,children:[(0,N.jsx)(p,{className:`w-4 h-4 mr-1`}),`Каталог`]}),(0,N.jsxs)(`div`,{children:[(0,N.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,N.jsx)(f,{className:`w-4 h-4 text-krona-green`}),(0,N.jsxs)(`h1`,{className:`text-base font-bold text-krona-primary`,children:[`Конструктор представлений: `,r?.name||e]}),z&&(0,N.jsx)(i,{variant:`warning`,size:`sm`,children:`Несохранённые изменения`})]}),(0,N.jsx)(`p`,{className:`text-xs text-krona-secondary`,children:`Настройка колонок таблицы, расширенной фильтрации (AND/OR), сортировки и сохранённых видов`})]})]}),(0,N.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,N.jsxs)(n,{variant:`outline`,size:`sm`,onClick:()=>{if(!L||J.length===0){D({type:`info`,title:`Нет записей для экспорта`});return}let t=L.visibleFieldKeys.map(e=>P.get(e)||{key:e,label:e}),n=``+[t.map(e=>`"${e.label.replace(/"/g,`""`)}"`).join(`,`),...J.map(e=>t.map(t=>{let n=e[t.key];return n==null?`""`:`"${String(n).replace(/"/g,`""`)}"`}).join(`,`))].join(`\r
|
||
`),r=new Blob([n],{type:`text/csv;charset=utf-8;`}),i=URL.createObjectURL(r),a=document.createElement(`a`);a.setAttribute(`href`,i),a.setAttribute(`download`,`${e}_export_${new Date().toISOString().slice(0,10)}.csv`),document.body.appendChild(a),a.click(),document.body.removeChild(a),D({type:`success`,title:`Файл CSV успешно сформирован и загружен`})},children:[(0,N.jsx)(l,{className:`w-3.5 h-3.5 mr-1`}),`Экспорт CSV`]}),(0,N.jsxs)(n,{variant:`primary`,size:`sm`,"data-testid":`save-view-btn`,onClick:async()=>{if(L)try{await C(L),B(!1),D({type:`success`,title:`Представление «${L.name}» сохранено`})}catch(e){D({type:`error`,title:`Ошибка сохранения представления`,message:e instanceof Error?e.message:String(e)})}},disabled:!L,children:[(0,N.jsx)(d,{className:`w-3.5 h-3.5 mr-1`}),`Сохранить вид`]})]})]}),(0,N.jsxs)(`div`,{className:`flex items-center justify-between gap-2 p-2 bg-krona-surface border border-krona-border rounded-xl overflow-x-auto`,children:[(0,N.jsxs)(`div`,{className:`flex items-center gap-1`,children:[a.map(e=>(0,N.jsxs)(`button`,{onClick:()=>{I(e.id),R({...e}),B(!1)},className:`px-3 py-1.5 rounded-lg text-xs font-medium cursor-pointer transition-all flex items-center gap-1.5 ${F===e.id?`bg-krona-green text-white shadow-sm`:`bg-krona-workspace text-krona-secondary hover:text-krona-primary`}`,children:[(0,N.jsx)(`span`,{children:e.name}),e.isDefault&&(0,N.jsx)(`span`,{className:`text-[10px] opacity-80`,title:`По умолчанию`,children:`★`})]},e.id)),(0,N.jsxs)(`button`,{onClick:()=>H(!0),className:`px-2.5 py-1.5 rounded-lg text-xs font-medium bg-krona-workspace hover:bg-krona-surface-muted text-krona-secondary hover:text-krona-primary flex items-center gap-1 border border-dashed border-krona-border cursor-pointer`,children:[(0,N.jsx)(m,{className:`w-3 h-3`}),`Создать вид`]})]}),L&&!L.isDefault&&(0,N.jsxs)(`button`,{onClick:async()=>{if(L){if(L.isDefault){D({type:`error`,title:`Нельзя удалить представление по умолчанию`});return}if(confirm(`Удалить сохранённое представление «${L.name}»?`))try{await T(L.id),D({type:`success`,title:`Представление удалено`}),I(``),R(null)}catch(e){D({type:`error`,title:`Ошибка удаления`,message:e instanceof Error?e.message:String(e)})}}},className:`text-xs text-krona-danger hover:underline px-2 py-1 flex items-center gap-1 cursor-pointer`,children:[(0,N.jsx)(x,{className:`w-3.5 h-3.5`}),`Удалить этот вид`]})]}),L&&(0,N.jsxs)(`div`,{className:`grid grid-cols-1 lg:grid-cols-12 gap-4`,children:[(0,N.jsxs)(`div`,{className:`lg:col-span-4 space-y-4`,children:[(0,N.jsxs)(`div`,{className:`p-3.5 bg-krona-surface border border-krona-border rounded-xl space-y-3`,children:[(0,N.jsx)(_,{label:`Название представления`,value:L.name,onChange:e=>{R({...L,name:e.target.value}),B(!0)}}),(0,N.jsxs)(`label`,{className:`flex items-center gap-2 cursor-pointer text-xs font-medium text-krona-primary`,children:[(0,N.jsx)(`input`,{type:`checkbox`,checked:L.isDefault||!1,onChange:e=>{R({...L,isDefault:e.target.checked}),B(!0)},className:`rounded text-krona-green`}),`Представление по умолчанию для всех`]})]}),(0,N.jsxs)(`div`,{className:`p-3.5 bg-krona-surface border border-krona-border rounded-xl space-y-3`,children:[(0,N.jsx)(`div`,{className:`flex items-center justify-between`,children:(0,N.jsxs)(`span`,{className:`text-xs font-bold text-krona-primary uppercase tracking-wider flex items-center gap-1.5`,children:[(0,N.jsx)(w,{className:`w-3.5 h-3.5 text-krona-green`}),`Колонки таблицы (`,L.visibleFieldKeys.length,`)`]})}),(0,N.jsx)(`div`,{className:`space-y-1.5 max-h-56 overflow-y-auto pr-1`,children:L.visibleFieldKeys.map((e,t)=>{let n=P.get(e);return(0,N.jsxs)(`div`,{"data-testid":`column-pill-${e}`,draggable:!0,onDragStart:e=>{e.dataTransfer.setData(`text/plain`,String(t))},onDragOver:e=>e.preventDefault(),onDrop:e=>{e.preventDefault();let n=Number(e.dataTransfer.getData(`text/plain`));!isNaN(n)&&n!==t&&X(n,t)},className:`flex items-center justify-between p-2 rounded bg-krona-workspace text-xs border border-krona-border/60 cursor-grab active:cursor-grabbing`,children:[(0,N.jsx)(`span`,{className:`font-medium text-krona-primary truncate`,children:n?.label||e}),(0,N.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,N.jsx)(`button`,{type:`button`,onClick:()=>X(t,t-1),disabled:t===0,className:`p-1 text-krona-secondary hover:text-krona-primary disabled:opacity-20`,title:`Влево`,children:(0,N.jsx)(A,{className:`w-3 h-3`})}),(0,N.jsx)(`button`,{type:`button`,onClick:()=>X(t,t+1),disabled:t===L.visibleFieldKeys.length-1,className:`p-1 text-krona-secondary hover:text-krona-primary disabled:opacity-20`,title:`Вправо`,children:(0,N.jsx)(O,{className:`w-3 h-3`})}),(0,N.jsx)(`button`,{type:`button`,onClick:()=>Y(e),className:`p-1 text-krona-danger hover:bg-krona-danger/10 rounded`,title:`Скрыть колонку`,children:`✕`})]})]},e)})}),(0,N.jsxs)(`div`,{className:`pt-2 border-t border-krona-border/60`,children:[(0,N.jsx)(`span`,{className:`text-[11px] font-semibold text-krona-secondary block mb-1.5`,children:`Доступные поля сущности:`}),(0,N.jsx)(`div`,{className:`space-y-1 max-h-36 overflow-y-auto text-xs`,children:k.map(e=>{let t=L.visibleFieldKeys.includes(e.key);return(0,N.jsxs)(`label`,{className:`flex items-center gap-2 p-1 rounded hover:bg-krona-workspace cursor-pointer`,children:[(0,N.jsx)(`input`,{type:`checkbox`,checked:t,onChange:()=>Y(e.key),className:`rounded text-krona-green`}),(0,N.jsx)(`span`,{className:`truncate text-krona-primary`,children:e.label}),(0,N.jsx)(`span`,{className:`text-[10px] font-mono text-krona-secondary ml-auto`,children:e.key})]},e.key)})})]})]}),(0,N.jsxs)(`div`,{className:`p-3.5 bg-krona-surface border border-krona-border rounded-xl space-y-3`,children:[(0,N.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,N.jsxs)(`span`,{className:`text-xs font-bold text-krona-primary uppercase tracking-wider flex items-center gap-1.5`,children:[(0,N.jsx)(E,{className:`w-3.5 h-3.5 text-krona-gold`}),`Фильтрация (`,L.filters?.length||0,`)`]}),(0,N.jsx)(`div`,{className:`flex items-center gap-1 bg-krona-workspace rounded p-0.5 border border-krona-border`,children:[`AND`,`OR`].map(e=>(0,N.jsx)(`button`,{onClick:()=>{R({...L,filterConjunction:e}),B(!0)},className:`px-2 py-0.5 text-[10px] font-bold rounded ${(L.filterConjunction||`AND`)===e?`bg-krona-green text-white`:`text-krona-secondary`}`,children:e===`AND`?`И`:`ИЛИ`},e))})]}),(0,N.jsx)(`div`,{className:`space-y-2`,children:L.filters?.map((e,t)=>(0,N.jsxs)(`div`,{className:`p-2 bg-krona-workspace rounded-lg border border-krona-border/60 space-y-1.5`,children:[(0,N.jsxs)(`div`,{className:`flex items-center justify-between gap-1`,children:[(0,N.jsx)(`select`,{value:e.field,onChange:e=>Q(t,{field:e.target.value}),className:`bg-krona-surface text-krona-primary border border-krona-border rounded px-2 py-1 text-xs w-full`,children:k.map(e=>(0,N.jsx)(`option`,{value:e.key,children:e.label},e.key))}),(0,N.jsx)(`button`,{type:`button`,onClick:()=>$(t),className:`p-1 text-krona-danger hover:bg-krona-danger/10 rounded`,title:`Удалить фильтр`,children:(0,N.jsx)(x,{className:`w-3.5 h-3.5`})})]}),(0,N.jsxs)(`div`,{className:`grid grid-cols-2 gap-1.5`,children:[(0,N.jsxs)(`select`,{value:e.operator,onChange:e=>Q(t,{operator:e.target.value}),className:`bg-krona-surface text-krona-primary border border-krona-border rounded px-2 py-1 text-xs`,children:[(0,N.jsx)(`option`,{value:`contains`,children:`содержит`}),(0,N.jsx)(`option`,{value:`eq`,children:`равно`}),(0,N.jsx)(`option`,{value:`neq`,children:`не равно`}),(0,N.jsx)(`option`,{value:`gt`,children:`больше (>)`}),(0,N.jsx)(`option`,{value:`lt`,children:`меньше (<)`}),(0,N.jsx)(`option`,{value:`is_empty`,children:`пусто`}),(0,N.jsx)(`option`,{value:`is_not_empty`,children:`не пусто`})]}),e.operator!==`is_empty`&&e.operator!==`is_not_empty`&&(0,N.jsx)(`input`,{type:`text`,placeholder:`Значение...`,value:String(e.value??``),onChange:e=>Q(t,{value:e.target.value}),className:`bg-krona-surface text-krona-primary border border-krona-border rounded px-2 py-1 text-xs`})]})]},t))}),(0,N.jsxs)(n,{variant:`outline`,size:`sm`,className:`w-full text-xs`,onClick:Z,children:[(0,N.jsx)(m,{className:`w-3 h-3 mr-1`}),`Добавить условие`]})]}),(0,N.jsxs)(`div`,{className:`p-3.5 bg-krona-surface border border-krona-border rounded-xl space-y-2`,children:[(0,N.jsxs)(`span`,{className:`text-xs font-bold text-krona-primary uppercase tracking-wider flex items-center gap-1.5`,children:[(0,N.jsx)(c,{className:`w-3.5 h-3.5 text-krona-info`}),`Сортировка`]}),(0,N.jsxs)(`div`,{className:`grid grid-cols-2 gap-2`,children:[(0,N.jsxs)(`select`,{value:L.sortBy||``,onChange:e=>{R({...L,sortBy:e.target.value}),B(!0)},className:`bg-krona-surface text-krona-primary border border-krona-border rounded px-2 py-1.5 text-xs`,children:[(0,N.jsx)(`option`,{value:``,children:`Без сортировки`}),k.map(e=>(0,N.jsx)(`option`,{value:e.key,children:e.label},e.key))]}),(0,N.jsxs)(`select`,{value:L.sortOrder||`asc`,onChange:e=>{R({...L,sortOrder:e.target.value}),B(!0)},className:`bg-krona-surface text-krona-primary border border-krona-border rounded px-2 py-1.5 text-xs`,children:[(0,N.jsx)(`option`,{value:`asc`,children:`По возрастанию (А-Я)`}),(0,N.jsx)(`option`,{value:`desc`,children:`По убыванию (Я-А)`})]})]})]})]}),(0,N.jsx)(`div`,{className:`lg:col-span-8 space-y-3`,children:(0,N.jsxs)(`div`,{className:`p-3.5 bg-krona-surface border border-krona-border rounded-xl shadow-krona-soft space-y-3`,children:[(0,N.jsxs)(`div`,{className:`flex items-center justify-between text-xs`,children:[(0,N.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,N.jsx)(u,{className:`w-4 h-4 text-krona-gold`}),(0,N.jsx)(`span`,{className:`font-semibold text-krona-primary`,children:`Интерактивное превью таблицы данных`})]}),(0,N.jsxs)(`span`,{className:`text-krona-secondary`,children:[`Отображается записей: `,(0,N.jsx)(`strong`,{children:J.length}),` (всего в базе:`,` `,G.length,`)`]})]}),(0,N.jsx)(`div`,{className:`overflow-x-auto border border-krona-border rounded-lg max-h-[550px]`,children:(0,N.jsxs)(`table`,{className:`w-full text-left text-xs border-collapse`,children:[(0,N.jsx)(`thead`,{className:`bg-krona-workspace sticky top-0 border-b border-krona-border`,children:(0,N.jsx)(`tr`,{children:L.visibleFieldKeys.map(e=>{let t=P.get(e);return(0,N.jsx)(`th`,{className:`p-2.5 font-semibold text-krona-primary border-r border-krona-border/60 last:border-r-0 whitespace-nowrap`,children:t?.label||e},e)})})}),(0,N.jsxs)(`tbody`,{className:`divide-y divide-krona-border/60 bg-krona-surface`,children:[J.map(e=>(0,N.jsx)(`tr`,{className:`hover:bg-krona-workspace/50 transition-colors`,children:L.visibleFieldKeys.map(t=>{let n=P.get(t),r=e[t],a=`—`;return r!=null&&r!==``&&(a=n?.type===`money`?typeof r==`number`?S(r):String(r):n?.type===`boolean`?r?`Да`:`Нет`:n?.type===`date`||n?.type===`datetime`?g(String(r)):String(r)),(0,N.jsx)(`td`,{className:`p-2.5 text-krona-secondary truncate max-w-xs border-r border-krona-border/40 last:border-r-0`,children:t===`status`?(0,N.jsx)(i,{variant:`neutral`,size:`sm`,children:a}):(0,N.jsx)(`span`,{className:`text-krona-primary font-medium`,children:a})},t)})},e.id)),J.length===0&&(0,N.jsx)(`tr`,{children:(0,N.jsx)(`td`,{colSpan:L.visibleFieldKeys.length,className:`text-center py-10 text-krona-secondary`,children:`Записи не найдены или отфильтрованы`})})]})]})})]})})]}),(0,N.jsx)(y,{isOpen:V,onClose:()=>H(!1),title:`Новое представление`,subtitle:`Создайте сохранённый вид таблицы с индивидуальными фильтрами и колонками`,maxWidth:`sm`,children:(0,N.jsxs)(`div`,{className:`space-y-4`,children:[(0,N.jsx)(_,{label:`Название представления *`,value:U,onChange:e=>W(e.target.value),placeholder:`Например: Мои активные заявки`,autoFocus:!0}),(0,N.jsxs)(`div`,{className:`flex justify-end gap-2 pt-3 border-t border-krona-border`,children:[(0,N.jsx)(n,{variant:`outline`,size:`sm`,onClick:()=>H(!1),children:`Отмена`}),(0,N.jsx)(n,{variant:`primary`,size:`sm`,onClick:async()=>{if(!U.trim()||!e)return;let t=`view_${Date.now().toString(36)}`,n={id:t,entityCode:e,name:U.trim(),type:`table`,isDefault:!1,visibleFieldKeys:k.slice(0,5).map(e=>e.key),filters:[],filterConjunction:`AND`};try{await C(n),I(t),R(n),H(!1),W(``),D({type:`success`,title:`Представление «${n.name}» создано`})}catch(e){D({type:`error`,title:`Ошибка создания представления`,message:e instanceof Error?e.message:String(e)})}},children:`Создать`})]})]})})]})};export{P as ViewBuilder,P as default}; |