Commit d3186a394b6581878fe6338b3d354ba895e4ab06
1 parent
41be6d5c
feat: 业务研发明细表
Showing
12 changed files
with
1802 additions
and
13 deletions
src/api/project/invoice.ts
... | ... | @@ -43,20 +43,23 @@ enum Api { |
43 | 43 | PACKAGEPROFIT = '/order/cost/BusinessProfitDetail/listByPage', //包装费用明细表 |
44 | 44 | INNERPROFIT = '/order/cost/InnerProfitDetail/listByPage', //内部生产费用明细表 |
45 | 45 | PACKAGEEDIT = '/order/cost/edit', //编辑 |
46 | + BUSINESSDEVELOPMENTEDIT = '/project/edit', //业务研发明细表编辑 | |
46 | 47 | PACKAGEAPPLYEDIT = '/order/cost/applyEditFileds', //申请编辑字段 |
47 | 48 | SERVICEPROFIT = '/project/BusinessProfitInfo/listByPage', //业务研发净利润分析表 |
48 | 49 | INNERPRODUCEPROFIT = '/project/InnerProfitInfo/listByPage', //内部生产利润分析表 |
49 | 50 | SERVICEPROFITEXPORT = '/project/businessProfit/export', //业务研发净利润分析表导出 |
50 | 51 | INNERPROFITEXPORT = '/project/innerProfit/export', //内部研发净利润分析表导出 |
51 | 52 | SERVICEEDIT = '/project/edit', //编辑 |
52 | - SERVICEAPPLYEDIT = '/project/applyEditFileds', //申请修改 | |
53 | + SERVICEAPPLYEDIT = '/project/applyEditFileds', //申请字段编辑权限申请 | |
53 | 54 | APPLYLIST = '/project/pageProjectLockFieldApply', //分页查询项目字段申请记录 |
54 | 55 | AUDITAPPLY = '/project/audit', //审核 |
55 | 56 | ACTIONRECORD = '/projectOptLog/listByPage', //业务/内部研发净利润操作记录以及申请记录 |
56 | 57 | ORDERCOSTDETAILEDOPTLOG = '/orderCostDetailedOptLog/listByPage', //包装费用明细/内部生产明细操作记录表 |
58 | + PROJECTCOSTDETAILEDOPTLOG = '/projectOptLog/listByPage', //业务研发明细表操作记录表 | |
57 | 59 | SETPACKSTATUS = '/order/cost/setPackStatus', //包装费用明细表审批 |
58 | 60 | SETINNERSTATUS = '/order/cost/setInnerStatus', //内部生产明细表审批 |
59 | 61 | PROJECTBUSINESSPROFITSETSTATUS = '/project/businessProfit/setStatus', //业务研发净利润分析表审批 |
62 | + PROJECTBUSINESSDEVELOPMENTSETSTATUS = '/project/setDetailBusinessProfitStatus', //业务研发明细表审核通过 | |
60 | 63 | PROJECTINNERPROFITSETSTATUS = '/project/innerProfitInfo/setStatus', //内部研发净利润分析表审批 |
61 | 64 | } |
62 | 65 | |
... | ... | @@ -427,12 +430,25 @@ export const getServiceEdit = async (params: any) => { |
427 | 430 | }); |
428 | 431 | }; |
429 | 432 | |
433 | +export const getBusinessDevelopmentEdit = async (params: any) => { | |
434 | + return await defHttp.post<any>({ | |
435 | + url: Api.BUSINESSDEVELOPMENTEDIT, | |
436 | + params, | |
437 | + }); | |
438 | +}; | |
439 | + | |
430 | 440 | export const getServiceApplyEdit = async (params: any) => { |
431 | 441 | return await defHttp.post<any>({ |
432 | 442 | url: Api.SERVICEAPPLYEDIT, |
433 | 443 | params, |
434 | 444 | }); |
435 | 445 | }; |
446 | +export const getBusinessDevelopmentApplyEdit = async (params: any) => { | |
447 | + return await defHttp.post<any>({ | |
448 | + url: Api.SERVICEAPPLYEDIT, | |
449 | + params, | |
450 | + }); | |
451 | +}; | |
436 | 452 | |
437 | 453 | export const getApplyList = async (params: any) => { |
438 | 454 | // const res = ref(); |
... | ... | @@ -516,16 +532,43 @@ export const getProjectOptLog = async (params: any) => { |
516 | 532 | }); |
517 | 533 | }; |
518 | 534 | |
535 | +// 业务研发明细表操作记录表 | |
536 | +export const getProjectCostDetailedOptLog = async (params: any) => { | |
537 | + const res = await defHttp.post<any>({ | |
538 | + url: Api.PROJECTCOSTDETAILEDOPTLOG, | |
539 | + params, | |
540 | + }); | |
541 | + | |
542 | + | |
543 | + const formattedRecords = res.records.map((record: any) => { | |
544 | + return { | |
545 | + ...record, | |
546 | + }; | |
547 | + }); | |
548 | + | |
549 | + const orderStore = useOrderStoreWithOut(); | |
550 | + orderStore.setTotal(res.total); | |
551 | + orderStore.setQueryVO(params); | |
552 | + return new Promise((resolve) => { | |
553 | + resolve({ | |
554 | + items: formattedRecords, | |
555 | + total: res.total, | |
556 | + }); | |
557 | + }); | |
558 | +}; | |
519 | 559 | export const getOrderCostDetailedOptLog = async (params: any) => { |
520 | 560 | const res = await defHttp.post<any>({ |
521 | 561 | url: Api.ORDERCOSTDETAILEDOPTLOG, |
522 | 562 | params, |
523 | 563 | }); |
564 | + | |
565 | + | |
524 | 566 | const formattedRecords = res.records.map((record: any) => { |
525 | 567 | return { |
526 | 568 | ...record, |
527 | 569 | }; |
528 | 570 | }); |
571 | + | |
529 | 572 | const orderStore = useOrderStoreWithOut(); |
530 | 573 | orderStore.setTotal(res.total); |
531 | 574 | orderStore.setQueryVO(params); |
... | ... | @@ -569,3 +612,56 @@ export const setCommissionStatus = async (data: { orderId: number[] }) => { |
569 | 612 | data, |
570 | 613 | }); |
571 | 614 | }; |
615 | +// 业务研发明细表接口 | |
616 | +export const getBusinessDevelopmentDetail = async (params: any) => { | |
617 | + const res = await defHttp.post<any>({ | |
618 | + url: '/project/BusinessDevelopmentDetail/listByPage', | |
619 | + params, | |
620 | + }); | |
621 | + const formattedRecords = res.records.map((record: any) => ({ | |
622 | + ...record, | |
623 | + })); | |
624 | + return new Promise((resolve) => { | |
625 | + resolve({ | |
626 | + items: formattedRecords, | |
627 | + total: res.total, | |
628 | + }); | |
629 | + }); | |
630 | +}; | |
631 | + | |
632 | +export const setBusinessDevelopmentStatus = async (params: any) => { | |
633 | + return await defHttp.post<any>({ | |
634 | + url: Api.PROJECTBUSINESSDEVELOPMENTSETSTATUS, | |
635 | + params, | |
636 | + }); | |
637 | +}; | |
638 | + | |
639 | +// 项目列表接口 | |
640 | +export const getProjectList = async (params: any) => { | |
641 | + console.log('getProjectList - params:', params); | |
642 | + const res = await defHttp.post<any>({ | |
643 | + url: '/project/list_by_/project/list', | |
644 | + params, | |
645 | + }); | |
646 | + console.log('getProjectList - raw response:', res); | |
647 | + | |
648 | + // 处理返回的数据格式 - 直接返回数组 | |
649 | + const formattedRecords = (res || []).map((record: any) => ({ | |
650 | + ...record, | |
651 | + })); | |
652 | + console.log('getProjectList - formattedRecords:', formattedRecords); | |
653 | + | |
654 | + return new Promise((resolve) => { | |
655 | + resolve({ | |
656 | + items: formattedRecords, | |
657 | + total: formattedRecords.length, | |
658 | + }); | |
659 | + }); | |
660 | +}; | |
661 | + | |
662 | +export const setBusinessDevStatusSend = async (params: any) => { | |
663 | + return await defHttp.post<any>({ | |
664 | + url: '/project/setDetailBusinessProfitStatus', | |
665 | + params, | |
666 | + }); | |
667 | +} | ... | ... |
src/components/SimpleMenu/src/components/menu.less
src/router/routes/modules/project/finance.ts
... | ... | @@ -59,16 +59,6 @@ const finance: AppRouteModule = { |
59 | 59 | ], |
60 | 60 | }, |
61 | 61 | children: [ |
62 | - // { | |
63 | - // path: '', | |
64 | - // name: 'Receive', | |
65 | - // meta: { | |
66 | - // title: '财务管理', | |
67 | - // roles: [RoleEnum.ADMIN, RoleEnum.FINANCE, RoleEnum.TRACKER, RoleEnum.BUSINESS], | |
68 | - // ignoreKeepAlive: false, | |
69 | - // }, | |
70 | - // // component: () => import('/@/views/project/finance/index.vue'), | |
71 | - // }, | |
72 | 62 | { |
73 | 63 | path: 'serviceProfit', |
74 | 64 | name: 'ServiceProfit', |
... | ... | @@ -82,7 +72,7 @@ const finance: AppRouteModule = { |
82 | 72 | path: 'ServiceProfit', |
83 | 73 | name: 'ServiceProfit', |
84 | 74 | meta: { |
85 | - title: '业务研发净利润分析表', | |
75 | + title: '业务研发净利润分析报价', | |
86 | 76 | roles: [RoleEnum.ADMIN, RoleEnum.FINANCE], |
87 | 77 | ignoreKeepAlive: false, |
88 | 78 | }, |
... | ... | @@ -92,6 +82,43 @@ const finance: AppRouteModule = { |
92 | 82 | ), |
93 | 83 | }, |
94 | 84 | { |
85 | + path: 'BusinessDevelopmentDetail', | |
86 | + name: 'BusinessDevelopmentDetail', | |
87 | + meta: { | |
88 | + title: '业务研发明细表', | |
89 | + roles: [RoleEnum.ADMIN, RoleEnum.FINANCE], | |
90 | + ignoreKeepAlive: false, | |
91 | + }, | |
92 | + component: () => | |
93 | + import( | |
94 | + '/@/views/project/finance/financeProfit/ServiceProfit/BusinessDevelopmentDetail/index.vue' | |
95 | + ), | |
96 | + }, | |
97 | + ], | |
98 | + }, | |
99 | + { | |
100 | + path: 'PackageProfit', | |
101 | + name: 'PackageProfit', | |
102 | + meta: { | |
103 | + title: '包装费用净利润分析', | |
104 | + roles: [RoleEnum.ADMIN, RoleEnum.FINANCE], | |
105 | + ignoreKeepAlive: false, | |
106 | + }, | |
107 | + children: [ | |
108 | + { | |
109 | + path: 'PackageProfitReport', | |
110 | + name: 'PackageProfitReport', | |
111 | + meta: { | |
112 | + title: '包装费用净利润分析报表', | |
113 | + roles: [RoleEnum.ADMIN, RoleEnum.FINANCE], | |
114 | + ignoreKeepAlive: false, | |
115 | + }, | |
116 | + component: () => | |
117 | + import( | |
118 | + '/@/views/project/finance/financeProfit/PackageProfit/PackageProfitReport/index.vue' | |
119 | + ), | |
120 | + }, | |
121 | + { | |
95 | 122 | path: 'PackageProfit', |
96 | 123 | name: 'PackageProfit', |
97 | 124 | meta: { |
... | ... | @@ -119,7 +146,7 @@ const finance: AppRouteModule = { |
119 | 146 | path: 'InnerProduce', |
120 | 147 | name: 'InnerProduce', |
121 | 148 | meta: { |
122 | - title: '内部生产净利润分析表', | |
149 | + title: '内部生产净利润分析报表', | |
123 | 150 | roles: [RoleEnum.ADMIN, RoleEnum.FINANCE], |
124 | 151 | ignoreKeepAlive: false, |
125 | 152 | }, |
... | ... | @@ -141,6 +168,41 @@ const finance: AppRouteModule = { |
141 | 168 | }, |
142 | 169 | ], |
143 | 170 | }, |
171 | + { | |
172 | + path: 'ExchangeProfit', | |
173 | + name: 'ExchangeProfit', | |
174 | + meta: { | |
175 | + title: '汇率收益利润汇总保报表', | |
176 | + roles: [RoleEnum.ADMIN, RoleEnum.FINANCE], | |
177 | + ignoreKeepAlive: false, | |
178 | + }, | |
179 | + children: [ | |
180 | + { | |
181 | + path: 'ExchangeProfitReport', | |
182 | + name: 'ExchangeProfitReport', | |
183 | + meta: { | |
184 | + title: '汇率收益利润汇总报表', | |
185 | + roles: [RoleEnum.ADMIN, RoleEnum.FINANCE], | |
186 | + ignoreKeepAlive: false, | |
187 | + }, | |
188 | + component: () => | |
189 | + import( | |
190 | + '/@/views/project/finance/financeProfit/ExchangeProfit/ExchangeProfitReport/index.vue' | |
191 | + ), | |
192 | + }, | |
193 | + { | |
194 | + path: 'ExchangeDetail', | |
195 | + name: 'ExchangeDetail', | |
196 | + meta: { | |
197 | + title: '汇率兑换明细表', | |
198 | + roles: [RoleEnum.ADMIN, RoleEnum.FINANCE], | |
199 | + ignoreKeepAlive: false, | |
200 | + }, | |
201 | + component: () => | |
202 | + import('/@/views/project/finance/financeProfit/ExchangeProfit/ExchangeDetail/index.vue'), | |
203 | + }, | |
204 | + ], | |
205 | + }, | |
144 | 206 | ], |
145 | 207 | }, |
146 | 208 | ], | ... | ... |
src/views/project/approve/data.ts
... | ... | @@ -109,6 +109,20 @@ export const FIELDS_BASE_INFO = [ |
109 | 109 | rules: [{ required: true }], |
110 | 110 | }, |
111 | 111 | { |
112 | + field: 'detailSpainPaidRmbCommission', | |
113 | + component: 'Select', | |
114 | + labelWidth: 150, | |
115 | + label: '西班牙已发提成¥', | |
116 | + rules: [{ required: true }], | |
117 | + }, | |
118 | + { | |
119 | + field: 'detailPaidRmbCommission', | |
120 | + component: 'Select', | |
121 | + labelWidth: 150, | |
122 | + label: '中国团队已发提成¥', | |
123 | + rules: [{ required: true }], | |
124 | + }, | |
125 | + { | |
112 | 126 | field: 'actualExchangeRate', |
113 | 127 | component: 'Select', |
114 | 128 | labelWidth: 150, | ... | ... |
src/views/project/finance/financeProfit/ServiceProfit/BusinessDevelopmentDetail/ApproveReason.vue
0 → 100644
1 | +<template> | |
2 | + <BasicModal | |
3 | + v-bind="$attrs" | |
4 | + destroyOnClose | |
5 | + @register="register" | |
6 | + title="申请原因" | |
7 | + :helpMessage="['提示1', '提示2']" | |
8 | + @open-change="handleShow" | |
9 | + :bodyStyle="{ height: '200px' }" | |
10 | + @ok="handleOk" | |
11 | + z-index="9999" | |
12 | + > | |
13 | + <a-textarea v-model:value="input" :rows="7" /> | |
14 | + </BasicModal> | |
15 | +</template> | |
16 | +<script lang="ts" setup> | |
17 | + import { ref, watch } from 'vue'; | |
18 | + import { BasicModal, useModalInner } from '@/components/Modal'; | |
19 | + import { orderAuth } from '/@/api/project/order'; | |
20 | + import { getBusinessDevelopmentApplyEdit } from '/@/api/project/invoice'; | |
21 | + import { getPackageApplyEdit } from '/@/api/project/invoice'; | |
22 | + | |
23 | + const emit = defineEmits(['success']); | |
24 | + const input = ref(''); | |
25 | + const baseFieldValues = ref(); | |
26 | + const [register, { setModalProps, redoModalHeight, closeModal }] = useModalInner(async (data) => { | |
27 | + baseFieldValues.value = data.data; | |
28 | + baseFieldValues.value.projectNoPrefix = data.projectNoPrefix; | |
29 | + }); | |
30 | + async function handleOk() { | |
31 | + baseFieldValues.value.applyRemark = input.value; | |
32 | + await getBusinessDevelopmentApplyEdit({ | |
33 | + projectNoPrefix: baseFieldValues.value.projectNoPrefix, | |
34 | + detailPaidRmbCommission: baseFieldValues.value.detailPaidRmbCommission, | |
35 | + detailSpainPaidRmbCommission: baseFieldValues.value.detailSpainPaidRmbCommission, | |
36 | + applyRemark: baseFieldValues.value.applyRemark, | |
37 | + type: 'ORDER_DEVELOPMENT_COST_FIELD_EDIT_APPLY', | |
38 | + }); | |
39 | + emit('success'); | |
40 | + setTimeout(() => { | |
41 | + closeModal(); | |
42 | + }, 50); | |
43 | + } | |
44 | + function handleShow() { | |
45 | + input.value = ''; | |
46 | + closeModal(); | |
47 | + } | |
48 | +</script> | ... | ... |
src/views/project/finance/financeProfit/ServiceProfit/BusinessDevelopmentDetail/CheckDetail.vue
0 → 100644
1 | +<template> | |
2 | + <div class="container"> | |
3 | + <BasicDrawer | |
4 | + @register="register" | |
5 | + v-bind="$attrs" | |
6 | + showFooter | |
7 | + title="字段编辑权限申请" | |
8 | + width="60%" | |
9 | + :destroyOnClose="true" | |
10 | + :isDetail="true" | |
11 | + @ok="handleSubmit" | |
12 | + :showDetailBack="false" | |
13 | + okText="申请" | |
14 | + ><input /> | |
15 | + <div> | |
16 | + <template v-if="role === ROLE.ADMIN || role === ROLE.FINANCE"> | |
17 | + <BasicForm @register="registerForm" /> | |
18 | + </template> | |
19 | + </div> | |
20 | + <!-- <template #titleToolbar> <a-button type="primary"> 申请编辑权限 </a-button></template> --> | |
21 | + | |
22 | + <!-- <template #appendFooter> | |
23 | + <a-button type="primary" @click="onGoFormDetail"> 返回编辑</a-button> | |
24 | + </template> --> | |
25 | + </BasicDrawer> | |
26 | + <ApproveReason @register="approveReasonRegister" @success="handleCloseModal" /> | |
27 | + </div> | |
28 | +</template> | |
29 | +<script lang="ts"> | |
30 | + import { computed, defineComponent, reactive, ref } from 'vue'; | |
31 | + import { BasicForm, useForm } from '/@/components/Form/index'; | |
32 | + import { getServiceApplyEdit } from '/@/api/project/invoice'; | |
33 | + import { ROLE } from '../../../financeList/type.d'; | |
34 | + import { useModal } from '/@/components/Modal'; | |
35 | + import ApproveReason from './ApproveReason.vue'; | |
36 | + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; | |
37 | + import { FIELDS_BASE_INFO } from './tableData'; | |
38 | + import { useUserStoreWithOut } from '/@/store/modules/user'; | |
39 | + | |
40 | + const userStore = useUserStoreWithOut(); | |
41 | + const getSchema = (fields) => | |
42 | + fields.map((item) => ({ | |
43 | + field: `${item.field}`, | |
44 | + dataIndex: `${item.field}`, | |
45 | + label: item.label, | |
46 | + component: 'Switch', | |
47 | + componentProps: { | |
48 | + checkedValue: 'UN_LOCKED', | |
49 | + unCheckedValue: 'LOCKED', | |
50 | + }, | |
51 | + colProps: { | |
52 | + span: 8, | |
53 | + }, | |
54 | + })); | |
55 | + | |
56 | + export default defineComponent({ | |
57 | + components: { BasicDrawer, BasicForm, ApproveReason }, | |
58 | + props: { | |
59 | + onGoFormDetail: { | |
60 | + type: Function, | |
61 | + }, | |
62 | + }, | |
63 | + setup() { | |
64 | + const projectNoPrefix = ref(''); | |
65 | + const schemas = getSchema(FIELDS_BASE_INFO); | |
66 | + const [registerForm, { getFieldsValue }] = useForm({ | |
67 | + labelWidth: 180, | |
68 | + schemas, | |
69 | + showActionButtonGroup: false, | |
70 | + actionColOptions: { | |
71 | + span: 24, | |
72 | + }, | |
73 | + }); | |
74 | + const [approveReasonRegister, { openModal: openApproveReasonDrawer }] = useModal(); | |
75 | + | |
76 | + const lockFields = reactive({}); | |
77 | + const [register, { closeDrawer }] = useDrawerInner((data) => { | |
78 | + Object.assign(lockFields, data.lockFields); | |
79 | + projectNoPrefix.value = data.projectNoPrefix; // 保存projectNoPrefix | |
80 | + }); | |
81 | + function handleCloseModal() { | |
82 | + closeDrawer(); | |
83 | + } | |
84 | + | |
85 | + const role = computed(() => { | |
86 | + return userStore.getUserInfo?.roleSmallVO?.code; | |
87 | + }); | |
88 | + | |
89 | + const handleSubmit = async () => { | |
90 | + const baseFieldValues = getFieldsValue(); | |
91 | + openApproveReasonDrawer(true, { | |
92 | + data: baseFieldValues, | |
93 | + projectNoPrefix: projectNoPrefix.value, // 传递projectNoPrefix,参数名为projectNo | |
94 | + }); | |
95 | + }; | |
96 | + | |
97 | + return { | |
98 | + register, | |
99 | + schemas, | |
100 | + registerForm, | |
101 | + handleSubmit, | |
102 | + handleCloseModal, | |
103 | + approveReasonRegister, | |
104 | + openApproveReasonDrawer, | |
105 | + ROLE, | |
106 | + role, | |
107 | + projectNoPrefix, | |
108 | + }; | |
109 | + }, | |
110 | + }); | |
111 | +</script> | |
112 | +<style> | |
113 | + .container { | |
114 | + position: fixed; /* 或 absolute, fixed */ | |
115 | + z-index: 10; | |
116 | + } | |
117 | +</style> | ... | ... |
src/views/project/finance/financeProfit/ServiceProfit/BusinessDevelopmentDetail/FinanceEdit.vue
0 → 100644
1 | +<template> | |
2 | + <template> | |
3 | + <BasicDrawer | |
4 | + @register="register" | |
5 | + v-bind="$attrs" | |
6 | + title="编辑" | |
7 | + width="30%" | |
8 | + :isDetail="true" | |
9 | + @ok="handleSubmit" | |
10 | + :showDetailBack="false" | |
11 | + okText="保存" | |
12 | + @visible-change="handleShow" | |
13 | + showFooter | |
14 | + :destroyOnClose="true" | |
15 | + > | |
16 | + <!-- <div> | |
17 | + <BasicForm @register="registerForm" /> | |
18 | + </div> --> | |
19 | + <div style="font-size: 15px">西班牙已发提成¥</div> | |
20 | + <a-input | |
21 | + v-model:value="input1" | |
22 | + placeholder="请输入" | |
23 | + :disabled="status2 === 'LOCKED'" | |
24 | + auto-size | |
25 | + /> | |
26 | + <div style="margin: 16px 0"></div> | |
27 | + <div style="font-size: 15px">中国团队已发提成¥</div> | |
28 | + <a-input | |
29 | + v-model:value="input2" | |
30 | + placeholder="请输入" | |
31 | + :disabled="status5 === 'LOCKED'" | |
32 | + auto-size | |
33 | + /> | |
34 | + <div style="margin: 16px 0"></div> | |
35 | + <!-- <template #titleToolbar> <a-button type="primary"> 申请编辑权限 </a-button></template> --> | |
36 | + <template #appendFooter> | |
37 | + <!-- <a-button type="primary" @click="onGoCheckDetail"> 申请权限</a-button> --> | |
38 | + </template> | |
39 | + </BasicDrawer> | |
40 | + </template> | |
41 | +</template> | |
42 | +<script lang="ts" setup> | |
43 | + import { BasicDrawer, useDrawerInner } from '@/components/Drawer'; | |
44 | + import { BasicForm, FormSchema, useForm } from '@/components/Form'; | |
45 | + import { defineComponent, ref, computed, unref, toRaw, reactive } from 'vue'; | |
46 | + import { getBusinessDevelopmentEdit } from '@/api/project/invoice'; | |
47 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
48 | + import { useUserStoreWithOut } from '/@/store/modules/user'; | |
49 | + import { ROLE } from './type.d'; | |
50 | + import type { Dayjs } from 'dayjs'; | |
51 | + import dayjs from 'dayjs'; | |
52 | + | |
53 | + const emit = defineEmits(['success']); | |
54 | + const userStore = useUserStoreWithOut(); | |
55 | + const user = userStore.getUserInfo; | |
56 | + const role = computed(() => { | |
57 | + return user?.roleSmallVO?.code; | |
58 | + }); | |
59 | + const schemas: FormSchema[] = [ | |
60 | + // { | |
61 | + // field: 'totalPayAmount', | |
62 | + // component: 'InputNumber', | |
63 | + // labelWidth: 250, | |
64 | + // colProps: { | |
65 | + // span: 23, | |
66 | + // }, | |
67 | + // label: '实际应收金额', | |
68 | + // }, | |
69 | + { | |
70 | + field: 'developmentCopyRmbTotalPrice', | |
71 | + component: 'InputNumber', | |
72 | + labelWidth: 250, | |
73 | + colProps: { | |
74 | + span: 23, | |
75 | + }, | |
76 | + // componentProps: () => ({ | |
77 | + // disabled: status.value === 10, | |
78 | + // }), | |
79 | + label: '研发复制费合计¥', | |
80 | + }, | |
81 | + { | |
82 | + field: 'actualPayedAmount2', | |
83 | + component: 'InputNumber', | |
84 | + labelWidth: 250, | |
85 | + colProps: { | |
86 | + span: 23, | |
87 | + }, | |
88 | + | |
89 | + label: '实际应收金额2$', | |
90 | + }, | |
91 | + { | |
92 | + field: 'actualPayedAmount3', | |
93 | + component: 'InputNumber', | |
94 | + labelWidth: 250, | |
95 | + colProps: { | |
96 | + span: 23, | |
97 | + }, | |
98 | + | |
99 | + label: '实际应收金额3$', | |
100 | + }, | |
101 | + { | |
102 | + field: 'otherAmount', | |
103 | + component: 'InputNumber', | |
104 | + labelWidth: 250, | |
105 | + colProps: { | |
106 | + span: 23, | |
107 | + }, | |
108 | + | |
109 | + label: '其他费用金额$', | |
110 | + }, | |
111 | + ]; | |
112 | + const [registerForm, { setFieldsValue, resetFields, validate }] = useForm({ | |
113 | + labelWidth: 120, | |
114 | + schemas, | |
115 | + layout: 'vertical', | |
116 | + showActionButtonGroup: false, | |
117 | + actionColOptions: { | |
118 | + span: 24, | |
119 | + }, | |
120 | + }); | |
121 | + const { createMessage } = useMessage(); | |
122 | + const { error } = createMessage; | |
123 | + | |
124 | + const update = ref(); | |
125 | + const status2 = ref(); | |
126 | + const status5 = ref(); | |
127 | + | |
128 | + const input1 = ref(); | |
129 | + const input2 = ref(); | |
130 | + const projectNoPrefix = ref(); | |
131 | + // function formatDate(dateStr: string): string { | |
132 | + // const date = new Date(dateStr); | |
133 | + // const year = date.getFullYear(); | |
134 | + // const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始,+1 | |
135 | + // const day = String(date.getDate()).padStart(2, '0'); | |
136 | + // const hours = String(date.getHours()).padStart(2, '0'); | |
137 | + // const minutes = String(date.getMinutes()).padStart(2, '0'); | |
138 | + // const seconds = String(date.getSeconds()).padStart(2, '0'); | |
139 | + | |
140 | + // // 返回格式化后的字符串:'YYYY-MM-DD HH:mm:ss' | |
141 | + // return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; | |
142 | + // } | |
143 | + function formatDateToDateOnly(dateStr: string): string { | |
144 | + const date = new Date(dateStr); | |
145 | + const year = date.getFullYear(); | |
146 | + const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始,+1 | |
147 | + const day = String(date.getDate()).padStart(2, '0'); | |
148 | + | |
149 | + // 返回格式化后的日期字符串:'YYYY-MM-DD' | |
150 | + return `${year}-${month}-${day}`; | |
151 | + } | |
152 | + const [register, { setDrawerProps, closeDrawer }] = useDrawerInner((data) => { | |
153 | + // 方式1 | |
154 | + if (data.data.lockFields) { | |
155 | + status2.value = data?.data?.lockFields?.detailSpainPaidRmbCommission; | |
156 | + status5.value = data?.data?.lockFields?.detailPaidRmbCommission; | |
157 | + } | |
158 | + projectNoPrefix.value = data?.data?.projectNoPrefix; | |
159 | + input1.value = data?.data?.spainPaidRmbCommission?.toFixed(2) || ''; | |
160 | + | |
161 | + input2.value = data?.data?.paidRmbCommission?.toFixed(2) || ''; | |
162 | + | |
163 | + resetFields(); | |
164 | + setDrawerProps({ confirmLoading: false }); | |
165 | + setFieldsValue({ | |
166 | + ...toRaw(data.data), | |
167 | + }); | |
168 | + update.value = data; | |
169 | + }); | |
170 | + const loading = ref(false); | |
171 | + //完成编辑 | |
172 | + async function handleSubmit() { | |
173 | + if (loading.value) return; | |
174 | + loading.value = true; | |
175 | + setDrawerProps({ confirmLoading: true }); | |
176 | + // const values = await validate(); | |
177 | + // const updatedValues = { | |
178 | + // ...values, | |
179 | + // id: update.value.data.id, | |
180 | + // bgUrl: update.value.data.bgUrl, | |
181 | + // }; | |
182 | + if (!input1.value || !input2.value) { | |
183 | + error('选项不能为空'); | |
184 | + loading.value = false; | |
185 | + setDrawerProps({ confirmLoading: false }); | |
186 | + } else { | |
187 | + try { | |
188 | + await getBusinessDevelopmentEdit({ | |
189 | + projectNoPrefix: projectNoPrefix.value, | |
190 | + detailSpainPaidRmbCommission: input1.value, | |
191 | + detailPaidRmbCommission: input2.value, | |
192 | + }); | |
193 | + emit('success'); | |
194 | + } finally { | |
195 | + loading.value = false; | |
196 | + setDrawerProps({ confirmLoading: false }); | |
197 | + closeDrawer(); | |
198 | + } | |
199 | + } | |
200 | + } | |
201 | + function handleShow(visible: boolean) { | |
202 | + if (!visible) { | |
203 | + input1.value = ''; | |
204 | + input2.value = ''; | |
205 | + } | |
206 | + } | |
207 | +</script> | ... | ... |
src/views/project/finance/financeProfit/ServiceProfit/BusinessDevelopmentDetail/HistoryDetail.vue
0 → 100644
1 | +<template> | |
2 | + <BasicDrawer | |
3 | + @register="register" | |
4 | + v-bind="$attrs" | |
5 | + title="操作记录" | |
6 | + width="60%" | |
7 | + :isDetail="true" | |
8 | + :showDetailBack="false" | |
9 | + okText="保存" | |
10 | + :destroyOnClose="true" | |
11 | + > | |
12 | + <Tabs v-model:activeKey="activeKey" className="my-0"> | |
13 | + <TabPanel :key="1" tab="操作记录" className="w-full"> | |
14 | + <a-list :pagination="pagination1" className="w-full"> | |
15 | + <template v-for="item in list1" :key="item.id"> | |
16 | + <a-list-item class="list"> | |
17 | + <a-list-item-meta> | |
18 | + <template #avatar> </template> | |
19 | + <template #title> | |
20 | + <span>{{ item.userName }}</span> | |
21 | + </template> | |
22 | + <template #description> | |
23 | + <div class="description"> | |
24 | + {{ item.optType }} | |
25 | + </div> | |
26 | + <div class="info"> | |
27 | + <div><span>操作时间:</span>{{ formatToDateTime(item.createTime) }}</div> | |
28 | + </div> | |
29 | + </template> | |
30 | + </a-list-item-meta> | |
31 | + </a-list-item> | |
32 | + </template> | |
33 | + </a-list> | |
34 | + </TabPanel> | |
35 | + <TabPanel :key="2" tab="审批记录" className="w-full"> | |
36 | + <a-list :pagination="pagination2" className="w-full"> | |
37 | + <template v-for="item in list2" :key="item.id"> | |
38 | + <a-list-item class="list"> | |
39 | + <a-list-item-meta> | |
40 | + <template #avatar> </template> | |
41 | + <template #title> | |
42 | + <span>{{ item.userName }}</span> | |
43 | + </template> | |
44 | + <template #description> | |
45 | + <div class="description"> | |
46 | + {{ item.optType }} | |
47 | + </div> | |
48 | + <div class="info"> | |
49 | + <div><span>操作时间:</span>{{ formatToDateTime(item.createTime) }}</div> | |
50 | + </div> | |
51 | + </template> | |
52 | + </a-list-item-meta> | |
53 | + </a-list-item> | |
54 | + </template> | |
55 | + </a-list> | |
56 | + </TabPanel> | |
57 | + </Tabs> | |
58 | + | |
59 | + <!-- <template #titleToolbar> <a-button type="primary"> 申请编辑权限 </a-button></template> --> | |
60 | + <template #appendFooter> | |
61 | + <!-- <a-button type="primary" @click="onGoCheckDetail"> 申请权限</a-button> --> | |
62 | + </template> | |
63 | + </BasicDrawer> | |
64 | +</template> | |
65 | +<script lang="ts"> | |
66 | + import { defineComponent, ref, computed } from 'vue'; | |
67 | + import { Tabs, Progress, Row, Col, List } from 'ant-design-vue'; | |
68 | + import { FormSchema, useForm } from '/@/components/Form/index'; | |
69 | + | |
70 | + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; | |
71 | + import { getProjectCostDetailedOptLog } from '/@/api/project/invoice'; | |
72 | + import { formatToDateTime } from '/@/utils/dateUtil'; | |
73 | + | |
74 | + const TabPanel = Tabs.TabPane; | |
75 | + | |
76 | + const schemas: FormSchema[] = [ | |
77 | + { | |
78 | + field: '订单号', | |
79 | + component: 'Input', | |
80 | + label: '字段1', | |
81 | + componentProps: { | |
82 | + readonly: true, | |
83 | + disabled: true, | |
84 | + }, | |
85 | + colProps: { | |
86 | + span: 12, | |
87 | + }, | |
88 | + defaultValue: '111', | |
89 | + }, | |
90 | + { | |
91 | + field: 'field2', | |
92 | + component: 'Input', | |
93 | + label: '字段2', | |
94 | + colProps: { | |
95 | + span: 12, | |
96 | + }, | |
97 | + }, | |
98 | + ]; | |
99 | + const achieveList = [ | |
100 | + { | |
101 | + key: '1', | |
102 | + name: '操作记录', | |
103 | + }, | |
104 | + { | |
105 | + key: '2', | |
106 | + name: '审批记录', | |
107 | + }, | |
108 | + ]; | |
109 | + export default defineComponent({ | |
110 | + components: { | |
111 | + BasicDrawer, | |
112 | + Tabs, | |
113 | + TabPanel, | |
114 | + [List.name]: List, | |
115 | + [List.Item.name]: List.Item, | |
116 | + AListItemMeta: List.Item.Meta, | |
117 | + }, | |
118 | + props: { | |
119 | + onGoCheckDetail: { | |
120 | + type: Function, | |
121 | + }, | |
122 | + }, | |
123 | + setup() { | |
124 | + const list1 = ref([]); | |
125 | + const total1 = ref(0); | |
126 | + const page1 = ref(1); | |
127 | + | |
128 | + const list2 = ref([]); | |
129 | + const total2 = ref(0); | |
130 | + const page2 = ref(1); | |
131 | + const projectNoPrefix = ref(''); | |
132 | + const activeKey = ref(1); | |
133 | + | |
134 | + const getOrderOptLogFunc = async (data, index, page) => { | |
135 | + // console.log('%c [ data ]-135', 'font-size:13px; background:pink; color:#bf2c9f;', data); | |
136 | + if (index === 1) { | |
137 | + const res = await getProjectCostDetailedOptLog({ | |
138 | + projectNoPrefix: data, | |
139 | + type: [50], | |
140 | + page: page, | |
141 | + pageSize: 20 | |
142 | + }); | |
143 | + list1.value = res.items; | |
144 | + total1.value = res.total; | |
145 | + page1.value = page; | |
146 | + } else { | |
147 | + const res = await getProjectCostDetailedOptLog({ | |
148 | + projectNoPrefix: data, | |
149 | + type: [4,5,6], | |
150 | + page: page, | |
151 | + pageSize: 20 | |
152 | + }); | |
153 | + list2.value = res.items; | |
154 | + total2.value = res.total; | |
155 | + page2.value = page; | |
156 | + } | |
157 | + }; | |
158 | + const [register] = useDrawerInner((data) => { | |
159 | + projectNoPrefix.value = data.data.projectNoPrefix; | |
160 | + getOrderOptLogFunc(projectNoPrefix.value, 1, 1); | |
161 | + getOrderOptLogFunc(projectNoPrefix.value, 2, 1); | |
162 | + }); | |
163 | + | |
164 | + const pagination1 = computed(() => { | |
165 | + return { | |
166 | + show: true, | |
167 | + pageSize: 20, | |
168 | + page: page1.value, | |
169 | + total: total1.value, | |
170 | + onChange(cur) { | |
171 | + getOrderOptLogFunc(projectNoPrefix.value, 1, cur); | |
172 | + }, | |
173 | + }; | |
174 | + }); | |
175 | + | |
176 | + const pagination2 = computed(() => { | |
177 | + return { | |
178 | + show: true, | |
179 | + pageSize: 20, | |
180 | + page: page1.value, | |
181 | + total: total1.value, | |
182 | + onChange(cur) { | |
183 | + getOrderOptLogFunc(projectNoPrefix.value, 2, cur); | |
184 | + }, | |
185 | + }; | |
186 | + }); | |
187 | + | |
188 | + return { | |
189 | + register, | |
190 | + schemas, | |
191 | + achieveList, | |
192 | + list1, | |
193 | + list2, | |
194 | + prefixCls: 'account-center', | |
195 | + pagination1, | |
196 | + pagination2, | |
197 | + activeKey, | |
198 | + formatToDateTime, | |
199 | + }; | |
200 | + }, | |
201 | + }); | |
202 | +</script> | ... | ... |
src/views/project/finance/financeProfit/ServiceProfit/BusinessDevelopmentDetail/InvoiceDetail.vue
0 → 100644
1 | +<template> | |
2 | + <BasicDrawer | |
3 | + @register="register" | |
4 | + v-bind="$attrs" | |
5 | + title="订单信息" | |
6 | + width="60%" | |
7 | + :isDetail="true" | |
8 | + :showDetailBack="false" | |
9 | + :destroyOnClose="true" | |
10 | + > | |
11 | + <div class="p-4"> | |
12 | + <BasicTable @register="registerTable" :bordered="true"> | |
13 | + <template #bodyCell="{ column, record }"> | |
14 | + <template v-if="column.key === 'picUrl'"> | |
15 | + <img :z-index="100000" :width="50" :height="50" :src="record?.picUrl" /> | |
16 | + </template> | |
17 | + </template> | |
18 | + </BasicTable> | |
19 | + </div> | |
20 | + </BasicDrawer> | |
21 | +</template> | |
22 | + | |
23 | +<script lang="ts" setup> | |
24 | + import { BasicDrawer, useDrawerInner } from '@/components/Drawer'; | |
25 | + import { BasicColumn, useTable, BasicTable } from '/@/components/Table'; | |
26 | + import { getProjectList } from '/@/api/project/invoice'; | |
27 | + import { ref } from 'vue'; | |
28 | + | |
29 | + // 定义表格列 | |
30 | + const columns: BasicColumn[] = [ | |
31 | + { | |
32 | + title: '客户编码', | |
33 | + dataIndex: 'customerCode', | |
34 | + width: 100, | |
35 | + }, | |
36 | + { | |
37 | + title: '项目号', | |
38 | + dataIndex: 'projectNo', | |
39 | + width: 100, | |
40 | + }, | |
41 | + { | |
42 | + title: '内部编号', | |
43 | + dataIndex: 'innerNo', | |
44 | + width: 100, | |
45 | + }, | |
46 | + { | |
47 | + title: '图片地址', | |
48 | + width: 150, | |
49 | + dataIndex: 'picUrl', | |
50 | + }, | |
51 | + { | |
52 | + title: '生产部门', | |
53 | + width: 150, | |
54 | + dataIndex: 'productionDepartment', | |
55 | + }, | |
56 | + { | |
57 | + title: '订单成分', | |
58 | + width: 150, | |
59 | + dataIndex: 'orderComposition', | |
60 | + }, | |
61 | + { | |
62 | + title: '客户po号', | |
63 | + width: 150, | |
64 | + dataIndex: 'customerPo', | |
65 | + }, | |
66 | + { | |
67 | + title: '款式类型', | |
68 | + width: 150, | |
69 | + dataIndex: 'productStyle', | |
70 | + }, | |
71 | + { | |
72 | + title: '客户Style', | |
73 | + width: 150, | |
74 | + dataIndex: 'customerStyle', | |
75 | + }, | |
76 | + { | |
77 | + title: '订单数量', | |
78 | + width: 150, | |
79 | + dataIndex: 'orderCount', | |
80 | + }, | |
81 | + { | |
82 | + title: '客户总价¥', | |
83 | + width: 150, | |
84 | + dataIndex: 'customerRmbTotalPrice', | |
85 | + }, | |
86 | + { | |
87 | + title: '客户总价$', | |
88 | + width: 150, | |
89 | + dataIndex: 'customerTotalPrice', | |
90 | + }, | |
91 | + { | |
92 | + title: '西班牙提成¥', | |
93 | + width: 150, | |
94 | + dataIndex: 'spainRmbCommission', | |
95 | + }, | |
96 | + { | |
97 | + title: '中国团队提成¥', | |
98 | + width: 150, | |
99 | + dataIndex: 'rmbCommission', | |
100 | + }, | |
101 | + { | |
102 | + title: '提成合计¥', | |
103 | + width: 150, | |
104 | + dataIndex: 'rmbTotalExpense', | |
105 | + }, | |
106 | + ]; | |
107 | + | |
108 | + const projectNo = ref(''); | |
109 | + | |
110 | + // 注册抽屉 | |
111 | + const [register] = useDrawerInner((data) => { | |
112 | + projectNo.value = data.data.projectNo; | |
113 | + }); | |
114 | + | |
115 | + // 注册表格 | |
116 | + const [registerTable] = useTable({ | |
117 | + api: async () => { | |
118 | + const result = await getProjectList({ projectNo: projectNo.value }); | |
119 | + return result; | |
120 | + }, | |
121 | + columns: columns, | |
122 | + bordered: true, | |
123 | + }); | |
124 | +</script> | |
125 | + | |
126 | +<style scoped> | |
127 | +</style> | |
0 | 128 | \ No newline at end of file | ... | ... |
src/views/project/finance/financeProfit/ServiceProfit/BusinessDevelopmentDetail/data.tsx
0 → 100644
1 | +import { InputNumber, Tag } from 'ant-design-vue'; | |
2 | +import { BasicColumn } from '@/components/Table'; | |
3 | +import { func } from 'vue-types'; | |
4 | +import { h, ref } from 'vue'; | |
5 | +import { FilePptOutlined } from '@ant-design/icons-vue'; | |
6 | +import axios from 'axios'; | |
7 | +import { queryNoOptions } from '/@/api/project/order'; | |
8 | +import { useOrderStoreWithOut } from '/@/store/modules/order'; | |
9 | +import { useOrderInfo } from '/@/hooks/component/order'; | |
10 | +import { useUserStoreWithOut } from '/@/store/modules/user'; | |
11 | + | |
12 | +const userStore = useUserStoreWithOut(); | |
13 | +// export const COLUMNS = [ | |
14 | +// { | |
15 | +// title: '客户编码', | |
16 | +// dataIndex: 'settingValue', | |
17 | +// width: 150, | |
18 | +// }, | |
19 | +// { | |
20 | +// title: '利润率', | |
21 | +// dataIndex: 'relationValue', | |
22 | +// width: 150, | |
23 | +// editComponent: 'InputNumber', | |
24 | +// editRow: true, | |
25 | +// scopedSlots: { customRender: 'name' } | |
26 | +// }, | |
27 | +// ]; | |
28 | +const innerNoOptions = ref([]); | |
29 | +const projectNoOptions = ref([]); | |
30 | +const allProjectNoOptions = ref<any[]>([]); | |
31 | +export { allProjectNoOptions }; | |
32 | +const orderStore = useOrderStoreWithOut(); | |
33 | +const { | |
34 | + customerCode, | |
35 | + productionDepartment, | |
36 | +} = useOrderInfo(orderStore); | |
37 | +export const searchFormSchema = [ | |
38 | + { | |
39 | + field: 'customerCode', | |
40 | + label: '客户编码', | |
41 | + component: 'Select', | |
42 | + colProps: { span: 8 }, | |
43 | + | |
44 | + componentProps: { | |
45 | + options: customerCode, | |
46 | + showSearch: true, | |
47 | + mode: 'multiple', | |
48 | + }, | |
49 | + }, | |
50 | + { | |
51 | + field: 'projectNo', | |
52 | + label: '项目号', | |
53 | + component: 'Select', | |
54 | + colProps: { span: 8 }, | |
55 | + | |
56 | + componentProps: { | |
57 | + options: projectNoOptions, | |
58 | + showSearch: true, | |
59 | + filterOption: false, | |
60 | + mode: 'multiple', | |
61 | + onSearch: async (value: any) => { | |
62 | + if (!value || value.trim() === '') { | |
63 | + return; | |
64 | + } | |
65 | + const result = await queryNoOptions('projectNo', value); | |
66 | + projectNoOptions.value = result; | |
67 | + allProjectNoOptions.value = result; | |
68 | + }, | |
69 | + }, | |
70 | + }, | |
71 | + { | |
72 | + field: 'productionDepartment', | |
73 | + label: '生产科', | |
74 | + component: 'Select', | |
75 | + colProps: { span: 8 }, | |
76 | + | |
77 | + componentProps: { | |
78 | + mode: 'multiple', | |
79 | + | |
80 | + options: productionDepartment, | |
81 | + showSearch: true, | |
82 | + }, | |
83 | + }, | |
84 | + { | |
85 | + field: 'innerNo', | |
86 | + label: '内部编号', | |
87 | + component: 'Select', | |
88 | + colProps: { span: 8 }, | |
89 | + | |
90 | + componentProps: { | |
91 | + options: innerNoOptions, | |
92 | + showSearch: true, | |
93 | + mode: 'multiple', | |
94 | + onSearch: async (value: any) => { | |
95 | + innerNoOptions.value = await queryNoOptions('innerNo', value); | |
96 | + }, | |
97 | + }, | |
98 | + }, | |
99 | + { | |
100 | + field: 'developmentStatus', | |
101 | + label: '状态', | |
102 | + component: 'Select', | |
103 | + colProps: { span: 8 }, | |
104 | + | |
105 | + componentProps: { | |
106 | + options: [ { | |
107 | + label: '未完成', | |
108 | + value: -1, | |
109 | + },{ | |
110 | + label: '待审核', | |
111 | + value: 0, | |
112 | + }, { | |
113 | + label: '已发放', | |
114 | + value: 1, | |
115 | + }, { | |
116 | + label: '应发但不发', | |
117 | + value: 2, | |
118 | + }], | |
119 | + }, | |
120 | + }, | |
121 | + // { | |
122 | + // field: 'productionDepartment', | |
123 | + // label: '生产科', | |
124 | + // component: 'Select', | |
125 | + // colProps: { span: 8 }, | |
126 | + | |
127 | + // componentProps: { | |
128 | + // mode: 'multiple', | |
129 | + | |
130 | + // options: productionDepartment, | |
131 | + // showSearch: true, | |
132 | + // }, | |
133 | + // }, | |
134 | + // { | |
135 | + // field: 'innerNo', | |
136 | + // label: '内部编号', | |
137 | + // component: 'Select', | |
138 | + // colProps: { span: 8 }, | |
139 | + | |
140 | + // componentProps: { | |
141 | + // options: innerNoOptions, | |
142 | + // showSearch: true, | |
143 | + // mode: 'multiple', | |
144 | + // onSearch: async (value: any) => { | |
145 | + // innerNoOptions.value = await queryNoOptions('innerNo', value); | |
146 | + // }, | |
147 | + // }, | |
148 | + // }, | |
149 | +] | |
150 | +export const COLUMNS = [ | |
151 | + { | |
152 | + title: '客户编码', | |
153 | + dataIndex: 'customerCode', | |
154 | + width: 150, | |
155 | + }, | |
156 | + { | |
157 | + title: '项目号', | |
158 | + dataIndex: 'projectNoPrefix', | |
159 | + // dataIndex: 'projectNo', | |
160 | + width: 140, | |
161 | + }, | |
162 | + { | |
163 | + title: '订单总数量', | |
164 | + dataIndex: 'orderCount', | |
165 | + width: 120, | |
166 | + customRender: (column) => { | |
167 | + return column.record?.orderCount; | |
168 | + }, | |
169 | + }, | |
170 | + { | |
171 | + title: '客户总金额¥', | |
172 | + width: 150, | |
173 | + dataIndex: 'customerTotalPrice', | |
174 | + customRender: (column) => { | |
175 | + return column.record?.customerRmbTotalPrice?.toFixed(2); | |
176 | + }, | |
177 | + }, | |
178 | + { | |
179 | + title: '客户总金额$', | |
180 | + width: 150, | |
181 | + dataIndex: 'customerTotalPrice', | |
182 | + customRender: (column) => { | |
183 | + return column.record?.customerTotalPrice?.toFixed(2); | |
184 | + }, | |
185 | + }, | |
186 | + { | |
187 | + title: '西班牙提成¥', | |
188 | + dataIndex: 'spainRmbCommission', | |
189 | + width: 150, | |
190 | + customRender: (column) => { | |
191 | + return column.record?.spainRmbCommission?.toFixed(2); | |
192 | + }, | |
193 | + }, | |
194 | + { | |
195 | + title: '已发提成¥', | |
196 | + dataIndex: 'spainPaidRmbCommission', | |
197 | + width: 120, | |
198 | + customRender: (column) => { | |
199 | + return column.record?.spainPaidRmbCommission?.toFixed(2); | |
200 | + }, | |
201 | + }, | |
202 | + { | |
203 | + title: '未发提成¥', | |
204 | + dataIndex: 'spainUnpaidRmbCommission', | |
205 | + width: 120, | |
206 | + customRender: (column) => { | |
207 | + return column.record?.spainUnpaidRmbCommission?.toFixed(2); | |
208 | + }, | |
209 | + }, | |
210 | + { | |
211 | + title: '中国团队提成¥', | |
212 | + dataIndex: 'rmbCommission', | |
213 | + width: 150, | |
214 | + customRender: (column) => { | |
215 | + return column.record?.rmbCommission?.toFixed(2); | |
216 | + }, | |
217 | + }, | |
218 | + { | |
219 | + title: '已发提成¥', | |
220 | + dataIndex: 'paidRmbCommission', | |
221 | + width: 120, | |
222 | + customRender: (column) => { | |
223 | + return column.record?.paidRmbCommission?.toFixed(2); | |
224 | + }, | |
225 | + }, | |
226 | + { | |
227 | + title: '未发提成¥', | |
228 | + dataIndex: 'unpaidRmbCommission', | |
229 | + width: 120, | |
230 | + customRender: (column) => { | |
231 | + return column.record?.unpaidRmbCommission?.toFixed(2); | |
232 | + }, | |
233 | + }, | |
234 | + { | |
235 | + title: '提成合计¥', | |
236 | + dataIndex: 'rmbTotalExpense', | |
237 | + width: 120, | |
238 | + customRender: (column) => { | |
239 | + return column.record?.rmbTotalExpense?.toFixed(2); | |
240 | + }, | |
241 | + }, | |
242 | + { | |
243 | + title: '状态', | |
244 | + dataIndex: 'detailDevelopmentStatus', | |
245 | + width: 120, | |
246 | + customRender: (column) => { | |
247 | + if (column.record?.detailDevelopmentStatus === null || column.record?.detailDevelopmentStatus === -1) { | |
248 | + return '未完成'; | |
249 | + } else if (column.record?.detailDevelopmentStatus === 0) { | |
250 | + return '待审核'; | |
251 | + } else if (column.record?.detailDevelopmentStatus === 1) { | |
252 | + return '已发放'; | |
253 | + } else if (column.record?.detailDevelopmentStatus === 2) { | |
254 | + return '应发但不发'; | |
255 | + } | |
256 | + }, | |
257 | + }, | |
258 | +]; | |
0 | 259 | \ No newline at end of file | ... | ... |
src/views/project/finance/financeProfit/ServiceProfit/BusinessDevelopmentDetail/index.vue
0 → 100644
1 | +<template> | |
2 | + <div> | |
3 | + <BasicTable @register="registerTable" :bordered="true" @field-value-change="handleFieldValueChange"> | |
4 | + <template #headerTop> | |
5 | + <a-alert type="info" show-icon> | |
6 | + <template #message> | |
7 | + <template v-if="checkedKeys.length > 0"> | |
8 | + <span>已选中{{ checkedKeys.length }}条记录(可跨页)</span> | |
9 | + <a-button | |
10 | + :style="{ borderRadius: '5px 5px 5px 5px' }" | |
11 | + type="link" | |
12 | + @click="handleClearChoose" | |
13 | + size="small" | |
14 | + >清空</a-button | |
15 | + > | |
16 | + </template> | |
17 | + <template v-else> | |
18 | + <span>未选中任何订单</span> | |
19 | + </template> | |
20 | + </template> | |
21 | + </a-alert> | |
22 | + </template> | |
23 | + <template #bodyCell="{ column, record }"> | |
24 | + <template v-if="column.key === 'picUrl'"> | |
25 | + <img :z-index="100000" :width="50" :height="50" :src="record?.picUrl" /> | |
26 | + </template> | |
27 | + <template v-if="column.key === 'action'"> | |
28 | + <TableAction | |
29 | + :actions="createActions(record)" | |
30 | + :dropDownActions="createDropActions(record)" | |
31 | + /> | |
32 | + </template> | |
33 | + </template> | |
34 | + <template #toolbar> | |
35 | + <a-dropdown | |
36 | + v-if="role == ROLE.ADMIN || role == ROLE.FINANCE" | |
37 | + :style="{ borderRadius: '5px 5px 5px 5px' }" | |
38 | + > | |
39 | + <a-button type="primary"> | |
40 | + 导出 | |
41 | + <DownOutlined /> | |
42 | + </a-button> | |
43 | + <template #overlay> | |
44 | + <a-menu @click="handleExportWithTeam"> | |
45 | + <a-menu-item key="0">中国团队</a-menu-item> | |
46 | + <a-menu-item key="1">西班牙团队</a-menu-item> | |
47 | + <a-menu-item key="2">所有团队</a-menu-item> | |
48 | + </a-menu> | |
49 | + </template> | |
50 | + </a-dropdown> | |
51 | + <a-button | |
52 | + type="primary" | |
53 | + @click="handleAllProjectNoQuery" | |
54 | + style="margin-left: 8px;position: fixed;right: 29%;top: 107.5px;" | |
55 | + >全选</a-button> | |
56 | + </template> | |
57 | + </BasicTable> | |
58 | + <CheckDetail @register="checkModalRegister" /> | |
59 | + <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" /> | |
60 | + <HistoryDetail @register="registerHistoryDetail" /> | |
61 | + <InvoiceDetail @register="registerOrderDetail" /> | |
62 | + </div> | |
63 | +</template> | |
64 | +<script setup lang="ts"> | |
65 | + import { BasicTable, useTable, TableAction } from '/@/components/Table'; | |
66 | + import { getBusinessDevelopmentDetail, setBusinessDevelopmentStatus, setBusinessDevStatusSend } from '@/api/project/invoice'; | |
67 | + import { saveConfig } from '@/api/sys/config'; | |
68 | + import { searchFormSchema, COLUMNS, allProjectNoOptions } from './data'; | |
69 | + import axios from 'axios'; | |
70 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
71 | + import { onMounted, ref, computed, unref, h } from 'vue'; | |
72 | + import { Modal } from 'ant-design-vue'; | |
73 | + import { DownOutlined } from '@ant-design/icons-vue'; | |
74 | + import { useDrawer } from '/@/components/Drawer'; | |
75 | + import FinanceEdit from './FinanceEdit.vue'; | |
76 | + import HistoryDetail from './HistoryDetail.vue'; | |
77 | + import CheckDetail from './CheckDetail.vue'; | |
78 | + import InvoiceDetail from './InvoiceDetail.vue'; | |
79 | + import { useUserStoreWithOut } from '/@/store/modules/user'; | |
80 | + import { ROLE } from '../../../type.d'; | |
81 | + import { useOrderStoreWithOut } from '/@/store/modules/order'; | |
82 | + | |
83 | + const { createMessage } = useMessage(); | |
84 | + const projectNoPrefixs = ref<string[]>([]); | |
85 | + const checkedKeys = ref<string[]>([]); | |
86 | + const invoiceIdKeys = ref<string[]>([]); | |
87 | + const checkIdKeys = ref<string[]>([]); | |
88 | + const detailProjectNoKeys = ref<string[]>([]); | |
89 | + const orderStore = useOrderStoreWithOut(); | |
90 | + const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer(); | |
91 | + const [registerFinanceEdit, { openDrawer: openFinanceEdit }] = useDrawer(); | |
92 | + const [registerHistoryDetail, { openDrawer: openHistoryDetail }] = useDrawer(); | |
93 | + const [registerOrderDetail, { openDrawer: openOrderDetail }] = useDrawer(); | |
94 | + const userStore = useUserStoreWithOut(); | |
95 | + const user = userStore.getUserInfo; | |
96 | + const role = computed(() => { | |
97 | + return user?.roleSmallVO?.code; | |
98 | + }); | |
99 | + const [registerTable, { reload, getSelectRowKeys, getDataSource, setSelectedRowKeys, setProps, getForm }] = useTable({ | |
100 | + title: '', | |
101 | + api: getBusinessDevelopmentDetail, | |
102 | + bordered: true, | |
103 | + columns: COLUMNS, | |
104 | + clickToRowSelect: false, | |
105 | + formConfig: { | |
106 | + labelWidth: 120, | |
107 | + schemas: searchFormSchema, | |
108 | + autoSubmitOnEnter: true, | |
109 | + resetFunc: async () => { | |
110 | + localStorage.removeItem('isAllSelected'); | |
111 | + setProps({ | |
112 | + searchInfo: { | |
113 | + projectNo: [] | |
114 | + } | |
115 | + }); | |
116 | + }, | |
117 | + }, | |
118 | + handleSearchInfoFn: (searchInfo) => { | |
119 | + | |
120 | + // 获取表单实例 | |
121 | + const formInstance = getForm(); | |
122 | + if (formInstance) { | |
123 | + const formValues = formInstance.getFieldsValue(); | |
124 | + | |
125 | + // 强制覆盖searchInfo,确保使用表单中的值 | |
126 | + if (formValues.projectNo && formValues.projectNo.length > 0) { | |
127 | + // 确保传递的是数组而不是Proxy对象,并去重 | |
128 | + const projectNoArray = [...new Set(formValues.projectNo)]; | |
129 | + // 强制覆盖,不使用原始值 | |
130 | + searchInfo = { | |
131 | + ...searchInfo, | |
132 | + projectNo: projectNoArray | |
133 | + }; | |
134 | + } else { | |
135 | + // 如果表单中没有项目号,清空查询条件 | |
136 | + searchInfo = { | |
137 | + ...searchInfo, | |
138 | + projectNo: [] | |
139 | + }; | |
140 | + } | |
141 | + } | |
142 | + | |
143 | + | |
144 | + return searchInfo; | |
145 | + }, | |
146 | + rowKey: (record) => record.projectNoPrefix, | |
147 | + rowSelection: { | |
148 | + type: 'checkbox', | |
149 | + selectedRowKeys: checkedKeys as any, | |
150 | + onSelect: onSelect, | |
151 | + onSelectAll: onSelectAll, | |
152 | + }, | |
153 | + useSearchForm: true, | |
154 | + showTableSetting: true, | |
155 | + showIndexColumn: false, | |
156 | + tableSetting: { | |
157 | + setting: false, | |
158 | + }, | |
159 | + actionColumn: { | |
160 | + width: 260, | |
161 | + title: 'Action', | |
162 | + dataIndex: 'action', | |
163 | + }, | |
164 | + }); | |
165 | + | |
166 | + function createActions(record: any): any[] { | |
167 | + if (!record.editable) { | |
168 | + const actions = [ | |
169 | + { | |
170 | + label: '财务编辑', | |
171 | + onClick: handleFinanceEdit.bind(null, record), | |
172 | + }, | |
173 | + { | |
174 | + label: '申请权限', | |
175 | + onClick: handleFalse.bind(null, record), | |
176 | + }, | |
177 | + ...(role.value === ROLE.ADMIN ? [ | |
178 | + { | |
179 | + label: '审核通过', | |
180 | + onClick: () => { | |
181 | + // 如果状态为未完成(-1),则不响应 | |
182 | + if (record.detailDevelopmentStatus === -1) { | |
183 | + createMessage.warning('订单状态未完成'); | |
184 | + return; | |
185 | + } | |
186 | + else{ | |
187 | + showAuditOptions(record); | |
188 | + } | |
189 | + }, | |
190 | + }, | |
191 | + ] : []), | |
192 | + ]; | |
193 | + return actions; | |
194 | + } | |
195 | + return [ | |
196 | + { | |
197 | + label: '保存', | |
198 | + onClick: handleSave.bind(null, record), | |
199 | + }, | |
200 | + { | |
201 | + label: '取消', | |
202 | + popConfirm: { | |
203 | + title: '是否取消编辑', | |
204 | + confirm: handleCancel.bind(null, record), | |
205 | + }, | |
206 | + }, | |
207 | + ]; | |
208 | + } | |
209 | + function createDropActions(record: any) { | |
210 | + if (!record.editable) { | |
211 | + const actions = [ | |
212 | + { | |
213 | + label: '订单信息', | |
214 | + onClick: handleOrderDetail.bind(null, record), | |
215 | + }, | |
216 | + { | |
217 | + label: '历史记录', | |
218 | + onClick: handleHistoryDetail.bind(null, record), | |
219 | + }, | |
220 | + // { | |
221 | + // label: '设置为应发但不发', | |
222 | + // onClick: handleSetStatus.bind(null, record), | |
223 | + // } | |
224 | + ]; | |
225 | + return actions; | |
226 | + } | |
227 | + } | |
228 | + | |
229 | + onMounted(async () => { | |
230 | + await orderStore.getDict(); | |
231 | + }); | |
232 | + | |
233 | + // 监听表单字段变化 | |
234 | + function handleFieldValueChange(field: string, value: any) { | |
235 | + // 如果是项目号字段变化且处于全选状态,同步更新查询条件 | |
236 | + if (field === 'projectNo' && localStorage.getItem('isAllSelected') === 'true') { | |
237 | + | |
238 | + // 确保value是数组格式,并去重 | |
239 | + const projectNoArray = Array.isArray(value) ? [...new Set(value)] : []; | |
240 | + | |
241 | + // 强制重新加载表格,使用新的查询条件 | |
242 | + reload({ | |
243 | + searchInfo: { | |
244 | + projectNo: projectNoArray | |
245 | + } | |
246 | + }); | |
247 | + | |
248 | + // 同时更新detailProjectNoKeys数组 | |
249 | + detailProjectNoKeys.value = projectNoArray; | |
250 | + | |
251 | + } | |
252 | + } | |
253 | + | |
254 | + function handleFinanceEdit(record) { | |
255 | + openFinanceEdit(true, { | |
256 | + data: record, | |
257 | + }); | |
258 | + } | |
259 | + | |
260 | + function handleFalse(record, e) { | |
261 | + openCheckDetailDrawer(true, record); | |
262 | + e?.stopPropagation(); | |
263 | + return false; | |
264 | + } | |
265 | + | |
266 | + function handleSuccess() { | |
267 | + setTimeout(() => { | |
268 | + reload(); | |
269 | + }, 50); | |
270 | + } | |
271 | + | |
272 | + async function handleSave(record) { | |
273 | + await saveConfig({ projectNo: record.projectNoPrefix, relationValue: record.relationValue }); | |
274 | + handleCancel(record); | |
275 | + reload(); | |
276 | + } | |
277 | + | |
278 | + function handleCancel(record) { | |
279 | + record.onEdit?.(false, false); | |
280 | + } | |
281 | + | |
282 | + async function handleStatus(record, status) { | |
283 | + try { | |
284 | + // 检查必要参数是否存在 | |
285 | + if (!record.projectNoPrefix) { | |
286 | + createMessage.error('缺少必要的参数:projectNoPrefix'); | |
287 | + return; | |
288 | + } | |
289 | + | |
290 | + // 根据不同的状态调用不同的接口 | |
291 | + if (status === 'approved') { | |
292 | + await setBusinessDevelopmentStatus({ | |
293 | + projectNo: record.projectNoPrefix, | |
294 | + customerCode: record.customerCode, | |
295 | + detailDevelopmentStatus: 1 // 审核通过状态 | |
296 | + }); | |
297 | + createMessage.success('审核通过成功!'); | |
298 | + } else if (status === 'completed') { | |
299 | + await setBusinessDevelopmentStatus({ | |
300 | + projectNo: record.projectNoPrefix, | |
301 | + customerCode: record.customerCode, | |
302 | + detailDevelopmentStatus: 1 // 已完成状态 | |
303 | + }); | |
304 | + createMessage.success('设置为已发放成功!'); | |
305 | + } else { | |
306 | + // 默认审核通过 | |
307 | + await setBusinessDevelopmentStatus({ | |
308 | + projectNo: record.projectNoPrefix, | |
309 | + customerCode: record.customerCode, | |
310 | + detailDevelopmentStatus: 1 // 默认审核通过状态 | |
311 | + }); | |
312 | + createMessage.success('状态更新成功!'); | |
313 | + } | |
314 | + | |
315 | + reload(); | |
316 | + } catch (error) { | |
317 | + console.error('Error updating status:', error); | |
318 | + createMessage.error('状态更新失败:' + (error.message || '未知错误')); | |
319 | + } | |
320 | + } | |
321 | + | |
322 | + async function handleHistoryDetail(record) { | |
323 | + openHistoryDetail(true, { | |
324 | + data: record, | |
325 | + }); | |
326 | + } | |
327 | + | |
328 | + async function handleSetStatus(record) { | |
329 | + await setBusinessDevStatusSend({ | |
330 | + projectNo: record.projectNoPrefix, | |
331 | + customerCode: record.customerCode, | |
332 | + detailDevelopmentStatus: 2 // 应发但不发状态 | |
333 | + }); | |
334 | + // 重新加载 | |
335 | + reload(); | |
336 | + } | |
337 | + | |
338 | + // 显示审核选项 | |
339 | + function showAuditOptions(record) { | |
340 | + // 检查当前状态 | |
341 | + const isReviewed = record.detailDevelopmentStatus === 1; // 已发放状态 | |
342 | + const isSentButNotPaid = record.detailDevelopmentStatus === 2; // 应发但不发状态 | |
343 | + | |
344 | + // 使用 Modal 显示选项 | |
345 | + Modal.confirm({ | |
346 | + title: '选择审核结果', | |
347 | + content: h('div', [ | |
348 | + h('div', { style: 'margin-top: 16px;' }, [ | |
349 | + h('button', { | |
350 | + style: isReviewed | |
351 | + ? 'margin-right: 8px; padding: 4px 8px; color: #666; background-color: #f5f5f5; border-radius: 2px; cursor: not-allowed; border: 1px solid #d9d9d9;' | |
352 | + : 'margin-right: 8px; padding: 4px 8px; color: white; background-color: #40a9ff; border-radius: 2px; cursor: pointer;', | |
353 | + disabled: isReviewed, // 如果已发放则禁用 | |
354 | + onClick: () => { | |
355 | + if (!isReviewed) { | |
356 | + Modal.destroyAll(); | |
357 | + handleStatus(record, 'approved'); // 审核通过 | |
358 | + } | |
359 | + } | |
360 | + }, isReviewed ? '已发放' : '已发放'), | |
361 | + h('button', { | |
362 | + style: (isReviewed || isSentButNotPaid) | |
363 | + ? 'margin-right: 8px; padding: 4px 8px; color: #666; background-color: #f5f5f5; border-radius: 2px; cursor: not-allowed; border: 1px solid #d9d9d9;' | |
364 | + : 'margin-right: 8px; padding: 4px 8px; color: white; background-color: #40a9ff; border-radius: 2px; cursor: pointer;', | |
365 | + disabled: isReviewed || isSentButNotPaid, // 如果已发放或应发但不发则禁用 | |
366 | + onClick: () => { | |
367 | + if (!isReviewed && !isSentButNotPaid) { | |
368 | + Modal.destroyAll(); | |
369 | + handleSetStatus(record); // 应发但不发 | |
370 | + } | |
371 | + } | |
372 | + }, (isReviewed || isSentButNotPaid) ? '应发但不发' : '应发但不发'), | |
373 | + ]) | |
374 | + ]), | |
375 | + onCancel: () => { | |
376 | + Modal.destroyAll(); | |
377 | + } | |
378 | + }); | |
379 | + } | |
380 | + | |
381 | + function handleExportWithTeam({ key }: { key: string }) { | |
382 | + // Get current search parameters from the form | |
383 | + const values = getForm().getFieldsValue(); | |
384 | + | |
385 | + // Create export parameters based on whether projectNoPrefixs are selected | |
386 | + let exportParams; | |
387 | + | |
388 | + // If projectNoPrefixs are selected, only use those and ignore search params | |
389 | + if (projectNoPrefixs.value.length > 0) { | |
390 | + exportParams = { | |
391 | + projectNos: projectNoPrefixs.value, // 复选选中的项目号使用 projectNos | |
392 | + selectExcel: parseInt(key) // 添加团队选择参数 | |
393 | + }; | |
394 | + } | |
395 | + // Otherwise use the search parameters | |
396 | + else { | |
397 | + exportParams = { | |
398 | + ...values, | |
399 | + projectNo: values.projectNo || undefined, // 搜索框的项目号使用 projectNo | |
400 | + customerCode: values.customerCode || undefined, | |
401 | + innerNo: values.innerNo || undefined, | |
402 | + productionDepartment: values.productionDepartment || undefined, | |
403 | + selectExcel: parseInt(key) // 添加团队选择参数 | |
404 | + }; | |
405 | + } | |
406 | + | |
407 | + | |
408 | + const token = userStore.getToken; | |
409 | + axios | |
410 | + .post( | |
411 | + '/basic-api/project/detailBusinessProfit/exportExcel', | |
412 | + exportParams, | |
413 | + { | |
414 | + headers: { | |
415 | + Authorization: `${token}`, // 去掉引号 | |
416 | + }, | |
417 | + responseType: 'blob', // 设置响应类型为 'blob' | |
418 | + }, | |
419 | + ) | |
420 | + .then((response) => { | |
421 | + // 创建一个 Blob 对象来保存二进制数据 | |
422 | + const blob = new Blob([response.data], { type: 'application/zip' }); | |
423 | + const getFormattedDate = (): string => { | |
424 | + const date = new Date(); | |
425 | + | |
426 | + const year = date.getFullYear(); | |
427 | + const month = String(date.getMonth() + 1).padStart(2, '0'); | |
428 | + const day = String(date.getDate()).padStart(2, '0'); | |
429 | + | |
430 | + const hours = String(date.getHours()).padStart(2, '0'); | |
431 | + const minutes = String(date.getMinutes()).padStart(2, '0'); | |
432 | + const seconds = String(date.getSeconds()).padStart(2, '0'); | |
433 | + | |
434 | + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; | |
435 | + }; | |
436 | + const date = getFormattedDate(); | |
437 | + // 创建一个链接元素用于下载 | |
438 | + const link = document.createElement('a'); | |
439 | + link.href = window.URL.createObjectURL(blob); | |
440 | + link.download = `业务研发明细表${date}.xlsx`; // 你可以为文件命名 | |
441 | + document.body.appendChild(link); | |
442 | + link.click(); // 自动点击链接,触发下载 | |
443 | + document.body.removeChild(link); // 下载完成后移除链接 | |
444 | + }) | |
445 | + .catch((error) => { | |
446 | + console.error(error); | |
447 | + }); | |
448 | + handleClearChoose(); | |
449 | + reload(); | |
450 | + } | |
451 | + | |
452 | + function handleExport() { | |
453 | + // Get current search parameters from the form | |
454 | + const values = getForm().getFieldsValue(); | |
455 | + | |
456 | + // Create export parameters based on whether projectNoPrefixs are selected | |
457 | + let exportParams; | |
458 | + | |
459 | + // If projectNoPrefixs are selected, only use those and ignore search params | |
460 | + if (projectNoPrefixs.value.length > 0) { | |
461 | + exportParams = { | |
462 | + projectNos: projectNoPrefixs.value // 复选选中的项目号使用 projectNos | |
463 | + }; | |
464 | + } | |
465 | + // Otherwise use the search parameters | |
466 | + else { | |
467 | + exportParams = { | |
468 | + ...values, | |
469 | + projectNo: values.projectNo || undefined, // 搜索框的项目号使用 projectNo | |
470 | + customerCode: values.customerCode || undefined, | |
471 | + innerNo: values.innerNo || undefined, | |
472 | + productionDepartment: values.productionDepartment || undefined | |
473 | + }; | |
474 | + } | |
475 | + | |
476 | + | |
477 | + const token = userStore.getToken; | |
478 | + axios | |
479 | + .post( | |
480 | + '/basic-api/project/detailBusinessProfit/exportExcel', | |
481 | + exportParams, | |
482 | + { | |
483 | + headers: { | |
484 | + Authorization: `${token}`, // 去掉引号 | |
485 | + }, | |
486 | + responseType: 'blob', // 设置响应类型为 'blob' | |
487 | + }, | |
488 | + ) | |
489 | + .then((response) => { | |
490 | + // 创建一个 Blob 对象来保存二进制数据 | |
491 | + const blob = new Blob([response.data], { type: 'application/zip' }); | |
492 | + const getFormattedDate = (): string => { | |
493 | + const date = new Date(); | |
494 | + | |
495 | + const year = date.getFullYear(); | |
496 | + const month = String(date.getMonth() + 1).padStart(2, '0'); | |
497 | + const day = String(date.getDate()).padStart(2, '0'); | |
498 | + | |
499 | + const hours = String(date.getHours()).padStart(2, '0'); | |
500 | + const minutes = String(date.getMinutes()).padStart(2, '0'); | |
501 | + const seconds = String(date.getSeconds()).padStart(2, '0'); | |
502 | + | |
503 | + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; | |
504 | + }; | |
505 | + const date = getFormattedDate(); | |
506 | + // 创建一个链接元素用于下载 | |
507 | + const link = document.createElement('a'); | |
508 | + link.href = window.URL.createObjectURL(blob); | |
509 | + link.download = `业务研发明细表${date}.xlsx`; // 你可以为文件命名 | |
510 | + document.body.appendChild(link); | |
511 | + link.click(); // 自动点击链接,触发下载 | |
512 | + document.body.removeChild(link); // 下载完成后移除链接 | |
513 | + }) | |
514 | + .catch((error) => { | |
515 | + console.error(error); | |
516 | + }); | |
517 | + handleClearChoose(); | |
518 | + reload(); | |
519 | + } | |
520 | + | |
521 | + function handleClearChoose() { | |
522 | + checkedKeys.value = []; | |
523 | + projectNoPrefixs.value = []; | |
524 | + detailProjectNoKeys.value = []; | |
525 | + invoiceIdKeys.value = []; | |
526 | + checkIdKeys.value = []; | |
527 | + } | |
528 | + | |
529 | + async function onSelect(record, selected: boolean) { | |
530 | + const rowKey = record.projectNoPrefix; | |
531 | + if (selected) { | |
532 | + if (!checkedKeys.value.includes(rowKey)) { | |
533 | + checkedKeys.value.push(rowKey); | |
534 | + } | |
535 | + if (record.projectNoPrefix !== undefined && !projectNoPrefixs.value.includes(record.projectNoPrefix)) { | |
536 | + projectNoPrefixs.value.push(record.projectNoPrefix); | |
537 | + } | |
538 | + } else { | |
539 | + checkedKeys.value = checkedKeys.value.filter((key) => key !== rowKey); | |
540 | + if (record.projectNoPrefix !== undefined) { | |
541 | + projectNoPrefixs.value = projectNoPrefixs.value.filter(projectNo => projectNo !== record.projectNoPrefix); | |
542 | + } | |
543 | + } | |
544 | + setSelectedRowKeys(checkedKeys.value as any); | |
545 | + } | |
546 | + | |
547 | + function onSelectAll(selected: boolean, selectedRows: any[]) { | |
548 | + if (selected) { | |
549 | + checkedKeys.value = selectedRows | |
550 | + .map(row => row && row.projectNoPrefix) | |
551 | + .filter((key, idx, arr) => key !== undefined && arr.indexOf(key) === idx); | |
552 | + projectNoPrefixs.value = checkedKeys.value.slice(); | |
553 | + } else { | |
554 | + checkedKeys.value = []; | |
555 | + projectNoPrefixs.value = []; | |
556 | + } | |
557 | + setSelectedRowKeys(checkedKeys.value as any); | |
558 | + } | |
559 | + // 6/25未完成工作:全选查询 | |
560 | + function handleAllProjectNoQuery() { | |
561 | + // 检查是否有项目号选项 | |
562 | + if (!allProjectNoOptions.value || allProjectNoOptions.value.length === 0) { | |
563 | + createMessage.warn('没有可查询的项目号!'); | |
564 | + return; | |
565 | + } | |
566 | + | |
567 | + // 获取所有项目号的value值 | |
568 | + const allProjectNos = allProjectNoOptions.value.map((item: any) => { | |
569 | + // 处理不同的数据结构 | |
570 | + if (typeof item === 'string') { | |
571 | + return item; | |
572 | + } else if (item && typeof item === 'object' && 'value' in item) { | |
573 | + return item.value; | |
574 | + } else if (item && typeof item === 'object' && 'label' in item) { | |
575 | + return item.label; | |
576 | + } | |
577 | + return item; | |
578 | + }).filter(Boolean); // 过滤掉空值 | |
579 | + | |
580 | + if (allProjectNos.length === 0) { | |
581 | + createMessage.warn('没有有效的项目号!'); | |
582 | + return; | |
583 | + } | |
584 | + | |
585 | + try { | |
586 | + // 提示用户全选成功 | |
587 | + createMessage.success(`已全选 ${allProjectNos.length} 个项目号`); | |
588 | + | |
589 | + // 获取表单实例并设置表单值,将项目号填入搜索框 | |
590 | + const formInstance = getForm(); | |
591 | + if (formInstance && formInstance.setFieldsValue) { | |
592 | + formInstance.setFieldsValue({ | |
593 | + projectNo: allProjectNos | |
594 | + }); | |
595 | + } | |
596 | + | |
597 | + // 将allProjectNoOptions更新为已勾选的项目号数组,这样用户取消勾选时数组会同步更新 | |
598 | + allProjectNoOptions.value = allProjectNos.map((projectNo: any) => ({ | |
599 | + label: projectNo, | |
600 | + value: projectNo | |
601 | + })); | |
602 | + | |
603 | + // 标记为全选状态 | |
604 | + localStorage.setItem('isAllSelected', 'true'); | |
605 | + } catch (error) { | |
606 | + console.error('全选失败:', error); | |
607 | + createMessage.error('全选失败,请检查网络连接!'); | |
608 | + } | |
609 | + } | |
610 | + | |
611 | + async function handleOrderDetail(record) { | |
612 | + // 打开订单信息抽屉 | |
613 | + openOrderDetail(true, { | |
614 | + data: { | |
615 | + projectNo: record.projectNoPrefix || record.projectNo | |
616 | + }, | |
617 | + }); | |
618 | + } | |
619 | +</script> | |
620 | +<style></style> | ... | ... |
src/views/project/finance/financeProfit/ServiceProfit/BusinessDevelopmentDetail/tableData.tsx
0 → 100644
1 | +import { ref } from 'vue'; | |
2 | +import { ROLE } from '../../../financeList/type.d'; | |
3 | +import { queryNoOptions } from '/@/api/project/order'; | |
4 | +import { useOrderInfo } from '/@/hooks/component/order'; | |
5 | +import { useOrderStoreWithOut } from '/@/store/modules/order'; | |
6 | +import { formatToDate } from '/@/utils/dateUtil'; | |
7 | + | |
8 | +// 角色 | |
9 | +// 业务员- 查看all,编辑-利润分析,报告书 | |
10 | +// 跟单员- 查看利润分析(单价和总金额),跟单,质检,编辑 | |
11 | +// 质检员- 查看跟单,质检,编辑质检 | |
12 | + | |
13 | +const innerNoOptions = ref([]); | |
14 | +const projectNoOptions = ref([]); | |
15 | +const orderStore = useOrderStoreWithOut(); | |
16 | +// const { productionDepartment: productionDepartmentOptions } = useOrderInfo(orderStore); | |
17 | + | |
18 | +/** | |
19 | + * drawer面板的字段 | |
20 | + */ | |
21 | +// 基本信息 | |
22 | +export const FIELDS_BASE_INFO = [ | |
23 | + { | |
24 | + field: 'detailSpainPaidRmbCommission', | |
25 | + component: 'Select', | |
26 | + labelWidth: 150, | |
27 | + label: '西班牙已发提成¥', | |
28 | + rules: [{ required: true }], | |
29 | + }, | |
30 | + { | |
31 | + field: 'detailPaidRmbCommission', | |
32 | + component: 'Select', | |
33 | + labelWidth: 150, | |
34 | + label: '中国团队已发提成¥', | |
35 | + rules: [{ required: true }], | |
36 | + }, | |
37 | +]; | ... | ... |