Files
flow-center-front/src/views/flow/components/InstanceDrawer.vue
T
chenxing c93313cdb7
build / build (push) Successful in 1m28s
feat(flow): 流程图入口/失败提示/指派预览/线级停发闭环/配置分层/选人宿主
- 修复办理页「查看流程图」双 hash URL:改 router.resolve + toAppHashUrl 单 hash
- 修复管理端办件抽屉「查看大图」域名尾点(origin + BASE_URL("./") 拼接)
- 新增 flowError 口径层与办理页内联失败条,审批失败提示可读、不泄漏堆栈
- 审批节点抽屉新增「预览候选人」真入口 + AssigneePreviewModal(只读,不写回定义)
- 线级停发/恢复失败改为单条错误面,避免同错双 toast
- 审批抽屉核心区/高级设置分层;插入菜单常用/高级分组
- 新增 FlowAssignEmbed 选人 iframe 父侧宿主(origin/source/信封/context 四校验)
- 修复 /diagram、/assign-preview 面包屑误显示「流程编辑器」
2026-10-28 03:18:54 +08:00

109 lines
3.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
// 办件详情抽屉(管理面列表页复用):非 iframe,内部直接复用 InstanceBody(full 口径)。
// 宽度与 Notice 审批记录抽屉对齐 740px;关闭后清空状态,下次打开重新加载。
import { ref, computed, watch } from "vue";
import { useRouter } from "vue-router";
import { Drawer, Tag } from "view-ui-plus";
import { flowApi, INSTANCE_STATUS, INSTANCE_STATUS_COLOR } from "@/api/module/flow";
import InstanceBody from "@/views/flow/components/InstanceBody.vue";
import config from "@/assets/config/host.config";
import { toAppHashUrl } from "@/utils/appUrl";
const router = useRouter();
const props = defineProps<{
modelValue: boolean;
instanceId?: string | number;
}>();
const emit = defineEmits<{ (e: "update:modelValue", val: boolean): void }>();
const visible = computed({
get: () => props.modelValue,
set: (val) => emit("update:modelValue", val),
});
const loading = ref(false);
const detail = ref<any>(null);
const mode = ref("user");
async function load() {
const id = props.instanceId;
if (!id || !visible.value) return;
loading.value = true;
try {
detail.value = await flowApi.detail(String(id)).send();
} finally {
loading.value = false;
}
}
watch(() => [props.instanceId, visible.value], load, { immediate: true });
watch(visible, (val) => {
if (!val) detail.value = null;
});
function switchMode(val: string) {
mode.value = val;
}
const diagramSrc = computed(() => {
if (!detail.value?.instanceId) return "";
return `${config.serviceHost}/api/flow/diagram.png?instanceId=${detail.value.instanceId}&mode=${mode.value}`;
});
function openDiagram() {
if (!detail.value?.instanceId) return;
// 原写法 `${origin}${BASE_URL}#/diagram?…` 里 BASE_URL 构建期是 "./",拼出
// `https://host./#/…`(域名尾点);改为按当前真实地址丢 hash 再接目标 hash
const href = router.resolve({
path: "/diagram",
query: { instanceId: String(detail.value.instanceId), mode: mode.value },
}).href;
window.open(toAppHashUrl(href), "_blank");
}
function statusName(s: number) {
return INSTANCE_STATUS[s] || s;
}
function statusColor(s: number) {
return INSTANCE_STATUS_COLOR[s] || "gray";
}
</script>
<template>
<Drawer
v-model="visible"
:title="detail?.bizTitle || '办件详情'"
:width="740"
:transfer="false"
:styles="{ body: { padding: '0' } }"
>
<div v-if="loading" class="drawer-loading muted">加载中…</div>
<template v-else-if="detail">
<div class="drawer-head">
<Tag :color="statusColor(detail.status)">{{ statusName(detail.status) }}</Tag>
</div>
<div class="drawer-body">
<InstanceBody
full
:detail="detail"
:diagram-src="diagramSrc"
:initial-mode="mode"
@mode-change="switchMode"
>
<template #diagram-link>
<a class="fold-link" @click.stop.prevent="openDiagram">查看大图</a>
</template>
</InstanceBody>
</div>
</template>
</Drawer>
</template>
<style scoped>
.drawer-head { padding: 12px 16px 8px; }
.drawer-body { padding: 0 16px 16px; }
.drawer-loading { padding: 48px 16px; text-align: center; }
.fold-link { font-size: 12px; font-weight: normal; }
</style>