diff --git a/api/openapi.yaml b/api/openapi.yaml index 2d2908d..1100a55 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.1.0 info: title: Krona Staff API - version: 0.3.0 + version: 0.3.1 description: API посещаемости Krona Staff для кабинета сотрудника, терминала и табеля руководителя. license: name: Proprietary @@ -107,6 +107,39 @@ paths: schema: { $ref: '#/components/schemas/Employee' } '403': { description: Недостаточно прав } '409': { description: Табельный номер уже используется } + /professions: + get: + summary: Получить кадровый справочник профессий + operationId: listStaffProfessions + tags: [Employees] + security: [{ bearerAuth: [] }] + responses: + '200': { description: Tenant profession catalogue } + '401': { description: Требуется авторизация } + post: + summary: Добавить профессию в кадровый справочник + operationId: createStaffProfession + tags: [Employees] + security: [{ bearerAuth: [] }] + responses: + '201': { description: Profession created } + '403': { description: Недостаточно прав } + '409': { description: Профессия уже существует } + /professions/{professionId}: + parameters: + - in: path + name: professionId + required: true + schema: { type: string, pattern: '^[0-9A-HJKMNP-TV-Z]{26}$' } + patch: + summary: Изменить профессию или её статус + operationId: updateStaffProfession + tags: [Employees] + security: [{ bearerAuth: [] }] + responses: + '200': { description: Profession updated } + '403': { description: Недостаточно прав } + '404': { description: Профессия не найдена } /employees/{employeeId}: patch: summary: Изменить карточку или статус сотрудника @@ -177,7 +210,8 @@ paths: date_to: { type: string, format: date } business_day_start_hour: { type: integer, minimum: 0, maximum: 23, default: 4 } automatic_close_hour: { type: integer, minimum: 0, maximum: 23, default: 2 } - open_shift_threshold_minutes: { type: integer, minimum: 60, maximum: 2880, default: 840 } + open_shift_threshold_minutes: + { type: integer, minimum: 60, maximum: 2880, default: 840 } responses: '200': description: Итоги сверки, включая события без назначенного подразделения @@ -185,7 +219,14 @@ paths: application/json: schema: type: object - required: [groups, sessions_created_or_updated, confirmed_sessions_skipped, anomalous_sessions, unresolved_events] + required: + [ + groups, + sessions_created_or_updated, + confirmed_sessions_skipped, + anomalous_sessions, + unresolved_events, + ] properties: groups: { type: integer, minimum: 0 } sessions_created_or_updated: { type: integer, minimum: 0 } @@ -359,7 +400,12 @@ paths: tags: [Finance] security: [{ bearerAuth: [] }] parameters: - - { in: path, name: orgUnitId, required: true, schema: { $ref: '#/components/schemas/Ulid' } } + - { + in: path, + name: orgUnitId, + required: true, + schema: { $ref: '#/components/schemas/Ulid' }, + } - { in: path, name: businessDate, required: true, schema: { type: string, format: date } } - { in: path, name: metricKey, required: true, schema: { type: string } } requestBody: @@ -370,7 +416,8 @@ paths: type: object required: [value_minor] properties: - value_minor: { type: integer, minimum: -9000000000000000, maximum: 9000000000000000 } + value_minor: + { type: integer, minimum: -9000000000000000, maximum: 9000000000000000 } currency_code: { type: string, pattern: '^[A-Z]{3}$' } responses: '200': { description: Сумма сохранена } @@ -394,7 +441,12 @@ paths: tags: [Schedule] security: [{ bearerAuth: [] }] parameters: - - { in: path, name: employeeId, required: true, schema: { $ref: '#/components/schemas/Ulid' } } + - { + in: path, + name: employeeId, + required: true, + schema: { $ref: '#/components/schemas/Ulid' }, + } - { in: path, name: businessDate, required: true, schema: { type: string, format: date } } requestBody: required: true @@ -448,7 +500,8 @@ paths: application/json: schema: type: object - required: [run_id, status, period_start, period_end, total_accrued_minor, totals, warnings] + required: + [run_id, status, period_start, period_end, total_accrued_minor, totals, warnings] properties: run_id: { $ref: '#/components/schemas/Ulid' } status: { const: calculated } @@ -478,7 +531,8 @@ paths: application/json: schema: type: object - required: [run_id, status, approved_by, approved_at, total_accrued_minor, entries_posted] + required: + [run_id, status, approved_by, approved_at, total_accrued_minor, entries_posted] properties: run_id: { $ref: '#/components/schemas/Ulid' } status: { const: approved } @@ -613,7 +667,19 @@ components: PayAssignment: type: object additionalProperties: false - required: [id, employee_id, pay_rule_id, pay_rule_code, pay_rule_name, rate_minor, percent_bp, guarantee_minor, pool_weight_bp, effective_from] + required: + [ + id, + employee_id, + pay_rule_id, + pay_rule_code, + pay_rule_name, + rate_minor, + percent_bp, + guarantee_minor, + pool_weight_bp, + effective_from, + ] properties: id: { $ref: '#/components/schemas/Ulid' } employee_id: { $ref: '#/components/schemas/Ulid' } diff --git a/apps/KronaStaffService/KronaStaffService.csproj b/apps/KronaStaffService/KronaStaffService.csproj index e6fe5e7..523b4ed 100644 --- a/apps/KronaStaffService/KronaStaffService.csproj +++ b/apps/KronaStaffService/KronaStaffService.csproj @@ -8,9 +8,9 @@ x64 win-x64 KronaStaffService - 0.3.0 - 0.3.0.0 - 0.3.0.0 + 0.3.1 + 0.3.1.0 + 0.3.1.0 diff --git a/apps/KronaStaffTerminal/KronaStaffTerminal.csproj b/apps/KronaStaffTerminal/KronaStaffTerminal.csproj index 72a56a9..162dc09 100644 --- a/apps/KronaStaffTerminal/KronaStaffTerminal.csproj +++ b/apps/KronaStaffTerminal/KronaStaffTerminal.csproj @@ -17,10 +17,10 @@ enable enable x64 - 0.3.0 - 0.3.0.0 - 0.3.0.0 - 0.3.0 + 0.3.1 + 0.3.1.0 + 0.3.1.0 + 0.3.1 diff --git a/docs/TERMINAL-API-REQUIREMENTS.md b/docs/TERMINAL-API-REQUIREMENTS.md index 8feb5f7..6538645 100644 --- a/docs/TERMINAL-API-REQUIREMENTS.md +++ b/docs/TERMINAL-API-REQUIREMENTS.md @@ -31,7 +31,7 @@ POST /api/v1/staff/attendance/events | `Authorization` | String | Yes | Terminal Bearer API Key | `Bearer trm_sec_991823ab...` | | `Idempotency-Key` | String | Yes | Unique idempotency key per event batch or event | `6ba7b810-9dad-11d1-80b4-00c04fd430c8` | | `X-Request-Id` | String | Yes | Unique trace ID for telemetry and crash debugging | `req_01HV8G7P89J21...` | -| `User-Agent` | String | Yes | Terminal client identification | `KronaStaffTerminal/0.3.0 (Windows NT 10.0; Win64; x64)` | +| `User-Agent` | String | Yes | Terminal client identification | `KronaStaffTerminal/0.3.1 (Windows NT 10.0; Win64; x64)` | --- diff --git a/module.json b/module.json index 56109d3..8555f83 100644 --- a/module.json +++ b/module.json @@ -2,7 +2,7 @@ "$schema": "./schemas/module.schema.json", "id": "ru.krona.staff", "name": "Krona Staff", - "version": "0.3.0", + "version": "0.3.1", "min_platform_version": "3.2.0", "dependencies": ["ru.krona.core"], "optional_dependencies": [], diff --git a/package-lock.json b/package-lock.json index d336af8..a5ea0ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@krona/staff", - "version": "0.3.0", + "version": "0.3.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@krona/staff", - "version": "0.3.0", + "version": "0.3.1", "dependencies": { "@fastify/helmet": "^13.0.2", "@fastify/sensible": "^6.0.3", diff --git a/package.json b/package.json index b7de79c..6977e97 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@krona/staff", - "version": "0.3.0", + "version": "0.3.1", "private": true, "type": "module", "engines": { diff --git a/src/portal-ui.ts b/src/portal-ui.ts index af96721..3d549d2 100644 --- a/src/portal-ui.ts +++ b/src/portal-ui.ts @@ -1,5 +1,5 @@ export const portalHtml = ` - + @@ -7,7 +7,7 @@ export const portalHtml = ` Krona Staff - + @@ -28,7 +28,7 @@ export const portalHtml = ` КKrona Staff - Подключение…УведомленияВыйтиОбновить + Подключение…ТемаЗелёнаяПергаментТёмнаяУведомленияВыйтиОбновить Обзор @@ -51,7 +51,7 @@ export const portalHtml = ` Последние событияОтметки терминала● в реальном времени - + Сверка терминалаРабочие сменыСверить 7 днейДатаСотрудникПодразделениеИнтервалЧасыСостояниеПричина правки Учёт времениТабель за 40 днейИзменения сохраняет руководительСотрудникДатаЧасыСтатусЧерновикНа проверкеУтверждёнВозвращёнПримечаниеДобавить строкуДатаСотрудникЧасыСтатусПримечание @@ -77,7 +77,9 @@ export const portalHtml = ` ИсторияНачисления и выплатыДатаСотрудникОперацияСуммаПримечание - Карточка командыНовый сотрудник×Табельный номерФамилия, имя и отчествоДолжностьПолНе указанЖенскийМужскойСтатусРаботаетЗаблокированУволенЗарплатный профильТорговая точкаСхема расчётаСтавка в час, ₽Процент от выручки, %Гарантия за смену, ₽Доля в фонде, %Действует с датыОтменаСохранить + + Карточка командыНовый сотрудник×Табельный номерФамилия, имя и отчествоПрофессияНе указанаРоль доступа: сотрудник. Роли и права платформы управляются в Krona Core отдельно от кадровой профессии.ПолНе указанЖенскийМужскойСтатусРаботаетЗаблокированУволенЗарплатный профильТорговая точкаСхема расчётаСтавка в час, ₽Процент от выручки, %Гарантия за смену, ₽Доля в фонде, %Действует с датыНовая версия действует с выбранной даты; предыдущая автоматически закрывается днём ранее.ОтменаСохранить + Кадровый справочникПрофессии×Новая профессияДобавить профессию Личный кабинетКлюч сотрудника×Скопируйте ключ сейчас. В программе хранится только его защищённый отпечаток, повторно показать ключ нельзя.Ключ доступаСкопироватьЗакрыть @@ -122,16 +124,26 @@ export const portalJs = `(() => { if('serviceWorker' in navigator) navigator.serviceWorker.register('/staff/sw.js'); load(false); setInterval(()=>{if(!el('app-shell').hidden)load(true);},15000); })();`; -export const portalCssEnhanced = portalCss + ` +export const portalCssEnhanced = + portalCss + + ` +[data-omni-theme="parchment-light"]{--omni-bg-app:#EFE3CC;--omni-bg-workspace:#F3EAD7;--omni-surface:#F8F2E6;--omni-surface-raised:#FCF8EF;--omni-surface-muted:#E9DDC5;--omni-surface-hover:#EDE0C7;--omni-text-primary:#302A23;--omni-text-secondary:#756A5B;--omni-text-inverse:#FFF;--omni-border:#D9C9AC;--omni-border-strong:#CBB99B;--omni-border-focus:#9A743D;--omni-primary:#9A743D;--omni-primary-hover:#7D5B2D;--omni-primary-soft:#EADBC1;--omni-gold:#B78335;--omni-gold-soft:#EFE0C2;--omni-danger:#A44E3F;--omni-danger-soft:#F1DDD5;--omni-info:#5F7480;--omni-shadow-medium:0 6px 18px rgb(72 55 34/.10);--omni-shadow-strong:0 14px 36px rgb(52 39 24/.16)} +[data-omni-theme="noble-green"]{--omni-bg-app:#EDE5D3;--omni-bg-workspace:#F2EAD9;--omni-surface:#F8F2E6;--omni-surface-raised:#FCF8EF;--omni-surface-muted:#E6DBC5;--omni-surface-hover:#E3E9DE;--omni-text-primary:#2E302A;--omni-text-secondary:#6B6C60;--omni-text-inverse:#FFF;--omni-border:#D2CCB9;--omni-border-strong:#9DAA98;--omni-border-focus:#315F46;--omni-primary:#315F46;--omni-primary-hover:#294F3B;--omni-primary-soft:#DDE7DB;--omni-gold:#B78335;--omni-gold-soft:#EFE0C2;--omni-danger:#A44E3F;--omni-danger-soft:#F1DDD5;--omni-info:#527286;--omni-shadow-medium:0 6px 18px rgb(72 55 34/.10);--omni-shadow-strong:0 14px 36px rgb(52 39 24/.16)} +[data-omni-theme="graphite-forest-dark"]{--omni-bg-app:#171A18;--omni-bg-workspace:#1D211E;--omni-surface:#252A26;--omni-surface-raised:#2B312C;--omni-surface-muted:#212621;--omni-surface-hover:#2B342D;--omni-text-primary:#EEE7DA;--omni-text-secondary:#B7B3A8;--omni-text-inverse:#171A18;--omni-border:#39423A;--omni-border-strong:#465249;--omni-border-focus:#6F9A79;--omni-primary:#527D60;--omni-primary-hover:#648E70;--omni-primary-soft:#29382E;--omni-gold:#C99A4D;--omni-gold-soft:#403522;--omni-danger:#C06B5F;--omni-danger-soft:#432B28;--omni-info:#7693A0;--omni-shadow-medium:0 8px 22px rgb(0 0 0/.24);--omni-shadow-strong:0 16px 40px rgb(0 0 0/.34)} +:root{--omni-radius-sm:6px;--omni-radius-md:8px;--omni-radius-lg:12px;--omni-radius-xl:16px;--omni-font-sans:Inter,"Segoe UI",system-ui,sans-serif;--omni-font-serif:Georgia,serif;--omni-warning:#7A5B16;--omni-warning-soft:#F7EAC9;--bg:var(--omni-bg-app);--workspace:var(--omni-bg-workspace);--surface:var(--omni-surface);--raised:var(--omni-surface-raised);--text:var(--omni-text-primary);--muted:var(--omni-text-secondary);--border:var(--omni-border);--primary:var(--omni-primary);--gold:var(--omni-gold);--danger:var(--omni-danger);--info:var(--omni-info);--shadow:var(--omni-shadow-medium)} +body,.auth-screen{background:var(--omni-bg-workspace);color:var(--omni-text-primary)}.topbar,.section-nav{background:color-mix(in srgb,var(--omni-surface) 94%,transparent)}.hero{background:linear-gradient(120deg,var(--omni-primary-active,var(--omni-primary)),var(--omni-primary))}.stats article,.panel,.employee-dialog{background:var(--omni-surface);border-color:var(--omni-border);box-shadow:var(--omni-shadow-medium)}button{background:var(--omni-primary);color:var(--omni-text-inverse)}button:hover{background:var(--omni-primary-hover);filter:none}.quiet{background:transparent;color:var(--omni-primary);border-color:var(--omni-border)}input,select,.timesheet-create input,.timesheet-create select,.employee-dialog input,.employee-dialog select,.period-control input,.stack-form input,.stack-form select,.inline-form input,.inline-form select{background:var(--omni-surface-raised);color:var(--omni-text-primary);border-color:var(--omni-border)}button:focus-visible,input:focus-visible,select:focus-visible{outline-color:var(--omni-border-focus)}.theme-control{display:flex;align-items:center;gap:6px;color:var(--omni-text-secondary);font-size:12px}.theme-control select{min-height:36px;border:1px solid var(--omni-border);border-radius:var(--omni-radius-md);padding:0 8px}.role-note{margin:0;padding:10px 12px;border-radius:var(--omni-radius-md);background:var(--omni-primary-soft);color:var(--omni-text-secondary);font-size:12px;line-height:1.45}.payroll-warnings{background:var(--omni-warning-soft)!important;color:var(--omni-warning)!important}.message,.login-error{background:var(--omni-danger-soft);color:var(--omni-danger);border-color:var(--omni-danger)} .section-nav{position:sticky;top:72px;z-index:4;display:flex;align-items:center;gap:8px;padding:10px max(20px,calc((100vw - 1240px)/2));border-bottom:1px solid var(--border);background:rgba(243,234,215,.96);backdrop-filter:blur(12px);overflow-x:auto}.nav-item{flex:0 0 auto;background:transparent;color:var(--muted);border:1px solid transparent}.nav-item.selected{background:var(--surface);color:var(--primary);border-color:var(--border)}.period-control{margin-left:auto;display:flex;align-items:center;gap:8px;color:var(--muted);font-size:13px;font-weight:700;white-space:nowrap}.period-control input,.stack-form input,.stack-form select,.inline-form input,.inline-form select{min-height:42px;border:1px solid var(--border);border-radius:8px;background:#fffdf8;color:var(--text);padding:7px 9px}.view-head{display:flex;justify-content:space-between;align-items:end;gap:24px;margin-bottom:22px}.view-head h1{margin:4px 0 8px;font:500 clamp(30px,4vw,46px)/1.05 Georgia,serif}.view-head p{margin:0;color:var(--muted)}.finance-layout{display:grid;grid-template-columns:minmax(0,1.7fr) minmax(260px,.7fr);gap:18px;margin-bottom:18px}.stack-form{display:grid;gap:13px}.stack-form label,.inline-form label{display:grid;gap:6px;color:var(--muted);font-size:12px;font-weight:700}.inline-form{display:grid;grid-template-columns:repeat(6,minmax(120px,1fr)) auto;align-items:end;gap:10px}.finance-chart{min-height:280px}.finance-chart svg{display:block;width:100%;height:280px}.chart-legend{display:flex;gap:16px;margin-top:10px;color:var(--muted);font-size:12px}.legend-dot{display:inline-block;width:9px;height:9px;margin-right:5px;border-radius:50%}.income-dot{background:var(--primary)}.expense-dot{background:var(--gold)}.calendar-panel{overflow:auto}.calendar-weekdays,.calendar-grid{display:grid;grid-template-columns:repeat(7,minmax(145px,1fr));min-width:1015px}.calendar-weekdays span{padding:8px 10px;color:var(--muted);font-size:12px;font-weight:750;text-align:center}.calendar-day{min-height:142px;padding:10px;border-top:1px solid var(--border);border-right:1px solid var(--border);background:var(--raised)}.calendar-day.outside{opacity:.45}.calendar-day.today{outline:2px solid var(--gold);outline-offset:-2px}.day-number{display:block;margin-bottom:8px;font-weight:750}.shift-card{margin:5px 0;padding:7px;border-left:3px solid var(--primary);border-radius:6px;background:#e8eadf;font-size:11px;line-height:1.35}.shift-card.actual{border-left-color:var(--gold);background:#f3e5cd}.shift-card strong,.shift-card span{display:block}.positive{color:var(--primary)}.negative{color:var(--danger)}.person-access{min-height:36px;padding:0 10px;margin-left:5px}.app-view[hidden]{display:none!important}@media(max-width:900px){.section-nav{top:68px;padding-inline:14px}.period-control{margin-left:8px}.finance-layout{grid-template-columns:1fr}.inline-form{grid-template-columns:repeat(2,minmax(0,1fr))}.inline-form button{grid-column:1/-1}.view-head{align-items:flex-start}.calendar-panel{padding:12px}}@media(max-width:520px){.view-head{display:block}.view-head>button{margin-top:14px}.stats{grid-template-columns:1fr}.stats article:last-child{grid-column:auto}.inline-form{grid-template-columns:1fr}.period-control{order:-1;margin-left:0}.section-nav{top:92px}.finance-chart{min-height:220px}.finance-chart svg{height:220px}} .form-row-2{display:grid;grid-template-columns:1fr 1fr;gap:10px} .pay-profile-section{display:grid;gap:10px;padding:14px;background:var(--raised);border:1px solid var(--border);border-radius:10px;margin-top:6px} .payroll-warnings{background:#fff8e6!important;border:1px solid #e2cb91!important;color:#6b5314!important;margin-bottom:18px} .payroll-warnings ul{margin:6px 0 0 18px;padding:0} .payroll-warnings li{margin-bottom:4px} +.section-nav{background:color-mix(in srgb,var(--omni-surface) 94%,transparent)}.period-control input,.stack-form input,.stack-form select,.inline-form input,.inline-form select{background:var(--omni-surface-raised)}.shift-card{background:var(--omni-primary-soft)}.shift-card.actual{background:var(--omni-gold-soft)}.payroll-warnings{background:var(--omni-warning-soft)!important;border-color:color-mix(in srgb,var(--omni-warning) 35%,transparent)!important;color:var(--omni-warning)!important}[data-omni-theme="graphite-forest-dark"]{--omni-warning:#E0B96C;--omni-warning-soft:#403522} `; -export const portalJsEnhanced = portalJs.replace('Неверный ключ администратора.', 'Неверный ключ доступа.') + ` +export const portalJsEnhanced = + portalJs.replace('Неверный ключ администратора.', 'Неверный ключ доступа.') + + ` (() => { const api='/api/v1/staff',byId=id=>document.getElementById(id),esc=value=>String(value??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])),rub=value=>(Number(value||0)/100).toLocaleString('ru-RU',{style:'currency',currency:'RUB',maximumFractionDigits:2}),hours=value=>(Number(value||0)/60).toLocaleString('ru-RU',{maximumFractionDigits:1}),jsonHeaders={'content-type':'application/json'}; let role='manager',units=[],initialized=false,active='overview-view',payRulesCache=[],currentRunId=null; @@ -153,6 +165,7 @@ export const portalJsEnhanced = portalJs.replace('Неверный ключ ад const state=await get('/portal'); role=state.viewer&&state.viewer.role||'manager'; document.querySelectorAll('.manager-only').forEach(node=>node.hidden=role!=='manager'); + byId('manage-professions').hidden=role!=='manager'; byId('viewer').textContent=role==='employee'?'Личный кабинет сотрудника':'Кабинет руководителя'; units=(await get('/org-units')).org_units||[]; try{payRulesCache=(await get('/pay-rules')).pay_rules||[]}catch{} @@ -273,6 +286,29 @@ export const portalJsEnhanced = portalJs.replace('Неверный ключ ад }); } + const themeSelect=byId('theme-select'); + const allowedThemes=['noble-green','parchment-light','graphite-forest-dark']; + const savedTheme=localStorage.getItem('krona-staff-theme'); + if(savedTheme&&allowedThemes.includes(savedTheme))document.documentElement.dataset.omniTheme=savedTheme; + themeSelect.value=document.documentElement.dataset.omniTheme||'noble-green'; + themeSelect.addEventListener('change',()=>{document.documentElement.dataset.omniTheme=themeSelect.value;localStorage.setItem('krona-staff-theme',themeSelect.value)}); + + let professionsCache=[]; + async function loadProfessions(){ + const result=await get('/professions'); + professionsCache=result.professions||[]; + const select=byId('employee-profession'); + const current=select.value; + select.innerHTML='Не указана'+professionsCache.filter(x=>x.status==='active').map(x=>option(x.id,x.name)).join(''); + if([...select.options].some(x=>x.value===current))select.value=current; + byId('profession-list').innerHTML=professionsCache.length?professionsCache.map(x=>''+esc(x.name).slice(0,1).toUpperCase()+''+esc(x.name)+''+(x.status==='active'?'Активна':'В архиве')+'').join(''):'Профессии ещё не добавлены'; + } + byId('employee-profession').addEventListener('change',()=>{const selected=byId('employee-profession').selectedOptions[0];byId('employee-position').value=selected&&selected.value?selected.textContent:''}); + document.addEventListener('click',event=>{const target=event.target.closest?.('.edit-employee,#add-employee');if(!target)return;setTimeout(async()=>{await loadProfessions();const position=byId('employee-position').value;const match=professionsCache.find(x=>x.name===position);byId('employee-profession').value=match?.id||''},0)},true); + byId('manage-professions').addEventListener('click',async()=>{byId('profession-error').hidden=true;await loadProfessions();byId('profession-dialog').showModal()}); + byId('profession-close').addEventListener('click',()=>byId('profession-dialog').close()); + byId('profession-form').addEventListener('submit',async event=>{event.preventDefault();const name=byId('profession-name').value.trim();if(!name)return;try{const created=await send('/professions','POST',{name});byId('profession-name').value='';await loadProfessions();byId('employee-profession').value=created.id;byId('employee-position').value=created.name}catch(error){byId('profession-error').textContent=error.message||'Не удалось сохранить профессию.';byId('profession-error').hidden=false}}); + if(byId('payroll-approve-btn')){ byId('payroll-approve-btn').addEventListener('click',async()=>{ if(!currentRunId)return; @@ -292,6 +328,17 @@ export const portalJsEnhanced = portalJs.replace('Неверный ключ ад })(); `; -export const portalManifest = JSON.stringify({ name: 'Krona Staff', short_name: 'Staff', start_url: '/staff', display: 'standalone', background_color: '#F3EAD7', theme_color: '#657255', lang: 'ru' }); +export const portalManifest = JSON.stringify({ + name: 'Krona Staff', + short_name: 'Staff', + start_url: '/staff', + display: 'standalone', + background_color: '#F3EAD7', + theme_color: '#657255', + lang: 'ru', +}); export const portalServiceWorker = `const CACHE='krona-staff-v3';const ASSETS=['/staff','/staff/styles.css','/staff/app.js','/staff/manifest.webmanifest'];self.addEventListener('install',e=>e.waitUntil(caches.open(CACHE).then(c=>c.addAll(ASSETS))));self.addEventListener('activate',e=>e.waitUntil(caches.keys().then(keys=>Promise.all(keys.filter(k=>k!==CACHE).map(k=>caches.delete(k))))));self.addEventListener('fetch',e=>{if(e.request.method==='GET'&&new URL(e.request.url).pathname.startsWith('/staff'))e.respondWith(fetch(e.request).then(r=>{const copy=r.clone();caches.open(CACHE).then(c=>c.put(e.request,copy));return r;}).catch(()=>caches.match(e.request)));});`; -export const portalServiceWorkerEnhanced = portalServiceWorker.replace('krona-staff-v3', 'krona-staff-v4'); +export const portalServiceWorkerEnhanced = portalServiceWorker.replace( + 'krona-staff-v3', + 'krona-staff-v4', +); diff --git a/src/version.ts b/src/version.ts index 6359178..678c7b8 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1,2 +1,2 @@ export const SERVICE_NAME = 'krona-staff'; -export const SERVICE_VERSION = '0.3.0'; +export const SERVICE_VERSION = '0.3.1';
Последние события
Сверка терминала
Учёт времени
История
Карточка команды
Зарплатный профиль
Роль доступа: сотрудник. Роли и права платформы управляются в Krona Core отдельно от кадровой профессии.
Кадровый справочник
Личный кабинет
Скопируйте ключ сейчас. В программе хранится только его защищённый отпечаток, повторно показать ключ нельзя.