diff --git a/app/Http/Controllers/Business/SystemizationTodos.php b/app/Http/Controllers/Business/SystemizationTodos.php index 31356fc8..4d758834 100644 --- a/app/Http/Controllers/Business/SystemizationTodos.php +++ b/app/Http/Controllers/Business/SystemizationTodos.php @@ -29,6 +29,20 @@ class SystemizationTodos extends Controller 'none' => '无提醒', ]; private const OWNER_OPTIONS = ['人参', '晨曦', '常仪', '待定']; + private const COLUMN_WIDTHS_SETTING = 'business.systemization_todos.column_widths'; + private const COLUMN_WIDTH_KEYS = [ + 'type', + 'section', + 'sequence', + 'title', + 'owner', + 'assignee', + 'start_date', + 'due_date', + 'reminder', + 'status', + 'progress_notes', + ]; private const OWNER_ALIASES = [ '人参' => '人参', '苏木' => '人参', @@ -205,6 +219,7 @@ class SystemizationTodos extends Controller $filters, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES, )), + 'todoColumnWidths' => $this->columnWidths(), 'todoSummary' => [ 'total' => $totalCount, 'incomplete' => $incompleteCount, @@ -224,10 +239,57 @@ class SystemizationTodos extends Controller 'import' => route('business.systemization-todos.import'), 'history' => route('business.systemization-todos.history'), 'historyExport' => route('business.systemization-todos.history.export'), + 'columnWidths' => route('business.systemization-todos.column-widths'), ], ]; } + public function saveColumnWidths(Request $request): JsonResponse + { + $ruleKeys = implode(',', self::COLUMN_WIDTH_KEYS); + $data = $request->validate([ + 'widths' => ['required', 'array:' . $ruleKeys], + 'widths.*' => ['required', 'integer', 'min:64', 'max:720'], + ]); + $widths = []; + foreach (self::COLUMN_WIDTH_KEYS as $key) { + $widths[$key] = (int) $data['widths'][$key]; + } + + setting([ + self::COLUMN_WIDTHS_SETTING => json_encode( + $widths, + JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES, + ), + ])->save(); + + return response()->json(['ok' => true, 'widths' => $widths]); + } + + private function columnWidths(): ?array + { + $encoded = setting(self::COLUMN_WIDTHS_SETTING); + $widths = is_string($encoded) ? json_decode($encoded, true) : $encoded; + if (! is_array($widths)) { + return null; + } + + $normalized = []; + foreach (self::COLUMN_WIDTH_KEYS as $key) { + $width = $widths[$key] ?? null; + if (! is_int($width) && ! ctype_digit((string) $width)) { + return null; + } + $width = (int) $width; + if ($width < 64 || $width > 720) { + return null; + } + $normalized[$key] = $width; + } + + return $normalized; + } + private function hierarchySequenceMap(): array { $todos = SystemizationTodo::query() diff --git a/public/fonts/caiwu-ui/DroidSansFallback.ttf b/public/fonts/caiwu-ui/DroidSansFallback.ttf new file mode 100644 index 00000000..1099b177 Binary files /dev/null and b/public/fonts/caiwu-ui/DroidSansFallback.ttf differ diff --git a/resources/assets/sass/app.css b/resources/assets/sass/app.css index 340a8e49..1bbdae84 100644 --- a/resources/assets/sass/app.css +++ b/resources/assets/sass/app.css @@ -41,6 +41,14 @@ font-weight: 700; } +@font-face { + font-family: "CaiWu CJK"; + src: url("/public/fonts/caiwu-ui/DroidSansFallback.ttf") format("truetype"); + font-display: swap; + font-style: normal; + font-weight: 400; +} + @tailwind base; @tailwind components; @tailwind utilities; @@ -1063,7 +1071,7 @@ form { body { @apply text-black; - font-family: "JetBrains Mono", "Microsoft YaHei", "PingFang SC", monospace; + font-family: "JetBrains Mono", "CaiWu CJK", monospace; height: 100%; } diff --git a/resources/views/business/pages/systemization-todos.blade.php b/resources/views/business/pages/systemization-todos.blade.php index 7caf45be..aa319e5a 100644 --- a/resources/views/business/pages/systemization-todos.blade.php +++ b/resources/views/business/pages/systemization-todos.blade.php @@ -19,11 +19,27 @@ .sys-todo-summary__value { color:#171717; font-size:1rem; font-weight:700; font-variant-numeric:tabular-nums; } .sys-todo-summary__item.is-warning .sys-todo-summary__value { color:#935f07; } .sys-todo-summary__item.is-success .sys-todo-summary__value { color:#53793e; } - .sys-todo-filter { display:flex; flex-wrap:wrap; gap:.65rem .55rem; align-items:end; margin:0 0 .85rem; padding:.7rem; border:1px solid #e6dfd2; border-radius:.65rem; background:#fcfaf5; } - .sys-todo-filter label { display:grid; flex:1 1 7.4rem; gap:.25rem; min-width:0; color:#595959; font-size:.72rem; } - .sys-todo-filter label.sys-todo-filter__keyword { flex:2.2 1 16rem; } + .sys-todo-filter { display:grid; grid-template-columns:repeat(6,minmax(8.5rem,1fr)); gap:.65rem .55rem; align-items:end; margin:0 0 .85rem; padding:.7rem; border:1px solid #e6dfd2; border-radius:.65rem; background:#fcfaf5; } + .sys-todo-filter > label { display:grid; grid-column:span 1; gap:.25rem; min-width:0; color:#595959; font-size:.72rem; } + .sys-todo-filter > label.sys-todo-filter__keyword { grid-column:span 3; } .sys-todo-filter input, .sys-todo-filter select { width:100%; height:2.125rem; padding:0 .6rem; border:1px solid var(--sys-border); border-radius:.45rem; background:#fff; color:#171717; font:inherit; font-size:.8125rem; } - .sys-todo-filter__multi { display:grid; flex:1 1 8.2rem; gap:.25rem; min-width:0; color:#595959; font-size:.72rem; } + .sys-todo-filter > label input, + .sys-todo-filter > label select { -webkit-appearance:none; appearance:none; } + .sys-todo-page select:not([multiple]) { + padding-right:2rem; + background-color:#fff; + background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%23856632' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); + background-repeat:no-repeat; + background-position:right .7rem center; + background-size:.7rem .47rem; + } + .sys-todo-page select:not([multiple])::-ms-expand { display:none; } + .sys-todo-page select:focus-visible, + .sys-todo-filter input:focus-visible, + .sys-todo-field input:focus-visible, + .sys-todo-field textarea:focus-visible { border-color:var(--sys-gold); outline:none; box-shadow:0 0 0 3px rgba(133,102,50,.18); } + .sys-todo-page input[type="search"]::-webkit-search-cancel-button { -webkit-appearance:none; display:none; } + .sys-todo-filter__multi { display:grid; grid-column:span 1; gap:.25rem; min-width:0; color:#595959; font-size:.72rem; } .sys-todo-filter__multi details { position:relative; min-width:0; } .sys-todo-filter__multi > details > summary { position:relative; display:flex; align-items:center; min-height:2.125rem; padding:0 1.8rem 0 .6rem; border:1px solid var(--sys-border); border-radius:.45rem; background:#fff; color:#171717; cursor:pointer; list-style:none; } .sys-todo-filter__multi > details > summary::-webkit-details-marker { display:none; } @@ -37,7 +53,7 @@ .sys-todo-filter__multi-menu label:hover { background:var(--sys-gold-soft); } .sys-todo-filter__multi-menu input[type="checkbox"] { flex:0 0 auto; width:1rem; height:1rem; padding:0; accent-color:var(--sys-gold); } .sys-todo-filter__multi-empty { padding:.65rem; color:#777; font-size:.75rem; text-align:center; } - .sys-todo-filter__actions { display:flex; flex:0 0 auto; gap:.45rem; } + .sys-todo-filter__actions { display:flex; grid-column:span 2; justify-content:flex-end; gap:.45rem; } .sys-todo-table-wrap { overflow-x:auto; overflow-y:visible; border:1px solid var(--sys-border); border-radius:.65rem; background:#fff; scrollbar-width:none; } .sys-todo-table-wrap::-webkit-scrollbar { height:0; } .sys-todo-table { width:108rem; min-width:108rem; table-layout:fixed; border-collapse:separate; border-spacing:0; font-size:.75rem; } @@ -152,6 +168,31 @@ .sys-todo-owner-checks label { display:flex; align-items:center; gap:.35rem; min-height:1.6rem; color:#333; font-size:.76rem; cursor:pointer; } .sys-todo-owner-checks label:hover { color:var(--sys-gold); } .sys-todo-owner-checks input[type="checkbox"] { flex:0 0 auto; width:1rem; height:1rem; min-height:0; padding:0; accent-color:var(--sys-gold); } + .sys-todo-page input[type="checkbox"] { + -webkit-appearance:none; + appearance:none; + display:inline-grid; + flex:0 0 1rem; + place-items:center; + width:1rem; + height:1rem; + min-height:0; + padding:0; + border:1px solid #bfb3a0; + border-radius:.24rem; + background-color:#fff; + background-image:none; + cursor:pointer; + } + .sys-todo-page input[type="checkbox"]:checked { + border-color:var(--sys-gold); + background-color:var(--sys-gold); + background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.2 6.4 4.8 9 9.8 3.3' fill='none' stroke='%23FFFFFF' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); + background-repeat:no-repeat; + background-position:center; + background-size:.72rem; + } + .sys-todo-page input[type="checkbox"]:focus-visible { outline:2px solid var(--sys-gold); outline-offset:2px; } .sys-todo-upload-zone { display:flex; flex-wrap:wrap; align-items:center; gap:.45rem .65rem; min-height:4.5rem; padding:.7rem; border:1px dashed #cfc3ad; border-radius:.55rem; background:#fcfaf5; } .sys-todo-upload-zone input[type="file"] { position:absolute; width:1px; height:1px; padding:0; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0; } .sys-todo-upload-button { display:inline-flex; align-items:center; justify-content:center; min-height:2rem; padding:0 .75rem; border:1px solid var(--sys-gold); border-radius:.4rem; background:var(--sys-gold); color:#fff; font-size:.78rem; cursor:pointer; } @@ -239,9 +280,22 @@ .sys-todo-image-dialog__body button[hidden] { visibility:hidden; } .sys-todo-image-dialog__foot { display:flex; justify-content:flex-end; padding:.55rem .85rem; background:#1d1d1f; } .sys-todo-image-dialog__foot a { color:#f0e4bf; font-size:.75rem; } - @media (max-width:1300px) { .sys-todo-summary { grid-template-columns:repeat(2,minmax(0,1fr)); } } - @media (max-width:900px) { .sys-todo-filter label, .sys-todo-filter label.sys-todo-filter__keyword { flex-basis:9rem; } .sys-todo-filter__actions { width:100%; } .sys-todo-filter__actions .sys-todo-page__button { flex:1; } } - @media (max-width:720px) { .sys-todo-summary { grid-template-columns:repeat(2,minmax(0,1fr)); } .sys-todo-filter label, .sys-todo-filter label.sys-todo-filter__keyword { flex-basis:10rem; } .sys-todo-field--2,.sys-todo-field--3,.sys-todo-field--4,.sys-todo-field--6 { grid-column:span 12; } .sys-todo-combined-grid { grid-column:span 12; grid-template-columns:1fr; } } + @media (max-width:1100px) { + .sys-todo-summary { grid-template-columns:repeat(2,minmax(0,1fr)); } + .sys-todo-filter { grid-template-columns:repeat(3,minmax(8.5rem,1fr)); } + .sys-todo-filter > label.sys-todo-filter__keyword { grid-column:span 2; } + .sys-todo-filter__actions { grid-column:span 3; } + } + @media (max-width:720px) { + .sys-todo-filter { grid-template-columns:minmax(0,1fr); } + .sys-todo-filter > label, + .sys-todo-filter > label.sys-todo-filter__keyword, + .sys-todo-filter__multi, + .sys-todo-filter__actions { grid-column:1 / -1; } + .sys-todo-filter__actions .sys-todo-page__button { flex:1; } + .sys-todo-field--2,.sys-todo-field--3,.sys-todo-field--4,.sys-todo-field--6 { grid-column:span 12; } + .sys-todo-combined-grid { grid-column:span 12; grid-template-columns:1fr; } + }