- index.vue:画布与面板包进 .ed-body(flex row),新增 aside.ed-info 五分区—— 流程信息(名称/编码/归属应用,与画布同源同一 ref,编码沿用 !!editId||!!baseGuid 禁用)/ 状态与版本(状态 Tag + v 版本号 + flowGuid 等宽 + 复制,新建态显示「保存后生成」)/ 校验问题清单(错误在前警告在后,项内 path+msg)/ 结构统计(walkItems 递归四类计数)/ 快捷入口(流程设置/源码/图示预览,:disabled=!editId 同现状) - sourceFlowGuid ref:load() 里 defGet 后取 d.flowGuid,新建态空串 - locateIssue:清单项点击 scrollIntoView 居中 + .nd-locate 高亮 2.8s;三张卡片根元素加 :id="'nd-'+node.uid", uid 为空的清单项 class=fix 不可点;高亮样式走 :deep(卡片在子组件内) - 画布左对齐:.ed-canvas align-items center→flex-start 验证:npm run build 通过;npx tsc --noEmit 48 条=基线无新增;convert 往返 ALL PASS
137 lines
3.5 KiB
Vue
137 lines
3.5 KiB
Vue
<script setup lang="ts">
|
||
// 审批节点卡片(方案 §3.2):标题 + 审批人摘要 + 会签/时限标签 + 就地校验标注;hover 显示删除
|
||
import { computed, inject } from "vue";
|
||
import { ApprovalNode, EDITOR_CTX, assigneeText, nodeTags } from "../model";
|
||
|
||
const props = defineProps<{ node: ApprovalNode }>();
|
||
|
||
const ctx = inject(EDITOR_CTX)!;
|
||
|
||
const issues = computed(() => ctx.issueOf(props.node.uid));
|
||
const hasError = computed(() => issues.value.some((i) => i.level === "error"));
|
||
const summary = computed(() => assigneeText(props.node.assignee, ctx.depts, ctx.userNames));
|
||
const tags = computed(() => nodeTags(props.node));
|
||
|
||
// 删除控件在卡片内,点击不应顺带打开配置抽屉(确认气泡已 transfer 到 body,不受影响)
|
||
function onOpen(e: MouseEvent): void {
|
||
if ((e.target as HTMLElement).closest(".nc-del")) return;
|
||
ctx.openNode(props.node.uid);
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<div :id="'nd-' + node.uid" class="node-card" :class="{ error: hasError }" @click="onOpen">
|
||
<div class="nc-head">
|
||
<span class="nc-icon">审</span>
|
||
<span class="nc-name">{{ node.name || "未命名节点" }}</span>
|
||
<!-- view-ui-plus 无 Popconfirm 组件,二次确认用 Poptip 的 confirm 模式 -->
|
||
<Poptip
|
||
confirm
|
||
title="删除该审批节点?"
|
||
ok-text="删除"
|
||
cancel-text="取消"
|
||
transfer
|
||
@on-ok="ctx.removeNode(node.uid)"
|
||
>
|
||
<span class="nc-del" title="删除节点">×</span>
|
||
</Poptip>
|
||
</div>
|
||
<div class="nc-sub">{{ summary }}</div>
|
||
<div class="nc-sub last">
|
||
<span v-for="t in tags" :key="t" class="tag">{{ t }}</span>
|
||
</div>
|
||
<div v-for="(i, k) in issues" :key="k" class="nc-issue" :class="i.level">⚠ {{ i.msg }}</div>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.node-card {
|
||
width: 264px;
|
||
background: #fff;
|
||
border-radius: 8px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||
cursor: pointer;
|
||
border: 2px solid transparent;
|
||
transition: all 0.15s;
|
||
}
|
||
.node-card:hover {
|
||
border-color: var(--brand);
|
||
}
|
||
.node-card.error {
|
||
border-color: #ed4014;
|
||
}
|
||
.nc-head {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 12px 14px 2px;
|
||
}
|
||
.nc-icon {
|
||
flex: none;
|
||
width: 26px;
|
||
height: 26px;
|
||
border-radius: 6px;
|
||
background: #e8f3ff;
|
||
color: var(--brand);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 13px;
|
||
}
|
||
.nc-name {
|
||
flex: 1;
|
||
font-weight: 600;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
.nc-del {
|
||
flex: none;
|
||
width: 20px;
|
||
height: 20px;
|
||
border-radius: 50%;
|
||
display: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: #fff;
|
||
background: #c5c9d1;
|
||
font-size: 13px;
|
||
line-height: 1;
|
||
}
|
||
.node-card:hover .nc-del {
|
||
display: inline-flex;
|
||
}
|
||
.nc-del:hover {
|
||
background: #ed4014;
|
||
}
|
||
.nc-sub {
|
||
padding: 4px 16px 0;
|
||
color: #808695;
|
||
font-size: 12px;
|
||
line-height: 1.6;
|
||
word-break: break-all;
|
||
}
|
||
.nc-sub.last {
|
||
padding-bottom: 12px;
|
||
}
|
||
.tag {
|
||
display: inline-block;
|
||
padding: 1px 6px;
|
||
margin-right: 4px;
|
||
border-radius: 4px;
|
||
font-size: 11px;
|
||
background: #f5f7fa;
|
||
color: #808695;
|
||
}
|
||
.nc-issue {
|
||
padding: 4px 16px 8px;
|
||
font-size: 12px;
|
||
}
|
||
.nc-issue.error {
|
||
color: #ed4014;
|
||
}
|
||
.nc-issue.warn {
|
||
color: #ff9900;
|
||
}
|
||
</style>
|