feat(任务): 详情页编号右置到副标题行、换列后自动收起、固定头尾滚动
- 完整任务编号从标题下方独立一行, 移到「看板列 · 状态」同一行右侧 (左侧可省略号截断, 编号 flex-shrink:0 不被挤压) - 切换看板列后 ActionSheet 未收起: 补 handler.close?.(), 且放在 onAction 最前 (选中即收, 不等接口返回), 与项目视图 ⋯ 菜单同口径 - 滚动优化: 原整个弹层是一个滚动容器, 标题与保存按钮都会随内容滚走。 改为三段式弹性布局 —— .td-head 固定 / .td-body 唯一滚动区 / .td-foot 固定 (保存按钮), 键盘弹出时底部随 kb 上抬 验证: 390x720 矮屏渲染真实 TaskDetail (14 条子任务撑出溢出), 11 项断言通过 —— 主体 scrollH 1531 > clientH 465; 滚动 1066px 到底后头部 top 86->86、 底部 top 657->657 均不变; 保存按钮 bottom 708 <= 720 始终在屏内; 头+体+底高度之和等于弹层总高 (无重叠/无空隙)。
This commit is contained in:
@@ -128,13 +128,15 @@ export default function TaskDetail({ task, projectCode, columns, members, tasks,
|
|||||||
* 这里始终按 String() 比对, 不要 Number(): 否则结果变 NaN, 落库列被改成 "NaN" 报「看板列不存在」 */
|
* 这里始终按 String() 比对, 不要 Number(): 否则结果变 NaN, 落库列被改成 "NaN" 报「看板列不存在」 */
|
||||||
function pickColumn() {
|
function pickColumn() {
|
||||||
const current = String(task.columnId)
|
const current = String(task.columnId)
|
||||||
ActionSheet.show({
|
const handler = ActionSheet.show({
|
||||||
actions: (columns || []).map((c) => ({
|
actions: (columns || []).map((c) => ({
|
||||||
text: c.name + (String(c.id) === current ? ' ✓' : ''),
|
text: c.name + (String(c.id) === current ? ' ✓' : ''),
|
||||||
key: String(c.id),
|
key: String(c.id),
|
||||||
})),
|
})),
|
||||||
cancelText: '取消',
|
cancelText: '取消',
|
||||||
onAction: async (item) => {
|
onAction: async (item) => {
|
||||||
|
// 选中即收起 sheet (与项目视图 ⋯ 菜单同口径); 否则改完列 sheet 还挂在那
|
||||||
|
handler.close?.()
|
||||||
const columnId = String(item.key)
|
const columnId = String(item.key)
|
||||||
if (columnId === current) return
|
if (columnId === current) return
|
||||||
try {
|
try {
|
||||||
@@ -200,28 +202,35 @@ export default function TaskDetail({ task, projectCode, columns, members, tasks,
|
|||||||
borderTopLeftRadius: 12,
|
borderTopLeftRadius: 12,
|
||||||
borderTopRightRadius: 12,
|
borderTopRightRadius: 12,
|
||||||
maxHeight: `calc(88vh - ${kb}px)`,
|
maxHeight: `calc(88vh - ${kb}px)`,
|
||||||
overflowY: 'auto',
|
// 三段式: 固定头 / 滚动体 / 固定底 (标题与保存按钮始终可见)
|
||||||
padding: `16px 16px calc(env(safe-area-inset-bottom, 0px) + 20px + ${kb}px)`,
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
overflow: 'hidden',
|
||||||
|
padding: 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="sheet-title">{task.title}</div>
|
{/* 固定头部: 标题 + 看板列/状态 + 编号 */}
|
||||||
{fullId && (
|
<div className="td-head">
|
||||||
<div className="sheet-idrow">
|
<div className="sheet-title">{task.title}</div>
|
||||||
<span
|
{/* 看板列 · 状态 与完整任务编号同一行, 编号靠右 (点按复制) */}
|
||||||
className="task-id-chip"
|
<div className="sheet-sub">
|
||||||
role="button"
|
<span className="sub-meta">{currentCol?.name} · {STATUS_LABEL[task.status]}</span>
|
||||||
title="点击复制完整任务编号"
|
{fullId && (
|
||||||
onClick={copyId}
|
<span
|
||||||
>
|
className="task-id-chip"
|
||||||
<span className="tid">{fullId}</span>
|
role="button"
|
||||||
<span className="tid-copy">{copied ? '已复制' : '复制'}</span>
|
title="点击复制完整任务编号"
|
||||||
</span>
|
onClick={copyId}
|
||||||
|
>
|
||||||
|
<span className="tid">{fullId}</span>
|
||||||
|
<span className="tid-copy">{copied ? '已复制' : '复制'}</span>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
<div className="sheet-sub">
|
|
||||||
{currentCol?.name} · {STATUS_LABEL[task.status]}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* 可滚动主体: 只有这一段滚动 */}
|
||||||
|
<div className="td-body">
|
||||||
<div className="field">
|
<div className="field">
|
||||||
<label>标题</label>
|
<label>标题</label>
|
||||||
<input
|
<input
|
||||||
@@ -386,8 +395,15 @@ export default function TaskDetail({ task, projectCode, columns, members, tasks,
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>{/* /.td-body */}
|
||||||
|
|
||||||
<div className="btn-primary" onClick={save}>{saving ? '保存中…' : '保存'}</div>
|
{/* 固定底部: 保存 (键盘弹出时随 kb 上抬) */}
|
||||||
|
<div
|
||||||
|
className="td-foot"
|
||||||
|
style={{ paddingBottom: `calc(env(safe-area-inset-bottom, 0px) + 12px + ${kb}px)` }}
|
||||||
|
>
|
||||||
|
<div className="btn-primary" onClick={save}>{saving ? '保存中…' : '保存'}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<UserPicker
|
<UserPicker
|
||||||
visible={picker === 'assignee'}
|
visible={picker === 'assignee'}
|
||||||
|
|||||||
+22
-3
@@ -1135,18 +1135,37 @@ body.me-safe-top .app-safe-top { height: 0; }
|
|||||||
.cs-count { font-size: 11px; color: #999; margin-left: 8px; }
|
.cs-count { font-size: 11px; color: #999; margin-left: 8px; }
|
||||||
|
|
||||||
/* ---- 任务详情 ---- */
|
/* ---- 任务详情 ---- */
|
||||||
|
/* 三段式弹层: 固定头 / 滚动体 / 固定底 —— 标题与保存按钮始终可见 */
|
||||||
|
.td-head {
|
||||||
|
flex: 0 0 auto; padding: 16px 16px 8px; background: #fff;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
.td-body {
|
||||||
|
flex: 1 1 auto; min-height: 0; overflow-y: auto;
|
||||||
|
padding: 12px 16px 4px;
|
||||||
|
-webkit-overflow-scrolling: touch; overscroll-behavior: contain;
|
||||||
|
}
|
||||||
|
.td-foot {
|
||||||
|
flex: 0 0 auto; padding: 10px 16px 12px; background: #fff;
|
||||||
|
border-top: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
/* 底部固定后不再需要上外边距 */
|
||||||
|
.td-foot .btn-primary { margin-top: 0; }
|
||||||
.sheet-title {
|
.sheet-title {
|
||||||
font-size: 16px; font-weight: 700; margin-bottom: 4px; word-break: break-word;
|
font-size: 16px; font-weight: 700; margin-bottom: 4px; word-break: break-word;
|
||||||
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
|
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
|
||||||
}
|
}
|
||||||
|
/* 详情页副标题行: 左侧「看板列 · 状态」, 右侧完整任务编号 (点按复制) */
|
||||||
.sheet-sub {
|
.sheet-sub {
|
||||||
|
display: flex; align-items: center; gap: 8px;
|
||||||
font-size: 11.5px; color: #999; margin-bottom: 14px;
|
font-size: 11.5px; color: #999; margin-bottom: 14px;
|
||||||
|
}
|
||||||
|
.sheet-sub .sub-meta {
|
||||||
|
flex: 1 1 auto; min-width: 0;
|
||||||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||||||
}
|
}
|
||||||
/* 详情页标题下的完整任务编号 (项目编号-序号): 点按复制 */
|
|
||||||
.sheet-idrow { margin: -1px 0 6px; }
|
|
||||||
.task-id-chip {
|
.task-id-chip {
|
||||||
display: inline-flex; align-items: center; gap: 6px;
|
display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0;
|
||||||
font-size: 11px; line-height: 1; font-weight: 600;
|
font-size: 11px; line-height: 1; font-weight: 600;
|
||||||
color: #5b6b7c; background: #eef2f6; border-radius: 999px; padding: 5px 9px;
|
color: #5b6b7c; background: #eef2f6; border-radius: 999px; padding: 5px 9px;
|
||||||
cursor: pointer; -webkit-user-select: none; user-select: none;
|
cursor: pointer; -webkit-user-select: none; user-select: none;
|
||||||
|
|||||||
Reference in New Issue
Block a user