Compare commits

..

3 Commits

Author SHA1 Message Date
48bf07ab0f 新增页面 2026-01-13 17:34:28 +08:00
a128d2f139 更新保安公司送培 2026-01-13 16:32:59 +08:00
1a30a3ece4 更新 2026-01-12 23:59:19 +08:00
17 changed files with 1507 additions and 422 deletions

View File

@ -8,6 +8,7 @@
:key="item.value"
:index="index"
:class="item.elTagType"
:style="{'color': props.color}"
>{{ item.label }}</span>
<el-tag
v-else
@ -33,6 +34,10 @@ const props = defineProps({
type: Array,
default: null
},
color: {
type: String,
default: ''
},
tag: false,
value: [Number, String, Array]
});

View File

@ -212,6 +212,24 @@ export const privateRoutes = [
icon: "personnel"
}
},
{
path: "/trainingCompanyNjgl",
name: "trainingCompanyNjgl",
component: () => import("@/views/Training/trainingCompanyNjgl/index"),
meta: {
title: "公司保安员年检管理",
icon: "personnel"
}
},
{
path: "/trainingCompanyNjsp",
name: "trainingCompanyNjsp",
component: () => import("@/views/Training/trainingCompanyNjsp/index"),
meta: {
title: "年检签到",
icon: "personnel"
}
},
]
},
{

View File

@ -7,165 +7,131 @@
<div class="cntinfo">
<!-- 标签 -->
<ul class="tag-box">
<li class="tag_item">驳回</li>
<li class="tag_item">通过</li>
<li class="tag_item">待审核</li>
<li class="tag_item" :class="detail.shzt == 0 ? 'dsh_item' : detail.shzt == 1 ? 'tgg_item' : 'jtb_item'">
<!-- 0-待审核 1-通过 2-驳回 -->
{{ detail.shzt == 0 ? '待审核' : detail.shzt == 1 ? '通过' : '驳回' }}
</li>
</ul>
<!-- 内容描述 -->
<el-descriptions class="desc" :column="3" border label-width="200px">
<el-descriptions-item label="保安公司名称">{{ detail.companyName }}</el-descriptions-item>
<el-descriptions-item label="年审年份">{{ detail.reviewYear }}</el-descriptions-item>
<el-descriptions-item label="保安公司名称">{{ detail.ssbakk }}</el-descriptions-item>
<el-descriptions-item label="年审年份">{{ detail.njnf }}</el-descriptions-item>
<el-descriptions-item label="姓名">{{ detail.xm }}</el-descriptions-item>
<el-descriptions-item label="身份证号码">{{ detail.sfzh }}</el-descriptions-item>
<el-descriptions-item label="电话">{{ detail.phone }}</el-descriptions-item>
<el-descriptions-item label="性别">{{ detail.sexText }}</el-descriptions-item>
<el-descriptions-item label="身份证号码">{{ detail.sfzhm }}</el-descriptions-item>
<el-descriptions-item label="电话">{{ detail.dh }}</el-descriptions-item>
<el-descriptions-item label="性别">
<DictTag :value="detail.xb" :tag="false" :options="props.dic.D_BZ_XB" />
</el-descriptions-item>
<el-descriptions-item label="民族">
<DictTag :value="detail.mz" :tag="false" :options="props.dic.D_BZ_MZ" />
</el-descriptions-item>
<el-descriptions-item label="籍贯">{{ detail.jg }}</el-descriptions-item>
<el-descriptions-item label="文化程度">
<DictTag :value="detail.whcd" :tag="false" :options="props.dic.D_BZ_WHCD" />
</el-descriptions-item>
<el-descriptions-item label="民族">{{ detail.nationText }}</el-descriptions-item>
<el-descriptions-item label="籍贯">{{ detail.nativePlace }}</el-descriptions-item>
<el-descriptions-item label="文化程度">{{ detail.education }}</el-descriptions-item>
<el-descriptions-item label="证书编号">{{ detail.zsbh }}</el-descriptions-item>
<el-descriptions-item label="上岗证号码">{{ detail.sgxkhm }}</el-descriptions-item>
<el-descriptions-item label="服务行业">
<DictTag :value="detail.fwxy" :tag="false" :options="props.dic.D_BAXX_SSHY" />
</el-descriptions-item>
<el-descriptions-item label="证书编号">{{ detail.certificateNo }}</el-descriptions-item>
<el-descriptions-item label="上岗证号码">{{ detail.workCardNo }}</el-descriptions-item>
<el-descriptions-item label="服务行业">{{ detail.serviceIndustry }}</el-descriptions-item>
<el-descriptions-item label="服务行业名称">{{ detail.serviceIndustryName }}</el-descriptions-item>
<el-descriptions-item label="入职时间">{{ detail.entryDate }}</el-descriptions-item>
<el-descriptions-item label="政治面貌">{{ detail.politicalStatus }}</el-descriptions-item>
<el-descriptions-item label="服务行业名称">{{ detail.fwxymc }}</el-descriptions-item>
<el-descriptions-item label="入职时间">{{ detail.rzsj }}</el-descriptions-item>
<el-descriptions-item label="政治面貌">
<DictTag :value="detail.zzmm" :tag="false" :options="props.dic.D_BZ_ZZMM" />
</el-descriptions-item>
<el-descriptions-item label="无犯罪记录证明">
<div class="img-grid one">
<el-image
v-for="(src, idx) in noCrimeUrls"
:key="idx"
:src="src"
:src="baseUrl + detail.wfbjlzm"
fit="cover"
:preview-src-list="noCrimeUrls"
:preview-src-list='[baseUrl + detail.wfbjlzm]'
preview-teleported
class="img"
/>
<div v-if="noCrimeUrls.length === 0" class="img-placeholder"></div>
</div>
</el-descriptions-item>
<el-descriptions-item label="体检报告">
<div class="img-grid one">
<el-image
v-for="(src, idx) in medicalUrls"
:key="idx"
:src="src"
:src="baseUrl + detail.tjbg"
fit="cover"
:preview-src-list="medicalUrls"
:preview-src-list='[baseUrl + detail.tjbg]'
preview-teleported
class="img"
/>
<div v-if="medicalUrls.length === 0" class="img-placeholder"></div>
</div>
</el-descriptions-item>
<el-descriptions-item label="身份证正反面">
<div class="img-grid two">
<el-image
v-for="(src, idx) in idCardUrls"
:key="idx"
:src="src"
:src="baseUrl + detail.sfzzm"
fit="cover"
:preview-src-list="idCardUrls"
:preview-src-list='[baseUrl + detail.sfzzm]'
preview-teleported
class="img"
/>
<el-image
:src="baseUrl + detail.sfzfm"
fit="cover"
:preview-src-list='[baseUrl + detail.sfzfm]'
preview-teleported
class="img"
/>
<template v-if="idCardUrls.length === 0">
<div class="img-placeholder"></div>
<div class="img-placeholder"></div>
</template>
</div>
</el-descriptions-item>
<el-descriptions-item label="审核时间">{{ detail.auditTime }}</el-descriptions-item>
<el-descriptions-item label="发证机关">{{ detail.issuingAuthority }}</el-descriptions-item>
<el-descriptions-item label="发证日期">{{ detail.issueDate }}</el-descriptions-item>
<el-descriptions-item label="审核时间">{{ detail.shsj }}</el-descriptions-item>
<el-descriptions-item label="发证机关">{{ detail.fqjg }}</el-descriptions-item>
<el-descriptions-item label="发证日期">{{ detail.fqsj }}</el-descriptions-item>
<el-descriptions-item label="驳回原因" :span="3">{{ detail.rejectReason }}</el-descriptions-item>
<el-descriptions-item label="驳回原因" :span="3">{{ detail.bhyy }}</el-descriptions-item>
</el-descriptions>
</div>
</div>
</template>
<script setup>
import { ref, computed, defineEmits, getCurrentInstance } from 'vue';
import { ref, computed, defineEmits, getCurrentInstance,defineProps } from 'vue';
import { qcckPost } from "@/api/qcckApi.js";
const emit = defineEmits(["refresh"]);
const { proxy } = getCurrentInstance();
const baseUrl = '/bagl/mosty-base/minio/image/download'
const props = defineProps({
dict: {
dic: {
default: [[]], //二维数组
type: Array
}
})
const dialogForm = ref(false);
const listQuery = ref({});
const detail = ref({})
// 初始化数据
const init = (type, row,) => {
dialogForm.value = true;
const raw = row || {};
listQuery.value = {
...raw,
companyName: raw.companyName || raw.dwmc || raw.gsmc || raw.bagsmc,
reviewYear: raw.reviewYear || raw.njnd || raw.njYear || raw.nf || raw.year,
phone: raw.phone || raw.lxdh || raw.dh || raw.sjhm || raw.xssbrdh,
sexText: raw.sexText || raw.xbText || raw.xb || raw.sex,
nationText: raw.nationText || raw.mzText || raw.mz,
nativePlace: raw.nativePlace || raw.jg || raw.jgText,
education: raw.education || raw.whcd || raw.whcdText,
certificateNo: raw.certificateNo || raw.zsbh || raw.zsbhm || raw.zjbh,
workCardNo: raw.workCardNo || raw.sgzh || raw.sgzNumber,
serviceIndustry: raw.serviceIndustry || raw.fwhy || raw.fwhyText || raw.hy,
serviceIndustryName: raw.serviceIndustryName || raw.fwhymc || raw.hyName,
entryDate: raw.entryDate || raw.rzsj || raw.rzrq,
politicalStatus: raw.politicalStatus || raw.zzmm || raw.zzmmText,
auditTime: raw.auditTime || raw.shsj || raw.njsj,
rejectReason: raw.rejectReason || raw.bhyy || raw.bhReason || raw.reason,
issuingAuthority: raw.issuingAuthority || raw.fzjg,
issueDate: raw.issueDate || raw.fzrq,
noCrimeProof: raw.noCrimeProof || raw.wffzjlzm || raw.wffzjlzmId,
medicalReport: raw.medicalReport || raw.tjbg || raw.tjbgId,
idCardImages: raw.idCardImages || raw.sfzzf || raw.sfzImgs || raw.sfzzm,
};
qcckPost({},'/mosty-base/bans/njxx/getInfo/'+row.id).then(res => {
let zj = res.sfzzfmj.split(',');
res.sfzzm = [zj[0]];
res.sfzfm = [zj[1]];
detail.value = res || {};
})
};
const close = () => {
dialogForm.value = false;
listQuery.value = {};
};;
const detail = computed(() => listQuery.value || {});
const toIdList = (val, limit) => {
const v = val ?? [];
const arr = Array.isArray(v) ? v : [v];
const ids = arr
.map((el) => {
if (!el) return null;
if (typeof el === 'string' || typeof el === 'number') return String(el);
if (typeof el === 'object') return el.id ? String(el.id) : null;
return null;
})
.filter(Boolean);
return typeof limit === 'number' ? ids.slice(0, limit) : ids;
detail.value = {};
};
const toUrls = (val, limit) => {
return toIdList(val, limit).map((id) => `/bagl/mosty-base/minio/image/download/${id}`);
};
const noCrimeUrls = computed(() => toUrls(detail.value.noCrimeProof, 1));
const medicalUrls = computed(() => toUrls(detail.value.medicalReport, 1));
const idCardUrls = computed(() => toUrls(detail.value.idCardImages, 2));
defineExpose({ init })
</script>
<style lang="scss" scoped>
@import "@/assets/css/layout.scss";
.mapBox {
width: calc(100% - 24rem);
height: 500px;
@ -183,6 +149,7 @@ defineExpose({ init })
display: flex;
flex-direction: column;
gap: 10px;
z-index: 99999;
.tag_item{
width: 70px;
height: 70px;
@ -192,17 +159,17 @@ defineExpose({ init })
font-size: 16px;
margin-bottom: 20px;
}
.tag_item:nth-child(1){
.jtb_item{
border: 5px solid #FA3758;
color: #FA3758;
background: rgba(250,55,88,0.2);
}
.tag_item:nth-child(2){
.tgg_item{
color: #28EEBF;
background: rgba(40,238,191,0.2);
border: 5px solid #28EEBF;
}
.tag_item:nth-child(3){
.dsh_item{
background: rgba(0,114,255,0.2);
color: #0072FF;
border: 5px solid #0072FF;

View File

@ -1,6 +1,6 @@
<template>
<div>
<el-dialog class="steps-dialog" title="审核" v-model="dialogForm" :close-on-click-modal="false" @close="dialogForm = false" width="420px">
<el-dialog class="steps-dialog" title="审核" v-model="dialogForm" :close-on-click-modal="false" @close="dialogForm = false,formData = {}" width="420px">
<el-form :model="formData" ref="formRef" :rules="rules" label-width="120px">
<el-form-item label="是否通过" prop="auditStatus">
<el-radio-group v-model="formData.auditStatus">
@ -8,12 +8,12 @@
<el-radio label="0">不通过</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="驳回原因" prop="auditRemark" v-if="formData.auditStatus === '0'">
<el-input v-model="formData.auditRemark" type="textarea" placeholder="请输入驳回原因" :autosize="{ minRows: 2, maxRows: 4 }" />
<el-form-item label="驳回原因" prop="rejectReason" v-if="formData.auditStatus === '0'">
<el-input v-model="formData.rejectReason" type="textarea" placeholder="请输入驳回原因" :autosize="{ minRows: 2, maxRows: 4 }" />
</el-form-item>
<div class="flex just-center">
<el-button @click="dialogForm = false">取消</el-button>
<el-button type="primary" @click="submitForm">提交</el-button>
<el-button @click="dialogForm = false,formData = {}">取消</el-button>
<el-button type="primary" :loading="loading" @click="submitForm">提交</el-button>
</div>
</el-form>
</el-dialog>
@ -21,18 +21,43 @@
</template>
<script setup>
import { ref, defineExpose } from 'vue';
import { ElMessage } from "element-plus";
import { ref, defineExpose,defineEmits } from 'vue';
import { qcckPost } from "@/api/qcckApi.js";
const emit = defineEmits(['refresh'])
const dialogForm = ref(false);
const loading = ref(false)
const formData = ref({})
const rules = ref({
auditType: [{ required: true, message: '请选择审核类型', trigger: 'blur' }],
auditStatus: [{ required: true, message: '请选择是否通过', trigger: 'blur' }],
auditRemark: [{ required: true, message: '请输入驳回原因', trigger: 'blur' }],
rejectReason: [{ required: true, message: '请输入驳回原因', trigger: 'blur' }],
})
const init = (row) => {
formData.value = row
const formRef = ref();
const idsVal = ref([])
const init = (ids) => {
idsVal.value = ids;
dialogForm.value = true;
}
const submitForm = () =>{
formRef.value.validate((valid) => {
if (!valid) return;
loading.value = true;
// // 保安公司审核 - bakk 培训公司审核 -- pxgs 公安局审核 -- gongan
let params = { ...formData.value,ids:idsVal.value,auditType:'bakk' }
qcckPost(params,"/mosty-base/bans/njxx/batchAudit").then((res) => {
loading.value = false;
ElMessage.success("操作成功");
dialogForm.value = false;
formData.value={}
emit('refresh')
}).catch(()=>{
loading.value = false;
});
});
}
defineExpose({
init
})

View File

@ -3,7 +3,9 @@
<el-dialog class="steps-dialog" title="审核流程" v-model="dialogForm" width="420px">
<div class="steps-body">
<el-steps direction="vertical" :active="active" :space="90">
<el-step v-for="(item, idx) in steps" :key="item.title" :title="item.title" :description="idx === 0 ? item.time : ''" />
<el-step title="保安公司审核" :description="dataForm.bakkShsj || '未审核'" />
<el-step title="培训公司审核" :description="dataForm.pxgsShsj || '未审核'" />
<el-step title="公安局审核" :description="dataForm.gonganShsj || '未审核'" />
</el-steps>
</div>
</el-dialog>
@ -11,18 +13,19 @@
</template>
<script setup>
import { qcckPost } from "@/api/qcckApi.js";
import { ref, defineExpose } from 'vue';
const dialogForm = ref(false);
const pxgsData = ref()
const active = ref(1)
const steps = ref([
{ title: '保安公司审核', time: '2026-01-07 21:00' },
{ title: '培训公司审核', time: '2026-01-07 21:00' },
{ title: '公安局审核', time: '2026-01-07 21:00' },
])
const active = ref(0)
const dataForm = ref({})
const init = (row) => {
pxgsData.value = row
dialogForm.value = true;
let ids = [row.id]
qcckPost(ids,"/mosty-base/bans/njxx/getAuditStatusList").then(res=>{
dialogForm.value = true;
let obj = res ? res[0] : {};
dataForm.value = obj;
active.value = Number(obj.currentAuditStage) - 1;
})
}
defineExpose({
@ -102,4 +105,22 @@ defineExpose({
::v-deep .is-finish .el-step__icon{
background: #86b6f1;
}
::v-deep .el-dialog__close{
width: 30px;
height: 30px;
color: #fff;
svg{
width: 30px;
height: 30px;
}
}
::v-deep .el-dialog__headerbtn{
top: auto;
bottom: -60px;
border: 2px solid #fff;
color: #fff;
left: 50%;
transform: translateX(-50%);
border-radius: 50%;
}
</style>

View File

@ -1,7 +1,10 @@
<template>
<div>
<div class="titleBox">
<PageTitle title="保安员年检管理" />
<PageTitle title="保安员年检管理" >
<el-button type="primary" @click="onBatchAudit(selectedRows)">批量审核</el-button>
<el-button type="primary" @click="handleItemSp(selectedRows)">批量送培</el-button>
</PageTitle>
</div>
<!-- 搜索 -->
<div ref="searchBox">
@ -9,28 +12,27 @@
</div>
<!-- 表格 -->
<div class="tabBox">
<div style="margin-bottom: 12px;">
<el-button type="primary" @click="onBatchAudit">批量审核</el-button>
</div>
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth"
@chooseData="chooseData">
<template #auditStatus="{ row }">
<el-tag v-if="String(row.auditStatus || '').includes('驳回')" type="danger">{{ row.auditStatus }}</el-tag>
<el-tag v-else-if="String(row.auditStatus || '').includes('待')" type="warning">{{ row.auditStatus }}</el-tag>
<el-tag v-else-if="String(row.auditStatus || '').includes('通过')" type="success">{{ row.auditStatus }}</el-tag>
<span v-else>{{ row.auditStatus }}</span>
<template #whcd="{ row }">
<DictTag :value="row.whcd" :tag="false" :options="D_BZ_WHCD" />
</template>
<template #sendStatus="{ row }">
<el-tag v-if="String(row.sendStatus || '').includes('未')" type="info">{{ row.sendStatus }}</el-tag>
<el-tag v-else-if="String(row.sendStatus || '').includes('已')" type="success">{{ row.sendStatus }}</el-tag>
<span v-else>{{ row.sendStatus }}</span>
<template #fwxy="{ row }">
<DictTag :value="row.fwxy" :tag="false" :options="D_BAXX_SSHY" />
</template>
<template #bakkShzt="{ row }">
<DictTag :value="row.bakkShzt" :tag="false" :color="row.bakkShzt == 0 ? '#ff0000' : row.bakkShzt == 1 ? '#28EEBF' : '#FA3758'" :options="D_BA_SHZT" />
</template>
<template #sptz="{ row }">
<DictTag :value="row.sptz" :tag="false" :options="D_BA_SPZT" />
</template>
<!-- 操作 -->
<template #controls="{ row }">
<el-link type="primary" link @click="addEdit('shForm', row)">立即审核</el-link>
<!--currentAuditStage 当前审核阶段1-保安公司审核阶段2-培训公司审核阶段3-公安局审核阶段4-审核完成 -->
<el-link type="primary" link @click="onBatchAudit([row.id])" v-if="row.bakkShzt == 0">立即审核</el-link>
<el-link type="primary" link @click="addEdit('RefSteap', row)">审核流程</el-link>
<el-link type="primary" link @click="addEdit('sp', row)">送培</el-link>
<el-link type="primary" link @click="handleItemSp([row.id])" v-if="row.sptz == 0 && row.bakkShzt == 1">送培</el-link>
<el-link type="primary" link @click="addEdit('detail', row)">详情</el-link>
</template>
</MyTable>
@ -40,15 +42,16 @@
}"></Pages>
</div>
<!-- 详情 -->
<DetailForm ref="detailDiloag" :dict="{D_BZ_SF}"/>
<DetailForm ref="detailDiloag" :dic="{D_BZ_ZZMM,D_BZ_XB,D_BZ_MZ,D_BA_SHZT,D_BAXX_SSHY,D_BA_SPZT,D_BZ_WHCD}"/>
<!-- 审核流程 -->
<Steps ref="RefSteap" ></Steps>
<!-- 审核 -->
<ShForm ref="shForm" />
<ShForm ref="shForm" @refresh="getList" />
</div>
</template>
<script setup>
import { getItem } from "@/utils/storage";
import PageTitle from "@/components/aboutTable/PageTitle.vue";
import MyTable from "@/components/aboutTable/MyTable.vue";
import Pages from "@/components/aboutTable/Pages.vue";
@ -56,12 +59,12 @@ import Search from "@/components/aboutTable/Search.vue";
import DetailForm from "./components/detailForm.vue";
import Steps from "./components/steps.vue";
import ShForm from "./components/shForm.vue";
import {getItem} from '@/utils/storage.js'
import { cyryPage,njryPage} from "@/api/pxzx.js";
import { qcckPost } from "@/api/qcckApi.js";
import { reactive, ref, onMounted, getCurrentInstance, nextTick } from "vue";
import { ElMessage } from "element-plus";
const { proxy } = getCurrentInstance();
const { D_BZ_SF ,D_BAXX_DWLX} = proxy.$dict("D_BZ_SF","D_BAXX_DWLX");
const { D_BZ_ZZMM,D_BZ_XB,D_BZ_MZ,D_BA_SHZT,D_BAXX_SSHY,D_BA_SPZT,D_BZ_WHCD } = proxy.$dict('D_BZ_ZZMM','D_BZ_XB','D_BZ_MZ','D_BA_SHZT','D_BAXX_SSHY','D_BA_SPZT','D_BZ_WHCD');
const userInfo = getItem('userInfo');
const detailDiloag = ref();
const RefSteap = ref();
const shForm = ref();
@ -75,60 +78,36 @@ const searchConfiger = ref([
},
{
label: "身份证号码",
prop: "sfzh",
prop: "sfzhm",
showType: "input"
},
{
label: "电话",
prop: "lxdh",
prop: "dh",
showType: "input"
},
{
label: "审核状态",
prop: "shzt",
prop: "bakkShzt",
showType: "select",
placeholder: "不限",
clearable: true,
defaultVal: "",
options: [
{ label: "驳回", value: "驳回" },
{ label: "待审核", value: "待审核" },
{ label: "通过", value: "通过" }
]
options: D_BA_SHZT
},
{
label: "送培状态",
prop: "spzt",
prop: "sptz",
showType: "select",
placeholder: "不限",
clearable: true,
defaultVal: "",
options: [
{ label: "未送培", value: "未送培" },
{ label: "已送培", value: "已送培" }
]
options: D_BA_SPZT
}
]);
const idEntityCard=getItem('idEntityCard')
const queryFrom = ref({});
const pageData = reactive({
tableData: [
{
companyName: "保安公司名称",
reviewYear: "年审年份",
xm: "姓名",
sfzh: "身份证号码",
phone: "电话",
education: "文化程度",
certificateNo: "证书编号",
serviceIndustry: "服务行业",
entryDate: "入职时间",
workCardNo: "上岗证号码",
auditStatus: "审核状态",
auditTime: "审核时间",
sendStatus: "送培状态"
}
],
tableData: [],
keyCount: 0,
tableConfiger: {
rowHieght: 61,
@ -138,36 +117,35 @@ const pageData = reactive({
total: 0,
pageConfiger: {
pageSize: 20,
pageCurrent: 1
pageNum: 1
},
controlsWidth: 280,
tableColumn: [
{ label: "保安公司名称", prop: "companyName", width: 160, showOverflowTooltip: true },
{ label: "年审年份", prop: "reviewYear", width: 100 },
{ label: "姓名", prop: "xm", width: 100 },
{ label: "身份证号码", prop: "sfzh", width: 170, showOverflowTooltip: true },
{ label: "电话", prop: "phone", width: 120 },
{ label: "文化程度", prop: "education", width: 110 },
{ label: "证书编号", prop: "certificateNo", width: 140, showOverflowTooltip: true },
{ label: "服务行业", prop: "serviceIndustry", width: 110 },
{ label: "入职时间", prop: "entryDate", width: 120 },
{ label: "上岗证号码", prop: "workCardNo", width: 140, showOverflowTooltip: true },
{ label: "审核状态", prop: "auditStatus", width: 100, showSolt: true },
{ label: "审核时间", prop: "auditTime", width: 140 },
{ label: "送培状态", prop: "sendStatus", width: 100, showSolt: true }
{ label: "保安公司名称", prop: "ssbakk", showOverflowTooltip: true },
{ label: "年审年份", prop: "njnf" },
{ label: "姓名", prop: "xm" },
{ label: "身份证号码", prop: "sfzhm", showOverflowTooltip: true },
{ label: "电话", prop: "dh" },
{ label: "文化程度", prop: "whcd",showSolt: true },
{ label: "证书编号", prop: "zsbh", showOverflowTooltip: true },
{ label: "服务行业", prop: "fwxy", showSolt: true },
{ label: "入职时间", prop: "rzsj" },
{ label: "上岗证号码", prop: "sgxkhm", showOverflowTooltip: true },
{ label: "审核状态", prop: "bakkShzt", showSolt: true },
{ label: "审核时间", prop: "shsj" },
{ label: "送培状态", prop: "sptz", showSolt: true }
]
});
onMounted(() => {
// getInfo();
getList();
tabHeightFn();
});
// 搜索
const onSearch = (val) => {
queryFrom.value = { ...val };
pageData.pageConfiger.pageCurrent = 1;
pageData.pageConfiger.pageNum = 1;
getList();
};
const gsId=ref('')
const changeNo = (val) => {
pageData.pageConfiger.pageNum = val;
getList();
@ -176,74 +154,66 @@ const changeSize = (val) => {
pageData.pageConfiger.pageSize = val;
getList();
};
const getInfo = () => {
let promes = { sfzh: idEntityCard }
cyryPage(promes).then(res => {
const data = res.records[0] || {};
if (data) {
gsId.value=data.code
}
getList()
}).finally(() => {
pageData.tableConfiger.loading = false;
})
}
// 获取列表
const getList = () => {
pageData.tableConfiger.loading = true;
const promes = {
...pageData.pageConfiger,
...queryFrom.value,
dwbm: gsId.value
ssbakk:userInfo.pxgs,
ssbakkId:userInfo.pxgsid
}
njryPage(promes).then((res) => {
pageData.tableData = (res.records || []).map((item) => {
return {
...item,
companyName: item.companyName || item.dwmc || item.gsmc || item.dwmcName || item.bagsmc,
reviewYear: item.reviewYear || item.njnd || item.njYear || item.nf || item.year,
phone: item.phone || item.lxdh || item.dh || item.sjhm || item.xssbrdh,
education: item.education || item.whcd || item.whcdText,
certificateNo: item.certificateNo || item.zsbh || item.zsbhm || item.zjbh,
serviceIndustry: item.serviceIndustry || item.fwhy || item.fwhyText || item.hy,
entryDate: item.entryDate || item.rzsj || item.rzrq,
workCardNo: item.workCardNo || item.sgzh || item.sgzNumber,
auditStatus: item.auditStatus || item.shztText || item.shzt,
auditTime: item.auditTime || item.shsj || item.njsj,
sendStatus: item.sendStatus || item.spztText || item.spzt || (item.RefSteap ? "已送培" : "未送培")
};
});
qcckPost(promes,'/mosty-base/bans/njxx/page').then(res => {
pageData.tableData = res.records || [];
pageData.total = res.total;
}).catch((err) => {
console.log(err);
}).finally(() => {
pageData.tableConfiger.loading = false;
});
}).catch((err) => {
pageData.tableConfiger.loading = false;
})
};
const chooseData = (rows) => {
selectedRows.value = Array.isArray(rows) ? rows : [];
};
const onBatchAudit = () => {
if (!selectedRows.value.length) {
ElMessage.warning("请选择需要审核的数据");
return;
}
ElMessage.success("已选择 " + selectedRows.value.length + " 条");
const onBatchAudit = (valIds) => {
let ids = [];
valIds.forEach(id =>{
let obj = pageData.tableData.find(it=>it.id == id);
if(obj && obj.bakkShzt == 0) ids.push(id);
});
if (!ids.length) return ElMessage.warning("请选择未审核的数据!该数据再审核状态下不能操作!");
shForm.value.init(ids);
};
// 送培
const handleItemSp = (valIds) =>{
let ids = [];
valIds.forEach(id =>{
let obj = pageData.tableData.find(it=>it.id == id);
if(obj && obj.sptz == 0 && obj.bakkShzt == 1) ids.push(id);
});
if (!ids.length) return ElMessage.warning("请选择未送培的数据!该数据已送培!");
proxy.$modal.confirm("是否确认送培?").then(() => {
let params = {
ssbakk:userInfo.pxgs,
ssbakkId:userInfo.pxgsid,
ids:ids
}
qcckPost(params,'/mosty-base/bans/njxx/sendTraining').then(res=>{
getList()
ElMessage.success("送培成功");
})
});
}
// 详情
const addEdit = (type, row) => {
nextTick(() => {
if(type == 'RefSteap'){
RefSteap.value.init(row);
}else if(type == 'shForm'){
shForm.value.init(row);
}
else{
}else{
detailDiloag.value.init(type, row);
}
})

View File

@ -0,0 +1,100 @@
<template>
<div>
<el-dialog v-model="visible" title="批量送培" width="80%" @close="close">
<MyTable
:tableData="pageData.tableData"
:tableColumn="pageData.tableColumn"
:tableHeight="pageData.tableHeight"
:key="pageData.keyCount"
:tableConfiger="pageData.tableConfiger"
@chooseData="chooseData"
>
</MyTable>
<div class="flex just-center mt10">
<el-button type="primary" @click="close">取消</el-button>
<el-button type="primary" @click="onBatchAudit">确定</el-button>
</div>
</el-dialog>
</div>
</template>
<script setup>
import { ElMessage } from "element-plus";
import { getItem } from '@/utils/storage.js'
import { qcckPost } from "@/api/qcckApi.js";
import MyTable from "@/components/aboutTable/MyTable.vue";
import { ref , reactive , defineExpose , getCurrentInstance, defineEmits} from 'vue'
const userInfo = getItem('userInfo');
const emit = defineEmits(['refresh'])
const { proxy } = getCurrentInstance();
const visible = ref(false);
const pageData = reactive({
tableData: [],
keyCount: 0,
tableConfiger: {
rowHieght: 61,
showSelectType: "checkBox",
loading: false,
haveControls: false
},
tableHeight: 550,
tableColumn: [
{ label: "保安公司名称", prop: "ssbakk",showOverflowTooltip: true },
{ label: "年审年份", prop: "njnf"},
{ label: "姓名", prop: "xm" },
{ label: "身份证号码", prop: "sfzhm",showOverflowTooltip: true },
{ label: "电话", prop: "dh" },
{ label: "文化程度", prop: "whcd" },
{ label: "证书编号", prop: "zsbh", showOverflowTooltip: true },
{ label: "服务行业", prop: "fwxymc" },
{ label: "入职时间", prop: "rzsj" },
{ label: "上岗证号码", prop: "sgxkhm", showOverflowTooltip: true },
]
});
const ids = ref([])
const chooseData = (rows) => {
ids.value = Array.isArray(rows) ? rows.map(item => item.id) : [];
};
const init = () => {
pageData.tableConfiger.loading = true;
pageData.keyCount++;
visible.value = true;
let promes = {
pageNum:1,
pageSize:9999,
ssbakk:userInfo.pxgs,
ssbakkId:userInfo.pxgsid,
sptz:0
}
qcckPost(promes,'/mosty-base/bans/njxx/listForSendTraining').then((res) => {
pageData.tableData = res.records || []
pageData.tableConfiger.loading = false;
}).catch((err) => {
pageData.tableConfiger.loading = false;
})
}
const onBatchAudit = () => {
if (ids.value.length === 0) return ElMessage.warning("请选择要送培的人员");
proxy.$modal.confirm("是否确认送培?").then(() => {
let params = { ssbakk:userInfo.pxgs, ssbakkId:userInfo.pxgsid, ids:ids.value }
qcckPost(params,'/mosty-base/bans/njxx/sendTraining').then(res=>{
ElMessage.success("送培成功");
emit('refresh');
close();
})
});
}
const close = () => {
visible.value = false;
ids.value = [];
pageData.tableData = []
}
defineExpose({
init
})
</script>
<style scoped lang="scss">
</style>

View File

@ -7,75 +7,80 @@
<div class="cntinfo">
<!-- 标签 -->
<ul class="tag-box">
<li class="tag_item">驳回</li>
<li class="tag_item">通过</li>
<li class="tag_item">待审核</li>
<li class="tag_item" :class="detail.pxgsShzt == 0 ? 'dsh_item' : detail.pxgsShzt == 1 ? 'tgg_item' : 'jtb_item'">
<!-- 0-待审核 1-通过 2-驳回 -->
{{ detail.pxgsShzt == 0 ? '待审核' : detail.pxgsShzt == 1 ? '通过' : '驳回' }}
</li>
</ul>
<!-- 内容描述 -->
<el-descriptions class="desc" :column="3" border label-width="200px">
<el-descriptions-item label="保安公司名称">{{ detail.companyName }}</el-descriptions-item>
<el-descriptions-item label="年审年份">{{ detail.reviewYear }}</el-descriptions-item>
<el-descriptions-item label="保安公司名称">{{ detail.ssbakk }}</el-descriptions-item>
<el-descriptions-item label="年审年份">{{ detail.njnf }}</el-descriptions-item>
<el-descriptions-item label="姓名">{{ detail.xm }}</el-descriptions-item>
<el-descriptions-item label="身份证号码">{{ detail.sfzh }}</el-descriptions-item>
<el-descriptions-item label="电话">{{ detail.phone }}</el-descriptions-item>
<el-descriptions-item label="性别">{{ detail.sexText }}</el-descriptions-item>
<el-descriptions-item label="身份证号码">{{ detail.sfzhm }}</el-descriptions-item>
<el-descriptions-item label="电话">{{ detail.dh }}</el-descriptions-item>
<el-descriptions-item label="性别">
<DictTag :value="detail.xb" :tag="false" :options="props.dic.D_BZ_XB" />
</el-descriptions-item>
<el-descriptions-item label="民族">
<DictTag :value="detail.mz" :tag="false" :options="props.dic.D_BZ_MZ" />
</el-descriptions-item>
<el-descriptions-item label="籍贯">{{ detail.jg }}</el-descriptions-item>
<el-descriptions-item label="文化程度">
<DictTag :value="detail.whcd" :tag="false" :options="props.dic.D_BZ_WHCD" />
</el-descriptions-item>
<el-descriptions-item label="民族">{{ detail.nationText }}</el-descriptions-item>
<el-descriptions-item label="籍贯">{{ detail.nativePlace }}</el-descriptions-item>
<el-descriptions-item label="文化程度">{{ detail.education }}</el-descriptions-item>
<el-descriptions-item label="证书编号">{{ detail.zsbh }}</el-descriptions-item>
<el-descriptions-item label="上岗证号码">{{ detail.sgxkhm }}</el-descriptions-item>
<el-descriptions-item label="服务行业">
<DictTag :value="detail.fwxy" :tag="false" :options="props.dic.D_BAXX_SSHY" />
</el-descriptions-item>
<el-descriptions-item label="证书编号">{{ detail.certificateNo }}</el-descriptions-item>
<el-descriptions-item label="上岗证号码">{{ detail.workCardNo }}</el-descriptions-item>
<el-descriptions-item label="服务行业">{{ detail.serviceIndustry }}</el-descriptions-item>
<el-descriptions-item label="服务行业名称">{{ detail.serviceIndustryName }}</el-descriptions-item>
<el-descriptions-item label="入职时间">{{ detail.entryDate }}</el-descriptions-item>
<el-descriptions-item label="政治面貌">{{ detail.politicalStatus }}</el-descriptions-item>
<el-descriptions-item label="服务行业名称">{{ detail.fwxymc }}</el-descriptions-item>
<el-descriptions-item label="入职时间">{{ detail.rzsj }}</el-descriptions-item>
<el-descriptions-item label="政治面貌">
<DictTag :value="detail.zzmm" :tag="false" :options="props.dic.D_BZ_ZZMM" />
</el-descriptions-item>
<el-descriptions-item label="无犯罪记录证明">
<div class="img-grid one">
<el-image
v-for="(src, idx) in noCrimeUrls"
:key="idx"
:src="src"
:src="baseUrl + detail.wfbjlzm"
fit="cover"
:preview-src-list="noCrimeUrls"
:preview-src-list='[baseUrl + detail.wfbjlzm]'
preview-teleported
class="img"
/>
<div v-if="noCrimeUrls.length === 0" class="img-placeholder"></div>
</div>
</el-descriptions-item>
<el-descriptions-item label="体检报告">
<div class="img-grid one">
<el-image
v-for="(src, idx) in medicalUrls"
:key="idx"
:src="src"
:src="baseUrl + detail.tjbg"
fit="cover"
:preview-src-list="medicalUrls"
:preview-src-list='[baseUrl + detail.tjbg]'
preview-teleported
class="img"
/>
<div v-if="medicalUrls.length === 0" class="img-placeholder"></div>
</div>
</el-descriptions-item>
<el-descriptions-item label="身份证正反面">
<div class="img-grid two">
<el-image
v-for="(src, idx) in idCardUrls"
:key="idx"
:src="src"
<el-image
:src="baseUrl + detail.sfzzm"
fit="cover"
:preview-src-list="idCardUrls"
:preview-src-list='[baseUrl + detail.sfzzm]'
preview-teleported
class="img"
/>
<el-image
:src="baseUrl + detail.sfzfm"
fit="cover"
:preview-src-list='[baseUrl + detail.sfzfm]'
preview-teleported
class="img"
/>
<template v-if="idCardUrls.length === 0">
<div class="img-placeholder"></div>
<div class="img-placeholder"></div>
</template>
</div>
</el-descriptions-item>
@ -90,45 +95,29 @@
</template>
<script setup>
import { ref, computed, defineEmits, getCurrentInstance } from 'vue';
import { ref, defineEmits } from 'vue';
const emit = defineEmits(["refresh"]);
const { proxy } = getCurrentInstance();
const baseUrl = '/bagl/mosty-base/minio/image/download'
const props = defineProps({
dict: {
dic: {
default: [[]], //二维数组
type: Array
}
})
const dialogForm = ref(false);
const listQuery = ref({});
const detail = ref({})
// 初始化数据
const init = (type, row,) => {
dialogForm.value = true;
const raw = row || {};
listQuery.value = {
...raw,
companyName: raw.companyName || raw.dwmc || raw.gsmc || raw.bagsmc,
reviewYear: raw.reviewYear || raw.njnd || raw.njYear || raw.nf || raw.year,
phone: raw.phone || raw.lxdh || raw.dh || raw.sjhm || raw.xssbrdh,
sexText: raw.sexText || raw.xbText || raw.xb || raw.sex,
nationText: raw.nationText || raw.mzText || raw.mz,
nativePlace: raw.nativePlace || raw.jg || raw.jgText,
education: raw.education || raw.whcd || raw.whcdText,
certificateNo: raw.certificateNo || raw.zsbh || raw.zsbhm || raw.zjbh,
workCardNo: raw.workCardNo || raw.sgzh || raw.sgzNumber,
serviceIndustry: raw.serviceIndustry || raw.fwhy || raw.fwhyText || raw.hy,
serviceIndustryName: raw.serviceIndustryName || raw.fwhymc || raw.hyName,
entryDate: raw.entryDate || raw.rzsj || raw.rzrq,
politicalStatus: raw.politicalStatus || raw.zzmm || raw.zzmmText,
auditTime: raw.auditTime || raw.shsj || raw.njsj,
rejectReason: raw.rejectReason || raw.bhyy || raw.bhReason || raw.reason,
issuingAuthority: raw.issuingAuthority || raw.fzjg,
issueDate: raw.issueDate || raw.fzrq,
noCrimeProof: raw.noCrimeProof || raw.wffzjlzm || raw.wffzjlzmId,
medicalReport: raw.medicalReport || raw.tjbg || raw.tjbgId,
idCardImages: raw.idCardImages || raw.sfzzf || raw.sfzImgs || raw.sfzzm,
};
let obj = JSON.parse(JSON.stringify(row));
let zj = obj.sfzzfmj.split(',');
obj.sfzzm = [zj[0]];
obj.sfzfm = [zj[1]];
setTimeout(() => {
detail.value = obj;
}, 1000);
};
const close = () => {
@ -136,29 +125,6 @@ const close = () => {
listQuery.value = {};
};;
const detail = computed(() => listQuery.value || {});
const toIdList = (val, limit) => {
const v = val ?? [];
const arr = Array.isArray(v) ? v : [v];
const ids = arr
.map((el) => {
if (!el) return null;
if (typeof el === 'string' || typeof el === 'number') return String(el);
if (typeof el === 'object') return el.id ? String(el.id) : null;
return null;
})
.filter(Boolean);
return typeof limit === 'number' ? ids.slice(0, limit) : ids;
};
const toUrls = (val, limit) => {
return toIdList(val, limit).map((id) => `/bagl/mosty-base/minio/image/download/${id}`);
};
const noCrimeUrls = computed(() => toUrls(detail.value.noCrimeProof, 1));
const medicalUrls = computed(() => toUrls(detail.value.medicalReport, 1));
const idCardUrls = computed(() => toUrls(detail.value.idCardImages, 2));
defineExpose({ init })
</script>
@ -192,17 +158,17 @@ defineExpose({ init })
font-size: 16px;
margin-bottom: 20px;
}
.tag_item:nth-child(1){
.jtb_item{
border: 5px solid #FA3758;
color: #FA3758;
background: rgba(250,55,88,0.2);
}
.tag_item:nth-child(2){
.tgg_item{
color: #28EEBF;
background: rgba(40,238,191,0.2);
border: 5px solid #28EEBF;
}
.tag_item:nth-child(3){
.dsh_item{
background: rgba(0,114,255,0.2);
color: #0072FF;
border: 5px solid #0072FF;

View File

@ -3,7 +3,9 @@
<el-dialog class="steps-dialog" title="审核流程" v-model="dialogForm" width="420px">
<div class="steps-body">
<el-steps direction="vertical" :active="active" :space="90">
<el-step v-for="(item, idx) in steps" :key="item.title" :title="item.title" :description="idx === 0 ? item.time : ''" />
<el-step title="保安公司审核" :description="dataForm.bakkShsj || '未审核'" />
<el-step title="培训公司审核" :description="dataForm.pxgsShsj || '未审核'" />
<el-step title="公安局审核" :description="dataForm.gonganShsj || '未审核'" />
</el-steps>
</div>
</el-dialog>
@ -11,18 +13,19 @@
</template>
<script setup>
import { qcckPost } from "@/api/qcckApi.js";
import { ref, defineExpose } from 'vue';
const dialogForm = ref(false);
const pxgsData = ref()
const active = ref(1)
const steps = ref([
{ title: '保安公司审核', time: '2026-01-07 21:00' },
{ title: '培训公司审核', time: '2026-01-07 21:00' },
{ title: '公安局审核', time: '2026-01-07 21:00' },
])
const dataForm = ref({})
const init = (row) => {
pxgsData.value = row
dialogForm.value = true;
let ids = [row.id]
qcckPost(ids,"/mosty-base/bans/njxx/getAuditStatusList").then(res=>{
dialogForm.value = true;
let obj = res ? res[0] : {};
dataForm.value = obj;
active.value = Number(obj.currentAuditStage) - 1;
})
}
defineExpose({

View File

@ -2,7 +2,7 @@
<div>
<div class="titleBox">
<PageTitle title="保安员年检送培">
<el-button type="primary" @click="onBatchAudit">新增</el-button>
<el-button type="primary" @click="onBatchAudit">批量送培</el-button>
</PageTitle>
</div>
<!-- 搜索 -->
@ -11,26 +11,15 @@
</div>
<!-- 表格 -->
<div class="tabBox">
<div style="margin-bottom: 12px;">
<el-button type="primary" @click="onBatchAudit">批量审核</el-button>
</div>
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth"
@chooseData="chooseData">
<template #auditStatus="{ row }">
<el-tag v-if="String(row.auditStatus || '').includes('驳回')" type="danger">{{ row.auditStatus }}</el-tag>
<el-tag v-else-if="String(row.auditStatus || '').includes('待')" type="warning">{{ row.auditStatus }}</el-tag>
<el-tag v-else-if="String(row.auditStatus || '').includes('通过')" type="success">{{ row.auditStatus }}</el-tag>
<span v-else>{{ row.auditStatus }}</span>
</template>
<template #sendStatus="{ row }">
<el-tag v-if="String(row.sendStatus || '').includes('未')" type="info">{{ row.sendStatus }}</el-tag>
<el-tag v-else-if="String(row.sendStatus || '').includes('已')" type="success">{{ row.sendStatus }}</el-tag>
<span v-else>{{ row.sendStatus }}</span>
<template #sptz="{ row }">
<DictTag :value="row.sptz" :tag="false" :options="D_BA_SPZT" />
</template>
<!-- 操作 -->
<template #controls="{ row }">
<el-link type="primary" link @click="addEdit('RefSteap', row)">审核流程</el-link>
<el-link type="primary" link @click="addEdit('sh', row)">审核流程</el-link>
<el-link type="primary" link @click="addEdit('detail', row)">详情</el-link>
</template>
</MyTable>
@ -40,9 +29,11 @@
}"></Pages>
</div>
<!-- 详情 -->
<DetailForm ref="detailDiloag" :dict="{D_BZ_SF}"/>
<DetailForm ref="detailDiloag" :dic="{ D_BZ_ZZMM,D_BZ_XB,D_BZ_MZ,D_BA_SHZT,D_BAXX_SSHY,D_BA_SPZT,D_BZ_WHCD }"/>
<!-- 审核流程 -->
<Steps ref="RefSteap" ></Steps>
<!-- 送培 -->
<AddSp ref="addSpDiloag" @refresh="getList" />
</div>
</template>
@ -53,14 +44,16 @@ import Pages from "@/components/aboutTable/Pages.vue";
import Search from "@/components/aboutTable/Search.vue";
import DetailForm from "./components/detailForm.vue";
import Steps from "./components/steps.vue";
import AddSp from "./components/addSp.vue";
import {getItem} from '@/utils/storage.js'
import { cyryPage,njryPage} from "@/api/pxzx.js";
import { qcckPost } from "@/api/qcckApi.js";
import { reactive, ref, onMounted, getCurrentInstance, nextTick } from "vue";
import { ElMessage } from "element-plus";
const userInfo = getItem('userInfo');
const { proxy } = getCurrentInstance();
const { D_BZ_SF ,D_BAXX_DWLX} = proxy.$dict("D_BZ_SF","D_BAXX_DWLX");
const { D_BZ_ZZMM,D_BZ_XB,D_BZ_MZ,D_BA_SHZT,D_BAXX_SSHY,D_BA_SPZT,D_BZ_WHCD } = proxy.$dict('D_BZ_ZZMM','D_BZ_XB','D_BZ_MZ','D_BA_SHZT','D_BAXX_SSHY','D_BA_SPZT','D_BZ_WHCD');
const detailDiloag = ref();
const RefSteap = ref();
const addSpDiloag = ref();
const shForm = ref();
const searchBox = ref(); //搜索框
const selectedRows = ref([]);
@ -72,35 +65,18 @@ const searchConfiger = ref([
},
{
label: "身份证号码",
prop: "sfzh",
prop: "sfzhm",
showType: "input"
},
{
label: "电话",
prop: "lxdh",
prop: "dh",
showType: "input"
},
]);
const idEntityCard=getItem('idEntityCard')
const queryFrom = ref({});
const pageData = reactive({
tableData: [
{
companyName: "保安公司名称",
reviewYear: "年审年份",
xm: "姓名",
sfzh: "身份证号码",
phone: "电话",
education: "文化程度",
certificateNo: "证书编号",
serviceIndustry: "服务行业",
entryDate: "入职时间",
workCardNo: "上岗证号码",
auditStatus: "审核状态",
auditTime: "审核时间",
sendStatus: "送培状态"
}
],
tableData: [],
keyCount: 0,
tableConfiger: {
rowHieght: 61,
@ -110,35 +86,34 @@ const pageData = reactive({
total: 0,
pageConfiger: {
pageSize: 20,
pageCurrent: 1
pageNum: 1
},
controlsWidth: 180,
tableColumn: [
{ label: "保安公司名称", prop: "companyName",showOverflowTooltip: true },
{ label: "培训公司", prop: "pxgs", showOverflowTooltip: true },
{ label: "年审年份", prop: "reviewYear"},
{ label: "保安公司名称", prop: "ssbakk",showOverflowTooltip: true },
{ label: "培训公司", prop: "sptzCompanyName", showOverflowTooltip: true },
{ label: "年审年份", prop: "njnf"},
{ label: "姓名", prop: "xm" },
{ label: "身份证号码", prop: "sfzh",showOverflowTooltip: true },
{ label: "电话", prop: "phone" },
{ label: "文化程度", prop: "education" },
{ label: "证书编号", prop: "certificateNo", showOverflowTooltip: true },
{ label: "服务行业", prop: "serviceIndustry" },
{ label: "入职时间", prop: "entryDate" },
{ label: "上岗证号码", prop: "workCardNo", showOverflowTooltip: true },
{ label: "送培状态", prop: "sendStatus", showSolt: true }
{ label: "身份证号码", prop: "sfzhm",showOverflowTooltip: true },
{ label: "电话", prop: "dh" },
{ label: "文化程度", prop: "whcd" },
{ label: "证书编号", prop: "zsbh", showOverflowTooltip: true },
{ label: "服务行业", prop: "fwxymc" },
{ label: "入职时间", prop: "rzsj" },
{ label: "上岗证号码", prop: "sgxkhm", showOverflowTooltip: true },
{ label: "送培状态", prop: "sptz", showSolt: true }
]
});
onMounted(() => {
// getInfo();
getList();
tabHeightFn();
});
// 搜索
const onSearch = (val) => {
queryFrom.value = { ...val };
pageData.pageConfiger.pageCurrent = 1;
pageData.pageConfiger.pageNum = 1;
getList();
};
const gsId=ref('')
const changeNo = (val) => {
pageData.pageConfiger.pageNum = val;
getList();
@ -147,50 +122,22 @@ const changeSize = (val) => {
pageData.pageConfiger.pageSize = val;
getList();
};
const getInfo = () => {
let promes = { sfzh: idEntityCard }
cyryPage(promes).then(res => {
const data = res.records[0] || {};
if (data) {
gsId.value=data.code
}
getList()
}).finally(() => {
pageData.tableConfiger.loading = false;
})
}
// 获取列表
const getList = () => {
pageData.tableConfiger.loading = true;
const promes = {
...pageData.pageConfiger,
...queryFrom.value,
dwbm: gsId.value
ssbakk:userInfo.pxgs,
ssbakkId:userInfo.pxgsid
}
njryPage(promes).then((res) => {
pageData.tableData = (res.records || []).map((item) => {
return {
...item,
companyName: item.companyName || item.dwmc || item.gsmc || item.dwmcName || item.bagsmc,
reviewYear: item.reviewYear || item.njnd || item.njYear || item.nf || item.year,
phone: item.phone || item.lxdh || item.dh || item.sjhm || item.xssbrdh,
education: item.education || item.whcd || item.whcdText,
certificateNo: item.certificateNo || item.zsbh || item.zsbhm || item.zjbh,
serviceIndustry: item.serviceIndustry || item.fwhy || item.fwhyText || item.hy,
entryDate: item.entryDate || item.rzsj || item.rzrq,
workCardNo: item.workCardNo || item.sgzh || item.sgzNumber,
auditStatus: item.auditStatus || item.shztText || item.shzt,
auditTime: item.auditTime || item.shsj || item.njsj,
sendStatus: item.sendStatus || item.spztText || item.spzt || (item.RefSteap ? "已送培" : "未送培")
};
});
qcckPost(promes,'/mosty-base/bans/njxx/listForSendTraining').then((res) => {
pageData.tableData = res.records || []
pageData.total = res.total;
pageData.tableConfiger.loading = false;
}).catch((err) => {
console.log(err);
}).finally(() => {
pageData.tableConfiger.loading = false;
});
pageData.tableConfiger.loading = false;
})
};
const chooseData = (rows) => {
@ -198,19 +145,15 @@ const chooseData = (rows) => {
};
const onBatchAudit = () => {
if (!selectedRows.value.length) {
ElMessage.warning("请选择需要审核的数据");
return;
}
ElMessage.success("已选择 " + selectedRows.value.length + " 条");
addSpDiloag.value.init();
};
// 详情
const addEdit = (type, row) => {
nextTick(() => {
if(type == 'RefSteap'){
RefSteap.value.init(row);
if(type == 'sh'){
addSpDiloag.value.init(row);
}else if(type == 'shForm'){
shForm.value.init(row);
}

View File

@ -0,0 +1,210 @@
<template>
<div class="dialog" v-if="dialogForm">
<div class="head_box">
<span>详情</span>
<div><el-button size="small" @click="close">关闭</el-button></div>
</div>
<div class="cntinfo">
<!-- 标签 -->
<ul class="tag-box">
<li class="tag_item" :class="detail.shzt == 0 ? 'dsh_item' : detail.shzt == 1 ? 'tgg_item' : 'jtb_item'">
<!-- 0-待审核 1-通过 2-驳回 -->
{{ detail.shzt == 0 ? '待审核' : detail.shzt == 1 ? '通过' : '驳回' }}
</li>
</ul>
<!-- 内容描述 -->
<el-descriptions class="desc" :column="3" border label-width="200px">
<el-descriptions-item label="保安公司名称">{{ detail.ssbakk }}</el-descriptions-item>
<el-descriptions-item label="年审年份">{{ detail.njnf }}</el-descriptions-item>
<el-descriptions-item label="姓名">{{ detail.xm }}</el-descriptions-item>
<el-descriptions-item label="身份证号码">{{ detail.sfzhm }}</el-descriptions-item>
<el-descriptions-item label="年龄">{{ detail.nl }}</el-descriptions-item>
<el-descriptions-item label="电话">{{ detail.dh }}</el-descriptions-item>
<el-descriptions-item label="性别">
<DictTag :value="detail.xb" :tag="false" :options="props.dic.D_BZ_XB" />
</el-descriptions-item>
<el-descriptions-item label="民族">
<DictTag :value="detail.mz" :tag="false" :options="props.dic.D_BZ_MZ" />
</el-descriptions-item>
<el-descriptions-item label="籍贯">{{ detail.jg }}</el-descriptions-item>
<el-descriptions-item label="文化程度">
<DictTag :value="detail.whcd" :tag="false" :options="props.dic.D_BZ_WHCD" />
</el-descriptions-item>
<el-descriptions-item label="证书编号">{{ detail.zsbh }}</el-descriptions-item>
<el-descriptions-item label="上岗证号码">{{ detail.sgxkhm }}</el-descriptions-item>
<el-descriptions-item label="服务行业">
<DictTag :value="detail.fwxy" :tag="false" :options="props.dic.D_BAXX_SSHY" />
</el-descriptions-item>
<el-descriptions-item label="服务行业名称">{{ detail.fwxymc }}</el-descriptions-item>
<el-descriptions-item label="入职时间">{{ detail.rzsj }}</el-descriptions-item>
<el-descriptions-item label="政治面貌">
<DictTag :value="detail.zzmm" :tag="false" :options="props.dic.D_BZ_ZZMM" />
</el-descriptions-item>
<el-descriptions-item label="无犯罪记录证明">
<div class="img-grid one">
<el-image
:src="baseUrl + detail.wfbjlzm"
fit="cover"
:preview-src-list='[baseUrl + detail.wfbjlzm]'
preview-teleported
class="img"
/>
</div>
</el-descriptions-item>
<el-descriptions-item label="体检报告">
<div class="img-grid one">
<el-image
:src="baseUrl + detail.tjbg"
fit="cover"
:preview-src-list='[baseUrl + detail.tjbg]'
preview-teleported
class="img"
/>
</div>
</el-descriptions-item>
<el-descriptions-item label="身份证正反面">
<div class="img-grid two">
<el-image
:src="baseUrl + detail.sfzzm"
fit="cover"
:preview-src-list='[baseUrl + detail.sfzzm]'
preview-teleported
class="img"
/>
<el-image
:src="baseUrl + detail.sfzfm"
fit="cover"
:preview-src-list='[baseUrl + detail.sfzfm]'
preview-teleported
class="img"
/>
</div>
</el-descriptions-item>
<el-descriptions-item label="审核时间">{{ detail.auditTime }}</el-descriptions-item>
<el-descriptions-item label="发证机关">{{ detail.issuingAuthority }}</el-descriptions-item>
<el-descriptions-item label="发证日期">{{ detail.issueDate }}</el-descriptions-item>
<el-descriptions-item label="驳回原因" :span="3">{{ detail.rejectReason }}</el-descriptions-item>
</el-descriptions>
</div>
</div>
</template>
<script setup>
import { ref, computed, defineEmits, getCurrentInstance,defineProps } from 'vue';
import { qcckPost } from "@/api/qcckApi.js";
const emit = defineEmits(["refresh"]);
const { proxy } = getCurrentInstance();
const baseUrl = '/bagl/mosty-base/minio/image/download'
const props = defineProps({
dic: {
default: [[]], //二维数组
type: Array
}
})
const dialogForm = ref(false);
const detail = ref({})
// 初始化数据
const init = (type, row,) => {
dialogForm.value = true;
qcckPost({},'/mosty-base/bans/njxx/getInfo/'+row.id).then(res => {
let zj = res.sfzzfmj.split(',');
res.sfzzm = [zj[0]];
res.sfzfm = [zj[1]];
detail.value = res || {};
})
};
const close = () => {
dialogForm.value = false;
detail.value = {};
};
defineExpose({ init })
</script>
<style lang="scss" scoped>
@import "@/assets/css/layout.scss";
.mapBox {
width: calc(100% - 24rem);
height: 500px;
overflow: hidden;
margin: 0 12rem;
}
.cntinfo{
position: relative;
padding: 10px 20px;
box-sizing: border-box;
.tag-box{
position: absolute;
top: 20px;
right: 50px;
display: flex;
flex-direction: column;
gap: 10px;
z-index: 99999;
.tag_item{
width: 70px;
height: 70px;
border-radius: 50%;
line-height: 65px;
text-align: center;
font-size: 16px;
margin-bottom: 20px;
}
.jtb_item{
border: 5px solid #FA3758;
color: #FA3758;
background: rgba(250,55,88,0.2);
}
.tgg_item{
color: #28EEBF;
background: rgba(40,238,191,0.2);
border: 5px solid #28EEBF;
}
.dsh_item{
background: rgba(0,114,255,0.2);
color: #0072FF;
border: 5px solid #0072FF;
}
}
}
.desc {
width: 100%;
}
.img-grid {
display: flex;
align-items: center;
gap: 10px;
min-height: 70px;
}
.img-grid.one .img,
.img-grid.one .img-placeholder {
width: 64px;
height: 64px;
}
.img-grid.two .img,
.img-grid.two .img-placeholder {
width: 64px;
height: 64px;
}
.img-placeholder {
background: #d9d9d9;
border-radius: 2px;
}
::v-deep .el-descriptions__label.el-descriptions__cell.is-bordered-label{
background: #F6FAFF;
}
</style>

View File

@ -0,0 +1,105 @@
<template>
<div>
<el-dialog class="steps-dialog" title="审核流程" v-model="dialogForm" width="420px">
<div class="steps-body">
<el-steps direction="vertical" :active="active" :space="90">
<el-step v-for="(item, idx) in steps" :key="item.title" :title="item.title" :description="idx === 0 ? item.time : ''" />
</el-steps>
</div>
</el-dialog>
</div>
</template>
<script setup>
import { ref, defineExpose } from 'vue';
const dialogForm = ref(false);
const pxgsData = ref()
const active = ref(1)
const steps = ref([
{ title: '保安公司审核', time: '2026-01-07 21:00' },
{ title: '培训公司审核', time: '2026-01-07 21:00' },
{ title: '公安局审核', time: '2026-01-07 21:00' },
])
const init = (row) => {
pxgsData.value = row
dialogForm.value = true;
}
defineExpose({
init
})
</script>
<style scoped lang="scss">
.steps-body {
height: 260px;
padding: 6px 10px 10px;
box-sizing: border-box;
}
:deep(.steps-dialog .el-dialog__header) {
text-align: center;
padding: 20px 20px 10px;
}
:deep(.steps-dialog .el-dialog__title) {
font-size: 24px;
font-weight: 700;
color: #333;
}
:deep(.steps-dialog .el-dialog__body) {
padding: 0 20px 20px;
}
:deep(.steps-dialog .el-step__title) {
font-size: 18px;
font-weight: 600;
color: #333;
line-height: 22px;
}
:deep(.steps-dialog .el-step__description) {
font-size: 16px;
color: #9AA8B6;
line-height: 20px;
margin-top: 8px;
}
:deep(.steps-dialog .el-step__line) {
left: 8px;
background-color: transparent;
border-left: 1px dashed #dadada;
}
:deep(.steps-dialog .el-step.is-vertical .el-step__head) {
width: 24px;
}
:deep(.steps-dialog .el-step__icon) {
width: 16px;
height: 16px;
border-radius: 50%;
}
:deep(.steps-dialog .el-step__head.is-process .el-step__icon),
:deep(.steps-dialog .el-step__head.is-process .el-step__icon.is-text) {
background: #2e6bff;
border: none;
box-shadow: 0 0 0 5px rgba(46, 107, 255, 0.15);
}
:deep(.steps-dialog .el-step.is-wait .el-step__icon),
:deep(.steps-dialog .el-step.is-finish .el-step__icon) {
background: #fff;
border: 1px solid #dadada;
box-shadow: none;
}
:deep(.steps-dialog .el-step__icon-inner) {
display: none;
}
::v-deep .is-finish .el-step__icon{
background: #86b6f1;
}
</style>

View File

@ -0,0 +1,182 @@
<template>
<div>
<div class="titleBox">
<PageTitle title="公司保安员年检管理">
<el-button type="primary" @click="onBatchAudit(selectedRows)">批量审核</el-button>
</PageTitle>
</div>
<!-- 搜索 -->
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch" :key="pageData.keyCount" />
</div>
<!-- 表格 -->
<div class="tabBox">
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth"
@chooseData="chooseData">
<!-- 操作 -->
<template #controls="{ row }">
<el-link type="primary" link @click="onBatchAudit([row.id])" v-if="row.pxgsShzt == 0">立即审核</el-link>
<el-link type="primary" link @click="addEdit('RefSteap', row)">审核流程</el-link>
<el-link type="primary" link @click="addEdit('detail', row)">详情</el-link>
</template>
</MyTable>
<Pages @changeNo="changeNo" @changeSize="changeSize" :tableHeight="pageData.tableHeight" :pageConfiger="{
...pageData.pageConfiger,
total: pageData.total
}"></Pages>
</div>
<!-- 详情 -->
<DetailForm ref="detailDiloag" :dict="{D_BZ_ZZMM,D_BZ_XB,D_BZ_MZ,D_BA_SHZT,D_BAXX_SSHY,D_BA_SPZT,D_BZ_WHCD}"/>
<!-- 审核流程 -->
<Steps ref="RefSteap" ></Steps>
</div>
</template>
<script setup>
import PageTitle from "@/components/aboutTable/PageTitle.vue";
import MyTable from "@/components/aboutTable/MyTable.vue";
import Pages from "@/components/aboutTable/Pages.vue";
import Search from "@/components/aboutTable/Search.vue";
import DetailForm from "./components/detailForm.vue";
import Steps from "./components/steps.vue";
import {getItem} from '@/utils/storage.js'
import { qcckPost } from "@/api/qcckApi.js";
import { reactive, ref, onMounted, getCurrentInstance, nextTick } from "vue";
import { ElMessage } from "element-plus";
const { proxy } = getCurrentInstance();
const { D_BZ_ZZMM,D_BZ_XB,D_BZ_MZ,D_BA_SHZT,D_BAXX_SSHY,D_BA_SPZT,D_BZ_WHCD } = proxy.$dict('D_BZ_ZZMM','D_BZ_XB','D_BZ_MZ','D_BA_SHZT','D_BAXX_SSHY','D_BA_SPZT','D_BZ_WHCD');
const userInfo = getItem('userInfo');
const detailDiloag = ref();
const RefSteap = ref();
const shForm = ref();
const searchBox = ref(); //搜索框
const selectedRows = ref([]);
const searchConfiger = ref([
{
label: "保安公司名称",
prop: "ssbakk",
showType: "input"
},
{
label: "姓名",
prop: "xm",
showType: "input"
},
{
label: "身份证号码",
prop: "sfzhm",
showType: "input"
},
{
label: "电话",
prop: "dh",
showType: "input"
},
]);
const queryFrom = ref({});
const pageData = reactive({
tableData: [],
keyCount: 0,
tableConfiger: {
rowHieght: 61,
showSelectType: "checkBox",
loading: false
},
total: 0,
pageConfiger: {
pageSize: 20,
pageNum: 1
},
controlsWidth: 180,
tableColumn: [
{ label: "保安公司名称", prop: "ssbakk",showOverflowTooltip: true },
{ label: "年审年份", prop: "njnf"},
{ label: "姓名", prop: "xm" },
{ label: "身份证号码", prop: "sfzhm",showOverflowTooltip: true },
{ label: "电话", prop: "dh" },
{ label: "文化程度", prop: "whcd" },
{ label: "证书编号", prop: "zsbh", showOverflowTooltip: true },
{ label: "服务行业", prop: "fwxymc" },
{ label: "入职时间", prop: "rzsj" },
{ label: "上岗证号码", prop: "sgxkhm", showOverflowTooltip: true },
]
});
onMounted(() => {
// getList();
tabHeightFn();
});
// 搜索
const onSearch = (val) => {
queryFrom.value = { ...val };
pageData.pageConfiger.pageNum = 1;
getList();
};
const changeNo = (val) => {
pageData.pageConfiger.pageNum = val;
getList();
};
const changeSize = (val) => {
pageData.pageConfiger.pageSize = val;
getList();
};
// 获取列表
const getList = () => {
pageData.tableConfiger.loading = true;
const promes = {
...pageData.pageConfiger,
...queryFrom.value,
ssbakk:userInfo.pxgs,
ssbakkId:userInfo.pxgsid,
bakkShzt:'1',
}
qcckPost(promes,'/mosty-base/bans/njxx/page').then((res) => {
pageData.tableData = res.records || []
pageData.total = res.total;
pageData.tableConfiger.loading = false;
}).catch((err) => {
pageData.tableConfiger.loading = false;
})
};
const chooseData = (rows) => {
selectedRows.value = Array.isArray(rows) ? rows : [];
};
const onBatchAudit = (valIds) => {
let ids = [];
valIds.forEach(id =>{
let obj = pageData.tableData.find(it=>it.id == id);
if(obj && obj.bakkShzt == 0) ids.push(id);
});
if (!ids.length) return ElMessage.warning("请选择未审核的数据!该数据再审核状态下不能操作!");
shForm.value.init(ids);
};
// 详情
const addEdit = (type, row) => {
nextTick(() => {
if(type == 'RefSteap'){
RefSteap.value.init(row);
}else{
detailDiloag.value.init(type, row);
}
})
};
// 表格高度计算
const tabHeightFn = () => {
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 250;
window.onresize = function () {
tabHeightFn();
};
};
</script>
<style>
.el-loading-mask {
background: rgba(0, 0, 0, 0.5) !important;
}
</style>

View File

@ -0,0 +1,93 @@
<template>
<el-dialog title="年检签到" v-model="visible" width="80%" :destroy-on-close="true" @close="close">
<div class="cntinfo">
<FormMessage ref="FormRef" v-model="formData" :rules="rules" :formList="formList" :labelWidth='120'>
</FormMessage>
<el-divider border-style="dashed"><span class="pointer f16">培训人员<el-icon size="22" color="#409eff" class="ml5" style="top: 4px;"><CirclePlus /></el-icon></span></el-divider>
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth"
@chooseData="chooseData">
<template #sptz="{ row }">
<DictTag :value="row.sptz" :tag="false" :options="D_BA_SPZT" />
</template>
<!-- 操作 -->
<template #controls="{ row }">
<el-link type="primary" link @click="addEdit('RefSteap', row)">审核流程</el-link>
<el-link type="primary" link @click="addEdit('detail', row)">详情</el-link>
</template>
</MyTable>
<div class="mt10 flex just-center">
<el-button @click="save" type="primary" :loading="loading">保存</el-button>
<el-button @click="close">关闭</el-button>
</div>
</div>
</el-dialog>
</template>
<script setup>
import * as rule from "@/utils/rules.js";
import MyTable from "@/components/aboutTable/MyTable.vue";
import FormMessage from '@/components/aboutTable/FormMessage.vue'
import { ref,reactive } from 'vue'
const formData = ref({})
const visible = ref(false)
const loading = ref(false)
const formList = reactive([
[
{ label: "培训项目名称", prop: "xm", type: "input" },
{ label: "培训地址", prop: "sfzh", type: "input"},
],
[
{ label: "培训开始时间", prop: "lxdh", type: "date",lx:'datetime' },
{ label: "培训结束时间", prop: "jzdz", type: "date" ,lx:'datetime' },
],
[
{ label: "组织单位", prop: "rzsj", type: "input" },
{ label: "培训内容", prop: "lzsj", type: "input" },
]
])
const rules = ref({
pxgs: [{ required: true, message: '请选择培训公司', trigger: ['blur'] }],
lzsj: [{ required: true, message: '请选择离职时间', trigger: ['blur'] }],
})
const pageData = reactive({
tableData: [],
keyCount: 0,
tableConfiger: {
rowHieght: 61,
showSelectType: "checkBox",
loading: false,
haveControls: false
},
tableHeight: 320,
tableColumn: [
{ label: "培训项目名称", prop: "ssbakk",showOverflowTooltip: true },
{ label: "培训地址", prop: "sptzCompanyName", showOverflowTooltip: true },
{ label: "培训开始时间", prop: "njnf"},
{ label: "培训结束时间", prop: "xm" },
{ label: "组织单位", prop: "sfzhm",showOverflowTooltip: true },
{ label: "培训内容", prop: "dh" },
{ label: "培训人员", prop: "whcd" },
{ label: "已签到人员", prop: "zsbh", showOverflowTooltip: true },
{ label: "未签到人员", prop: "fwxymc" },
{ label: "是否上报分县局", prop: "rzsj" },
]
});
const init = () => {
visible.value = true
pageData.keyCount++
}
const close = () => {
visible.value = false
}
defineExpose({
init
})
</script>
<style lang="scss" scoped>
.cntinfo{
padding: 20px 10px;
box-sizing: border-box;
}
</style>

View File

@ -0,0 +1,201 @@
<template>
<div class="dialog" v-if="dialogForm">
<div class="head_box">
<span>详情</span>
<div><el-button size="small" @click="close">关闭</el-button></div>
</div>
<div class="cntinfo">
<!-- 内容描述 -->
<el-descriptions class="desc" :column="3" border label-width="200px">
<el-descriptions-item label="培训项目名称">{{ detail.ssbakk }}</el-descriptions-item>
<el-descriptions-item label="培训地址">{{ detail.njnf }}</el-descriptions-item>
<el-descriptions-item label="培训开始时间">{{ detail.xm }}</el-descriptions-item>
<el-descriptions-item label="培训结束时间">{{ detail.sfzhm }}</el-descriptions-item>
<el-descriptions-item label="组织单位">{{ detail.dh }}</el-descriptions-item>
<el-descriptions-item label="培训内容">{{ detail.xb }}</el-descriptions-item>
<el-descriptions-item label="保安公司名称">{{ detail.ssbakk }}</el-descriptions-item>
<el-descriptions-item label="年审年份">{{ detail.njnf }}</el-descriptions-item>
<el-descriptions-item label="姓名">{{ detail.xm }}</el-descriptions-item>
<el-descriptions-item label="身份证号码">{{ detail.sfzhm }}</el-descriptions-item>
<el-descriptions-item label="电话">{{ detail.dh }}</el-descriptions-item>
<el-descriptions-item label="性别">{{ detail.xb }}</el-descriptions-item>
<el-descriptions-item label="民族">{{ detail.mz }}</el-descriptions-item>
<el-descriptions-item label="年龄">{{ detail.nl }}</el-descriptions-item>
<el-descriptions-item label="籍贯">{{ detail.jg }}</el-descriptions-item>
<el-descriptions-item label="文化程度">{{ detail.whcd }}</el-descriptions-item>
<el-descriptions-item label="证书编号">{{ detail.zsbh }}</el-descriptions-item>
<el-descriptions-item label="上岗证号码">{{ detail.sgxkhm }}</el-descriptions-item>
<el-descriptions-item label="服务行业"> {{ detail.fwxy }}</el-descriptions-item>
<el-descriptions-item label="服务行业名称">{{ detail.fwxymc }}</el-descriptions-item>
<el-descriptions-item label="入职时间">{{ detail.rzsj }}</el-descriptions-item>
<el-descriptions-item label="政治面貌"> {{ detail.zzmm }}</el-descriptions-item>
<el-descriptions-item label="无犯罪记录证明">
<div class="img-grid one">
<el-image
:src="baseUrl + detail.wfbjlzm"
fit="cover"
:preview-src-list='[baseUrl + detail.wfbjlzm]'
preview-teleported
class="img"
/>
</div>
</el-descriptions-item>
<el-descriptions-item label="体检报告">
<div class="img-grid one">
<el-image
:src="baseUrl + detail.tjbg"
fit="cover"
:preview-src-list='[baseUrl + detail.tjbg]'
preview-teleported
class="img"
/>
</div>
</el-descriptions-item>
<el-descriptions-item label="身份证正反面">
<div class="img-grid two">
<el-image
:src="baseUrl + detail.sfzzm"
fit="cover"
:preview-src-list='[baseUrl + detail.sfzzm]'
preview-teleported
class="img"
/>
<el-image
:src="baseUrl + detail.sfzfm"
fit="cover"
:preview-src-list='[baseUrl + detail.sfzfm]'
preview-teleported
class="img"
/>
</div>
</el-descriptions-item>
<el-descriptions-item label="发证机关">{{ detail.fqjg }}</el-descriptions-item>
<el-descriptions-item label="发证日期">{{ detail.fqsj }}</el-descriptions-item>
<el-descriptions-item label="签到状态">{{ detail.qdzt }}</el-descriptions-item>
<el-descriptions-item label="签到时间" :span="2">{{ detail.qdsj }}</el-descriptions-item>
<el-descriptions-item label="签到表" :span="3"></el-descriptions-item>
<el-descriptions-item label="培训图片" :span="3"></el-descriptions-item>
</el-descriptions>
</div>
</div>
</template>
<script setup>
import { ref, computed, defineEmits, getCurrentInstance,defineProps } from 'vue';
import { qcckPost } from "@/api/qcckApi.js";
const emit = defineEmits(["refresh"]);
const { proxy } = getCurrentInstance();
const baseUrl = '/bagl/mosty-base/minio/image/download'
const props = defineProps({
dic: {
default: [[]], //二维数组
type: Array
}
})
const dialogForm = ref(false);
const detail = ref({})
// 初始化数据
const init = (type, row,) => {
// dialogForm.value = true;
// qcckPost({},'/mosty-base/bans/njxx/getInfo/'+row.id).then(res => {
// let zj = res.sfzzfmj.split(',');
// res.sfzzm = [zj[0]];
// res.sfzfm = [zj[1]];
// detail.value = res || {};
// })
};
const close = () => {
dialogForm.value = false;
detail.value = {};
};
defineExpose({ init })
</script>
<style lang="scss" scoped>
@import "@/assets/css/layout.scss";
.mapBox {
width: calc(100% - 24rem);
height: 500px;
overflow: hidden;
margin: 0 12rem;
}
.cntinfo{
position: relative;
padding: 10px 20px;
box-sizing: border-box;
.tag-box{
position: absolute;
top: 20px;
right: 50px;
display: flex;
flex-direction: column;
gap: 10px;
z-index: 99999;
.tag_item{
width: 70px;
height: 70px;
border-radius: 50%;
line-height: 65px;
text-align: center;
font-size: 16px;
margin-bottom: 20px;
}
.jtb_item{
border: 5px solid #FA3758;
color: #FA3758;
background: rgba(250,55,88,0.2);
}
.tgg_item{
color: #28EEBF;
background: rgba(40,238,191,0.2);
border: 5px solid #28EEBF;
}
.dsh_item{
background: rgba(0,114,255,0.2);
color: #0072FF;
border: 5px solid #0072FF;
}
}
}
.desc {
width: 100%;
}
.img-grid {
display: flex;
align-items: center;
gap: 10px;
min-height: 70px;
}
.img-grid.one .img,
.img-grid.one .img-placeholder {
width: 64px;
height: 64px;
}
.img-grid.two .img,
.img-grid.two .img-placeholder {
width: 64px;
height: 64px;
}
.img-placeholder {
background: #d9d9d9;
border-radius: 2px;
}
::v-deep .el-descriptions__label.el-descriptions__cell.is-bordered-label{
background: #F6FAFF;
}
</style>

View File

@ -0,0 +1,105 @@
<template>
<div>
<el-dialog class="steps-dialog" title="审核流程" v-model="dialogForm" width="420px">
<div class="steps-body">
<el-steps direction="vertical" :active="active" :space="90">
<el-step v-for="(item, idx) in steps" :key="item.title" :title="item.title" :description="idx === 0 ? item.time : ''" />
</el-steps>
</div>
</el-dialog>
</div>
</template>
<script setup>
import { ref, defineExpose } from 'vue';
const dialogForm = ref(false);
const pxgsData = ref()
const active = ref(1)
const steps = ref([
{ title: '保安公司审核', time: '2026-01-07 21:00' },
{ title: '培训公司审核', time: '2026-01-07 21:00' },
{ title: '公安局审核', time: '2026-01-07 21:00' },
])
const init = (row) => {
pxgsData.value = row
dialogForm.value = true;
}
defineExpose({
init
})
</script>
<style scoped lang="scss">
.steps-body {
height: 260px;
padding: 6px 10px 10px;
box-sizing: border-box;
}
:deep(.steps-dialog .el-dialog__header) {
text-align: center;
padding: 20px 20px 10px;
}
:deep(.steps-dialog .el-dialog__title) {
font-size: 24px;
font-weight: 700;
color: #333;
}
:deep(.steps-dialog .el-dialog__body) {
padding: 0 20px 20px;
}
:deep(.steps-dialog .el-step__title) {
font-size: 18px;
font-weight: 600;
color: #333;
line-height: 22px;
}
:deep(.steps-dialog .el-step__description) {
font-size: 16px;
color: #9AA8B6;
line-height: 20px;
margin-top: 8px;
}
:deep(.steps-dialog .el-step__line) {
left: 8px;
background-color: transparent;
border-left: 1px dashed #dadada;
}
:deep(.steps-dialog .el-step.is-vertical .el-step__head) {
width: 24px;
}
:deep(.steps-dialog .el-step__icon) {
width: 16px;
height: 16px;
border-radius: 50%;
}
:deep(.steps-dialog .el-step__head.is-process .el-step__icon),
:deep(.steps-dialog .el-step__head.is-process .el-step__icon.is-text) {
background: #2e6bff;
border: none;
box-shadow: 0 0 0 5px rgba(46, 107, 255, 0.15);
}
:deep(.steps-dialog .el-step.is-wait .el-step__icon),
:deep(.steps-dialog .el-step.is-finish .el-step__icon) {
background: #fff;
border: 1px solid #dadada;
box-shadow: none;
}
:deep(.steps-dialog .el-step__icon-inner) {
display: none;
}
::v-deep .is-finish .el-step__icon{
background: #86b6f1;
}
</style>

View File

@ -0,0 +1,171 @@
<template>
<div>
<div class="titleBox">
<PageTitle title="年检签到">
<el-button type="primary" @click="onBatchAudit">新增</el-button>
</PageTitle>
</div>
<!-- 搜索 -->
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch" :key="pageData.keyCount" />
</div>
<!-- 表格 -->
<div class="tabBox">
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth"
@chooseData="chooseData">
<template #sptz="{ row }">
<DictTag :value="row.sptz" :tag="false" :options="D_BA_SPZT" />
</template>
<!-- 操作 -->
<template #controls="{ row }">
<el-link type="primary" link @click="addEdit('RefSteap', row)">审核流程</el-link>
<el-link type="primary" link @click="addEdit('detail', row)">详情</el-link>
</template>
</MyTable>
<Pages @changeNo="changeNo" @changeSize="changeSize" :tableHeight="pageData.tableHeight" :pageConfiger="{
...pageData.pageConfiger,
total: pageData.total
}"></Pages>
</div>
<!-- 新增 -->
<AddForm ref="addFormRef"></AddForm>
<!-- 详情 -->
<DetailForm ref="detailDiloag" :dict="{D_BZ_SF}"/>
<!-- 审核流程 -->
<Steps ref="RefSteap" ></Steps>
</div>
</template>
<script setup>
import PageTitle from "@/components/aboutTable/PageTitle.vue";
import MyTable from "@/components/aboutTable/MyTable.vue";
import Pages from "@/components/aboutTable/Pages.vue";
import Search from "@/components/aboutTable/Search.vue";
import AddForm from "./components/addForm.vue";
import DetailForm from "./components/detailForm.vue";
import Steps from "./components/steps.vue";
import {getItem} from '@/utils/storage.js'
import { qcckPost } from "@/api/qcckApi.js";
import { reactive, ref, onMounted, getCurrentInstance, nextTick } from "vue";
import { ElMessage } from "element-plus";
const { proxy } = getCurrentInstance();
const { D_BA_SHZT,D_BA_SPZT } = proxy.$dict("D_BA_SHZT",'D_BA_SPZT');
const detailDiloag = ref();
const RefSteap = ref();
const addFormRef = ref();
const shForm = ref();
const searchBox = ref(); //搜索框
const selectedRows = ref([]);
const searchConfiger = ref([
{
label: "培训项目名称",
prop: "pxxm",
showType: "input"
},
{
label: "培训时间",
prop: "pxsj",
showType: "datetimerange"
},
]);
const queryFrom = ref({});
const pageData = reactive({
tableData: [],
keyCount: 0,
tableConfiger: {
rowHieght: 61,
showSelectType: "checkBox",
loading: false
},
total: 0,
pageConfiger: {
pageSize: 20,
pageNum: 1
},
controlsWidth: 180,
tableColumn: [
{ label: "培训项目名称", prop: "ssbakk",showOverflowTooltip: true },
{ label: "培训地址", prop: "sptzCompanyName", showOverflowTooltip: true },
{ label: "培训开始时间", prop: "njnf"},
{ label: "培训结束时间", prop: "xm" },
{ label: "组织单位", prop: "sfzhm",showOverflowTooltip: true },
{ label: "培训内容", prop: "dh" },
{ label: "培训人员", prop: "whcd" },
{ label: "已签到人员", prop: "zsbh", showOverflowTooltip: true },
{ label: "未签到人员", prop: "fwxymc" },
{ label: "是否上报分县局", prop: "rzsj" },
]
});
onMounted(() => {
// getList();
tabHeightFn();
});
// 搜索
const onSearch = (val) => {
queryFrom.value = { ...val };
pageData.pageConfiger.pageNum = 1;
getList();
};
const changeNo = (val) => {
pageData.pageConfiger.pageNum = val;
getList();
};
const changeSize = (val) => {
pageData.pageConfiger.pageSize = val;
getList();
};
// 获取列表
const getList = () => {
pageData.tableConfiger.loading = true;
const promes = {
...pageData.pageConfiger,
...queryFrom.value,
}
qcckPost(promes,'/mosty-base/bans/njxx/listForSendTraining').then((res) => {
pageData.tableData = res.records || []
pageData.total = res.total;
pageData.tableConfiger.loading = false;
}).catch((err) => {
pageData.tableConfiger.loading = false;
})
};
const chooseData = (rows) => {
selectedRows.value = Array.isArray(rows) ? rows : [];
};
const onBatchAudit = () => {
addFormRef.value.init();
};
// 详情
const addEdit = (type, row) => {
nextTick(() => {
if(type == 'RefSteap'){
RefSteap.value.init(row);
}else if(type == 'shForm'){
shForm.value.init(row);
}
else{
detailDiloag.value.init(type, row);
}
})
};
// 表格高度计算
const tabHeightFn = () => {
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 250;
window.onresize = function () {
tabHeightFn();
};
};
</script>
<style>
.el-loading-mask {
background: rgba(0, 0, 0, 0.5) !important;
}
</style>