我发起的变更页面完成
This commit is contained in:
@@ -1,441 +1,19 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, onMounted } from 'vue';
|
import { ref, computed, onMounted, h } from 'vue';
|
||||||
import { Icon } from '@iconify/vue'
|
import { Icon } from '@iconify/vue'
|
||||||
import { useThemeStore } from '@/store/modules/theme';
|
import { useThemeStore } from '@/store/modules/theme';
|
||||||
import { useRouterPush } from '@/hooks/common/router';
|
import { useRouterPush } from '@/hooks/common/router';
|
||||||
|
import { tagTextColor, tagBgColor, tagBorderColor } from '@/utils/common';
|
||||||
import { systemConfigApi } from '@/service/api/system';
|
import { systemConfigApi } from '@/service/api/system';
|
||||||
|
import { orgListApi } from '@/service/api/user';
|
||||||
import { changeLedgerListApi } from '@/service/api/changeLedger';
|
import { changeLedgerListApi } from '@/service/api/changeLedger';
|
||||||
|
|
||||||
const { routerPushByKey } = useRouterPush();
|
const { routerPushByKey } = useRouterPush();
|
||||||
const themeStore = useThemeStore();
|
const themeStore = useThemeStore();
|
||||||
|
|
||||||
const revokeModal = ref(false);
|
|
||||||
const revokeSaving = ref<boolean>(false);
|
|
||||||
const progressDrawer = ref<boolean>(false);
|
|
||||||
const dept = ref("全部组织");
|
|
||||||
const openOnly = ref(false);
|
|
||||||
const kw = ref("");
|
|
||||||
const typeFilter = ref("全部");
|
|
||||||
const statusFilter = ref("全部");
|
|
||||||
const durFilter = ref("全部");
|
|
||||||
|
|
||||||
const customFrom = ref<any>(null);
|
|
||||||
const customTo = ref<any>(null);
|
|
||||||
const sort = ref<{ k: string; dir: "asc" | "desc" }>({ k: "applyTime", dir: "desc" });
|
|
||||||
const me = "张工艺";
|
|
||||||
const DEPTS = ["全部组织", "一车间", "二车间", "供应部", "质量部"];
|
|
||||||
const deptOpts = DEPTS.map((d) => ({ label: d, value: d }));
|
|
||||||
const LEDGER_ROWS = [
|
|
||||||
{ id: "MOC-2026-R01-0035", changeId: "MOC-2026-R01-0035", title: "R-201 反应釜搅拌器电机更换(55kW→75kW 防爆电机)", type: "设备", level: "重要", duration: "永久", applyTime: "2026-07-28 09:12", dept: "一车间", applicant: "张工艺", planUse: "2026-08-10", status: "审批中", statusDetail: "专业会签中(周设备、王仪表待签)", statusTime: "2026-07-30 14:20", handlers: [{ name: "王仪表", done: true }, { name: "周设备", done: false }, { name: "王仪表", done: false }] },
|
|
||||||
{ id: "MOC-2026-R01-0036", changeId: "MOC-2026-R01-0036", title: "聚合反应温度控制上限调整(78℃→82℃)", type: "工艺", level: "重要", duration: "永久", applyTime: "2026-07-25 10:05", dept: "一车间", applicant: "孙丽", planUse: "2026-08-05", status: "审批中", statusDetail: "安全审查(王海燕)", statusTime: "2026-07-29 16:40", handlers: [{ name: "王海燕", done: false }] },
|
|
||||||
{ id: "MOC-2026-R02-0038", changeId: "MOC-2026-R02-0038", title: "DCS 罐区液位报警值 LIA-301 调整", type: "工艺", level: "一般", duration: "永久", applyTime: "2026-07-20 08:30", dept: "一车间", applicant: "吴强", planUse: "2026-07-31", status: "待PSSR", statusDetail: "培训 / PSSR 资料已传 · 待确认投用", statusTime: "2026-07-27 11:15", approveTime: "2026-07-26 16:40", handlers: [{ name: "吴强", done: false }] },
|
|
||||||
{ id: "MOC-2026-R01-0039", changeId: "MOC-2026-R01-0039", title: "V-102 安全阀起跳压力临时调整(紧急补办)", type: "设备", level: "一般", duration: "临时", urgent: true, applyTime: "2026-07-15 19:40", dept: "一车间", applicant: "张工艺", planUse: "2026-07-16(已投用)", status: "待关闭", statusDetail: "待关闭确认(资料更新核查中)", statusTime: "2026-07-27 09:02", approveTime: "2026-07-15 21:05", useTime: "2026-07-16 06:30", overdueDays: 4, handlers: [{ name: "李主任", done: false }] },
|
|
||||||
{ id: "MOC-2026-R03-0040", changeId: "MOC-2026-R03-0040", title: "原料环己烷供应商变更(新增 B 供应商)", type: "管理", level: "重要", duration: "永久", applyTime: "2026-07-18 14:22", dept: "供应部", applicant: "刘芳", planUse: "2026-08-01", status: "实施中", statusDetail: "实施准备中 · 培训 / PSSR 资料待上传", statusTime: "2026-07-26 10:30", handlers: [{ name: "刘芳", done: false }] },
|
|
||||||
{ id: "MOC-2026-R02-0031", title: "冷冻盐水泵 P-103 叶轮材质变更", type: "设备", level: "一般", duration: "永久", applyTime: "2026-06-28 09:50", dept: "二车间", applicant: "周涛", planUse: "2026-07-15", status: "待验收", statusDetail: "变更验收(72h 运行验证)", statusTime: "2026-07-24 15:44", overdueDays: 7, handlers: [{ name: "李主任", done: false }] },
|
|
||||||
{ id: "MOC-2026-R01-0029", title: "操作规程修订(夏季工况)", type: "管理", level: "一般", duration: "临时", applyTime: "2026-06-20 11:26", dept: "一车间", applicant: "张工艺", planUse: "2026-07-01", status: "审批中", statusDetail: "部门审核(李主任)", statusTime: "2026-06-21 08:40", handlers: [{ name: "李主任", done: false }] },
|
|
||||||
{ id: "MOC-2026-R02-0033", title: "包装线贴标机控制程序升级", type: "设备", level: "一般", duration: "永久", applyTime: "2026-07-08 13:35", dept: "二车间", applicant: "吴强", planUse: "2026-08-02", status: "已批准", statusDetail: "待实施(计划 8 月 2 日投用)", statusTime: "2026-07-22 09:12", handlers: [{ name: "周设备", done: false }] },
|
|
||||||
{ id: "MOC-2026-R03-0027", title: "化验室通风橱整体更换", type: "设备", level: "一般", duration: "永久", applyTime: "2026-06-12 15:10", dept: "质量部", applicant: "陈静", planUse: "2026-06-25", status: "已关闭", statusDetail: "关闭确认完成,已归档", statusTime: "2026-07-02 10:18", handlers: [{ name: "钱峰", done: true }] },
|
|
||||||
{ id: "MOC-2026-R01-0024", title: "氮气管网压力分级调整", type: "工艺", level: "重要", duration: "永久", applyTime: "2026-05-30 09:00", dept: "一车间", applicant: "孙丽", planUse: "2026-06-20", status: "已关闭", statusDetail: "关闭确认完成,已归档", statusTime: "2026-06-28 16:30", handlers: [{ name: "李主任", done: true }, { name: "刘副总", done: true }] },
|
|
||||||
];
|
|
||||||
const REF_NOW = new Date("2026-08-03T12:00:00");
|
|
||||||
const PERIOD_DAYS: Record<string, number> = { 近一年: 365, 近半年: 183, 近三个月: 92, 近一个月: 31 };
|
|
||||||
const rows = computed(() => {
|
|
||||||
let list = LEDGER_ROWS.slice();
|
|
||||||
if (dept.value !== "全部组织") list = list.filter((r) => r.dept === dept.value);
|
|
||||||
if (openOnly.value) list = list.filter((r) => r.status !== "已关闭");
|
|
||||||
if (typeFilter.value !== "全部") list = list.filter((r) => r.type === typeFilter.value);
|
|
||||||
if (statusFilter.value !== "全部") list = list.filter((r) => r.status === statusFilter.value);
|
|
||||||
if (durFilter.value !== "全部") list = list.filter((r) => r.duration === durFilter.value);
|
|
||||||
if (period.value !== "自定义") {
|
|
||||||
const from = new Date(REF_NOW.getTime() - PERIOD_DAYS[period.value] * 86400000);
|
|
||||||
list = list.filter((r) => new Date(r.applyTime.replace(" ", "T")) >= from);
|
|
||||||
} else {
|
|
||||||
if (customFrom.value) list = list.filter((r) => r.applyTime.slice(0, 10) >= customFrom.value);
|
|
||||||
if (customTo.value) list = list.filter((r) => r.applyTime.slice(0, 10) <= customTo.value);
|
|
||||||
}
|
|
||||||
if (kw.value.trim()) list = list.filter((r) => r.title.includes(kw.value.trim()) || r.id.includes(kw.value.trim()));
|
|
||||||
list.sort((a:any, b:any) => {
|
|
||||||
const va = a[sort.value.k], vb = b[sort.value.k];
|
|
||||||
return sort.value.dir === "asc" ? va.localeCompare(vb) : vb.localeCompare(va);
|
|
||||||
});
|
|
||||||
return list;
|
|
||||||
});
|
|
||||||
const navPreset = ref<string>("mine");
|
|
||||||
const finalRows = computed(() => {
|
|
||||||
switch (navPreset.value) {
|
|
||||||
case "mine": return rows.value.filter((r:any) => r.applicant === me);
|
|
||||||
case "important": return rows.value.filter((r:any) => r.level === "重要");
|
|
||||||
case "temp": return rows.value.filter((r:any) => r.duration === "临时");
|
|
||||||
case "overdue": return rows.value.filter((r:any) => r.overdueDays);
|
|
||||||
case "highrisk": return rows.value.filter((r:any) => r.level === "重要" && r.status !== "已关闭");
|
|
||||||
default: return rows.value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
interface LedgerExtra {
|
|
||||||
special?: ("延期" | "临时转永久" | "未实施" | "未投用")[];
|
|
||||||
actualUse?: string; planRestore?: string; extRestore?: string; closeTime?: string;
|
|
||||||
}
|
|
||||||
const LEDGER_EXTRA: Record<string, LedgerExtra> = {
|
|
||||||
"MOC-2026-R01-0039": { special: ["延期"], actualUse: "2026-07-16 08:30", planRestore: "2026-07-27", extRestore: "2026-08-03" },
|
|
||||||
"MOC-2026-R01-0029": { special: ["临时转永久"], planRestore: "2026-08-01" },
|
|
||||||
"MOC-2026-R02-0033": { special: ["未实施"] },
|
|
||||||
"MOC-2026-R03-0040": { special: ["未投用"] },
|
|
||||||
"MOC-2026-R02-0031": { actualUse: "2026-07-15 09:20" },
|
|
||||||
"MOC-2026-R03-0027": { actualUse: "2026-06-25 10:00", closeTime: "2026-07-02 10:18" },
|
|
||||||
"MOC-2026-R01-0024": { actualUse: "2026-06-20 08:10", closeTime: "2026-06-28 16:30" },
|
|
||||||
};
|
|
||||||
const SPECIAL_COLOR: Record<string, string> = {
|
|
||||||
延期: "bg-amber-50 text-amber-700 border-amber-300",
|
|
||||||
临时转永久: "bg-[#DFE9F6] text-[#17407F] border-[#6E93C6]/50",
|
|
||||||
未实施: "bg-red-50 text-red-600 border-red-200",
|
|
||||||
未投用: "bg-red-50 text-red-600 border-red-200",
|
|
||||||
};
|
|
||||||
const STATUS_COLOR: Record<string, string> = {
|
|
||||||
审批中: "bg-amber-100 text-amber-700 border-amber-200",
|
|
||||||
已批准: "bg-[#DFE9F6] text-[#17407F] border-[#ACC6E5]",
|
|
||||||
实施中: "bg-[#1D4E9C]/10 text-[#1D4E9C] border-[#1D4E9C]/30",
|
|
||||||
待PSSR: "bg-violet-100 text-violet-700 border-violet-200",
|
|
||||||
待验收: "bg-emerald-50 text-emerald-600 border-emerald-200",
|
|
||||||
待关闭: "bg-[#E15555]/10 text-[#E15555] border-[#E15555]/30",
|
|
||||||
已关闭: "bg-emerald-100 text-emerald-700 border-emerald-200",
|
|
||||||
};
|
|
||||||
function opsOf(r: any, me: string, role?: string): { label: string; act: string; danger?: boolean }[] {
|
|
||||||
const ops: { label: string; act: string; danger?: boolean }[] = [];
|
|
||||||
if (r.status === "审批中" && r.applicant === me) ops.push({ label: "撤回", act: "withdraw", danger: true });
|
|
||||||
if (r.status === "已批准" || r.status === "待PSSR") ops.push({ label: "未实施情况说明", act: "unimpl" });
|
|
||||||
if (r.status === "实施中") ops.push({ label: "未投用情况说明", act: "unuse" });
|
|
||||||
if (role === "dept" && (r.overdueDays ?? 0) > 0) ops.push({ label: "催办", act: "urge" });
|
|
||||||
ops.push({ label: "详情", act: "detail" }, { label: "进度", act: "progress" });
|
|
||||||
if (r.status === "已批准") ops.push({ label: "下载申请表", act: "download" });
|
|
||||||
if (r.status === "待关闭") ops.push({ label: "下载", act: "download" });
|
|
||||||
if (r.status === "已关闭") ops.push({ label: "下载归档包", act: "download" });
|
|
||||||
return ops;
|
|
||||||
}
|
|
||||||
const FLOW_IMPORTANT = [
|
|
||||||
{ name: "部门审核", kind: "审批", roles: ["dept"], status: "done" },
|
|
||||||
{
|
|
||||||
name: "专业会签",
|
|
||||||
kind: "会签",
|
|
||||||
roles: ["process", "process2", "quality"],
|
|
||||||
status: "current",
|
|
||||||
members: [
|
|
||||||
{ name: "王仪表(仪表)", done: true },
|
|
||||||
{ name: "周设备(设备)", done: false },
|
|
||||||
{ name: "陈质量(质量)", done: false },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{ name: "安全审查", kind: "审批", roles: ["safety"], status: "todo", locked: true },
|
|
||||||
{ name: "分管领导最终批准", kind: "最终批准", roles: ["vp"], status: "todo", locked: true },
|
|
||||||
];
|
|
||||||
const FLOW_SIMPLE = [
|
|
||||||
{ name: "部门审核", kind: "审批", roles: ["dept"], status: "done" },
|
|
||||||
{ name: "专业审批", kind: "审批", roles: ["process"], status: "current" },
|
|
||||||
{ name: "部门负责人批准", kind: "最终批准", roles: ["dept"], status: "todo", locked: true },
|
|
||||||
];
|
|
||||||
const CHANGES = [
|
|
||||||
{
|
|
||||||
id: "MOC-2026-R01-0035",
|
|
||||||
title: "R-201 反应釜搅拌器电机更换(55kW→75kW 防爆电机)",
|
|
||||||
type: "设备",
|
|
||||||
level: "重要",
|
|
||||||
duration: "永久",
|
|
||||||
urgent: false,
|
|
||||||
status: "审批中",
|
|
||||||
applicant: "张工艺",
|
|
||||||
org: "一车间 · 工艺组",
|
|
||||||
device: "R-201 反应釜 / M-201A 搅拌电机",
|
|
||||||
date: "2026-07-28",
|
|
||||||
purpose: "原 55kW 电机在高粘度工况下频繁过载跳闸,影响反应均匀性与产品质量,需更换为 75kW 防爆电机。",
|
|
||||||
effect: "消除过载跳闸(月均 3 次降至 0),搅拌电流裕量提升至 25%,产品批次合格率预计提升 1.5%。",
|
|
||||||
before: "M-201A 搅拌电机:55kW,ExdⅡBT4,额定电流 102A,原设计工况粘度 ≤3000cP。",
|
|
||||||
after: "更换为 75kW 防爆电机:ExdⅡCT4,额定电流 138A,适配粘度 ≤6000cP;电缆与开关容量同步校核升级。",
|
|
||||||
related: ["更新 P&ID(图号 PID-R201-03)", "修订电气图纸与电缆清册", "校核联锁跳车电流设定", "更新设备台账与备件清单", "操作人员培训"],
|
|
||||||
materials: ["设备数据表", "防爆合格证与材质证明", "电气负荷校核计算书", "更新后的 P&ID", "制造商安装维护手册"],
|
|
||||||
riskTools: ["AI 分析", "JSA", "检查表法"],
|
|
||||||
flow: FLOW_IMPORTANT,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "MOC-2026-R01-0036",
|
|
||||||
title: "聚合反应温度控制上限调整(78℃→82℃)",
|
|
||||||
type: "工艺",
|
|
||||||
level: "重要",
|
|
||||||
duration: "永久",
|
|
||||||
urgent: false,
|
|
||||||
status: "审批中",
|
|
||||||
applicant: "孙丽",
|
|
||||||
org: "一车间 · 工艺组",
|
|
||||||
device: "R-101 聚合釜 / TIC-101",
|
|
||||||
date: "2026-07-25",
|
|
||||||
purpose: "提高反应温度上限以缩短聚合时间、提升装置产能,满足新增订单需求。",
|
|
||||||
effect: "单釜反应周期缩短约 40 分钟,年产能预计提升 8%。",
|
|
||||||
before: "聚合反应温度控制范围 65–78℃,TIC-101 高报 78℃、联锁 80℃。",
|
|
||||||
after: "控制范围调整为 65–82℃,TIC-101 高报 82℃、联锁值维持 85℃ 安全边界不变。",
|
|
||||||
related: ["修订工艺卡片与操作规程", "DCS 参数与报警值修改", "更新 HAZOP 分析报告", "岗位人员再培训"],
|
|
||||||
materials: ["工艺计算书", "热平衡与飞温风险分析", "HAZOP 分析报告", "更新后的工艺卡片"],
|
|
||||||
riskTools: ["AI 分析", "HAZOP"],
|
|
||||||
flow: [
|
|
||||||
{ name: "部门审核", kind: "审批", roles: ["dept"], status: "done" },
|
|
||||||
{
|
|
||||||
name: "专业会签",
|
|
||||||
kind: "会签",
|
|
||||||
roles: ["process", "quality"],
|
|
||||||
status: "done",
|
|
||||||
members: [
|
|
||||||
{ name: "王仪表(仪表)", done: true },
|
|
||||||
{ name: "陈质量(质量)", done: true },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{ name: "安全审查", kind: "审批", roles: ["safety"], status: "current", locked: true },
|
|
||||||
{ name: "分管领导最终批准", kind: "最终批准", roles: ["vp"], status: "todo", locked: true },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "MOC-2026-R02-0038",
|
|
||||||
title: "DCS 罐区液位报警值 LIA-301 调整",
|
|
||||||
type: "工艺",
|
|
||||||
level: "一般",
|
|
||||||
duration: "永久",
|
|
||||||
urgent: false,
|
|
||||||
status: "待PSSR",
|
|
||||||
applicant: "吴强",
|
|
||||||
org: "一车间 · 罐区",
|
|
||||||
device: "V-301 储罐 / LIA-301",
|
|
||||||
date: "2026-07-20",
|
|
||||||
purpose: "原高报值偏保守,频繁误报导致操作疲劳,按最新容积表校准报警值。",
|
|
||||||
effect: "误报次数由每周 5 次降至 0,报警响应有效性提升。",
|
|
||||||
before: "LIA-301 高报 80%(对应 7.2m)。",
|
|
||||||
after: "高报调整为 85%(对应 7.65m),联锁值 90% 不变。",
|
|
||||||
related: ["DCS 组态修改", "更新报警台账", "岗位告知培训"],
|
|
||||||
materials: ["储罐容积表", "DCS 组态修改记录", "报警台账"],
|
|
||||||
riskTools: ["AI 分析", "检查表法"],
|
|
||||||
flow: FLOW_SIMPLE.map((n) => ({ ...n, status: "done" as const })),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "MOC-2026-R01-0039",
|
|
||||||
title: "紧急变更:V-102 安全阀起跳压力临时调整(补办手续)",
|
|
||||||
type: "设备",
|
|
||||||
level: "一般",
|
|
||||||
duration: "临时",
|
|
||||||
urgent: true,
|
|
||||||
status: "待关闭",
|
|
||||||
applicant: "张工艺",
|
|
||||||
org: "一车间 · 工艺组",
|
|
||||||
device: "V-102 缓冲罐 / PSV-102",
|
|
||||||
date: "2026-07-15",
|
|
||||||
purpose: "上游工况波动导致安全阀频繁起跳,经紧急批准临时调整起跳压力并限期恢复原设定。",
|
|
||||||
effect: "装置维持连续运行,临时期限内风险受控。",
|
|
||||||
before: "PSV-102 起跳压力 0.8MPa。",
|
|
||||||
after: "临时调整为 0.88MPa(不超过设计压力 1.0MPa 的 90%),期限 30 天,到期恢复 0.8MPa。",
|
|
||||||
related: ["恢复性检查", "更新安全阀台账", "事后风险分析补办"],
|
|
||||||
materials: ["安全阀校验报告", "紧急变更审批单", "事后 JSA 分析"],
|
|
||||||
riskTools: ["AI 分析", "JSA"],
|
|
||||||
flow: FLOW_SIMPLE.map((n) => ({ ...n, status: "done" as const })),
|
|
||||||
overdueDays: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "MOC-2026-R03-0040",
|
|
||||||
title: "原料环己烷供应商变更(新增 B 供应商)",
|
|
||||||
type: "管理",
|
|
||||||
level: "重要",
|
|
||||||
duration: "永久",
|
|
||||||
urgent: false,
|
|
||||||
status: "实施中",
|
|
||||||
applicant: "刘芳",
|
|
||||||
org: "供应部",
|
|
||||||
device: "原料罐区 / TK-201",
|
|
||||||
date: "2026-07-18",
|
|
||||||
purpose: "引入第二供应商保障原料供应安全,降低单一来源断供风险。",
|
|
||||||
effect: "供应保障能力提升,采购成本预计下降 3%。",
|
|
||||||
before: "环己烷单一供应商 A,纯度 ≥99.5%。",
|
|
||||||
after: "新增供应商 B(纯度 ≥99.8%,已提供 MSDS 与质检报告),双源供应。",
|
|
||||||
related: ["更新合格供应商名录", "修订进厂检验规程", "更新 MSDS 档案", "卸料操作培训"],
|
|
||||||
materials: ["新供应商资质文件", "产品质检报告与 MSDS", "进厂检验规程"],
|
|
||||||
riskTools: ["AI 分析", "检查表法"],
|
|
||||||
flow: FLOW_IMPORTANT.map((n) => ({ ...n, status: "done" as const })),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "MOC-2026-R01-0029",
|
|
||||||
title: "操作规程修订(夏季工况)",
|
|
||||||
type: "管理",
|
|
||||||
level: "一般",
|
|
||||||
duration: "临时",
|
|
||||||
urgent: false,
|
|
||||||
status: "审批中",
|
|
||||||
applicant: "张工艺",
|
|
||||||
org: "一车间 · 工艺组",
|
|
||||||
device: "全装置",
|
|
||||||
date: "2026-06-20",
|
|
||||||
purpose: "夏季高温工况下循环水温度升高,原操作规程冷却参数不适用,需修订夏季操作参数与巡检频次。",
|
|
||||||
effect: "夏季工况下装置运行参数受控,避免超温降负荷,预计减少非计划降量 2 次/年。",
|
|
||||||
before: "操作规程(2025 版)未区分冬夏季工况,冷却参数单一。",
|
|
||||||
after: "增加夏季工况章节:循环水温度 >28℃ 时启用备用冷却塔,巡检频次由 4h 调整为 2h。",
|
|
||||||
related: ["操作规程升版发布", "岗位人员培训"],
|
|
||||||
materials: ["修订后操作规程", "参数核算表"],
|
|
||||||
riskTools: ["AI 分析", "检查表法"],
|
|
||||||
flow: [
|
|
||||||
{ name: "部门审核", kind: "审批", roles: ["dept"], status: "current" },
|
|
||||||
{ name: "专业审批", kind: "审批", roles: ["process"], status: "todo", locked: true },
|
|
||||||
{ name: "部门负责人批准", kind: "最终批准", roles: ["dept"], status: "todo", locked: true },
|
|
||||||
],
|
|
||||||
overdueDays: 3,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "MOC-2026-R02-0041",
|
|
||||||
title: "公用工程氮气减压阀组改造",
|
|
||||||
type: "设备",
|
|
||||||
level: "一般",
|
|
||||||
duration: "永久",
|
|
||||||
urgent: false,
|
|
||||||
status: "审批中",
|
|
||||||
applicant: "周涛",
|
|
||||||
org: "公用工程车间",
|
|
||||||
device: "氮气总管 / PV-208 减压阀组",
|
|
||||||
date: "2026-07-29",
|
|
||||||
purpose: "氮气减压阀组单路运行,检修时需停氮气,影响装置密封气供应,需改造为双路并联。",
|
|
||||||
effect: "减压阀组可在线切换检修,氮气供应连续性提升至 100%。",
|
|
||||||
before: "PV-208 单路减压,无备用回路。",
|
|
||||||
after: "新增并联减压回路 PV-208B,双路一用一备,可在线切换。",
|
|
||||||
related: ["更新 P&ID", "修订氮气系统操作规程", "更新设备台账"],
|
|
||||||
materials: ["阀门数据表", "管道单线图", "施工方案"],
|
|
||||||
riskTools: ["AI 分析", "JSA"],
|
|
||||||
flow: [
|
|
||||||
{ name: "部门审核", kind: "审批", roles: ["dept"], status: "done" },
|
|
||||||
{ name: "专业审批", kind: "审批", roles: ["process"], status: "current" },
|
|
||||||
{ name: "部门负责人批准", kind: "最终批准", roles: ["dept"], status: "todo", locked: true },
|
|
||||||
],
|
|
||||||
overdueDays: 3,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "MOC-2026-R03-0042",
|
|
||||||
title: "三车间自动化和安全隐患整改项目变更",
|
|
||||||
type: "管理",
|
|
||||||
level: "重要",
|
|
||||||
duration: "永久",
|
|
||||||
urgent: false,
|
|
||||||
status: "审批中",
|
|
||||||
applicant: "刘芳",
|
|
||||||
org: "三车间",
|
|
||||||
device: "三车间装置区",
|
|
||||||
date: "2026-07-31",
|
|
||||||
purpose: "落实安全隐患整改要求,对三车间自动化控制系统升级改造,消除加料互串与超温隐患。",
|
|
||||||
effect: "隐患整改闭环率 100%,自动化水平提升,误操作风险显著降低。",
|
|
||||||
before: "加料系统手动控制,存在互串与超温隐患(隐患编号 YH-2026-017)。",
|
|
||||||
after: "改为 DCS 自动控制 + 加料顺序联锁,增设独立超温切断。",
|
|
||||||
related: ["修订操作规程", "DCS 组态修改", "更新 HAZOP 分析", "岗位再培训"],
|
|
||||||
materials: ["隐患整改方案", "HAZOP 分析报告", "联锁因果表"],
|
|
||||||
riskTools: ["AI 分析", "HAZOP"],
|
|
||||||
flow: [
|
|
||||||
{ name: "部门审核", kind: "审批", roles: ["dept"], status: "done" },
|
|
||||||
{
|
|
||||||
name: "专业会签",
|
|
||||||
kind: "会签",
|
|
||||||
roles: ["process", "process2", "quality"],
|
|
||||||
status: "done",
|
|
||||||
members: [
|
|
||||||
{ name: "王仪表(仪表)", done: true },
|
|
||||||
{ name: "周设备(设备)", done: true },
|
|
||||||
{ name: "陈质量(质量)", done: true },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{ name: "安全审查", kind: "审批", roles: ["safety"], status: "done" },
|
|
||||||
{ name: "分管领导最终批准", kind: "最终批准", roles: ["vp"], status: "current" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const progressRow = ref<any>(null);
|
|
||||||
const ledgerAct = ref<{ id: string; act: "withdraw" | "unimpl" | "unuse" } | null>(null);
|
|
||||||
const ledgerReason = ref("");
|
|
||||||
function nowStr() {
|
|
||||||
const d = new Date();
|
|
||||||
const p = (n: number) => String(n).padStart(2, "0");
|
|
||||||
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`;
|
|
||||||
}
|
|
||||||
type DemoListener = () => void;
|
|
||||||
const demoListeners = new Set<DemoListener>();
|
|
||||||
function emitDemo() { demoListeners.forEach((f) => f()); }
|
|
||||||
interface UrgeRecord { id: string; changeId: string; title: string; applicant: string; by: string; time: string; }
|
|
||||||
let urgeSeq = 1;
|
|
||||||
const URGE_RECORDS: UrgeRecord[] = [];
|
|
||||||
const ROLES = [
|
|
||||||
{ id: "applicant", name: "申请人", person: "张工艺", org: "一车间 · 工艺组", desc: "发起变更申请、AI 辅助判定、跟踪进度" },
|
|
||||||
{ id: "process", name: "专业会签(仪表)", person: "王仪表", org: "技术部 · 仪表科", desc: "专业会签、HAZOP 分析、确认连带变更" },
|
|
||||||
{ id: "process2", name: "专业会签(设备)", person: "周设备", org: "设备管理部 · 设备科", desc: "专业会签、设备完整性检查、行动项落实" },
|
|
||||||
{ id: "safety", name: "安全工程师", person: "王海燕", org: "安全环保部", desc: "安全审查、PSSR 检查表确认、风险分析组织" },
|
|
||||||
{ id: "dept", name: "车间主任", person: "李主任", org: "一车间", desc: "部门审核、现场验收、变更关闭确认" },
|
|
||||||
{ id: "vp", name: "分管领导", person: "刘副总", org: "公司领导", desc: "重要变更最终批准、移动端审批" },
|
|
||||||
{ id: "admin", name: "系统管理员", person: "刘敏", org: "信息化部", desc: "流程配置、字典维护、权限分配" },
|
|
||||||
{ id: "quality", name: "质量工程师", person: "陈质量", org: "质量部", desc: "质量会签、产品合格判定、检验方案确认" },
|
|
||||||
{ id: "viewer", name: "非审批人员", person: "吴新", org: "相关部门", desc: "以信息查看为主,不参与变更流程" },
|
|
||||||
];
|
|
||||||
function urgeChange(changeId: string, byRole: string) {
|
|
||||||
const row = LEDGER_ROWS.find((r) => r.id === changeId || r.changeId === changeId);
|
|
||||||
const c = CHANGES.find((x) => x.id === changeId);
|
|
||||||
const by = ROLES.find((r:any) => r.id === byRole)?.person ?? byRole;
|
|
||||||
URGE_RECORDS.unshift({
|
|
||||||
id: `URGE-${urgeSeq++}`,
|
|
||||||
changeId,
|
|
||||||
title: row?.title ?? c?.title ?? changeId,
|
|
||||||
applicant: row?.applicant ?? c?.applicant ?? "",
|
|
||||||
by,
|
|
||||||
time: nowStr(),
|
|
||||||
});
|
|
||||||
emitDemo();
|
|
||||||
}
|
|
||||||
|
|
||||||
const stages = ["提交申请", "审批", "实施与投用前确认", "投用", "验收", "关闭"];
|
|
||||||
const curIdx = computed(() => ({ 审批中: 1, 已批准: 2, 实施中: 2, 待PSSR: 2, 待验收: 4, 待关闭: 5, 已关闭: 6 } as Record<string, number>)[progressRow.value?.status ?? ""] ?? 1);
|
|
||||||
const closed = computed(() => progressRow.value?.status === "已关闭");
|
|
||||||
const timeOf = (i: number) => (i === 0 ? progressRow.value?.applyTime : i === 3 ? progressRow.value?.actualUse : i === 5 ? progressRow.value?.closeTime : undefined);
|
|
||||||
|
|
||||||
const role = ref<string>("applicant");
|
|
||||||
const doOp = (r: any, act: string) => {
|
|
||||||
if (act === "detail") {
|
|
||||||
const c = CHANGES.find((x) => x.id === r.changeId);
|
|
||||||
if (c) {
|
|
||||||
// 跳转详情页面
|
|
||||||
// emit("openChange", c);
|
|
||||||
}else {
|
|
||||||
window.$message?.info(`演示:打开变更详情页 ${r.id}`);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (act === "progress") {
|
|
||||||
progressRow.value = r;
|
|
||||||
progressDrawer.value = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (act === "withdraw" || act === "unimpl" || act === "unuse") {
|
|
||||||
ledgerAct.value = { id: r.id, act };
|
|
||||||
ledgerReason.value = "";
|
|
||||||
revokeModal.value = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (act === "urge") {
|
|
||||||
urgeChange(r.id, role.value ?? "dept");
|
|
||||||
window.$message?.success(`已催办 ${r.id} 申请人 ${r.applicant}(系统消息 + 企业微信),催办记录已留痕并抄送变更主管部门,申请人操作台将出现催办提示`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
window.$message?.info(`演示:下载 ${r.id} 变更申请表 / 归档包(PDF)`);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 撤回弹框取消
|
|
||||||
const revokeCancel = () => {
|
|
||||||
ledgerAct.value = null;
|
|
||||||
ledgerReason.value = "";
|
|
||||||
revokeModal.value = false;
|
|
||||||
}
|
|
||||||
// 撤回弹框提交
|
|
||||||
const revokeSave = () => {
|
|
||||||
if (!ledgerReason.value) {
|
|
||||||
window.$message?.warning("请输入撤回理由");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
window.$message?.success(ledgerAct.value?.act === 'withdraw' ? `已撤回 ${ledgerAct.value?.id},申请退回草稿箱,审批记录保留可查` : `${ledgerAct.value?.id} 情况说明已提交,变更转入关闭流程(主管部门确认后记录关闭时间)`);
|
|
||||||
revokeCancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
const loading = ref<boolean>(false);
|
const loading = ref<boolean>(false);
|
||||||
|
// 组织树
|
||||||
|
const orgTree = ref<any[]>([]);
|
||||||
// 筛选条件
|
// 筛选条件
|
||||||
const formInfo = ref<any>({
|
const formInfo = ref<any>({
|
||||||
kw: '',
|
kw: '',
|
||||||
@@ -459,14 +37,14 @@ const typeList = ref<any[]>([{ label: "全部", value: null }]);
|
|||||||
const levelList = ref<any[]>([{ label: "全部", value: null }]);
|
const levelList = ref<any[]>([{ label: "全部", value: null }]);
|
||||||
// 状态选项
|
// 状态选项
|
||||||
const STATUS_OPTIONS = [
|
const STATUS_OPTIONS = [
|
||||||
{ label: "全部", value: "" },
|
{ label: "全部", value: "", type:'all' },
|
||||||
{ label: "审批中", value: "APPROVING" },
|
{ label: "审批中", value: "APPROVING", type:'warning' },
|
||||||
{ label: "待实施", value: "APPROVED" },
|
{ label: "已通过", value: "APPROVED", type:'success' },
|
||||||
{ label: "待验收", value: "IMPLEMENTED" },
|
{ label: "待验收", value: "IMPLEMENTED", type:'success' },
|
||||||
{ label: "待关闭", value: "ACCEPTED" },
|
{ label: "待关闭", value: "ACCEPTED", type:'error' },
|
||||||
{ label: "已关闭", value: "CLOSED" },
|
{ label: "已关闭", value: "CLOSED", type:'success' },
|
||||||
{ label: "已撤回", value: "WITHDRAWN" },
|
{ label: "已撤回", value: "WITHDRAWN", type:'error' },
|
||||||
{ label: "已驳回", value: "REJECTED" },
|
{ label: "已驳回", value: "REJECTED", type:'error' },
|
||||||
];
|
];
|
||||||
// 排序选项
|
// 排序选项
|
||||||
const SORT_OPTS = [
|
const SORT_OPTS = [
|
||||||
@@ -495,7 +73,15 @@ const TIME_OPTIONS = [
|
|||||||
const period = ref<string>("year");
|
const period = ref<string>("year");
|
||||||
// 是否显示全部
|
// 是否显示全部
|
||||||
const isAll = ref<boolean>(true);
|
const isAll = ref<boolean>(true);
|
||||||
|
// 当前选中行
|
||||||
|
const currentRow = ref<any>(null);
|
||||||
|
// 进度抽屉
|
||||||
|
const progressDrawer = ref<boolean>(false);
|
||||||
|
// 撤回/未实施情况说明弹框
|
||||||
|
const revokeModal = ref<boolean>(false);
|
||||||
|
const modalType = ref<string>('');
|
||||||
|
const reason = ref<string>('');
|
||||||
|
const revokeSaving = ref<boolean>(false);
|
||||||
// 列表
|
// 列表
|
||||||
const list = ref<any[]>([]);
|
const list = ref<any[]>([]);
|
||||||
|
|
||||||
@@ -516,6 +102,35 @@ const exportChanges = () => {
|
|||||||
window.$message?.info('还差接口');
|
window.$message?.info('还差接口');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 自定义渲染展开图标
|
||||||
|
const renderSwitcherIcon = (node:any) => {
|
||||||
|
// 如果节点没有 children 或 children 为空数组,则不显示图标
|
||||||
|
if (!node.option.children || node.option.children.length === 0) {
|
||||||
|
return null; // 返回 null 表示不渲染任何图标
|
||||||
|
}
|
||||||
|
// 有子节点:返回 undefined 表示使用默认展开图标,也可自定义
|
||||||
|
return h(Icon,{
|
||||||
|
icon: node.option.expanded ? 'bi:caret-down-fill' : 'bi:caret-right-fill',
|
||||||
|
class: 'size-12px',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 匹配对象
|
||||||
|
const matchObj= (list:any[],val:any) => {
|
||||||
|
const item = list.find((item:any) => item.value == val);
|
||||||
|
return item || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索
|
||||||
|
const searchHandle = () => {
|
||||||
|
pagination.value.page = 1;
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
// 组织选择改变
|
||||||
|
const orgChange = (val:any) => {
|
||||||
|
formInfo.value.org_id = val;
|
||||||
|
searchHandle();
|
||||||
|
}
|
||||||
// 显示全部改变
|
// 显示全部改变
|
||||||
const showAll = () => {
|
const showAll = () => {
|
||||||
isAll.value = !isAll.value;
|
isAll.value = !isAll.value;
|
||||||
@@ -524,39 +139,80 @@ const showAll = () => {
|
|||||||
}else{
|
}else{
|
||||||
formInfo.value.status = 'APPROVING,APPROVED,IMPLEMENTED,ACCEPTED,WITHDRAWN,REJECTED';
|
formInfo.value.status = 'APPROVING,APPROVED,IMPLEMENTED,ACCEPTED,WITHDRAWN,REJECTED';
|
||||||
}
|
}
|
||||||
pagination.value.page = 1;
|
searchHandle();
|
||||||
getList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 类型选择
|
// 类型选择
|
||||||
const typeChoose = (val:any) => {
|
const typeChoose = (val:any) => {
|
||||||
formInfo.value.type = val;
|
formInfo.value.type = val;
|
||||||
pagination.value.page = 1;
|
searchHandle();
|
||||||
getList();
|
|
||||||
}
|
}
|
||||||
// 时限选择
|
// 时限选择
|
||||||
const durChoose = (val:any) => {
|
const durChoose = (val:any) => {
|
||||||
formInfo.value.duration = val;
|
formInfo.value.duration = val;
|
||||||
pagination.value.page = 1;
|
searchHandle();
|
||||||
getList();
|
|
||||||
}
|
}
|
||||||
// 时间范围选择
|
// 时间范围选择
|
||||||
const timeChoose = (val:string) => {
|
const timeChoose = (val:string) => {
|
||||||
period.value = val;
|
period.value = val;
|
||||||
pagination.value.page = 1;
|
searchHandle();
|
||||||
getList();
|
|
||||||
}
|
}
|
||||||
// 状态选择
|
// 状态选择
|
||||||
const statusChoose = (val:string) => {
|
const statusChoose = (val:string) => {
|
||||||
formInfo.value.status = val;
|
formInfo.value.status = val;
|
||||||
pagination.value.page = 1;
|
searchHandle();
|
||||||
getList();
|
|
||||||
}
|
}
|
||||||
// 排序选择
|
// 排序选择
|
||||||
const sortChoose = (val:string) => {
|
const sortChoose = (val:string) => {
|
||||||
formInfo.value.sort = val;
|
formInfo.value.sort = val;
|
||||||
pagination.value.page = 1;
|
searchHandle();
|
||||||
getList();
|
}
|
||||||
|
|
||||||
|
// 跳转详情
|
||||||
|
const jumpTo = (r:any) => {
|
||||||
|
routerPushByKey("details_index",{ query: { id: r?.id?.toString(),status:r?.status?.toString() || '',key:'changeledger_mychanges' } });
|
||||||
|
}
|
||||||
|
// 打开进度
|
||||||
|
const openProgress = (r: any) => {
|
||||||
|
currentRow.value = r;
|
||||||
|
progressDrawer.value = true;
|
||||||
|
};
|
||||||
|
// 撤回/未实施情况说明
|
||||||
|
const openModal = (r: any,type:string) => {
|
||||||
|
currentRow.value = r;
|
||||||
|
modalType.value = type;
|
||||||
|
revokeModal.value = true;
|
||||||
|
}
|
||||||
|
// 撤回/未实施情况说明提交
|
||||||
|
const revokeSave = async () => {
|
||||||
|
if (!reason.value) {
|
||||||
|
return window.$message?.warning(modalType.value === "withdraw" ? "请输入撤回理由" : "请输入未实施情况说明");
|
||||||
|
}
|
||||||
|
revokeSaving.value = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
revokeSaving.value = false;
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下载文件
|
||||||
|
const downloadFiles = (r:any,type:string) => {
|
||||||
|
// 下载申请表
|
||||||
|
if(type==='apply'){
|
||||||
|
|
||||||
|
}
|
||||||
|
// 下载已验收待关闭
|
||||||
|
if(type==='accepted'){
|
||||||
|
|
||||||
|
}
|
||||||
|
// 下载归档包
|
||||||
|
if(type==='closed'){
|
||||||
|
|
||||||
|
}
|
||||||
|
window.$message?.info('还差接口');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 催办
|
||||||
|
const urge = (r:any) => {
|
||||||
|
window.$message?.info('还差接口');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分页改变
|
// 分页改变
|
||||||
@@ -581,7 +237,6 @@ const getList = async () => {
|
|||||||
page_size: pagination.value.pageSize,
|
page_size: pagination.value.pageSize,
|
||||||
});
|
});
|
||||||
if (!error) {
|
if (!error) {
|
||||||
console.log(data)
|
|
||||||
list.value = data?.list ?? [];
|
list.value = data?.list ?? [];
|
||||||
pagination.value.itemCount = data?.total ?? 0;
|
pagination.value.itemCount = data?.total ?? 0;
|
||||||
}
|
}
|
||||||
@@ -604,9 +259,22 @@ const getConfig = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
// // 获取组织列表
|
||||||
getConfig();
|
const getOrgList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const {data,error} = await orgListApi();
|
||||||
|
if(!error){
|
||||||
|
orgTree.value = data;
|
||||||
|
if(orgTree.value.length > 0){
|
||||||
getList();
|
getList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await getConfig();
|
||||||
|
getOrgList();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -622,10 +290,20 @@ onMounted(() => {
|
|||||||
>
|
>
|
||||||
<span class="flex items-center gap-1.5 text-sm font-semibold text-slate-700">
|
<span class="flex items-center gap-1.5 text-sm font-semibold text-slate-700">
|
||||||
<Icon icon="akar-icons:file" class="size-16px" :style="{ color: themeStore.themeColor }" /> 全部变更
|
<Icon icon="akar-icons:file" class="size-16px" :style="{ color: themeStore.themeColor }" /> 全部变更
|
||||||
<span class="rounded bg-slate-100 px-1.5 text-xs text-slate-500">{{ finalRows.length }}</span>
|
<span class="rounded bg-slate-100 px-1.5 text-xs text-slate-500">{{ pagination.itemCount }}</span>
|
||||||
</span>
|
</span>
|
||||||
<NSelect size="small" class="!w-32" :value="formInfo.org_id" :options="deptOpts" @update:value="(v: string) => formInfo.org_id = v" />
|
<NTreeSelect
|
||||||
|
class="!w-200px"
|
||||||
|
:value="formInfo.org_id"
|
||||||
|
:options="orgTree"
|
||||||
|
size="small"
|
||||||
|
default-expand-all
|
||||||
|
label-field="label"
|
||||||
|
key-field="id"
|
||||||
|
:render-switcher-icon="renderSwitcherIcon"
|
||||||
|
placeholder="请选择组织层级"
|
||||||
|
@update:value="orgChange"
|
||||||
|
/>
|
||||||
<NRadio
|
<NRadio
|
||||||
size="small"
|
size="small"
|
||||||
:checked="isAll"
|
:checked="isAll"
|
||||||
@@ -645,9 +323,9 @@ onMounted(() => {
|
|||||||
显示未关闭
|
显示未关闭
|
||||||
</NRadio>
|
</NRadio>
|
||||||
<div class="relative ml-auto">
|
<div class="relative ml-auto">
|
||||||
<NInput v-model:value="kw" size="small" type="text" clearable placeholder="搜索变更名称 / 编号">
|
<NInput v-model:value="formInfo.kw" size="small" type="text" clearable placeholder="搜索变更名称 / 编号" @clear="searchHandle">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<Icon icon="akar-icons:search" class="size-14px text-slate-400 cursor-pointer" />
|
<Icon icon="akar-icons:search" class="size-14px text-slate-400 cursor-pointer" @click="searchHandle" />
|
||||||
</template>
|
</template>
|
||||||
</NInput>
|
</NInput>
|
||||||
</div>
|
</div>
|
||||||
@@ -695,52 +373,95 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="space-y-3 scroll">
|
<div class="space-y-3 scroll">
|
||||||
<!-- 列表 -->
|
<!-- 列表 -->
|
||||||
<div v-for="(r, i) in finalRows" :key="r.id" class="rounded-lg border bg-white px-4 py-3">
|
<div
|
||||||
|
v-for="(r, i) in list" :key="r.id"
|
||||||
|
class="rounded-lg border bg-white px-4 py-3"
|
||||||
|
:style="{
|
||||||
|
'--theme-color': themeStore.themeColor
|
||||||
|
}"
|
||||||
|
>
|
||||||
<div class="flex flex-wrap items-start gap-3">
|
<div class="flex flex-wrap items-start gap-3">
|
||||||
<div class="min-w-0 flex-1">
|
<div class="min-w-0 flex-1">
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
<span class="text-xs text-slate-300">{{ String(i + 1).padStart(2, '0') }}</span>
|
<span class="text-xs text-slate-300">{{ Number(i)+1 }}</span>
|
||||||
<NButton text class="text-left text-sm font-semibold text-slate-800 hover:text-[#1D4E9C] hover:underline" @click="doOp(r, 'detail')">{{ r.title }}</NButton>
|
<p class="cursor-pointer text-left text-sm font-semibold text-slate-800 hover:text-[var(--theme-color)] hover:underline" @click="jumpTo(r)">
|
||||||
|
{{ r.title }}
|
||||||
|
</p>
|
||||||
<NTag size="small" v-if="r.urgent" class="animate-breathe border-[#E15555] bg-[#E15555] text-white">紧急</NTag>
|
<NTag size="small" v-if="r.urgent" class="animate-breathe border-[#E15555] bg-[#E15555] text-white">紧急</NTag>
|
||||||
<span class="font-mono text-[11px] text-slate-400">{{ r.id }}</span>
|
<span class="font-mono text-[11px] text-slate-400">{{ r.change_no }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-1.5 flex flex-wrap items-center gap-1.5">
|
<div class="mt-1.5 flex flex-wrap items-center gap-1.5">
|
||||||
<NTag size="small" class="border-slate-200 bg-white text-slate-600">{{ r.type }}</NTag>
|
<!-- 类型 -->
|
||||||
<NTag size="small" :class="r.level === '重要' ? 'border-red-200 bg-red-100 text-red-700' : 'border-slate-200 bg-slate-100 text-slate-600'">{{ r.level }}</NTag>
|
<NTag
|
||||||
<NTag size="small" :class="r.duration === '临时' ? 'border-[#FAAD14] bg-[#FAAD14] text-white' : 'border-[#1D4E9C] bg-[#1D4E9C] text-white'">{{ r.duration }}</NTag>
|
size="small"
|
||||||
<NTag size="small" v-for="s in LEDGER_EXTRA[r.id]?.special ?? []" :key="s" :class="SPECIAL_COLOR[s]">{{ s }}</NTag>
|
:color="{
|
||||||
|
color: tagBgColor(matchObj(typeList,r.change_type)?.color),
|
||||||
|
textColor: tagTextColor(matchObj(typeList,r.change_type)?.color),
|
||||||
|
borderColor: tagBorderColor(matchObj(typeList,r.change_type)?.color),
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ matchObj(typeList,r.change_type)?.label }}
|
||||||
|
</NTag>
|
||||||
|
<!-- 等级 -->
|
||||||
|
<NTag
|
||||||
|
size="small"
|
||||||
|
:color="{
|
||||||
|
color: tagBgColor(matchObj(levelList,r.change_level)?.color),
|
||||||
|
textColor: tagTextColor(matchObj(levelList,r.change_level)?.color),
|
||||||
|
borderColor: tagBorderColor(matchObj(levelList,r.change_level)?.color),
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ matchObj(levelList,r.change_level)?.label }}
|
||||||
|
</NTag>
|
||||||
|
<NTag v-if="r.duration_type===2" size="small" type="warning">临时</NTag>
|
||||||
|
<NTag v-if="r.duration_type===1" size="small" type="info">永久</NTag>
|
||||||
|
<NTag v-if="r.extend_count" size="small" type="warning">延期</NTag>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-1.5 flex flex-wrap gap-x-4 gap-y-0.5 text-[11px] text-slate-500">
|
<div class="mt-1.5 flex flex-wrap gap-x-4 gap-y-0.5 text-[11px] text-slate-500">
|
||||||
<span>申请 {{ r.applyTime }}</span>
|
<span v-if="r.apply_time">申请 {{ r.apply_time?.slice(0,16) }}</span>
|
||||||
<span>{{ r.dept }} · {{ r.applicant }}</span>
|
<span>{{ r.org_name }} · {{ r.applicant_name }}</span>
|
||||||
<span>计划投用 {{ r.planUse }}</span>
|
<span v-if="r.plan_use_date">计划投用 {{ r.plan_use_date?.slice(0,16) }}</span>
|
||||||
<span v-if="LEDGER_EXTRA[r.id]?.actualUse">实际投用 {{ LEDGER_EXTRA[r.id].actualUse }}</span>
|
<span v-if="r.use_time">实际投用 {{ r.use_time?.slice(0,16) }}</span>
|
||||||
<span v-if="LEDGER_EXTRA[r.id]?.planRestore">计划恢复 {{ LEDGER_EXTRA[r.id].planRestore }}</span>
|
<span v-if="r.restore_deadline">计划恢复 {{ r.restore_deadline?.slice(0,16) }}</span>
|
||||||
<span v-if="LEDGER_EXTRA[r.id]?.extRestore" class="text-amber-600">延期后恢复 {{ LEDGER_EXTRA[r.id].extRestore }}</span>
|
<span v-if="r.close_time">关闭 {{ r.close_time?.slice(0,16) }}</span>
|
||||||
<span v-if="LEDGER_EXTRA[r.id]?.closeTime">关闭 {{ LEDGER_EXTRA[r.id].closeTime }}</span>
|
<span v-if="r.status_changed_at">状态更新 {{ r.status_changed_at?.slice(0,16) }}</span>
|
||||||
<span>状态更新 {{ r.statusTime }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex shrink-0 flex-col items-end gap-1.5">
|
<div class="flex shrink-0 flex-col items-end gap-1.5">
|
||||||
<div class="flex flex-wrap items-center justify-end gap-2">
|
<div class="flex flex-wrap items-center justify-end gap-2">
|
||||||
<span class="text-[11px] text-slate-400">{{ r.statusDetail }}</span>
|
<!-- 状态标签 -->
|
||||||
<NTag size="small" :class="STATUS_COLOR[r.status]">{{ r.status }}</NTag>
|
<NTag v-if="r.status==='APPROVING'" size="small" type="warning">审批中</NTag>
|
||||||
<span v-if="r.overdueDays" class="text-[11px] font-medium text-red-500">超期 {{ r.overdueDays }} 天</span>
|
<NTag v-if="r.status==='APPROVED'" size="small" type="success">已通过</NTag>
|
||||||
|
<NTag v-if="r.status==='IMPLEMENTED'" size="small" type="success">待验收</NTag>
|
||||||
|
<NTag v-if="r.status==='ACCEPTED'" size="small" type="error">待关闭</NTag>
|
||||||
|
<NTag v-if="r.status==='CLOSED'" size="small" type="success">已关闭</NTag>
|
||||||
|
<NTag v-if="r.status==='WITHDRAWN'" size="small" type="error">已撤回</NTag>
|
||||||
|
<NTag v-if="r.status==='REJECTED'" size="small" type="error">已驳回</NTag>
|
||||||
|
<!-- 超期 -->
|
||||||
|
<span v-if="r.overdue_status===2" class="text-[11px] font-medium text-red-500">超期 {{ r.overdue_days }} 天</span>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 操作按钮 -->
|
||||||
<div class="flex flex-wrap items-center justify-end gap-1 pt-0.5">
|
<div class="flex flex-wrap items-center justify-end gap-1 pt-0.5">
|
||||||
<NButton size="small" v-for="op in opsOf(r, me, role)" :key="op.label"
|
<!-- 审批中 -->
|
||||||
class="text-xs"
|
<NButton v-if="r.status==='APPROVING'" size="small" ghost type="error" class="text-xs" @click="openModal(r,'withdraw')">撤回</NButton>
|
||||||
:ghost="op.act === 'detail' ? false : true"
|
<!-- 已批准待实施 -->
|
||||||
:type="op.act === 'detail' ? 'primary' : op.danger ? 'error' : 'default'"
|
<NButton v-if="r.status==='APPROVED'" size="small" ghost type="primary" class="text-xs" @click="openModal(r,'unimplemented')">未实施情况说明</NButton>
|
||||||
@click="doOp(r, op.act)">
|
<NButton v-if="r.status==='APPROVED'" size="small" ghost type="primary" class="text-xs" @click="downloadFiles(r,'apply')">下载申请表</NButton>
|
||||||
{{ op.label }}
|
<!-- 已验收待关闭 -->
|
||||||
</NButton>
|
<NButton v-if="r.status==='ACCEPTED'" size="small" ghost type="error" class="text-xs" @click="downloadFiles(r,'accepted')">下载</NButton>
|
||||||
|
<!-- 已关闭 -->
|
||||||
|
<NButton v-if="r.status==='CLOSED'" size="small" ghost type="success" class="text-xs" @click="downloadFiles(r,'closed')">下载归档包</NButton>
|
||||||
|
<!-- 催办(超期) -->
|
||||||
|
<NButton v-if="r.overdue_days" size="small" ghost type="error" class="text-xs" @click="urge(r)">催办</NButton>
|
||||||
|
<NButton size="small" type="primary" class="text-xs" @click="jumpTo(r)">详情</NButton>
|
||||||
|
<NButton size="small" type="default" class="text-xs" @click="openProgress(r)">进度</NButton>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="r.duration === '临时'" class="text-right text-[10px] leading-4 text-slate-400">临时变更恢复 / 延期 / 转永久请在详情页中操作</div>
|
<!-- 临时变更 -->
|
||||||
|
<div v-if="r.duration_type === 2" class="text-right text-[10px] leading-4 text-slate-400">临时变更恢复 / 延期 / 转永久请在详情页中操作</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="finalRows.length === 0" class="rounded-lg border border-dashed bg-white py-12 text-center text-sm text-slate-400">当前筛选条件下暂无变更记录</div>
|
<div v-if="list.length === 0" class="rounded-lg border border-dashed bg-white py-12 text-center text-sm text-slate-400">当前筛选条件下暂无变更记录</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end mt-3">
|
<div class="flex justify-end mt-3">
|
||||||
<NPagination
|
<NPagination
|
||||||
@@ -764,73 +485,72 @@ onMounted(() => {
|
|||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<h3 class="text-sm font-bold text-slate-800">
|
<h3 class="text-sm font-bold text-slate-800">
|
||||||
<span v-if="ledgerAct?.act === 'withdraw'">撤回变更申请</span>
|
<span v-if="modalType === 'withdraw'">撤回变更申请</span>
|
||||||
<span v-else-if="ledgerAct?.act === 'unuse'">未投用情况说明</span>
|
<span v-else-if="modalType === 'unuse'">未投用情况说明</span>
|
||||||
<span v-else>未实施情况说明</span>
|
<span v-else>未实施情况说明</span>
|
||||||
{{ledgerAct?.id}}
|
{{currentRow?.change_no}}
|
||||||
</h3>
|
</h3>
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
<div class="rounded-lg bg-slate-50 px-3 py-2 text-xs leading-5 text-slate-500">
|
<div class="rounded-lg bg-slate-50 px-3 py-2 text-xs leading-5 text-slate-500">
|
||||||
{{ ledgerAct?.act === 'withdraw'
|
{{ modalType === 'withdraw'
|
||||||
? '撤回后申请退回草稿状态,已产生的审批记录保留可查;修改内容后可重新提交。仅本人发起的审批中变更可撤回。'
|
? '撤回后申请退回草稿状态,已产生的审批记录保留可查;修改内容后可重新提交。仅本人发起的审批中变更可撤回。'
|
||||||
: '变更审批通过 / 投用后未实施或未投用的,由申请人填写情况说明,提交后变更转入关闭流程,由变更主管部门专责确认关闭并记录关闭时间。' }}
|
: '变更审批通过 / 投用后未实施或未投用的,由申请人填写情况说明,提交后变更转入关闭流程,由变更主管部门专责确认关闭并记录关闭时间。' }}
|
||||||
</div>
|
</div>
|
||||||
<NInput
|
<NInput
|
||||||
class="mt-3"
|
class="mt-3"
|
||||||
v-model:value="ledgerReason"
|
v-model:value="reason"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
:rows="3"
|
:rows="3"
|
||||||
:placeholder="ledgerAct?.act === 'withdraw' ? '撤回理由(必填)…' : '情况说明(必填):原因、现场当前状态、后续处置安排…'"
|
:placeholder="modalType === 'withdraw' ? '撤回理由(必填)…' : '情况说明(必填):原因、现场当前状态、后续处置安排…'"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="flex justify-end gap-[10px]">
|
<div class="flex justify-end gap-[10px]">
|
||||||
<NButton size="small" @click="revokeCancel">取消</NButton>
|
<NButton size="small" @click="revokeModal = false">取消</NButton>
|
||||||
<NButton size="small" type="primary" :loading="revokeSaving" @click="revokeSave">提交</NButton>
|
<NButton size="small" type="primary" :loading="revokeSaving" @click="revokeSave">提交</NButton>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</NModal>
|
</NModal>
|
||||||
<!-- 进度抽屉 -->
|
<!-- 进度弹框 -->
|
||||||
<NDrawer v-model:show="progressDrawer" :width="502" placement="right">
|
<NDrawer v-model:show="progressDrawer" :width="502" placement="right">
|
||||||
<NDrawerContent title="变更进度">
|
<NDrawerContent title="变更进度">
|
||||||
<div class="rounded-lg border bg-slate-50/60 px-3 py-2.5">
|
<div class="rounded-lg border bg-slate-50/60 px-3 py-2.5">
|
||||||
<div class="text-sm font-semibold text-slate-800">{{ progressRow?.title }}</div>
|
<div class="text-sm font-semibold text-slate-800">{{ currentRow?.title }}</div>
|
||||||
<div class="mt-1.5 flex flex-wrap items-center gap-1.5 text-[11px] text-slate-400">
|
<div class="mt-1.5 flex flex-wrap items-center gap-1.5 text-[11px] text-slate-400">
|
||||||
<span class="font-mono">{{ progressRow?.id }}</span>
|
<span class="font-mono">{{ currentRow?.change_no }}</span>
|
||||||
<NTag v-if="progressRow?.status==='审批中'" size="small" type="warning">{{progressRow.status}}</NTag>
|
<NTag v-if="currentRow?.status==='APPROVING'" size="small" type="warning">审批中</NTag>
|
||||||
<NTag v-if="progressRow?.status==='已批准'" size="small" type="primary">{{progressRow.status}}</NTag>
|
<NTag v-if="currentRow?.status==='APPROVED'" size="small" type="success">已通过</NTag>
|
||||||
<NTag v-if="progressRow?.status==='待验收'" size="small" type="success">{{progressRow.status}}</NTag>
|
<NTag v-if="currentRow?.status==='IMPLEMENTED'" size="small" type="warning">待验收</NTag>
|
||||||
<NTag v-if="progressRow?.status==='待关闭'" size="small" type="error">{{progressRow.status}}</NTag>
|
<NTag v-if="currentRow?.status==='ACCEPTED'" size="small" type="error">待关闭</NTag>
|
||||||
<span v-if="progressRow?.overdue" class="font-medium text-red-500">超期 {{ progressRow?.day }} 天</span>
|
<NTag v-if="currentRow?.status==='CLOSED'" size="small" type="error">已关闭</NTag>
|
||||||
|
<NTag v-if="currentRow?.status==='WITHDRAWN'" size="small" type="error">已撤回</NTag>
|
||||||
|
<NTag v-if="currentRow?.status==='REJECTED'" size="small" type="error">已驳回</NTag>
|
||||||
|
<span v-if="currentRow?.overdue_status===2" class="font-medium text-red-500">超期 {{ currentRow?.overdue_days }} 天</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="progressRow?.dept || progressRow?.applicant" class="mt-1 text-[11px] text-slate-400">{{ [progressRow?.dept, progressRow?.applicant].filter(Boolean).join(' · ') }}</div>
|
<div v-if="currentRow?.dept || currentRow?.applicant" class="mt-1 text-[11px] text-slate-400">{{ [currentRow?.dept, currentRow?.applicant].filter(Boolean).join(' · ') }}</div>
|
||||||
<div v-if="progressRow?.meta" class="mt-1 text-[11px] text-slate-400">{{ progressRow?.meta }}</div>
|
<div v-if="currentRow?.meta" class="mt-1 text-[11px] text-slate-400">{{ currentRow?.meta }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<div v-for="(s, i) in stages" :key="s" class="flex gap-3">
|
<div v-for="(s, i) in currentRow?.approval_records" :key="s.id" class="flex gap-3">
|
||||||
<div class="flex flex-col items-center">
|
<div class="flex flex-col items-center">
|
||||||
<span class="flex h-6 w-6 shrink-0 items-center justify-center rounded-full border-2"
|
<span class="flex h-6 w-6 shrink-0 items-center justify-center rounded-full border-2 border-[#7CC242] bg-[#7CC242] text-white">
|
||||||
:class="i < curIdx || closed ? 'border-[#7CC242] bg-[#7CC242] text-white' : i === curIdx && !closed ? 'border-[#1D4E9C] bg-[#1D4E9C] text-white' : 'border-slate-200 bg-white text-slate-300'">
|
<Icon icon="ix:success" />
|
||||||
<Icon v-if="i < curIdx || closed" icon="ix:success" />
|
|
||||||
<Icon v-else-if="i === curIdx" icon="tabler:clock" />
|
|
||||||
<span v-else class="text-[10px]">{{ i + 1 }}</span>
|
|
||||||
</span>
|
</span>
|
||||||
<span v-if="i < stages.length - 1" class="w-0.5 flex-1" :class="i < curIdx ? 'bg-[#7CC242]' : 'bg-slate-200'" />
|
<span
|
||||||
|
v-if="Number(i) < Number(currentRow?.approval_records?.length) - 1"
|
||||||
|
class="w-0.5 flex-1"
|
||||||
|
:class="Number(i) < Number(currentRow?.approval_records?.length) ? 'bg-[#7CC242]' : 'bg-slate-200'"
|
||||||
|
></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="pb-5">
|
<div class="pb-5">
|
||||||
<div class="text-sm" :class="i === curIdx && !closed ? 'font-semibold text-[#1D4E9C]' : i < curIdx || closed ? 'font-medium text-slate-700' : 'text-slate-400'">
|
<p class="text-sm">{{ s.action }}</p>
|
||||||
{{ s }}{{ i === curIdx && !closed ? '(当前)' : '' }}
|
<span class="mt-0.5 text-[11px] text-slate-400">{{s.finished_at?.slice(0, 16)}}</span>
|
||||||
</div>
|
|
||||||
<div v-if="timeOf(i)" class="mt-0.5 text-[11px] text-slate-400">{{ timeOf(i) }}</div>
|
|
||||||
<div v-if="i === curIdx && !closed && (progressRow?.detail || progressRow?.updateTime)" class="mt-0.5 text-[11px] text-slate-400">
|
|
||||||
{{ [progressRow?.detail, progressRow?.updateTime ? `更新 ${progressRow?.updateTime}` : ''].filter(Boolean).join(' · ') }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div v-if="currentRow?.duration_type === 2" class="rounded-lg border border-amber-200 bg-amber-50/50 px-3 py-2 text-[11px] leading-5 text-amber-700">
|
||||||
<div v-if="progressRow?.dur === '临时'" class="rounded-lg border border-amber-200 bg-amber-50/50 px-3 py-2 text-[11px] leading-5 text-amber-700">
|
临时变更:计划恢复 {{ currentRow?.restore_deadline ?? '—' }} · 恢复 / 延期 / 转永久请在详情页中操作
|
||||||
临时变更:计划恢复 {{ progressRow?.deadline ?? '—' }}{{ progressRow?.extended ? ` · 延期后恢复 ${progressRow?.deadline}` : '' }} · 恢复 / 延期 / 转永久请在详情页中操作
|
|
||||||
</div>
|
</div>
|
||||||
</NDrawerContent>
|
</NDrawerContent>
|
||||||
</NDrawer>
|
</NDrawer>
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ const { routerPushByKey } = useRouterPush();
|
|||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
const loading = ref<boolean>(false);
|
const loading = ref<boolean>(false);
|
||||||
|
// 返回键
|
||||||
|
const backKey = ref<string>('');
|
||||||
// 判定说明
|
// 判定说明
|
||||||
const typeAiLoading = ref<boolean>(false);
|
const typeAiLoading = ref<boolean>(false);
|
||||||
const typeAi = ref<{ type: string; confidence: number; conclusion: string; hit_rules: string[]; exclude_rules: string[]; knowledge_refs: string[] } | null>(null);
|
const typeAi = ref<{ type: string; confidence: number; conclusion: string; hit_rules: string[]; exclude_rules: string[]; knowledge_refs: string[] } | null>(null);
|
||||||
@@ -233,7 +235,7 @@ const openTypeSheet = async () => {
|
|||||||
|
|
||||||
// 返回
|
// 返回
|
||||||
const back = () => {
|
const back = () => {
|
||||||
routerPushByKey('my_mytask');
|
routerPushByKey(backKey.value as any);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 导出
|
// 导出
|
||||||
@@ -381,6 +383,9 @@ onMounted(async () => {
|
|||||||
if(route.query.status){
|
if(route.query.status){
|
||||||
currentStatus.value = route.query.status.toString();
|
currentStatus.value = route.query.status.toString();
|
||||||
}
|
}
|
||||||
|
if(route.query.key){
|
||||||
|
backKey.value = route.query.key.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -67,23 +67,23 @@ const tabChange = (k: string) => {
|
|||||||
|
|
||||||
// 处置申请跳转
|
// 处置申请跳转
|
||||||
const jumpTo = (act: string) => {
|
const jumpTo = (act: string) => {
|
||||||
routerPushByKey("details_disposal",{ query: { id: currentRow.value?.change_id.toString(),type:act } });
|
routerPushByKey("details_disposal",{ query: { id: currentRow.value?.change_id?.toString(),type:act } });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打开详情、修改重报
|
// 打开详情、修改重报
|
||||||
const openDetail = (c: any,type:string = '') => {
|
const openDetail = (c: any,type:string = '') => {
|
||||||
console.log(c)
|
console.log(c)
|
||||||
if(type==='detail'){
|
if(type==='detail'){
|
||||||
routerPushByKey("details_index",{ query: { id: c.change_id.toString(),status:c.status.toString() || '' } });
|
routerPushByKey("details_index",{ query: { id: c?.change_id?.toString(),status:c?.status?.toString() || '',key:'my_mytask' } });
|
||||||
}
|
}
|
||||||
if(type==='edit'){
|
if(type==='edit'){
|
||||||
routerPushByKey("my_initiatechange",{ query: { id: c.change_id.toString() } });
|
routerPushByKey("my_initiatechange",{ query: { id: c?.change_id?.toString() } });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// 打开资料关闭
|
// 打开资料关闭
|
||||||
const openDocClose = (c: any) => {
|
const openDocClose = (c: any) => {
|
||||||
currentRow.value = c;
|
currentRow.value = c;
|
||||||
routerPushByKey("details_closedoc",{ query: { id: c.change_id.toString() } });
|
routerPushByKey("details_closedoc",{ query: { id: c?.change_id?.toString() } });
|
||||||
};
|
};
|
||||||
// 打开处置申请
|
// 打开处置申请
|
||||||
const openDisposal = (c: any,) => {
|
const openDisposal = (c: any,) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user