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,20 +43,23 @@ enum Api { | ||
43 | PACKAGEPROFIT = '/order/cost/BusinessProfitDetail/listByPage', //包装费用明细表 | 43 | PACKAGEPROFIT = '/order/cost/BusinessProfitDetail/listByPage', //包装费用明细表 |
44 | INNERPROFIT = '/order/cost/InnerProfitDetail/listByPage', //内部生产费用明细表 | 44 | INNERPROFIT = '/order/cost/InnerProfitDetail/listByPage', //内部生产费用明细表 |
45 | PACKAGEEDIT = '/order/cost/edit', //编辑 | 45 | PACKAGEEDIT = '/order/cost/edit', //编辑 |
46 | + BUSINESSDEVELOPMENTEDIT = '/project/edit', //业务研发明细表编辑 | ||
46 | PACKAGEAPPLYEDIT = '/order/cost/applyEditFileds', //申请编辑字段 | 47 | PACKAGEAPPLYEDIT = '/order/cost/applyEditFileds', //申请编辑字段 |
47 | SERVICEPROFIT = '/project/BusinessProfitInfo/listByPage', //业务研发净利润分析表 | 48 | SERVICEPROFIT = '/project/BusinessProfitInfo/listByPage', //业务研发净利润分析表 |
48 | INNERPRODUCEPROFIT = '/project/InnerProfitInfo/listByPage', //内部生产利润分析表 | 49 | INNERPRODUCEPROFIT = '/project/InnerProfitInfo/listByPage', //内部生产利润分析表 |
49 | SERVICEPROFITEXPORT = '/project/businessProfit/export', //业务研发净利润分析表导出 | 50 | SERVICEPROFITEXPORT = '/project/businessProfit/export', //业务研发净利润分析表导出 |
50 | INNERPROFITEXPORT = '/project/innerProfit/export', //内部研发净利润分析表导出 | 51 | INNERPROFITEXPORT = '/project/innerProfit/export', //内部研发净利润分析表导出 |
51 | SERVICEEDIT = '/project/edit', //编辑 | 52 | SERVICEEDIT = '/project/edit', //编辑 |
52 | - SERVICEAPPLYEDIT = '/project/applyEditFileds', //申请修改 | 53 | + SERVICEAPPLYEDIT = '/project/applyEditFileds', //申请字段编辑权限申请 |
53 | APPLYLIST = '/project/pageProjectLockFieldApply', //分页查询项目字段申请记录 | 54 | APPLYLIST = '/project/pageProjectLockFieldApply', //分页查询项目字段申请记录 |
54 | AUDITAPPLY = '/project/audit', //审核 | 55 | AUDITAPPLY = '/project/audit', //审核 |
55 | ACTIONRECORD = '/projectOptLog/listByPage', //业务/内部研发净利润操作记录以及申请记录 | 56 | ACTIONRECORD = '/projectOptLog/listByPage', //业务/内部研发净利润操作记录以及申请记录 |
56 | ORDERCOSTDETAILEDOPTLOG = '/orderCostDetailedOptLog/listByPage', //包装费用明细/内部生产明细操作记录表 | 57 | ORDERCOSTDETAILEDOPTLOG = '/orderCostDetailedOptLog/listByPage', //包装费用明细/内部生产明细操作记录表 |
58 | + PROJECTCOSTDETAILEDOPTLOG = '/projectOptLog/listByPage', //业务研发明细表操作记录表 | ||
57 | SETPACKSTATUS = '/order/cost/setPackStatus', //包装费用明细表审批 | 59 | SETPACKSTATUS = '/order/cost/setPackStatus', //包装费用明细表审批 |
58 | SETINNERSTATUS = '/order/cost/setInnerStatus', //内部生产明细表审批 | 60 | SETINNERSTATUS = '/order/cost/setInnerStatus', //内部生产明细表审批 |
59 | PROJECTBUSINESSPROFITSETSTATUS = '/project/businessProfit/setStatus', //业务研发净利润分析表审批 | 61 | PROJECTBUSINESSPROFITSETSTATUS = '/project/businessProfit/setStatus', //业务研发净利润分析表审批 |
62 | + PROJECTBUSINESSDEVELOPMENTSETSTATUS = '/project/setDetailBusinessProfitStatus', //业务研发明细表审核通过 | ||
60 | PROJECTINNERPROFITSETSTATUS = '/project/innerProfitInfo/setStatus', //内部研发净利润分析表审批 | 63 | PROJECTINNERPROFITSETSTATUS = '/project/innerProfitInfo/setStatus', //内部研发净利润分析表审批 |
61 | } | 64 | } |
62 | 65 | ||
@@ -427,12 +430,25 @@ export const getServiceEdit = async (params: any) => { | @@ -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 | export const getServiceApplyEdit = async (params: any) => { | 440 | export const getServiceApplyEdit = async (params: any) => { |
431 | return await defHttp.post<any>({ | 441 | return await defHttp.post<any>({ |
432 | url: Api.SERVICEAPPLYEDIT, | 442 | url: Api.SERVICEAPPLYEDIT, |
433 | params, | 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 | export const getApplyList = async (params: any) => { | 453 | export const getApplyList = async (params: any) => { |
438 | // const res = ref(); | 454 | // const res = ref(); |
@@ -516,16 +532,43 @@ export const getProjectOptLog = async (params: any) => { | @@ -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 | export const getOrderCostDetailedOptLog = async (params: any) => { | 559 | export const getOrderCostDetailedOptLog = async (params: any) => { |
520 | const res = await defHttp.post<any>({ | 560 | const res = await defHttp.post<any>({ |
521 | url: Api.ORDERCOSTDETAILEDOPTLOG, | 561 | url: Api.ORDERCOSTDETAILEDOPTLOG, |
522 | params, | 562 | params, |
523 | }); | 563 | }); |
564 | + | ||
565 | + | ||
524 | const formattedRecords = res.records.map((record: any) => { | 566 | const formattedRecords = res.records.map((record: any) => { |
525 | return { | 567 | return { |
526 | ...record, | 568 | ...record, |
527 | }; | 569 | }; |
528 | }); | 570 | }); |
571 | + | ||
529 | const orderStore = useOrderStoreWithOut(); | 572 | const orderStore = useOrderStoreWithOut(); |
530 | orderStore.setTotal(res.total); | 573 | orderStore.setTotal(res.total); |
531 | orderStore.setQueryVO(params); | 574 | orderStore.setQueryVO(params); |
@@ -569,3 +612,56 @@ export const setCommissionStatus = async (data: { orderId: number[] }) => { | @@ -569,3 +612,56 @@ export const setCommissionStatus = async (data: { orderId: number[] }) => { | ||
569 | data, | 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
@@ -302,6 +302,7 @@ | @@ -302,6 +302,7 @@ | ||
302 | .@{menu-prefix-cls}-submenu-has-parent-submenu { | 302 | .@{menu-prefix-cls}-submenu-has-parent-submenu { |
303 | .@{menu-prefix-cls}-submenu-title { | 303 | .@{menu-prefix-cls}-submenu-title { |
304 | background-color: transparent; | 304 | background-color: transparent; |
305 | + color: rgb(0, 147, 245); | ||
305 | } | 306 | } |
306 | } | 307 | } |
307 | } | 308 | } |
src/router/routes/modules/project/finance.ts
@@ -59,16 +59,6 @@ const finance: AppRouteModule = { | @@ -59,16 +59,6 @@ const finance: AppRouteModule = { | ||
59 | ], | 59 | ], |
60 | }, | 60 | }, |
61 | children: [ | 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 | path: 'serviceProfit', | 63 | path: 'serviceProfit', |
74 | name: 'ServiceProfit', | 64 | name: 'ServiceProfit', |
@@ -82,7 +72,7 @@ const finance: AppRouteModule = { | @@ -82,7 +72,7 @@ const finance: AppRouteModule = { | ||
82 | path: 'ServiceProfit', | 72 | path: 'ServiceProfit', |
83 | name: 'ServiceProfit', | 73 | name: 'ServiceProfit', |
84 | meta: { | 74 | meta: { |
85 | - title: '业务研发净利润分析表', | 75 | + title: '业务研发净利润分析报价', |
86 | roles: [RoleEnum.ADMIN, RoleEnum.FINANCE], | 76 | roles: [RoleEnum.ADMIN, RoleEnum.FINANCE], |
87 | ignoreKeepAlive: false, | 77 | ignoreKeepAlive: false, |
88 | }, | 78 | }, |
@@ -92,6 +82,43 @@ const finance: AppRouteModule = { | @@ -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 | path: 'PackageProfit', | 122 | path: 'PackageProfit', |
96 | name: 'PackageProfit', | 123 | name: 'PackageProfit', |
97 | meta: { | 124 | meta: { |
@@ -119,7 +146,7 @@ const finance: AppRouteModule = { | @@ -119,7 +146,7 @@ const finance: AppRouteModule = { | ||
119 | path: 'InnerProduce', | 146 | path: 'InnerProduce', |
120 | name: 'InnerProduce', | 147 | name: 'InnerProduce', |
121 | meta: { | 148 | meta: { |
122 | - title: '内部生产净利润分析表', | 149 | + title: '内部生产净利润分析报表', |
123 | roles: [RoleEnum.ADMIN, RoleEnum.FINANCE], | 150 | roles: [RoleEnum.ADMIN, RoleEnum.FINANCE], |
124 | ignoreKeepAlive: false, | 151 | ignoreKeepAlive: false, |
125 | }, | 152 | }, |
@@ -141,6 +168,41 @@ const finance: AppRouteModule = { | @@ -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,6 +109,20 @@ export const FIELDS_BASE_INFO = [ | ||
109 | rules: [{ required: true }], | 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 | field: 'actualExchangeRate', | 126 | field: 'actualExchangeRate', |
113 | component: 'Select', | 127 | component: 'Select', |
114 | labelWidth: 150, | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | +]; |