build / build (push) Successful in 1m28s
- 修复办理页「查看流程图」双 hash URL:改 router.resolve + toAppHashUrl 单 hash
- 修复管理端办件抽屉「查看大图」域名尾点(origin + BASE_URL("./") 拼接)
- 新增 flowError 口径层与办理页内联失败条,审批失败提示可读、不泄漏堆栈
- 审批节点抽屉新增「预览候选人」真入口 + AssigneePreviewModal(只读,不写回定义)
- 线级停发/恢复失败改为单条错误面,避免同错双 toast
- 审批抽屉核心区/高级设置分层;插入菜单常用/高级分组
- 新增 FlowAssignEmbed 选人 iframe 父侧宿主(origin/source/信封/context 四校验)
- 修复 /diagram、/assign-preview 面包屑误显示「流程编辑器」
109 lines
3.5 KiB
Vue
109 lines
3.5 KiB
Vue
<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>
|