626 lines
16 KiB
Vue
626 lines
16 KiB
Vue
<template>
|
||
<div class="warning-page">
|
||
<LeftMenu
|
||
v-model="active"
|
||
:tabs="['项目名称', '工程名称']"
|
||
:records="records"
|
||
@change-page="onCurChange"
|
||
@search="onSearchInput"
|
||
:pageable="pages"
|
||
class="leftMenu"
|
||
>
|
||
<template #default="{ data }">
|
||
<div class="leftProject" @click="onSearch(data)">
|
||
<span class="projectName">{{
|
||
(data as any).projectName || (data as any).engineeringName
|
||
}}</span>
|
||
<div class="leftMenu_item">
|
||
<div class="video">
|
||
<img style="margin-right: 5px" src="@/assets/images/AIwaring/dustMap.png" alt="" />
|
||
<span class="middleSize">{{ data.projectAddress || data.address }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</LeftMenu>
|
||
<div class="table-box">
|
||
<ProTable
|
||
ref="proTable"
|
||
title="参建单位列表"
|
||
:columns="columns"
|
||
:requestApi="getTableList"
|
||
:dataCallback="dataCallback"
|
||
:tool-button="false"
|
||
:pagination="true"
|
||
background
|
||
>
|
||
<template #formButton="scope">
|
||
<div class="attendance-label">
|
||
<span class="successCircle"></span>
|
||
<span class="text">正常出勤</span>
|
||
<span class="errorCircle"></span>
|
||
<span class="text">未出勤</span>
|
||
</div>
|
||
</template>
|
||
<template #operation="{ row }">
|
||
<el-button type="primary" link @click="handleEditItem(row)">
|
||
<img src="@/assets/images/tableIcon/配置权限.png" alt="" class="configureIcon" />
|
||
<span>配置权限</span>
|
||
</el-button>
|
||
<el-button type="primary" link @click="handleAddItem(2, row)">
|
||
<img src="@/assets/images/tableIcon/updateIcon.png" alt="" class="configureIcon" />
|
||
<span>编辑</span>
|
||
</el-button>
|
||
<el-button type="danger" link :icon="Delete" @click="deleteAccount(row)">删除</el-button>
|
||
</template>
|
||
<template #state="{ row }">
|
||
<span :class="row.state === 1 ? '' : 'redText'">{{ row.state == 1 ? "启用" : "禁用" }}</span>
|
||
</template>
|
||
<template v-for="(item, index) in monthColumns" #[item.prop]="{ row }">
|
||
<span class="successCircle" v-if="row[item.prop]" @click="showAttendance(row, index)"></span>
|
||
<span class="errorCircle" v-else @click="showAttendance(row, index)"></span>
|
||
</template>
|
||
</ProTable>
|
||
<div class="table" v-if="attendanceDetailShow">
|
||
<h4>考勤明细</h4>
|
||
<el-table
|
||
:data="attendanceSingles"
|
||
max-height="340"
|
||
class="el-table"
|
||
:header-cell-style="{ textAlign: 'center' }"
|
||
:cell-style="{ textAlign: 'center' }"
|
||
>
|
||
<el-table-column prop="personName" label="姓名" />
|
||
<el-table-column prop="name" label="人员类别">
|
||
<template #default="scope">
|
||
<span>{{ scope.row.personType == 1 ? "管理" : "工人" }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="teamName" label="班组" />
|
||
<el-table-column prop="name" label="进入/离开">
|
||
<template #default="scope">
|
||
<span>{{ scope.row.passType == 1 ? "进入" : "离开" }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="createTime" label="考勤时间" />
|
||
<el-table-column prop="devName" label="考勤设备" />
|
||
<el-table-column label="考勤照片">
|
||
<template #default="scope">
|
||
<el-image style="width: 26px; height: 37px" :src="scope.row.imageUrl" fit="fill"></el-image>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
<el-drawer v-model="drawerVisible" :destroy-on-close="true" :before-close="closeDrawer" size="450px" title="配置权限">
|
||
<span class="title sle">所拥有的权限</span>
|
||
<el-scrollbar :style="{ height: title ? `calc(100% - 95px)` : `calc(100% - 56px)` }">
|
||
<!-- check-strictly 父子不关联 这样数据选择父 子不会默认被勾选 子被选择 父也不会 -->
|
||
<el-tree ref="treeRef" default-expand-all :data="datas" show-checkbox node-key="name" :props="defaultProps"> </el-tree>
|
||
</el-scrollbar>
|
||
<template #footer>
|
||
<div class="flx-center">
|
||
<el-button style="margin-right: 60px" @click="cacel">取消</el-button>
|
||
<el-button type="primary" @click="confirm">保存并关闭</el-button>
|
||
</div>
|
||
</template>
|
||
</el-drawer>
|
||
|
||
<DialogForm
|
||
:title="title"
|
||
:formConfig="formConfig"
|
||
:formData="formData"
|
||
v-model:visible="visible"
|
||
append-to-body
|
||
width="700px"
|
||
@confirm="saveItem"
|
||
>
|
||
</DialogForm>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="tsx" name="ProjectSupervisionRecord">
|
||
import { ref, reactive, nextTick, onBeforeMount, onMounted } from "vue";
|
||
import { ElMessage, ElMessageBox, ElTree } from "element-plus";
|
||
import { useRouter } from "vue-router";
|
||
import { ColumnProps } from "@/components/ProTable/interface";
|
||
import { useHandleData } from "@/hooks/useHandleData";
|
||
import { useTime } from "@/hooks/useTime";
|
||
import ProTable from "@/components/ProTable/index.vue";
|
||
import { jxj_User } from "@/api/types";
|
||
import TreeFilter from "@/components/TreeFilter/index.vue";
|
||
import {
|
||
addRole,
|
||
editRole,
|
||
deleteRole,
|
||
editRolePermissions,
|
||
getSystemRole,
|
||
getTreemRoleList,
|
||
getTreeByIdList
|
||
} from "@/api/modules/goverment";
|
||
import DialogForm from "@/components/DialogForm/index.vue";
|
||
import { statisticsList, statisticsDetail } from "@/api/modules/project";
|
||
|
||
import { Delete } from "@element-plus/icons-vue";
|
||
import { GlobalStore } from "@/stores";
|
||
import SearchFormItem from "@/components/SearchForm/components/SearchFormItem.vue";
|
||
import LeftMenu from "@/components/LeftMenu/LeftMenu.vue";
|
||
import { getDustprojectPage, getDustengineeringPage, getAIQuestionPage } from "@/api/modules/goverment";
|
||
const pages = ref({
|
||
pageNo: 1,
|
||
pageSize: 7,
|
||
total: 0
|
||
});
|
||
const pageable = ref({
|
||
pageNo: 1,
|
||
pageSize: 12,
|
||
total: 0
|
||
});
|
||
const records = ref([]);
|
||
const active = ref(1);
|
||
const treeRef = ref(null);
|
||
const datas = reactive([]);
|
||
|
||
const defaultProps = {
|
||
children: "children",
|
||
label: (data, node) => node.data.meta.title
|
||
};
|
||
const router = useRouter();
|
||
const store = GlobalStore();
|
||
const currentData = ref();
|
||
const visible = ref(false);
|
||
const drawerVisible = ref(false);
|
||
const title = ref("");
|
||
const attendanceSingles = ref([]);
|
||
const SearchFormValue = ref({}); // 表格上分搜索参数
|
||
const attendanceDetailShow = ref(false);
|
||
const formData = ref({
|
||
personName: "123",
|
||
priority: 1,
|
||
state: 0,
|
||
roleDesc: ""
|
||
});
|
||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
|
||
const proTable = ref();
|
||
|
||
const getId = ref<number | undefined>(undefined);
|
||
|
||
// 表格配置项
|
||
const columns: ColumnProps[] = [
|
||
{ type: "index", label: "序号", width: 80 },
|
||
{
|
||
prop: "personName",
|
||
label: "姓名",
|
||
search: { el: "input" }
|
||
},
|
||
{
|
||
prop: "teamName",
|
||
label: "班组",
|
||
width: 150,
|
||
search: { el: "input" }
|
||
},
|
||
{
|
||
prop: "month",
|
||
label: "月份",
|
||
search: {
|
||
el: "date-picker",
|
||
span: 2,
|
||
props: { type: "month", valueFormat: "YYYY-MM" },
|
||
defaultValue: "2023-05"
|
||
}
|
||
},
|
||
{
|
||
prop: "lateDay",
|
||
width: 150,
|
||
label: "迟到天数"
|
||
},
|
||
{
|
||
prop: "earlyDay",
|
||
width: 150,
|
||
label: "早退天数"
|
||
},
|
||
{
|
||
prop: "workerHour",
|
||
width: 150,
|
||
label: "总工时"
|
||
}
|
||
];
|
||
const monthColumns: ColumnProps[] = [];
|
||
|
||
// 弹窗中的配置
|
||
const formConfig = {
|
||
formItemConfig: [
|
||
{
|
||
label: "角色名称",
|
||
prop: "roleName",
|
||
type: "input"
|
||
},
|
||
{
|
||
label: "角色顺序",
|
||
prop: "priority",
|
||
type: "number"
|
||
},
|
||
{
|
||
label: "状态",
|
||
prop: "state",
|
||
type: "radio",
|
||
data: [
|
||
{ label: "启用", value: 1 },
|
||
{ label: "禁用", value: 0 }
|
||
]
|
||
},
|
||
{
|
||
label: "备注",
|
||
prop: "roleDesc",
|
||
type: "input",
|
||
mapIcon: true
|
||
// 标记dialog
|
||
}
|
||
],
|
||
rules: {
|
||
roleName: [
|
||
{
|
||
required: true,
|
||
message: "请输入角色名称",
|
||
trigger: "blur"
|
||
}
|
||
],
|
||
priority: [
|
||
{
|
||
required: true,
|
||
message: "请输入角色顺序",
|
||
trigger: "blur"
|
||
}
|
||
]
|
||
}
|
||
};
|
||
|
||
// 项目或者工程名字
|
||
const searchName = ref<string>("");
|
||
// 搜索用的项目sn或者工程sn
|
||
const searchSn = ref("");
|
||
// 页面的项目名称和工程名称的div点击事件
|
||
const onSearch = async (params: any) => {
|
||
// const { result } = await getAIQuestionPage(
|
||
// active.value === 0
|
||
// ? { projectSn: (params as ResAiProjectPage).projectSn, pageNo: pageable.value.pageNo, pageSize: pageable.value.pageSize }
|
||
// : {
|
||
// engineeringSn: (params as ResAiEngineerPage).engineeringSn,
|
||
// pageNo: pageable.value.pageNo,
|
||
// pageSize: pageable.value.pageSize
|
||
// }
|
||
// );
|
||
// pageable.value.total = Number(result.total);
|
||
active.value === 0 ? (searchSn.value = params.projectSn) : (searchSn.value = params.engineeringSn);
|
||
active.value === 0 ? (searchName.value = params.projectName) : (searchName.value = params.engineeringName);
|
||
proTable.value.getTableList();
|
||
};
|
||
// leftMenu页面的搜索按钮
|
||
const onSearchInput = async (params: string) => {
|
||
console.log(params);
|
||
if (active.value === 0) {
|
||
const { result } = await getDustprojectPage({ projectName: params, ...pages.value });
|
||
records.value = result.records;
|
||
} else {
|
||
const { result } = await getDustengineeringPage({ engineeringName: params, ...pages.value });
|
||
records.value = result.records;
|
||
}
|
||
};
|
||
// leftMenu页面的分页
|
||
const onCurChange = async (params: number) => {
|
||
console.log(active.value);
|
||
if (active.value === 0) {
|
||
const { result } = await getDustprojectPage({ ...pages.value, pageNo: params });
|
||
records.value = result.records;
|
||
} else {
|
||
const { result } = await getDustengineeringPage({ ...pages.value, pageNo: params });
|
||
records.value = result.records;
|
||
pages.value.total = +result.total;
|
||
}
|
||
pages.value.total = +res.result.total;
|
||
};
|
||
// dataCallback 是对于返回的表格数据做处理,如果你后台返回的数据不是 list && total && pageNum && pageSize 这些字段,那么你可以在这里进行处理成这些字段
|
||
// 或者直接去 hooks/useTable.ts 文件中把字段改为你后端对应的就行
|
||
const dataCallback = (data: any) => {
|
||
// console.log(data);
|
||
return {
|
||
list: data.records,
|
||
total: Number(data.total),
|
||
pageNo: Number(data.current),
|
||
pageSize: Number(data.size)
|
||
};
|
||
};
|
||
|
||
const closeDrawer = done => {
|
||
datas.length = 0;
|
||
done();
|
||
};
|
||
|
||
const cacel = () => {
|
||
drawerVisible.value = false;
|
||
datas.length = 0;
|
||
};
|
||
// 展示考勤数据
|
||
const showAttendance = async (row, index) => {
|
||
let dayDate = "";
|
||
let day = index + 1 < 10 ? "0" + (index + 1) : index + 1;
|
||
if (SearchFormValue.value.month) {
|
||
dayDate = SearchFormValue.value.month + "-" + day;
|
||
} else {
|
||
let month = currentData.value.month < 10 ? "0" + currentData.value.month : currentData.value.month;
|
||
dayDate = currentData.value.year + "-" + month + "-" + day;
|
||
}
|
||
|
||
const res = await statisticsDetail({
|
||
workerId: row.id,
|
||
dayDate
|
||
});
|
||
attendanceSingles.value = res.result;
|
||
attendanceDetailShow.value = true;
|
||
};
|
||
const transfrom = (arr: Array<any>) => {
|
||
const result = [];
|
||
return arr
|
||
.map(item => {
|
||
if (arr.children && Array.isArray(arr.children)) {
|
||
result.concat(transfrom(arr.children));
|
||
}
|
||
|
||
return {
|
||
authorityId: item.name,
|
||
roleId: getId.value,
|
||
type: item.type
|
||
};
|
||
})
|
||
.concat(result);
|
||
};
|
||
|
||
const confirm = async () => {
|
||
const checked = treeRef.value.getCheckedNodes();
|
||
await editRolePermissions(transfrom(checked));
|
||
drawerVisible.value = false;
|
||
datas.length = 0;
|
||
};
|
||
|
||
// 如果你想在请求之前对当前请求参数做一些操作,可以自定义如下函数:params 为当前所有的请求参数(包括分页),最后返回请求列表接口
|
||
// 默认不做操作就直接在 ProTable 组件上绑定 :requestApi="getUserList"
|
||
const getTableList = (params: any) => {
|
||
console.log(params);
|
||
let newParams = JSON.parse(JSON.stringify(params));
|
||
SearchFormValue.value = newParams;
|
||
// if (newParams.createTime) {
|
||
// newParams.createTime_begin = newParams.createTime[0];
|
||
// newParams.createTime_end = newParams.createTime[1];
|
||
// delete newParams.createTime;
|
||
// }
|
||
if (!newParams.month) {
|
||
let month = currentData.value.month < 10 ? "0" + currentData.value.month : currentData.value.month;
|
||
newParams.month = currentData.value.year + "-" + month;
|
||
}
|
||
newParams.engineeringSn = searchSn.value;
|
||
return statisticsList(newParams);
|
||
};
|
||
|
||
const handleAddItem = (index: number, row: any) => {
|
||
if (index === 1) {
|
||
title.value = "新增角色";
|
||
formData.value = reactive({
|
||
roleName: "",
|
||
priority: 1,
|
||
state: 1,
|
||
roleDesc: ""
|
||
});
|
||
} else {
|
||
title.value = "编辑角色";
|
||
formData.value = reactive({ ...row });
|
||
}
|
||
visible.value = true;
|
||
};
|
||
|
||
// 修改数据按钮
|
||
const handleEditItem = async (row: any) => {
|
||
getId.value = row.roleId;
|
||
|
||
drawerVisible.value = true;
|
||
const { result = [] } = await getTreemRoleList();
|
||
// console.log("test", result);
|
||
datas.push(...result);
|
||
|
||
const res = await getTreeByIdList({ roleId: row.roleId });
|
||
// 打开弹窗时调用上面的接口勾选
|
||
nextTick(() => {
|
||
treeRef.value.setCheckedKeys(res.result.map(item => item.authorityId));
|
||
});
|
||
};
|
||
|
||
const saveItem = async (form: any) => {
|
||
if (form.roleId) {
|
||
// console.log(form.dictCode);
|
||
const res = await editRole(form);
|
||
proTable.value.getTableList();
|
||
ElMessage.success("编辑成功");
|
||
} else {
|
||
const res = await addRole(form);
|
||
ElMessage.success("新增成功");
|
||
proTable.value.getTableList();
|
||
}
|
||
visible.value = false;
|
||
};
|
||
|
||
// 删除用户信息
|
||
const deleteAccount = async (params: jxj_User.ResUserList) => {
|
||
await useHandleData(deleteRole, { roleId: params.roleId }, `删除【${params.roleName}】`);
|
||
proTable.value.getTableList();
|
||
};
|
||
|
||
const changeTreeFilter = () => {
|
||
console.log(11);
|
||
};
|
||
onBeforeMount(() => {
|
||
for (let i = 0; i < 31; i++) {
|
||
monthColumns.push({
|
||
prop: "day" + (i + 1),
|
||
label: "" + (i + 1)
|
||
});
|
||
columns.push({
|
||
prop: "day" + (i + 1),
|
||
label: "" + (i + 1)
|
||
});
|
||
}
|
||
currentData.value = useTime();
|
||
let month = currentData.value.month < 10 ? "0" + currentData.value.month : currentData.value.month;
|
||
columns[3] = {
|
||
prop: "month",
|
||
label: "月份",
|
||
isShow: false,
|
||
search: {
|
||
el: "date-picker",
|
||
span: 2,
|
||
props: { type: "month", valueFormat: "YYYY-MM" },
|
||
defaultValue: currentData.value.year + "-" + month
|
||
}
|
||
};
|
||
});
|
||
// 获取工程名称分页
|
||
const getEngPage = async () => {
|
||
const { result } = await getDustengineeringPage(pages.value);
|
||
records.value = result.records;
|
||
records.value.map(item => {
|
||
let showGif = false;
|
||
item.showGif = showGif;
|
||
});
|
||
pages.value.total = +result.total;
|
||
};
|
||
onMounted(async () => {
|
||
await getEngPage();
|
||
onSearch(records.value[0]);
|
||
searchSn.value = records.value[0].projectSn;
|
||
searchName.value = records.value[0].projectName;
|
||
});
|
||
</script>
|
||
<style lang="scss" scoped>
|
||
.warning-page {
|
||
// background-color: blue;
|
||
display: flex;
|
||
width: 100%;
|
||
height: 100%;
|
||
.leftMenu {
|
||
width: 300px;
|
||
// width: 290px;
|
||
// 页面的项目工程
|
||
:deep(.item) {
|
||
height: 78px !important;
|
||
}
|
||
:deep(.content) {
|
||
height: calc(100% - 160px) !important;
|
||
}
|
||
:deep {
|
||
.tab-wrapper {
|
||
display: none;
|
||
}
|
||
}
|
||
.leftProject {
|
||
// padding: 5px 8px;
|
||
font-size: 20px;
|
||
color: #333333;
|
||
.projectName {
|
||
display: block;
|
||
width: 100%;
|
||
overflow: hidden;
|
||
|
||
// font-weight: 700;
|
||
font-family: "siyuan_Medium";
|
||
font-size: 20px;
|
||
color: #ffffff;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
.leftMenu_item {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-top: 5px;
|
||
overflow: hidden;
|
||
.video {
|
||
display: flex;
|
||
align-items: center;
|
||
.middleSize {
|
||
font-size: 18px;
|
||
color: #c4c4c4;
|
||
white-space: nowrap;
|
||
}
|
||
img {
|
||
width: 14px;
|
||
height: 14px;
|
||
margin: 0 4px;
|
||
}
|
||
}
|
||
}
|
||
.bottom_item {
|
||
.bottomSize {
|
||
font-size: 18px !important;
|
||
color: #666666;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.table-box {
|
||
width: calc(100% - 320px);
|
||
height: 100%;
|
||
margin-left: 20px;
|
||
.attendance-label {
|
||
min-width: 160px;
|
||
}
|
||
.successCircle {
|
||
display: inline-block;
|
||
width: 11px;
|
||
height: 11px;
|
||
background: #008bff;
|
||
opacity: 1;
|
||
border-radius: 50%;
|
||
cursor: pointer;
|
||
}
|
||
.errorCircle {
|
||
display: inline-block;
|
||
width: 11px;
|
||
height: 11px;
|
||
background: #d9d9d9;
|
||
opacity: 1;
|
||
border-radius: 50%;
|
||
cursor: pointer;
|
||
}
|
||
.text {
|
||
font-size: 20px;
|
||
font-family: Source Han Sans CN-Regular, Source Han Sans CN;
|
||
font-weight: 400;
|
||
color: var(--el-menu-text-color);
|
||
margin-right: 10px;
|
||
margin-left: 10px;
|
||
}
|
||
.table {
|
||
display: flex;
|
||
flex-direction: column;
|
||
padding: 20px;
|
||
h4 {
|
||
position: relative;
|
||
padding-left: 6px;
|
||
font-size: 24px;
|
||
font-weight: 500;
|
||
color: #ffffff;
|
||
border-left: 3px solid #0bc4f0;
|
||
}
|
||
.el-table {
|
||
width: calc(100% - 20px);
|
||
margin-left: 20px;
|
||
}
|
||
}
|
||
:deep(.operation) {
|
||
flex: 1;
|
||
}
|
||
:deep(.operation .el-button) {
|
||
margin-right: auto;
|
||
}
|
||
}
|
||
}
|
||
</style>
|