Commit d9cb58ab authored by 刘斌's avatar 刘斌

feat: 增加编制计划初版

parent ec6e2c90
import type { BaseModel, PageQuery } from '#/api/baseModel';
import { commonExport } from '#/api/helper';
import { requestClient } from '#/api/request';
export namespace StaffingPlanDataApi {
export interface StaffingPlanData extends BaseModel {
/**
* 板块
*/
plate?: string;
/**
* 一级部门
*/
firstLevelDepartment?: string;
/**
* 二级部门
*/
secondLevelDepartment?: string;
/**
* 三级部门
*/
thirdLevelDepartment?: string;
/**
* 部门ID
*/
deptId?: number;
/**
* 主岗位
*/
position?: string;
/**
* 上一年编制
*/
lastYearStaffing?: number;
/**
* 今年编制
*/
thisYearStaffing?: number;
/**
* 下一年编制
*/
nextYearStaffing?: number;
/**
* 1月正式工计划
*/
m1FormalPlan?: number;
/**
* 1月正式工实际
*/
m1FormalActual?: string;
/**
* 1月兼职计划
*/
m1PartPlan?: number;
/**
* 1月兼职实际
*/
m1PartActual?: string;
/**
* 2月正式工计划
*/
m2FormalPlan?: number;
/**
* 2月正式工实际
*/
m2FormalActual?: string;
/**
* 2月兼职计划
*/
m2PartPlan?: number;
/**
* 2月兼职实际
*/
m2PartActual?: string;
/**
* 3月正式工计划
*/
m3FormalPlan?: number;
/**
* 3月正式工实际
*/
m3FormalActual?: string;
/**
* 3月兼职计划
*/
m3PartPlan?: number;
/**
* 3月兼职实际
*/
m3PartActual?: string;
/**
* 4月正式工计划
*/
m4FormalPlan?: number;
/**
* 4月正式工实际
*/
m4FormalActual?: string;
/**
* 4月兼职计划
*/
m4PartPlan?: number;
/**
* 4月兼职实际
*/
m4PartActual?: string;
/**
* 5月正式工计划
*/
m5FormalPlan?: number;
/**
* 5月正式工实际
*/
m5FormalActual?: string;
/**
* 5月兼职计划
*/
m5PartPlan?: number;
/**
* 5月兼职实际
*/
m5PartActual?: string;
/**
* 6月正式工计划
*/
m6FormalPlan?: number;
/**
* 6月正式工实际
*/
m6FormalActual?: string;
/**
* 6月兼职计划
*/
m6PartPlan?: number;
/**
* 6月兼职实际
*/
m6PartActual?: string;
/**
* 7月正式工计划
*/
m7FormalPlan?: number;
/**
* 7月正式工实际
*/
m7FormalActual?: string;
/**
* 7月兼职计划
*/
m7PartPlan?: number;
/**
* 7月兼职实际
*/
m7PartActual?: string;
/**
* 8月正式工计划
*/
m8FormalPlan?: number;
/**
* 8月正式工实际
*/
m8FormalActual?: string;
/**
* 8月兼职计划
*/
m8PartPlan?: number;
/**
* 8月兼职实际
*/
m8PartActual?: string;
/**
* 9月正式工计划
*/
m9FormalPlan?: number;
/**
* 9月正式工实际
*/
m9FormalActual?: string;
/**
* 9月兼职计划
*/
m9PartPlan?: number;
/**
* 9月兼职实际
*/
m9PartActual?: string;
/**
* 10月正式工计划
*/
m10FormalPlan?: number;
/**
* 10月正式工实际
*/
m10FormalActual?: string;
/**
* 10月兼职计划
*/
m10PartPlan?: number;
/**
* 10月兼职实际
*/
m10PartActual?: string;
/**
* 11月正式工计划
*/
m11FormalPlan?: number;
/**
* 11月正式工实际
*/
m11FormalActual?: string;
/**
* 11月兼职计划
*/
m11PartPlan?: number;
/**
* 11月兼职实际
*/
m11PartActual?: string;
/**
* 12月正式工计划
*/
m12FormalPlan?: number;
/**
* 12月正式工实际
*/
m12FormalActual?: string;
/**
* 12月兼职计划
*/
m12PartPlan?: number;
/**
* 12月兼职实际
*/
m12PartActual?: string;
/**
* 合计行
*/
summary?: string;
/**
* 备注
*/
remark?: string;
}
}
/**
* 查询编制规划记录明细列表
* @param params
* @returns {*} page
*/
export function apiPage(params: PageQuery) {
return requestClient.get('/employee/staffingPlanData/page', { params });
}
/**
* 查询编制规划记录明细详细
* @param id
*/
export function apiDetail(id: number) {
return requestClient.get(`/employee/staffingPlanData/${id}`);
}
/**
* 新增编制规划记录明细
* @param data
*/
export function apiAdd(data: StaffingPlanDataApi.StaffingPlanData) {
return requestClient.post('/employee/staffingPlanData', data);
}
/**
* 修改编制规划记录明细
* @param data
*/
export function apiUpdate(data: StaffingPlanDataApi.StaffingPlanData[]) {
return requestClient.put('/employee/staffingPlanData', data);
}
/**
* 删除编制规划记录明细
* @param id
*/
export function apiDelete(id: Array<number> | number) {
return requestClient.delete(`/employee/staffingPlanData/${id}`);
}
/**
* 导出编制规划记录明细
* @param params
*/
export function apiExport(id: number) {
return commonExport(`/employee/staffingPlanData/export/${id}`, {});
}
/**
* 下载用户导入模板
* @returns blob
*/
export function downloadImportTemplate() {
return commonExport('/employee/staffingPlanData/importTemplate', {});
}
/**
* 从excel导入培训信息
* @param file
* @returns void
*/
export function staffingPlanDataImportData(recordId: number, file: Blob) {
return requestClient.post<{ errMessage: string; success: boolean }>(
`/employee/staffingPlanData/import/${recordId}`,
{ file },
{
headers: {
'Content-Type': 'multipart/form-data;charset=UTF-8',
},
isTransformResponse: false,
responseReturn: 'body',
timeout: 300_000,
},
);
}
import type { BaseModel, PageQuery } from '#/api/baseModel';
import { commonExport } from '#/api/helper';
import { requestClient } from '#/api/request';
export namespace StaffingPlanRecordsApi {
export interface StaffingPlanRecords extends BaseModel {
/**
* 记录时间
*/
recordDate?: string;
/**
* 上一年标题
*/
lastYearTitle?: string;
/**
* 今年标题
*/
currentYearTitle?: string;
/**
* 明年标题
*/
nextYearTitle?: string;
/**
* 是否已初始化
*/
initFlag?: string;
/**
* 备注
*/
remark?: string;
}
}
/**
* 查询编制规划记录列表
* @param params
* @returns {*} page
*/
export function apiPage(params: PageQuery) {
return requestClient.get('/employee/staffingPlanRecords/page', { params });
}
/**
* 查询编制规划记录详细
* @param id
*/
export function apiDetail(id: number) {
return requestClient.get(`/employee/staffingPlanRecords/${id}`);
}
/**
* 新增编制规划记录
* @param data
*/
export function apiAdd(data: StaffingPlanRecordsApi.StaffingPlanRecords) {
return requestClient.post('/employee/staffingPlanRecords', data);
}
/**
* 修改编制规划记录
* @param data
*/
export function apiUpdate(data: StaffingPlanRecordsApi.StaffingPlanRecords) {
return requestClient.put('/employee/staffingPlanRecords', data);
}
/**
* 删除编制规划记录
* @param id
*/
export function apiDelete(id: Array<number> | number) {
return requestClient.delete(`/employee/staffingPlanRecords/${id}`);
}
/**
* 导出编制规划记录
* @param params
*/
export function apiExport(params: PageQuery) {
return commonExport('/employee/staffingPlanRecords/export', params);
}
......@@ -168,6 +168,31 @@ const routes: RouteRecordRaw[] = [
componentPath: '#/views/hr/employeeStatusAnalysis/list.vue',
},
},
{
path: '/hr/report/staffingPlanRecords/records',
name: 'StaffingPlanRecordsList',
component: () => import('#/views/hr/staffingPlanRecords/list.vue'),
meta: {
title: '编制规划记录',
icon: 'arcticons:one-hand-operation',
keepAlive: true,
permission: ['dashboard'],
componentPath: '#/views/hr/staffingPlanRecords/list.vue',
},
},
{
path: '/hr/report/staffingPlan/data/:recordId',
component: () => import('#/views/hr/staffingPlanData/list.vue'),
name: 'StaffingPlanDataList',
meta: {
title: '编制明细',
icon: 'mingcute:department-line',
keepAlive: true,
hideInMenu: true,
permission: ['dashboard'],
componentPath: '#/views/hr/staffingPlanData/list.vue',
},
},
],
},
{
......
This diff is collapsed.
<script lang="ts" setup>
import type { VbenFormSchema } from '#/adapter/form';
import type { StaffingPlanDataApi } from '#/api/hr/staffingPlanData';
import { computed, ref } from 'vue';
import { useVbenDrawer } from '@vben/common-ui';
import { useVbenForm } from '#/adapter/form';
import { apiAdd, apiUpdate } from '#/api/hr/staffingPlanData';
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
const emit = defineEmits<{
success: [];
}>();
const isUpdate = ref(false);
const formSchema: VbenFormSchema[] = [
{
component: 'Input',
dependencies: {
show: () => false,
triggerFields: [''],
},
fieldName: 'id',
label: 'id',
},
{
component: 'Input',
fieldName: 'plate',
label: '板块',
rules: 'required',
},
{
component: 'Input',
fieldName: 'firstLevelDepartment',
label: '一级部门',
rules: 'required',
},
{
component: 'Input',
fieldName: 'secondLevelDepartment',
label: '二级部门',
rules: 'required',
},
{
component: 'Input',
fieldName: 'thirdLevelDepartment',
label: '三级部门',
rules: 'required',
},
{
component: 'Input',
fieldName: 'deptId',
label: '部门ID',
rules: 'required',
},
{
component: 'Input',
fieldName: 'position',
label: '主岗位',
rules: 'required',
},
{
component: 'Input',
fieldName: 'lastYearStaffing',
label: '上一年编制',
rules: 'required',
},
{
component: 'Input',
fieldName: 'thisYearStaffing',
label: '今年编制',
rules: 'required',
},
{
component: 'Input',
fieldName: 'nextYearStaffing',
label: '下一年编制',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm1FormalPlan',
label: '1月正式工计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm1FormalActual',
label: '1月正式工实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm1PartPlan',
label: '1月兼职计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm1PartActual',
label: '1月兼职实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm2FormalPlan',
label: '2月正式工计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm2FormalActual',
label: '2月正式工实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm2PartPlan',
label: '2月兼职计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm2PartActual',
label: '2月兼职实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm3FormalPlan',
label: '3月正式工计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm3FormalActual',
label: '3月正式工实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm3PartPlan',
label: '3月兼职计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm3PartActual',
label: '3月兼职实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm4FormalPlan',
label: '4月正式工计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm4FormalActual',
label: '4月正式工实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm4PartPlan',
label: '4月兼职计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm4PartActual',
label: '4月兼职实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm5FormalPlan',
label: '5月正式工计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm5FormalActual',
label: '5月正式工实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm5PartPlan',
label: '5月兼职计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm5PartActual',
label: '5月兼职实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm6FormalPlan',
label: '6月正式工计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm6FormalActual',
label: '6月正式工实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm6PartPlan',
label: '6月兼职计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm6PartActual',
label: '6月兼职实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm7FormalPlan',
label: '7月正式工计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm7FormalActual',
label: '7月正式工实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm7PartPlan',
label: '7月兼职计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm7PartActual',
label: '7月兼职实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm8FormalPlan',
label: '8月正式工计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm8FormalActual',
label: '8月正式工实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm8PartPlan',
label: '8月兼职计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm8PartActual',
label: '8月兼职实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm9FormalPlan',
label: '9月正式工计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm9FormalActual',
label: '9月正式工实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm9PartPlan',
label: '9月兼职计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm9PartActual',
label: '9月兼职实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm10FormalPlan',
label: '10月正式工计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm10FormalActual',
label: '10月正式工实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm10PartPlan',
label: '10月兼职计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm10PartActual',
label: '10月兼职实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm11FormalPlan',
label: '11月正式工计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm11FormalActual',
label: '11月正式工实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm11PartPlan',
label: '11月兼职计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm11PartActual',
label: '11月兼职实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm12FormalPlan',
label: '12月正式工计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm12FormalActual',
label: '12月正式工实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm12PartPlan',
label: '12月兼职计划',
rules: 'required',
},
{
component: 'Input',
fieldName: 'm12PartActual',
label: '12月兼职实际',
rules: 'required',
},
{
component: 'Input',
fieldName: 'summary',
label: '合计行',
rules: 'required',
},
{
component: 'Input',
fieldName: 'remark',
label: '备注',
rules: 'required',
},
];
const [BasicForm, formApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
formItemClass: 'col-span-2',
labelWidth: 90,
},
schema: formSchema,
showDefaultActions: false,
wrapperClass: 'grid-cols-2',
});
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
{
initializedGetter: defaultFormValueGetter(formApi),
currentGetter: defaultFormValueGetter(formApi),
},
);
const [Drawer, drawerApi] = useVbenDrawer({
onBeforeClose,
onClosed: handleClosed,
onConfirm: onSubmit,
async onOpenChange(isOpen) {
if (!isOpen) {
return null;
}
const data = drawerApi.getData<StaffingPlanDataApi.StaffingPlanData>();
isUpdate.value = !!data?.id;
if (isUpdate.value) {
await formApi.setValues(data);
} else {
formApi.resetForm();
}
await markInitialized();
},
});
async function onSubmit() {
const { valid } = await formApi.validate();
if (valid) {
drawerApi.lock();
const data =
await formApi.getValues<StaffingPlanDataApi.StaffingPlanData>();
try {
await (isUpdate.value ? apiUpdate(data) : apiAdd(data));
resetInitialized();
emit('success');
drawerApi.close();
} finally {
drawerApi.unlock();
}
}
}
async function handleClosed() {
await formApi.resetForm();
resetInitialized();
}
const getDrawerTitle = computed(() =>
isUpdate.value ? '修改编制规划记录明细' : '新增编制规划记录明细',
);
</script>
<template>
<Drawer class="w-full max-w-[800px]" :title="getDrawerTitle">
<BasicForm class="mx-4" />
</Drawer>
</template>
<script lang="ts" setup>
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { StaffingPlanDataApi } from '#/api/hr/staffingPlanData';
import { onMounted, reactive, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui';
import { Plus } from '@vben/icons';
import { ExportOutlined, SaveOutlined } from '@ant-design/icons-vue';
import { Button, message, Space } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { apiExport, apiPage, apiUpdate } from '#/api/hr/staffingPlanData';
import { apiDetail as recordInfo } from '#/api/hr/staffingPlanRecords';
import { commonDownloadExcel } from '#/utils/file/download';
import { useColumns } from './data';
import staffingImportModal from './staffing-import-modal.vue';
// import Form from './form.vue';
const route = useRoute();
const recordId = route.params.recordId ? Number(route.params.recordId) : 0;
const initFlagRef = ref('N');
const staffingRecords = reactive({
lastYearTitle: '',
currentYearTitle: '',
nextYearTitle: '',
});
watch(
() => staffingRecords,
() => {
const cols = useColumns(staffingRecords) as any;
gridApi.grid?.reloadColumn?.(cols);
},
{ deep: true },
);
onMounted(async () => {
const records = await recordInfo(recordId);
initFlagRef.value = records.initFlag;
staffingRecords.lastYearTitle = records.lastYearTitle;
staffingRecords.currentYearTitle = records.currentYearTitle;
staffingRecords.nextYearTitle = records.nextYearTitle;
});
/**
* 导入
*/
const [StaffingImportModal, staffingImportModalApi] = useVbenModal({
connectedComponent: staffingImportModal,
});
function handleImport() {
staffingImportModalApi.setData({ recordId }).open();
}
// const formOptions: VbenFormProps = {
// commonConfig: {
// labelWidth: 80,
// componentProps: {
// allowClear: true,
// },
// },
// schema: querySchema,
// wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
// };
// const [FormDrawer, formDrawerApi] = useVbenDrawer({
// connectedComponent: Form,
// });
const [Grid, gridApi] = useVbenVxeGrid({
// formOptions,
gridOptions: {
columns: useColumns(staffingRecords) as any,
height: 'auto',
keepSource: true,
pagerConfig: {
enabled: true,
pageSize: 20,
},
editConfig: {
mode: 'cell',
trigger: 'click',
// activeMethod({ row }) {
// return !row.summary;
// },
// beforeEditMethod({ row }) {
// // name 为 'x' 开头的列禁止编辑
// console.log('[row]', row);
// return true;
// },
},
proxyConfig: {
ajax: {
query: async ({ page }, formValues = {}) => {
return await apiPage({
pageNo: page.currentPage,
pageSize: page.pageSize,
recordId,
...formValues,
});
},
},
},
border: true,
columnConfig: {
resizable: false,
},
showCustomHeader: true,
spanMethod({ row, column }) {
if (row.summary === 'Y') {
const mergeFields = [
'plate',
'firstLevelDepartment',
'secondLevelDepartment',
'thirdLevelDepartment',
];
if (mergeFields.includes(column.field as string)) {
if (column.field === 'plate') {
return { rowspan: 1, colspan: 4 } as any;
}
return { rowspan: 0, colspan: 0 } as any;
}
}
return undefined as any;
},
rowClassName: ({ row }) => {
if (row.summary === 'Y') {
return row.plate === '片区合计'
? 'bg-red-500 text-white'
: 'bg-red-100';
}
return '';
},
mergeHeaderCells: [
{ row: 0, col: 0, rowspan: 2, colspan: 1 },
{ row: 0, col: 1, rowspan: 2, colspan: 1 },
{ row: 0, col: 2, rowspan: 2, colspan: 1 },
{ row: 0, col: 3, rowspan: 2, colspan: 1 },
{ row: 0, col: 4, rowspan: 2, colspan: 1 },
{ row: 0, col: 5, rowspan: 2, colspan: 1 },
{ row: 0, col: 6, rowspan: 2, colspan: 1 },
{ row: 0, col: 7, rowspan: 2, colspan: 1 },
{ row: 0, col: 8, rowspan: 1, colspan: 48 },
{ row: 0, col: 56, rowspan: 2, colspan: 1 },
],
rowConfig: {
keyField: 'id',
// 高亮当前行
isCurrent: false,
},
} as VxeTableGridOptions,
});
// function onActionClick({
// code,
// row,
// }: OnActionClickParams<StaffingPlanDataApi.StaffingPlanData>) {
// switch (code) {
// case 'delete': {
// onDelete(row);
// break;
// }
// case 'edit': {
// onEdit(row);
// break;
// }
// default: {
// break;
// }
// }
// }
async function onEdit() {
const full =
(await gridApi.grid?.getUpdateRecords()) as StaffingPlanDataApi.StaffingPlanData[];
if (full && full.length > 0) {
await apiUpdate(full);
message.success('已保存编制计划');
} else {
message.error('无修改,请检查');
}
}
function onRefresh() {
gridApi.query();
initFlagRef.value = 'Y';
}
// function onDelete(row: StaffingPlanDataApi.StaffingPlanData) {
// const hideLoading = message.loading({
// content: `正在删除${row.name}...`,
// duration: 0,
// key: 'action_process_msg',
// });
// apiDelete(row.id || 0)
// .then(() => {
// message.success({
// content: `${row.name}删除成功`,
// key: 'action_process_msg',
// });
// onRefresh();
// })
// .catch(() => {
// hideLoading();
// });
// }
function handleDownloadExcel() {
commonDownloadExcel(apiExport, '编制规划记录明细', recordId);
}
</script>
<template>
<Page auto-content-height>
<!-- <FormDrawer @success="onRefresh" /> -->
<StaffingImportModal @reload="onRefresh" />
<Grid table-title="编制规划记录明细列表">
<template #toolbar-tools>
<Space>
<Button
type="primary"
ghost
v-access:code="['employee:staffingPlanData:edit']"
@click="onEdit"
>
<template #icon>
<SaveOutlined />
</template>
保存修改
</Button>
<Button
type="primary"
danger
v-access:code="['employee:staffingPlanData:export']"
@click="handleDownloadExcel"
>
<template #icon>
<ExportOutlined />
</template>
导出
</Button>
<Button
v-access:code="['employee:staffingPlanData:add']"
v-if="initFlagRef === 'N'"
type="primary"
@click="handleImport"
>
<Plus class="size-5" />
导入明细
</Button>
</Space>
</template>
</Grid>
</Page>
</template>
<script setup lang="ts">
import type { UploadFile } from 'ant-design-vue/es/upload/interface';
import { h, ref, unref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { ExcelIcon, InBoxIcon } from '@vben/icons';
import { Button, Modal, Upload } from 'ant-design-vue';
import {
downloadImportTemplate,
staffingPlanDataImportData,
} from '#/api/hr/staffingPlanData';
import { commonDownloadExcel } from '#/utils/file/download';
const emit = defineEmits<{ reload: [] }>();
const UploadDragger = Upload.Dragger;
const recordIdRef = ref(0);
const [BasicModal, modalApi] = useVbenModal({
onCancel: handleCancel,
onConfirm: handleSubmit,
onOpenChange: async (isOpen) => {
if (!isOpen) {
return null;
}
const { recordId } = modalApi.getData() as { recordId: number };
recordIdRef.value = recordId;
},
});
const fileList = ref<UploadFile[]>([]);
// const checked = ref(false);
async function handleSubmit() {
try {
modalApi.modalLoading(true);
if (fileList.value.length !== 1) {
handleCancel();
return;
}
// const data = {
// file: fileList.value[0]!.originFileObj as Blob,
// updateSupport: unref(checked),
// };
const { success, errMessage } = await staffingPlanDataImportData(
unref(recordIdRef),
fileList.value[0]!.originFileObj as Blob,
);
let modal = Modal.success;
if (success) {
emit('reload');
} else {
modal = Modal.error;
}
handleCancel();
modal({
content: h('div', {
class: 'max-h-[260px] overflow-y-auto',
innerHTML: errMessage, // 后台已经处理xss问题
}),
title: '提示',
});
} catch (error) {
console.warn(error);
modalApi.close();
} finally {
modalApi.modalLoading(false);
}
}
function handleCancel() {
modalApi.close();
fileList.value = [];
// checked.value = false;
}
</script>
<template>
<BasicModal
:close-on-click-modal="false"
:fullscreen-button="false"
title="编制计划导入"
>
<!-- z-index不设置会遮挡模板下载loading -->
<!-- 手动处理 而不是放入文件就上传 -->
<UploadDragger
v-model:file-list="fileList"
:before-upload="() => false"
:max-count="1"
:show-upload-list="true"
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
>
<p class="ant-upload-drag-icon flex items-center justify-center">
<InBoxIcon class="text-primary size-[48px]" />
</p>
<p class="ant-upload-text">点击或者拖拽到此处上传文件</p>
</UploadDragger>
<div class="mt-2 flex flex-col gap-2">
<div class="flex items-center gap-2">
<span>允许导入xlsx, xls文件</span>
<Button
type="link"
@click="
commonDownloadExcel(downloadImportTemplate, '编制计划导入模板')
"
>
<div class="flex items-center gap-[4px]">
<ExcelIcon />
<span>下载模板</span>
</div>
</Button>
</div>
<!-- <div class="flex items-center gap-2">
<span :class="{ 'text-red-500': checked }">
是否更新/覆盖已存在的用户数据
</span>
<Switch v-model:checked="checked" />
</div> -->
</div>
</BasicModal>
</template>
import type { VbenFormSchema } from '#/adapter/form';
import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table';
import type { StaffingPlanRecordsApi } from '#/api/hr/staffingPlanRecords';
export const querySchema: VbenFormSchema[] = [
{
component: 'DatePicker',
componentProps: {
picker: 'year',
format: 'YYYY',
valueFormat: 'YYYY',
},
fieldName: 'recordDate',
label: '记录时间',
},
// {
// component: 'Input',
// fieldName: 'lastYearTitle',
// label: '上一年标题',
// },
// {
// component: 'Input',
// fieldName: 'currentYearTitle',
// label: '今年标题',
// },
// {
// component: 'Input',
// fieldName: 'nextYearTitle',
// label: '明年标题',
// },
// {
// component: 'Input',
// fieldName: 'initFlag',
// label: '是否已初始化',
// },
];
export function useColumns(
onActionClick: OnActionClickFn<StaffingPlanRecordsApi.StaffingPlanRecords>,
): VxeTableGridOptions<StaffingPlanRecordsApi.StaffingPlanRecords>['columns'] {
return [
{
title: '记录时间',
field: 'recordDate',
// formatter: 'formatDateTime',
},
// {
// title: '上一年标题',
// field: 'lastYearTitle',
// },
// {
// title: '今年标题',
// field: 'currentYearTitle',
// },
// {
// title: '明年标题',
// field: 'nextYearTitle',
// },
// {
// title: '是否已初始化',
// field: 'initFlag',
// },
{
title: '备注',
field: 'remark',
},
{
align: 'right',
cellRender: {
attrs: {
nameField: 'recordDate',
nameTitle: '编制规划记录',
onClick: onActionClick,
},
name: 'CellOperation',
options: [
{
text: '明细',
code: 'detail',
accessCode: ['employee:staffingPlanRecords:edit'],
}, // 明细数据
{
code: 'edit',
accessCode: ['employee:staffingPlanRecords:edit'],
}, // 默认的编辑按钮
{
code: 'delete',
accessCode: ['employee:staffingPlanRecords:remove'],
}, // 默认的删除按钮
],
},
field: 'action',
fixed: 'right',
headerAlign: 'center',
resizable: false,
showOverflow: false,
title: '操作',
width: 'auto',
},
];
}
<script lang="ts" setup>
import type { VbenFormProps } from '@vben/common-ui';
import type {
OnActionClickParams,
VxeTableGridOptions,
} from '#/adapter/vxe-table';
import type { StaffingPlanRecordsApi } from '#/api/hr/staffingPlanRecords';
import { useRouter } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui';
import { Plus } from '@vben/icons';
import { Button, message, Space } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { apiDelete, apiPage } from '#/api/hr/staffingPlanRecords';
import { querySchema, useColumns } from './data';
import staffingPlanRecordModal from './modal.vue';
const formOptions: VbenFormProps = {
commonConfig: {
labelWidth: 80,
componentProps: {
allowClear: true,
},
},
schema: querySchema,
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
};
const [StaffingPlanRecordModal, modalApi] = useVbenModal({
connectedComponent: staffingPlanRecordModal,
});
const [Grid, gridApi] = useVbenVxeGrid({
formOptions,
gridOptions: {
columns: useColumns(onActionClick),
height: 'auto',
keepSource: true,
pagerConfig: {
enabled: true,
},
proxyConfig: {
ajax: {
query: async ({ page }, formValues = {}) => {
return await apiPage({
pageNo: page.currentPage,
pageSize: page.pageSize,
...formValues,
});
},
},
},
rowConfig: {
keyField: 'id',
// 高亮当前行
isCurrent: true,
},
} as VxeTableGridOptions,
});
function onActionClick({
code,
row,
}: OnActionClickParams<StaffingPlanRecordsApi.StaffingPlanRecords>) {
switch (code) {
case 'delete': {
onDelete(row);
break;
}
case 'detail': {
onRecordData(row);
break;
}
case 'edit': {
onEdit(row);
break;
}
default: {
break;
}
}
}
function onRefresh() {
gridApi.query();
}
function onEdit(row: StaffingPlanRecordsApi.StaffingPlanRecords) {
modalApi.setData(row).open();
}
function onCreate() {
modalApi.setData({}).open();
}
function onDelete(row: StaffingPlanRecordsApi.StaffingPlanRecords) {
const hideLoading = message.loading({
content: `正在删除${row.recordDate}...`,
duration: 0,
key: 'action_process_msg',
});
apiDelete(row.id || 0)
.then(() => {
message.success({
content: `${row.recordDate}删除成功`,
key: 'action_process_msg',
});
onRefresh();
})
.catch(() => {
hideLoading();
});
}
const router = useRouter();
function onRecordData(record: StaffingPlanRecordsApi.StaffingPlanRecords) {
router.push(`/hr/report/staffingPlan/data/${record.id}`);
}
// function handleDownloadExcel() {
// commonDownloadExcel(apiExport, '编制规划记录', gridApi.formApi.form.values);
// }
</script>
<template>
<Page auto-content-height>
<StaffingPlanRecordModal @success="onRefresh" />
<Grid table-title="编制规划记录列表">
<template #toolbar-tools>
<Space>
<!-- <Button
v-access:code="['employee:staffingPlanRecords:export']"
@click="handleDownloadExcel"
>
导出
</Button> -->
<Button
v-access:code="['employee:staffingPlanRecords:add']"
type="primary"
@click="onCreate"
>
<Plus class="size-5" />
新增
</Button>
</Space>
</template>
</Grid>
</Page>
</template>
<script lang="ts" setup>
import type { VbenFormSchema } from '#/adapter/form';
import type { StaffingPlanRecordsApi } from '#/api/hr/staffingPlanRecords';
import { computed, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { getVxePopupContainer } from '@vben/utils';
import { useVbenForm } from '#/adapter/form';
import { apiAdd, apiUpdate } from '#/api/hr/staffingPlanRecords';
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
const emit = defineEmits<{
success: [];
}>();
const formData = ref<StaffingPlanRecordsApi.StaffingPlanRecords>();
const formSchema: VbenFormSchema[] = [
{
component: 'DatePicker',
componentProps: {
picker: 'year',
format: 'YYYY',
valueFormat: 'YYYY',
getVxePopupContainer,
},
fieldName: 'recordDate',
label: '记录时间',
rules: 'required',
},
// {
// component: 'Input',
// fieldName: 'lastYearTitle',
// label: '上一年标题',
// rules: 'required',
// },
// {
// component: 'Input',
// fieldName: 'currentYearTitle',
// label: '今年标题',
// rules: 'required',
// },
// {
// component: 'Input',
// fieldName: 'nextYearTitle',
// label: '明年标题',
// rules: 'required',
// },
// {
// component: 'Input',
// fieldName: 'initFlag',
// label: '是否已初始化',
// rules: 'required',
// },
{
component: 'Input',
fieldName: 'remark',
label: '备注',
// rules: 'required',
},
];
const [BasicForm, formApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
formItemClass: 'col-span-2',
labelWidth: 90,
},
schema: formSchema,
showDefaultActions: false,
wrapperClass: 'grid-cols-2',
});
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
{
initializedGetter: defaultFormValueGetter(formApi),
currentGetter: defaultFormValueGetter(formApi),
},
);
const [BasicModal, modalApi] = useVbenModal({
fullscreenButton: false,
onBeforeClose,
onClosed: handleClosed,
onConfirm: onSubmit,
onOpenChange: async (isOpen) => {
if (!isOpen) {
return null;
}
modalApi.modalLoading(true);
const data = modalApi.getData<StaffingPlanRecordsApi.StaffingPlanRecords>();
if (data) {
formData.value = data;
await formApi.setValues(formData.value);
}
await markInitialized();
modalApi.modalLoading(false);
},
});
async function onSubmit() {
const { valid } = await formApi.validate();
if (valid) {
modalApi.lock();
const data =
await formApi.getValues<StaffingPlanRecordsApi.StaffingPlanRecords>();
try {
await (formData.value?.id
? apiUpdate({ id: formData.value.id, ...data })
: apiAdd(data));
resetInitialized();
emit('success');
modalApi.close();
} finally {
modalApi.unlock();
}
}
}
async function handleClosed() {
await formApi.resetForm();
resetInitialized();
}
const getModalTitle = computed(() =>
formData.value?.id ? '修改编制规划记录' : '新增编制规划记录',
);
</script>
<template>
<BasicModal :title="getModalTitle">
<BasicForm class="mx-4" />
</BasicModal>
</template>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment