待投用变更页面完成
This commit is contained in:
@@ -0,0 +1,10 @@
|
|||||||
|
import { request } from '../request';
|
||||||
|
|
||||||
|
// 列表查询
|
||||||
|
export function pendingChangeListApi(params:{page_num:number,page_size:number}) {
|
||||||
|
return request({
|
||||||
|
url: `/api/pssr/pending-use`,
|
||||||
|
method: 'get',
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,101 +1,110 @@
|
|||||||
|
<!-- 待投用变更 -->
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } 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 { getColorWithOpacity } from '@/utils/common';
|
import { localStg } from '@/utils/storage';
|
||||||
|
import previewComponent from '@/components/previewFile/index.vue'
|
||||||
|
import { tagTextColor, tagBgColor, tagBorderColor, downloadFileFun } from '@/utils/common';
|
||||||
|
import { systemConfigApi } from '@/service/api/system';
|
||||||
|
import { pendingChangeListApi } from '@/service/api/pendingChange';
|
||||||
|
|
||||||
const themeStore = useThemeStore();
|
const themeStore = useThemeStore();
|
||||||
const { routerPushByKey } = useRouterPush();
|
const { routerPushByKey } = useRouterPush();
|
||||||
|
|
||||||
const loading = ref<boolean>(false);
|
const loading = ref<boolean>(false);
|
||||||
const btnLoading = ref<boolean>(false);
|
// 组织
|
||||||
const useTime = ref<any>(null);
|
const org = ref<string>(localStg.get('userInfo')?.department?.label || '');
|
||||||
const useTimeModal = ref<boolean>(false);
|
// 列表
|
||||||
const currentRow = ref<any>(null);
|
|
||||||
const list = ref<any[]>([]);
|
const list = ref<any[]>([]);
|
||||||
const lists = [
|
// 分页
|
||||||
{
|
const pagination = ref<{page: number, pageSize: number, itemCount: number}>({
|
||||||
id: "MOC-2026-R02-0038",statusDetail: "培训 / PSSR 资料已传 · 待确认投用",
|
page: 1,
|
||||||
approveTime: "2026-07-31", applicant: "吴强", level: "一般", type: "工艺",
|
pageSize: 20,
|
||||||
title: 'DCS 罐区液位报警值 LIA-301 调整', status: '待PSSR', duration: "永久",
|
itemCount: 0,
|
||||||
useTime: "", planUse: "2026-08-01", pssr: "PSSR 检查确认表-签字版.pdf",
|
})
|
||||||
hasChange: true,
|
// 变更类型列表
|
||||||
},
|
const typeList = ref<any[]>([]);
|
||||||
{
|
// 变更等级列表
|
||||||
id: "MOC-2026-R02-0038",statusDetail: "培训 / PSSR 资料已传 · 待确认投用",
|
const levelList = ref<any[]>([]);
|
||||||
approveTime: "2026-07-31", applicant: "吴强", level: "重要", type: "工艺",
|
// 附件在线预览弹窗
|
||||||
title: 'DCS 罐区液位报警值 LIA-301 调整', status: '待PSSR', duration: "临时",
|
const previewModal = ref<boolean>(false);
|
||||||
useTime: "2026-07-16 06:30", planUse: "2026-08-01", pssr: "",
|
// 附件在线预览文件
|
||||||
hasChange: true,
|
const previewFile = ref<any>(null);
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const timePickerProps = {
|
|
||||||
format: 'HH:mm', // 时间选择器面板上显示的格式
|
|
||||||
seconds: false // 隐藏秒选择器[reference:3][reference:4]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 禁用今天之前的日期(今天可选)
|
|
||||||
const disabledDate = (ts: number) => {
|
|
||||||
const today = new Date()
|
|
||||||
today.setHours(0, 0, 0, 0) // 今天的 00:00:00
|
|
||||||
return ts < today.getTime() // 时间戳小于今天 0 点则禁用
|
|
||||||
}
|
|
||||||
// 获取列表数据
|
|
||||||
const getList = () => {
|
|
||||||
loading.value = true;
|
|
||||||
setTimeout(() => {
|
|
||||||
list.value = lists;
|
|
||||||
loading.value = false;
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查看
|
// 查看
|
||||||
const viewFile = (record: any) => {
|
const viewFile = (file: any) => {
|
||||||
window.$message?.info(`预览「${record.pssr}」(上传件不做内容识别,原件已随单归档)`)
|
previewFile.value = file;
|
||||||
|
previewModal.value = true;
|
||||||
};
|
};
|
||||||
// 下载
|
// 下载
|
||||||
const downloadFile = (record: any) => {
|
const downloadFile = (file: any) => {
|
||||||
window.$message?.success(`下载「${record.pssr}」`)
|
downloadFileFun(file.file_url, file.file_name);
|
||||||
};
|
};
|
||||||
// 打开变更单
|
// 打开变更单
|
||||||
const openChange = (record: any) => {
|
const openChange = (record: any) => {
|
||||||
routerPushByKey('details_index', { query: { params: JSON.stringify(record) } })
|
routerPushByKey("details_index",{ query: { id: record?.id?.toString(),status:record?.status?.toString() || '',key:'my_pendingchange' } });
|
||||||
};
|
};
|
||||||
// 填写投用日期
|
|
||||||
const fillUseTime = (record: any) => {
|
// 分页改变
|
||||||
useTime.value = null;
|
const pageChange = (page: number) => {
|
||||||
currentRow.value = record;
|
pagination.value.page = page;
|
||||||
useTimeModal.value = true;
|
getList();
|
||||||
};
|
|
||||||
// 保存投用日期
|
|
||||||
const saveUseTime = () => {
|
|
||||||
if (!useTime.value) {
|
|
||||||
return window.$message?.warning("请选择投用时间");
|
|
||||||
}
|
|
||||||
btnLoading.value = true;
|
|
||||||
setTimeout(() => {
|
|
||||||
btnLoading.value = false;
|
|
||||||
useTimeModal.value = false;
|
|
||||||
}, 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 匹配对象
|
||||||
|
const matchObj= (list:any[],val:any) => {
|
||||||
|
const item = list.find((item:any) => item.value == val);
|
||||||
|
return item || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取列表数据
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const {data,error} = await pendingChangeListApi({
|
||||||
|
page_num:pagination.value.page,
|
||||||
|
page_size:pagination.value.pageSize,
|
||||||
|
});
|
||||||
|
if(!error){
|
||||||
|
list.value = data?.list || [];
|
||||||
|
pagination.value.itemCount = data?.total || 0;
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取配置
|
||||||
|
const getConfig = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const {data,error} = await systemConfigApi();
|
||||||
|
if(!error){
|
||||||
|
// 解析 变更类型设置
|
||||||
|
const changeTypeGroup = data.find((group:{group_key:string}) => group.group_key === 'change_type');
|
||||||
|
if (changeTypeGroup) {
|
||||||
|
typeList.value = typeList.value.concat(changeTypeGroup.items);
|
||||||
|
}
|
||||||
|
// 解析 变更等级设置
|
||||||
|
const changeLevelGroup = data.find((group:{group_key:string}) => group.group_key === 'change_level');
|
||||||
|
if (changeLevelGroup) {
|
||||||
|
levelList.value = levelList.value.concat(changeLevelGroup.items);
|
||||||
|
}
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getConfig();
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NSpace vertical :size="16">
|
<NSpace vertical :size="16">
|
||||||
<!-- PSSR监督 -->
|
|
||||||
<NSpin :show="loading" size="small">
|
<NSpin :show="loading" size="small">
|
||||||
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||||
<div class="flex flex-wrap items-center gap-2 mb-3">
|
<div class="flex flex-wrap items-center gap-2 mb-3">
|
||||||
<span class="text-sm font-semibold text-slate-700">待投用变更(本车间 · 一车间)</span>
|
<span class="text-sm font-semibold text-slate-700">待投用变更(本车间 · {{ org }})</span>
|
||||||
<NTag size="small" type="primary">{{ list.length }} 起</NTag>
|
<NTag size="small" type="primary">{{ pagination.itemCount }} 起</NTag>
|
||||||
<span class="ml-auto text-[11px] text-slate-400">按审批通过时间排序 · 投用时间由发起人在资料关闭页填报 · 支持属地负责人在此代录投用日期</span>
|
<span class="ml-auto text-[11px] text-slate-400">按审批通过时间排序 · 投用时间由发起人在资料关闭页填报 · 支持属地负责人在此代录投用日期</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="scroll">
|
<div class="scroll">
|
||||||
@@ -107,28 +116,51 @@ onMounted(() => {
|
|||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<div v-for="(s, i) in list" :key="`${s.id ?? 'x'}-${i}`" class="flex flex-wrap items-center gap-x-3 gap-y-2 border p-4" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
<div v-for="(s, i) in list" :key="`${s.id ?? 'x'}-${i}`" class="flex flex-wrap items-center gap-x-3 gap-y-2 border p-4" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||||
<NTag v-if="s.status==='待PSSR'" type="warning" size="small">{{ s.status }}</NTag>
|
<!-- 状态标签 -->
|
||||||
<NTag v-if="s.status==='待关闭'" type="error" size="small">{{ s.status }}</NTag>
|
<NTag v-if="s.status==='APPROVING'" size="small" type="warning">审批中</NTag>
|
||||||
<NTag v-if="s.status==='实施中'" type="primary" size="small">{{ s.status }}</NTag>
|
<NTag v-if="s.status==='APPROVED'" size="small" type="success">已通过</NTag>
|
||||||
<NTag v-if="s.status==='待验收'" type="success" size="small">{{ s.status }}</NTag>
|
<NTag v-if="s.status==='IMPLEMENTED'" size="small" type="success">待验收</NTag>
|
||||||
|
<NTag v-if="s.status==='ACCEPTED'" size="small" type="error">待关闭</NTag>
|
||||||
|
<NTag v-if="s.status==='CLOSED'" size="small" type="success">已关闭</NTag>
|
||||||
|
<NTag v-if="s.status==='WITHDRAWN'" size="small" type="error">已撤回</NTag>
|
||||||
|
<NTag v-if="s.status==='REJECTED'" size="small" type="error">已驳回</NTag>
|
||||||
|
|
||||||
<div class="min-w-0 flex-1">
|
<div class="min-w-0 flex-1">
|
||||||
<div class="flex flex-wrap items-center gap-1.5">
|
<div class="flex flex-wrap items-center gap-1.5">
|
||||||
<p class="truncate text-sm font-medium text-slate-800">{{ s.title }}</p>
|
<p class="truncate text-sm font-medium text-slate-800">{{ s.title }}</p>
|
||||||
<NTag v-if="s.level==='一般'" size="small">{{s.level}}</NTag>
|
<!-- 等级 -->
|
||||||
<NTag v-if="s.level==='重要'" size="small" type="error">{{s.level}}</NTag>
|
<NTag
|
||||||
<NTag size="small" type="primary">{{s.type}}</NTag>
|
size="small"
|
||||||
<NTag v-if="s.duration==='永久'" size="small">{{s.duration}}</NTag>
|
:color="{
|
||||||
<NTag v-if="s.duration==='临时'" size="small" type="warning">{{s.duration}}</NTag>
|
color: tagBgColor(matchObj(levelList,s.change_level)?.color),
|
||||||
|
textColor: tagTextColor(matchObj(levelList,s.change_level)?.color),
|
||||||
|
borderColor: tagBorderColor(matchObj(levelList,s.change_level)?.color),
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ matchObj(levelList,s.change_level)?.label }}
|
||||||
|
</NTag>
|
||||||
|
<!-- 类型 -->
|
||||||
|
<NTag
|
||||||
|
size="small"
|
||||||
|
:color="{
|
||||||
|
color: tagBgColor(matchObj(typeList,s.change_type)?.color),
|
||||||
|
textColor: tagTextColor(matchObj(typeList,s.change_type)?.color),
|
||||||
|
borderColor: tagBorderColor(matchObj(typeList,s.change_type)?.color),
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ matchObj(typeList,s.change_type)?.label }}
|
||||||
|
</NTag>
|
||||||
|
<NTag v-if="s.duration_type===2" size="small" type="warning">临时</NTag>
|
||||||
|
<NTag v-if="s.duration_type===1" size="small" type="info">永久</NTag>
|
||||||
</div>
|
</div>
|
||||||
<p class="mt-0.5 text-[11px] text-slate-400">{{ s.id }} · {{ s.applicant }}</p>
|
<p class="mt-0.5 text-[11px] text-slate-400">{{ s.change_no }} · {{ s.applicant_name }}</p>
|
||||||
<p class="text-slate-400 text-[11px]">审批通过时间:<span class="font-medium text-slate-600">{{ s.approveTime ?? '—' }}</span></p>
|
<p class="text-slate-400 text-[11px]">审批通过时间:<span class="font-medium text-slate-600">{{ s.approve_time?.slice(0,16) }}</span></p>
|
||||||
<p class="text-slate-400 text-[11px]">变更投用时间:<span class="font-medium text-[var(--warning-color)]">{{ s.useTime ? s.useTime : `待投用(计划 ${s.planUse})` }}</span></p>
|
<p class="text-slate-400 text-[11px]">变更投用时间:<span class="font-medium text-[var(--warning-color)]">{{ s.use_time ? s.use_time?.slice(0,10) : `待投用(计划 ${s.plan_use_date?.slice(0,10)})` }}</span></p>
|
||||||
<p class="mt-0.5 text-[11px] text-slate-400">{{ s.statusDetail }}</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-1.5 rounded-md border bg-slate-50/60 px-2 py-1">
|
<div class="flex items-center gap-1.5 rounded-md border bg-slate-50/60 px-2 py-1">
|
||||||
<Icon icon="akar-icons:file" class="size-14px text-[var(--theme-color)]" />
|
<Icon icon="akar-icons:file" class="size-14px text-[var(--theme-color)]" />
|
||||||
<span class="text-[11px] font-medium text-slate-600">PSSR 确认表</span>
|
<span class="text-[11px] font-medium text-slate-600">PSSR 确认表</span>
|
||||||
<template v-if="s.pssr">
|
<template v-if="s.pssr_attachment">
|
||||||
<NButton ghost size="tiny" class="text-11px" @click="viewFile(s)">查看</NButton>
|
<NButton ghost size="tiny" class="text-11px" @click="viewFile(s)">查看</NButton>
|
||||||
<NButton ghost size="tiny" class="text-11px" @click="downloadFile(s)">下载</NButton>
|
<NButton ghost size="tiny" class="text-11px" @click="downloadFile(s)">下载</NButton>
|
||||||
</template>
|
</template>
|
||||||
@@ -136,50 +168,47 @@ onMounted(() => {
|
|||||||
<span class="text-[11px] text-[var(--warning-color)]">待传</span>
|
<span class="text-[11px] text-[var(--warning-color)]">待传</span>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<NButton v-if="!s.useTime" size="small" type="primary" class="text-xs" @click="fillUseTime(s)">填写投用日期</NButton>
|
<NButton size="small" ghost class="text-xs" @click="openChange(s)">打开变更单</NButton>
|
||||||
<NButton v-if="s.hasChange" size="small" ghost class="text-xs" @click="openChange(s)">打开变更单</NButton>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-if="list.length === 0" class="h-100% flex items-center justify-center">
|
<div v-if="list.length === 0" class="h-100% flex items-center justify-center">
|
||||||
<NEmpty description="暂无数据"></NEmpty>
|
<NEmpty description="暂无数据"></NEmpty>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex justify-end mt-3">
|
||||||
|
<NPagination
|
||||||
|
v-model:page="pagination.page"
|
||||||
|
:page-size="pagination.pageSize"
|
||||||
|
:item-count="pagination.itemCount"
|
||||||
|
:on-update:page="pageChange"
|
||||||
|
>
|
||||||
|
<template #prefix="{ itemCount }">
|
||||||
|
共 {{ itemCount }} 条
|
||||||
|
</template>
|
||||||
|
</NPagination>
|
||||||
|
</div>
|
||||||
</NCard>
|
</NCard>
|
||||||
<!-- 填写投用日期弹窗 -->
|
<!-- 附件在线预览弹窗 -->
|
||||||
<NModal
|
<NModal
|
||||||
v-model:show="useTimeModal"
|
v-model:show="previewModal"
|
||||||
preset="card"
|
preset="card"
|
||||||
title="填写投用日期"
|
|
||||||
:auto-focus="false"
|
:auto-focus="false"
|
||||||
:style="{ width: '450px', height: 'auto' }"
|
:style="{ width: '80%', height: 'auto' }"
|
||||||
:segmented="{ content: true, footer: true }"
|
:segmented="{ content: true, footer: true }"
|
||||||
>
|
>
|
||||||
<template #default>
|
<template #header>
|
||||||
<div
|
<div class="flex items-center gap-2 text-base font-semibold text-slate-800">
|
||||||
class="space-y-3 text-sm"
|
<Icon icon="akar-icons:file" class="size-18px" /> {{ previewFile?.file_name }}
|
||||||
:style="{
|
|
||||||
'--warning-bg': getColorWithOpacity(themeStore.otherColor.warning, 0.1),
|
|
||||||
'--warning-color': themeStore.otherColor.warning,
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<p class="text-xs text-slate-500">{{ currentRow?.id }} · {{ currentRow?.title }}</p>
|
|
||||||
<div class="rounded-lg border border-[var(--warning-color)] bg-[var(--warning-bg)] px-3 py-2 text-xs leading-relaxed text-[var(--warning-color)]">
|
|
||||||
提示:投用前应完成变更培训与 PSSR 确认(资料已上传)。投用后变更进入待验收阶段,临时变更自投用日起计算时限。
|
|
||||||
</div>
|
|
||||||
<NDatePicker
|
|
||||||
v-model:value="useTime"
|
|
||||||
type="datetime"
|
|
||||||
:is-date-disabled="disabledDate"
|
|
||||||
format="yyyy-MM-dd HH:mm"
|
|
||||||
placeholder="请选择投用时间"
|
|
||||||
:time-picker-props="timePickerProps"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #footer>
|
<template #default>
|
||||||
<div class="flex justify-end gap-[10px]">
|
<div class="space-y-3">
|
||||||
<NButton size="small" @click="useTimeModal = false">取消</NButton>
|
<div class="flex flex-wrap gap-x-4 gap-y-1 text-xs text-slate-400">
|
||||||
<NButton size="small" type="primary" :loading="btnLoading" @click="saveUseTime">确认投用</NButton>
|
<span>上传人:{{ previewFile?.uploader_name }}</span>
|
||||||
|
<span>上传时间:{{ previewFile?.created_at?.slice(0, 16) }}</span>
|
||||||
|
<span v-if="previewFile?.version">{{ `版本:${previewFile?.version}(受控)` }}</span>
|
||||||
|
</div>
|
||||||
|
<previewComponent v-if="previewFile" :previewFile="previewFile" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</NModal>
|
</NModal>
|
||||||
@@ -189,7 +218,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.scroll {
|
.scroll {
|
||||||
height: calc(100vh - 180px);
|
height: calc(100vh - 220px);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user