feat: 格式化代码

This commit is contained in:
fyy
2025-07-23 14:40:26 +08:00
parent d03743f996
commit d91cfeb388
8 changed files with 507 additions and 388 deletions

View File

@@ -1,25 +1,34 @@
<script setup lang="ts">
import { computed, reactive,onMounted } from 'vue';
import { computed, reactive, onMounted } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { useVbenForm } from '#/adapter/form';
import { arrangementAdd, arrangementInfo, arrangementUpdate } from '#/api/property/attendanceManagement/arrangement';
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
import {
useVbenVxeGrid,
type VxeGridProps
} from '#/adapter/vxe-table';
import { modalSchema,attendanceColumns } from './data';
import { Radio,DatePicker,Form,Select,FormItem,RadioGroup, message } from 'ant-design-vue';
arrangementAdd,
arrangementInfo,
arrangementUpdate,
} from '#/api/property/attendanceManagement/arrangement';
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
import { useVbenVxeGrid, type VxeGridProps } from '#/adapter/vxe-table';
import { modalSchema, attendanceColumns } from './data';
import {
Radio,
DatePicker,
Form,
Select,
FormItem,
RadioGroup,
message,
} from 'ant-design-vue';
import unitPersonModal from './unit-person-modal.vue';
import {groupList} from '#/api/property/attendanceManagement/attendanceGroupSettings'
import {getDictOptions} from "#/utils/dict";
import { groupList } from '#/api/property/attendanceManagement/attendanceGroupSettings';
import { getDictOptions } from '#/utils/dict';
import dayjs from 'dayjs';
import type { PersonVO } from './type';
import { ref, h } from 'vue';
import { Tag,Table } from 'ant-design-vue';
import { Tag, Table } from 'ant-design-vue';
const emit = defineEmits<{ reload: [] }>();
const isUpdate = ref(false);
const title = computed(() => {
@@ -27,7 +36,9 @@ const title = computed(() => {
});
const groupOptions = ref<any[]>([]);
const groupMap = ref<Record<string, any>>({}); // 用于快速查找
const tableData = reactive<{dept: {unitId: string | number,unitName: string}, users: PersonVO[]}[]>([]);
const tableData = reactive<
{ dept: { unitId: string | number; unitName: string }; users: PersonVO[] }[]
>([]);
const columns = [
{
@@ -68,22 +79,23 @@ const columns = [
},
style: 'margin-right: 4px;',
},
() => user.userName
)
() => user.userName,
),
),
},
{
title: '操作',
key: 'action',
width: 80,
customRender: ({ record, index }: { record: any, index: number }) =>
customRender: ({ record, index }: { record: any; index: number }) =>
h(
'a',
'a',
{
style: 'color: #ff4d4f; font-size: 18px; margin-left: 8px; cursor: pointer;',
style:
'color: #ff4d4f; font-size: 18px; margin-left: 8px; cursor: pointer;',
onClick: () => handleRemoveRow(index),
},
'移除'
'移除',
),
},
];
@@ -103,27 +115,27 @@ const formModel = reactive<{
id: string;
groupId: string;
attendanceType: string;
dateType: number | undefined;
dateType: number | undefined;
startDate: string;
endDate: string;
userGroupList: any[];
}>({
id: '',
groupId: '',
attendanceType:'',//考勤组类型
dateType: undefined,//日期类型1-单个日期2-长期有效3-期间有效
attendanceType: '', //考勤组类型
dateType: undefined, //日期类型1-单个日期2-长期有效3-期间有效
// dateSingle: null,
// dateLong: null,
// dateRange: [null, null],
startDate:'',//开始日期
endDate:'',//结束日期
userGroupList:[
// scheduleId:undefined,//排班ID
// employeeId:undefined,//员工ID
// employeeName:undefined,//员工姓名
// deptId:undefined,//部门ID
// deptName:undefined,//部门名称
]//考勤组人员列表
startDate: '', //开始日期
endDate: '', //结束日期
userGroupList: [
// scheduleId:undefined,//排班ID
// employeeId:undefined,//员工ID
// employeeName:undefined,//员工姓名
// deptId:undefined,//部门ID
// deptName:undefined,//部门名称
], //考勤组人员列表
});
const singleDate = ref('');
const longDate = ref('');
@@ -143,7 +155,7 @@ const [BasicForm, formApi] = useVbenForm({
// 通用配置项 会影响到所有表单项
componentProps: {
class: 'w-full',
}
},
},
schema: modalSchema(),
showDefaultActions: false,
@@ -184,37 +196,37 @@ const [BasicModal, modalApi] = useVbenModal({
modalApi.modalLoading(false);
},
});
const totalSelected:number = 0;
const totalSelected: number = 0;
function handleAdd() {
unitPersonmodalApi.setData({});
unitPersonmodalApi.open();
}
async function getGroupList(){
async function getGroupList() {
const res = await groupList({
pageSize:1000000000,
pageNum:1,
status:1//0:停用 1:启用
pageSize: 1000000000,
pageNum: 1,
status: 1, //0:停用 1:启用
});
groupOptions.value = (res.rows || []).map(item=>({
label:item.groupName,
value:item.id
groupOptions.value = (res.rows || []).map((item) => ({
label: item.groupName,
value: item.id,
}));
// 构建 id 到 group 对象的映射
// 构建 id 到 group 对象的映射
groupMap.value = {};
(res.rows || []).forEach(item => {
(res.rows || []).forEach((item) => {
groupMap.value[item.id] = item;
});
}
function chooseGroup(value:any){
function chooseGroup(value: any) {
console.log(value);
const group = groupMap.value[value];
if(group){
if (group) {
formModel.attendanceType = String(group.attendanceType);
}
}
async function handleDateTypeChange(value:any){
async function handleDateTypeChange(value: any) {
formModel.dateType = value;
}
async function handleConfirm() {
@@ -222,36 +234,35 @@ async function handleConfirm() {
modalApi.lock(true);
// await formRef.value.validate(); // 先校验
const data = formModel;
const { id } = modalApi.getData() as { id?:string };
data.id = id? id:'';
const { id } = modalApi.getData() as { id?: string };
data.id = id ? id : '';
console.log(data);
if(data.dateType == 1){
if(singleDate.value){
if (data.dateType == 1) {
if (singleDate.value) {
data.startDate = dayjs(singleDate.value).format('YYYY-MM-DD');
}else{
message.error('请选择单个日期')
} else {
message.error('请选择单个日期');
return;
}
}else if(data.dateType == 2){
if(longDate.value){
} else if (data.dateType == 2) {
if (longDate.value) {
data.startDate = dayjs(longDate.value).format('YYYY-MM-DD');
}else{
message.error('请选择起始日期')
} else {
message.error('请选择起始日期');
return;
}
}else if(data.dateType == 3){
if(!rangeDate.value[0]){
message.error('请选择开始日期')
} else if (data.dateType == 3) {
if (!rangeDate.value[0]) {
message.error('请选择开始日期');
return;
}else if(!rangeDate.value[1]){
message.error('请选择结束日期')
} else if (!rangeDate.value[1]) {
message.error('请选择结束日期');
return;
}else{
} else {
data.startDate = dayjs(rangeDate.value[0]).format('YYYY-MM-DD');
data.endDate = dayjs(rangeDate.value[1]).format('YYYY-MM-DD');
}
}
// await (isUpdate.value ? arrangementUpdate(data) : arrangementAdd(data));
resetInitialized();
@@ -268,41 +279,69 @@ async function handleClosed() {
await formApi.resetForm();
resetInitialized();
}
onMounted(() => {
})
onMounted(() => {});
</script>
<template>
<BasicModal :title="title">
<BasicModal :title="title">
<!-- 顶部表单区 -->
<Form :model="formModel" :rules="rules" ref="formRef" layout="horizontal" class="mb-4" >
<Form
:model="formModel"
:rules="rules"
ref="formRef"
layout="horizontal"
class="mb-4"
>
<div class="grid grid-cols-2 gap-x-8 gap-y-2">
<FormItem name="groupId" label="请选择考勤组" class="mb-0">
<Select v-model:value="formModel.groupId" :options="groupOptions" placeholder="请选择" @change="chooseGroup"/>
<Select
v-model:value="formModel.groupId"
:options="groupOptions"
placeholder="请选择"
@change="chooseGroup"
/>
</FormItem>
<FormItem name="attendanceType" label="考勤类型" class="mb-0">
<Select :disabled="true" :options="getDictOptions('wy_kqlx')" v-model:value="formModel.attendanceType" placeholder="请选择考勤组" />
<FormItem name="attendanceType" label="考勤类型" class="mb-0">
<Select
:disabled="true"
:options="getDictOptions('wy_kqlx')"
v-model:value="formModel.attendanceType"
placeholder="请选择考勤组"
/>
</FormItem>
<FormItem label="排班日期" name="dateType" class="col-span-2 mb-0">
<RadioGroup v-model:value="formModel.dateType" class="mr-4">
<Radio value=1>
<Radio value="1">
<span>
单个日期
<DatePicker v-model:value="singleDate" @click="handleDateTypeChange(1)"/>
<DatePicker
v-model:value="singleDate"
@click="handleDateTypeChange(1)"
/>
</span>
</Radio>
<Radio value=2>
</Radio>
<Radio value="2">
<span>
从此日起长期有效
<DatePicker v-model:value="longDate" @click="handleDateTypeChange(2)"/>
<DatePicker
v-model:value="longDate"
@click="handleDateTypeChange(2)"
/>
</span>
</Radio>
<Radio value=3>
</Radio>
<Radio value="3">
<span>
在此期间有效
<DatePicker v-model:value="rangeDate[0]" class="ml-2" @click="handleDateTypeChange(3)"/>
<DatePicker
v-model:value="rangeDate[0]"
class="ml-2"
@click="handleDateTypeChange(3)"
/>
<span class="mx-2">~</span>
<DatePicker v-model:value="rangeDate[1]" @click="handleDateTypeChange(3)"/>
<DatePicker
v-model:value="rangeDate[1]"
@click="handleDateTypeChange(3)"
/>
</span>
</Radio>
</RadioGroup>
@@ -311,9 +350,14 @@ onMounted(() => {
</Form>
<!-- 考勤组人员表格区 -->
<div class="mb-2">
<div class="flex items-center mb-2">
<span>考勤组人员已选 <span class="text-red-500">{{ totalSelected }}</span> </span>
<a-button type="primary" size="small" class="ml-4" @click="handleAdd">+ 添加人员</a-button>
<div class="mb-2 flex items-center">
<span
>考勤组人员已选
<span class="text-red-500">{{ totalSelected }}</span> </span
>
<a-button type="primary" size="small" class="ml-4" @click="handleAdd"
>+ 添加人员</a-button
>
</div>
<Table
:columns="columns"
@@ -323,7 +367,7 @@ onMounted(() => {
bordered
/>
</div>
<UnitPersonModal @reload="handleTableData"/>
<UnitPersonModal @reload="handleTableData" />
<!-- 底部按钮区 -->
</BasicModal>
</template>
@@ -339,4 +383,4 @@ onMounted(() => {
/* 有些浏览器需要这个来覆盖默认颜色 */
-webkit-text-fill-color: rgba(0, 0, 0, 0.65) !important;
}
</style>
</style>

View File

@@ -1,36 +1,43 @@
<script lang="ts" setup>
import { Radio, Button,Calendar,DatePicker } from 'ant-design-vue';
import type { RadioChangeEvent,BadgeProps, } from 'ant-design-vue';
import {ref} from 'vue';
import { Radio, Button, Calendar, DatePicker } from 'ant-design-vue';
import type { RadioChangeEvent, BadgeProps } from 'ant-design-vue';
import { ref } from 'vue';
import { Dayjs } from 'dayjs';
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<{
(e: 'changeView',value:boolean):void
(e: 'changeView', value: boolean): void;
}>();
const props = defineProps<{
viewMode:'calender' | 'schedule'
viewMode: 'calender' | 'schedule';
}>();
const selectedDate = ref();
// 切换视图模式
function handleViewModeChange(e: RadioChangeEvent): void {
// 将父组件的isCalenderView变为true
emit('changeView',e.target.value)
emit('changeView', e.target.value);
}
// 日历模拟数据
const scheduleData:{ date: string; list: { type: BadgeProps['status']; content: string }[] }[] = [
{ date: '2025-07-08', list: [ { type: 'warning', content: '7月8日事件' } ] },
{ date: '2025-07-06', list: [ { type: 'success', content: '8月8日事件' } ] },
const scheduleData: {
date: string;
list: { type: BadgeProps['status']; content: string }[];
}[] = [
{ date: '2025-07-08', list: [{ type: 'warning', content: '7月8日事件' }] },
{ date: '2025-07-06', list: [{ type: 'success', content: '8月8日事件' }] },
// ...
];
const getListData2 = (current: Dayjs): { type: BadgeProps['status']; content: string }[] => {
const getListData2 = (
current: Dayjs,
): { type: BadgeProps['status']; content: string }[] => {
const dateStr = current.format('YYYY-MM-DD');
const found = scheduleData.find(item => item.date === dateStr);
const found = scheduleData.find((item) => item.date === dateStr);
return found ? found.list : [];
};
const getListData = (value: Dayjs):{ type: BadgeProps['status']; content: string }[] => {
const getListData = (
value: Dayjs,
): { type: BadgeProps['status']; content: string }[] => {
let listData: { type: BadgeProps['status']; content: string }[] | undefined;
switch (value.date()) {
case 8:
@@ -77,49 +84,63 @@ function handleAdd() {
modalApi.setData({});
modalApi.open();
}
</script>
<template>
<div class="h-full flex flex-col">
<div class="flex h-full flex-col">
<div class="flex justify-between">
<div class="flex gap-7">
<Radio.Group v-model:value="props.viewMode" @change="handleViewModeChange">
<Radio.Group
v-model:value="props.viewMode"
@change="handleViewModeChange"
>
<Radio.Button value="calender">日历视图</Radio.Button>
<Radio.Button value="schedule">班表视图</Radio.Button>
</Radio.Group>
<div class="my-auto flex gap-1">
<div class="my-auto">排班日历</div>
<DatePicker picker="month" v-model:value="selectedDate" />
</div>
</div>
</Radio.Group>
<div class="my-auto flex gap-1">
<div class="my-auto">排班日历</div>
<DatePicker picker="month" v-model:value="selectedDate" />
</div>
</div>
<div>
<Button type="primary" @click="handleAdd">新增排班</Button>
<Button type="primary" @click="handleAdd">新增排班</Button>
</div>
</div>
<div class="flex-1 p-1">
<Calendar v-model:value="selectedDate" :mode="'month'" :headerRender="customHeader">
<Calendar
v-model:value="selectedDate"
:mode="'month'"
:headerRender="customHeader"
>
<template #dateCellRender="{ current }">
<ul class="events">
<li v-for="item in getListData2(current)" :key="item.content">
<span>
<!-- <Badge :status="item.type" :text="item.content" /> -->
<span>{{ item.content }}</span>
<a style="margin-left: 4px; color: #1890ff; cursor: pointer;">编辑</a>
<a style="margin-left: 4px; color: #ff4d4f; cursor: pointer;">删除</a>
</span>
</li>
<a v-if="getListData2(current).length > 0" style="margin-left: 4px; color: #1890ff; cursor: pointer;">详情</a>
</ul>
</template>
<template #monthCellRender="{ current }">
<div v-if="getMonthData(current)" class="notes-month">
<section>{{ getMonthData(current) }}</section>
<span>Backlog number</span>
</div>
</template>
<ul class="events">
<li v-for="item in getListData2(current)" :key="item.content">
<span>
<!-- <Badge :status="item.type" :text="item.content" /> -->
<span>{{ item.content }}</span>
<a style="margin-left: 4px; color: #1890ff; cursor: pointer"
>编辑</a
>
<a style="margin-left: 4px; color: #ff4d4f; cursor: pointer"
>删除</a
>
</span>
</li>
<a
v-if="getListData2(current).length > 0"
style="margin-left: 4px; color: #1890ff; cursor: pointer"
>详情</a
>
</ul>
</template>
<template #monthCellRender="{ current }">
<div v-if="getMonthData(current)" class="notes-month">
<section>{{ getMonthData(current) }}</section>
<span>Backlog number</span>
</div>
</template>
</Calendar>
</div>
<ArrangementModal @reload=""/>
<ArrangementModal @reload="" />
</div>
</template>
<style scoped>

View File

@@ -1,7 +1,6 @@
import type { FormSchemaGetter } from '#/adapter/form';
import type { VxeGridProps } from '#/adapter/vxe-table';
export const querySchema: FormSchemaGetter = () => [
{
component: 'Input',
@@ -15,15 +14,13 @@ export const querySchema: FormSchemaGetter = () => [
},
{
component: 'Select',
componentProps: {
},
componentProps: {},
fieldName: 'scheduleType',
label: '排班类型1-固定班制2-排班制',
},
{
component: 'Select',
componentProps: {
},
componentProps: {},
fieldName: 'dateType',
label: '日期类型1-单个日期2-长期有效3-期间有效',
},
@@ -75,33 +72,33 @@ export const columns: VxeGridProps['columns'] = [
{
title: '序号',
field: 'id',
slots:{
default:({rowIndex}) => {
slots: {
default: ({ rowIndex }) => {
return (rowIndex + 1).toString();
}
},
},
width:60
width: 60,
},
{
title: '人员',
field: 'scheduleName',
width:120,
width: 120,
// width: 'auto',
},
{
title: '单位',
field: 'scheduleName',
width:'auto',
width: 'auto',
},
{
title: '排班名称',
field: 'scheduleName',
minWidth:120
minWidth: 120,
},
{
title: '考勤组',
field: 'groupId',
minWidth:120
minWidth: 120,
},
{
title: '考勤类型',
@@ -111,8 +108,7 @@ export const columns: VxeGridProps['columns'] = [
{
title: '考勤时间',
field: 'dateType',
minWidth:200
minWidth: 200,
},
{
field: 'action',
@@ -128,27 +124,27 @@ export const attendanceColumns: VxeGridProps['columns'] = [
{
title: '序号',
field: 'id',
slots:{
default:({rowIndex}) => {
slots: {
default: ({ rowIndex }) => {
return (rowIndex + 1).toString();
}
},
},
width:60
width: 60,
},
{
title: '单位',
field: 'scheduleName',
width:'auto',
width: 'auto',
},
{
title: '已选人数',
field: 'scheduleName',
width:'auto',
width: 'auto',
},
{
title: '人员',
field: 'dateType',
minWidth:200
minWidth: 200,
},
{
field: 'action',
@@ -165,28 +161,28 @@ export const unitColumns: VxeGridProps['columns'] = [
{
title: '序号',
field: 'id',
slots:{
default:({rowIndex}) => {
slots: {
default: ({ rowIndex }) => {
return (rowIndex + 1).toString();
}
},
},
width:60
width: 60,
},
{
title: '姓名',
field: 'userName',
minWidth:120
minWidth: 120,
},
{
title: '所属单位',
field: 'unitName',
width:'auto',
width: 'auto',
},
{
title: '电话',
field: 'phone',
minWidth:120
}
minWidth: 120,
},
];
export const modalSchema: FormSchemaGetter = () => [
{
@@ -212,15 +208,13 @@ export const modalSchema: FormSchemaGetter = () => [
label: '排班类型1-固定班制2-排班制',
fieldName: 'scheduleType',
component: 'Select',
componentProps: {
},
componentProps: {},
},
{
label: '日期类型1-单个日期2-长期有效3-期间有效',
fieldName: 'dateType',
component: 'Select',
componentProps: {
},
componentProps: {},
},
{
label: '开始日期',

View File

@@ -1,20 +1,27 @@
<script setup lang="ts">
import { ref } from 'vue';
import calendarView from './calendarView.vue'
import calendarView from './calendarView.vue';
import scheduleView from './scheduleView.vue';
const viewMode = ref<'calender' | 'schedule'>('calender');
// const isCalenderView = ref(true);
function handleViewModeChange(mode:'calender' | 'schedule'){
viewMode.value = mode
function handleViewModeChange(mode: 'calender' | 'schedule') {
viewMode.value = mode;
}
</script>
<template>
<div class="p-4 h-full">
<div class="p-4 h-full bg-white">
<calendarView v-show="viewMode === 'calender'" :viewMode="viewMode" @changeView="handleViewModeChange"/>
<scheduleView v-show="viewMode === 'schedule'" :viewMode="viewMode" @changeView="handleViewModeChange"/>
</div>
<div class="h-full p-4">
<div class="h-full bg-white p-4">
<calendarView
v-show="viewMode === 'calender'"
:viewMode="viewMode"
@changeView="handleViewModeChange"
/>
<scheduleView
v-show="viewMode === 'schedule'"
:viewMode="viewMode"
@changeView="handleViewModeChange"
/>
</div>
</div>
</template>
<style scoped>
</style>
<style scoped></style>

View File

@@ -1,13 +1,10 @@
<script lang="ts" setup>
import { Radio, Button, Calendar } from 'ant-design-vue';
import type { RadioChangeEvent } from 'ant-design-vue';
import {ref} from 'vue';
import { ref } from 'vue';
import { Dayjs } from 'dayjs';
import { columns } from './data';
import {
useVbenVxeGrid,
type VxeGridProps
} from '#/adapter/vxe-table';
import { useVbenVxeGrid, type VxeGridProps } from '#/adapter/vxe-table';
import { getVxePopupContainer } from '@vben/utils';
import {
arrangementList,
@@ -17,9 +14,9 @@ import arrangementModal from './arrangement-modal.vue';
import type { ArrangementForm } from '#/api/property/attendanceManagement/arrangement/model';
import { Page, useVbenModal } from '@vben/common-ui';
import { Popconfirm, Space } from 'ant-design-vue';
const emit = defineEmits<{(e:'changeView',value:boolean):void}>();
const emit = defineEmits<{ (e: 'changeView', value: boolean): void }>();
const props = defineProps<{
viewMode:'calender' | 'schedule'
viewMode: 'calender' | 'schedule';
}>();
const value = ref<Dayjs>();
const onPanelChange = (value: Dayjs, mode: string) => {
@@ -28,10 +25,9 @@ const onPanelChange = (value: Dayjs, mode: string) => {
// 切换视图模式
function handleViewModeChange(e: RadioChangeEvent): void {
// 将父组件的isCalenderView变为false
emit('changeView',e.target.value)
emit('changeView', e.target.value);
}
const gridOptions: VxeGridProps = {
checkboxConfig: {
// 高亮
@@ -66,7 +62,7 @@ const gridOptions: VxeGridProps = {
toolbarConfig: {
// 隐藏"刷新/重置"按钮(对应 redo
refresh: false,
zoom: false, // 显示全屏
zoom: false, // 显示全屏
custom: false, // 隐藏列设置
},
};
@@ -93,55 +89,68 @@ async function handleDelete(row: Required<ArrangementForm>) {
}
</script>
<template>
<div class="h-full ">
<div class="h-full">
<div class="flex justify-between">
<Radio.Group v-model:value="props.viewMode" @change="handleViewModeChange">
<Radio.Button value="calender">日历视图</Radio.Button>
<Radio.Button value="schedule">班表视图</Radio.Button>
<Radio.Group
v-model:value="props.viewMode"
@change="handleViewModeChange"
>
<Radio.Button value="calender">日历视图</Radio.Button>
<Radio.Button value="schedule">班表视图</Radio.Button>
</Radio.Group>
<div>
<Button type="primary" @click="handleAdd">新增排班</Button>
<Button type="primary" @click="handleAdd">新增排班</Button>
</div>
</div>
<div class="flex p-2 h-full">
<div style="padding-top: 48.4px;">
<div :style="{ width: '300px', border: '1px solid #d9d9d9', borderRadius: '4px' }">
<Calendar v-model:value="value" :fullscreen="false" :mode="'month'" @panelChange="onPanelChange"/>
<div class="flex h-full p-2">
<div style="padding-top: 48.4px">
<div
:style="{
width: '300px',
border: '1px solid #d9d9d9',
borderRadius: '4px',
}"
>
<Calendar
v-model:value="value"
:fullscreen="false"
:mode="'month'"
@panelChange="onPanelChange"
/>
</div>
</div>
<div class="flex-1">
<Page :auto-content-height="true">
<BasicTable>
<template #action="{ row }">
<Space>
<ghost-button
v-access:code="['property:arrangement:edit']"
@click.stop="handleEdit(row)"
>
{{ $t('pages.common.edit') }}
</ghost-button>
<Popconfirm
:get-popup-container="getVxePopupContainer"
placement="left"
title="确认删除?"
@confirm="handleDelete(row)"
>
<BasicTable>
<template #action="{ row }">
<Space>
<ghost-button
danger
v-access:code="['property:arrangement:remove']"
@click.stop=""
v-access:code="['property:arrangement:edit']"
@click.stop="handleEdit(row)"
>
{{ $t('pages.common.delete') }}
{{ $t('pages.common.edit') }}
</ghost-button>
</Popconfirm>
</Space>
</template>
</BasicTable>
<Popconfirm
:get-popup-container="getVxePopupContainer"
placement="left"
title="确认删除?"
@confirm="handleDelete(row)"
>
<ghost-button
danger
v-access:code="['property:arrangement:remove']"
@click.stop=""
>
{{ $t('pages.common.delete') }}
</ghost-button>
</Popconfirm>
</Space>
</template>
</BasicTable>
</Page>
</div>
</div>
<ArrangementModal @reload="tableApi.query()"/>
<ArrangementModal @reload="tableApi.query()" />
</div>
</template>
<style>
</style>
<style></style>

View File

@@ -1,68 +1,67 @@
//列表数据,用于展示人员列表
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;
}
/**
* 主键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;
}

View File

@@ -1,24 +1,39 @@
<script setup lang="ts">
import { computed, ref, reactive, onMounted, watch } from 'vue';
import { SyncOutlined } from '@ant-design/icons-vue';
import { Tree, InputSearch, Skeleton, Empty, Button,Tag } from 'ant-design-vue';
import {
Tree,
InputSearch,
Skeleton,
Empty,
Button,
Tag,
} from 'ant-design-vue';
import { $t } from '@vben/locales';
import { cloneDeep } from '@vben/utils';
import { useVbenForm } from '#/adapter/form';
import { arrangementAdd, arrangementInfo, arrangementUpdate } from '#/api/property/attendanceManagement/arrangement';
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
import {
useVbenVxeGrid,
type VxeGridProps
} from '#/adapter/vxe-table';
import { modalSchema,unitColumns,unitQuerySchema } from './data';
arrangementAdd,
arrangementInfo,
arrangementUpdate,
} from '#/api/property/attendanceManagement/arrangement';
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
import { useVbenVxeGrid, type VxeGridProps } from '#/adapter/vxe-table';
import { modalSchema, unitColumns, unitQuerySchema } from './data';
import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui';
import { resident_unitList } from '#/api/property/resident/unit';
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 emit = defineEmits<{
reload: [
tableData: {
dept: { unitId: string | number; unitName: string };
users: PersonVO[];
}[],
];
}>();
const selectDeptId = ref<string[]>([]);
const isUpdate = ref(false);
const title = computed(() => {
@@ -29,29 +44,33 @@ const searchValue = ref('');
const selectedDeptIds = ref<string[]>([]);
const showTreeSkeleton = ref(false);
//单位树
const deptTree = reactive<{
id: string;
label: string;
children: {
const deptTree = reactive<
{
id: string;
label: string;
}[];
}[]>([
{
id: '',
label: '全部单位',
children: [
],
},
children: {
id: string;
label: string;
}[];
}[]
>([
{
id: '',
label: '全部单位',
children: [],
},
]);
//勾选内容
const selectedUsers = ref<PersonVO[]>([]);
//已选内容,需要展示到父组件
const tableData = reactive<{
dept: {unitId: string | number,unitName: string},
users: PersonVO[]}[]>([]);
const tableData = reactive<
{
dept: { unitId: string | number; unitName: string };
users: PersonVO[];
}[]
>([]);
function handleReload() {
showTreeSkeleton.value = true;
setTimeout(() => {
@@ -64,7 +83,7 @@ const filteredDeptTree = computed(() => {
// 递归过滤树
function filter(tree: any[]): any[] {
return tree
.map(node => {
.map((node) => {
if (node.label.includes(searchValue.value)) return node;
if (node.children) {
const children = filter(node.children);
@@ -86,7 +105,7 @@ const [BasicForm, formApi] = useVbenForm({
// 通用配置项 会影响到所有表单项
componentProps: {
class: 'w-full',
}
},
},
schema: modalSchema(),
showDefaultActions: false,
@@ -176,41 +195,47 @@ const gridOptions: VxeGridProps = {
toolbarConfig: {
// 隐藏"刷新/重置"按钮(对应 redo
refresh: false,
zoom: false, // 显示全屏
zoom: false, // 显示全屏
custom: false, // 隐藏列设置
},
};
const gridEvents = {
checkboxChange:async (params:any) => {
const currentRecords = await params.$grid.getCheckboxRecords()??[];
const reserveRecords = await params.$grid.getCheckboxReserveRecords()??[];
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()??[];
checkboxAll: async (params: any) => {
const currentRecords = (await params.$grid.getCheckboxRecords()) ?? [];
const reserveRecords =
(await params.$grid.getCheckboxReserveRecords()) ?? [];
selectedUsers.value = [...reserveRecords, ...currentRecords];
},
};
const [BasicTable, tableApi] = useVbenVxeGrid({
formOptions,
gridOptions,
gridEvents
gridEvents,
});
async function handleConfirm() {
try {
for(const user of selectedUsers.value){
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] });
for (const user of selectedUsers.value) {
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);
emit('reload', tableData);
modalApi.close();
} catch (error) {
console.error(error);
@@ -224,13 +249,13 @@ async function handleClosed() {
resetInitialized();
}
async function getUnitList(){
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){
for (const item of res.rows) {
deptTree[0].children.push({
id: item.id as string,
id: item.id as string,
label: item.name as string,
});
}
@@ -251,59 +276,79 @@ onMounted(() => {
</script>
<template>
<BasicModal :title="title">
<BasicModal :title="title">
<div class="mb-2 flex">
<div>
<Skeleton :loading="showTreeSkeleton" :paragraph="{ rows: 8 }" active class="p-[8px]">
<div class="bg-background z-100 sticky left-0 top-0 p-[8px] flex items-center">
<InputSearch
v-model:value="searchValue"
placeholder="搜索单位"
size="small"
style="flex:1;"
<div>
<Skeleton
:loading="showTreeSkeleton"
:paragraph="{ rows: 8 }"
active
class="p-[8px]"
>
<div
class="bg-background z-100 sticky left-0 top-0 flex items-center p-[8px]"
>
<template #enterButton>
<Button type="text" @click="getUnitList">
<SyncOutlined class="text-primary" />
</Button>
</template>
</InputSearch>
</div>
<div class="h-full overflow-x-hidden px-[8px]">
<Tree
v-if="filteredDeptTree.length > 0"
v-model:selectedKeys="selectedDeptIds"
:field-names="{ title: 'label', key: 'id' }"
:show-line="{ showLeafIcon: false }"
:tree-data="filteredDeptTree"
:virtual="false"
default-expand-all
>
<template #title="{ label }">
<span v-if="searchValue && label.indexOf(searchValue) > -1">
{{ label.substring(0, label.indexOf(searchValue)) }}
<span style="color: #f50">{{ searchValue }}</span>
{{ label.substring(label.indexOf(searchValue) + searchValue.length) }}
</span>
<span v-else>{{ label }}</span>
</template>
</Tree>
<div v-else class="mt-5">
<Empty :image="Empty.PRESENTED_IMAGE_SIMPLE" description="无单位数据" />
<InputSearch
v-model:value="searchValue"
placeholder="搜索单位"
size="small"
style="flex: 1"
>
<template #enterButton>
<Button type="text" @click="getUnitList">
<SyncOutlined class="text-primary" />
</Button>
</template>
</InputSearch>
</div>
<div class="h-full overflow-x-hidden px-[8px]">
<Tree
v-if="filteredDeptTree.length > 0"
v-model:selectedKeys="selectedDeptIds"
:field-names="{ title: 'label', key: 'id' }"
:show-line="{ showLeafIcon: false }"
:tree-data="filteredDeptTree"
:virtual="false"
default-expand-all
>
<template #title="{ label }">
<span v-if="searchValue && label.indexOf(searchValue) > -1">
{{ label.substring(0, label.indexOf(searchValue)) }}
<span style="color: #f50">{{ searchValue }}</span>
{{
label.substring(
label.indexOf(searchValue) + searchValue.length,
)
}}
</span>
<span v-else>{{ label }}</span>
</template>
</Tree>
<div v-else class="mt-5">
<Empty
:image="Empty.PRESENTED_IMAGE_SIMPLE"
description="无单位数据"
/>
</div>
</div>
</Skeleton>
</div>
<div class="flex-1">
<div
class="mb-2 flex 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>
</Skeleton>
</div>
<div class="flex-1">
<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>
<BasicTable>
</BasicTable>
</div>
<BasicTable> </BasicTable>
</div>
</div>
</BasicModal>
</template>

View File

@@ -1,18 +1,12 @@
<script setup lang="ts">
import type { Recordable } from '@vben/types';
import { ref } from 'vue';
import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui';
import { getVxePopupContainer } from '@vben/utils';
import { Modal, Popconfirm, Space } from 'ant-design-vue';
import dayjs from 'dayjs';
import {
import {
useVbenVxeGrid,
vxeCheckboxChecked,
type VxeGridProps
type VxeGridProps,
} from '#/adapter/vxe-table';
import {
@@ -76,7 +70,7 @@ const gridOptions: VxeGridProps = {
keyField: 'id',
},
// 表格全局唯一表示 保存列配置需要用到
id: 'property-costMeterWater-index'
id: 'property-costMeterWater-index',
};
const [BasicTable, tableApi] = useVbenVxeGrid({
@@ -118,9 +112,14 @@ function handleMultiDelete() {
}
function handleDownloadExcel() {
commonDownloadExcel(costMeterWaterExport, '费用-水电抄数据', tableApi.formApi.form.values, {
fieldMappingTime: formOptions.fieldMappingTime,
});
commonDownloadExcel(
costMeterWaterExport,
'费用-水电抄数据',
tableApi.formApi.form.values,
{
fieldMappingTime: formOptions.fieldMappingTime,
},
);
}
</script>
@@ -138,9 +137,10 @@ function handleDownloadExcel() {
<a-button
:disabled="!vxeCheckboxChecked(tableApi)"
danger
type="primary"
v-access:code="['property:costMeterWater:remove']"
@click="handleMultiDelete">
type="primary"
v-access:code="['property:costMeterWater:remove']"
@click="handleMultiDelete"
>
{{ $t('pages.common.delete') }}
</a-button>
<a-button