三面拆分⑯:流程包详情改三栏 · 字段只声明 · 版本可删可改名
**字段只声明,不做任何要求**(用户定):编排层不再碰字段 ——
· 激活闸只剩两面:结构闭合(dangling-node / multi-default-edge)与活动装载
(unknown-activity);字段类的检查(同名不同型、容忍分支被必填依赖)全部退役。
· 节点属性卡的「数据接口」从「推来源」改成**纯声明**:照活动契约列出吃什么、吐什么,
不标必填、不推来源、不提补全 —— 缺了怎么补是**活动内实现**的事,不在这一层现形。
· 字段类型支持数组:统一写成 `T[]`(如 `any[]`),出口口的字段也带上类型
(原来只有字段名)。实测 A2 的 benchmark 口显示「rows any[] · needSourcing boolean」。
**详情页改三栏**:左窄轨版本(132px) | 中流程图 | 右节点属性。
· 版本条一版一行(v几 · 状态 · 点/边计数),动作只在**看着的那一版**上展开 ——
窄栏放不下每行一排钮,也不该让人误点别版。
· 删掉「激活 · 双判据」整卡:没选节点时,属性栏就地列出还差哪几条(点一条定位过去);
两面都齐时盖一枚小检验章,不再占一整张卡。
· 删掉节点拣选行 —— 直接在图上点节点。
· 属性卡用包壳绝对定位:行高由中栏的图定,属性长了在卡内滚,不把图拉长
(实测卡高 467、明细内容 1039、可滚,图框不受影响)。窄轨里属性小卡改单列竖排。
· 顺带校正:上一轮那条「图框下沿对齐左列底栏顶线」的 20px 留白,
三栏改版后左栏已无底栏,没有对齐对象了 —— 改回四边等距(18px)。
**版本可删可改名**(新):
· 删:生效版不可删(先停用,ActiveVersionError → 409)、在途钉版不可删
(那些单要按它跑完,PinnedVersionError → 409);删掉正看的那版会落到剩下的最新版,
一版不剩就回货架。
· 改名:名字是**这条流的身份**,一次改及于所有版本 —— 版本列表上只显示 v1/v2…,
若只改一版的名,列表上什么也看不见,人会以为没生效。
· 5 条单测守两道闸与改名口径;实测走查:改名落库 → 改回;生效版删 409、停用版删 200。
process CONTRACT.md 与产品设计.md 同步。五闸绿。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
@@ -341,10 +341,9 @@
|
||||
/* 图自身按 aspect-ratio 缩放,整张一定看得全——纸面不再限高、不再内部滚动 */
|
||||
.g-canvas .process-desk { flex: 1; min-height: 0; height: auto; max-height: none; overflow: visible; padding: 0; background: transparent; display: flex; flex-direction: column; }
|
||||
.g-canvas .process-doc { flex: 1; min-height: 0; box-sizing: border-box; max-width: none; padding: 14px 18px 18px; border-radius: 10px; box-shadow: var(--cshadow); display: flex; flex-direction: column; }
|
||||
/* 图框吃满纸面,并在下方空出**恰好一条底栏的高度** —— 图框下沿与左列版本卡底栏
|
||||
(.g-vercard-f,净高 38)的上沿连成同一条横线。20 = 38(底栏净高) − 18(纸面下内距)。
|
||||
纸面被栅格拉高时(版本多、左列更长)图框跟着长,才不会又浮回上面去。 */
|
||||
.g-canvas .process-doc > .hero { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; margin-bottom: 20px; }
|
||||
/* 图框吃满纸面(纸被栅格拉高时跟着长,不会浮回上面);下沿留白与纸面左右内距同为 18,
|
||||
四边等距 —— 三栏改版后左列不再有底栏,原先那条「对齐底栏顶线」的 20px 就没有对齐对象了。 */
|
||||
.g-canvas .process-doc > .hero { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; margin-bottom: 0; }
|
||||
.g-canvas .process-doc > .hero > .fig-body { flex: 1 1 auto; min-height: 0; }
|
||||
/* 画布上的选中态(外挂类,_flow 复刻件未改):命中层描边 = 选中框 */
|
||||
.g-canvas .flow-node-sel .djs-hit { fill: rgba(51, 112, 255, .09) !important; stroke: #3370ff !important; stroke-width: 2.5px !important; stroke-opacity: 1 !important; rx: 7px; ry: 7px; }
|
||||
@@ -520,7 +519,11 @@
|
||||
/* ── 流程详情:左版本列 + 右画布(补充)──────────────────────────────
|
||||
版本收在流程内部:左列是这条流的全部版本(恰一个生效),点谁看谁的图;
|
||||
属性区从右侧窄栏挪到图下整行(g-wide),声明式契约细节再往下。 */
|
||||
.g-flowlab { display: grid; grid-template-columns: minmax(220px, 1fr) minmax(0, 2.2fr); gap: 12px; align-items: stretch; }
|
||||
/* 三栏(2026-07-30):左**窄**版本条 · 中流程图 · 右节点属性。
|
||||
右栏用包壳绝对定位 —— 行高由中栏的图定,属性长了在卡内滚,不把图拉长。 */
|
||||
.g-flowlab { display: grid; grid-template-columns: 132px minmax(0, 2.5fr) minmax(320px, 1.25fr); gap: 12px; align-items: stretch; }
|
||||
.g-nodewrap { position: relative; min-height: 0; }
|
||||
.g-nodewrap > .g-nodecard { position: absolute; inset: 0; height: auto; }
|
||||
/* 版本卡:与右侧的图**等高**(grid stretch),版本多了在卡内滚,不把页面撑长。
|
||||
形制取**图纸风**,与右边的流程图同一套语言(flow-canvas.css 的 process-doc):
|
||||
白纸同影同角、mono 小字距大写题头(VER — 前缀对 FIG — 前缀)、钢青/黄铜色系、
|
||||
@@ -541,6 +544,27 @@
|
||||
.g-ver-new:hover { border-color: #4e7daf; box-shadow: 0 0 0 2px rgba(78, 125, 175, .14); }
|
||||
.g-ver-new:disabled { opacity: .5; cursor: default; box-shadow: none; }
|
||||
.g-vercard-list { flex: 1; min-height: 0; overflow-y: auto; padding: 12px 14px; display: flex; flex-direction: column; gap: 8px; }
|
||||
|
||||
/* ── 窄版本条:一版一行(v几 + 状态 + 计数),动作只在**看着的那一版**上展开 ── */
|
||||
.g-verslim .g-vercard-h { padding: 30px 10px 16px; gap: 4px; }
|
||||
.g-verslim .g-vercard-list { padding: 10px 8px; gap: 6px; }
|
||||
.g-verrow { display: flex; flex-direction: column; border: 1px solid var(--sh-line); border-left: 3px solid var(--sh-steel); background: #fff; }
|
||||
.g-verrow.on { border-color: #9fb0c0; background: #f2f5f8; }
|
||||
.g-verrow.live { border-left-color: var(--sh-brass); background: var(--sh-brass-wash); }
|
||||
.g-verrow.live.on { border-color: #cbb98d; }
|
||||
.g-verrow-h { display: flex; flex-wrap: wrap; align-items: baseline; gap: 3px 6px; padding: 7px 8px; border: 0; background: transparent; font-family: var(--sh-mono); font-size: 10px; color: #3a4452; text-align: left; cursor: pointer; }
|
||||
.g-verrow-h > b { font-size: 12.5px; font-weight: 700; color: var(--sh-ink); }
|
||||
.g-verrow-h .st { font-size: 9px; letter-spacing: .1em; color: var(--sh-muted); }
|
||||
.g-verrow-h .st.live { color: var(--sh-brass); font-weight: 700; }
|
||||
.g-verrow-h .cnt { flex-basis: 100%; font-size: 9px; color: var(--sh-muted); }
|
||||
.g-verrow-a { display: flex; flex-wrap: wrap; gap: 4px; padding: 0 8px 8px; }
|
||||
.g-verrow-a .g-ver-act { flex: 1 1 auto; text-align: center; padding: 3px 6px; letter-spacing: .06em; }
|
||||
.g-ver-act.t-bad { color: #b0413e; border-color: #e0bcba; }
|
||||
.g-ver-act:disabled { opacity: .45; cursor: default; }
|
||||
/* 改名条:名字改的是整条流,所以落在卡底、不挂在某一行上 */
|
||||
.g-verrename { flex: none; display: flex; flex-direction: column; gap: 5px; padding: 9px 10px; border-top: 1px solid var(--sh-line); background: #f9fafc; }
|
||||
.g-verrename .g-input { height: 26px; font-size: 12px; }
|
||||
.g-verrename .t { font-family: var(--sh-mono); font-size: 8.5px; line-height: 1.7; color: var(--sh-muted); }
|
||||
.g-ver { display: flex; align-items: center; gap: 9px; padding: 9px 11px; border: 1px solid var(--sh-line); border-left: 3px solid var(--sh-steel); background: #fff; cursor: pointer; font-family: var(--sh-mono); font-size: 11px; color: #3a4452; }
|
||||
.g-ver:hover { border-color: #aeb9c6; }
|
||||
.g-ver.on { background: #f2f5f8; border-color: #9fb0c0; }
|
||||
@@ -554,10 +578,6 @@
|
||||
.g-ver-act { border: 1px solid var(--sh-line); background: #fff; padding: 2px 8px; font-family: inherit; font-size: 9.5px; letter-spacing: .1em; color: #3a4452; cursor: pointer; }
|
||||
.g-ver-act:hover { border-color: #aeb9c6; }
|
||||
.g-ver-act.t-go { color: var(--sh-brass); border-color: #d9c9a4; }
|
||||
/* 卡底栏 —— 它的净高(1 顶线 + 10 + 17 行 + 10 = 38)是**两列共用的基线**:
|
||||
右侧画布的图框下沿要落在这条顶线上(见上面 .g-canvas .process-doc > .hero 的下外距)。
|
||||
文案改长到换行、或改了内距,那边的 20px 要跟着算。 */
|
||||
.g-vercard-f { flex: none; min-height: 38px; box-sizing: border-box; padding: 10px 16px; border-top: 1px solid var(--sh-line); font-family: var(--sh-mono); font-size: 9.5px; line-height: 1.8; color: var(--sh-muted); }
|
||||
.g-ver { display: flex; align-items: center; gap: 8px; padding: 10px 12px; background: var(--card); border: 1px solid var(--cline); border-radius: 11px; cursor: pointer; font: inherit; text-align: left; transition: border-color var(--t-fast), box-shadow var(--t-fast); }
|
||||
.g-ver:hover { border-color: #c9d6e6; }
|
||||
.g-ver.on { border-color: var(--brand); box-shadow: 0 0 0 2px var(--brand-wash); }
|
||||
@@ -572,35 +592,16 @@
|
||||
检验章(判据面全清的合格章)是唯一的戏眼,其余一律细线纪律。 */
|
||||
|
||||
/* ── 激活 · 双判据 → 检验单:上下两格判据面均分卡高,面头一行、面体列违规 ── */
|
||||
.g-exboard { min-height: 0; }
|
||||
.g-exboard .g-vercard-h { height: auto; padding: 13px 18px 10px; }
|
||||
.g-vercard-list.g-exsheet { padding: 0; gap: 0; overflow: hidden; }
|
||||
.g-exface { flex: 1 1 0; min-height: 0; display: flex; flex-direction: column; }
|
||||
.g-exface + .g-exface { border-top: 1px solid var(--sh-line); }
|
||||
.g-exfacet { flex: none; display: flex; align-items: center; gap: 7px; padding: 10px 16px 9px; font: 600 9.5px/1 var(--sh-mono, var(--mono)); letter-spacing: 0.14em; text-transform: uppercase; color: var(--sh-steel, #46586a); border-bottom: 1px dashed #e4e9ef; }
|
||||
.g-exfacet.ok { color: #2e7d4f; }
|
||||
.g-exfacet .st { margin-left: auto; letter-spacing: .1em; text-align: right; }
|
||||
.g-exfacet:not(.ok) .st { color: #b0413e; }
|
||||
.g-exfacet:not(.ok) svg { color: #b0413e; }
|
||||
.g-exface-b { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 7px; padding: 10px 14px 12px; }
|
||||
/* 违规行:方角细线 + 红左线(压回全局 .g-ver 的圆角白卡版);点一条定位到节点属性 */
|
||||
.g-exface-b .g-ver { border-radius: 0; border: 1px solid var(--sh-line); border-left: 3px solid #b0413e; padding: 7px 10px; font-family: var(--sh-mono); box-shadow: none; }
|
||||
.g-exface-b .g-ver:hover { border-color: #aeb9c6; border-left-color: #b0413e; }
|
||||
.g-exface-b .g-ver:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
|
||||
.g-ex { cursor: pointer; border-left-color: #b0413e; }
|
||||
.g-ex > b { font-size: 11px; }
|
||||
.g-ex .msg { flex: 1; min-width: 0; font-size: 10.5px; line-height: 1.55; letter-spacing: 0; text-transform: none; color: #3a4452; }
|
||||
/* 检验章:该面清零即盖 —— 双线方框微旋,检验单的通过凭证;半透边线是印泥感 */
|
||||
.g-exstamp { margin: auto; display: flex; flex-direction: column; align-items: center; gap: 5px; padding: 11px 20px 10px; border: 1.5px solid rgba(46, 125, 79, .55); outline: 1px solid rgba(46, 125, 79, .3); outline-offset: 3px; color: #2e7d4f; transform: rotate(-4deg); font: 700 12.5px/1.2 var(--sh-mono); letter-spacing: .34em; text-indent: .34em; }
|
||||
.g-exstamp small { font-size: 7.5px; font-weight: 600; letter-spacing: .18em; text-indent: .18em; opacity: .7; }
|
||||
/* 第二面的章反向微旋 —— 两枚章不该是同一手势盖出来的 */
|
||||
.g-exface + .g-exface .g-exstamp { transform: rotate(2.5deg); }
|
||||
/* 裁定带:两面全清才出 —— 黄铜是「可生效」的颜色 */
|
||||
.g-exverdict { flex: none; padding: 9px 16px 9px 13px; border-top: 1px solid var(--sh-line); border-left: 3px solid var(--sh-brass); background: var(--sh-brass-wash); font-family: var(--sh-mono); font-size: 10px; line-height: 1.8; color: var(--sh-brass); }
|
||||
.g-exboard-empty { padding: 16px 18px; font-family: var(--sh-mono); font-size: 10px; line-height: 1.9; color: var(--sh-muted); }
|
||||
|
||||
/* ── 节点 · 属性 → 索引栏(固定)+ 明细区(滚动)────────────────────── */
|
||||
.g-nodecard { height: 560px; min-height: 0; }
|
||||
.g-nodecard { min-height: 0; }
|
||||
.g-nodecard .g-vercard-h { height: auto; padding: 13px 18px 10px; }
|
||||
.g-nodecard .g-vercard-h .n { margin-left: auto; letter-spacing: .1em; }
|
||||
.g-nodecard .g-vercard-h .n.dirty { color: var(--sh-brass); }
|
||||
@@ -609,15 +610,6 @@
|
||||
.g-nodecard-b > .g-note { flex: none; margin: 10px 14px 0; }
|
||||
|
||||
/* 索引栏 = 图框分度带:浅底压一层,行首竖签(节点/边 + 计数),芯片缩成分度块 */
|
||||
.g-pickrail { flex: none; background: #f9fafc; border-bottom: 1px solid var(--sh-line); }
|
||||
.g-pickrow { display: flex; align-items: flex-start; gap: 10px; padding: 8px 14px; }
|
||||
.g-pickrow + .g-pickrow { border-top: 1px dashed #e4e9ef; }
|
||||
.g-picklbl { flex: none; display: inline-flex; align-items: baseline; gap: 4px; min-width: 42px; padding-top: 6px; font: 600 9px/1 var(--sh-mono); letter-spacing: .14em; text-transform: uppercase; color: var(--sh-steel); }
|
||||
.g-picklbl b { font-weight: 600; font-size: 9px; color: var(--sh-muted); }
|
||||
.g-pickrow .g-picker { gap: 4px; }
|
||||
.g-nodecard .g-pick { height: 22px; padding: 0 8px; gap: 5px; border-radius: 0; border-color: var(--sh-line); background: #fff; font-size: 11px; color: #3a4452; }
|
||||
.g-nodecard .g-pick b { font-size: 9px; font-family: var(--sh-mono); }
|
||||
.g-nodecard .g-pick:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
|
||||
|
||||
/* 明细区:卡内唯一的滚动层 —— 索引在上钉住,拉表单不丢定位 */
|
||||
.g-propsheet { flex: 1; min-height: 0; overflow-y: auto; padding: 12px 14px 14px; }
|
||||
@@ -628,9 +620,19 @@
|
||||
.g-sheetempty b { font-size: 12px; font-weight: 700; color: var(--sh-steel); }
|
||||
.g-sheetempty p { margin: 0; font-size: 11px; line-height: 1.9; color: var(--sh-muted); }
|
||||
|
||||
/* 属性小卡:两列手排、按内容自高 —— 空白不再被 250 定高摊出来,长卡也不内滚;
|
||||
左列 = 身份与数据口,右列 = 类型与装载(JSX 里 .g-propcol 手排,语义成组、高度可控) */
|
||||
.g-nodecard .g-props { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; gap: 12px; }
|
||||
/* 缺项清单:没选节点时占住空态 —— 原「激活判据」看板的活儿收进这里,点一条定位过去 */
|
||||
.g-lack { width: 100%; display: flex; flex-direction: column; gap: 6px; text-align: left; }
|
||||
.g-lack-h { display: flex; align-items: center; gap: 7px; font: 600 9.5px/1 var(--sh-mono); letter-spacing: .14em; text-transform: uppercase; color: #b0413e; padding-bottom: 2px; }
|
||||
.g-lack-r { display: flex; align-items: baseline; gap: 8px; width: 100%; padding: 7px 10px; border: 1px solid var(--sh-line); border-left: 3px solid #b0413e; background: #fff; font: inherit; font-size: 11px; line-height: 1.7; color: #3a4452; text-align: left; cursor: pointer; }
|
||||
.g-lack-r:hover:not(:disabled) { border-color: #aeb9c6; border-left-color: #b0413e; }
|
||||
.g-lack-r:disabled { cursor: default; opacity: .75; }
|
||||
.g-lack-r > b { flex: none; font-family: var(--sh-mono); font-size: 10px; color: var(--sh-ink); }
|
||||
/* 两面都齐:一枚小检验章,别再占一整张卡 */
|
||||
.g-okstamp { display: inline-flex; align-items: center; gap: 6px; margin-top: 4px; padding: 5px 11px; border: 1px solid rgba(46, 125, 79, .45); font: 600 10px/1 var(--sh-mono); letter-spacing: .08em; color: #2e7d4f; }
|
||||
|
||||
/* 属性小卡:三栏改版后右栏是**窄轨**(≈335),两列摊不开 —— 改单列竖排,
|
||||
顺序即阅读次序:身份 → 数据接口 → 类型与责任 → 装载 → 出边。长了在明细区自己滚。 */
|
||||
.g-nodecard .g-props { display: flex; flex-direction: column; align-items: stretch; gap: 12px; }
|
||||
.g-propcol { min-width: 0; display: flex; flex-direction: column; gap: 12px; }
|
||||
.g-nodecard .g-props.g-eprops { display: flex; flex-direction: column; align-items: stretch; gap: 12px; }
|
||||
.g-nodecard .g-prop { border: 1px solid var(--sh-line); border-radius: 0; box-shadow: none; }
|
||||
|
||||
Reference in New Issue
Block a user