diff --git a/src/i18n/en/tasks.ts b/src/i18n/en/tasks.ts index 38f0796..7c07ef6 100644 --- a/src/i18n/en/tasks.ts +++ b/src/i18n/en/tasks.ts @@ -4,6 +4,7 @@ export default { title: '🔀 Task Queue', refresh: '🔄 Refresh', create: '+ New Task', + searchPlaceholder: 'Search title/description...', // Filter bar filter: { @@ -11,6 +12,14 @@ export default { status: 'Status: ', all: 'All', }, + // Sort + sort: { + label: 'Sort: ', + updated: 'Updated', + created: 'Created', + priority: 'Priority', + status: 'Status', + }, // Status filters (with icons) — D-260616-01 aligned to backend 7 states statusFilter: { all: 'All', diff --git a/src/i18n/zh-CN/tasks.ts b/src/i18n/zh-CN/tasks.ts index f05eb19..4e69b64 100644 --- a/src/i18n/zh-CN/tasks.ts +++ b/src/i18n/zh-CN/tasks.ts @@ -4,6 +4,7 @@ export default { title: '🔀 任务队列', refresh: '🔄 刷新', create: '+ 新建任务', + searchPlaceholder: '搜索任务标题/描述...', // 筛选栏 filter: { @@ -11,6 +12,14 @@ export default { status: '状态:', all: '全部', }, + // 排序 + sort: { + label: '排序:', + updated: '更新时间', + created: '创建时间', + priority: '优先级', + status: '状态', + }, // 状态筛选(含图标) — D-260616-01 对齐后端 7 态 statusFilter: { all: '全部', diff --git a/src/views/Tasks.vue b/src/views/Tasks.vue index a798703..deaab06 100644 --- a/src/views/Tasks.vue +++ b/src/views/Tasks.vue @@ -1,61 +1,77 @@ @@ -306,11 +372,27 @@ onMounted(async () => { justify-content: space-between; align-items: center; margin-bottom: var(--df-gap-page); + gap: 12px; } -.page-header h1 { font-size: 24px; font-weight: 500; color: var(--df-text); } -.header-actions { display: flex; gap: 10px; } +.page-header h1 { font-size: 24px; font-weight: 500; color: var(--df-text); white-space: nowrap; } +.header-actions { display: flex; gap: 10px; align-items: center; } -/* ===== 按钮 ===== */ +/* 搜索框 */ +.search-input { + width: 220px; + padding: 6px 12px; + border: 0.5px solid var(--df-border); + border-radius: var(--df-radius-sm); + background: var(--df-bg-card); + color: var(--df-text); + font-size: 13px; + outline: none; + transition: border-color 0.15s; +} +.search-input:focus { border-color: var(--df-accent); } +.search-input::placeholder { color: var(--df-text-dim); } + +/* 按钮 */ .btn { padding: 8px 16px; border: none; @@ -323,14 +405,16 @@ onMounted(async () => { .btn-primary:hover { background: var(--df-accent-hover); } .btn-ghost { background: transparent; color: var(--df-text-secondary); border: 0.5px solid var(--df-border); } .btn-ghost:hover { background: var(--df-bg-card); color: var(--df-text); } +.btn-sm { padding: 4px 12px; font-size: 12px; } -/* ===== 筛选栏 ===== */ +/* 筛选栏(紧凑) */ .filter-bar { display: flex; flex-wrap: wrap; - gap: 16px; + align-items: center; + gap: 12px; margin-bottom: var(--df-gap-page); - padding: var(--df-pad-panel); + padding: 10px 14px; background: var(--df-bg-card); border: 0.5px solid var(--df-border); border-radius: var(--df-radius-lg); @@ -338,7 +422,6 @@ onMounted(async () => { .filter-group { display: flex; align-items: center; - flex-wrap: wrap; /* 窄屏按钮可换行,避免 nowrap 溢出 */ gap: 6px; } .filter-label { @@ -346,37 +429,25 @@ onMounted(async () => { color: var(--df-text-dim); white-space: nowrap; } -.filter-btn { - display: inline-flex; - align-items: center; - gap: 4px; - padding: 4px 12px; +.filter-select { + padding: 4px 10px; border: 0.5px solid var(--df-border); border-radius: var(--df-radius-sm); - background: transparent; - color: var(--df-text-secondary); + background: var(--df-bg); + color: var(--df-text); font-size: 12px; cursor: pointer; - transition: all 0.15s; + outline: none; + transition: border-color 0.15s; } -.filter-btn-icon { line-height: 1; } /* 图标基线对齐,避免行高跳动 */ -.filter-btn-label { white-space: nowrap; } /* 文字不内断行,换行只发生在按钮间 */ -.filter-btn:hover { background: rgba(108, 99, 255, 0.06); color: var(--df-text); } -.filter-btn.active { - background: var(--df-accent); - color: #fff; - border-color: var(--df-accent); -} -/* 窄屏(手机宽):按钮内图标与文字改纵向排布,避免横向挤压致图标/文字在空格处错位断行 */ -@media (max-width: 480px) { - .filter-btn { - flex-direction: column; - gap: 2px; - padding: 4px 8px; - } +.filter-select:hover { border-color: var(--df-accent); } +.filter-count { + margin-left: auto; + font-size: 12px; + color: var(--df-text-dim); } -/* ===== 任务分组 ===== */ +/* 任务分组 */ .task-groups { display: flex; flex-direction: column; @@ -387,22 +458,33 @@ onMounted(async () => { background: var(--df-bg-card); border: 0.5px solid var(--df-border); border-radius: var(--df-radius-lg); - padding: var(--df-pad-panel); + overflow: hidden; } .group-header { display: flex; align-items: center; gap: 8px; - margin-bottom: var(--df-gap-head); - padding-bottom: 10px; + padding: 10px 14px; + cursor: pointer; + user-select: none; border-bottom: 0.5px solid var(--df-border); + transition: background 0.1s; +} +.group-header:hover { background: rgba(108, 99, 255, 0.04); } +.task-group.collapsed .group-header { border-bottom: none; } +.group-chevron { font-size: 10px; color: var(--df-text-dim); width: 12px; text-align: center; } +.group-icon { font-size: 16px; } +.group-name { font-size: 14px; font-weight: 500; color: var(--df-text); flex: 1; } +.group-count { + font-size: 11px; + color: var(--df-text-dim); + background: rgba(255,255,255,0.06); + padding: 1px 8px; + border-radius: 8px; } -.group-icon { font-size: 18px; } -.group-name { font-size: 15px; font-weight: 500; color: var(--df-text); } -.group-count { font-size: 12px; color: var(--df-text-dim); margin-left: 8px; } -/* ===== 任务条目 ===== */ +/* 任务条目(紧凑) */ .task-list { display: flex; flex-direction: column; @@ -411,11 +493,12 @@ onMounted(async () => { display: flex; justify-content: space-between; align-items: center; - padding: 12px 14px; - border-radius: var(--df-radius); + padding: 8px 14px; + border-bottom: 0.5px solid rgba(255,255,255,0.03); transition: background 0.1s; cursor: pointer; } +.task-item:last-child { border-bottom: none; } .task-item:hover { background: rgba(108, 99, 255, 0.04); } .task-main { flex: 1; min-width: 0; } @@ -424,14 +507,22 @@ onMounted(async () => { display: flex; align-items: center; gap: 8px; - margin-bottom: 4px; } -.task-title { font-size: 14px; font-weight: 500; color: var(--df-text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.task-title { + font-size: 13px; + font-weight: 500; + color: var(--df-text); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} .priority-badge { - font-size: 10px; font-weight: 500; + font-size: 10px; + font-weight: 500; padding: 1px 6px; border-radius: var(--df-radius-xs); + flex-shrink: 0; } .priority-critical { background: rgba(255,107,107,0.2); color: var(--df-danger); } .priority-high { background: rgba(255,152,0,0.2); color: #ff9800; } @@ -441,55 +532,85 @@ onMounted(async () => { .task-meta { display: flex; align-items: center; - gap: 14px; + gap: 12px; + margin-top: 2px; } .branch-tag { display: inline-flex; align-items: center; gap: 3px; - font-size: 12px; - color: var(--df-text-secondary); - background: rgba(108, 99, 255, 0.06); - padding: 2px 8px; - border-radius: var(--df-radius-xs); - font-family: monospace; -} -.branch-icon { font-size: 12px; color: var(--df-accent); } -.task-date { font-size: 11px; color: var(--df-text-dim); } -.task-time { font-size: 11px; color: var(--df-text-dim); - opacity: 0.7; +} +.task-date { + font-size: 11px; + color: var(--df-text-dim); } -/* ===== 状态标签 ===== */ .status-tag { - font-size: 11px; font-weight: 500; - padding: 4px 10px; - border-radius: var(--df-radius-sm); + font-size: 11px; + padding: 2px 8px; + border-radius: var(--df-radius-xs); + flex-shrink: 0; white-space: nowrap; } -.status-todo { background: rgba(90,99,128,0.2); color: var(--df-text-dim); } -.status-progress { background: rgba(100,181,246,0.2); color: var(--df-info); } -.status-review { background: rgba(255,217,61,0.2); color: var(--df-warning); } -.status-done { background: rgba(100,255,218,0.15); color: var(--df-success); } -.status-abandoned { background: rgba(255,107,107,0.2); color: var(--df-danger); } -/* D-260616-01:7 态新增 — testing(橙警告,近 review 区分)/blocked(红 danger,与 cancelled 区分用实心边框) */ -.status-testing { background: rgba(255,152,0,0.2); color: #ff9800; } -.status-blocked { background: rgba(255,107,107,0.12); color: var(--df-danger); border: 0.5px solid var(--df-danger); } -/* ===== 空状态(Y-2: loading/error/empty 兜底,样式参考 Projects.vue) ===== */ +/* 空态 */ .empty-state { - text-align: center; padding: 60px 20px; - font-size: 14px; color: var(--df-text-dim); + display: flex; + flex-direction: column; + align-items: center; + gap: 10px; + padding: 48px 0; + color: var(--df-text-dim); + font-size: 13px; } +.empty-icon { font-size: 32px; opacity: 0.4; } -/* ===== 模态框 ===== */ -.modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: 100; } -.modal-box { background: var(--df-bg-card); border: 0.5px solid var(--df-border); border-radius: var(--df-radius-lg); padding: 24px; min-width: 360px; max-width: 90vw; } -.modal-box h3 { color: var(--df-text); margin-bottom: 16px; } -.modal-box input, .modal-box select { width: 100%; padding: 8px 12px; border: 0.5px solid var(--df-border); border-radius: var(--df-radius-sm); background: var(--df-bg); color: var(--df-text); font-size: 13px; margin-bottom: 12px; box-sizing: border-box; } -.modal-box .modal-actions { display: flex; gap: 8px; justify-content: flex-end; } -.modal-box .btn-cancel { padding: 6px 16px; border: 0.5px solid var(--df-border); border-radius: var(--df-radius-sm); background: transparent; color: var(--df-text-secondary); cursor: pointer; } -.modal-box .btn-confirm { padding: 6px 16px; border: none; border-radius: var(--df-radius-sm); background: var(--df-accent); color: #fff; cursor: pointer; } +/* 模态框 */ +.modal-overlay { + position: fixed; + inset: 0; + background: rgba(0,0,0,0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 100; +} +.modal-box { + background: var(--df-bg-card); + border: 0.5px solid var(--df-border); + border-radius: var(--df-radius-lg); + padding: 20px; + min-width: 400px; + max-width: 480px; +} +.modal-box h3 { font-size: 16px; color: var(--df-text); margin-bottom: 16px; } +.modal-field { + margin-bottom: 12px; +} +.modal-field label { + display: block; + font-size: 12px; + color: var(--df-text-secondary); + margin-bottom: 4px; +} +.modal-input { + width: 100%; + box-sizing: border-box; + padding: 8px 12px; + border: 0.5px solid var(--df-border); + border-radius: var(--df-radius-sm); + background: var(--df-bg); + color: var(--df-text); + font-size: 13px; + outline: none; +} +.modal-input:focus { border-color: var(--df-accent); } +.modal-actions { + display: flex; + justify-content: flex-end; + gap: 8px; + margin-top: 16px; +}