feat: 完成考勤排版管理页面交互
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {ref, shallowRef} from 'vue';
|
import { ref, shallowRef } from 'vue';
|
||||||
import {useVbenModal} from '@vben/common-ui';
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
@@ -11,16 +11,16 @@ import {
|
|||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import duration from 'dayjs/plugin/duration';
|
import duration from 'dayjs/plugin/duration';
|
||||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||||
import {renderDict} from "#/utils/render";
|
import { renderDict } from '#/utils/render';
|
||||||
import {groupInfo} from "#/api/property/attendanceManagement/attendanceGroupSettings";
|
import { groupInfo } from '#/api/property/attendanceManagement/attendanceGroupSettings';
|
||||||
import type {GroupVO} from "#/api/property/attendanceManagement/attendanceGroupSettings/model";
|
import type { GroupVO } from '#/api/property/attendanceManagement/attendanceGroupSettings/model';
|
||||||
import {
|
import {
|
||||||
infoCycleColumns,
|
infoCycleColumns,
|
||||||
infoClockingColumns,
|
infoClockingColumns,
|
||||||
infoNoClockingColumns,
|
infoNoClockingColumns,
|
||||||
infoWeekdayColumns
|
infoWeekdayColumns,
|
||||||
} from "#/views/property/attendanceManagement/attendanceGroupSettings/data";
|
} from '#/views/property/attendanceManagement/attendanceGroupSettings/data';
|
||||||
import holidayCalendar from './holiday-calendar.vue'
|
import holidayCalendar from './holiday-calendar.vue';
|
||||||
|
|
||||||
dayjs.extend(duration);
|
dayjs.extend(duration);
|
||||||
dayjs.extend(relativeTime);
|
dayjs.extend(relativeTime);
|
||||||
@@ -34,17 +34,17 @@ const [BasicModal, modalApi] = useVbenModal({
|
|||||||
|
|
||||||
const groupDetail = shallowRef<null | GroupVO>(null);
|
const groupDetail = shallowRef<null | GroupVO>(null);
|
||||||
|
|
||||||
const weekdayData = ref<any[]>([])
|
const weekdayData = ref<any[]>([]);
|
||||||
const cycleData = ref<any[]>([])
|
const cycleData = ref<any[]>([]);
|
||||||
const unCheckInData = ref<any[]>([])
|
const unCheckInData = ref<any[]>([]);
|
||||||
const checkInData = ref<any[]>([])
|
const checkInData = ref<any[]>([]);
|
||||||
|
|
||||||
async function handleOpenChange(open: boolean) {
|
async function handleOpenChange(open: boolean) {
|
||||||
if (!open) {
|
if (!open) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
modalApi.modalLoading(true);
|
modalApi.modalLoading(true);
|
||||||
const {id} = modalApi.getData() as { id: number | string };
|
const { id } = modalApi.getData() as { id: number | string };
|
||||||
groupDetail.value = await groupInfo(id);
|
groupDetail.value = await groupInfo(id);
|
||||||
modalApi.modalLoading(false);
|
modalApi.modalLoading(false);
|
||||||
}
|
}
|
||||||
@@ -57,74 +57,122 @@ const [HolidayCalendar, holidayApi] = useVbenModal({
|
|||||||
* 查看法定节假日日历
|
* 查看法定节假日日历
|
||||||
*/
|
*/
|
||||||
async function showHoliday() {
|
async function showHoliday() {
|
||||||
holidayApi.open()
|
holidayApi.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<BasicModal :footer="false" :fullscreen-button="false" title="考勤组信息" class="w-[70%]">
|
<BasicModal
|
||||||
|
:footer="false"
|
||||||
|
:fullscreen-button="false"
|
||||||
|
title="考勤组信息"
|
||||||
|
class="w-[70%]"
|
||||||
|
>
|
||||||
<div v-if="groupDetail" class="des-container">
|
<div v-if="groupDetail" class="des-container">
|
||||||
<Descriptions size="small" :column="1" :labelStyle="{width:'100px'}">
|
<Descriptions size="small" :column="1" :labelStyle="{ width: '100px' }">
|
||||||
<DescriptionsItem label="考勤组名称">
|
<DescriptionsItem label="考勤组名称">
|
||||||
{{ groupDetail.groupName }}
|
{{ groupDetail.groupName }}
|
||||||
</DescriptionsItem>
|
</DescriptionsItem>
|
||||||
<DescriptionsItem label="考勤类型">
|
<DescriptionsItem label="考勤类型">
|
||||||
<component
|
<component
|
||||||
:is="groupDetail.attendanceType ? renderDict(groupDetail.attendanceType,'wy_kqlx') : ''"
|
:is="
|
||||||
|
groupDetail.attendanceType
|
||||||
|
? renderDict(groupDetail.attendanceType, 'wy_kqlx')
|
||||||
|
: ''
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</DescriptionsItem>
|
</DescriptionsItem>
|
||||||
<DescriptionsItem label="状态">
|
<DescriptionsItem label="状态">
|
||||||
<component
|
<component :is="renderDict(groupDetail.status, 'wy_state')" />
|
||||||
:is="renderDict(groupDetail.status,'wy_state')"
|
|
||||||
/>
|
|
||||||
</DescriptionsItem>
|
</DescriptionsItem>
|
||||||
<DescriptionsItem label="工作日设置" v-if="groupDetail.attendanceType==0">
|
<DescriptionsItem
|
||||||
<div class="item-font" style="width: 100%;">
|
label="工作日设置"
|
||||||
<Table style="width: 90%" bordered :columns="infoWeekdayColumns"
|
v-if="groupDetail.attendanceType == 0"
|
||||||
:data-source="weekdayData"
|
>
|
||||||
size="small" :pagination="false">
|
<div class="item-font" style="width: 100%">
|
||||||
|
<Table
|
||||||
|
style="width: 90%"
|
||||||
|
bordered
|
||||||
|
:columns="infoWeekdayColumns"
|
||||||
|
:data-source="weekdayData"
|
||||||
|
size="small"
|
||||||
|
:pagination="false"
|
||||||
|
>
|
||||||
</Table>
|
</Table>
|
||||||
<Checkbox class="item-padding-top" v-model:checked="groupDetail.isAutomatic">
|
<Checkbox
|
||||||
|
class="item-padding-top"
|
||||||
|
v-model:checked="groupDetail.isAutomatic"
|
||||||
|
>
|
||||||
法定节假日自动排休
|
法定节假日自动排休
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
<Button type="link" @click="showHoliday">查看法定节假日日历</Button>
|
<Button type="link" @click="showHoliday">查看法定节假日日历</Button>
|
||||||
<p class="item-padding-top item-font-weight">特殊日期:</p>
|
<p class="item-padding-top item-font-weight">特殊日期:</p>
|
||||||
<p class="item-padding">无需打卡日期:</p>
|
<p class="item-padding">无需打卡日期:</p>
|
||||||
<Table style="width: 75%" bordered :columns="infoNoClockingColumns"
|
<Table
|
||||||
:data-source="unCheckInData"
|
style="width: 75%"
|
||||||
size="small" :pagination="false">
|
bordered
|
||||||
<template #bodyCell="{ column,record,index }">
|
:columns="infoNoClockingColumns"
|
||||||
<template v-if="column.dataIndex==='dateTime'">
|
:data-source="unCheckInData"
|
||||||
<span v-if="record.dateType==0">{{ record.startDate }}</span>
|
size="small"
|
||||||
<span v-else>{{ record.startDate + '~' + record.endDate }}</span>
|
:pagination="false"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record, index }">
|
||||||
|
<template v-if="column.dataIndex === 'dateTime'">
|
||||||
|
<span v-if="record.dateType == 0">{{
|
||||||
|
record.startDate
|
||||||
|
}}</span>
|
||||||
|
<span v-else>{{
|
||||||
|
record.startDate + '~' + record.endDate
|
||||||
|
}}</span>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</Table>
|
</Table>
|
||||||
<p class="item-padding">必须打卡日期:</p>
|
<p class="item-padding">必须打卡日期:</p>
|
||||||
<Table style="width: 75%" bordered :columns="infoClockingColumns"
|
<Table
|
||||||
:data-source="checkInData"
|
style="width: 75%"
|
||||||
size="small" :pagination="false">
|
bordered
|
||||||
<template #bodyCell="{ column,record,index }">
|
:columns="infoClockingColumns"
|
||||||
<template v-if="column.dataIndex==='dateTime'">
|
:data-source="checkInData"
|
||||||
<span v-if="record.dateType==0">{{ record.startDate }}</span>
|
size="small"
|
||||||
<span v-else>{{ record.startDate + '~' + record.endDate }}</span>
|
:pagination="false"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record, index }">
|
||||||
|
<template v-if="column.dataIndex === 'dateTime'">
|
||||||
|
<span v-if="record.dateType == 0">{{
|
||||||
|
record.startDate
|
||||||
|
}}</span>
|
||||||
|
<span v-else>{{
|
||||||
|
record.startDate + '~' + record.endDate
|
||||||
|
}}</span>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</Table>
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
</DescriptionsItem>
|
</DescriptionsItem>
|
||||||
<DescriptionsItem label="排班周期" v-if="groupDetail.attendanceType==1">
|
<DescriptionsItem
|
||||||
<p class="item-font">周期天数
|
label="排班周期"
|
||||||
<span class="item-font-weight item-font-color">{{ cycleData.length }}</span>
|
v-if="groupDetail.attendanceType == 1"
|
||||||
天</p>
|
>
|
||||||
<Table style="width: 80%;margin-top: 5px" bordered :columns="infoCycleColumns" :data-source="cycleData"
|
<p class="item-font">
|
||||||
size="small" :pagination="false">
|
周期天数
|
||||||
<template #bodyCell="{ column,record,index }">
|
<span class="item-font-weight item-font-color">{{
|
||||||
<template v-if="column.dataIndex==='day'">
|
cycleData.length
|
||||||
|
}}</span>
|
||||||
|
天
|
||||||
|
</p>
|
||||||
|
<Table
|
||||||
|
style="width: 80%; margin-top: 5px"
|
||||||
|
bordered
|
||||||
|
:columns="infoCycleColumns"
|
||||||
|
:data-source="cycleData"
|
||||||
|
size="small"
|
||||||
|
:pagination="false"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record, index }">
|
||||||
|
<template v-if="column.dataIndex === 'day'">
|
||||||
<span>{{ '第' + (index + 1) + '天' }}</span>
|
<span>{{ '第' + (index + 1) + '天' }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="column.dataIndex==='shiftId'">
|
<template v-if="column.dataIndex === 'shiftId'">
|
||||||
<!-- {{item.name+'\xa0'}}-->
|
<!-- {{item.name+'\xa0'}}-->
|
||||||
<!-- <span v-if="item.isRest">{{item.startTime+'~'+item.restStartTime+'\xa0'+item.restEndTime+'~'+item.endTime}}</span>-->
|
<!-- <span v-if="item.isRest">{{item.startTime+'~'+item.restStartTime+'\xa0'+item.restEndTime+'~'+item.endTime}}</span>-->
|
||||||
<!-- <span v-else>{{item.startTime+'~'+item.endTime}}</span>-->
|
<!-- <span v-else>{{item.startTime+'~'+item.endTime}}</span>-->
|
||||||
@@ -159,7 +207,11 @@ async function showHoliday() {
|
|||||||
padding: 1.1rem 0 0.5rem 0;
|
padding: 1.1rem 0 0.5rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ant-descriptions .ant-descriptions-item-container .ant-descriptions-item-content) {
|
:deep(
|
||||||
|
.ant-descriptions
|
||||||
|
.ant-descriptions-item-container
|
||||||
|
.ant-descriptions-item-content
|
||||||
|
) {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref, reactive,onMounted } from 'vue';
|
import { computed, reactive,onMounted } from 'vue';
|
||||||
|
|
||||||
import { useVbenModal } from '@vben/common-ui';
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
import { $t } from '@vben/locales';
|
import { $t } from '@vben/locales';
|
||||||
@@ -17,6 +17,9 @@ import unitPersonModal from './unit-person-modal.vue';
|
|||||||
import {groupList} from '#/api/property/attendanceManagement/attendanceGroupSettings'
|
import {groupList} from '#/api/property/attendanceManagement/attendanceGroupSettings'
|
||||||
import {getDictOptions} from "#/utils/dict";
|
import {getDictOptions} from "#/utils/dict";
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
import type { PersonVO } from './type';
|
||||||
|
import { ref, h } from 'vue';
|
||||||
|
import { Tag,Table } from 'ant-design-vue';
|
||||||
const emit = defineEmits<{ reload: [] }>();
|
const emit = defineEmits<{ reload: [] }>();
|
||||||
const isUpdate = ref(false);
|
const isUpdate = ref(false);
|
||||||
const title = computed(() => {
|
const title = computed(() => {
|
||||||
@@ -24,7 +27,77 @@ const title = computed(() => {
|
|||||||
});
|
});
|
||||||
const groupOptions = ref<any[]>([]);
|
const groupOptions = ref<any[]>([]);
|
||||||
const groupMap = ref<Record<string, any>>({}); // 用于快速查找
|
const groupMap = ref<Record<string, any>>({}); // 用于快速查找
|
||||||
|
const tableData = reactive<{dept: {unitId: string | number,unitName: string}, users: PersonVO[]}[]>([]);
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: '序号',
|
||||||
|
dataIndex: 'index',
|
||||||
|
key: 'index',
|
||||||
|
width: 60,
|
||||||
|
customRender: ({ index }: { index: number }) => index + 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '部门',
|
||||||
|
dataIndex: ['dept', 'unitName'],
|
||||||
|
key: 'dept',
|
||||||
|
width: 120,
|
||||||
|
customRender: ({ record }: { record: any }) => record.dept.unitName,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '已选人数',
|
||||||
|
dataIndex: 'users',
|
||||||
|
key: 'userCount',
|
||||||
|
width: 100,
|
||||||
|
customRender: ({ record }: { record: any }) => record.users.length,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '人员',
|
||||||
|
dataIndex: 'users',
|
||||||
|
key: 'users',
|
||||||
|
customRender: ({ record }: { record: any }) =>
|
||||||
|
record.users.map((user: any) =>
|
||||||
|
h(
|
||||||
|
Tag,
|
||||||
|
{
|
||||||
|
color: 'blue',
|
||||||
|
closable: true,
|
||||||
|
onClose: (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
handleRemoveUser(record, user);
|
||||||
|
},
|
||||||
|
style: 'margin-right: 4px;',
|
||||||
|
},
|
||||||
|
() => user.userName
|
||||||
|
)
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'action',
|
||||||
|
width: 80,
|
||||||
|
customRender: ({ record, index }: { record: any, index: number }) =>
|
||||||
|
h(
|
||||||
|
'a',
|
||||||
|
{
|
||||||
|
style: 'color: #ff4d4f; font-size: 18px; margin-left: 8px; cursor: pointer;',
|
||||||
|
onClick: () => handleRemoveRow(index),
|
||||||
|
},
|
||||||
|
'移除'
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function handleRemoveUser(row: any, user: any) {
|
||||||
|
row.users = row.users.filter((u: any) => u.id !== user.id);
|
||||||
|
}
|
||||||
|
function handleRemoveRow(index: number) {
|
||||||
|
tableData.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleTableData(newTableData: any) {
|
||||||
|
tableData.splice(0, tableData.length, ...newTableData);
|
||||||
|
}
|
||||||
//表单项
|
//表单项
|
||||||
const formModel = reactive<{
|
const formModel = reactive<{
|
||||||
id: string;
|
id: string;
|
||||||
@@ -111,68 +184,7 @@ const [BasicModal, modalApi] = useVbenModal({
|
|||||||
modalApi.modalLoading(false);
|
modalApi.modalLoading(false);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
// mock 表格数据
|
const totalSelected:number = 0;
|
||||||
const tableData = ref([
|
|
||||||
{ dept: 'xx部门', users: ['张三', '张三', '张三', '张三', '张三', '张三', '张三', '张三', '张三', '张三', '张三'] },
|
|
||||||
{ dept: 'xx部门', users: ['张三', '张三', '张三', '张三', '张三', '张三', '张三', '张三', '张三', '张三', '张三'] },
|
|
||||||
{ dept: '', users: [] },
|
|
||||||
]);
|
|
||||||
const staticData = [
|
|
||||||
{ id: 1, dept: 'xx部门', name: '张三' },
|
|
||||||
{ id: 2, dept: 'yy部门', name: '李四' },
|
|
||||||
];
|
|
||||||
const totalSelected = computed(() => tableData.value.reduce((sum, row) => sum + row.users.length, 0));
|
|
||||||
|
|
||||||
const gridOptions: VxeGridProps = {
|
|
||||||
checkboxConfig: {
|
|
||||||
// 高亮
|
|
||||||
highlight: true,
|
|
||||||
// 翻页时保留选中状态
|
|
||||||
reserve: true,
|
|
||||||
// 点击行选中
|
|
||||||
// trigger: 'row',
|
|
||||||
},
|
|
||||||
// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新
|
|
||||||
columns: attendanceColumns,
|
|
||||||
// columns,
|
|
||||||
// height: 'auto',
|
|
||||||
keepSource: true,
|
|
||||||
data:staticData,
|
|
||||||
pagerConfig: {},
|
|
||||||
proxyConfig: {
|
|
||||||
// ajax: {
|
|
||||||
// query: async ({ page }, formValues = {}) => {
|
|
||||||
// return await arrangementList({
|
|
||||||
// pageNum: page.currentPage,
|
|
||||||
// pageSize: page.pageSize,
|
|
||||||
// ...formValues,
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
},
|
|
||||||
rowConfig: {
|
|
||||||
keyField: 'id',
|
|
||||||
},
|
|
||||||
// 表格全局唯一表示 保存列配置需要用到
|
|
||||||
id: 'property-arrangement-index',
|
|
||||||
toolbarConfig: {
|
|
||||||
// 隐藏"刷新/重置"按钮(对应 redo)
|
|
||||||
refresh: false,
|
|
||||||
zoom: false, // 显示全屏
|
|
||||||
custom: false, // 隐藏列设置
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const [BasicTable, tableApi] = useVbenVxeGrid({
|
|
||||||
gridOptions,
|
|
||||||
});
|
|
||||||
async function handleEdit(row: any){
|
|
||||||
modalApi.setData({ id: row.id });
|
|
||||||
modalApi.open();
|
|
||||||
}
|
|
||||||
async function handleDelete(row: any) {
|
|
||||||
console.log(12);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function handleAdd() {
|
function handleAdd() {
|
||||||
unitPersonmodalApi.setData({});
|
unitPersonmodalApi.setData({});
|
||||||
@@ -303,27 +315,15 @@ onMounted(() => {
|
|||||||
<span>考勤组人员(已选 <span class="text-red-500">{{ totalSelected }}</span> 人)</span>
|
<span>考勤组人员(已选 <span class="text-red-500">{{ totalSelected }}</span> 人)</span>
|
||||||
<a-button type="primary" size="small" class="ml-4" @click="handleAdd">+ 添加人员</a-button>
|
<a-button type="primary" size="small" class="ml-4" @click="handleAdd">+ 添加人员</a-button>
|
||||||
</div>
|
</div>
|
||||||
<BasicTable>
|
<Table
|
||||||
<template #action="{ row }">
|
:columns="columns"
|
||||||
<Space>
|
:dataSource="tableData"
|
||||||
<Popconfirm
|
:pagination="false"
|
||||||
placement="left"
|
rowKey="dept.unitId"
|
||||||
title="确认移除?"
|
bordered
|
||||||
@confirm="handleDelete(row)"
|
/>
|
||||||
>
|
|
||||||
<ghost-button
|
|
||||||
danger
|
|
||||||
v-access:code="['property:arrangement:remove']"
|
|
||||||
@click.stop=""
|
|
||||||
>
|
|
||||||
移除
|
|
||||||
</ghost-button>
|
|
||||||
</Popconfirm>
|
|
||||||
</Space>
|
|
||||||
</template>
|
|
||||||
</BasicTable>
|
|
||||||
</div>
|
</div>
|
||||||
<UnitPersonModal />
|
<UnitPersonModal @reload="handleTableData"/>
|
||||||
<!-- 底部按钮区 -->
|
<!-- 底部按钮区 -->
|
||||||
</BasicModal>
|
</BasicModal>
|
||||||
</template>
|
</template>
|
||||||
|
@@ -5,7 +5,7 @@ import {ref} from 'vue';
|
|||||||
import { Dayjs } from 'dayjs';
|
import { Dayjs } from 'dayjs';
|
||||||
import arrangementModal from './arrangement-modal.vue';
|
import arrangementModal from './arrangement-modal.vue';
|
||||||
import {useVbenModal} from '@vben/common-ui';
|
import {useVbenModal} from '@vben/common-ui';
|
||||||
|
import type { PersonVO } from './type';
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'changeView',value:boolean):void
|
(e: 'changeView',value:boolean):void
|
||||||
}>();
|
}>();
|
||||||
@@ -77,6 +77,7 @@ function handleAdd() {
|
|||||||
modalApi.setData({});
|
modalApi.setData({});
|
||||||
modalApi.open();
|
modalApi.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="h-full flex flex-col">
|
<div class="h-full flex flex-col">
|
||||||
|
@@ -174,17 +174,17 @@ export const unitColumns: VxeGridProps['columns'] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '姓名',
|
title: '姓名',
|
||||||
field: 'scheduleName',
|
field: 'userName',
|
||||||
minWidth:120
|
minWidth:120
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '所属单位',
|
title: '所属单位',
|
||||||
field: 'scheduleName',
|
field: 'unitName',
|
||||||
width:'auto',
|
width:'auto',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '电话',
|
title: '电话',
|
||||||
field: 'groupId',
|
field: 'phone',
|
||||||
minWidth:120
|
minWidth:120
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
68
apps/web-antd/src/views/property/attendanceManagement/workforceManagement/type.d.ts
vendored
Normal file
68
apps/web-antd/src/views/property/attendanceManagement/workforceManagement/type.d.ts
vendored
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
//列表数据,用于展示人员列表
|
||||||
|
export interface PersonVO {
|
||||||
|
/**
|
||||||
|
* 主键id
|
||||||
|
*/
|
||||||
|
id: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
|
userId: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户名称
|
||||||
|
*/
|
||||||
|
userName: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 联系电话
|
||||||
|
*/
|
||||||
|
phone: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 性别
|
||||||
|
*/
|
||||||
|
gender: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人脸图片
|
||||||
|
*/
|
||||||
|
img: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所属单位id
|
||||||
|
*/
|
||||||
|
unitId: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所属单位名称
|
||||||
|
*/
|
||||||
|
unitName: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 入驻位置
|
||||||
|
*/
|
||||||
|
locathon: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 入驻时间
|
||||||
|
*/
|
||||||
|
time: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车牌号码
|
||||||
|
*/
|
||||||
|
carNumber: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
state: number|string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
remark: string;
|
||||||
|
|
||||||
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref, reactive, onMounted } from 'vue';
|
import { computed, ref, reactive, onMounted, watch } from 'vue';
|
||||||
import { SyncOutlined } from '@ant-design/icons-vue';
|
import { SyncOutlined } from '@ant-design/icons-vue';
|
||||||
import { Tree, InputSearch, Skeleton, Empty, Button } from 'ant-design-vue';
|
import { Tree, InputSearch, Skeleton, Empty, Button,Tag } from 'ant-design-vue';
|
||||||
|
|
||||||
import { $t } from '@vben/locales';
|
import { $t } from '@vben/locales';
|
||||||
import { cloneDeep } from '@vben/utils';
|
import { cloneDeep } from '@vben/utils';
|
||||||
@@ -16,7 +16,9 @@ import {
|
|||||||
import { modalSchema,unitColumns,unitQuerySchema } from './data';
|
import { modalSchema,unitColumns,unitQuerySchema } from './data';
|
||||||
import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui';
|
import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui';
|
||||||
import { resident_unitList } from '#/api/property/resident/unit';
|
import { resident_unitList } from '#/api/property/resident/unit';
|
||||||
const emit = defineEmits<{ reload: [] }>();
|
import { personList } from '#/api/property/resident/person';
|
||||||
|
import type { PersonVO } from './type';
|
||||||
|
const emit = defineEmits<{ reload: [tableData: {dept: {unitId: string | number,unitName: string}, users: PersonVO[]}[]] }>();
|
||||||
const selectDeptId = ref<string[]>([]);
|
const selectDeptId = ref<string[]>([]);
|
||||||
const isUpdate = ref(false);
|
const isUpdate = ref(false);
|
||||||
const title = computed(() => {
|
const title = computed(() => {
|
||||||
@@ -27,28 +29,29 @@ const searchValue = ref('');
|
|||||||
const selectedDeptIds = ref<string[]>([]);
|
const selectedDeptIds = ref<string[]>([]);
|
||||||
const showTreeSkeleton = ref(false);
|
const showTreeSkeleton = ref(false);
|
||||||
//单位树
|
//单位树
|
||||||
const deptTree = reactive([
|
const deptTree = reactive<{
|
||||||
{
|
id: string;
|
||||||
id: '',
|
label: string;
|
||||||
label: '全部单位',
|
children: {
|
||||||
children: [
|
id: string;
|
||||||
{ id: '1-3', label: '人事部' },
|
label: string;
|
||||||
],
|
}[];
|
||||||
},
|
}[]>([
|
||||||
|
{
|
||||||
|
id: '',
|
||||||
|
label: '全部单位',
|
||||||
|
children: [
|
||||||
|
],
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
//勾选内容
|
||||||
|
const selectedUsers = ref<PersonVO[]>([]);
|
||||||
//已选内容,需要展示到父组件
|
//已选内容,需要展示到父组件
|
||||||
const tableData = ref([
|
|
||||||
{ dept: 'xx部门', users: ['张三', '张三', '张三', '张三', '张三', '张三', '张三', '张三', '张三', '张三', '张三'] },
|
|
||||||
{ dept: 'xx部门', users: ['张三', '张三', '张三', '张三', '张三', '张三', '张三', '张三', '张三', '张三', '张三'] },
|
|
||||||
{ dept: '', users: [] },
|
|
||||||
]);
|
|
||||||
//已选人
|
|
||||||
const staticData = [
|
|
||||||
{ id: 1, dept: 'xx部门', name: '张三' },
|
|
||||||
{ id: 2, dept: 'yy部门', name: '李四' },
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
|
const tableData = reactive<{
|
||||||
|
dept: {unitId: string | number,unitName: string},
|
||||||
|
users: PersonVO[]}[]>([]);
|
||||||
function handleReload() {
|
function handleReload() {
|
||||||
showTreeSkeleton.value = true;
|
showTreeSkeleton.value = true;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -57,7 +60,7 @@ function handleReload() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const filteredDeptTree = computed(() => {
|
const filteredDeptTree = computed(() => {
|
||||||
if (!searchValue.value) return deptTree.value;
|
if (!searchValue.value) return deptTree;
|
||||||
// 递归过滤树
|
// 递归过滤树
|
||||||
function filter(tree: any[]): any[] {
|
function filter(tree: any[]): any[] {
|
||||||
return tree
|
return tree
|
||||||
@@ -71,27 +74,9 @@ const filteredDeptTree = computed(() => {
|
|||||||
})
|
})
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
}
|
}
|
||||||
return filter(deptTree.value);
|
return filter(deptTree);
|
||||||
});
|
});
|
||||||
const formOptions: VbenFormProps = {
|
|
||||||
commonConfig: {
|
|
||||||
labelWidth: 80,
|
|
||||||
componentProps: {
|
|
||||||
allowClear: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
schema: unitQuerySchema(),
|
|
||||||
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
|
|
||||||
// 处理区间选择器RangePicker时间格式 将一个字段映射为两个字段 搜索/导出会用到
|
|
||||||
// 不需要直接删除
|
|
||||||
// fieldMappingTime: [
|
|
||||||
// [
|
|
||||||
// 'createTime',
|
|
||||||
// ['params[beginTime]', 'params[endTime]'],
|
|
||||||
// ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
|
|
||||||
// ],
|
|
||||||
// ],
|
|
||||||
};
|
|
||||||
const [BasicForm, formApi] = useVbenForm({
|
const [BasicForm, formApi] = useVbenForm({
|
||||||
commonConfig: {
|
commonConfig: {
|
||||||
// 默认占满两列
|
// 默认占满两列
|
||||||
@@ -127,72 +112,35 @@ const [BasicModal, modalApi] = useVbenModal({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
modalApi.modalLoading(true);
|
modalApi.modalLoading(true);
|
||||||
console.log(12)
|
|
||||||
const { id } = modalApi.getData() as { id?: number | string };
|
const { id } = modalApi.getData() as { id?: number | string };
|
||||||
console.log(2)
|
|
||||||
|
|
||||||
isUpdate.value = !!id;
|
isUpdate.value = !!id;
|
||||||
|
|
||||||
if (isUpdate.value && id) {
|
if (isUpdate.value && id) {
|
||||||
console.log(3)
|
|
||||||
|
|
||||||
const record = await arrangementInfo(id);
|
const record = await arrangementInfo(id);
|
||||||
await formApi.setValues(record);
|
await formApi.setValues(record);
|
||||||
}
|
}
|
||||||
console.log(4)
|
|
||||||
|
|
||||||
// await markInitialized();
|
// await markInitialized();
|
||||||
console.log(5)
|
|
||||||
|
|
||||||
modalApi.modalLoading(false);
|
modalApi.modalLoading(false);
|
||||||
console.log(6)
|
|
||||||
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const formOptions: VbenFormProps = {
|
||||||
async function handleConfirm() {
|
commonConfig: {
|
||||||
try {
|
labelWidth: 80,
|
||||||
modalApi.lock(true);
|
componentProps: {
|
||||||
const { valid } = await formApi.validate();
|
allowClear: true,
|
||||||
if (!valid) {
|
},
|
||||||
return;
|
},
|
||||||
}
|
schema: unitQuerySchema(),
|
||||||
// getValues获取为一个readonly的对象 需要修改必须先深拷贝一次
|
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
|
||||||
const data = cloneDeep(await formApi.getValues());
|
// 处理区间选择器RangePicker时间格式 将一个字段映射为两个字段 搜索/导出会用到
|
||||||
await (isUpdate.value ? arrangementUpdate(data) : arrangementAdd(data));
|
// 不需要直接删除
|
||||||
resetInitialized();
|
// fieldMappingTime: [
|
||||||
emit('reload');
|
// [
|
||||||
modalApi.close();
|
// 'createTime',
|
||||||
} catch (error) {
|
// ['params[beginTime]', 'params[endTime]'],
|
||||||
console.error(error);
|
// ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
|
||||||
} finally {
|
// ],
|
||||||
modalApi.lock(false);
|
// ],
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
async function handleClosed() {
|
|
||||||
await formApi.resetForm();
|
|
||||||
resetInitialized();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const formModel = reactive({
|
|
||||||
group: '',
|
|
||||||
type: '',
|
|
||||||
dateType: 'long',
|
|
||||||
dateSingle: null,
|
|
||||||
dateLong: null,
|
|
||||||
dateRange: [null, null],
|
|
||||||
startDate:'',
|
|
||||||
endDate:''
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
const totalSelected = computed(() => tableData.value.reduce((sum, row) => sum + row.users.length, 0));
|
|
||||||
|
|
||||||
function addRow() {
|
|
||||||
tableData.value.push({ dept: '', users: [] });
|
|
||||||
}
|
|
||||||
const gridOptions: VxeGridProps = {
|
const gridOptions: VxeGridProps = {
|
||||||
checkboxConfig: {
|
checkboxConfig: {
|
||||||
// 高亮
|
// 高亮
|
||||||
@@ -207,18 +155,18 @@ const gridOptions: VxeGridProps = {
|
|||||||
// columns,
|
// columns,
|
||||||
// height: 'auto',
|
// height: 'auto',
|
||||||
keepSource: true,
|
keepSource: true,
|
||||||
data:staticData,
|
// data:selectedUsers,
|
||||||
pagerConfig: {},
|
pagerConfig: {},
|
||||||
proxyConfig: {
|
proxyConfig: {
|
||||||
// ajax: {
|
ajax: {
|
||||||
// query: async ({ page }, formValues = {}) => {
|
query: async ({ page }) => {
|
||||||
// return await arrangementList({
|
return await personList({
|
||||||
// pageNum: page.currentPage,
|
pageNum: page.currentPage,
|
||||||
// pageSize: page.pageSize,
|
pageSize: page.pageSize,
|
||||||
// ...formValues,
|
unitId: selectedDeptIds.value[0],
|
||||||
// });
|
});
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
},
|
},
|
||||||
rowConfig: {
|
rowConfig: {
|
||||||
keyField: 'id',
|
keyField: 'id',
|
||||||
@@ -232,21 +180,73 @@ const gridOptions: VxeGridProps = {
|
|||||||
custom: false, // 隐藏列设置
|
custom: false, // 隐藏列设置
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const gridEvents = {
|
||||||
|
checkboxChange:async (params:any) => {
|
||||||
|
const currentRecords = await params.$grid.getCheckboxRecords()??[];
|
||||||
|
const reserveRecords = await params.$grid.getCheckboxReserveRecords()??[];
|
||||||
|
selectedUsers.value = [...reserveRecords, ...currentRecords];
|
||||||
|
},
|
||||||
|
checkboxAll:async (params:any) => {
|
||||||
|
const currentRecords = await params.$grid.getCheckboxRecords()??[];
|
||||||
|
const reserveRecords = await params.$grid.getCheckboxReserveRecords()??[];
|
||||||
|
selectedUsers.value = [...reserveRecords, ...currentRecords];
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
||||||
const [BasicTable, tableApi] = useVbenVxeGrid({
|
const [BasicTable, tableApi] = useVbenVxeGrid({
|
||||||
formOptions,
|
formOptions,
|
||||||
gridOptions,
|
gridOptions,
|
||||||
|
gridEvents
|
||||||
});
|
});
|
||||||
|
|
||||||
async function getUnitList(){
|
async function handleConfirm() {
|
||||||
const res = await resident_unitList();
|
try {
|
||||||
for(const item of res.rows){
|
for(const user of selectedUsers.value){
|
||||||
deptTree.
|
if(tableData.find(item=>item.dept.unitId === user.unitId)){
|
||||||
|
tableData.find(item=>item.dept.unitId===user.unitId)!.users.push(user);
|
||||||
|
}else{
|
||||||
|
tableData.push({ dept:{unitId:user.unitId,unitName:user.unitName}, users: [user] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(tableData);
|
||||||
|
resetInitialized();
|
||||||
|
emit('reload',tableData);
|
||||||
|
modalApi.close();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
} finally {
|
||||||
|
modalApi.lock(false);
|
||||||
}
|
}
|
||||||
console.log(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleClosed() {
|
||||||
|
await formApi.resetForm();
|
||||||
|
resetInitialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getUnitList(){
|
||||||
|
deptTree[0]!.children = [];
|
||||||
|
const res = await resident_unitList();
|
||||||
|
if (deptTree[0] && Array.isArray(deptTree[0].children)) {
|
||||||
|
for(const item of res.rows){
|
||||||
|
deptTree[0].children.push({
|
||||||
|
id: item.id as string,
|
||||||
|
label: item.name as string,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 查询对应部门人员列表
|
||||||
|
async function fetchDeptUsers() {
|
||||||
|
tableApi.query();
|
||||||
|
}
|
||||||
|
watch(selectedDeptIds, (newVal) => {
|
||||||
|
if (newVal && newVal.length > 0) {
|
||||||
|
fetchDeptUsers();
|
||||||
|
}
|
||||||
|
});
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getUnitList();
|
getUnitList();
|
||||||
console.log(tableData.value);
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -263,7 +263,7 @@ onMounted(() => {
|
|||||||
style="flex:1;"
|
style="flex:1;"
|
||||||
>
|
>
|
||||||
<template #enterButton>
|
<template #enterButton>
|
||||||
<Button type="text" @click="handleReload">
|
<Button type="text" @click="getUnitList">
|
||||||
<SyncOutlined class="text-primary" />
|
<SyncOutlined class="text-primary" />
|
||||||
</Button>
|
</Button>
|
||||||
</template>
|
</template>
|
||||||
@@ -297,6 +297,9 @@ onMounted(() => {
|
|||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<div class="flex mb-2 overflow-auto" style="max-height: 80px;font-size: 14px;">
|
<div class="flex mb-2 overflow-auto" style="max-height: 80px;font-size: 14px;">
|
||||||
已选人员:
|
已选人员:
|
||||||
|
<span v-for="user in selectedUsers" :key="user.id" style="margin-right: 8px;">
|
||||||
|
<Tag>{{ user.userName }}</Tag>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<BasicTable>
|
<BasicTable>
|
||||||
</BasicTable>
|
</BasicTable>
|
||||||
|
Reference in New Issue
Block a user