发起变更,底部封装通用组件
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
<!-- 变更培训内容 -->
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { Icon } from '@iconify/vue'
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
import { getColorWithOpacity } from "@/utils/common";
|
||||
import ApprovalDrawer from './approvalDrawer.vue'
|
||||
|
||||
const themeStore = useThemeStore();
|
||||
|
||||
// 抽屉类型
|
||||
const approvalDrawerShow = ref<boolean>(false);
|
||||
const trainText = ref<string>('');
|
||||
const btnDisabled = ref<boolean>(false);
|
||||
const saveLoading = ref<boolean>(false);
|
||||
const downloadLoading = ref<boolean>(false);
|
||||
const regenerateLoading = ref<boolean>(false);
|
||||
const submitLoading = ref<boolean>(false);
|
||||
const confirmed = ref<boolean>(false);
|
||||
const approvers = ref<Record<string, string>>({
|
||||
部门审核: "李主任(一车间主任)",
|
||||
最终批准: "李主任(部门负责人 · 固定)",
|
||||
});
|
||||
const signers = ref<Record<string, string>>({});
|
||||
|
||||
const editing = ref<any>(null);
|
||||
const acceptRows = ref([
|
||||
{ id: 1, item: "反应转化率", basis: "转化率不低于 98%", standard: "转化率 ≥ 98%(连续 3 批化验合格)", method: "化验室逐批取样分析,出具检验报告", owner: "车间 · 张工艺", result: "待验收" },
|
||||
{ id: 2, item: "单批反应时间 / 产能", basis: "反应时间缩短 50%、产能提升一倍", standard: "保温时间 4h±0.5h,产能提升 ≥ 80%", method: "DCS 批次记录统计,对比变更前 30 天均值", owner: "车间 · 李主任", result: "待验收" },
|
||||
{ id: 3, item: "未知杂质含量", basis: "杂质水平受控、产品质量合格", standard: "杂质 ≤ 0.15%,产品质量指标全部合格", method: "每批化验跟踪,连续 5 批数据趋势评估", owner: "质量 · 王海燕", result: "待验收" },
|
||||
{ id: 4, item: "温控与联锁有效性", basis: "温度窗口上调后保护层有效", standard: "温度波动 ≤ ±2℃,高报/联锁动作正确率 100%", method: "DCS 趋势核查 + 联锁测试记录复核", owner: "仪表 · 王仪表", result: "待验收" },
|
||||
{ id: 5, item: "设备运行状态", basis: "负荷变化后设备长周期稳定", standard: "搅拌电流、釜壁温度无异常趋势,无泄漏", method: "设备巡检 + 振动/温度记录评估", owner: "设备 · 周设备", result: "待验收" },
|
||||
]);
|
||||
const acceptNote = ref("");
|
||||
|
||||
const regenerate = () => window.$message?.success(`演示:已根据变更描述重新生成变更申请表(本页内容已刷新)`);
|
||||
const download = () => window.$message?.success(`演示:变更申请表已下载(Word/PDF)`);
|
||||
|
||||
// 保存草稿
|
||||
const saveDraft = async () => {
|
||||
// if(changeApplyRules()){
|
||||
// return
|
||||
// }
|
||||
// saveLoading.value = true;
|
||||
// const {error} = await applicationSaveApi(props.currentId, form.value);
|
||||
// if(!error){
|
||||
// window.$message?.success("已保存为草稿,可在左侧「我的草稿」中继续编辑");
|
||||
// }
|
||||
// saveLoading.value = false;
|
||||
}
|
||||
// ---------- 提交 ----------
|
||||
const submitApply = () => {
|
||||
|
||||
}
|
||||
const confirmTab = () => {
|
||||
confirmed.value = !confirmed.value;
|
||||
}
|
||||
|
||||
defineExpose({trainText})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="p-4">
|
||||
<div class="space-y-4 scroll">
|
||||
<div class="flex flex-wrap items-center gap-3">
|
||||
<span class="flex items-center gap-1.5 text-sm font-semibold text-slate-700">
|
||||
<Icon icon="ix:success" class="size-18px text-emerald-500" />
|
||||
验收评价(依据预期效果设定可量化验收标准)
|
||||
</span>
|
||||
<span class="inline-flex items-center gap-1 rounded-full border border-violet-200 bg-violet-100 px-2 py-0.5 text-xs font-medium text-violet-700">
|
||||
✨ AI 生成 · 需人工确认
|
||||
</span>
|
||||
<span class="ml-auto text-xs text-slate-400">申请阶段由 AI 依据「预期效果」生成量化标准与验收方式,可手动修改;投用运行后由车间和各专业按标准验收并给出评估结论</span>
|
||||
</div>
|
||||
<div
|
||||
class="space-y-1.5 rounded-lg border border-[var(--border-color)] bg-[var(--bg-color)] px-4 py-3 text-xs leading-6 text-slate-700"
|
||||
:style="{
|
||||
'--bg-color': getColorWithOpacity(themeStore.themeColor, 0.1),
|
||||
'--border-color': getColorWithOpacity(themeStore.themeColor, 0.2)
|
||||
}"
|
||||
>
|
||||
<!-- <div><b :style="{color: themeStore.themeColor}">变更目的:</b>{{ form?.purposes?.join('、') || '提高生产效能、改善操作条件' }}</div>
|
||||
<div><b :style="{color: themeStore.themeColor}">预期效果:</b>{{ form?.effect || '在保持转化率不低于98%的前提下,反应时间缩短50%,产能提升一倍' }}</div> -->
|
||||
<div
|
||||
class="border-t border-[var(--border-color)] pt-1.5 text-slate-500"
|
||||
:style="{'--border-color': getColorWithOpacity(themeStore.themeColor, 0.2)}"
|
||||
>
|
||||
<b :style="{color: themeStore.themeColor}">对应说明:</b>验收项目由预期效果逐条拆解设定,各项目对应的预期效果来源见表格「验收项目」列下方灰色小字(点击可修改);验收时须逐项对照预期效果判定达成程度。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto border" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||
<table class="w-full min-w-[900px] border-collapse text-sm">
|
||||
<thead>
|
||||
<tr class="bg-slate-100 text-left text-slate-600">
|
||||
<th class="w-8 px-3 py-2 font-medium">#</th>
|
||||
<th class="w-56 px-3 py-2 font-medium">验收项目(含对应预期效果)</th>
|
||||
<th class="px-3 py-2 font-medium">量化验收标准</th>
|
||||
<th class="px-3 py-2 font-medium">验收方式(可执行)</th>
|
||||
<th class="w-32 px-3 py-2 font-medium">责任单位/人</th>
|
||||
<th class="px-3 py-2 font-medium">评估结论</th>
|
||||
<th class="w-12 px-2 py-2 font-medium text-center">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, i) in acceptRows" :key="row.id" class="align-top">
|
||||
<td class="border-t px-3 py-2.5 text-slate-400">{{ i + 1 }}</td>
|
||||
<td class="border-t px-3 py-2.5">
|
||||
<NInput
|
||||
v-if="editing === `acc-${row.id}-item`"
|
||||
class="text-xs"
|
||||
v-model:value="row.item"
|
||||
type="textarea"
|
||||
autofocus
|
||||
rows="2"
|
||||
@blur="editing = null"
|
||||
/>
|
||||
<button v-else @click="editing = `acc-${row.id}-item`" title="点击修改"
|
||||
class="bg-transparent block w-full rounded-md px-2 py-1 text-left text-xs font-medium leading-relaxed text-slate-700 transition hover:bg-[#EAF0F9]"
|
||||
>
|
||||
{{ row.item }}
|
||||
</button>
|
||||
<NInput
|
||||
v-if="editing === `acc-${row.id}-basis`"
|
||||
class="text-[11px]"
|
||||
size="small"
|
||||
v-model:value="row.basis"
|
||||
autofocus
|
||||
@blur="editing = null"
|
||||
/>
|
||||
<button v-else @click="editing = `acc-${row.id}-basis`" title="本项目对应的预期效果来源,点击修改"
|
||||
class="bg-transparent mt-0.5 block w-full rounded px-2 text-left text-[11px] text-slate-400 transition hover:bg-[#EAF0F9] hover:text-slate-500"
|
||||
>
|
||||
对应预期:{{ row.basis || '(点击填写对应预期效果)' }}
|
||||
</button>
|
||||
</td>
|
||||
<td v-for="field in (['standard', 'method', 'owner'])" :key="field" class="border-t px-3 py-2.5">
|
||||
<NInput
|
||||
v-if="editing === `acc-${row.id}-${field}`"
|
||||
class="text-xs"
|
||||
v-model:value="row[field]"
|
||||
type="textarea"
|
||||
autofocus
|
||||
rows="2"
|
||||
@blur="editing = null"
|
||||
/>
|
||||
<button v-else @click="editing = `acc-${row.id}-${field}`" title="点击修改"
|
||||
class="bg-transparent block w-full rounded-md px-2 py-1 text-left text-xs leading-relaxed text-slate-700 transition hover:bg-[#EAF0F9]"
|
||||
>
|
||||
{{ row[field] }}
|
||||
</button>
|
||||
</td>
|
||||
<td class="border-t px-3 py-2.5">
|
||||
<div class="flex flex-nowrap items-center gap-1">
|
||||
<NButton v-for="v in (['完全达到', '基本达到', '未达成'])" :key="v"
|
||||
size="small"
|
||||
round
|
||||
@click="acceptRows = acceptRows.map((x) => (x.id === row.id ? { ...x, result: x.result === v ? '待验收' : v } : x))"
|
||||
class="text-[11px]"
|
||||
:type="row.result === v
|
||||
? v === '未达成' ? 'error' : v === '基本达到' ? 'warning' : 'success'
|
||||
: 'default'">
|
||||
{{ v }}
|
||||
</NButton>
|
||||
</div>
|
||||
</td>
|
||||
<td class="border-t px-2 py-2.5 text-center">
|
||||
<NButton text type="error" title="删除本验收项" @click="acceptRows = acceptRows.filter((x) => x.id !== row.id)">
|
||||
<Icon icon="iconamoon:trash" class="size-16px" />
|
||||
</NButton>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<NButton ghost class="text-xs"
|
||||
@click="acceptRows = [...acceptRows, { id: Date.now(), item: '新验收项目', basis: '', standard: '', method: '', owner: '', result: '待验收' }]">
|
||||
<Icon icon="ic:round-plus" class="size-16px" />添加验收项
|
||||
</NButton>
|
||||
<span class="text-xs text-slate-400">评估结论在验收阶段由责任单位填写:点击选择「完全达到 / 基本达到 / 未达成」,再次点击取消;行尾可删除验收项</span>
|
||||
</div>
|
||||
<div class="rounded-lg border">
|
||||
<div class="border-b bg-slate-100 px-3 py-2 text-sm font-medium text-slate-700">综合验收结论(验收阶段由车间会同各专业评估填写)</div>
|
||||
<div class="space-y-3 p-3">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<span v-for="v in (['完全达到', '基本达到', '未达成'])" :key="v">
|
||||
<NRadio :checked="acceptNote !== '' && acceptNote.startsWith(v)" :value="'v'" :label="v" @change="acceptNote = v + ':'"></NRadio>
|
||||
</span>
|
||||
<span class="text-xs text-slate-400">「基本达到 / 未达成」须说明偏差原因与处置措施,并纳入变更关闭审核</span>
|
||||
</div>
|
||||
<NInput v-model:value="acceptNote" type="textarea" rows="2" placeholder="验收意见:总体评价、偏差说明、后续跟踪措施…(验收阶段填写)" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="rounded-lg bg-emerald-50/80 px-4 py-2.5 text-xs leading-5 text-emerald-700">
|
||||
流程说明:投用运行满验收周期后,系统向车间(属地)与涉及专业推送验收任务;各责任单位按上表逐项给出评估结论并上传佐证(数据报表 / 化验报告 / 现场照片),全部完成后汇总至综合验收结论,结论与佐证资料一并纳入变更关闭校验,验收不通过时退回整改或评估恢复原状。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center justify-between gap-2 border-t p-4">
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<NButton ghost type="success" :disabled="btnDisabled" :loading="downloadLoading" @click="download">
|
||||
<Icon icon="material-symbols:download" class="size-16px" /> 下载验收评价
|
||||
</NButton>
|
||||
<NButton ghost type="warning" :disabled="btnDisabled" :loading="regenerateLoading" @click="regenerate">
|
||||
<Icon icon="tdesign:refresh" class="size-14px" /> 重新生成验收评价
|
||||
</NButton>
|
||||
<NButton ghost :type="confirmed ? 'success' : 'primary'" :disabled="btnDisabled" @click="confirmTab">
|
||||
<Icon icon="ix:success" class="size-16px" /> {{ confirmed ? '已确认完毕' : '本标签内容确认完毕' }}
|
||||
</NButton>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center gap-x-4 gap-y-2 bg-[#EAF0F9] px-4 py-2.5 shadow-[0_-2px_8px_rgba(0,0,0,0.05)]">
|
||||
<div class="flex min-w-0 flex-1 flex-wrap items-center gap-x-2 gap-y-1 text-xs text-slate-500">
|
||||
<Icon icon="lucide:users" class="size-14px" />
|
||||
<span class="min-w-0 truncate">
|
||||
部门审核:{{ approvers.部门审核 }} → 专业会签:{{ Object.keys(signers).length ? Object.values(signers).join('、') : '未涉及专业 · 免会签' }} → 最终批准:{{ approvers.最终批准 }}
|
||||
</span>
|
||||
<NButton ghost size="small" type="primary" @click="approvalDrawerShow = true">
|
||||
<Icon icon="octicon:sliders-24" class="size-14px" />
|
||||
审批流程设置
|
||||
</NButton>
|
||||
</div>
|
||||
<div class="ml-auto flex shrink-0 items-center gap-2">
|
||||
<NButton size="small" type="primary" :disabled="btnDisabled" :loading="saveLoading" @click="saveDraft">保存</NButton>
|
||||
<!-- <span v-if="!form" class="flex items-center text-xs text-amber-600">请先在「变更预识别」页生成变更申请单</span> -->
|
||||
<NButton size="small" type="primary" @click="submitApply" :disabled="btnDisabled" :loading="submitLoading">
|
||||
提交 <Icon icon="formkit:right" class="size-14px" />
|
||||
</NButton>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 审批流程设置 -->
|
||||
<NDrawer v-model:show="approvalDrawerShow" placement="right" width="28rem">
|
||||
<NDrawerContent>
|
||||
<template #header>
|
||||
<div class="text-base font-semibold text-slate-800">审批流程设置</div>
|
||||
</template>
|
||||
<ApprovalDrawer />
|
||||
</NDrawerContent>
|
||||
</NDrawer>
|
||||
</template>
|
||||
<style scoped lang="scss">
|
||||
.scroll {
|
||||
height: calc(100vh - 393px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user