数字督察一体化平台-前端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

848 lines
32 KiB

<template>
<div class="container">
<header class="mb-20">
<el-form :label-width="114">
<el-row>
<el-col :span="6">
<el-form-item label="检测单位">
<depart-tree-select v-model="query.departId" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="任务名称">
<el-input
placeholder="请输入任务名称"
v-model="query.nickName"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="flex between">
<el-button type="primary" @click="handleShowAdd">
<template #icon>
<icon name="el-icon-Plus" />
</template>
发布任务</el-button
>
<div>
<el-button type="primary" @click="getList">
<template #icon>
<icon name="el-icon-Search" />
</template>
查询</el-button
>
<el-button @click="reset">重置</el-button>
</div>
</div>
</header>
<div class="table-container">
<el-table :data="list">
<el-table-column label="任务名称" prop="taskName" />
<el-table-column
label="检测单位"
prop="supDepartName"
width="120"
/>
<el-table-column
label="检测人员"
prop="persons"
show-overflow-tooltip
/>
<el-table-column label="检测时间" prop="updateTime" width="280">
<template #default="{ row }">
<span>{{ row.beginTime }}</span>
<span>-</span>
<span>{{ row.endTime }}</span>
</template>
</el-table-column>
<el-table-column
label="抽检人数"
prop="totalNumber"
width="100"
align="center"
/>
<el-table-column
label="未检测人数"
prop="notDetectedNumber"
width="100"
align="center"
/>
<el-table-column
label="未饮酒人数"
prop="notDrinkingNumber"
width="100"
align="center"
/>
<el-table-column
label="饮酒人数"
prop="drinkNumber"
width="100"
align="center"
/>
<el-table-column label="操作" width="200">
<template #default="{ row }">
<el-button
type="primary"
link
@click="handleShowDetail(row)"
>任务详情</el-button
>
<el-button
type="primary"
link
@click="handleTestingDetailShow(row)"
>检测情况</el-button
>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex end mt-8">
<el-pagination
@size-change="getList"
@current-change="getList"
:page-sizes="[10, 20, 50]"
v-model:page-size="query.size"
v-model:current-page="query.current"
layout="total, sizes, prev, pager, next"
:total="total"
>
</el-pagination>
</div>
</div>
<el-dialog
title="发布任务"
v-model="show"
width="1076px"
top="3vh"
style="margin-bottom: 0"
>
<el-scrollbar max-height="76vh">
<el-form
:label-width="150"
ref="formRef"
:model="form"
style="min-height: 76vh"
>
<el-form-item
label="任务名称"
:rules="{
required: true,
message: '请输入任务名称',
trigger: ['blur'],
}"
prop="taskName"
>
<el-input
v-model="form.taskName"
placeholder="请输入任务名称"
/>
</el-form-item>
<el-form-item
label="检测单位"
:rules="{
required: true,
message: '请选择',
}"
prop="supDepartId"
>
<div style="width: 300px">
<depart-tree-select v-model="form.supDepartId" />
</div>
</el-form-item>
<el-form-item
label="检测人员"
:rules="{
required: true,
message: '请选择',
}"
prop="persons"
>
<police-picker v-model="form.persons" :departId="form.supDepartId" />
</el-form-item>
<el-form-item
label="检测时间"
prop="times"
:rules="{
required: true,
message: '请选择',
}"
>
<div style="width: 800px">
<el-date-picker
v-model="form.times"
type="datetimerange"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
/>
</div>
</el-form-item>
<el-form-item
label="检测对象"
prop="dataGenerationMethod"
:rules="{
required: true,
message: '请选择',
}"
>
<el-radio-group v-model="form.dataGenerationMethod">
<el-radio value="Excel导入人员">Excel导入人员</el-radio>
<el-radio value="自定义人员">自定义人员</el-radio>
</el-radio-group>
</el-form-item>
<template v-if="form.dataGenerationMethod === 'Excel导入人员'">
<div v-loading="importLoading">
<el-upload
drag
:multiple="false"
:auto-upload="false"
:show-file-list="false"
v-model:file-list="fileList"
@change="handleImport"
accept="application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
>
<template v-if="fileList.length === 0">
<el-icon class="el-icon--upload"
><upload-filled
/></el-icon>
<div class="el-upload__text">
<p>点击或拖拽文件到此区域上传</p>
</div>
</template>
<template v-else>
<el-icon class="el-icon--upload"
><Select
/></el-icon>
<div class="el-upload__text">
已选择文件:{{
fileList[fileList.length - 1].name
}}
</div>
</template>
</el-upload>
<div class="mt-20">
<span>文件模板</span>
<a
class="link"
:href="`${BASE_PATH}/templates/测酒任务被测人员模板.xlsx`"
target="__blank"
>测酒任务被测人员模板.xlsx 下载</a
>
</div>
<div class="flex gap wrap pepole-container mt-20">
<el-tag v-for="item in form.peoples" :key="item"
>{{ item.name }}-{{ item.empNo }}</el-tag
>
</div>
</div>
</template>
<template v-if="form.dataGenerationMethod === '自定义人员'">
<h5>筛选条件</h5>
<el-row>
<el-col :span="8">
<el-form-item
label="被抽检次数少于"
prop="filterMinSupNumber"
:rules="{
required: true,
message: '请输入',
}"
>
<el-input-number
controls-position="right"
style="width: 80px"
v-model="form.filterMinSupNumber"
/>
<span class="ml-8">次</span>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="距最后一次检测时间"
prop="filterLastDays"
:rules="{
required: true,
message: '请输入距最后一次检测时间',
}"
>
<el-input-number
controls-position="right"
style="width: 80px"
v-model="form.filterLastDays"
/>
<span class="ml-8">天</span>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="有无饮酒历史">
<el-radio-group
v-model="form.filterAlcoholHistory"
>
<el-radio :value="true">有</el-radio>
<el-radio :value="false">无</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="抽检人数"
prop="filterPeopleNumber"
:rules="{
required: true,
message: '请输入抽检人数',
}"
>
<el-input-number
controls-position="right"
style="width: 80px"
v-model="form.filterPeopleNumber"
/>
<span class="ml-8">人</span>
</el-form-item>
</el-col>
</el-row>
<div class="flex between v-center">
<h5>被抽检对象</h5>
<el-button
type="primary"
plain
size="small"
@click="form.filterPeopleConditions.push({})"
>
<template #icon>
<icon name="el-icon-Plus" />
</template>
添加部门</el-button
>
</div>
<div>
<div
class="flex between mb-10"
v-for="(item, index) in form.filterPeopleConditions"
:key="index"
>
<div class="flex gap">
<div>
<depart-tree-select
style="width: 280px"
v-model="item.departId"
@change="
() => {
handleGetPersonNumber(item);
}
"
/>
</div>
<el-select
v-model="item.personType"
multiple
clearable
style="width: 280px"
@change="
() => {
handleGetPersonNumber(item);
}
"
>
<el-option
v-for="item in dict.personType"
:key="item.id"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select>
<el-select
v-model="item.position"
style="width: 180px"
multiple
clearable
@change="
() => {
handleGetPersonNumber(item);
}
"
>
<el-option value="正职">正职</el-option>
<el-option value="副职">副职</el-option>
<el-option value="">无职位</el-option>
</el-select>
<span class="ml-20">
<span
>人数:{{
item.polices?.length || 0
}}人</span
>
<span></span>
</span>
</div>
<el-button
type="danger"
plain
@click="
form.filterPeopleConditions.splice(index, 1)
"
>删除</el-button
>
</div>
</div>
<div class="flex between v-center">
<h5>被抽检对象名单</h5>
<div>
<el-button
type="primary"
plain
size="small"
@click="handleGenPeople"
v-if="form.peoples.length > 0"
>重新生成抽检对象</el-button
>
</div>
</div>
<div class="text-center" v-if="form.peoples.length === 0">
<el-button type="primary" plain @click="handleGenPeople"
>生成抽检对象</el-button
>
</div>
<div class="flex gap wrap pepole-container">
<el-tag v-for="item in form.peoples" :key="item"
>{{ item.name }}-{{ item.empNo }}</el-tag
>
</div>
</template>
</el-form>
</el-scrollbar>
<footer class="flex end mt-20">
<el-button type="primary" @click="submit" size="large"
>发布</el-button
>
</footer>
</el-dialog>
<el-dialog title="任务详情" v-model="detailShow" width="40vw">
<div class="row mb-40">
<div class="col col-24">
<label>任务名称</label>
<span>{{ activeRow.taskName }}</span>
</div>
<div class="col col-24">
<label>检测单位</label>
<span>{{ activeRow.supDepartName }}</span>
</div>
<div class="col col-24">
<label>检测人员</label>
<span>{{ activeRow.persons }}</span>
</div>
<div class="col col-24">
<label>检测时间</label>
<span
><span>{{ activeRow.beginTime }}</span>
<span>-</span>
<span>{{ activeRow.endTime }}</span></span
>
</div>
<div class="col col-24">
<label>抽检人数</label>
<span>{{ activeRow.totalNumber }}</span>
</div>
<div class="col col-12">
<label>未饮酒人数</label>
<span>{{ activeRow.notDrinkingNumber }}</span>
</div>
<div class="col col-12">
<label>饮酒人数</label>
<span>{{ activeRow.drinkNumber }}</span>
</div>
<div class="col col-12">
<label>未检测人数</label>
<span>{{ activeRow.notDetectedNumber }}</span>
</div>
</div>
<footer class="flex end mt-20">
<el-button size="large" @click="detailShow = false">关闭</el-button>
</footer>
</el-dialog>
<el-dialog
title="检测情况"
v-model="testingDetailShow"
width="60vw"
top="2vh"
style="margin-bottom: 0"
>
<header class="mb-20">
<el-form :label-width="94">
<el-row>
<el-col :span="6">
<el-form-item label="姓名">
<el-input
v-model="peopleQuery.name"
clearable
placeholder="请输入警员姓名"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="警号">
<el-input
v-model="peopleQuery.empNo"
clearable
placeholder="请输入警号"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="检测情况">
<el-select
clearable
v-model="peopleQuery.testingResult"
>
<el-option value="已检测">已检测</el-option>
<el-option value="未检测">未检测</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col
:span="6"
v-if="peopleQuery.testingResult === '已检测'"
>
<el-form-item label="饮酒结果">
<el-select
clearable
v-model="peopleQuery.drinkResult"
>
<el-option value="饮酒">饮酒</el-option>
<el-option value="未饮酒">未饮酒</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<div class="flex end">
<el-button type="primary" @click="getPolices">
<template #icon>
<icon name="el-icon-Search" />
</template>
查询</el-button
>
<el-button @click="peopleReset">重置</el-button>
</div>
</el-form>
</header>
<div class="table-container">
<el-table :data="peoples" :max-height="640">
<el-table-column width="60" align="center">
<template #default="{ row }">
<img
class="avatar"
:src="`${BASE_PATH}/file/stream/${row.avatarUrl}`"
v-if="row.avatarUrl"
/>
<img class="avatar" src="/imgs/police.png" v-else />
</template>
</el-table-column>
<el-table-column label="姓名" prop="name" width="80" />
<el-table-column label="警号" prop="empNo" width="80" />
<el-table-column
label="单位"
prop="departName"
width="140"
show-overflow-tooltip
/>
<el-table-column
label="检测情况"
prop="testingResult"
width="90"
/>
<el-table-column
label="测酒时间"
prop="testingTime"
width="160"
/>
<el-table-column label="饮酒情况/未检测原因" show-overflow-tooltip>
<template #default="{ row }">
<el-tag type="success" v-if="row.drinkResult === '未饮酒'">未饮酒</el-tag>
<el-tag type="error" v-if="row.drinkResult === '饮酒'">饮酒</el-tag>
<span v-if="row.drinkResult === '饮酒'" class="ml-10">(酒精含量:{{ row.alcoholContent }} mg/100ml)</span>
<span>{{ row.unTestingDesc }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="100">
<template #default="{ row }">
<el-button
type="primary"
link
@click="handleShowPeople(row)"
>详情</el-button
>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex end mt-8">
<el-pagination
@size-change="getPolices"
@current-change="getPolices"
:page-sizes="[10, 20, 50]"
v-model:page-size="peopleQuery.size"
v-model:current-page="peopleQuery.current"
layout="total, sizes, prev, pager, next"
:total="peopleTotal"
>
</el-pagination>
</div>
</el-dialog>
<el-dialog title="人员检测情况" v-model="peopleDetailShow" width="40vw">
<div style="width: 600px; margin: auto">
<el-row>
<el-col :span="6">
<img
style="height: 100px"
:src="`${BASE_PATH}/file/stream/${activePeople.avatarUrl}`"
v-if="activePeople.avatarUrl"
/>
<img style="height: 100px" src="/imgs/police.png" v-else />
</el-col>
<el-col :span="18">
<div class="row">
<div class="col col-12">
<label>姓名</label>
<span>{{ activePeople.name }}</span>
</div>
<div class="col col-12">
<label>警号</label>
<span>{{ activePeople.empNo }}</span>
</div>
<div class="col col-24">
<label>警号</label>
<span>{{ activePeople.idCode }}</span>
</div>
<div class="col col-24">
<label>单位</label>
<span>{{ activePeople.departName }}</span>
</div>
</div>
</el-col>
</el-row>
<el-divider />
<div class="row">
<div class="col col-24" v-if="activePeople.testingResult">
<label>检测情况</label>
<span>{{ activePeople.testingResult }}</span>
</div>
<div class="col col-12" v-if="activePeople.drinkResult">
<label>饮酒结果</label>
<span>{{ activePeople.drinkResult }}</span>
</div>
<div class="col col-12" v-if="activePeople.drinkResult === '饮酒'">
<label>酒精含量</label>
<span>{{ activePeople.alcoholContent }} mg/100ml</span>
</div>
<div class="col col-24" v-if="activePeople.unTestingDesc">
<label>未检测原因</label>
<span>{{ activePeople.unTestingDesc }} mg/100ml</span>
</div>
</div>
<div v-if="activePeople.testingFileList.length">
<div class="mb-8">测酒现场照片</div>
<file-list v-model:files="activePeople.testingFileList" />
</div>
</div>
<footer class="flex end mt-20">
<el-button size="large" @click="peopleDetailShow = false">关闭</el-button>
</footer>
</el-dialog>
</template>
<script setup>
import { BASE_PATH } from "@/api/request";
import {
listTestingAlcohol,
addTestingAlcohol,
getPersonNumber,
listTestingAlcoholPeoples,
importTestingAlcoholPeople
} from "@/api/mobileSupervision/testingAlcohol";
import feedback from "@/utils/feedback";
import useCatchStore from "@/stores/modules/catch";
const catchStore = useCatchStore();
const dict = catchStore.getDicts(["personType"]);
const list = ref([]);
const query = ref({
current: 1,
size: 10,
});
const total = ref(0);
function getList() {
listTestingAlcohol(query.value).then((data) => {
list.value = data.records;
total.value = data.total;
});
}
function reset() {
query.value = {
current: 1,
size: 10,
};
getList();
}
getList();
const show = ref(false);
const form = ref({
dataGenerationMethod: "自定义人员",
filterMinSupNumber: 10,
filterLastDays: 60,
filterAlcoholHistory: false,
filterPeopleNumber: 10,
filterPeopleConditions: [],
peoples: [],
});
const formRef = ref(null);
async function submit() {
await formRef.value.validate();
if (form.value.peoples.length === 0) {
feedback.msgWarning("请生成抽检对象");
return
}
await addTestingAlcohol(form.value);
feedback.msgSuccess("发布成功");
show.value = false;
getList();
}
async function handleGetPersonNumber(item) {
console.log(item);
if (item.departId) {
item.polices = await getPersonNumber(item);
} else {
item.polices = [];
}
}
function handleShowAdd() {
show.value = true;
}
async function handleGenPeople() {
const arr = form.value.filterPeopleConditions
.filter((item) => item.polices).map((item) => item.polices.length);
if (arr.length === 0) {
feedback.msgWarning('请选择被抽检对象')
return
}
const sum = arr.reduce((a, b) => a + b);
if (form.value.filterPeopleNumber > sum) {
await feedback.confirm(`被抽检对象人数小于抽检人数,是否将抽检人数调整为${sum}`);
form.value.filterPeopleNumber = sum
}
const peoples = [];
form.value.filterPeopleConditions
.filter((item) => item.polices)
.forEach((item) => {
const count =
(item.polices.length / sum) * form.value.filterPeopleNumber;
for (let i = 0; i < count; i++) {
addPepole(peoples, item.polices);
}
});
form.value.peoples = peoples;
}
function addPepole(peoples, polices) {
const randomIndex = Math.floor(Math.random() * polices.length);
console.log(randomIndex);
const item = polices[randomIndex];
if (!peoples.includes(item)) {
peoples.push(item);
} else {
addPepole(peoples, polices);
}
}
const detailShow = ref(false);
const activeRow = ref({});
function handleShowDetail(row) {
activeRow.value = row;
detailShow.value = true;
}
const testingDetailShow = ref(false);
const peoples = ref([]);
function handleTestingDetailShow(row) {
activeRow.value = row;
testingDetailShow.value = true;
getPolices();
}
const peopleQuery = ref({
size: 10,
current: 1,
});
const peopleTotal = ref(0);
function getPolices() {
listTestingAlcoholPeoples(activeRow.value.id, peopleQuery.value).then(
(data) => {
peoples.value = data.records;
peopleTotal.value = data.total;
}
);
}
function peopleReset() {
peopleQuery.value = {
size: 10,
current: 1,
};
}
const activePeople = ref([]);
const peopleDetailShow = ref(false);
function handleShowPeople(row) {
activePeople.value = row;
peopleDetailShow.value = true;
}
const fileList = ref([])
const importLoading = ref(false)
watch(fileList, async () => {
if (fileList.value.length === 0) {
return;
}
importLoading.value = true
const formData = new FormData();
formData.append("file", fileList.value[fileList.value.length - 1].raw);
try {
form.value.peoples = await importTestingAlcoholPeople(formData);
} catch (e) {
importLoading.value = false
throw e;
}
importLoading.value = false
})
</script>
<style lang="scss" scoped>
h5 {
margin-bottom: 10px;
}
.pepole-container > * {
margin-bottom: 8px;
}
.avatar {
height: 50px;
display: block;
}
</style>