|
|
@@ -55,6 +55,8 @@ export class ViewWorkbench extends LitElement {
|
|
|
.bento > .row { display: grid; gap: var(--kf-space-card-gap); align-items: stretch; }
|
|
|
.bento > .row.ab { grid-template-columns: repeat(12, minmax(0, 1fr)); }
|
|
|
.bento > .row.ab > kf-glass-card { height: auto; }
|
|
|
+ /* A/B 用 fill-to 吃满行高:卡面 .face 是 flex 列,slotted 的第一层(.me / .live)伸到底(下方各行的实际高度由本页 CSS 排) */
|
|
|
+ .bento > .row.ab > kf-glass-card[fill-to] .me, .bento > .row.ab > kf-glass-card[fill-to] .live { flex: 1 1 auto; }
|
|
|
.bento > .row.ab > kf-glass-card[data-role="a"] { grid-column: span 8; }
|
|
|
.bento > .row.ab > kf-glass-card[data-role="b"] { grid-column: span 4; }
|
|
|
.bento > .row.cde { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
|
|
@@ -76,44 +78,57 @@ export class ViewWorkbench extends LitElement {
|
|
|
.empty .go { margin-left: auto; }
|
|
|
|
|
|
/* ---------- A 卡:我的推进 ---------- */
|
|
|
- .me { display: grid; gap: var(--kf-space-in); height: 100%; align-content: start; }
|
|
|
- .me-id { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
|
|
|
+ /* A 卡内容按行贴顶排;行距 12;下半的两个分区用 1fr 行把底边对齐(待评分区贴底,不再在卡片中段留 59px 空洞) */
|
|
|
+ /* A 卡是 flex 列:阶段行以「剩余高度」行出现,多出来的空间从它这里再分给三格(格内进度条沉底)。 */
|
|
|
+ .me { display: flex; flex-direction: column; gap: var(--kf-space-in); }
|
|
|
+ .me > .me-id { flex: none; }
|
|
|
+ .me > .stagebar { flex: none; }
|
|
|
+ .me > .empty { flex: none; }
|
|
|
+ .me > .me-split { flex: none; margin-top: auto; }
|
|
|
+ .me-id { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 2px 12px; }
|
|
|
+ .me-id .me-title { display: grid; align-content: center; min-width: 0; }
|
|
|
.avatar { width: 44px; height: 44px; border-radius: var(--r-md); display: grid; place-items: center; font-size: 20px; font-weight: 600; color: #fff;
|
|
|
background: var(--kf-ink); flex: none; }
|
|
|
.avatar.q { background: var(--kf-fill); color: var(--kf-ink-3); border: 1px dashed color-mix(in srgb, var(--kf-ink-3) 34%, transparent); }
|
|
|
.me-id h3 { margin: 0; font-size: 20px; line-height: var(--lh-title); font-weight: 600; color: var(--kf-ink); letter-spacing: var(--ls-cn-display); }
|
|
|
.me-id .sub { font-size: 14px; color: var(--kf-ink-3); }
|
|
|
.me-id .go { margin-left: auto; }
|
|
|
- .me-nums { margin-left: auto; display: flex; gap: 24px; }
|
|
|
- .me-nums div { text-align: right; }
|
|
|
- .me-nums b { display: block; font-size: 20px; font-weight: 600; line-height: 1; letter-spacing: var(--ls-cn-display); color: var(--gray-12);
|
|
|
+ .me-nums { display: flex; gap: 24px; justify-self: end; }
|
|
|
+ .me-nums div { display: flex; align-items: baseline; gap: 4px; }
|
|
|
+ .me-nums b { font-size: 20px; font-weight: 600; line-height: 1; letter-spacing: var(--ls-cn-display); color: var(--gray-12);
|
|
|
font-variant-numeric: tabular-nums; }
|
|
|
- .me-nums span { font-size: 12px; font-weight: 500; color: var(--kf-ink-3); }
|
|
|
+ .me-nums span { font-size: 12px; font-weight: 500; color: var(--kf-ink-3); white-space: nowrap; }
|
|
|
|
|
|
/* 阶段条:五格一格一句「S1 · 份数」,徽标 + 大数字 + 一根细进度条 */
|
|
|
- .stagebar { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--kf-space-in); }
|
|
|
+ .stagebar { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--kf-space-in); margin-top: calc(-1 * var(--kf-space-in) + 4px); }
|
|
|
.stg { padding: 12px; border-radius: var(--r-md); background: var(--kf-fill); border: 1px solid transparent;
|
|
|
- display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 4px 8px; min-width: 0; }
|
|
|
+ /* 阶段格铺满分到的高度带:上面 3 行贴顶,细进度条沉到底边(不留「格子里空一截」) */
|
|
|
+ display: grid; grid-template-columns: auto 1fr; align-content: start; align-items: center; gap: 2px 8px; min-width: 0; }
|
|
|
.stg .b { font-size: 12px; font-weight: 600; line-height: 1; color: #fff; padding: 4px 6px; border-radius: var(--r-sm); letter-spacing: 0.02em; justify-self: start; }
|
|
|
.stg .b.blue { background: var(--kf-s1); } .stg .b.violet { background: var(--kf-s2); } .stg .b.teal { background: var(--kf-s3); }
|
|
|
.stg .b.amber { background: var(--kf-s4); } .stg .b.rose { background: var(--kf-s5); }
|
|
|
.stg .n { justify-self: end; font-size: 20px; font-weight: 600; line-height: 1; letter-spacing: var(--ls-cn-display); color: var(--gray-12); font-variant-numeric: tabular-nums; }
|
|
|
- .stg .sf { grid-column: 1 / -1; font-size: 12px; line-height: 1.3; color: var(--kf-ink-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
|
- .stg .f { grid-column: 1 / -1; height: 4px; border-radius: 2px; background: rgba(16, 24, 40, 0.07); overflow: hidden; margin-top: 4px; }
|
|
|
+ .stg .sf { grid-column: 1 / -1; min-height: 16px; font-size: 12px; line-height: 1.3; color: var(--kf-ink-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
|
+ .stg .f { grid-column: 1 / -1; height: 4px; border-radius: 2px; background: rgba(16, 24, 40, 0.07); overflow: hidden; margin-top: 3px; }
|
|
|
.stg .f i { display: block; height: 100%; border-radius: 2px; background: currentColor; width: calc(var(--v) * 100%); }
|
|
|
.stg.blue { color: var(--kf-s1); } .stg.violet { color: var(--kf-s2); } .stg.teal { color: var(--kf-s3); } .stg.amber { color: var(--kf-s4); } .stg.rose { color: var(--kf-s5); }
|
|
|
.stg.todo { color: var(--kf-ink-3); background: transparent; border-style: dashed; border-color: color-mix(in srgb, var(--kf-ink-3) 22%, transparent); }
|
|
|
.stg.todo .n { color: var(--kf-ink-3); font-weight: 500; }
|
|
|
/* A 卡下半:待评分(左)| 卡池进度(右)。两个分区头共用 .lbl,行底对齐 12 */
|
|
|
- .me-split { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); gap: 32px; }
|
|
|
+ .me-split { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 32px; align-items: start; }
|
|
|
.me-split > div { min-width: 0; }
|
|
|
.me-split .lbl { min-height: 22px; }
|
|
|
.pending { display: grid; gap: 0; margin-top: 4px; }
|
|
|
+ /* 待评分行贴底:与左列的三行进度在同一底线上 */
|
|
|
+ .me-split > div:last-child { display: flex; flex-direction: column; }
|
|
|
+ .me-split > div:last-child .pending, .me-split > div:last-child .me-none { margin-top: auto; }
|
|
|
.pending li { display: flex; align-items: baseline; gap: 8px; min-height: 32px; font-size: 14px; }
|
|
|
.pending li a { color: var(--kf-ink); text-decoration: none; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
|
.pending li a:hover { color: var(--kf-accent-ink); }
|
|
|
- .pending li .s { margin-left: auto; font-weight: 600; color: var(--kf-accent-ink); font-variant-numeric: tabular-nums; }
|
|
|
+ .pending li .d { font-size: 12px; color: var(--kf-ink-3); flex: none; }
|
|
|
+ .pending li .s { margin-left: auto; font-weight: 600; color: var(--kf-accent-ink); font-variant-numeric: tabular-nums; flex: none; }
|
|
|
.me-none { font-size: 14px; color: var(--kf-ink-3); padding-top: 10px; }
|
|
|
+ .me-note { font-size: 12px; line-height: 1.5; color: var(--kf-ink-3); padding-top: 2px; }
|
|
|
.prog { display: grid; gap: 0; margin-top: 4px; }
|
|
|
.prog li { display: grid; grid-template-columns: 6px auto 1fr auto; align-items: baseline; gap: 10px; min-height: 32px; font-size: 14px; }
|
|
|
.prog .pk { color: var(--kf-ink-2); }
|
|
|
@@ -122,7 +137,7 @@ export class ViewWorkbench extends LitElement {
|
|
|
.prog .pp { color: var(--kf-ink-3); font-size: 12px; font-variant-numeric: tabular-nums; }
|
|
|
|
|
|
/* ---------- B 卡:现场(深色) ---------- */
|
|
|
- .live { display: grid; gap: var(--kf-space-in); height: 100%; align-content: start;
|
|
|
+ .live { display: flex; flex-direction: column; gap: var(--kf-space-in); align-content: start;
|
|
|
--live-ink: #F4F4F5; --live-ink-3: #B4B4BC; --live-line: rgba(255, 255, 255, 0.12); }
|
|
|
.live .lbl { color: var(--live-ink-3); }
|
|
|
.live-head { display: flex; align-items: center; gap: 8px; }
|
|
|
@@ -139,7 +154,14 @@ export class ViewWorkbench extends LitElement {
|
|
|
.stalled .meta { color: var(--live-ink-3); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
|
.stalled .h { margin-left: auto; font-weight: 600; font-variant-numeric: tabular-nums; }
|
|
|
.live-ok { display: flex; align-items: center; gap: 8px; margin-top: 4px; font-size: 14px; font-weight: 500; color: var(--live-ink); }
|
|
|
- .live-foot { margin-top: auto; font-size: 12px; color: var(--live-ink-3); }
|
|
|
+ .live-rank { display: grid; gap: 0; border-top: 1px solid var(--live-line); padding-top: 8px; }
|
|
|
+ .live-rank .lbl { margin-bottom: 4px; }
|
|
|
+ .rk { display: grid; grid-template-columns: 6px minmax(0, 1fr) 56px auto; align-items: center; gap: 8px; min-height: 26px; font-size: 12px; color: var(--live-ink); }
|
|
|
+ .rk-k { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
|
+ .rk-bar { height: 4px; border-radius: 2px; background: var(--live-line); overflow: hidden; }
|
|
|
+ .rk-bar i { display: block; height: 100%; border-radius: 2px; background: var(--live-ink); }
|
|
|
+ .rk-n { font-variant-numeric: tabular-nums; color: var(--live-ink-3); }
|
|
|
+ .live-foot { margin-top: auto; padding-top: 8px; font-size: 12px; color: var(--live-ink-3); }
|
|
|
|
|
|
/* ---------- C/D/E:三张短数据卡 ---------- */
|
|
|
.stat { display: grid; grid-template-rows: auto auto auto; gap: 8px; height: 100%; align-content: start; }
|
|
|
@@ -157,9 +179,9 @@ export class ViewWorkbench extends LitElement {
|
|
|
.feed-head { display: flex; align-items: center; gap: 8px; min-height: 22px; }
|
|
|
.feed-head .go { margin-left: auto; }
|
|
|
/* 行:左标题 / 中阶段 / 右时间。网格而不是 flex —— 中间那列 auto 宽,右边永远贴右 */
|
|
|
- .feed { display: grid; margin-top: 8px; }
|
|
|
- .feed li { display: grid; grid-template-columns: minmax(0, 1fr) auto 64px; align-items: baseline; gap: 16px; padding: 11px 0; border-top: 1px solid var(--kf-line); font-size: 14px; }
|
|
|
- .feed li:first-child { border-top: 0; padding-top: 4px; }
|
|
|
+ .feed { display: grid; }
|
|
|
+ .feed li { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) 64px; align-items: baseline; gap: 16px; padding: 11px 0; border-top: 1px solid var(--kf-line); font-size: 14px; }
|
|
|
+ .feed li:first-child { border-top: 1px solid var(--kf-line); padding-top: 11px; margin-top: 8px; }
|
|
|
.feed li:last-child { padding-bottom: 4px; border-bottom: 0; }
|
|
|
.feed li:last-child a { font-weight: 500; }
|
|
|
.feed-more { display: inline-flex; align-items: center; gap: 4px; margin-top: 6px; font-size: 14px; }
|
|
|
@@ -182,8 +204,9 @@ export class ViewWorkbench extends LitElement {
|
|
|
.bento > .row { gap: var(--kf-space-card); }
|
|
|
.bento > .row.cde { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
|
|
|
.me { gap: 12px; }
|
|
|
- .me-id h3, .me-id .sub { display: inline; }
|
|
|
- .me-id > div { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
|
|
|
+ .me-id { grid-template-columns: auto minmax(0, 1fr) !important; }
|
|
|
+ .me-id .avatar { width: 40px; height: 40px; font-size: 20px; }
|
|
|
+ .me-nums { grid-column: 1 / -1; justify-self: start; }
|
|
|
.me-nums { margin-left: 0; width: 100%; justify-content: flex-start; gap: 24px; }
|
|
|
.me-nums div { text-align: left; display: flex; align-items: baseline; gap: 4px; }
|
|
|
/* 五阶段一行放不下英文名:两行三列(第五格占满第二行左半),英文名折行两行后省略 */
|
|
|
@@ -224,8 +247,8 @@ export class ViewWorkbench extends LitElement {
|
|
|
${head('我的推进', '五阶段进度与现场状态', html`<a class="go" href=${href('/pool')} data-link>机会卡池 →</a>`)}
|
|
|
<div class="bento">
|
|
|
<div class="row ab grid2 kf-enter" style="--i:0">
|
|
|
- <kf-glass-card data-role="a">${this.#mine(me, pool, live)}</kf-glass-card>
|
|
|
- <kf-glass-card data-role="b" dark>${this.#live(live, pool)}</kf-glass-card>
|
|
|
+ <kf-glass-card data-role="a" fill-to>${this.#mine(me, pool, live)}</kf-glass-card>
|
|
|
+ <kf-glass-card data-role="b" dark fill-to>${this.#live(live, pool)}</kf-glass-card>
|
|
|
</div>
|
|
|
|
|
|
<div class="row cde kf-enter" style="--i:1">
|
|
|
@@ -249,13 +272,9 @@ export class ViewWorkbench extends LitElement {
|
|
|
if (!this.me) {
|
|
|
const maxSub = Math.max(1, ...live.stages.map((r) => r.submitted));
|
|
|
return html`<div class="me" data-empty="no-me">
|
|
|
- <div class="me-id"><div class="avatar q">?</div>
|
|
|
- <div><h3>还没选「我是」</h3><span class="sub">先看全员:${live.memberCount} 人</span></div>
|
|
|
+ <div class="me-id" style="grid-template-columns:auto minmax(0,1fr) auto"><div class="avatar q">?</div>
|
|
|
+ <div class="me-title"><h3>还没选「我是」</h3><span class="sub">先看全员:${live.memberCount} 人 · 已交 ${live.submittedPeople} 人</span></div>
|
|
|
<a class="go" href=${href('/members')} data-link>${icon('user', 14)} ${t('选我')}</a></div>
|
|
|
- <div class="me-nums">
|
|
|
- <div><b>${live.memberCount}</b><span>人</span></div>
|
|
|
- <div><b>${live.submittedPeople}</b><span>已交</span></div>
|
|
|
- </div>
|
|
|
<div class="stagebar" data-allstages>
|
|
|
${live.stages.map((r, i) => html`<div class="stg ${TONE[r.stage.code]}" style=${`--i:${i + 1}`} data-stage=${r.stage.code}>
|
|
|
<span class="b ${TONE[r.stage.code]}">${r.stage.code}</span>
|
|
|
@@ -272,7 +291,7 @@ export class ViewWorkbench extends LitElement {
|
|
|
return html`<div class="me" data-empty=${me.count === 0 ? 'no-result' : 'none'}>
|
|
|
<div class="me-id">
|
|
|
<div class="avatar">${Array.from(me.me).slice(-1).join('')}</div>
|
|
|
- <div><h3>${me.me}</h3><span class="sub">已完成 ${me.stagesDone.length} / 5 个阶段</span></div>
|
|
|
+ <div class="me-title"><h3>${me.me}</h3><span class="sub">已完成 ${me.stagesDone.length} / 5 个阶段 · 累计 ${me.count} 份成果</span></div>
|
|
|
<div class="me-nums">
|
|
|
<div><b>${me.count}</b><span>份成果</span></div>
|
|
|
<div><b>${me.opps.length}</b><span>张卡</span></div>
|
|
|
@@ -299,8 +318,12 @@ export class ViewWorkbench extends LitElement {
|
|
|
</div>
|
|
|
<div>
|
|
|
<div class="lbl">待评分${pending.length ? ` ${pending.length}` : ''}</div>
|
|
|
- ${pending.length ? html`<ul class="pending">${pending.slice(0, 3).map((o) => html`<li>
|
|
|
- <a href=${href(`/pool/${o.id}`)} data-link>${o.title}</a><span class="s">${o.stats.avg != null ? Math.round(o.stats.avg) : '—'}</span></li>`)}</ul>`
|
|
|
+ <p class="me-note">候选卡里还没有你打分的卡,按最近上传排</p>
|
|
|
+ ${pending.length ? html`<ul class="pending">${pending.slice(0, 4).map((o) => html`<li>
|
|
|
+ <a href=${href(`/pool/${o.id}`)} data-link>${o.title}</a>
|
|
|
+ <span class="d">${o.stats.n ? `${o.stats.n} 人 · 均 ${o.stats.avg != null ? Math.round(o.stats.avg) : '—'}` : '尚未评分'}</span>
|
|
|
+ <a class="s" href=${href(`/pool/${o.id}`)} data-link aria-label="去评分">${o.stats.avg != null ? Math.round(o.stats.avg) : '去评'}</a></li>`)}</ul>
|
|
|
+ ${pending.length > 4 ? html`<a class="feed-more go" href=${href('/pool')} data-link>还有 ${pending.length - 4} 张待评分 →</a>` : ''}`
|
|
|
: html`<p class="me-none">没有等你评分的卡</p>`}
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -333,6 +356,14 @@ export class ViewWorkbench extends LitElement {
|
|
|
: html`
|
|
|
<div class="live-title">大家都在动</div>
|
|
|
<p class="live-ok">${icon('check', 16)} 没有超过 8 小时没交成果的人</p>`}
|
|
|
+ <div class="live-rank">
|
|
|
+ <div class="lbl">各阶段已交</div>
|
|
|
+ ${live.stages.map((r, i) => html`<div class="rk">
|
|
|
+ <i class="dot" style=${`background:var(--kf-${['s1', 's2', 's3', 's4', 's5'][i]})`}></i>
|
|
|
+ <span class="rk-k">${r.stage.code} ${r.stage.name}</span>
|
|
|
+ <span class="rk-bar"><i style=${`width:${Math.round((r.submitted / Math.max(1, live.memberCount)) * 100)}%`}></i></span>
|
|
|
+ <span class="rk-n">${r.submitted}/${live.memberCount}</span></div>`)}
|
|
|
+ </div>
|
|
|
<div class="live-foot">${t(`${live.memberCount} 人 · ${pool.total} 张卡在推进`)}</div>
|
|
|
</div>`;
|
|
|
}
|