feat(erp): 添加采购来票管理和付款关联功能
- 新增采购来票管理模块,支持来票信息录入和附件上传
- 实现付款单与来票关联选择功能,供应商变更时自动清空已选来票
- 在付款列表中显示关联来票信息,完善财务付款流程
- 添加员工合同管理功能,支持合同类型和状态管理
- 优化表单组件属性配置,提升用户体验和数据验证逻辑
| | |
| | | import type { PageParam, PageResult } from '@vben/request'; |
| | | |
| | | import type { ErpPurchaseInvoiceApi } from '#/api/erp/purchase/invoice'; |
| | | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace ErpFinancePaymentApi { |
| | |
| | | no: string; // 仿¬¾åå· |
| | | supplierId?: number; // ä¾åºåç¼å· |
| | | supplierName?: string; // ä¾åºååç§° |
| | | invoiceId?: number; // å
³èæ¥ç¥¨ç¼å· |
| | | invoice?: ErpPurchaseInvoiceApi.PurchaseInvoice; // å
³èæ¥ç¥¨ä¿¡æ¯ |
| | | paymentTime?: Date; // 仿¬¾æ¶é´ |
| | | totalPrice: number; // å计éé¢ï¼åä½ï¼å
|
| | | discountPrice: number; // 伿 éé¢ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { PageParam, PageResult } from '@vben/request'; |
| | | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace ErpPurchaseInvoiceApi { |
| | | /** éè´è®¢åä¿¡æ¯ï¼æ¥ç¥¨å
³èï¼ */ |
| | | export interface PurchaseOrder { |
| | | id?: number; |
| | | no?: string; |
| | | supplierId?: number; |
| | | supplierName?: string; |
| | | orderTime?: Date | string; |
| | | totalPrice?: number; |
| | | status?: number; |
| | | } |
| | | |
| | | /** æ¥ç¥¨ä¿¡æ¯ */ |
| | | export interface PurchaseInvoice { |
| | | id?: number; |
| | | no?: string; |
| | | supplierId?: number; |
| | | supplierName?: string; |
| | | purchaseOrderId?: number; |
| | | order?: PurchaseOrder; |
| | | invoiceNo?: string; |
| | | invoiceTitle?: string; |
| | | price?: number; |
| | | invoiceTime?: string; |
| | | auditStatus?: number; |
| | | processInstanceId?: string; |
| | | remark?: string; |
| | | attachmentList?: { id: number; name?: string; url?: string }[]; |
| | | blobIds?: number[]; |
| | | hasAttachment?: boolean; |
| | | remainingInvoicePrice?: number; |
| | | creator?: string; |
| | | creatorName?: string; |
| | | createTime?: string; |
| | | updateTime?: string; |
| | | } |
| | | |
| | | /** æ¥ç¥¨ç®è¦ä¿¡æ¯ï¼ç¨äºä»æ¬¾å
³èéæ©ï¼ */ |
| | | export interface PurchaseInvoiceSimple { |
| | | id: number; |
| | | no: string; |
| | | invoiceNo?: string; |
| | | invoiceTitle?: string; |
| | | price?: number; |
| | | supplierId?: number; |
| | | purchaseOrderId?: number; |
| | | auditStatus?: number; |
| | | hasAttachment?: boolean; |
| | | remainingInvoicePrice?: number; |
| | | } |
| | | } |
| | | |
| | | /** æ¥è¯¢æ¥ç¥¨å页 */ |
| | | export function getPurchaseInvoicePage(params: PageParam) { |
| | | return requestClient.get<PageResult<ErpPurchaseInvoiceApi.PurchaseInvoice>>( |
| | | '/erp/purchase-invoice/page', |
| | | { params }, |
| | | ); |
| | | } |
| | | |
| | | /** æ¥è¯¢æ¥ç¥¨è¯¦æ
*/ |
| | | export function getPurchaseInvoice(id: number) { |
| | | return requestClient.get<ErpPurchaseInvoiceApi.PurchaseInvoice>( |
| | | `/erp/purchase-invoice/get?id=${id}`, |
| | | ); |
| | | } |
| | | |
| | | /** æ°å¢æ¥ç¥¨ */ |
| | | export function createPurchaseInvoice(data: ErpPurchaseInvoiceApi.PurchaseInvoice) { |
| | | return requestClient.post('/erp/purchase-invoice/create', data); |
| | | } |
| | | |
| | | /** ä¿®æ¹æ¥ç¥¨ */ |
| | | export function updatePurchaseInvoice(data: ErpPurchaseInvoiceApi.PurchaseInvoice) { |
| | | return requestClient.put('/erp/purchase-invoice/update', data); |
| | | } |
| | | |
| | | /** å 餿¥ç¥¨ */ |
| | | export function deletePurchaseInvoice(id: number) { |
| | | return requestClient.delete(`/erp/purchase-invoice/delete?id=${id}`); |
| | | } |
| | | |
| | | /** å¯¼åºæ¥ç¥¨ */ |
| | | export function exportPurchaseInvoice(params: Record<string, unknown>) { |
| | | return requestClient.download('/erp/purchase-invoice/export-excel', { params }); |
| | | } |
| | | |
| | | /** æäº¤æ¥ç¥¨å®¡æ ¸ */ |
| | | export function submitPurchaseInvoice(id: number) { |
| | | return requestClient.put(`/erp/purchase-invoice/submit?id=${id}`); |
| | | } |
| | | |
| | | /** è·å¾å¾
å®¡æ ¸æ¥ç¥¨æ°é */ |
| | | export function getAuditPurchaseInvoiceCount() { |
| | | return requestClient.get<number>('/erp/purchase-invoice/audit-count'); |
| | | } |
| | | |
| | | /** æ¥è¯¢æ¥ç¥¨ä¸æåè¡¨ï¼æä¾åºåå¯éæ¥ç¥¨ï¼ä»
å®¡æ ¸éè¿ä¸å·²ä¸ä¼ å票éä»¶ï¼ */ |
| | | export function getPurchaseInvoiceSimpleList( |
| | | supplierId: number, |
| | | purchaseOrderId?: number, |
| | | ) { |
| | | const params = `supplierId=${supplierId}${ |
| | | purchaseOrderId ? `&purchaseOrderId=${purchaseOrderId}` : '' |
| | | }`; |
| | | return requestClient.get<ErpPurchaseInvoiceApi.PurchaseInvoiceSimple[]>( |
| | | `/erp/purchase-invoice/simple-list?${params}`, |
| | | ); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { PageParam, PageResult } from '#/packages/effects/request/src'; |
| | | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace HrmEmployeeContractApi { |
| | | /** åå·¥åå */ |
| | | export interface EmployeeContract { |
| | | id?: number; |
| | | /** ç»ç¾ä¸ä¸ä»½ååID */ |
| | | parentId?: number; |
| | | /** ç»ç¾ä¸ä¸ä»½ååç¼å· */ |
| | | parentNo?: string; |
| | | /** æ¯å¦å½åçæåå */ |
| | | isCurrent?: boolean; |
| | | /** ååç¼å·ï¼å端èªå¨çæï¼ */ |
| | | contractNo?: string; |
| | | /** åå·¥ID */ |
| | | employeeId?: number; |
| | | /** åå·¥å§å */ |
| | | employeeName?: string; |
| | | /** åå·¥å·¥å· */ |
| | | employeeNo?: string; |
| | | /** é¨é¨åç§° */ |
| | | deptName?: string; |
| | | /** ååç±»åï¼1-å³å¨åå 2-å³å¡åå 3-å®ä¹ åè®® 4-å³å¡æ´¾é£ 5-å
¶ä» */ |
| | | contractType?: number; |
| | | /** ååæéç±»åï¼1-åºå®æé 2-æ åºå®æé 3-以宿ä¸å®å·¥ä½ä»»å¡ä¸ºæé */ |
| | | contractTermType?: number; |
| | | /** ç¾çº¦ä¸»ä½ */ |
| | | signCompany?: string; |
| | | /** ç¾è®¢æ¥æ */ |
| | | signDate?: string; |
| | | /** ååå¼å§æ¥æ */ |
| | | startDate?: string; |
| | | /** ååç»ææ¥æ */ |
| | | endDate?: string; |
| | | /** è¯ç¨æå¼å§æ¥æ */ |
| | | probationStartDate?: string; |
| | | /** è¯ç¨æç»ææ¥æ */ |
| | | probationEndDate?: string; |
| | | /** è¯ç¨æå·¥èµ */ |
| | | probationSalary?: number; |
| | | /** 转æ£å·¥èµ */ |
| | | regularSalary?: number; |
| | | /** è§£é¤ç»æ¢ç¶æï¼0-æ£å¸¸ 1-å·²è§£é¤ 2-å·²ç»æ¢ */ |
| | | terminateStatus?: number; |
| | | /** è§£é¤/ç»æ¢æ¥æ */ |
| | | terminateDate?: string; |
| | | /** è§£é¤/ç»æ¢åå */ |
| | | terminateReason?: string; |
| | | /** ååç¶æï¼å¨æè®¡ç®ï¼ï¼1-å¾
çæ 2-çæä¸ 3-å³å°å°æ 4-已尿 5-å·²è§£é¤ 6-å·²ç»æ¢ */ |
| | | status?: number; |
| | | /** éä»¶ */ |
| | | attachmentList?: AttachmentItem[]; |
| | | /** éä»¶ blobId å表 */ |
| | | blobIds?: number[]; |
| | | remark?: string; |
| | | createTime?: string; |
| | | } |
| | | |
| | | /** é件项 */ |
| | | export interface AttachmentItem { |
| | | id: number; |
| | | name?: string; |
| | | url?: string; |
| | | uid?: string; |
| | | } |
| | | |
| | | /** åå·¥ååæ¥è¯¢åæ° */ |
| | | export interface EmployeeContractPageParam extends PageParam { |
| | | contractNo?: string; |
| | | employeeId?: number; |
| | | contractType?: number; |
| | | contractTermType?: number; |
| | | terminateStatus?: number; |
| | | status?: number; |
| | | /** å°æç±»åï¼1-å³å°å°æ 2-已尿 */ |
| | | expiryType?: number; |
| | | } |
| | | |
| | | /** è§£é¤/ç»æ¢ååè¯·æ± */ |
| | | export interface TerminateReq { |
| | | id: number; |
| | | terminateStatus: number; |
| | | terminateDate: string; |
| | | terminateReason: string; |
| | | } |
| | | } |
| | | |
| | | /** è·ååå·¥ååå页å表 */ |
| | | export function getEmployeeContractPage( |
| | | params: HrmEmployeeContractApi.EmployeeContractPageParam, |
| | | ) { |
| | | return requestClient.get<PageResult<HrmEmployeeContractApi.EmployeeContract>>( |
| | | '/hrm/employee-contract/page', |
| | | { params }, |
| | | ); |
| | | } |
| | | |
| | | /** è·ååå·¥åå详æ
*/ |
| | | export function getEmployeeContract(id: number) { |
| | | return requestClient.get<HrmEmployeeContractApi.EmployeeContract>( |
| | | `/hrm/employee-contract/get?id=${id}`, |
| | | ); |
| | | } |
| | | |
| | | /** å建åå·¥åå */ |
| | | export function createEmployeeContract(data: HrmEmployeeContractApi.EmployeeContract) { |
| | | return requestClient.post('/hrm/employee-contract/create', data); |
| | | } |
| | | |
| | | /** æ´æ°åå·¥åå */ |
| | | export function updateEmployeeContract(data: HrmEmployeeContractApi.EmployeeContract) { |
| | | return requestClient.put('/hrm/employee-contract/update', data); |
| | | } |
| | | |
| | | /** è§£é¤/ç»æ¢åå·¥åå */ |
| | | export function terminateEmployeeContract(data: HrmEmployeeContractApi.TerminateReq) { |
| | | return requestClient.put('/hrm/employee-contract/terminate', data); |
| | | } |
| | | |
| | | /** å é¤åå·¥åå */ |
| | | export function deleteEmployeeContract(id: number) { |
| | | return requestClient.delete(`/hrm/employee-contract/delete?id=${id}`); |
| | | } |
| | | |
| | | /** è·åå³å°å°æååæ°é */ |
| | | export function getExpiringContractCount() { |
| | | return requestClient.get<number>('/hrm/employee-contract/expiring-count'); |
| | | } |
| | |
| | | HRM_SALARY_STATUS: 'hrm_salary_status', // HRM èªèµç¶æ |
| | | HRM_HANDOVER_STATUS: 'hrm_handover_status', // HRM 交æ¥ç¶æ |
| | | HRM_PAYMENT_METHOD: 'hrm_payment_method', // HRM åæ¾æ¹å¼ |
| | | HRM_CONTRACT_TYPE: 'hrm_contract_type', // HRM ååç±»å |
| | | HRM_CONTRACT_TERM_TYPE: 'hrm_contract_term_type', // HRM ååæéç±»å |
| | | HRM_CONTRACT_STATUS: 'hrm_contract_status', // HRM ååç¶æ |
| | | HRM_CONTRACT_TERMINATE_STATUS: 'hrm_contract_terminate_status', // HRM ååè§£é¤ç»æ¢ç¶æ |
| | | } as const; |
| | | |
| | | /** åå
¸ç±»åæä¸¾ - ç»ä¸å¯¼åº */ |
| | |
| | | import { erpPriceInputFormatter } from '@vben/utils'; |
| | | |
| | | import { getAccountSimpleList } from '#/api/erp/finance/account'; |
| | | import { getPurchaseInvoiceSimpleList } from '#/api/erp/purchase/invoice'; |
| | | import { getSupplierSimpleList } from '#/api/srm/supplier'; |
| | | import { getSimpleUserList } from '#/api/system/user'; |
| | | import { getRangePickerDefaultProps } from '#/utils'; |
| | |
| | | fieldName: 'supplierId', |
| | | label: 'ä¾åºå', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | componentProps: (_values, form) => ({ |
| | | disabled: formType === 'detail', |
| | | placeholder: 'è¯·éæ©ä¾åºå', |
| | | allowClear: true, |
| | |
| | | api: getSupplierSimpleList, |
| | | labelField: 'name', |
| | | valueField: 'id', |
| | | }, |
| | | onChange: () => { |
| | | // ä¾åºååååï¼æ¸
空已éçå
³èæ¥ç¥¨ |
| | | form.setFieldValue('invoiceId', undefined); |
| | | }, |
| | | }), |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'invoiceId', |
| | | label: 'å
³èæ¥ç¥¨', |
| | | component: formType === 'detail' ? 'Input' : 'Select', |
| | | componentProps: |
| | | formType === 'detail' |
| | | ? { |
| | | disabled: true, |
| | | placeholder: '--', |
| | | } |
| | | : undefined, |
| | | rules: 'required', |
| | | dependencies: { |
| | | // ä¾èµ invoiceId èªèº«ï¼ç¡®ä¿ç¼è¾åæ¾æ¶éæ°å è½½é项以å¹é
å·²éæ¥ç¥¨ |
| | | triggerFields: ['supplierId', 'invoiceId'], |
| | | disabled: (values) => formType === 'detail' || !values.supplierId, |
| | | async componentProps(values) { |
| | | if (formType === 'detail') { |
| | | return {}; |
| | | } |
| | | if (!values.supplierId) { |
| | | return { |
| | | options: [], |
| | | placeholder: '请å
éæ©ä¾åºå', |
| | | }; |
| | | } |
| | | const invoices = await getPurchaseInvoiceSimpleList( |
| | | values.supplierId, |
| | | ); |
| | | return { |
| | | options: invoices.map((item) => { |
| | | const remain = item.remainingInvoicePrice ?? item.price ?? 0; |
| | | return { |
| | | label: `${item.no} / ${item.invoiceNo ?? '-'} / Â¥${item.price ?? 0} / å©ä½å¯ä» Â¥${remain.toFixed(2)}`, |
| | | value: item.id, |
| | | }; |
| | | }), |
| | | placeholder: 'è¯·éæ©å
³èæ¥ç¥¨', |
| | | } as any; |
| | | }, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'financeUserId', |
| | |
| | | minWidth: 120, |
| | | }, |
| | | { |
| | | field: 'invoice', |
| | | title: 'å
³èæ¥ç¥¨', |
| | | minWidth: 200, |
| | | slots: { default: 'invoice' }, |
| | | }, |
| | | { |
| | | field: 'paymentTime', |
| | | title: '仿¬¾æ¶é´', |
| | | width: 160, |
| | |
| | | ]" |
| | | /> |
| | | </template> |
| | | <template #invoice="{ row }"> |
| | | <span v-if="row.invoice"> |
| | | {{ row.invoice.no |
| | | }}{{ row.invoice.invoiceNo ? ` / ${row.invoice.invoiceNo}` : '' }} |
| | | </span> |
| | | <span v-else>--</span> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | |
| | | formData.value = await getFinancePayment(data.id); |
| | | // è®¾ç½®å° values |
| | | await formApi.setValues(formData.value, false); |
| | | // 详æ
模å¼ä¸ï¼å
³èæ¥ç¥¨åæ®µç¨ Input å±ç¤ºæ¥ç¥¨ç¼å· |
| | | if (formType.value === 'detail' && formData.value?.invoice) { |
| | | await formApi.setFieldValue('invoiceId', formData.value.invoice.no); |
| | | } |
| | | if (formData.value?.attachmentList?.length) { |
| | | const blobIds = formData.value.attachmentList.map((item) => ({ |
| | | uid: String(item.id), |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | |
| | | import { getSupplierSimpleList } from '#/api/srm/supplier'; |
| | | |
| | | import { markRaw } from 'vue'; |
| | | |
| | | import PurchaseOrderSelect from './modules/purchase-order-select.vue'; |
| | | |
| | | /** 表åç±»å */ |
| | | export type FormType = 'create' | 'detail' | 'edit'; |
| | | |
| | | /** æ°å¢/ä¿®æ¹ç表å */ |
| | | export function useFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'id', |
| | | component: 'Input', |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'no', |
| | | label: 'æ¥ç¥¨ç¼å·', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: 'ä¿åæ¶èªå¨çæ', |
| | | disabled: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'purchaseOrderId', |
| | | label: 'éè´è®¢å', |
| | | component: markRaw(PurchaseOrderSelect), |
| | | rules: 'required', |
| | | dependencies: { |
| | | triggerFields: ['id'], |
| | | disabled: (values) => !!values.id, |
| | | }, |
| | | componentProps: (_values, form) => ({ |
| | | placeholder: 'è¯·éæ©éè´è®¢å', |
| | | onChange: (order: { supplierName?: string } | undefined) => { |
| | | form.setFieldValue('supplierName', order?.supplierName); |
| | | }, |
| | | }), |
| | | }, |
| | | { |
| | | fieldName: 'supplierName', |
| | | label: 'ä¾åºå', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: 'éæ©éè´è®¢ååèªå¨å¸¦åº', |
| | | disabled: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'invoiceNo', |
| | | label: 'å票å·ç ', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å票å·ç ', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'invoiceTitle', |
| | | label: 'å票æ¬å¤´', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å票æ¬å¤´', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'price', |
| | | label: 'æ¥ç¥¨éé¢ï¼å
ï¼', |
| | | component: 'InputNumber', |
| | | rules: 'required', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | placeholder: '请è¾å
¥æ¥ç¥¨éé¢', |
| | | min: 0, |
| | | precision: 2, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'invoiceTime', |
| | | label: 'æ¥ç¥¨æ¥æ', |
| | | component: 'DatePicker', |
| | | rules: 'required', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©æ¥ç¥¨æ¥æ', |
| | | showTime: false, |
| | | valueFormat: 'YYYY-MM-DD', |
| | | format: 'YYYY-MM-DD', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'blobIds', |
| | | label: 'å票éä»¶', |
| | | component: 'FileUpload', |
| | | componentProps: { |
| | | valueKey: 'id', |
| | | maxNumber: 10, |
| | | multiple: true, |
| | | accept: ['jpg', 'jpeg', 'png', 'pdf'], |
| | | helpText: 'æ¯æjpgãjpegãpngãpdfæ ¼å¼ï¼å个æä»¶ä¸è¶
è¿2MB', |
| | | }, |
| | | formItemClass: 'md:col-span-2', |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | component: 'Textarea', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å¤æ³¨', |
| | | rows: 4, |
| | | }, |
| | | formItemClass: 'md:col-span-2', |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çæç´¢è¡¨å */ |
| | | export function useGridFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'no', |
| | | label: 'æ¥ç¥¨ç¼å·', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥æ¥ç¥¨ç¼å·', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'supplierId', |
| | | label: 'ä¾åºå', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©ä¾åºå', |
| | | allowClear: true, |
| | | showSearch: true, |
| | | api: getSupplierSimpleList, |
| | | labelField: 'name', |
| | | valueField: 'id', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'auditStatus', |
| | | label: '审æ¹ç¶æ', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: [ |
| | | { label: 'æªæäº¤', value: 0 }, |
| | | { label: '审æ¹ä¸', value: 10 }, |
| | | { label: 'å®¡æ ¸éè¿', value: 20 }, |
| | | { label: 'å®¡æ ¸ä¸éè¿', value: 30 }, |
| | | { label: 'å·²ä½åº', value: 40 }, |
| | | ], |
| | | placeholder: 'è¯·éæ©å®¡æ¹ç¶æ', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çåæ®µ */ |
| | | export function useGridColumns(): VxeTableGridOptions['columns'] { |
| | | return [ |
| | | { |
| | | title: 'æ¥ç¥¨ç¼å·', |
| | | field: 'no', |
| | | minWidth: 160, |
| | | fixed: 'left', |
| | | slots: { default: 'no' }, |
| | | }, |
| | | { |
| | | title: 'ä¾åºå', |
| | | field: 'supplierName', |
| | | minWidth: 150, |
| | | }, |
| | | { |
| | | title: 'éè´è®¢åç¼å·', |
| | | field: 'order', |
| | | minWidth: 160, |
| | | slots: { default: 'orderNo' }, |
| | | }, |
| | | { |
| | | title: 'å票å·ç ', |
| | | field: 'invoiceNo', |
| | | minWidth: 150, |
| | | }, |
| | | { |
| | | title: 'æ¥ç¥¨éé¢ï¼å
ï¼', |
| | | field: 'price', |
| | | minWidth: 150, |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | title: 'å©ä½å¯ä»éé¢', |
| | | field: 'remainingInvoicePrice', |
| | | minWidth: 150, |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | title: 'æ¥ç¥¨æ¥æ', |
| | | field: 'invoiceTime', |
| | | minWidth: 150, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | { |
| | | title: '夿³¨', |
| | | field: 'remark', |
| | | minWidth: 150, |
| | | }, |
| | | { |
| | | title: 'éä»¶', |
| | | field: 'attachmentList', |
| | | minWidth: 100, |
| | | fixed: 'right', |
| | | slots: { default: 'attachment' }, |
| | | }, |
| | | { |
| | | title: '审æ¹ç¶æ', |
| | | field: 'auditStatus', |
| | | minWidth: 100, |
| | | fixed: 'right', |
| | | slots: { default: 'auditStatus' }, |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | field: 'actions', |
| | | minWidth: 200, |
| | | fixed: 'right', |
| | | slots: { default: 'actions' }, |
| | | }, |
| | | ]; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { ErpPurchaseInvoiceApi } from '#/api/erp/purchase/invoice'; |
| | | |
| | | import { useRouter } from 'vue-router'; |
| | | |
| | | import { Page, useVbenModal } from '@vben/common-ui'; |
| | | import { downloadFileFromBlobPart } from '@vben/utils'; |
| | | |
| | | import { Button, message, Tag } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | deletePurchaseInvoice, |
| | | exportPurchaseInvoice, |
| | | getPurchaseInvoicePage, |
| | | submitPurchaseInvoice, |
| | | } from '#/api/erp/purchase/invoice'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useGridColumns, useGridFormSchema } from './data'; |
| | | import Form from './modules/form.vue'; |
| | | |
| | | defineOptions({ name: 'ErpPurchaseInvoice' }); |
| | | |
| | | const { push } = useRouter(); |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | /** å·æ°è¡¨æ ¼ */ |
| | | function handleRefresh() { |
| | | gridApi.query(); |
| | | } |
| | | |
| | | /** 导åºè¡¨æ ¼ */ |
| | | async function handleExport() { |
| | | const formValues = await gridApi.formApi.getValues(); |
| | | const data = await exportPurchaseInvoice(formValues); |
| | | downloadFileFromBlobPart({ fileName: 'æ¥ç¥¨.xls', source: data }); |
| | | } |
| | | |
| | | /** å建æ¥ç¥¨ */ |
| | | function handleCreate() { |
| | | formModalApi.setData({ formType: 'create' }).open(); |
| | | } |
| | | |
| | | /** ç¼è¾æ¥ç¥¨ */ |
| | | function handleEdit(row: ErpPurchaseInvoiceApi.PurchaseInvoice) { |
| | | formModalApi.setData({ formType: 'edit', id: row.id }).open(); |
| | | } |
| | | |
| | | /** æ¥çæ¥ç¥¨è¯¦æ
*/ |
| | | function handleDetail(row: ErpPurchaseInvoiceApi.PurchaseInvoice) { |
| | | formModalApi.setData({ formType: 'detail', id: row.id }).open(); |
| | | } |
| | | |
| | | /** å 餿¥ç¥¨ */ |
| | | async function handleDelete(row: ErpPurchaseInvoiceApi.PurchaseInvoice) { |
| | | const hideLoading = message.loading({ |
| | | content: $t('ui.actionMessage.deleting', [row.no]), |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await deletePurchaseInvoice(row.id!); |
| | | message.success($t('ui.actionMessage.deleteSuccess', [row.no])); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | /** æäº¤å®¡æ ¸ */ |
| | | async function handleSubmit(row: ErpPurchaseInvoiceApi.PurchaseInvoice) { |
| | | const hideLoading = message.loading({ |
| | | content: 'æäº¤å®¡æ ¸ä¸...', |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await submitPurchaseInvoice(row.id!); |
| | | message.success('æäº¤å®¡æ ¸æå'); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | /** æ¥ç审æ¹è¯¦æ
*/ |
| | | function handleProcessDetail(row: ErpPurchaseInvoiceApi.PurchaseInvoice) { |
| | | push({ |
| | | name: 'BpmProcessInstanceDetail', |
| | | query: { id: row.processInstanceId }, |
| | | }); |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | formOptions: { |
| | | schema: useGridFormSchema(), |
| | | }, |
| | | gridOptions: { |
| | | columns: useGridColumns(), |
| | | height: 'auto', |
| | | keepSource: true, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => { |
| | | return await getPurchaseInvoicePage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | }); |
| | | }, |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | search: true, |
| | | }, |
| | | } as VxeTableGridOptions<ErpPurchaseInvoiceApi.PurchaseInvoice>, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Page auto-content-height> |
| | | <FormModal @success="handleRefresh" /> |
| | | <Grid table-title="æ¥ç¥¨å表"> |
| | | <template #toolbar-tools> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('ui.actionTitle.create', ['æ¥ç¥¨']), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['erp:purchase-invoice:create'], |
| | | onClick: handleCreate, |
| | | }, |
| | | { |
| | | label: $t('ui.actionTitle.export'), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.DOWNLOAD, |
| | | auth: ['erp:purchase-invoice:export'], |
| | | onClick: handleExport, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | <template #no="{ row }"> |
| | | <Button type="link" @click="handleDetail(row)"> |
| | | {{ row.no }} |
| | | </Button> |
| | | </template> |
| | | <template #orderNo="{ row }"> |
| | | <span>{{ row.order?.no ?? '--' }}</span> |
| | | </template> |
| | | <template #attachment="{ row }"> |
| | | <Tag v-if="!row.hasAttachment" color="warning">æªä¸ä¼ </Tag> |
| | | <Tag v-else color="success">å·²ä¸ä¼ </Tag> |
| | | </template> |
| | | <template #auditStatus="{ row }"> |
| | | <Tag v-if="row.auditStatus === 0" color="default">æªæäº¤</Tag> |
| | | <Tag v-else-if="row.auditStatus === 10" color="warning">审æ¹ä¸</Tag> |
| | | <Tag v-else-if="row.auditStatus === 20" color="success">å®¡æ ¸éè¿</Tag> |
| | | <Tag v-else-if="row.auditStatus === 30" color="error">å®¡æ ¸ä¸éè¿</Tag> |
| | | <Tag v-else-if="row.auditStatus === 40" color="default">å·²ä½åº</Tag> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['erp:purchase-invoice:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.edit'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['erp:purchase-invoice:update'], |
| | | ifShow: row.auditStatus === 0, |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | | label: 'æäº¤å®¡æ ¸', |
| | | type: 'link', |
| | | auth: ['erp:purchase-invoice:update'], |
| | | onClick: handleSubmit.bind(null, row), |
| | | ifShow: row.auditStatus === 0, |
| | | }, |
| | | { |
| | | label: 'æ¥ç审æ¹', |
| | | type: 'link', |
| | | auth: ['erp:purchase-invoice:query'], |
| | | onClick: handleProcessDetail.bind(null, row), |
| | | ifShow: row.auditStatus !== 0 && !!row.processInstanceId, |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['erp:purchase-invoice:delete'], |
| | | ifShow: row.auditStatus !== 20, |
| | | popConfirm: { |
| | | title: $t('ui.actionMessage.deleteConfirm', [row.no]), |
| | | confirm: handleDelete.bind(null, row), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | </Page> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { FormType } from '../data'; |
| | | |
| | | import type { ErpPurchaseInvoiceApi } from '#/api/erp/purchase/invoice'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { |
| | | createPurchaseInvoice, |
| | | getPurchaseInvoice, |
| | | updatePurchaseInvoice, |
| | | } from '#/api/erp/purchase/invoice'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useFormSchema } from '../data'; |
| | | |
| | | const emit = defineEmits(['success']); |
| | | const formData = ref<ErpPurchaseInvoiceApi.PurchaseInvoice>(); |
| | | const formType = ref<FormType>('create'); |
| | | |
| | | const getTitle = computed(() => { |
| | | if (formType.value === 'create') { |
| | | return $t('ui.actionTitle.create', ['æ¥ç¥¨']); |
| | | } else if (formType.value === 'edit') { |
| | | return $t('ui.actionTitle.edit', ['æ¥ç¥¨']); |
| | | } else { |
| | | return 'æ¥ç¥¨è¯¦æ
'; |
| | | } |
| | | }); |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: 'w-full', |
| | | }, |
| | | labelWidth: 120, |
| | | }, |
| | | wrapperClass: 'grid-cols-2', |
| | | layout: 'horizontal', |
| | | schema: useFormSchema(), |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | const data = (await formApi.getValues()) as ErpPurchaseInvoiceApi.PurchaseInvoice; |
| | | if (formData.value?.id) { |
| | | data.id = formData.value.id; |
| | | } |
| | | try { |
| | | await (formData.value?.id |
| | | ? updatePurchaseInvoice(data) |
| | | : createPurchaseInvoice(data)); |
| | | await modalApi.close(); |
| | | emit('success'); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | formData.value = undefined; |
| | | return; |
| | | } |
| | | const data = modalApi.getData<{ formType: FormType; id?: number }>(); |
| | | formType.value = data.formType; |
| | | formApi.setDisabled(formType.value === 'detail'); |
| | | formApi.updateSchema(useFormSchema()); |
| | | await formApi.resetForm(); |
| | | if (!data || !data.id) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | try { |
| | | formData.value = await getPurchaseInvoice(data.id); |
| | | if (formData.value?.attachmentList?.length) { |
| | | // ç¨ attachmentList ä»£æ¿ blobIdsï¼è®©ä¸ä¼ ç»ä»¶è½å±ç¤ºæä»¶ååé¢è§é¾æ¥ |
| | | (formData.value as Record<string, unknown>).blobIds = |
| | | formData.value.attachmentList; |
| | | } |
| | | await formApi.setValues(formData.value as any); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal :title="getTitle" class="w-3/5"> |
| | | <Form class="mx-4" /> |
| | | </Modal> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { ErpPurchaseOrderApi } from '#/api/erp/purchase/order'; |
| | | |
| | | import { computed, nextTick, ref, watch } from 'vue'; |
| | | |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { IconifyIcon } from '@vben/icons'; |
| | | |
| | | import { Input, Modal } from 'ant-design-vue'; |
| | | |
| | | import { useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | getPurchaseOrder, |
| | | getPurchaseOrderPage, |
| | | } from '#/api/erp/purchase/order'; |
| | | |
| | | defineOptions({ name: 'ErpPurchaseInvoiceOrderSelect' }); |
| | | |
| | | const props = withDefaults( |
| | | defineProps<{ |
| | | disabled?: boolean; |
| | | modelValue?: number; |
| | | placeholder?: string; |
| | | }>(), |
| | | { |
| | | disabled: false, |
| | | modelValue: undefined, |
| | | placeholder: 'è¯·éæ©éè´è®¢å', |
| | | }, |
| | | ); |
| | | const emit = defineEmits<{ |
| | | change: [order: ErpPurchaseOrderApi.PurchaseOrder | undefined]; |
| | | 'update:modelValue': [value: number | undefined]; |
| | | }>(); |
| | | |
| | | const open = ref(false); // éæ©å¼¹çªæ¯å¦æå¼ |
| | | const order = ref<ErpPurchaseOrderApi.PurchaseOrder>(); // å½åéä¸éè´è®¢å |
| | | |
| | | const displayNo = computed(() => order.value?.no ?? ''); |
| | | |
| | | /** æ ¹æ®è®¢åç¼å·åæ¾éæ©å¨ */ |
| | | async function resolveOrderById(id: number | undefined) { |
| | | if (!id) { |
| | | order.value = undefined; |
| | | return; |
| | | } |
| | | if (order.value?.id === id) { |
| | | return; |
| | | } |
| | | order.value = await getPurchaseOrder(id); |
| | | } |
| | | |
| | | watch( |
| | | () => props.modelValue, |
| | | (value) => { |
| | | resolveOrderById(value); |
| | | }, |
| | | { immediate: true }, |
| | | ); |
| | | |
| | | /** è¡¨æ ¼é
ç½® */ |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | formOptions: { |
| | | schema: [ |
| | | { |
| | | fieldName: 'no', |
| | | label: '订ååå·', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è®¢ååå·', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | gridOptions: { |
| | | columns: [ |
| | | { field: 'no', title: '订ååå·', width: 200, fixed: 'left' }, |
| | | { field: 'supplierName', title: 'ä¾åºå', minWidth: 120 }, |
| | | { |
| | | field: 'orderTime', |
| | | title: 'è®¢åæ¶é´', |
| | | width: 160, |
| | | formatter: 'formatDate', |
| | | }, |
| | | { |
| | | field: 'totalPrice', |
| | | title: 'å«ç¨éé¢', |
| | | formatter: 'formatAmount2', |
| | | minWidth: 120, |
| | | }, |
| | | { |
| | | field: 'status', |
| | | title: 'ç¶æ', |
| | | minWidth: 100, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.ERP_AUDIT_STATUS }, |
| | | }, |
| | | }, |
| | | ], |
| | | height: 520, |
| | | keepSource: true, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => { |
| | | return await getPurchaseOrderPage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | status: 20, // ä»
å±ç¤ºå·²å®¡æ ¸éè¿çéè´è®¢å |
| | | ...formValues, |
| | | }); |
| | | }, |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | radioConfig: { |
| | | trigger: 'row', |
| | | highlight: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | search: true, |
| | | }, |
| | | } as VxeTableGridOptions<ErpPurchaseOrderApi.PurchaseOrder>, |
| | | gridEvents: { |
| | | radioChange: ({ row }: { row: ErpPurchaseOrderApi.PurchaseOrder }) => { |
| | | order.value = row; |
| | | }, |
| | | }, |
| | | }); |
| | | |
| | | /** æå¼éæ©å¼¹çª */ |
| | | async function handleOpen() { |
| | | if (props.disabled) { |
| | | return; |
| | | } |
| | | open.value = true; |
| | | await nextTick(); |
| | | gridApi.query(); |
| | | } |
| | | |
| | | /** ç¡®è®¤éæ©éè´è®¢å */ |
| | | function handleOk() { |
| | | if (!order.value?.id) { |
| | | return; |
| | | } |
| | | emit('update:modelValue', order.value.id); |
| | | emit('change', order.value); |
| | | open.value = false; |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | | <div> |
| | | <Input |
| | | readonly |
| | | :disabled="disabled" |
| | | :placeholder="placeholder" |
| | | :value="displayNo" |
| | | @click="handleOpen" |
| | | > |
| | | <template #suffix> |
| | | <IconifyIcon |
| | | class="size-4 cursor-pointer" |
| | | icon="lucide:search" |
| | | :style="{ cursor: disabled ? 'not-allowed' : 'pointer' }" |
| | | /> |
| | | </template> |
| | | </Input> |
| | | <Modal |
| | | v-model:open="open" |
| | | title="éæ©éè´è®¢åï¼ä»
å·²å®¡æ ¸éè¿ï¼" |
| | | width="80%" |
| | | @cancel.stop="open = false" |
| | | @ok.stop="handleOk" |
| | | > |
| | | <Grid table-title="éè´è®¢åå表" /> |
| | | </Modal> |
| | | </div> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { HrmEmployeeContractApi } from '#/api/hrm/employee/contract'; |
| | | |
| | | import { DICT_TYPE } from '#/packages/constants/src'; |
| | | import { getDictOptions } from '#/packages/effects/hooks/src'; |
| | | |
| | | import { getEmployeeSimpleList } from '#/api/hrm/employee'; |
| | | |
| | | /** 表åç±»å */ |
| | | export type FormType = 'create' | 'update'; |
| | | |
| | | /** æ°å¢/ä¿®æ¹åå·¥ååç表å */ |
| | | export function useFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'id', |
| | | component: 'Input', |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'employeeId', |
| | | label: 'åå·¥', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | api: getEmployeeSimpleList, |
| | | labelField: 'name', |
| | | valueField: 'id', |
| | | showSearch: true, |
| | | filterOption: (input: string, option: any) => |
| | | option.label?.toLowerCase().includes(input.toLowerCase()), |
| | | placeholder: 'è¯·éæ©åå·¥', |
| | | }, |
| | | rules: 'selectRequired', |
| | | formItemClass: 'col-span-2', |
| | | }, |
| | | { |
| | | fieldName: 'contractType', |
| | | label: 'ååç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©ååç±»å', |
| | | options: getDictOptions(DICT_TYPE.HRM_CONTRACT_TYPE, 'number'), |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | | { |
| | | fieldName: 'contractTermType', |
| | | label: 'æéç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©æéç±»å', |
| | | options: getDictOptions(DICT_TYPE.HRM_CONTRACT_TERM_TYPE, 'number'), |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | | { |
| | | fieldName: 'signCompany', |
| | | label: 'ç¾çº¦ä¸»ä½', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥ç¾çº¦ä¸»ä½ï¼å
¬å¸å
¨ç§°ï¼', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'signDate', |
| | | label: 'ç¾è®¢æ¥æ', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©ç¾è®¢æ¥æ', |
| | | valueFormat: 'YYYY-MM-DD', |
| | | style: { width: '100%' }, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'startDate', |
| | | label: 'å¼å§æ¥æ', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©å¼å§æ¥æ', |
| | | valueFormat: 'YYYY-MM-DD', |
| | | style: { width: '100%' }, |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'endDate', |
| | | label: 'ç»ææ¥æ', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | placeholder: 'æ åºå®æéå¯ä¸å¡«', |
| | | valueFormat: 'YYYY-MM-DD', |
| | | style: { width: '100%' }, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'probationStartDate', |
| | | label: 'è¯ç¨æå¼å§', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©è¯ç¨æå¼å§æ¥æ', |
| | | valueFormat: 'YYYY-MM-DD', |
| | | style: { width: '100%' }, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'probationEndDate', |
| | | label: 'è¯ç¨æç»æ', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©è¯ç¨æç»ææ¥æ', |
| | | valueFormat: 'YYYY-MM-DD', |
| | | style: { width: '100%' }, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'probationSalary', |
| | | label: 'è¯ç¨æå·¥èµ', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è¯ç¨æå·¥èµ', |
| | | min: 0, |
| | | precision: 2, |
| | | style: { width: '100%' }, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'regularSalary', |
| | | label: '转æ£å·¥èµ', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è½¬æ£å·¥èµ', |
| | | min: 0, |
| | | precision: 2, |
| | | style: { width: '100%' }, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'blobIds', |
| | | label: 'éä»¶', |
| | | component: 'FileUpload', |
| | | formItemClass: 'col-span-2', |
| | | componentProps: { |
| | | valueKey: 'id', |
| | | maxNumber: 10, |
| | | multiple: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | component: 'Textarea', |
| | | formItemClass: 'col-span-2', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å¤æ³¨', |
| | | rows: 2, |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çæç´¢è¡¨å */ |
| | | export function useGridFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'contractNo', |
| | | label: 'ååç¼å·', |
| | | component: 'Input', |
| | | componentProps: { |
| | | allowClear: true, |
| | | placeholder: '请è¾å
¥ååç¼å·', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'employeeId', |
| | | label: 'åå·¥', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | api: getEmployeeSimpleList, |
| | | labelField: 'name', |
| | | valueField: 'id', |
| | | showSearch: true, |
| | | filterOption: (input: string, option: any) => |
| | | option.label?.toLowerCase().includes(input.toLowerCase()), |
| | | allowClear: true, |
| | | placeholder: 'è¯·éæ©åå·¥', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'contractType', |
| | | label: 'ååç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.HRM_CONTRACT_TYPE, 'number'), |
| | | placeholder: 'è¯·éæ©ååç±»å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'contractTermType', |
| | | label: 'æéç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.HRM_CONTRACT_TERM_TYPE, 'number'), |
| | | placeholder: 'è¯·éæ©æéç±»å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'terminateStatus', |
| | | label: 'è§£é¤ç»æ¢ç¶æ', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.HRM_CONTRACT_TERMINATE_STATUS, 'number'), |
| | | placeholder: 'è¯·éæ©è§£é¤ç»æ¢ç¶æ', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'status', |
| | | label: 'ååç¶æ', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.HRM_CONTRACT_STATUS, 'number'), |
| | | placeholder: 'è¯·éæ©ååç¶æ', |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çåæ®µ */ |
| | | export function useGridColumns(): VxeTableGridOptions<HrmEmployeeContractApi.EmployeeContract>['columns'] { |
| | | return [ |
| | | { field: 'contractNo', title: 'ååç¼å·', minWidth: 160 }, |
| | | { |
| | | field: 'parentNo', |
| | | title: 'ç»ç¾èª', |
| | | minWidth: 140, |
| | | slots: { default: 'parentNo' }, |
| | | }, |
| | | { field: 'employeeName', title: 'åå·¥å§å', minWidth: 100 }, |
| | | { field: 'employeeNo', title: 'å工工å·', minWidth: 130 }, |
| | | { field: 'deptName', title: 'é¨é¨', minWidth: 120 }, |
| | | { |
| | | field: 'contractType', |
| | | title: 'ååç±»å', |
| | | width: 100, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.HRM_CONTRACT_TYPE }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'contractTermType', |
| | | title: 'æéç±»å', |
| | | width: 130, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.HRM_CONTRACT_TERM_TYPE }, |
| | | }, |
| | | }, |
| | | { field: 'signDate', title: 'ç¾è®¢æ¥æ', width: 110 }, |
| | | { field: 'startDate', title: 'å¼å§æ¥æ', width: 110 }, |
| | | { field: 'endDate', title: 'ç»ææ¥æ', width: 110 }, |
| | | { |
| | | field: 'status', |
| | | title: 'ååç¶æ', |
| | | width: 100, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.HRM_CONTRACT_STATUS }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'isCurrent', |
| | | title: 'å½ååå', |
| | | width: 90, |
| | | slots: { default: 'isCurrent' }, |
| | | }, |
| | | { |
| | | field: 'createTime', |
| | | title: 'å建æ¶é´', |
| | | width: 180, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | width: 260, |
| | | fixed: 'right', |
| | | slots: { default: 'actions' }, |
| | | }, |
| | | ]; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { HrmEmployeeContractApi } from '#/api/hrm/employee/contract'; |
| | | |
| | | import { Page, useVbenModal } from '#/packages/effects/common-ui/src'; |
| | | |
| | | import { message, Tag } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | deleteEmployeeContract, |
| | | getEmployeeContractPage, |
| | | } from '#/api/hrm/employee/contract'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useGridColumns, useGridFormSchema } from './data'; |
| | | import Form from './modules/form.vue'; |
| | | import Terminate from './modules/terminate.vue'; |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | const [TerminateModal, terminateModalApi] = useVbenModal({ |
| | | connectedComponent: Terminate, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | /** å·æ°è¡¨æ ¼ */ |
| | | function handleRefresh() { |
| | | gridApi.query(); |
| | | } |
| | | |
| | | /** æ°å¢åå */ |
| | | function handleCreate() { |
| | | formModalApi.setData({ formType: 'create' }).open(); |
| | | } |
| | | |
| | | /** ç¼è¾åå */ |
| | | function handleEdit(row: HrmEmployeeContractApi.EmployeeContract) { |
| | | formModalApi.setData({ id: row.id, formType: 'update' }).open(); |
| | | } |
| | | |
| | | /** ç»ç¾ååï¼å¸¦å
¥ä¸ä»½åååºç¡ä¿¡æ¯ï¼å建æ°ååï¼å端èªå¨å
³è parentIdï¼ */ |
| | | function handleRenew(row: HrmEmployeeContractApi.EmployeeContract) { |
| | | formModalApi.setData({ formType: 'create', renewFrom: row }).open(); |
| | | } |
| | | |
| | | /** è§£é¤/ç»æ¢åå */ |
| | | function handleTerminate(row: HrmEmployeeContractApi.EmployeeContract) { |
| | | terminateModalApi.setData({ id: row.id }).open(); |
| | | } |
| | | |
| | | /** å é¤åå */ |
| | | async function handleDelete(row: HrmEmployeeContractApi.EmployeeContract) { |
| | | await deleteEmployeeContract(row.id!); |
| | | message.success($t('ui.actionMessage.deleteSuccess', ['åå·¥åå'])); |
| | | handleRefresh(); |
| | | } |
| | | |
| | | /** æ¯å¦å¯è§£é¤/ç»æ¢ï¼ä»
æªè§£é¤/æªç»æ¢çååå¯æä½ */ |
| | | function isTerminable(row: HrmEmployeeContractApi.EmployeeContract) { |
| | | return row.terminateStatus === 0; |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | formOptions: { |
| | | schema: useGridFormSchema(), |
| | | }, |
| | | gridOptions: { |
| | | columns: useGridColumns(), |
| | | height: 'auto', |
| | | keepSource: true, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => |
| | | await getEmployeeContractPage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | }), |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | search: true, |
| | | }, |
| | | } as VxeTableGridOptions<HrmEmployeeContractApi.EmployeeContract>, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Page auto-content-height> |
| | | <FormModal @success="handleRefresh" /> |
| | | <TerminateModal @success="handleRefresh" /> |
| | | <Grid table-title="åå·¥ååå表"> |
| | | <template #parentNo="{ row }"> |
| | | <span>{{ row.parentNo || '-' }}</span> |
| | | </template> |
| | | <template #isCurrent="{ row }"> |
| | | <Tag v-if="row.isCurrent" color="processing">å½å</Tag> |
| | | <span v-else>-</span> |
| | | </template> |
| | | <template #toolbar-tools> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('ui.actionTitle.create', ['åå·¥åå']), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['hrm:employee-contract:create'], |
| | | onClick: handleCreate, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: 'ç»ç¾', |
| | | type: 'link', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['hrm:employee-contract:create'], |
| | | ifShow: isTerminable(row), |
| | | onClick: handleRenew.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.edit'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['hrm:employee-contract:update'], |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | | label: 'è§£é¤/ç»æ¢', |
| | | type: 'link', |
| | | icon: ACTION_ICON.CLOSE, |
| | | auth: ['hrm:employee-contract:update'], |
| | | ifShow: isTerminable(row), |
| | | onClick: handleTerminate.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['hrm:employee-contract:delete'], |
| | | popConfirm: { |
| | | title: $t('ui.actionMessage.deleteConfirm', ['åå·¥åå']), |
| | | confirm: handleDelete.bind(null, row), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | </Page> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { FormType } from '../data'; |
| | | import type { HrmEmployeeContractApi } from '#/api/hrm/employee/contract'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '#/packages/effects/common-ui/src'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { |
| | | createEmployeeContract, |
| | | getEmployeeContract, |
| | | updateEmployeeContract, |
| | | } from '#/api/hrm/employee/contract'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useFormSchema } from '../data'; |
| | | |
| | | const emit = defineEmits(['success']); |
| | | const formType = ref<FormType>('create'); |
| | | const isRenew = ref(false); |
| | | |
| | | const getTitle = computed(() => { |
| | | if (formType.value === 'update') { |
| | | return 'ä¿®æ¹åå·¥åå'; |
| | | } |
| | | return isRenew.value ? 'ç»ç¾åå·¥åå' : 'æ°å¢åå·¥åå'; |
| | | }); |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: 'w-full', |
| | | }, |
| | | formItemClass: 'col-span-1', |
| | | labelWidth: 100, |
| | | }, |
| | | wrapperClass: 'grid-cols-2', |
| | | layout: 'horizontal', |
| | | schema: useFormSchema(), |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | const data = |
| | | (await formApi.getValues()) as HrmEmployeeContractApi.EmployeeContract; |
| | | try { |
| | | // FileUpload ç»ä»¶çå¼é转æ¢ä¸º blobId æ°ç»æäº¤ |
| | | data.blobIds = (data.blobIds ?? []).map((item: any) => item.id ?? item); |
| | | if (data.id) { |
| | | await updateEmployeeContract(data); |
| | | } else { |
| | | await createEmployeeContract(data); |
| | | } |
| | | await modalApi.close(); |
| | | emit('success'); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | return; |
| | | } |
| | | const data = modalApi.getData<{ |
| | | formType: FormType; |
| | | id?: number; |
| | | renewFrom?: HrmEmployeeContractApi.EmployeeContract; |
| | | }>(); |
| | | formType.value = data.formType; |
| | | isRenew.value = !data?.id && !!data?.renewFrom; |
| | | // ç»ç¾ï¼å¸¦å
¥ä¸ä»½ååçåºç¡ä¿¡æ¯ï¼åå·¥ãç±»åãç¾çº¦ä¸»ä½ãå·¥èµãç»ç¾æ¥æºï¼ï¼æ¥æééæ°å¡«å |
| | | if (data?.renewFrom) { |
| | | await formApi.resetForm(); |
| | | await formApi.setValues({ |
| | | parentId: data.renewFrom.id, |
| | | employeeId: data.renewFrom.employeeId, |
| | | contractType: data.renewFrom.contractType, |
| | | contractTermType: data.renewFrom.contractTermType, |
| | | signCompany: data.renewFrom.signCompany, |
| | | probationSalary: data.renewFrom.probationSalary, |
| | | regularSalary: data.renewFrom.regularSalary, |
| | | }); |
| | | return; |
| | | } |
| | | if (!data?.id) { |
| | | await formApi.resetForm(); |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | try { |
| | | const detail = await getEmployeeContract(data.id); |
| | | await formApi.setValues(detail); |
| | | if (detail.attachmentList?.length) { |
| | | await formApi.setFieldValue( |
| | | 'blobIds', |
| | | detail.attachmentList.map((item) => ({ |
| | | uid: String(item.id), |
| | | name: item.name || '', |
| | | url: item.url || '', |
| | | status: 'done', |
| | | id: item.id, |
| | | })), |
| | | ); |
| | | } |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal :title="getTitle" class="w-[720px]"> |
| | | <Form class="mx-4" /> |
| | | </Modal> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VbenFormSchema } from '#/adapter/form'; |
| | | |
| | | import { ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '#/packages/effects/common-ui/src'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { terminateEmployeeContract } from '#/api/hrm/employee/contract'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | const emit = defineEmits(['success']); |
| | | const contractId = ref<number>(); |
| | | |
| | | /** è§£é¤/ç»æ¢è¡¨å */ |
| | | const schema: VbenFormSchema[] = [ |
| | | { |
| | | fieldName: 'terminateStatus', |
| | | label: 'æä½ç±»å', |
| | | component: 'RadioGroup', |
| | | componentProps: { |
| | | options: [ |
| | | { label: 'è§£é¤', value: 1 }, |
| | | { label: 'ç»æ¢', value: 2 }, |
| | | ], |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'terminateDate', |
| | | label: 'è§£é¤/ç»æ¢æ¥æ', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | placeholder: 'è¯·éæ©æ¥æ', |
| | | valueFormat: 'YYYY-MM-DD', |
| | | style: { width: '100%' }, |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'terminateReason', |
| | | label: 'åå ', |
| | | component: 'Textarea', |
| | | formItemClass: 'col-span-2', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥è§£é¤/ç»æ¢åå ', |
| | | rows: 3, |
| | | maxlength: 255, |
| | | showCount: true, |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | ]; |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: 'w-full', |
| | | }, |
| | | formItemClass: 'col-span-1', |
| | | labelWidth: 110, |
| | | }, |
| | | wrapperClass: 'grid-cols-2', |
| | | layout: 'horizontal', |
| | | schema, |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | const data = await formApi.getValues(); |
| | | try { |
| | | await terminateEmployeeContract({ id: contractId.value!, ...data }); |
| | | await modalApi.close(); |
| | | emit('success'); |
| | | message.success($t('ui.actionMessage.operationSuccess')); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | return; |
| | | } |
| | | const data = modalApi.getData<{ id: number }>(); |
| | | contractId.value = data.id; |
| | | await formApi.resetForm(); |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal title="è§£é¤/ç»æ¢åå" class="w-[520px]"> |
| | | <Form class="mx-4" /> |
| | | </Modal> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { HrmEmployeeContractApi } from '#/api/hrm/employee/contract'; |
| | | |
| | | import { ref, watch } from 'vue'; |
| | | |
| | | import { Table, Tag } from 'ant-design-vue'; |
| | | |
| | | import { getEmployeeContractPage } from '#/api/hrm/employee/contract'; |
| | | import { DICT_TYPE } from '#/packages/constants/src'; |
| | | import { getDictLabel } from '#/packages/effects/hooks/src'; |
| | | |
| | | const props = defineProps<{ |
| | | employeeId?: number; |
| | | }>(); |
| | | |
| | | const list = ref<HrmEmployeeContractApi.EmployeeContract[]>([]); |
| | | const loading = ref(false); |
| | | |
| | | /** ååç¶æé¢è²ï¼1-å¾
çæ 2-çæä¸ 3-å³å°å°æ 4-已尿 5-å·²è§£é¤ 6-å·²ç»æ¢ */ |
| | | const statusColorMap: Record<number, string> = { |
| | | 1: 'processing', |
| | | 2: 'success', |
| | | 3: 'warning', |
| | | 4: 'default', |
| | | 5: 'error', |
| | | 6: 'error', |
| | | }; |
| | | |
| | | /** å·æ°å表 */ |
| | | async function handleRefresh() { |
| | | if (!props.employeeId) return; |
| | | loading.value = true; |
| | | try { |
| | | const res = await getEmployeeContractPage({ |
| | | pageNo: 1, |
| | | pageSize: 100, |
| | | employeeId: props.employeeId, |
| | | }); |
| | | list.value = res.list; |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | } |
| | | |
| | | /** çå¬ employeeId åå */ |
| | | watch( |
| | | () => props.employeeId, |
| | | (val) => { |
| | | if (val) { |
| | | handleRefresh(); |
| | | } |
| | | }, |
| | | { immediate: true }, |
| | | ); |
| | | |
| | | const columns = [ |
| | | { title: 'ååç¼å·', dataIndex: 'contractNo', width: 150 }, |
| | | { title: 'ç»ç¾èª', dataIndex: 'parentNo', width: 130, key: 'parentNo' }, |
| | | { title: 'ååç±»å', dataIndex: 'contractType', width: 100, key: 'contractType' }, |
| | | { title: 'æéç±»å', dataIndex: 'contractTermType', width: 110, key: 'contractTermType' }, |
| | | { title: 'ç¾è®¢æ¥æ', dataIndex: 'signDate', width: 110 }, |
| | | { title: 'å¼å§æ¥æ', dataIndex: 'startDate', width: 110 }, |
| | | { title: 'ç»ææ¥æ', dataIndex: 'endDate', width: 110 }, |
| | | { title: 'ååç¶æ', dataIndex: 'status', width: 100, key: 'status' }, |
| | | { title: 'å½ååå', dataIndex: 'isCurrent', width: 90, key: 'isCurrent' }, |
| | | ]; |
| | | </script> |
| | | |
| | | <template> |
| | | <div class="contract-list"> |
| | | <Table |
| | | :columns="columns" |
| | | :data-source="list" |
| | | :loading="loading" |
| | | :pagination="false" |
| | | size="small" |
| | | row-key="id" |
| | | > |
| | | <template #bodyCell="{ column, record }"> |
| | | <template v-if="column.key === 'parentNo'"> |
| | | {{ record.parentNo || '-' }} |
| | | </template> |
| | | <template v-else-if="column.key === 'contractType'"> |
| | | {{ getDictLabel(DICT_TYPE.HRM_CONTRACT_TYPE, record.contractType) }} |
| | | </template> |
| | | <template v-else-if="column.key === 'contractTermType'"> |
| | | {{ getDictLabel(DICT_TYPE.HRM_CONTRACT_TERM_TYPE, record.contractTermType) }} |
| | | </template> |
| | | <template v-else-if="column.key === 'status'"> |
| | | <Tag :color="statusColorMap[record.status!] || 'default'"> |
| | | {{ getDictLabel(DICT_TYPE.HRM_CONTRACT_STATUS, record.status) }} |
| | | </Tag> |
| | | </template> |
| | | <template v-else-if="column.key === 'isCurrent'"> |
| | | <Tag v-if="record.isCurrent" color="processing">å½å</Tag> |
| | | <span v-else>-</span> |
| | | </template> |
| | | </template> |
| | | </Table> |
| | | </div> |
| | | </template> |
| | | |
| | | <style scoped> |
| | | .contract-list { |
| | | padding: 0; |
| | | } |
| | | </style> |
| | |
| | | import WorkHistoryList from './work-history-list.vue'; |
| | | import EmergencyContactList from './emergency-contact-list.vue'; |
| | | import SocialSecurityList from './social-security-list.vue'; |
| | | import ContractList from './contract-list.vue'; |
| | | |
| | | const props = defineProps<{ |
| | | employee: HrmEmployeeApi.Employee; |
| | |
| | | <Tabs.TabPane key="socialSecurity" tab="社ä¿å
¬ç§¯éæ¡£æ¡"> |
| | | <SocialSecurityList form-type="detail" :employee-id="employee.id" :user-id="employee.userId" /> |
| | | </Tabs.TabPane> |
| | | <Tabs.TabPane key="contract" tab="åå·¥åå"> |
| | | <ContractList :employee-id="employee.id" /> |
| | | </Tabs.TabPane> |
| | | </Tabs> |
| | | </div> |
| | | </template> |