feat(bpm): 添加业务附件配置功能
- 在 package.json 中添加 cross-env 和 vue-tsc 依赖
- 更新 pnpm-lock.yaml 以同步依赖变更
- 新增业务附件配置的数据结构定义文件 data.ts
- 创建业务附件配置的表单组件 modules/form.vue
- 实现业务附件配置的 API 接口 index.ts
- 开发业务附件配置的主页面 index.vue
- 添加 CRM 合同、发票、回款的审批详情页面
- 添加 ERP 财务付款的审批详情页面
| | |
| | | "@vben/tailwind-config": "workspace:*", |
| | | "@vben/tsconfig": "workspace:*", |
| | | "@vben/vite-config": "workspace:*", |
| | | "cross-env": "catalog:", |
| | | "jiti": "^2.7.0", |
| | | "tsdown": "^0.22.3", |
| | | "tsx": "^4.22.4", |
| | | "typescript": "catalog:", |
| | | "vite": "catalog:" |
| | | "vite": "catalog:", |
| | | "vue-tsc": "catalog:" |
| | | }, |
| | | "packageManager": "pnpm@11.0.9+sha512.34ce82e6780233cf9cad8685029a8f81d2e06196c5a9bad98879f7424940c6817c4e4524fb7d38b8553ceed48b9758b8ebaf1abd3600c232c4c8cf7366086f38" |
| | | } |
| | |
| | | cropperjs: |
| | | specifier: ^1.6.2 |
| | | version: 1.6.2 |
| | | cross-env: |
| | | specifier: ^10.1.0 |
| | | version: 10.1.0 |
| | | crypto-js: |
| | | specifier: ^4.2.0 |
| | | version: 4.2.0 |
| | |
| | | vue-tippy: |
| | | specifier: ^6.7.1 |
| | | version: 6.7.1 |
| | | vue-tsc: |
| | | specifier: ^3.3.9 |
| | | version: 3.3.9 |
| | | vue3-print-nb: |
| | | specifier: ^0.1.4 |
| | | version: 0.1.4 |
| | |
| | | '@vben/vite-config': |
| | | specifier: workspace:* |
| | | version: link:internal/vite-config |
| | | cross-env: |
| | | specifier: 'catalog:' |
| | | version: 10.1.0 |
| | | jiti: |
| | | specifier: ^2.7.0 |
| | | version: 2.7.0 |
| | | tsdown: |
| | | specifier: ^0.22.3 |
| | | version: 0.22.3(tsx@4.22.4)(typescript@6.0.3)(unrun@0.3.1(synckit@0.11.13)) |
| | | version: 0.22.3(tsx@4.22.4)(typescript@6.0.3)(unrun@0.3.1(synckit@0.11.13))(vue-tsc@3.3.9(typescript@6.0.3)) |
| | | tsx: |
| | | specifier: ^4.22.4 |
| | | version: 4.22.4 |
| | |
| | | vite: |
| | | specifier: 'catalog:' |
| | | version: 8.0.10(@types/node@25.9.4)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.101.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0) |
| | | vue-tsc: |
| | | specifier: 'catalog:' |
| | | version: 3.3.9(typescript@6.0.3) |
| | | |
| | | internal/lint-configs/commitlint-config: |
| | | dependencies: |
| | |
| | | |
| | | '@emotion/unitless@0.8.1': |
| | | resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==} |
| | | |
| | | '@epic-web/invariant@1.0.0': |
| | | resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} |
| | | |
| | | '@es-joy/jsdoccomment@0.84.0': |
| | | resolution: {integrity: sha512-0xew1CxOam0gV5OMjh2KjFQZsKL2bByX1+q4j3E73MpYIdyUxcZb/xQct9ccUb+ve5KGUYbCUxyPnYB7RbuP+w==} |
| | |
| | | '@vue/devtools-shared@8.1.3': |
| | | resolution: {integrity: sha512-CM3uIPL+v+lrJUk33+pxspYo0MhuMWlCvf7zC9fybifvCPyM2jUbYRPwoYEJgYbwRqPikm5HozbUhp60MF2QuA==} |
| | | |
| | | '@vue/language-core@3.3.9': |
| | | resolution: {integrity: sha512-in/68oAa4BCtVY6n/nkuhLIkV8DHYd2UivedJ6cMZ6UYtlq9jaoaSNUBHYCVO44z3nKg7MdE5OBoHKt5SxeBKQ==} |
| | | |
| | | '@vue/reactivity@3.5.38': |
| | | resolution: {integrity: sha512-pG6LV/NDNRbKizcUjFFLAfjaL8mcv4DmR9avNcUw2gDHBzZneuS2TWCmp633ynzxz9YYKNeEPK2I8Wraqy2HUQ==} |
| | | |
| | |
| | | |
| | | ajv@8.20.0: |
| | | resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} |
| | | |
| | | alien-signals@3.2.1: |
| | | resolution: {integrity: sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==} |
| | | |
| | | ansi-regex@5.0.1: |
| | | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} |
| | |
| | | |
| | | cropperjs@1.6.2: |
| | | resolution: {integrity: sha512-nhymn9GdnV3CqiEHJVai54TULFAE3VshJTXSqSJKa8yXAKyBKDWdhHarnlIPrshJ0WMFTGuFvG02YjLXfPiuOA==} |
| | | |
| | | cross-env@10.1.0: |
| | | resolution: {integrity: sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==} |
| | | engines: {node: '>=20'} |
| | | hasBin: true |
| | | |
| | | cross-spawn@7.0.6: |
| | | resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} |
| | |
| | | peerDependencies: |
| | | vue: ^3.2.0 |
| | | |
| | | vue-tsc@3.3.9: |
| | | resolution: {integrity: sha512-TS3Y1ux/IRoE8OCP2PpACAeOseuIs0UvWrcr7u+w3PmfY+SlCfEf8zjrBgnQksHUgLpthi5vHlffcQTQTdPBZA==} |
| | | hasBin: true |
| | | peerDependencies: |
| | | typescript: '>=5.0.0' |
| | | |
| | | vue-types@3.0.0: |
| | | resolution: {integrity: sha512-xzq2D7zLGbzn3bPQ0CWWYx4W78JWdGYZAFfRkzxz1aTm9DaNoH0qxYDiLXBofBEQ5X78l32uIq/G9INQ2E8X/Q==} |
| | | engines: {node: '>=10.15.0'} |
| | |
| | | '@emotion/hash@0.9.2': {} |
| | | |
| | | '@emotion/unitless@0.8.1': {} |
| | | |
| | | '@epic-web/invariant@1.0.0': {} |
| | | |
| | | '@es-joy/jsdoccomment@0.84.0': |
| | | dependencies: |
| | |
| | | |
| | | '@vue/devtools-shared@8.1.3': {} |
| | | |
| | | '@vue/language-core@3.3.9': |
| | | dependencies: |
| | | '@volar/language-core': 2.4.28 |
| | | '@vue/compiler-dom': 3.5.38 |
| | | '@vue/shared': 3.5.38 |
| | | alien-signals: 3.2.1 |
| | | muggle-string: 0.4.1 |
| | | path-browserify: 1.0.1 |
| | | picomatch: 4.0.4 |
| | | |
| | | '@vue/reactivity@3.5.38': |
| | | dependencies: |
| | | '@vue/shared': 3.5.38 |
| | |
| | | fast-uri: 3.1.2 |
| | | json-schema-traverse: 1.0.0 |
| | | require-from-string: 2.0.2 |
| | | |
| | | alien-signals@3.2.1: {} |
| | | |
| | | ansi-regex@5.0.1: {} |
| | | |
| | |
| | | croner@10.0.1: {} |
| | | |
| | | cropperjs@1.6.2: {} |
| | | |
| | | cross-env@10.1.0: |
| | | dependencies: |
| | | '@epic-web/invariant': 1.0.0 |
| | | cross-spawn: 7.0.6 |
| | | |
| | | cross-spawn@7.0.6: |
| | | dependencies: |
| | |
| | | |
| | | robust-predicates@3.0.3: {} |
| | | |
| | | rolldown-plugin-dts@0.26.0(rolldown@1.1.2)(typescript@6.0.3): |
| | | rolldown-plugin-dts@0.26.0(rolldown@1.1.2)(typescript@6.0.3)(vue-tsc@3.3.9(typescript@6.0.3)): |
| | | dependencies: |
| | | '@babel/generator': 8.0.0 |
| | | '@babel/helper-validator-identifier': 8.0.2 |
| | |
| | | rolldown: 1.1.2 |
| | | optionalDependencies: |
| | | typescript: 6.0.3 |
| | | vue-tsc: 3.3.9(typescript@6.0.3) |
| | | transitivePeerDependencies: |
| | | - oxc-resolver |
| | | |
| | |
| | | minimist: 1.2.8 |
| | | strip-bom: 3.0.0 |
| | | |
| | | tsdown@0.22.3(tsx@4.22.4)(typescript@6.0.3)(unrun@0.3.1(synckit@0.11.13)): |
| | | tsdown@0.22.3(tsx@4.22.4)(typescript@6.0.3)(unrun@0.3.1(synckit@0.11.13))(vue-tsc@3.3.9(typescript@6.0.3)): |
| | | dependencies: |
| | | ansis: 4.3.1 |
| | | cac: 7.0.0 |
| | |
| | | obug: 2.1.3 |
| | | picomatch: 4.0.4 |
| | | rolldown: 1.1.2 |
| | | rolldown-plugin-dts: 0.26.0(rolldown@1.1.2)(typescript@6.0.3) |
| | | rolldown-plugin-dts: 0.26.0(rolldown@1.1.2)(typescript@6.0.3)(vue-tsc@3.3.9(typescript@6.0.3)) |
| | | semver: 7.8.5 |
| | | tinyexec: 1.2.4 |
| | | tinyglobby: 0.2.17 |
| | |
| | | tippy.js: 6.3.7 |
| | | vue: 3.5.38(typescript@6.0.3) |
| | | |
| | | vue-tsc@3.3.9(typescript@6.0.3): |
| | | dependencies: |
| | | '@volar/typescript': 2.4.28 |
| | | '@vue/language-core': 3.3.9 |
| | | typescript: 6.0.3 |
| | | |
| | | vue-types@3.0.0(vue@3.5.38(typescript@6.0.3)): |
| | | dependencies: |
| | | is-plain-object: 3.0.1 |
| | |
| | | vue-json-pretty: ^2.6.0 |
| | | vue-router: ^5.1.0 |
| | | vue-tippy: ^6.7.1 |
| | | vue-tsc: ^3.3.3 |
| | | vue-tsc: ^3.3.9 |
| | | vue3-print-nb: ^0.1.4 |
| | | vue3-signature: ^0.4.4 |
| | | vuedraggable: ^4.1.0 |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { PageParam, PageResult } from '@vben/request'; |
| | | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace BpmBusinessAttachApi { |
| | | /** ä¸å¡éä»¶é
ç½® */ |
| | | export interface BusinessAttach { |
| | | id: number; |
| | | processDefinitionKey: string; |
| | | businessType?: string; |
| | | componentPath: string; |
| | | status: number; |
| | | remark?: string; |
| | | createTime?: string; |
| | | } |
| | | } |
| | | |
| | | /** æ¥è¯¢ä¸å¡éä»¶é
ç½®å页 */ |
| | | export async function getBusinessAttachPage(params: PageParam) { |
| | | return requestClient.get<PageResult<BpmBusinessAttachApi.BusinessAttach>>( |
| | | '/bpm/business-attach/page', |
| | | { params }, |
| | | ); |
| | | } |
| | | |
| | | /** æ¥è¯¢ä¸å¡éä»¶é
置详æ
*/ |
| | | export async function getBusinessAttach(id: number) { |
| | | return requestClient.get<BpmBusinessAttachApi.BusinessAttach>( |
| | | `/bpm/business-attach/get?id=${id}`, |
| | | ); |
| | | } |
| | | |
| | | /** æ°å¢ä¸å¡éä»¶é
ç½® */ |
| | | export async function createBusinessAttach( |
| | | data: BpmBusinessAttachApi.BusinessAttach, |
| | | ) { |
| | | return requestClient.post<number>('/bpm/business-attach/create', data); |
| | | } |
| | | |
| | | /** ä¿®æ¹ä¸å¡éä»¶é
ç½® */ |
| | | export async function updateBusinessAttach( |
| | | data: BpmBusinessAttachApi.BusinessAttach, |
| | | ) { |
| | | return requestClient.put<boolean>('/bpm/business-attach/update', data); |
| | | } |
| | | |
| | | /** å é¤ä¸å¡éä»¶é
ç½® */ |
| | | export async function deleteBusinessAttach(id: number) { |
| | | return requestClient.delete<boolean>( |
| | | `/bpm/business-attach/delete?id=${id}`, |
| | | ); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | |
| | | import { CommonStatusEnum, DICT_TYPE } from '@vben/constants'; |
| | | import { getDictOptions } from '@vben/hooks'; |
| | | |
| | | import { z } from '#/adapter/form'; |
| | | import { getRangePickerDefaultProps } from '#/utils'; |
| | | |
| | | /** æ°å¢/ä¿®æ¹ç表å */ |
| | | export function useFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'id', |
| | | component: 'Input', |
| | | dependencies: { |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'processDefinitionKey', |
| | | label: 'æµç¨å®ä¹ Key', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥æµç¨å®ä¹ Keyï¼å¦ purchase_approve', |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'businessType', |
| | | label: 'ä¸å¡ç±»å', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥ä¸å¡ç±»åï¼å¦ erp_purchase_order', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'componentPath', |
| | | label: 'ä¸å¡è¯¦æ
ç»ä»¶è·¯å¾', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: |
| | | '请è¾å
¥ä¸å¡è¯¦æ
ç»ä»¶è·¯å¾ï¼å¦ /erp/purchase/order/detail/index.vue', |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'status', |
| | | label: 'ç¶æ', |
| | | component: 'RadioGroup', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), |
| | | buttonStyle: 'solid', |
| | | optionType: 'button', |
| | | }, |
| | | rules: z.number().default(CommonStatusEnum.ENABLE), |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | component: 'Textarea', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥å¤æ³¨', |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çæç´¢è¡¨å */ |
| | | export function useGridFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'processDefinitionKey', |
| | | label: 'æµç¨å®ä¹ Key', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥æµç¨å®ä¹ Key', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'businessType', |
| | | label: 'ä¸å¡ç±»å', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请è¾å
¥ä¸å¡ç±»å', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'status', |
| | | label: 'ç¶æ', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), |
| | | placeholder: 'è¯·éæ©ç¶æ', |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'createTime', |
| | | label: 'å建æ¶é´', |
| | | component: 'RangePicker', |
| | | componentProps: { |
| | | ...getRangePickerDefaultProps(), |
| | | allowClear: true, |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çåæ®µ */ |
| | | export function useGridColumns(): VxeTableGridOptions['columns'] { |
| | | return [ |
| | | { |
| | | field: 'id', |
| | | title: 'ç¼å·', |
| | | minWidth: 80, |
| | | }, |
| | | { |
| | | field: 'processDefinitionKey', |
| | | title: 'æµç¨å®ä¹ Key', |
| | | minWidth: 180, |
| | | }, |
| | | { |
| | | field: 'businessType', |
| | | title: 'ä¸å¡ç±»å', |
| | | minWidth: 160, |
| | | }, |
| | | { |
| | | field: 'componentPath', |
| | | title: 'ä¸å¡è¯¦æ
ç»ä»¶è·¯å¾', |
| | | minWidth: 260, |
| | | }, |
| | | { |
| | | field: 'status', |
| | | title: 'ç¶æ', |
| | | minWidth: 80, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.COMMON_STATUS }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'remark', |
| | | title: '夿³¨', |
| | | minWidth: 160, |
| | | }, |
| | | { |
| | | field: 'createTime', |
| | | title: 'å建æ¶é´', |
| | | minWidth: 180, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | width: 160, |
| | | fixed: 'right', |
| | | slots: { default: 'actions' }, |
| | | }, |
| | | ]; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { BpmBusinessAttachApi } from '#/api/bpm/businessAttach'; |
| | | |
| | | import { Page, useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | deleteBusinessAttach, |
| | | getBusinessAttachPage, |
| | | } from '#/api/bpm/businessAttach'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useGridColumns, useGridFormSchema } from './data'; |
| | | import Form from './modules/form.vue'; |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | /** å·æ°è¡¨æ ¼ */ |
| | | function handleRefresh() { |
| | | gridApi.query(); |
| | | } |
| | | |
| | | /** å建ä¸å¡éä»¶é
ç½® */ |
| | | function handleCreate() { |
| | | formModalApi.setData(null).open(); |
| | | } |
| | | |
| | | /** ç¼è¾ä¸å¡éä»¶é
ç½® */ |
| | | function handleEdit(row: BpmBusinessAttachApi.BusinessAttach) { |
| | | formModalApi.setData(row).open(); |
| | | } |
| | | |
| | | /** å é¤ä¸å¡éä»¶é
ç½® */ |
| | | async function handleDelete(row: BpmBusinessAttachApi.BusinessAttach) { |
| | | const hideLoading = message.loading({ |
| | | content: $t('ui.actionMessage.deleting', [row.processDefinitionKey]), |
| | | duration: 0, |
| | | }); |
| | | try { |
| | | await deleteBusinessAttach(row.id as number); |
| | | message.success($t('ui.actionMessage.deleteSuccess')); |
| | | handleRefresh(); |
| | | } finally { |
| | | hideLoading(); |
| | | } |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | formOptions: { |
| | | schema: useGridFormSchema(), |
| | | }, |
| | | gridOptions: { |
| | | columns: useGridColumns(), |
| | | height: 'auto', |
| | | keepSource: true, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => { |
| | | return await getBusinessAttachPage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | }); |
| | | }, |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | search: true, |
| | | }, |
| | | } as VxeTableGridOptions<BpmBusinessAttachApi.BusinessAttach>, |
| | | }); |
| | | </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: ['bpm:business-attach:create'], |
| | | onClick: handleCreate, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: $t('common.edit'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['bpm:business-attach:update'], |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | | label: $t('common.delete'), |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['bpm:business-attach:delete'], |
| | | popConfirm: { |
| | | title: $t('ui.actionMessage.deleteConfirm', [ |
| | | row.processDefinitionKey, |
| | | ]), |
| | | confirm: handleDelete.bind(null, row), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | </Page> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { BpmBusinessAttachApi } from '#/api/bpm/businessAttach'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { |
| | | createBusinessAttach, |
| | | getBusinessAttach, |
| | | updateBusinessAttach, |
| | | } from '#/api/bpm/businessAttach'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useFormSchema } from '../data'; |
| | | |
| | | const emit = defineEmits(['success']); |
| | | const formData = ref<BpmBusinessAttachApi.BusinessAttach>(); |
| | | const getTitle = computed(() => { |
| | | return formData.value?.id |
| | | ? $t('ui.actionTitle.edit', ['ä¸å¡éä»¶é
ç½®']) |
| | | : $t('ui.actionTitle.create', ['ä¸å¡éä»¶é
ç½®']); |
| | | }); |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: 'w-full', |
| | | }, |
| | | formItemClass: 'col-span-2', |
| | | labelWidth: 140, |
| | | }, |
| | | 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 BpmBusinessAttachApi.BusinessAttach; |
| | | try { |
| | | await (formData.value?.id |
| | | ? updateBusinessAttach(data) |
| | | : createBusinessAttach(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<BpmBusinessAttachApi.BusinessAttach>(); |
| | | if (!data || !data.id) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | try { |
| | | formData.value = await getBusinessAttach(data.id); |
| | | // è®¾ç½®å° values |
| | | await formApi.setValues(formData.value); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal :title="getTitle" class="w-2/3"> |
| | | <Form class="mx-4" /> |
| | | </Modal> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { CrmContractApi } from '#/api/crm/contract'; |
| | | import type { DescriptionItemSchema } from '#/components/description'; |
| | | |
| | | import { h, nextTick, onMounted, ref } from 'vue'; |
| | | |
| | | import { ContentWrap } from '@vben/common-ui'; |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { |
| | | erpCountInputFormatter, |
| | | erpPriceInputFormatter, |
| | | formatDateTime, |
| | | } from '@vben/utils'; |
| | | |
| | | import { Spin } from 'ant-design-vue'; |
| | | |
| | | import { useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { getContract } from '#/api/crm/contract'; |
| | | import { DictTag } from '#/components/dict-tag'; |
| | | import { useDescription } from '#/components/description'; |
| | | |
| | | defineOptions({ name: 'CrmContractApproveDetail' }); |
| | | |
| | | const props = defineProps<{ id: string }>(); |
| | | |
| | | const loading = ref(false); |
| | | const formData = ref<CrmContractApi.Contract>(); |
| | | |
| | | /** ææ¬åæ®µç©ºå¼å ä½ */ |
| | | function textRender(val: unknown) { |
| | | return val === 0 || val ? String(val) : '-'; |
| | | } |
| | | |
| | | /** åå产åæç»ï¼å®¡æ¹è¯¦æ
åªè¯»åï¼ */ |
| | | function useProductColumns(): VxeTableGridOptions['columns'] { |
| | | return [ |
| | | { type: 'seq', title: 'åºå·', width: 60 }, |
| | | { field: 'itemName', title: '产ååç§°', minWidth: 180 }, |
| | | { field: 'itemCode', title: 'ç©æç¼ç ', minWidth: 120 }, |
| | | { field: 'itemUnitName', title: 'åä½', minWidth: 80, formatter: ({ cellValue }) => textRender(cellValue) }, |
| | | { |
| | | field: 'contractPrice', |
| | | title: 'ååä»·æ ¼ï¼å
ï¼', |
| | | minWidth: 120, |
| | | formatter: ({ cellValue }) => erpPriceInputFormatter(cellValue) || '-', |
| | | }, |
| | | { |
| | | field: 'count', |
| | | title: 'æ°é', |
| | | minWidth: 100, |
| | | formatter: ({ cellValue }) => erpCountInputFormatter(cellValue) || '-', |
| | | }, |
| | | { |
| | | field: 'totalPrice', |
| | | title: 'å计éé¢ï¼å
ï¼', |
| | | minWidth: 120, |
| | | formatter: ({ cellValue }) => erpPriceInputFormatter(cellValue) || '-', |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | gridOptions: { |
| | | columns: useProductColumns(), |
| | | data: [], |
| | | minHeight: 200, |
| | | autoResize: true, |
| | | border: true, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | pagerConfig: { |
| | | enabled: false, |
| | | }, |
| | | toolbarConfig: { |
| | | enabled: false, |
| | | }, |
| | | }, |
| | | }); |
| | | |
| | | const [Descriptions] = useDescription({ |
| | | bordered: true, |
| | | column: 2, |
| | | schema: [ |
| | | { label: 'ååç¼å·', field: 'no', render: textRender }, |
| | | { label: 'åååç§°', field: 'name', render: textRender }, |
| | | { label: '客æ·åç§°', field: 'customerName', render: textRender }, |
| | | { label: 'åæºåç§°', field: 'businessName', render: textRender }, |
| | | { |
| | | label: 'ååéé¢ï¼å
ï¼', |
| | | field: 'totalPrice', |
| | | render: (val) => erpPriceInputFormatter(val) || '-', |
| | | }, |
| | | { |
| | | label: 'å®ééé¢ï¼å
ï¼', |
| | | field: 'depositPrice', |
| | | render: (val) => erpPriceInputFormatter(val) || '-', |
| | | }, |
| | | { |
| | | label: '忬¾éé¢ï¼å
ï¼', |
| | | field: 'totalReceivablePrice', |
| | | render: (val) => erpPriceInputFormatter(val) || '-', |
| | | }, |
| | | { |
| | | label: 'å·²å¼ç¥¨éé¢ï¼å
ï¼', |
| | | field: 'totalInvoicePrice', |
| | | render: (val) => erpPriceInputFormatter(val) || '-', |
| | | }, |
| | | { |
| | | label: 'æªå¼ç¥¨éé¢ï¼å
ï¼', |
| | | field: 'unInvoicePrice', |
| | | render: (val) => erpPriceInputFormatter(val) || '-', |
| | | }, |
| | | { |
| | | label: 'ä¸åæ¶é´', |
| | | field: 'orderDate', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { |
| | | label: 'ååå¼å§æ¶é´', |
| | | field: 'startTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { |
| | | label: 'ååç»ææ¶é´', |
| | | field: 'endTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { label: '客æ·ç¾çº¦äºº', field: 'signContactName', render: textRender }, |
| | | { label: 'å
¬å¸ç¾çº¦äºº', field: 'signUserName', render: textRender }, |
| | | { label: 'éå®è®¢å', field: 'orderNo', render: textRender }, |
| | | { label: 'å建人', field: 'creatorName', render: textRender }, |
| | | { |
| | | label: 'å建æ¶é´', |
| | | field: 'createTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { |
| | | label: 'ååç¶æ', |
| | | field: 'auditStatus', |
| | | render: (val) => |
| | | h(DictTag, { type: DICT_TYPE.CRM_AUDIT_STATUS, value: val }), |
| | | }, |
| | | { label: '夿³¨', field: 'remark', render: textRender }, |
| | | ] as DescriptionItemSchema[], |
| | | }); |
| | | |
| | | onMounted(async () => { |
| | | try { |
| | | loading.value = true; |
| | | formData.value = await getContract(Number(props.id)); |
| | | if (formData.value?.products?.length) { |
| | | await nextTick(); |
| | | await gridApi.grid.reloadData(formData.value.products); |
| | | } |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <ContentWrap class="m-2"> |
| | | <Spin :spinning="loading" tip="å è½½ä¸..."> |
| | | <div class="space-y-4"> |
| | | <!-- åååºæ¬ä¿¡æ¯ --> |
| | | <div class="rounded-lg border border-border bg-background p-4"> |
| | | <div class="mb-4 flex items-center gap-2"> |
| | | <span class="inline-block h-4 w-1 rounded bg-primary" /> |
| | | <span class="text-base font-semibold">åååºæ¬ä¿¡æ¯</span> |
| | | </div> |
| | | <Descriptions :data="formData" /> |
| | | </div> |
| | | <!-- 产åæç» --> |
| | | <div |
| | | v-if="formData?.products?.length" |
| | | class="rounded-lg border border-border bg-background p-4" |
| | | > |
| | | <div class="mb-4 flex items-center gap-2"> |
| | | <span class="inline-block h-4 w-1 rounded bg-primary" /> |
| | | <span class="text-base font-semibold">产åæç»</span> |
| | | </div> |
| | | <Grid /> |
| | | </div> |
| | | </div> |
| | | </Spin> |
| | | </ContentWrap> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { CrmInvoiceApi } from '#/api/crm/invoice'; |
| | | import type { DescriptionItemSchema } from '#/components/description'; |
| | | |
| | | import { h, onMounted, ref } from 'vue'; |
| | | |
| | | import { ContentWrap } from '@vben/common-ui'; |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { erpPriceInputFormatter, formatDateTime } from '@vben/utils'; |
| | | |
| | | import { Spin } from 'ant-design-vue'; |
| | | |
| | | import { getInvoice } from '#/api/crm/invoice'; |
| | | import { DictTag } from '#/components/dict-tag'; |
| | | import { useDescription } from '#/components/description'; |
| | | |
| | | defineOptions({ name: 'CrmInvoiceApproveDetail' }); |
| | | |
| | | const props = defineProps<{ id: string }>(); |
| | | |
| | | const loading = ref(false); |
| | | const formData = ref<CrmInvoiceApi.Invoice>(); |
| | | |
| | | /** ææ¬åæ®µç©ºå¼å ä½ */ |
| | | function textRender(val: unknown) { |
| | | return val === 0 || val ? String(val) : '-'; |
| | | } |
| | | |
| | | const [Descriptions] = useDescription({ |
| | | bordered: true, |
| | | column: 2, |
| | | schema: [ |
| | | { label: 'å¼ç¥¨ç¼å·', field: 'no', render: textRender }, |
| | | { label: '客æ·åç§°', field: 'customerName', render: textRender }, |
| | | { |
| | | label: 'ååç¼å·', |
| | | field: 'contract', |
| | | render: (_val, data) => (data?.contract?.no ? data.contract.no : '-'), |
| | | }, |
| | | { |
| | | label: 'å票类å', |
| | | field: 'invoiceType', |
| | | render: (val) => |
| | | h(DictTag, { type: DICT_TYPE.CRM_INVOICE_TYPE, value: val }), |
| | | }, |
| | | { label: 'å票å·ç ', field: 'invoiceNo', render: textRender }, |
| | | { label: 'å票æ¬å¤´', field: 'invoiceTitle', render: textRender }, |
| | | { |
| | | label: 'å¼ç¥¨éé¢ï¼å
ï¼', |
| | | field: 'price', |
| | | render: (val) => erpPriceInputFormatter(val) || '-', |
| | | }, |
| | | { |
| | | label: 'å©ä½å¯å款éé¢ï¼å
ï¼', |
| | | field: 'remainingInvoicePrice', |
| | | render: (val) => erpPriceInputFormatter(val ?? 0) || '-', |
| | | }, |
| | | { |
| | | label: 'å¼ç¥¨æ¥æ', |
| | | field: 'invoiceTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { |
| | | label: '审æ¹ç¶æ', |
| | | field: 'auditStatus', |
| | | render: (val) => |
| | | h(DictTag, { type: DICT_TYPE.CRM_AUDIT_STATUS, value: val }), |
| | | }, |
| | | { label: 'è´è´£äºº', field: 'ownerUserName', render: textRender }, |
| | | { label: 'å建人', field: 'creatorName', render: textRender }, |
| | | { |
| | | label: 'å建æ¶é´', |
| | | field: 'createTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { label: '夿³¨', field: 'remark', render: textRender }, |
| | | ] as DescriptionItemSchema[], |
| | | }); |
| | | |
| | | onMounted(async () => { |
| | | try { |
| | | loading.value = true; |
| | | formData.value = await getInvoice(Number(props.id)); |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <ContentWrap class="m-2"> |
| | | <Spin :spinning="loading" tip="å è½½ä¸..."> |
| | | <div class="space-y-4"> |
| | | <!-- å¼ç¥¨åºæ¬ä¿¡æ¯ --> |
| | | <div class="rounded-lg border border-border bg-background p-4"> |
| | | <div class="mb-4 flex items-center gap-2"> |
| | | <span class="inline-block h-4 w-1 rounded bg-primary" /> |
| | | <span class="text-base font-semibold">å¼ç¥¨åºæ¬ä¿¡æ¯</span> |
| | | </div> |
| | | <Descriptions :data="formData" /> |
| | | </div> |
| | | </div> |
| | | </Spin> |
| | | </ContentWrap> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { CrmReceivableApi } from '#/api/crm/receivable'; |
| | | import type { DescriptionItemSchema } from '#/components/description'; |
| | | |
| | | import { h, onMounted, ref } from 'vue'; |
| | | |
| | | import { ContentWrap } from '@vben/common-ui'; |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { erpPriceInputFormatter, formatDateTime } from '@vben/utils'; |
| | | |
| | | import { Spin } from 'ant-design-vue'; |
| | | |
| | | import { getReceivable } from '#/api/crm/receivable'; |
| | | import { DictTag } from '#/components/dict-tag'; |
| | | import { useDescription } from '#/components/description'; |
| | | |
| | | defineOptions({ name: 'CrmReceivableApproveDetail' }); |
| | | |
| | | const props = defineProps<{ id: string }>(); |
| | | |
| | | const loading = ref(false); |
| | | const formData = ref<CrmReceivableApi.Receivable>(); |
| | | |
| | | /** ææ¬åæ®µç©ºå¼å ä½ */ |
| | | function textRender(val: unknown) { |
| | | return val === 0 || val ? String(val) : '-'; |
| | | } |
| | | |
| | | /** å
³èå¼ç¥¨å±ç¤º */ |
| | | function invoiceRender(_val: unknown, data?: CrmReceivableApi.Receivable) { |
| | | if (!data?.invoice?.no) { |
| | | return '-'; |
| | | } |
| | | return `${data.invoice.no} / ${data.invoice.invoiceNo ?? '-'} / ¥${ |
| | | data.invoice.price ?? 0 |
| | | }`; |
| | | } |
| | | |
| | | const [Descriptions] = useDescription({ |
| | | bordered: true, |
| | | column: 2, |
| | | schema: [ |
| | | { label: '忬¾ç¼å·', field: 'no', render: textRender }, |
| | | { label: '客æ·åç§°', field: 'customerName', render: textRender }, |
| | | { |
| | | label: 'ååç¼å·', |
| | | field: 'contract', |
| | | render: (_val, data) => (data?.contract?.no ? data.contract.no : '-'), |
| | | }, |
| | | { label: 'å
³èå¼ç¥¨', field: 'invoice', render: invoiceRender }, |
| | | { |
| | | label: '忬¾æ¥æ', |
| | | field: 'returnTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { |
| | | label: '忬¾éé¢ï¼å
ï¼', |
| | | field: 'price', |
| | | render: (val) => erpPriceInputFormatter(val) || '-', |
| | | }, |
| | | { |
| | | label: '忬¾æ¹å¼', |
| | | field: 'returnType', |
| | | render: (val) => |
| | | h(DictTag, { |
| | | type: DICT_TYPE.CRM_RECEIVABLE_RETURN_TYPE, |
| | | value: val, |
| | | }), |
| | | }, |
| | | { |
| | | label: '审æ¹ç¶æ', |
| | | field: 'auditStatus', |
| | | render: (val) => |
| | | h(DictTag, { type: DICT_TYPE.CRM_AUDIT_STATUS, value: val }), |
| | | }, |
| | | { label: 'è´è´£äºº', field: 'ownerUserName', render: textRender }, |
| | | { label: 'å建人', field: 'creatorName', render: textRender }, |
| | | { |
| | | label: 'å建æ¶é´', |
| | | field: 'createTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { label: '夿³¨', field: 'remark', render: textRender }, |
| | | ] as DescriptionItemSchema[], |
| | | }); |
| | | |
| | | onMounted(async () => { |
| | | try { |
| | | loading.value = true; |
| | | formData.value = await getReceivable(Number(props.id)); |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <ContentWrap class="m-2"> |
| | | <Spin :spinning="loading" tip="å è½½ä¸..."> |
| | | <div class="space-y-4"> |
| | | <!-- 忬¾åºæ¬ä¿¡æ¯ --> |
| | | <div class="rounded-lg border border-border bg-background p-4"> |
| | | <div class="mb-4 flex items-center gap-2"> |
| | | <span class="inline-block h-4 w-1 rounded bg-primary" /> |
| | | <span class="text-base font-semibold">忬¾åºæ¬ä¿¡æ¯</span> |
| | | </div> |
| | | <Descriptions :data="formData" /> |
| | | </div> |
| | | </div> |
| | | </Spin> |
| | | </ContentWrap> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { ErpFinancePaymentApi } from '#/api/erp/finance/payment'; |
| | | import type { DescriptionItemSchema } from '#/components/description'; |
| | | |
| | | import { h, nextTick, onMounted, ref } from 'vue'; |
| | | |
| | | import { ContentWrap } from '@vben/common-ui'; |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { erpPriceInputFormatter, formatDateTime } from '@vben/utils'; |
| | | |
| | | import { Spin } from 'ant-design-vue'; |
| | | |
| | | import { useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { getFinancePayment } from '#/api/erp/finance/payment'; |
| | | import { DictTag } from '#/components/dict-tag'; |
| | | import { useDescription } from '#/components/description'; |
| | | |
| | | defineOptions({ name: 'ErpFinancePaymentApproveDetail' }); |
| | | |
| | | const props = defineProps<{ id: string }>(); |
| | | |
| | | const loading = ref(false); |
| | | const formData = ref<ErpFinancePaymentApi.FinancePayment>(); |
| | | |
| | | /** ææ¬åæ®µç©ºå¼å ä½ */ |
| | | function textRender(val: unknown) { |
| | | return val === 0 || val ? String(val) : '-'; |
| | | } |
| | | |
| | | /** 仿¬¾æç»ï¼å®¡æ¹è¯¦æ
åªè¯»åï¼ */ |
| | | function usePaymentItemColumns(): VxeTableGridOptions['columns'] { |
| | | return [ |
| | | { type: 'seq', title: 'åºå·', width: 60 }, |
| | | { field: 'bizNo', title: 'æ¥ç¥¨ç¼å·', minWidth: 200 }, |
| | | { |
| | | field: 'totalPrice', |
| | | title: 'åºä»éé¢', |
| | | minWidth: 120, |
| | | formatter: ({ cellValue }) => erpPriceInputFormatter(cellValue) || '-', |
| | | }, |
| | | { |
| | | field: 'paidPrice', |
| | | title: 'å·²ä»éé¢', |
| | | minWidth: 120, |
| | | formatter: ({ cellValue }) => erpPriceInputFormatter(cellValue) || '-', |
| | | }, |
| | | { |
| | | field: 'paymentPrice', |
| | | title: 'æ¬æ¬¡ä»æ¬¾', |
| | | minWidth: 120, |
| | | formatter: ({ cellValue }) => erpPriceInputFormatter(cellValue) || '-', |
| | | }, |
| | | { |
| | | field: 'remark', |
| | | title: '夿³¨', |
| | | minWidth: 150, |
| | | formatter: ({ cellValue }) => textRender(cellValue), |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | gridOptions: { |
| | | columns: usePaymentItemColumns(), |
| | | data: [], |
| | | minHeight: 200, |
| | | autoResize: true, |
| | | border: true, |
| | | rowConfig: { |
| | | keyField: 'bizId', |
| | | isHover: true, |
| | | }, |
| | | pagerConfig: { |
| | | enabled: false, |
| | | }, |
| | | toolbarConfig: { |
| | | enabled: false, |
| | | }, |
| | | }, |
| | | }); |
| | | |
| | | const [Descriptions] = useDescription({ |
| | | bordered: true, |
| | | column: 2, |
| | | schema: [ |
| | | { label: '仿¬¾åå·', field: 'no', render: textRender }, |
| | | { label: 'ä¾åºååç§°', field: 'supplierName', render: textRender }, |
| | | { |
| | | label: 'å
³èæ¥ç¥¨', |
| | | field: 'invoice', |
| | | render: (_val, data) => (data?.invoice?.no ? data.invoice.no : '-'), |
| | | }, |
| | | { |
| | | label: '仿¬¾æ¶é´', |
| | | field: 'paymentTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { |
| | | label: 'å计éé¢ï¼å
ï¼', |
| | | field: 'totalPrice', |
| | | render: (val) => erpPriceInputFormatter(val) || '-', |
| | | }, |
| | | { |
| | | label: '伿 éé¢ï¼å
ï¼', |
| | | field: 'discountPrice', |
| | | render: (val) => erpPriceInputFormatter(val) || '-', |
| | | }, |
| | | { |
| | | label: 'å®é
仿¬¾éé¢ï¼å
ï¼', |
| | | field: 'paymentPrice', |
| | | render: (val) => erpPriceInputFormatter(val) || '-', |
| | | }, |
| | | { label: '仿¬¾è´¦æ·', field: 'accountName', render: textRender }, |
| | | { label: 'è´¢å¡äººå', field: 'financeUserName', render: textRender }, |
| | | { |
| | | label: '审æ¹ç¶æ', |
| | | field: 'status', |
| | | render: (val) => |
| | | h(DictTag, { type: DICT_TYPE.ERP_AUDIT_STATUS, value: val }), |
| | | }, |
| | | { label: 'å建人', field: 'creatorName', render: textRender }, |
| | | { |
| | | label: 'å建æ¶é´', |
| | | field: 'createTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { label: '夿³¨', field: 'remark', render: textRender }, |
| | | ] as DescriptionItemSchema[], |
| | | }); |
| | | |
| | | onMounted(async () => { |
| | | try { |
| | | loading.value = true; |
| | | formData.value = await getFinancePayment(Number(props.id)); |
| | | if (formData.value?.items?.length) { |
| | | await nextTick(); |
| | | await gridApi.grid.reloadData(formData.value.items); |
| | | } |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <ContentWrap class="m-2"> |
| | | <Spin :spinning="loading" tip="å è½½ä¸..."> |
| | | <div class="space-y-4"> |
| | | <!-- 仿¬¾ååºæ¬ä¿¡æ¯ --> |
| | | <div class="rounded-lg border border-border bg-background p-4"> |
| | | <div class="mb-4 flex items-center gap-2"> |
| | | <span class="inline-block h-4 w-1 rounded bg-primary" /> |
| | | <span class="text-base font-semibold">仿¬¾ååºæ¬ä¿¡æ¯</span> |
| | | </div> |
| | | <Descriptions :data="formData" /> |
| | | </div> |
| | | <!-- 仿¬¾æç» --> |
| | | <div |
| | | v-if="formData?.items?.length" |
| | | class="rounded-lg border border-border bg-background p-4" |
| | | > |
| | | <div class="mb-4 flex items-center gap-2"> |
| | | <span class="inline-block h-4 w-1 rounded bg-primary" /> |
| | | <span class="text-base font-semibold">仿¬¾æç»</span> |
| | | </div> |
| | | <Grid /> |
| | | </div> |
| | | </div> |
| | | </Spin> |
| | | </ContentWrap> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { ErpPurchaseInvoiceApi } from '#/api/erp/purchase/invoice'; |
| | | import type { DescriptionItemSchema } from '#/components/description'; |
| | | |
| | | import { onMounted, ref } from 'vue'; |
| | | |
| | | import { ContentWrap } from '@vben/common-ui'; |
| | | import { erpPriceInputFormatter, formatDateTime } from '@vben/utils'; |
| | | |
| | | import { Spin } from 'ant-design-vue'; |
| | | |
| | | import { getPurchaseInvoice } from '#/api/erp/purchase/invoice'; |
| | | import { useDescription } from '#/components/description'; |
| | | |
| | | defineOptions({ name: 'ErpPurchaseInvoiceApproveDetail' }); |
| | | |
| | | const props = defineProps<{ id: string }>(); |
| | | |
| | | const loading = ref(false); |
| | | const formData = ref<ErpPurchaseInvoiceApi.PurchaseInvoice>(); |
| | | |
| | | /** ææ¬åæ®µç©ºå¼å ä½ */ |
| | | function textRender(val: unknown) { |
| | | return val === 0 || val ? String(val) : '-'; |
| | | } |
| | | |
| | | const [Descriptions] = useDescription({ |
| | | bordered: true, |
| | | column: 2, |
| | | schema: [ |
| | | { label: 'æ¥ç¥¨ç¼å·', field: 'no', render: textRender }, |
| | | { label: 'ä¾åºååç§°', field: 'supplierName', render: textRender }, |
| | | { |
| | | label: 'éè´è®¢åå·', |
| | | field: 'order', |
| | | render: (_val, data) => (data?.order?.no ? data.order.no : '-'), |
| | | }, |
| | | { label: 'å票å·ç ', field: 'invoiceNo', render: textRender }, |
| | | { label: 'å票æ¬å¤´', field: 'invoiceTitle', render: textRender }, |
| | | { |
| | | label: 'æ¥ç¥¨éé¢ï¼å
ï¼', |
| | | field: 'price', |
| | | render: (val) => erpPriceInputFormatter(val) || '-', |
| | | }, |
| | | { |
| | | label: 'å©ä½å¯ä»éé¢ï¼å
ï¼', |
| | | field: 'remainingInvoicePrice', |
| | | render: (val) => erpPriceInputFormatter(val ?? 0) || '-', |
| | | }, |
| | | { |
| | | label: 'å¼ç¥¨æ¥æ', |
| | | field: 'invoiceTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { label: 'å建人', field: 'creatorName', render: textRender }, |
| | | { |
| | | label: 'å建æ¶é´', |
| | | field: 'createTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { label: '夿³¨', field: 'remark', render: textRender }, |
| | | ] as DescriptionItemSchema[], |
| | | }); |
| | | |
| | | onMounted(async () => { |
| | | try { |
| | | loading.value = true; |
| | | formData.value = await getPurchaseInvoice(Number(props.id)); |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <ContentWrap class="m-2"> |
| | | <Spin :spinning="loading" tip="å è½½ä¸..."> |
| | | <div class="space-y-4"> |
| | | <!-- æ¥ç¥¨åºæ¬ä¿¡æ¯ --> |
| | | <div class="rounded-lg border border-border bg-background p-4"> |
| | | <div class="mb-4 flex items-center gap-2"> |
| | | <span class="inline-block h-4 w-1 rounded bg-primary" /> |
| | | <span class="text-base font-semibold">æ¥ç¥¨åºæ¬ä¿¡æ¯</span> |
| | | </div> |
| | | <Descriptions :data="formData" /> |
| | | </div> |
| | | </div> |
| | | </Spin> |
| | | </ContentWrap> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { ErpPurchaseOrderApi } from '#/api/erp/purchase/order'; |
| | | import type { DescriptionItemSchema } from '#/components/description'; |
| | | |
| | | import { h, onMounted, ref } from 'vue'; |
| | | |
| | | import { ContentWrap } from '@vben/common-ui'; |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { |
| | | erpCountInputFormatter, |
| | | erpPriceInputFormatter, |
| | | formatDateTime, |
| | | } from '@vben/utils'; |
| | | |
| | | import { Spin, Tag } from 'ant-design-vue'; |
| | | |
| | | import { getPurchaseOrder } from '#/api/erp/purchase/order'; |
| | | import { DictTag } from '#/components/dict-tag'; |
| | | import { useDescription } from '#/components/description'; |
| | | |
| | | import ItemForm from '../modules/item-form.vue'; |
| | | |
| | | defineOptions({ name: 'ErpPurchaseOrderDetail' }); |
| | | |
| | | const props = defineProps<{ id: string }>(); |
| | | |
| | | const loading = ref(false); |
| | | const formData = ref<ErpPurchaseOrderApi.PurchaseOrder>(); |
| | | |
| | | /** ææ¬åæ®µç©ºå¼å ä½ */ |
| | | function textRender(val: unknown) { |
| | | return val === 0 || val ? String(val) : '-'; |
| | | } |
| | | |
| | | /** å
¥åºç¶ææ¸²æ */ |
| | | function renderInStatus(val?: number) { |
| | | const map: Record<number, { text: string; color: string }> = { |
| | | 0: { text: 'æªå
¥åº', color: 'default' }, |
| | | 1: { text: 'é¨åå
¥åº', color: 'warning' }, |
| | | 2: { text: 'å
¨é¨å
¥åº', color: 'success' }, |
| | | }; |
| | | const item = map[val ?? 0]!; |
| | | return h(Tag, { color: item.color }, () => item.text); |
| | | } |
| | | |
| | | const [Descriptions] = useDescription({ |
| | | bordered: true, |
| | | column: 2, |
| | | schema: [ |
| | | { label: 'éè´è®¢åå·', field: 'no' }, |
| | | { label: 'ä¾åºååç§°', field: 'supplierName', render: textRender }, |
| | | { |
| | | label: 'è®¢åæ¶é´', |
| | | field: 'orderTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { |
| | | label: 'å计æ°é', |
| | | field: 'totalCount', |
| | | render: (val) => erpCountInputFormatter(val) || '-', |
| | | }, |
| | | { |
| | | label: 'å计éé¢', |
| | | field: 'totalPrice', |
| | | render: (val) => erpPriceInputFormatter(val) || '-', |
| | | }, |
| | | { |
| | | label: '伿 éé¢', |
| | | field: 'discountPrice', |
| | | render: (val) => erpPriceInputFormatter(val) || '-', |
| | | }, |
| | | { |
| | | label: 'å®ééé¢', |
| | | field: 'depositPrice', |
| | | render: (val) => erpPriceInputFormatter(val) || '-', |
| | | }, |
| | | { |
| | | label: '审æ¹ç¶æ', |
| | | field: 'status', |
| | | render: (val) => |
| | | h(DictTag, { type: DICT_TYPE.ERP_AUDIT_STATUS, value: val }), |
| | | }, |
| | | { |
| | | label: 'å
¥åºç¶æ', |
| | | field: 'inStatus', |
| | | render: (val) => renderInStatus(val as number), |
| | | }, |
| | | { label: 'å建人', field: 'creatorName', render: textRender }, |
| | | { |
| | | label: 'å建æ¶é´', |
| | | field: 'createTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { label: '夿³¨', field: 'remark', render: textRender }, |
| | | ] as DescriptionItemSchema[], |
| | | }); |
| | | |
| | | onMounted(async () => { |
| | | try { |
| | | loading.value = true; |
| | | formData.value = await getPurchaseOrder(Number(props.id)); |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <ContentWrap class="m-2"> |
| | | <Spin :spinning="loading" tip="å è½½ä¸..."> |
| | | <div class="space-y-4"> |
| | | <!-- åºæ¬ä¿¡æ¯ --> |
| | | <div class="rounded-lg border border-border bg-background p-4"> |
| | | <div class="mb-4 flex items-center gap-2"> |
| | | <span class="inline-block h-4 w-1 rounded bg-primary" /> |
| | | <span class="text-base font-semibold">åºæ¬ä¿¡æ¯</span> |
| | | </div> |
| | | <Descriptions :data="formData" /> |
| | | </div> |
| | | <!-- éè´æç» --> |
| | | <div |
| | | v-if="formData?.items?.length" |
| | | class="rounded-lg border border-border bg-background p-4" |
| | | > |
| | | <div class="mb-4 flex items-center gap-2"> |
| | | <span class="inline-block h-4 w-1 rounded bg-primary" /> |
| | | <span class="text-base font-semibold">éè´æç»</span> |
| | | </div> |
| | | <ItemForm :items="formData.items" :disabled="true" /> |
| | | </div> |
| | | </div> |
| | | </Spin> |
| | | </ContentWrap> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { ErpPurchaseRequestApi } from '#/api/erp/purchase/request'; |
| | | import type { DescriptionItemSchema } from '#/components/description'; |
| | | |
| | | import { h, nextTick, onMounted, ref } from 'vue'; |
| | | |
| | | import { ContentWrap } from '@vben/common-ui'; |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { |
| | | erpCountInputFormatter, |
| | | erpPriceInputFormatter, |
| | | formatDateTime, |
| | | } from '@vben/utils'; |
| | | |
| | | import { Spin } from 'ant-design-vue'; |
| | | |
| | | import { useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { getPurchaseRequest } from '#/api/erp/purchase/request'; |
| | | import { DictTag } from '#/components/dict-tag'; |
| | | import { useDescription } from '#/components/description'; |
| | | |
| | | defineOptions({ name: 'ErpPurchaseRequestDetail' }); |
| | | |
| | | const props = defineProps<{ id: string }>(); |
| | | |
| | | const loading = ref(false); |
| | | const formData = ref<ErpPurchaseRequestApi.PurchaseRequest>(); |
| | | |
| | | /** ææ¬åæ®µç©ºå¼å ä½ */ |
| | | function textRender(val: unknown) { |
| | | return val === 0 || val ? String(val) : '-'; |
| | | } |
| | | |
| | | /** éè´ç³è¯·æç»ï¼å®¡æ¹è¯¦æ
åªè¯»åï¼ */ |
| | | function useDetailItemColumns(): VxeTableGridOptions['columns'] { |
| | | return [ |
| | | { type: 'seq', title: 'åºå·', width: 60 }, |
| | | { field: 'productName', title: '产ååç§°', minWidth: 180 }, |
| | | { field: 'productUnitName', title: 'åä½', minWidth: 80 }, |
| | | { |
| | | field: 'count', |
| | | title: 'æ°é', |
| | | minWidth: 100, |
| | | formatter: ({ cellValue }) => erpCountInputFormatter(cellValue) || '-', |
| | | }, |
| | | { |
| | | field: 'productPrice', |
| | | title: 'åä»·ï¼åèä»·ï¼', |
| | | minWidth: 120, |
| | | formatter: ({ cellValue }) => erpPriceInputFormatter(cellValue) || '-', |
| | | }, |
| | | { |
| | | field: 'totalPrice', |
| | | title: 'é¢ä¼°éé¢', |
| | | minWidth: 120, |
| | | formatter: ({ cellValue }) => erpPriceInputFormatter(cellValue) || '-', |
| | | }, |
| | | { |
| | | field: 'taxPercent', |
| | | title: 'ç¨ç(%)', |
| | | minWidth: 90, |
| | | formatter: ({ cellValue }) => (cellValue ? `${cellValue}%` : '-'), |
| | | }, |
| | | { field: 'demandTime', title: 'éæ±æ¥æ', minWidth: 110 }, |
| | | { |
| | | field: 'remark', |
| | | title: '夿³¨', |
| | | minWidth: 160, |
| | | showOverflow: 'tooltip', |
| | | }, |
| | | { |
| | | field: 'qcCheckFlag', |
| | | title: 'æ¯å¦è´¨æ£', |
| | | minWidth: 80, |
| | | formatter: ({ cellValue }) => (cellValue ? 'æ¯' : 'å¦'), |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | gridOptions: { |
| | | columns: useDetailItemColumns(), |
| | | data: [], |
| | | minHeight: 200, |
| | | autoResize: true, |
| | | border: true, |
| | | rowConfig: { |
| | | keyField: 'seq', |
| | | isHover: true, |
| | | }, |
| | | pagerConfig: { |
| | | enabled: false, |
| | | }, |
| | | toolbarConfig: { |
| | | enabled: false, |
| | | }, |
| | | }, |
| | | }); |
| | | |
| | | const [Descriptions] = useDescription({ |
| | | bordered: true, |
| | | column: 2, |
| | | schema: [ |
| | | { label: 'ç³è¯·ç¼å·', field: 'no' }, |
| | | { |
| | | label: '审æ¹ç¶æ', |
| | | field: 'status', |
| | | render: (val) => |
| | | h(DictTag, { type: DICT_TYPE.ERP_AUDIT_STATUS, value: val }), |
| | | }, |
| | | { label: 'ç³è¯·äºº', field: 'requestUserName', render: textRender }, |
| | | { label: 'ç³è¯·é¨é¨', field: 'requestDeptName', render: textRender }, |
| | | { |
| | | label: 'ç³è¯·æ¶é´', |
| | | field: 'requestTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { label: 'ä¾åºååç§°', field: 'supplierName', render: textRender }, |
| | | { |
| | | label: 'å计æ°é', |
| | | field: 'totalCount', |
| | | render: (val) => erpCountInputFormatter(val) || '-', |
| | | }, |
| | | { |
| | | label: 'å计éé¢', |
| | | field: 'totalPrice', |
| | | render: (val) => erpPriceInputFormatter(val) || '-', |
| | | }, |
| | | { label: 'ç³è¯·çç±', field: 'requestReason', render: textRender }, |
| | | { label: 'çæéè´è®¢å', field: 'orderNo', render: textRender }, |
| | | { |
| | | label: 'å建æ¶é´', |
| | | field: 'createTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { label: '夿³¨', field: 'remark', render: textRender }, |
| | | ] as DescriptionItemSchema[], |
| | | }); |
| | | |
| | | onMounted(async () => { |
| | | try { |
| | | loading.value = true; |
| | | formData.value = await getPurchaseRequest(Number(props.id)); |
| | | if (formData.value?.items?.length) { |
| | | await nextTick(); |
| | | await gridApi.grid.reloadData(formData.value.items); |
| | | } |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <ContentWrap class="m-2"> |
| | | <Spin :spinning="loading" tip="å è½½ä¸..."> |
| | | <div class="space-y-4"> |
| | | <!-- åºæ¬ä¿¡æ¯ --> |
| | | <div class="rounded-lg border border-border bg-background p-4"> |
| | | <div class="mb-4 flex items-center gap-2"> |
| | | <span class="inline-block h-4 w-1 rounded bg-primary" /> |
| | | <span class="text-base font-semibold">åºæ¬ä¿¡æ¯</span> |
| | | </div> |
| | | <Descriptions :data="formData" /> |
| | | </div> |
| | | <!-- ç³è¯·æç» --> |
| | | <div |
| | | v-if="formData?.items?.length" |
| | | class="rounded-lg border border-border bg-background p-4" |
| | | > |
| | | <div class="mb-4 flex items-center gap-2"> |
| | | <span class="inline-block h-4 w-1 rounded bg-primary" /> |
| | | <span class="text-base font-semibold">ç³è¯·æç»</span> |
| | | </div> |
| | | <Grid /> |
| | | </div> |
| | | </div> |
| | | </Spin> |
| | | </ContentWrap> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { HrmAttendanceExceptionApi } from '#/api/hrm/attendance/exception'; |
| | | import type { DescriptionItemSchema } from '#/components/description'; |
| | | |
| | | import { h, onMounted, ref } from 'vue'; |
| | | |
| | | import { ContentWrap } from '@vben/common-ui'; |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { formatDateTime } from '@vben/utils'; |
| | | |
| | | import { Spin } from 'ant-design-vue'; |
| | | |
| | | import { getAttendanceException } from '#/api/hrm/attendance/exception'; |
| | | import { DictTag } from '#/components/dict-tag'; |
| | | import { useDescription } from '#/components/description'; |
| | | |
| | | defineOptions({ name: 'HrmAttendanceExceptionApproveDetail' }); |
| | | |
| | | const props = defineProps<{ id: string }>(); |
| | | |
| | | const loading = ref(false); |
| | | const formData = ref<HrmAttendanceExceptionApi.AttendanceException>(); |
| | | |
| | | /** ææ¬åæ®µç©ºå¼å ä½ */ |
| | | function textRender(val: unknown) { |
| | | return val === 0 || val ? String(val) : '-'; |
| | | } |
| | | |
| | | const [Descriptions] = useDescription({ |
| | | bordered: true, |
| | | column: 2, |
| | | schema: [ |
| | | { label: 'åå·¥å§å', field: 'userName', render: textRender }, |
| | | { label: 'æå±é¨é¨', field: 'deptName', render: textRender }, |
| | | { |
| | | label: 'å¼å¸¸æ¥æ', |
| | | field: 'date', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { label: 'å¼å¸¸ç±»å', field: 'exceptionTypeName', render: textRender }, |
| | | { label: 'å¼å¸¸è¯´æ', field: 'reason', render: textRender }, |
| | | { |
| | | label: '审æ¹ç¶æ', |
| | | field: 'status', |
| | | render: (val) => |
| | | h(DictTag, { type: DICT_TYPE.HRM_AUDIT_STATUS, value: val }), |
| | | }, |
| | | { label: '夿³¨', field: 'remark', render: textRender }, |
| | | { |
| | | label: 'å建æ¶é´', |
| | | field: 'createTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | ] as DescriptionItemSchema[], |
| | | }); |
| | | |
| | | onMounted(async () => { |
| | | try { |
| | | loading.value = true; |
| | | formData.value = await getAttendanceException(Number(props.id)); |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <ContentWrap class="m-2"> |
| | | <Spin :spinning="loading" tip="å è½½ä¸..."> |
| | | <div class="space-y-4"> |
| | | <!-- èå¤å¼å¸¸åºæ¬ä¿¡æ¯ --> |
| | | <div class="rounded-lg border border-border bg-background p-4"> |
| | | <div class="mb-4 flex items-center gap-2"> |
| | | <span class="inline-block h-4 w-1 rounded bg-primary" /> |
| | | <span class="text-base font-semibold">èå¤å¼å¸¸åºæ¬ä¿¡æ¯</span> |
| | | </div> |
| | | <Descriptions :data="formData" /> |
| | | </div> |
| | | </div> |
| | | </Spin> |
| | | </ContentWrap> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { HrmLeaveApi } from '#/api/hrm/leave'; |
| | | import type { DescriptionItemSchema } from '#/components/description'; |
| | | |
| | | import { h, onMounted, ref } from 'vue'; |
| | | |
| | | import { ContentWrap } from '@vben/common-ui'; |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { formatDateTime } from '@vben/utils'; |
| | | |
| | | import { Spin } from 'ant-design-vue'; |
| | | |
| | | import { getLeave } from '#/api/hrm/leave'; |
| | | import { DictTag } from '#/components/dict-tag'; |
| | | import { useDescription } from '#/components/description'; |
| | | |
| | | defineOptions({ name: 'HrmLeaveApproveDetail' }); |
| | | |
| | | const props = defineProps<{ id: string }>(); |
| | | |
| | | const loading = ref(false); |
| | | const formData = ref<HrmLeaveApi.Leave>(); |
| | | |
| | | /** ææ¬åæ®µç©ºå¼å ä½ */ |
| | | function textRender(val: unknown) { |
| | | return val === 0 || val ? String(val) : '-'; |
| | | } |
| | | |
| | | const [Descriptions] = useDescription({ |
| | | bordered: true, |
| | | column: 2, |
| | | schema: [ |
| | | { label: 'åå·¥å§å', field: 'employeeName', render: textRender }, |
| | | { label: 'æå±é¨é¨', field: 'deptName', render: textRender }, |
| | | { |
| | | label: '请åç±»å', |
| | | field: 'leaveType', |
| | | render: (val) => |
| | | h(DictTag, { type: DICT_TYPE.HRM_LEAVE_TYPE, value: val }), |
| | | }, |
| | | { |
| | | label: 'å¼å§æ¶é´', |
| | | field: 'startTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { |
| | | label: 'ç»ææ¶é´', |
| | | field: 'endTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { label: 'è¯·åæ¶é¿', field: 'duration', render: textRender }, |
| | | { label: '请åäºç±', field: 'reason', render: textRender }, |
| | | { |
| | | label: '审æ¹ç¶æ', |
| | | field: 'status', |
| | | render: (val) => |
| | | h(DictTag, { type: DICT_TYPE.HRM_AUDIT_STATUS, value: val }), |
| | | }, |
| | | { label: '夿³¨', field: 'remark', render: textRender }, |
| | | { |
| | | label: 'å建æ¶é´', |
| | | field: 'createTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | ] as DescriptionItemSchema[], |
| | | }); |
| | | |
| | | onMounted(async () => { |
| | | try { |
| | | loading.value = true; |
| | | formData.value = await getLeave(Number(props.id)); |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <ContentWrap class="m-2"> |
| | | <Spin :spinning="loading" tip="å è½½ä¸..."> |
| | | <div class="space-y-4"> |
| | | <!-- 请ååºæ¬ä¿¡æ¯ --> |
| | | <div class="rounded-lg border border-border bg-background p-4"> |
| | | <div class="mb-4 flex items-center gap-2"> |
| | | <span class="inline-block h-4 w-1 rounded bg-primary" /> |
| | | <span class="text-base font-semibold">请ååºæ¬ä¿¡æ¯</span> |
| | | </div> |
| | | <Descriptions :data="formData" /> |
| | | </div> |
| | | </div> |
| | | </Spin> |
| | | </ContentWrap> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { HrmResignationApi } from '#/api/hrm/resignation'; |
| | | import type { DescriptionItemSchema } from '#/components/description'; |
| | | |
| | | import { h, onMounted, ref } from 'vue'; |
| | | |
| | | import { ContentWrap } from '@vben/common-ui'; |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { formatDateTime } from '@vben/utils'; |
| | | |
| | | import { Spin } from 'ant-design-vue'; |
| | | |
| | | import { getResignation } from '#/api/hrm/resignation'; |
| | | import { DictTag } from '#/components/dict-tag'; |
| | | import { useDescription } from '#/components/description'; |
| | | |
| | | defineOptions({ name: 'HrmResignationApproveDetail' }); |
| | | |
| | | const props = defineProps<{ id: string }>(); |
| | | |
| | | const loading = ref(false); |
| | | const formData = ref<HrmResignationApi.Resignation>(); |
| | | |
| | | /** ææ¬åæ®µç©ºå¼å ä½ */ |
| | | function textRender(val: unknown) { |
| | | return val === 0 || val ? String(val) : '-'; |
| | | } |
| | | |
| | | const [Descriptions] = useDescription({ |
| | | bordered: true, |
| | | column: 2, |
| | | schema: [ |
| | | { label: 'åå·¥å§å', field: 'employeeName', render: textRender }, |
| | | { label: 'æå±é¨é¨', field: 'deptName', render: textRender }, |
| | | { label: 'èä½', field: 'postName', render: textRender }, |
| | | { |
| | | label: '离èç±»å', |
| | | field: 'resignationType', |
| | | render: (val) => |
| | | h(DictTag, { type: DICT_TYPE.HRM_RESIGNATION_TYPE, value: val }), |
| | | }, |
| | | { |
| | | label: 'é¢è®¡ç¦»èæ¥æ', |
| | | field: 'expectedDate', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { label: '离èåå ', field: 'reason', render: textRender }, |
| | | { label: '交æ¥äºº', field: 'handoverUserName', render: textRender }, |
| | | { |
| | | label: '交æ¥ç¶æ', |
| | | field: 'handoverStatus', |
| | | render: (val) => |
| | | h(DictTag, { type: DICT_TYPE.HRM_HANDOVER_STATUS, value: val }), |
| | | }, |
| | | { |
| | | label: '审æ¹ç¶æ', |
| | | field: 'status', |
| | | render: (val) => |
| | | h(DictTag, { type: DICT_TYPE.HRM_AUDIT_STATUS, value: val }), |
| | | }, |
| | | { label: '夿³¨', field: 'remark', render: textRender }, |
| | | { |
| | | label: 'å建æ¶é´', |
| | | field: 'createTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | ] as DescriptionItemSchema[], |
| | | }); |
| | | |
| | | onMounted(async () => { |
| | | try { |
| | | loading.value = true; |
| | | formData.value = await getResignation(Number(props.id)); |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <ContentWrap class="m-2"> |
| | | <Spin :spinning="loading" tip="å è½½ä¸..."> |
| | | <div class="space-y-4"> |
| | | <!-- 离èåºæ¬ä¿¡æ¯ --> |
| | | <div class="rounded-lg border border-border bg-background p-4"> |
| | | <div class="mb-4 flex items-center gap-2"> |
| | | <span class="inline-block h-4 w-1 rounded bg-primary" /> |
| | | <span class="text-base font-semibold">离èåºæ¬ä¿¡æ¯</span> |
| | | </div> |
| | | <Descriptions :data="formData" /> |
| | | </div> |
| | | </div> |
| | | </Spin> |
| | | </ContentWrap> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { HrmTransferApi } from '#/api/hrm/transfer'; |
| | | import type { DescriptionItemSchema } from '#/components/description'; |
| | | |
| | | import { h, onMounted, ref } from 'vue'; |
| | | |
| | | import { ContentWrap } from '@vben/common-ui'; |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { formatDateTime } from '@vben/utils'; |
| | | |
| | | import { Spin } from 'ant-design-vue'; |
| | | |
| | | import { getTransfer } from '#/api/hrm/transfer'; |
| | | import { DictTag } from '#/components/dict-tag'; |
| | | import { useDescription } from '#/components/description'; |
| | | |
| | | defineOptions({ name: 'HrmTransferApproveDetail' }); |
| | | |
| | | const props = defineProps<{ id: string }>(); |
| | | |
| | | const loading = ref(false); |
| | | const formData = ref<HrmTransferApi.Transfer>(); |
| | | |
| | | /** ææ¬åæ®µç©ºå¼å ä½ */ |
| | | function textRender(val: unknown) { |
| | | return val === 0 || val ? String(val) : '-'; |
| | | } |
| | | |
| | | const [Descriptions] = useDescription({ |
| | | bordered: true, |
| | | column: 2, |
| | | schema: [ |
| | | { label: 'åå·¥å§å', field: 'employeeName', render: textRender }, |
| | | { label: 'å½åé¨é¨', field: 'currentDeptName', render: textRender }, |
| | | { label: 'å½åèä½', field: 'currentPostName', render: textRender }, |
| | | { label: 'ç®æ é¨é¨', field: 'targetDeptName', render: textRender }, |
| | | { label: 'ç®æ èä½', field: 'targetPostName', render: textRender }, |
| | | { |
| | | label: 'è°å²ç±»å', |
| | | field: 'transferType', |
| | | render: (val) => |
| | | h(DictTag, { type: DICT_TYPE.HRM_TRANSFER_TYPE, value: val }), |
| | | }, |
| | | { |
| | | label: 'çææ¥æ', |
| | | field: 'effectiveDate', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | { label: 'è°å²åå ', field: 'reason', render: textRender }, |
| | | { |
| | | label: '审æ¹ç¶æ', |
| | | field: 'status', |
| | | render: (val) => |
| | | h(DictTag, { type: DICT_TYPE.HRM_AUDIT_STATUS, value: val }), |
| | | }, |
| | | { label: '夿³¨', field: 'remark', render: textRender }, |
| | | { |
| | | label: 'å建æ¶é´', |
| | | field: 'createTime', |
| | | render: (val) => formatDateTime(val) as string, |
| | | }, |
| | | ] as DescriptionItemSchema[], |
| | | }); |
| | | |
| | | onMounted(async () => { |
| | | try { |
| | | loading.value = true; |
| | | formData.value = await getTransfer(Number(props.id)); |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <ContentWrap class="m-2"> |
| | | <Spin :spinning="loading" tip="å è½½ä¸..."> |
| | | <div class="space-y-4"> |
| | | <!-- è°å²åºæ¬ä¿¡æ¯ --> |
| | | <div class="rounded-lg border border-border bg-background p-4"> |
| | | <div class="mb-4 flex items-center gap-2"> |
| | | <span class="inline-block h-4 w-1 rounded bg-primary" /> |
| | | <span class="text-base font-semibold">è°å²åºæ¬ä¿¡æ¯</span> |
| | | </div> |
| | | <Descriptions :data="formData" /> |
| | | </div> |
| | | </div> |
| | | </Spin> |
| | | </ContentWrap> |
| | | </template> |