Commit c1f5be7741d0723a3ecd908473a8ca720ba3dcfe

Authored by 柏杨
2 parents cfb654e3 655ab711

fix: bug修复

Showing 41 changed files with 2862 additions and 492 deletions
src/api/project/approve.ts
@@ -21,12 +21,11 @@ export const approveAuditApi = async (params: any) => @@ -21,12 +21,11 @@ export const approveAuditApi = async (params: any) =>
21 { message: '操作成功' }, 21 { message: '操作成功' },
22 ); 22 );
23 23
24 -export const getWaitListApi = async (params: DemoParams) => { 24 +export const getWaitListApi = async (params: any) => {
25 const res = await defHttp.post({ 25 const res = await defHttp.post({
26 url: Api.APPROVE, 26 url: Api.APPROVE,
27 params, 27 params,
28 }); 28 });
29 -  
30 res.records = res.records.map((item) => { 29 res.records = res.records.map((item) => {
31 return item; 30 return item;
32 }); 31 });
@@ -44,7 +43,6 @@ export const getApprovedListApi = async (params: any) => { @@ -44,7 +43,6 @@ export const getApprovedListApi = async (params: any) => {
44 res.records = res.records.map((item) => { 43 res.records = res.records.map((item) => {
45 return item; 44 return item;
46 }); 45 });
47 -  
48 return new Promise((resolve) => { 46 return new Promise((resolve) => {
49 resolve({ items: res.records, total: res.total }); 47 resolve({ items: res.records, total: res.total });
50 }); 48 });
src/api/project/invoice.ts
@@ -52,6 +52,12 @@ enum Api { @@ -52,6 +52,12 @@ enum Api {
52 SERVICEAPPLYEDIT = '/project/applyEditFileds', //申请修改 52 SERVICEAPPLYEDIT = '/project/applyEditFileds', //申请修改
53 APPLYLIST = '/project/pageProjectLockFieldApply', //分页查询项目字段申请记录 53 APPLYLIST = '/project/pageProjectLockFieldApply', //分页查询项目字段申请记录
54 AUDITAPPLY = '/project/audit', //审核 54 AUDITAPPLY = '/project/audit', //审核
  55 + ACTIONRECORD = '/projectOptLog/listByPage', //业务/内部研发净利润操作记录以及申请记录
  56 + ORDERCOSTDETAILEDOPTLOG = '/orderCostDetailedOptLog/listByPage', //包装费用明细/内部生产明细操作记录表
  57 + SETPACKSTATUS = '/order/cost/setPackStatus', //包装费用明细表审批
  58 + SETINNERSTATUS = '/order/cost/setInnerStatus', //内部生产明细表审批
  59 + PROJECTBUSINESSPROFITSETSTATUS = '/project/businessProfit/setStatus', //业务研发净利润分析表审批
  60 + PROJECTINNERPROFITSETSTATUS = '/project/innerProfitInfo/setStatus', //内部研发净利润分析表审批
55 } 61 }
56 62
57 export const getRefundDate = async (params: any, data?: any) => { 63 export const getRefundDate = async (params: any, data?: any) => {
@@ -429,18 +435,30 @@ export const getServiceApplyEdit = async (params: any) => { @@ -429,18 +435,30 @@ export const getServiceApplyEdit = async (params: any) => {
429 }; 435 };
430 436
431 export const getApplyList = async (params: any) => { 437 export const getApplyList = async (params: any) => {
432 - const res = ref();  
433 - res.value = await defHttp.post<any>({ 438 + // const res = ref();
  439 + // res.value = await defHttp.post<any>({
  440 + // url: Api.APPLYLIST,
  441 + // params,
  442 + // });
  443 + // res.value.data.records.forEach((record) => {
  444 + // const jsonObj = JSON.parse(record?.fields);
  445 + // if (jsonObj) {
  446 + // record.fields = jsonObj;
  447 + // }
  448 + // });
  449 + // return res.value.data.records;
  450 + const data = await defHttp.post({
434 url: Api.APPLYLIST, 451 url: Api.APPLYLIST,
435 params, 452 params,
436 }); 453 });
437 - res.value.data.records.forEach((record) => {  
438 - const jsonObj = JSON.parse(record?.fields);  
439 - if (jsonObj) {  
440 - record.fields = jsonObj;  
441 - } 454 + const res = data.data;
  455 + res.records = res.records.map((item) => {
  456 + return item;
  457 + });
  458 +
  459 + return new Promise((resolve) => {
  460 + resolve({ items: res.records, total: res.total });
442 }); 461 });
443 - return res.value.data.records;  
444 }; 462 };
445 463
446 export const getAuditApply = async (params: any) => { 464 export const getAuditApply = async (params: any) => {
@@ -476,4 +494,71 @@ export const checkSetFinishStatus = async (params: any) =&gt; { @@ -476,4 +494,71 @@ export const checkSetFinishStatus = async (params: any) =&gt; {
476 url: Api.SETCHECKFINISHSTATUS, 494 url: Api.SETCHECKFINISHSTATUS,
477 params, 495 params,
478 }); 496 });
479 -};  
480 \ No newline at end of file 497 \ No newline at end of file
  498 +};
  499 +export const getProjectOptLog = async (params: any) => {
  500 + const res = await defHttp.post<any>({
  501 + url: Api.ACTIONRECORD,
  502 + params,
  503 + });
  504 + const formattedRecords = res.records.map((record: any) => {
  505 + return {
  506 + ...record,
  507 + };
  508 + });
  509 + const orderStore = useOrderStoreWithOut();
  510 + orderStore.setTotal(res.total);
  511 + orderStore.setQueryVO(params);
  512 + return new Promise((resolve) => {
  513 + resolve({
  514 + items: formattedRecords,
  515 + total: res.total,
  516 + });
  517 + });
  518 +};
  519 +
  520 +export const getOrderCostDetailedOptLog = async (params: any) => {
  521 + const res = await defHttp.post<any>({
  522 + url: Api.ORDERCOSTDETAILEDOPTLOG,
  523 + params,
  524 + });
  525 + const formattedRecords = res.records.map((record: any) => {
  526 + return {
  527 + ...record,
  528 + };
  529 + });
  530 + const orderStore = useOrderStoreWithOut();
  531 + orderStore.setTotal(res.total);
  532 + orderStore.setQueryVO(params);
  533 + return new Promise((resolve) => {
  534 + resolve({
  535 + items: formattedRecords,
  536 + total: res.total,
  537 + });
  538 + });
  539 +};
  540 +export const setPackStatus = async (params: any) => {
  541 + return await defHttp.post<any>({
  542 + url: Api.SETPACKSTATUS,
  543 + params,
  544 + });
  545 +};
  546 +export const setInnerStatus = async (params: any) => {
  547 + return await defHttp.post<any>({
  548 + url: Api.SETINNERSTATUS,
  549 + params,
  550 + });
  551 +};
  552 +
  553 +export const setBusinessProfitSetStatus = async (params: any) => {
  554 + return await defHttp.post<any>({
  555 + url: Api.PROJECTBUSINESSPROFITSETSTATUS,
  556 + params,
  557 + });
  558 +};
  559 +
  560 +export const setInnerProfitSetStatus = async (params: any) => {
  561 + return await defHttp.post<any>({
  562 + url: Api.PROJECTINNERPROFITSETSTATUS,
  563 + params,
  564 + });
  565 +};
src/router/routes/modules/project/finance.ts
@@ -43,106 +43,106 @@ const finance: AppRouteModule = { @@ -43,106 +43,106 @@ const finance: AppRouteModule = {
43 }, 43 },
44 component: () => import('/@/views/project/finance/financeList/index.vue'), 44 component: () => import('/@/views/project/finance/financeList/index.vue'),
45 }, 45 },
46 - // {  
47 - // path: 'financeProfit',  
48 - // name: 'FinanceProfit',  
49 - // meta: {  
50 - // title: '净利润分析',  
51 - // ignoreKeepAlive: true,  
52 - // roles: [  
53 - // RoleEnum.ADMIN,  
54 - // RoleEnum.FINANCE,  
55 - // // RoleEnum.TRACKER,  
56 - // // RoleEnum.BUSINESS,  
57 - // // RoleEnum.PRODUCE,  
58 - // // RoleEnum.DATA_REPORT_USER,  
59 - // ],  
60 - // },  
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 - // {  
73 - // path: 'serviceProfit',  
74 - // name: 'ServiceProfit',  
75 - // meta: {  
76 - // title: '业务研发净利润分析',  
77 - // roles: [RoleEnum.ADMIN, RoleEnum.FINANCE, RoleEnum.TRACKER, RoleEnum.BUSINESS],  
78 - // ignoreKeepAlive: false,  
79 - // },  
80 - // children: [  
81 - // {  
82 - // path: 'ServiceProfit',  
83 - // name: 'ServiceProfit',  
84 - // meta: {  
85 - // title: '业务研发净利润分析表',  
86 - // roles: [RoleEnum.ADMIN, RoleEnum.FINANCE, RoleEnum.TRACKER, RoleEnum.BUSINESS],  
87 - // ignoreKeepAlive: false,  
88 - // },  
89 - // component: () =>  
90 - // import(  
91 - // '/@/views/project/finance/financeProfit/ServiceProfit/ServiceProfit/index.vue'  
92 - // ),  
93 - // },  
94 - // {  
95 - // path: 'PackageProfit',  
96 - // name: 'PackageProfit',  
97 - // meta: {  
98 - // title: '包装费用明细表',  
99 - // roles: [RoleEnum.ADMIN, RoleEnum.FINANCE, RoleEnum.TRACKER, RoleEnum.BUSINESS],  
100 - // ignoreKeepAlive: false,  
101 - // },  
102 - // component: () =>  
103 - // import(  
104 - // '/@/views/project/finance/financeProfit/ServiceProfit/PackageProfit/index.vue'  
105 - // ),  
106 - // },  
107 - // ],  
108 - // },  
109 - // {  
110 - // path: 'ProductProfit',  
111 - // name: 'ProductProfit',  
112 - // meta: {  
113 - // title: '内部生产净利润分析',  
114 - // roles: [RoleEnum.ADMIN, RoleEnum.FINANCE, RoleEnum.TRACKER, RoleEnum.BUSINESS],  
115 - // ignoreKeepAlive: false,  
116 - // },  
117 - // children: [  
118 - // {  
119 - // path: 'InnerData',  
120 - // name: 'InnerData',  
121 - // meta: {  
122 - // title: '内部生产净利润分析表',  
123 - // roles: [RoleEnum.ADMIN, RoleEnum.FINANCE, RoleEnum.TRACKER, RoleEnum.BUSINESS],  
124 - // ignoreKeepAlive: false,  
125 - // },  
126 - // component: () =>  
127 - // import(  
128 - // '/@/views/project/finance/financeProfit/ProductProfit/InnerProduce/index.vue'  
129 - // ),  
130 - // },  
131 - // {  
132 - // path: 'InnerProduce',  
133 - // name: 'InnerProduce',  
134 - // meta: {  
135 - // title: '内部生产明细表',  
136 - // roles: [RoleEnum.ADMIN, RoleEnum.FINANCE, RoleEnum.TRACKER, RoleEnum.BUSINESS],  
137 - // ignoreKeepAlive: false,  
138 - // },  
139 - // component: () =>  
140 - // import('/@/views/project/finance/financeProfit/ProductProfit/InnerData/index.vue'),  
141 - // },  
142 - // ],  
143 - // },  
144 - // ],  
145 - // }, 46 + {
  47 + path: 'financeProfit',
  48 + name: 'FinanceProfit',
  49 + meta: {
  50 + title: '净利润分析',
  51 + ignoreKeepAlive: true,
  52 + roles: [
  53 + RoleEnum.ADMIN,
  54 + RoleEnum.FINANCE,
  55 + // RoleEnum.TRACKER,
  56 + // RoleEnum.BUSINESS,
  57 + // RoleEnum.PRODUCE,
  58 + // RoleEnum.DATA_REPORT_USER,
  59 + ],
  60 + },
  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 + {
  73 + path: 'serviceProfit',
  74 + name: 'ServiceProfit',
  75 + meta: {
  76 + title: '业务研发净利润分析',
  77 + roles: [RoleEnum.ADMIN, RoleEnum.FINANCE, RoleEnum.TRACKER, RoleEnum.BUSINESS],
  78 + ignoreKeepAlive: false,
  79 + },
  80 + children: [
  81 + {
  82 + path: 'ServiceProfit',
  83 + name: 'ServiceProfit',
  84 + meta: {
  85 + title: '业务研发净利润分析表',
  86 + roles: [RoleEnum.ADMIN, RoleEnum.FINANCE, RoleEnum.TRACKER, RoleEnum.BUSINESS],
  87 + ignoreKeepAlive: false,
  88 + },
  89 + component: () =>
  90 + import(
  91 + '/@/views/project/finance/financeProfit/ServiceProfit/ServiceProfit/index.vue'
  92 + ),
  93 + },
  94 + {
  95 + path: 'PackageProfit',
  96 + name: 'PackageProfit',
  97 + meta: {
  98 + title: '包装费用明细表',
  99 + roles: [RoleEnum.ADMIN, RoleEnum.FINANCE, RoleEnum.TRACKER, RoleEnum.BUSINESS],
  100 + ignoreKeepAlive: false,
  101 + },
  102 + component: () =>
  103 + import(
  104 + '/@/views/project/finance/financeProfit/ServiceProfit/PackageProfit/index.vue'
  105 + ),
  106 + },
  107 + ],
  108 + },
  109 + {
  110 + path: 'ProductProfit',
  111 + name: 'ProductProfit',
  112 + meta: {
  113 + title: '内部生产净利润分析',
  114 + roles: [RoleEnum.ADMIN, RoleEnum.FINANCE, RoleEnum.TRACKER, RoleEnum.BUSINESS],
  115 + ignoreKeepAlive: false,
  116 + },
  117 + children: [
  118 + {
  119 + path: 'InnerProduce',
  120 + name: 'InnerProduce',
  121 + meta: {
  122 + title: '内部生产净利润分析表',
  123 + roles: [RoleEnum.ADMIN, RoleEnum.FINANCE, RoleEnum.TRACKER, RoleEnum.BUSINESS],
  124 + ignoreKeepAlive: false,
  125 + },
  126 + component: () =>
  127 + import(
  128 + '/@/views/project/finance/financeProfit/ProductProfit/InnerProduce/index.vue'
  129 + ),
  130 + },
  131 + {
  132 + path: 'InnerData',
  133 + name: 'InnerData',
  134 + meta: {
  135 + title: '内部生产明细表',
  136 + roles: [RoleEnum.ADMIN, RoleEnum.FINANCE, RoleEnum.TRACKER, RoleEnum.BUSINESS],
  137 + ignoreKeepAlive: false,
  138 + },
  139 + component: () =>
  140 + import('/@/views/project/finance/financeProfit/ProductProfit/InnerData/index.vue'),
  141 + },
  142 + ],
  143 + },
  144 + ],
  145 + },
146 ], 146 ],
147 }; 147 };
148 148
src/views/project/approve/ProduceFieldPanel.vue
@@ -94,7 +94,7 @@ @@ -94,7 +94,7 @@
94 dataIndex: 'innerNo', 94 dataIndex: 'innerNo',
95 width: 150, 95 width: 150,
96 customRender: (column) => { 96 customRender: (column) => {
97 - return column.record.orderBaseInfo.innerNo; 97 + return column.record.orderBaseInfo?.innerNo || '-';
98 }, 98 },
99 }, 99 },
100 { 100 {
@@ -102,7 +102,7 @@ @@ -102,7 +102,7 @@
102 dataIndex: 'projectNo', 102 dataIndex: 'projectNo',
103 width: 150, 103 width: 150,
104 customRender: (column) => { 104 customRender: (column) => {
105 - return column.record.orderBaseInfo.projectNo; 105 + return column.record.orderBaseInfo?.projectNo || '-';
106 }, 106 },
107 }, 107 },
108 { 108 {
@@ -130,7 +130,7 @@ @@ -130,7 +130,7 @@
130 const [registerTable, { reload }] = useTable({ 130 const [registerTable, { reload }] = useTable({
131 scroll: false, 131 scroll: false,
132 api: props.isApproved ? getApprovedListApi : getWaitListApi, 132 api: props.isApproved ? getApprovedListApi : getWaitListApi,
133 - searchInfo: { typeIn: [60, 70] }, 133 + searchInfo: { typeIn: [80, 90] },
134 columns, 134 columns,
135 useSearchForm: false, 135 useSearchForm: false,
136 formConfig: getFormConfig('true'), 136 formConfig: getFormConfig('true'),
src/views/project/approve/ProfitFieldPanel.vue
@@ -39,7 +39,7 @@ @@ -39,7 +39,7 @@
39 import { BasicDrawer, useDrawer } from '/@/components/Drawer'; 39 import { BasicDrawer, useDrawer } from '/@/components/Drawer';
40 import { approveAuditApi, getApprovedListApi, getWaitListApi } from '/@/api/project/approve'; 40 import { approveAuditApi, getApprovedListApi, getWaitListApi } from '/@/api/project/approve';
41 import { getAuditApply, getApplyList } from '/@/api/project/invoice'; 41 import { getAuditApply, getApplyList } from '/@/api/project/invoice';
42 - import { FIELDS_BASE_INFO } from '../finance/financeProfit/ServiceProfit/ServiceProfit/tableData'; 42 + import { FIELDS_BASE_INFO } from './data';
43 import { COLUMNS } from '../finance/financeProfit/ServiceProfit/ServiceProfit/data'; 43 import { COLUMNS } from '../finance/financeProfit/ServiceProfit/ServiceProfit/data';
44 import { find, isEmpty } from 'lodash-es'; 44 import { find, isEmpty } from 'lodash-es';
45 import { ROLE } from '../order//type.d'; 45 import { ROLE } from '../order//type.d';
@@ -85,7 +85,11 @@ @@ -85,7 +85,11 @@
85 dataIndex: 'auditRoleCodes', 85 dataIndex: 'auditRoleCodes',
86 width: 150, 86 width: 150,
87 customRender: (column) => { 87 customRender: (column) => {
88 - return '业务研发净利字段'; 88 + if (column.record.type === 'FIELD_EDIT_APPLY') {
  89 + return '业务利润字段编辑申请';
  90 + } else if (column.record.type === 'INNER_PROFIT_FIELD_EDIT_APPLY') {
  91 + return '内部利润字段编辑申请';
  92 + }
89 }, 93 },
90 }, 94 },
91 { 95 {
src/views/project/approve/data.ts
@@ -70,4 +70,63 @@ export function getFormConfig(showFieldConfig: string) { @@ -70,4 +70,63 @@ export function getFormConfig(showFieldConfig: string) {
70 : []), 70 : []),
71 ], 71 ],
72 }; 72 };
73 -}  
74 \ No newline at end of file 73 \ No newline at end of file
  74 +}
  75 +
  76 +export const FIELDS_BASE_INFO = [
  77 + {
  78 + field: 'developmentCopyRmbTotalPrice',
  79 + component: 'Select',
  80 + labelWidth: 150,
  81 + label: '研发复制费合计¥',
  82 + rules: [{ required: true }],
  83 + },
  84 + {
  85 + field: 'projectStartTime',
  86 + component: 'Select',
  87 + labelWidth: 150,
  88 + label: '项目开始时间',
  89 + rules: [{ required: true }],
  90 + },
  91 + {
  92 + field: 'projectEndTime',
  93 + component: 'Select',
  94 + labelWidth: 150,
  95 + label: '项目结束时间',
  96 + rules: [{ required: true }],
  97 + },
  98 + {
  99 + field: 'spainPaidRmbCommission',
  100 + component: 'Select',
  101 + labelWidth: 150,
  102 + label: '西班牙已发提成¥',
  103 + rules: [{ required: true }],
  104 + },
  105 + {
  106 + field: 'paidRmbCommission',
  107 + component: 'Select',
  108 + labelWidth: 150,
  109 + label: '中国团队已发提成¥',
  110 + rules: [{ required: true }],
  111 + },
  112 + {
  113 + field: 'actualExchangeRate',
  114 + component: 'Select',
  115 + labelWidth: 150,
  116 + label: '实际汇率¥',
  117 + rules: [{ required: true }],
  118 + },
  119 + {
  120 + field: 'projectInnerProfitInfoStartTime',
  121 + component: 'Select',
  122 + labelWidth: 150,
  123 + label: '项目开始时间',
  124 + rules: [{ required: true }],
  125 + },
  126 + {
  127 + field: 'projectInnerProfitInfoEndTime',
  128 + component: 'Select',
  129 + labelWidth: 150,
  130 + label: '项目结束时间',
  131 + rules: [{ required: true }],
  132 + },
  133 +];
src/views/project/approve/index.vue
@@ -35,7 +35,7 @@ @@ -35,7 +35,7 @@
35 > 35 >
36 <PayPanel /> 36 <PayPanel />
37 </a-tab-pane> 37 </a-tab-pane>
38 - <!-- <a-tab-pane 38 + <a-tab-pane
39 key="11" 39 key="11"
40 tab="利润分析表字段审核" 40 tab="利润分析表字段审核"
41 v-if="role == ROLE.FINANCE || role == ROLE.ADMIN" 41 v-if="role == ROLE.FINANCE || role == ROLE.ADMIN"
@@ -44,7 +44,7 @@ @@ -44,7 +44,7 @@
44 </a-tab-pane> 44 </a-tab-pane>
45 <a-tab-pane key="13" tab="明细表字段审核" v-if="role == ROLE.FINANCE || role == ROLE.ADMIN"> 45 <a-tab-pane key="13" tab="明细表字段审核" v-if="role == ROLE.FINANCE || role == ROLE.ADMIN">
46 <ProduceFieldPanel /> 46 <ProduceFieldPanel />
47 - </a-tab-pane> --> 47 + </a-tab-pane>
48 <a-tab-pane key="2" tab="字段已审核" v-if="role !== ROLE.FINANCE"> 48 <a-tab-pane key="2" tab="字段已审核" v-if="role !== ROLE.FINANCE">
49 <FieldPanel isApproved /> 49 <FieldPanel isApproved />
50 </a-tab-pane> 50 </a-tab-pane>
@@ -79,7 +79,7 @@ @@ -79,7 +79,7 @@
79 > 79 >
80 <PayPanel isApproved /> 80 <PayPanel isApproved />
81 </a-tab-pane> 81 </a-tab-pane>
82 - <!-- <a-tab-pane 82 + <a-tab-pane
83 key="12" 83 key="12"
84 tab="利润分析表字段已审核" 84 tab="利润分析表字段已审核"
85 v-if="role == ROLE.FINANCE || role == ROLE.ADMIN" 85 v-if="role == ROLE.FINANCE || role == ROLE.ADMIN"
@@ -88,7 +88,7 @@ @@ -88,7 +88,7 @@
88 </a-tab-pane> 88 </a-tab-pane>
89 <a-tab-pane key="14" tab="明细表字段审核" v-if="role == ROLE.FINANCE || role == ROLE.ADMIN"> 89 <a-tab-pane key="14" tab="明细表字段审核" v-if="role == ROLE.FINANCE || role == ROLE.ADMIN">
90 <ProduceFieldPanel isApproved /> 90 <ProduceFieldPanel isApproved />
91 - </a-tab-pane> --> 91 + </a-tab-pane>
92 </a-tabs> 92 </a-tabs>
93 </div> 93 </div>
94 </template> 94 </template>
src/views/project/config/ProduCostCreate.vue
@@ -22,9 +22,15 @@ @@ -22,9 +22,15 @@
22 <a-input v-model:value="fixCost" 22 <a-input v-model:value="fixCost"
23 /></div> 23 /></div>
24 <div 24 <div
25 - ><span style="margin-right: 8px; width: 80%">提成比例:</span> 25 + ><span style="margin-right: 8px; width: 80%">提成单价:</span>
26 <a-input v-model:value="ratio" /> 26 <a-input v-model:value="ratio" />
27 </div> 27 </div>
  28 + <div
  29 + ><span style="margin-right: 8px; width: 80%">年份:</span>
  30 + <a-select v-model:value="year" style="width: 100%">
  31 + <a-select-option v-for="y in yearOptions" :key="y" :value="y">{{ y }}</a-select-option>
  32 + </a-select>
  33 + </div>
28 </a-space> 34 </a-space>
29 </BasicModal> 35 </BasicModal>
30 </template> 36 </template>
@@ -54,6 +60,13 @@ @@ -54,6 +60,13 @@
54 //获取现有的列表 60 //获取现有的列表
55 const listAll = ref(); 61 const listAll = ref();
56 const fixCost = ref(); 62 const fixCost = ref();
  63 + const year = ref(new Date().getFullYear().toString());
  64 + // Generate year options from 2023 to current year
  65 + const currentYear = new Date().getFullYear();
  66 + const yearOptions = ref<string[]>([]);
  67 + for (let y = 2023; y <= currentYear; y++) {
  68 + yearOptions.value.push(y.toString());
  69 + }
57 const ratio = ref(); 70 const ratio = ref();
58 // const relationValue = ref(); 71 // const relationValue = ref();
59 const customerCode = ref(); 72 const customerCode = ref();
@@ -91,7 +104,7 @@ @@ -91,7 +104,7 @@
91 settingValue: customerCode.value, 104 settingValue: customerCode.value,
92 settingType: 4, 105 settingType: 4,
93 relationCode: 'ProduceSettingItem', 106 relationCode: 'ProduceSettingItem',
94 - relationName: '成本配置项集合', 107 + relationName: year.value,
95 costSettingItemVOS: relationValue.value, 108 costSettingItemVOS: relationValue.value,
96 }); 109 });
97 emit('modal-success'); 110 emit('modal-success');
@@ -108,6 +121,8 @@ @@ -108,6 +121,8 @@
108 activeUser, 121 activeUser,
109 fixCost, 122 fixCost,
110 ratio, 123 ratio,
  124 + year,
  125 + yearOptions,
111 customerCode, 126 customerCode,
112 customerCodeOptions, 127 customerCodeOptions,
113 handleOk, 128 handleOk,
src/views/project/config/ProduCostEdit.vue
@@ -16,7 +16,8 @@ @@ -16,7 +16,8 @@
16 > 16 >
17 <a-space direction="vertical" style="width: 100%"> 17 <a-space direction="vertical" style="width: 100%">
18 <a-input v-model:value="fixCost" addonBefore="固定成本 " /> 18 <a-input v-model:value="fixCost" addonBefore="固定成本 " />
19 - <a-input v-model:value="ratio" addonBefore="提成比例 " /> 19 + <a-input v-model:value="ratio" addonBefore="提成单价 " />
  20 + <a-input v-model:value="year" :disabled="true" addonBefore="年份 " />
20 </a-space> 21 </a-space>
21 </BasicDrawer> 22 </BasicDrawer>
22 </template> 23 </template>
@@ -35,13 +36,14 @@ @@ -35,13 +36,14 @@
35 relationValue.value = JSON.parse(listAll.value.relationValue); 36 relationValue.value = JSON.parse(listAll.value.relationValue);
36 fixCost.value = relationValue.value[0].relationValue; 37 fixCost.value = relationValue.value[0].relationValue;
37 ratio.value = relationValue.value[1].relationValue; 38 ratio.value = relationValue.value[1].relationValue;
  39 + year.value = listAll.value.relationName;
38 }); 40 });
39 //获取现有的列表 41 //获取现有的列表
40 const listAll = ref(); 42 const listAll = ref();
41 const fixCost = ref(); 43 const fixCost = ref();
42 const ratio = ref(); 44 const ratio = ref();
43 const relationValue = ref(); 45 const relationValue = ref();
44 - 46 + const year = ref();
45 //完成编辑 47 //完成编辑
46 async function handleSubmit() { 48 async function handleSubmit() {
47 relationValue.value[0].relationValue = fixCost.value; 49 relationValue.value[0].relationValue = fixCost.value;
@@ -53,7 +55,7 @@ @@ -53,7 +55,7 @@
53 settingValue: listAll.value.settingValue, 55 settingValue: listAll.value.settingValue,
54 settingType: 4, 56 settingType: 4,
55 relationCode: 'ProduceSettingItem', 57 relationCode: 'ProduceSettingItem',
56 - relationName: '成本配置项集合', 58 + relationName: year.value,
57 costSettingItemVOS: relationValue.value, 59 costSettingItemVOS: relationValue.value,
58 }); 60 });
59 emit('success'); 61 emit('success');
src/views/project/config/TablePanel.vue
@@ -46,7 +46,7 @@ @@ -46,7 +46,7 @@
46 import { BasicTable, useTable, TableAction } from '/@/components/Table'; 46 import { BasicTable, useTable, TableAction } from '/@/components/Table';
47 import CreateModal from './CreateModal.vue'; 47 import CreateModal from './CreateModal.vue';
48 import { deleteConfig, getList, saveConfig } from '/@/api/sys/config'; 48 import { deleteConfig, getList, saveConfig } from '/@/api/sys/config';
49 - import { COLUMNS } from './data'; 49 + import { COLUMNS, searchFormSchema } from './data';
50 import { useModal } from '/@/components/Modal'; 50 import { useModal } from '/@/components/Modal';
51 import { useDrawer } from '/@/components/Drawer'; 51 import { useDrawer } from '/@/components/Drawer';
52 import CostEdit from './costEdit.vue'; 52 import CostEdit from './costEdit.vue';
@@ -74,6 +74,10 @@ @@ -74,6 +74,10 @@
74 pagination: false, 74 pagination: false,
75 columns: COLUMNS[props.column!], 75 columns: COLUMNS[props.column!],
76 rowKey: 'id', 76 rowKey: 'id',
  77 + useSearchForm: props.column === 6 || props.column === 9,
  78 + formConfig: {
  79 + schemas: props.column === 6 || props.column === 9 ? searchFormSchema : [],
  80 + },
77 actionColumn: { 81 actionColumn: {
78 width: 160, 82 width: 160,
79 title: 'Action', 83 title: 'Action',
src/views/project/config/costCreate.vue
@@ -29,6 +29,12 @@ @@ -29,6 +29,12 @@
29 ><span style="margin-right: 8px; width: 80%">西班牙提成比例:</span> 29 ><span style="margin-right: 8px; width: 80%">西班牙提成比例:</span>
30 <a-input v-model:value="spainRatio" /> 30 <a-input v-model:value="spainRatio" />
31 </div> 31 </div>
  32 + <div
  33 + ><span style="margin-right: 8px; width: 80%">年份:</span>
  34 + <a-select v-model:value="year" style="width: 100%">
  35 + <a-select-option v-for="y in yearOptions" :key="y" :value="y">{{ y }}</a-select-option>
  36 + </a-select>
  37 + </div>
32 <!-- <div 38 <!-- <div
33 ><span style="margin-right: 8px; width: 80%">生产提成单价:</span> 39 ><span style="margin-right: 8px; width: 80%">生产提成单价:</span>
34 <a-input v-model:value="price" /> 40 <a-input v-model:value="price" />
@@ -65,6 +71,13 @@ @@ -65,6 +71,13 @@
65 const ratio = ref(); 71 const ratio = ref();
66 const spainRatio = ref(); 72 const spainRatio = ref();
67 const price = ref(); 73 const price = ref();
  74 + const year = ref(new Date().getFullYear().toString());
  75 + // Generate year options from 2023 to current year
  76 + const currentYear = new Date().getFullYear();
  77 + const yearOptions = ref<string[]>([]);
  78 + for (let y = 2023; y <= currentYear; y++) {
  79 + yearOptions.value.push(y.toString());
  80 + }
68 // const relationValue = ref(); 81 // const relationValue = ref();
69 const customerCode = ref(); 82 const customerCode = ref();
70 const relationValue = ref([ 83 const relationValue = ref([
@@ -89,8 +102,6 @@ @@ -89,8 +102,6 @@
89 // relationValue: '', 102 // relationValue: '',
90 // }, 103 // },
91 ]); 104 ]);
92 - // const loading = ref(true);  
93 -  
94 const { customerCode: customerCodeOptions } = useOrderInfo(orderStore); 105 const { customerCode: customerCodeOptions } = useOrderInfo(orderStore);
95 106
96 function handleShow(visible: boolean) { 107 function handleShow(visible: boolean) {
@@ -101,18 +112,30 @@ @@ -101,18 +112,30 @@
101 } 112 }
102 } 113 }
103 114
  115 + // 格式化百分比值,去除百分号并除以100
  116 + function formatPercentage(value) {
  117 + if (!value) return '';
  118 + // 检查值是否包含百分号
  119 + if (typeof value === 'string' && value.includes('%')) {
  120 + // 去除百分号并转为数值,然后除以100
  121 + return (parseFloat(value.replace('%', '')) / 100).toString();
  122 + }
  123 + // 如果没有百分号但是是数值,直接除以100
  124 + return value;
  125 + }
  126 +
104 async function handleOk() { 127 async function handleOk() {
105 try { 128 try {
106 relationValue.value[0].relationValue = fixCost.value; 129 relationValue.value[0].relationValue = fixCost.value;
107 - relationValue.value[1].relationValue = ratio.value;  
108 - relationValue.value[2].relationValue = spainRatio.value; 130 + relationValue.value[1].relationValue = formatPercentage(ratio.value);
  131 + relationValue.value[2].relationValue = formatPercentage(spainRatio.value);
109 await addConfig({ 132 await addConfig({
110 settingCode: 'customerCode', 133 settingCode: 'customerCode',
111 settingName: '客户提成成本配置', 134 settingName: '客户提成成本配置',
112 settingValue: customerCode.value, 135 settingValue: customerCode.value,
113 settingType: 3, 136 settingType: 3,
114 relationCode: 'costSettingItem', 137 relationCode: 'costSettingItem',
115 - relationName: '成本配置项集合', 138 + relationName: year.value,
116 costSettingItemVOS: relationValue.value, 139 costSettingItemVOS: relationValue.value,
117 }); 140 });
118 emit('modal-success'); 141 emit('modal-success');
@@ -132,6 +155,8 @@ @@ -132,6 +155,8 @@
132 spainRatio, 155 spainRatio,
133 price, 156 price,
134 customerCode, 157 customerCode,
  158 + year,
  159 + yearOptions,
135 customerCodeOptions, 160 customerCodeOptions,
136 handleOk, 161 handleOk,
137 }; 162 };
src/views/project/config/costEdit.vue
@@ -18,26 +18,30 @@ @@ -18,26 +18,30 @@
18 <a-input v-model:value="fixCost" addonBefore="固定成本 " /> 18 <a-input v-model:value="fixCost" addonBefore="固定成本 " />
19 <a-input v-model:value="ratio" addonBefore="提成比例 " /> 19 <a-input v-model:value="ratio" addonBefore="提成比例 " />
20 <a-input v-model:value="spainRatio" addonBefore="西班牙提成比例 " /> 20 <a-input v-model:value="spainRatio" addonBefore="西班牙提成比例 " />
  21 + <a-input v-model:value="year" :disabled="true" addonBefore="年份 " />
21 <!-- <a-input v-model:value="price" addonBefore="生产提成单价" /> --> 22 <!-- <a-input v-model:value="price" addonBefore="生产提成单价" /> -->
22 </a-space> 23 </a-space>
23 </BasicDrawer> 24 </BasicDrawer>
24 </template> 25 </template>
25 <script lang="ts" setup> 26 <script lang="ts" setup>
26 import { BasicDrawer, useDrawerInner } from '@/components/Drawer'; 27 import { BasicDrawer, useDrawerInner } from '@/components/Drawer';
27 - import { BasicForm, FormSchema, useForm } from '@/components/Form';  
28 - import { defineComponent, ref, computed, unref, toRaw, reactive, onMounted } from 'vue'; 28 + import { ref } from 'vue';
29 import { saveConfig } from '/@/api/sys/config'; 29 import { saveConfig } from '/@/api/sys/config';
30 30
31 - // const emit = defineEmits(['success']);  
32 - // const isUpdate = ref(true);  
33 const emit = defineEmits(['success']); 31 const emit = defineEmits(['success']);
34 32
35 const [register, { closeDrawer }] = useDrawerInner((data) => { 33 const [register, { closeDrawer }] = useDrawerInner((data) => {
36 listAll.value = data.data; 34 listAll.value = data.data;
37 relationValue.value = JSON.parse(listAll.value.relationValue); 35 relationValue.value = JSON.parse(listAll.value.relationValue);
38 fixCost.value = relationValue.value[0].relationValue; 36 fixCost.value = relationValue.value[0].relationValue;
39 - ratio.value = relationValue.value[1].relationValue;  
40 - spainRatio.value = relationValue.value[2].relationValue; 37 + // 将小数转换为百分比格式显示
  38 + ratio.value = relationValue.value[1].relationValue
  39 + ? (parseFloat(relationValue.value[1].relationValue) * 100).toFixed(2) + '%'
  40 + : '';
  41 + spainRatio.value = relationValue.value[2].relationValue
  42 + ? (parseFloat(relationValue.value[2].relationValue) * 100).toFixed(2) + '%'
  43 + : '';
  44 + year.value = listAll.value.relationName;
41 }); 45 });
42 //获取现有的列表 46 //获取现有的列表
43 const listAll = ref(); 47 const listAll = ref();
@@ -45,12 +49,25 @@ @@ -45,12 +49,25 @@
45 const ratio = ref(); 49 const ratio = ref();
46 const spainRatio = ref(); 50 const spainRatio = ref();
47 const relationValue = ref(); 51 const relationValue = ref();
  52 + const year = ref();
  53 +
  54 + // 格式化百分比值,去除百分号并除以100
  55 + function formatPercentage(value) {
  56 + if (!value) return '';
  57 + // 检查值是否包含百分号
  58 + if (typeof value === 'string' && value.includes('%')) {
  59 + // 去除百分号并转为数值,然后除以100
  60 + return (parseFloat(value.replace('%', '')) / 100).toString();
  61 + }
  62 + // 如果没有百分号但是是数值,直接除以100
  63 + return value;
  64 + }
48 65
49 //完成编辑 66 //完成编辑
50 async function handleSubmit() { 67 async function handleSubmit() {
51 relationValue.value[0].relationValue = fixCost.value; 68 relationValue.value[0].relationValue = fixCost.value;
52 - relationValue.value[1].relationValue = ratio.value;  
53 - relationValue.value[2].relationValue = spainRatio.value; 69 + relationValue.value[1].relationValue = formatPercentage(ratio.value);
  70 + relationValue.value[2].relationValue = formatPercentage(spainRatio.value);
54 await saveConfig({ 71 await saveConfig({
55 id: listAll.value.id, 72 id: listAll.value.id,
56 settingCode: 'customerCode', 73 settingCode: 'customerCode',
@@ -58,7 +75,7 @@ @@ -58,7 +75,7 @@
58 settingValue: listAll.value.settingValue, 75 settingValue: listAll.value.settingValue,
59 settingType: 3, 76 settingType: 3,
60 relationCode: 'costSettingItem', 77 relationCode: 'costSettingItem',
61 - relationName: '成本配置项集合', 78 + relationName: year.value,
62 costSettingItemVOS: relationValue.value, 79 costSettingItemVOS: relationValue.value,
63 }); 80 });
64 emit('success'); 81 emit('success');
src/views/project/config/data.tsx
1 -import { InputNumber, Tag } from 'ant-design-vue'; 1 +import { Tag } from 'ant-design-vue';
2 import { BasicColumn } from '@/components/Table'; 2 import { BasicColumn } from '@/components/Table';
3 -import { func } from 'vue-types';  
4 -import { h, ref } from 'vue';  
5 - 3 +import { h } from 'vue';
  4 +import { queryNoOptions } from '/@/api/project/order';
6 5
7 export const COLUMNS = { 6 export const COLUMNS = {
8 1: [ 7 1: [
@@ -68,6 +67,11 @@ export const COLUMNS = { @@ -68,6 +67,11 @@ export const COLUMNS = {
68 width: 150, 67 width: 150,
69 }, 68 },
70 { 69 {
  70 + title: '年份',
  71 + dataIndex: 'relationName',
  72 + width: 150,
  73 + },
  74 + {
71 title: '固定成本', 75 title: '固定成本',
72 dataIndex: 'relationValue', 76 dataIndex: 'relationValue',
73 width: 150, 77 width: 150,
@@ -82,7 +86,7 @@ export const COLUMNS = { @@ -82,7 +86,7 @@ export const COLUMNS = {
82 width: 150, 86 width: 150,
83 customRender: (column) => { 87 customRender: (column) => {
84 const value = JSON.parse(column.record.relationValue); 88 const value = JSON.parse(column.record.relationValue);
85 - return value[1].relationValue; 89 + return (value[1]?.relationValue * 100).toFixed(2) + '%';
86 }, 90 },
87 }, 91 },
88 { 92 {
@@ -91,7 +95,7 @@ export const COLUMNS = { @@ -91,7 +95,7 @@ export const COLUMNS = {
91 width: 150, 95 width: 150,
92 customRender: (column) => { 96 customRender: (column) => {
93 const value = JSON.parse(column.record.relationValue); 97 const value = JSON.parse(column.record.relationValue);
94 - return value[2].relationValue; 98 + return (value[2]?.relationValue * 100).toFixed(2) + '%';
95 }, 99 },
96 }, 100 },
97 // { 101 // {
@@ -139,6 +143,11 @@ export const COLUMNS = { @@ -139,6 +143,11 @@ export const COLUMNS = {
139 width: 150, 143 width: 150,
140 }, 144 },
141 { 145 {
  146 + title: '年份',
  147 + dataIndex: 'relationName',
  148 + width: 150,
  149 + },
  150 + {
142 title: '固定成本', 151 title: '固定成本',
143 dataIndex: 'relationValue', 152 dataIndex: 'relationValue',
144 width: 150, 153 width: 150,
@@ -148,7 +157,7 @@ export const COLUMNS = { @@ -148,7 +157,7 @@ export const COLUMNS = {
148 }, 157 },
149 }, 158 },
150 { 159 {
151 - title: '提成比例', 160 + title: '提成单价',
152 dataIndex: 'relationValue', 161 dataIndex: 'relationValue',
153 width: 150, 162 width: 150,
154 customRender: (column) => { 163 customRender: (column) => {
@@ -258,3 +267,23 @@ export const columnsProduct: BasicColumn[] = [ @@ -258,3 +267,23 @@ export const columnsProduct: BasicColumn[] = [
258 editRow: true, 267 editRow: true,
259 }, 268 },
260 ]; 269 ];
  270 +
  271 +export const searchFormSchema = [
  272 + {
  273 + field: 'relationName',
  274 + label: '年份',
  275 + component: 'Select',
  276 + colProps: { span: 8 },
  277 + componentProps: {
  278 + showSearch: true,
  279 + options: (() => {
  280 + const options = [];
  281 + const currentYear = new Date().getFullYear();
  282 + for (let y = 2023; y <= currentYear; y++) {
  283 + options.push({ label: y.toString(), value: y.toString() });
  284 + }
  285 + return options;
  286 + })(),
  287 + },
  288 + },
  289 +]
261 \ No newline at end of file 290 \ No newline at end of file
src/views/project/config/index.vue
@@ -22,7 +22,7 @@ @@ -22,7 +22,7 @@
22 <TablePanel :searchInfo="{ relationCode: 'orderHodTime' }" :column="5" /> 22 <TablePanel :searchInfo="{ relationCode: 'orderHodTime' }" :column="5" />
23 </Tabs.TabPane> 23 </Tabs.TabPane>
24 <Tabs.TabPane key="6" tab="提成成本配置"> 24 <Tabs.TabPane key="6" tab="提成成本配置">
25 - <TablePanel :searchInfo="{ relationCode: 'costSettingItem' }" :column="6" /> 25 + <TablePanel :searchInfo="{ relationCode: 'costSettingItem', relationName: currentYear }" :column="6" />
26 </Tabs.TabPane> 26 </Tabs.TabPane>
27 <Tabs.TabPane key="7" tab="销售额配置" v-if="role !== ROLE.FINANCE"> 27 <Tabs.TabPane key="7" tab="销售额配置" v-if="role !== ROLE.FINANCE">
28 <TablePanel :searchInfo="{ relationCode: 'salesAmount' }" :column="7" /> 28 <TablePanel :searchInfo="{ relationCode: 'salesAmount' }" :column="7" />
@@ -31,7 +31,7 @@ @@ -31,7 +31,7 @@
31 <TablePanel :searchInfo="{ relationCode: 'produHodTime' }" :column="8" /> 31 <TablePanel :searchInfo="{ relationCode: 'produHodTime' }" :column="8" />
32 </Tabs.TabPane> 32 </Tabs.TabPane>
33 <Tabs.TabPane key="9" tab="生产科固定成本"> 33 <Tabs.TabPane key="9" tab="生产科固定成本">
34 - <TablePanel :searchInfo="{ relationCode: 'ProduceSettingItem' }" :column="9" /> 34 + <TablePanel :searchInfo="{ relationCode: 'ProduceSettingItem', relationName: currentYear }" :column="9" />
35 </Tabs.TabPane> 35 </Tabs.TabPane>
36 <Tabs.TabPane key="10" tab="客户公司" v-if="role !== ROLE.FINANCE"> 36 <Tabs.TabPane key="10" tab="客户公司" v-if="role !== ROLE.FINANCE">
37 <TablePanel :searchInfo="{ relationCode: 'companyConfiguration' }" :column="10" /> 37 <TablePanel :searchInfo="{ relationCode: 'companyConfiguration' }" :column="10" />
@@ -56,6 +56,7 @@ @@ -56,6 +56,7 @@
56 const orderStore = useOrderStoreWithOut(); 56 const orderStore = useOrderStoreWithOut();
57 const userStore = useUserStoreWithOut(); 57 const userStore = useUserStoreWithOut();
58 const user = userStore.getUserInfo; 58 const user = userStore.getUserInfo;
  59 + const currentYear = new Date().getFullYear().toString();
59 const role = computed(() => { 60 const role = computed(() => {
60 return user?.roleSmallVO?.code; 61 return user?.roleSmallVO?.code;
61 }); 62 });
src/views/project/finance/financeProfit/ProductProfit/InnerData/ApproveReason.vue
@@ -32,7 +32,9 @@ @@ -32,7 +32,9 @@
32 orderId: baseFieldValues.value.orderId, 32 orderId: baseFieldValues.value.orderId,
33 productionActualPrice: baseFieldValues.value.productionActualPrice, 33 productionActualPrice: baseFieldValues.value.productionActualPrice,
34 productionDepartmentPredictPrice: baseFieldValues.value.productionDepartmentPredictPrice, 34 productionDepartmentPredictPrice: baseFieldValues.value.productionDepartmentPredictPrice,
35 - type: 70, 35 + productionDepartmentPredictUnitPrice: baseFieldValues.value.productionDepartmentPredictUnitPrice,
  36 + applyRemark: baseFieldValues.value.applyRemark,
  37 + type: 90,
36 }); 38 });
37 emit('success'); 39 emit('success');
38 setTimeout(() => { 40 setTimeout(() => {
src/views/project/finance/financeProfit/ProductProfit/InnerData/FinanceEdit.vue
@@ -9,6 +9,7 @@ @@ -9,6 +9,7 @@
9 @ok="handleSubmit" 9 @ok="handleSubmit"
10 :showDetailBack="false" 10 :showDetailBack="false"
11 okText="保存" 11 okText="保存"
  12 + @visible-change="handleShow"
12 showFooter 13 showFooter
13 :destroyOnClose="true" 14 :destroyOnClose="true"
14 > 15 >
@@ -19,7 +20,7 @@ @@ -19,7 +20,7 @@
19 <a-input 20 <a-input
20 v-model:value="input1" 21 v-model:value="input1"
21 placeholder="请输入" 22 placeholder="请输入"
22 - :disabled="status1 === 'LOCKED'" 23 + :disabled="status1 == 'LOCKED'"
23 auto-size 24 auto-size
24 /> 25 />
25 <div style="margin: 16px 0"></div> 26 <div style="margin: 16px 0"></div>
@@ -27,7 +28,15 @@ @@ -27,7 +28,15 @@
27 <a-input 28 <a-input
28 v-model:value="input2" 29 v-model:value="input2"
29 placeholder="请输入" 30 placeholder="请输入"
30 - :disabled="status2 === 'LOCKED'" 31 + :disabled="status2 == 'LOCKED'"
  32 + auto-size
  33 + />
  34 + <div style="margin: 16px 0"></div>
  35 + <div style="font-size: 15px">生产科预算单价</div>
  36 + <a-input
  37 + v-model:value="input3"
  38 + placeholder="请输入"
  39 + :disabled="status3 == 'LOCKED'"
31 auto-size 40 auto-size
32 /> 41 />
33 <div style="margin: 16px 0"></div> 42 <div style="margin: 16px 0"></div>
@@ -42,7 +51,7 @@ @@ -42,7 +51,7 @@
42 <script lang="ts" setup> 51 <script lang="ts" setup>
43 import { BasicDrawer, useDrawerInner } from '@/components/Drawer'; 52 import { BasicDrawer, useDrawerInner } from '@/components/Drawer';
44 import { BasicForm, FormSchema, useForm } from '@/components/Form'; 53 import { BasicForm, FormSchema, useForm } from '@/components/Form';
45 - import { defineComponent, ref, computed, unref, toRaw, reactive } from 'vue'; 54 + import { defineComponent, ref, computed, watch, toRaw, reactive } from 'vue';
46 import { getPackageEdit } from '@/api/project/invoice'; 55 import { getPackageEdit } from '@/api/project/invoice';
47 import { useMessage } from '/@/hooks/web/useMessage'; 56 import { useMessage } from '/@/hooks/web/useMessage';
48 import { ROLE } from './type.d'; 57 import { ROLE } from './type.d';
@@ -125,25 +134,37 @@ @@ -125,25 +134,37 @@
125 const update = ref(); 134 const update = ref();
126 const status1 = ref(); 135 const status1 = ref();
127 const status2 = ref(); 136 const status2 = ref();
  137 + const status3 = ref();
128 138
129 const input1 = ref(); 139 const input1 = ref();
130 const input2 = ref(); 140 const input2 = ref();
  141 + const input3 = ref();
  142 + const orderCount = ref();
131 const id = ref(); 143 const id = ref();
  144 + watch(input3, (newVal) => {
  145 + if (newVal && orderCount.value) {
  146 + input1.value = (parseFloat(newVal) * parseFloat(orderCount.value)).toFixed(2);
  147 + } else {
  148 + input1.value = '';
  149 + }
  150 + });
132 const [register, { setDrawerProps, closeDrawer }] = useDrawerInner((data) => { 151 const [register, { setDrawerProps, closeDrawer }] = useDrawerInner((data) => {
133 // 方式1 152 // 方式1
134 - if (data.data.lockFields) {  
135 - status1.value = data.data?.productionDepartmentPredictPrice;  
136 - status2.value = data.data?.productionActualPrice; 153 + if (data.data?.lockFields) {
  154 + status1.value = data.data?.lockFields?.productionDepartmentPredictPrice;
  155 + status2.value = data.data?.lockFields?.productionActualPrice;
  156 + status3.value = data.data?.lockFields?.productionDepartmentPredictUnitPrice;
137 } 157 }
138 -  
139 id.value = data.data.orderId; 158 id.value = data.data.orderId;
140 - input1.value = data.data?.productionDepartmentPredictPrice.toFixed(2);  
141 - input2.value = data.data?.productionActualPrice.toFixed(2); 159 + input1.value = data.data?.productionDepartmentPredictPrice?.toFixed(2);
  160 + input2.value = data.data?.productionActualPrice?.toFixed(2);
  161 + orderCount.value = data.data?.orderCount;
  162 + input3.value = data.data?.productionDepartmentPredictUnitPrice?.toFixed(2);
142 resetFields(); 163 resetFields();
143 setDrawerProps({ confirmLoading: false }); 164 setDrawerProps({ confirmLoading: false });
144 - setFieldsValue({  
145 - ...toRaw(data.data),  
146 - }); 165 + // setFieldsValue({
  166 + // ...toRaw(data.data),
  167 + // });
147 update.value = data; 168 update.value = data;
148 }); 169 });
149 //完成编辑 170 //完成编辑
@@ -154,16 +175,25 @@ @@ -154,16 +175,25 @@
154 // id: update.value.data.id, 175 // id: update.value.data.id,
155 // bgUrl: update.value.data.bgUrl, 176 // bgUrl: update.value.data.bgUrl,
156 // }; 177 // };
157 - if (!input1.value || !input2.value) { 178 + if (!input1.value || !input2.value || !input3.value) {
158 error('选项不能为空'); 179 error('选项不能为空');
159 } else { 180 } else {
160 await getPackageEdit({ 181 await getPackageEdit({
161 orderId: id.value, 182 orderId: id.value,
162 productionDepartmentPredictPrice: input1.value, 183 productionDepartmentPredictPrice: input1.value,
163 productionActualPrice: input2.value, 184 productionActualPrice: input2.value,
  185 + orderCount: orderCount.value,
  186 + productionDepartmentPredictUnitPrice: input3.value,
164 }); 187 });
165 emit('success'); 188 emit('success');
166 closeDrawer(); 189 closeDrawer();
167 } 190 }
168 } 191 }
  192 + function handleShow(visible: boolean) {
  193 + if (!visible) {
  194 + input1.value = '';
  195 + input2.value = '';
  196 + input3.value = '';
  197 + }
  198 + }
169 </script> 199 </script>
src/views/project/finance/financeProfit/ProductProfit/InnerData/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, List } from 'ant-design-vue';
  68 + import { FormSchema } from '/@/components/Form/index';
  69 +
  70 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  71 + import { getOrderCostDetailedOptLog } 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 orderId = 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 getOrderCostDetailedOptLog({
  138 + orderId: data,
  139 + type: [40],
  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 getOrderCostDetailedOptLog({
  148 + orderId: data,
  149 + type: [90,91],
  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 + orderId.value = data.data.orderId;
  160 + getOrderOptLogFunc(orderId.value, 1, 1);
  161 + getOrderOptLogFunc(orderId.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(orderId.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(orderId.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/ProductProfit/InnerData/data.tsx
@@ -137,7 +137,15 @@ export const COLUMNS = [ @@ -137,7 +137,15 @@ export const COLUMNS = [
137 }, 137 },
138 }, 138 },
139 { 139 {
140 - title: '生产科预算金额¥', 140 + title: '生产科预算单价¥',
  141 + width: 150,
  142 + dataIndex: 'productionDepartmentPredictUnitPrice',
  143 + customRender: (column) => {
  144 + return column.record?.productionDepartmentPredictUnitPrice?.toFixed(2);
  145 + },
  146 + },
  147 + {
  148 + title: '生产科预算总金额¥',
141 width: 150, 149 width: 150,
142 dataIndex: 'productionDepartmentPredictPrice', 150 dataIndex: 'productionDepartmentPredictPrice',
143 customRender: (column) => { 151 customRender: (column) => {
@@ -145,9 +153,9 @@ export const COLUMNS = [ @@ -145,9 +153,9 @@ export const COLUMNS = [
145 }, 153 },
146 }, 154 },
147 { 155 {
148 - title: '实际发生费用', 156 + title: '生产科实际花费总金额¥',
149 dataIndex: 'productionActualPrice', 157 dataIndex: 'productionActualPrice',
150 - width: 120, 158 + width: 180,
151 customRender: (column) => { 159 customRender: (column) => {
152 return column.record?.productionActualPrice?.toFixed(2); 160 return column.record?.productionActualPrice?.toFixed(2);
153 }, 161 },
@@ -158,7 +166,7 @@ export const COLUMNS = [ @@ -158,7 +166,7 @@ export const COLUMNS = [
158 width: 120, 166 width: 120,
159 customRender: (column) => { 167 customRender: (column) => {
160 if (column.record?.predictRatio) { 168 if (column.record?.predictRatio) {
161 - return column.record?.predictRatio?.toFixed(2) + '%'; 169 + return (column.record?.predictRatio * 100).toFixed(2) + '%';
162 } 170 }
163 return column.record?.predictRatio?.toFixed(2); 171 return column.record?.predictRatio?.toFixed(2);
164 }, 172 },
@@ -169,7 +177,7 @@ export const COLUMNS = [ @@ -169,7 +177,7 @@ export const COLUMNS = [
169 width: 120, 177 width: 120,
170 customRender: (column) => { 178 customRender: (column) => {
171 if (column.record?.predictAndActualRatio) { 179 if (column.record?.predictAndActualRatio) {
172 - return column.record?.predictAndActualRatio?.toFixed(2) + '%'; 180 + return (column.record?.predictAndActualRatio * 100).toFixed(2) + '%';
173 } 181 }
174 return column.record?.predictAndActualRatio?.toFixed(2); 182 return column.record?.predictAndActualRatio?.toFixed(2);
175 }, 183 },
@@ -188,7 +196,7 @@ export const COLUMNS = [ @@ -188,7 +196,7 @@ export const COLUMNS = [
188 width: 120, 196 width: 120,
189 customRender: (column) => { 197 customRender: (column) => {
190 if (column.record?.beforeGrossProfitRate) { 198 if (column.record?.beforeGrossProfitRate) {
191 - return column.record?.beforeGrossProfitRate?.toFixed(2) + '%'; 199 + return (column.record?.beforeGrossProfitRate * 100).toFixed(2) + '%';
192 } 200 }
193 return column.record?.beforeGrossProfitRate?.toFixed(2); 201 return column.record?.beforeGrossProfitRate?.toFixed(2);
194 }, 202 },
@@ -207,11 +215,25 @@ export const COLUMNS = [ @@ -207,11 +215,25 @@ export const COLUMNS = [
207 width: 120, 215 width: 120,
208 customRender: (column) => { 216 customRender: (column) => {
209 if (column.record?.grossProfitRate) { 217 if (column.record?.grossProfitRate) {
210 - return column.record?.grossProfitRate?.toFixed(2) + '%'; 218 + return (column.record?.grossProfitRate * 100).toFixed(2) + '%';
211 } 219 }
212 return column.record?.grossProfitRate?.toFixed(2); 220 return column.record?.grossProfitRate?.toFixed(2);
213 }, 221 },
214 }, 222 },
  223 + {
  224 + title: '状态',
  225 + dataIndex: 'status',
  226 + width: 120,
  227 + customRender: (column) => {
  228 + if (column.record?.innerProduceStatus === null || column.record?.innerProduceStatus === -1) {
  229 + return '未完成';
  230 + } else if (column.record?.innerProduceStatus === 0) {
  231 + return '待审核';
  232 + } else if (column.record?.innerProduceStatus === 1) {
  233 + return '已审核';
  234 + }
  235 + },
  236 + },
215 // { 237 // {
216 // title: '内部生产固定成本¥', 238 // title: '内部生产固定成本¥',
217 // dataIndex: 'innerProductionFixedCost', 239 // dataIndex: 'innerProductionFixedCost',
src/views/project/finance/financeProfit/ProductProfit/InnerData/index.vue
1 <template> 1 <template>
2 <div> 2 <div>
3 <BasicTable @register="registerTable" :bordered="true"> 3 <BasicTable @register="registerTable" :bordered="true">
  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>
4 <template #bodyCell="{ column, record }"> 23 <template #bodyCell="{ column, record }">
5 <template v-if="column.key === 'picUrl'"> 24 <template v-if="column.key === 'picUrl'">
6 <img :z-index="100000" :width="50" :height="50" :src="record?.picUrl" /> 25 <img :z-index="100000" :width="50" :height="50" :src="record?.picUrl" />
7 </template> 26 </template>
8 <template v-if="column.key === 'action'"> 27 <template v-if="column.key === 'action'">
9 - <TableAction :actions="createActions(record)" /> 28 + <TableAction :actions="createActions(record)" :dropDownActions="createDropActions(record)" />
10 </template> 29 </template>
11 <!-- <template v-if="column.key === 'relationValue'"> 30 <!-- <template v-if="column.key === 'relationValue'">
12 <a-input 31 <a-input
@@ -19,6 +38,15 @@ @@ -19,6 +38,15 @@
19 </span> 38 </span>
20 </template> --> 39 </template> -->
21 </template> 40 </template>
  41 + <template #toolbar>
  42 + <a-button
  43 + type="primary"
  44 + @click="handleExport"
  45 + v-if="role == ROLE.ADMIN || role == ROLE.FINANCE"
  46 + :style="{ borderRadius: '5px 5px 5px 5px' }"
  47 + >导出</a-button
  48 + >
  49 + </template>
22 </BasicTable> 50 </BasicTable>
23 <!-- <BasicModal 51 <!-- <BasicModal
24 title="拒绝原因" 52 title="拒绝原因"
@@ -32,28 +60,48 @@ @@ -32,28 +60,48 @@
32 <a-textarea :rows="6" placeholder="请输入拒绝原因" v-model:value="message" /> 60 <a-textarea :rows="6" placeholder="请输入拒绝原因" v-model:value="message" />
33 </div> 61 </div>
34 </BasicModal> --> 62 </BasicModal> -->
35 - <CheckDetail @register="checkModalRegister" /> 63 + <CheckDetail @register="checkModalRegister" :onGoFormDetail="handleGoFormDetail" />
36 <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" /> 64 <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" />
  65 + <HistoryDetail @register="registerHistoryDetail" />
37 </div> 66 </div>
38 </template> 67 </template>
39 <script setup lang="ts"> 68 <script setup lang="ts">
40 import { BasicTable, useTable, TableAction } from '/@/components/Table'; 69 import { BasicTable, useTable, TableAction } from '/@/components/Table';
41 - import { getInnerProfit } from '@/api/project/invoice'; 70 + import { getInnerProfit, setInnerStatus } from '@/api/project/invoice';
42 import { searchFormSchema, COLUMNS } from './data'; 71 import { searchFormSchema, COLUMNS } from './data';
43 import { BasicModal, useModal } from '/@/components/Modal'; 72 import { BasicModal, useModal } from '/@/components/Modal';
44 import { useMessage } from '/@/hooks/web/useMessage'; 73 import { useMessage } from '/@/hooks/web/useMessage';
45 - import { onMounted, ref } from 'vue'; 74 + import { onMounted, ref, computed } from 'vue';
  75 + import axios from 'axios';
46 import { useDrawer } from '/@/components/Drawer'; 76 import { useDrawer } from '/@/components/Drawer';
47 import FinanceEdit from './FinanceEdit.vue'; 77 import FinanceEdit from './FinanceEdit.vue';
48 import CheckDetail from './CheckDetail.vue'; 78 import CheckDetail from './CheckDetail.vue';
  79 + import HistoryDetail from './HistoryDetail.vue';
49 import { useOrderStoreWithOut } from '/@/store/modules/order'; 80 import { useOrderStoreWithOut } from '/@/store/modules/order';
  81 + import { useUserStoreWithOut } from '/@/store/modules/user';
  82 + import { RoleEnum } from '/@/enums/roleEnum';
  83 + import { ROLE } from '../../../type.d';
50 84
51 const { createMessage } = useMessage(); 85 const { createMessage } = useMessage();
52 const { error } = createMessage; 86 const { error } = createMessage;
53 const message = ref(); 87 const message = ref();
  88 + const checkedKeys = ref<string[]>([]);
  89 + // Define arrays to store collected data from selected rows
  90 + const orderIds = ref<number[]>([]);
  91 + const projectNo = ref<string[]>([]);
  92 + const customerCode = ref<string[]>([]);
  93 + const innerNo = ref<string[]>([]);
  94 + const productionDepartment = ref<string[]>([]);
  95 + const detailProjectNoKeys = ref<string[]>([]);
54 const orderStore = useOrderStoreWithOut(); 96 const orderStore = useOrderStoreWithOut();
55 const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer(); 97 const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer();
56 const [registerFinanceEdit, { openDrawer: openFinanceEdit }] = useDrawer(); 98 const [registerFinanceEdit, { openDrawer: openFinanceEdit }] = useDrawer();
  99 + const [registerHistoryDetail, { openDrawer: openHistoryDetail }] = useDrawer();
  100 + const userStore = useUserStoreWithOut();
  101 + const user = userStore.getUserInfo;
  102 + const role = computed(() => {
  103 + return user?.roleSmallVO?.code;
  104 + });
57 const handleOk = (record) => { 105 const handleOk = (record) => {
58 // 修改父组件的状态 106 // 修改父组件的状态
59 closeModal(); 107 closeModal();
@@ -63,11 +111,28 @@ @@ -63,11 +111,28 @@
63 message.value = ''; 111 message.value = '';
64 } 112 }
65 }; 113 };
66 - const [registerTable, { reload }] = useTable({ 114 + const [registerTable, { reload, setSelectedRowKeys, getForm }] = useTable({
67 api: getInnerProfit, 115 api: getInnerProfit,
68 bordered: true, 116 bordered: true,
69 columns: COLUMNS, 117 columns: COLUMNS,
70 - rowKey: 'id', 118 + rowKey: 'orderId',
  119 + customRow: () => {
  120 + return {
  121 + onClick: (e) => {
  122 + // Prevent row selection when clicking anywhere except checkboxes
  123 + if (!e.target.closest('.ant-checkbox-wrapper')) {
  124 + e.stopPropagation();
  125 + }
  126 + },
  127 + };
  128 + },
  129 + rowSelection: {
  130 + type: 'checkbox',
  131 + selectedRowKeys: checkedKeys as any,
  132 + onSelect: onSelect,
  133 + onSelectAll: onSelectAll,
  134 + checkStrictly: true,
  135 + },
71 formConfig: { 136 formConfig: {
72 labelWidth: 120, 137 labelWidth: 120,
73 schemas: searchFormSchema, 138 schemas: searchFormSchema,
@@ -80,7 +145,7 @@ @@ -80,7 +145,7 @@
80 setting: false, 145 setting: false,
81 }, 146 },
82 actionColumn: { 147 actionColumn: {
83 - width: 240, 148 + width: 260,
84 title: 'Action', 149 title: 'Action',
85 dataIndex: 'action', 150 dataIndex: 'action',
86 }, 151 },
@@ -111,6 +176,18 @@ @@ -111,6 +176,18 @@
111 // }, 176 // },
112 onClick: handleFalse.bind(null, record), 177 onClick: handleFalse.bind(null, record),
113 }, 178 },
  179 + {
  180 + label: '审批通过',
  181 + popConfirm: {
  182 + title: '确认审批?',
  183 + confirm: () => {
  184 + if (record.innerProduceStatus === 0 && role.value === ROLE.ADMIN) {
  185 + handleStatus(record, true);
  186 + }
  187 + return;
  188 + },
  189 + },
  190 + },
114 ]; 191 ];
115 } 192 }
116 return [ 193 return [
@@ -128,6 +205,18 @@ @@ -128,6 +205,18 @@
128 ]; 205 ];
129 } 206 }
130 207
  208 + function createDropActions(record: any) {
  209 + if (!record.editable) {
  210 + const actions = [
  211 + {
  212 + label: '历史记录',
  213 + onClick: handleHistoryDetail.bind(null, record),
  214 + },
  215 + ];
  216 + return actions;
  217 + }
  218 + }
  219 +
131 onMounted(async () => { 220 onMounted(async () => {
132 await orderStore.getDict(); 221 await orderStore.getDict();
133 }); 222 });
@@ -175,5 +264,224 @@ @@ -175,5 +264,224 @@
175 reload(); 264 reload();
176 }, 50); 265 }, 50);
177 } 266 }
  267 +
  268 + async function handleStatus(record, status) {
  269 + try {
  270 + // Add your API call here for updating status
  271 + // Example: await updateStatus({ id: record.id, status: status ? 1 : 2 });
  272 + await setInnerStatus({ orderId: record.orderId });
  273 + reload();
  274 + } catch (error) {
  275 + console.error(error);
  276 + }
  277 + }
  278 +
  279 + function handleHistoryDetail(record) {
  280 + openHistoryDetail(true, {
  281 + data: record,
  282 + });
  283 + }
  284 +
  285 + function handleGoFormDetail() {
  286 + reload();
  287 + }
  288 +
  289 + function handleClearChoose() {
  290 + checkedKeys.value = [];
  291 + orderIds.value = [];
  292 + projectNo.value = [];
  293 + customerCode.value = [];
  294 + innerNo.value = [];
  295 + productionDepartment.value = [];
  296 + detailProjectNoKeys.value = [];
  297 + setSelectedRowKeys([]);
  298 + }
  299 +
  300 + function handleExport() {
  301 + // Get current search parameters from the form
  302 + const values = getForm().getFieldsValue();
  303 +
  304 + // Create export parameters based on whether orderIds are selected
  305 + let exportParams;
  306 +
  307 + // If orderIds are selected, only use those and ignore search params
  308 + if (orderIds.value.length > 0) {
  309 + exportParams = {
  310 + orderIds: orderIds.value
  311 + };
  312 + }
  313 + // Otherwise use the search parameters
  314 + else {
  315 + exportParams = {
  316 + ...values,
  317 + projectNo: values.projectNo || undefined,
  318 + customerCode: values.customerCode || undefined,
  319 + innerNo: values.innerNo || undefined,
  320 + productionDepartment: values.productionDepartment || undefined
  321 + };
  322 + }
  323 +
  324 +
  325 + const token = userStore.getToken;
  326 + axios
  327 + .post(
  328 + '/basic-api/order/cost/innerProfitDetail/exportExcel',
  329 + exportParams,
  330 + {
  331 + headers: {
  332 + Authorization: `${token}`,
  333 + },
  334 + responseType: 'blob',
  335 + },
  336 + )
  337 + .then((response) => {
  338 + // 创建一个 Blob 对象来保存二进制数据
  339 + const blob = new Blob([response.data], { type: 'application/zip' });
  340 + const getFormattedDate = (): string => {
  341 + const date = new Date();
  342 +
  343 + const year = date.getFullYear();
  344 + const month = String(date.getMonth() + 1).padStart(2, '0');
  345 + const day = String(date.getDate()).padStart(2, '0');
  346 +
  347 + const hours = String(date.getHours()).padStart(2, '0');
  348 + const minutes = String(date.getMinutes()).padStart(2, '0');
  349 + const seconds = String(date.getSeconds()).padStart(2, '0');
  350 +
  351 + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  352 + };
  353 + const date = getFormattedDate();
  354 + // 创建一个链接元素用于下载
  355 + const link = document.createElement('a');
  356 + link.href = window.URL.createObjectURL(blob);
  357 + link.download = `内研数据筛选净利润分析表${date}.xlsx`;
  358 + document.body.appendChild(link);
  359 + link.click(); // 自动点击链接,触发下载
  360 + document.body.removeChild(link); // 下载完成后移除链接
  361 + })
  362 + .catch((error) => {
  363 + console.error(error);
  364 + });
  365 + handleClearChoose();
  366 + reload();
  367 + }
  368 +
  369 + async function onSelect(record, selected: boolean) {
  370 + const rowKey = record.orderId;
  371 + if (selected) {
  372 + checkedKeys.value = [...checkedKeys.value, rowKey];
  373 +
  374 + // Add data from the selected row to the corresponding arrays
  375 + if (record.orderId !== undefined && !orderIds.value.includes(record.orderId)) {
  376 + orderIds.value.push(record.orderId);
  377 + }
  378 +
  379 + if (record.projectNo !== undefined && !projectNo.value.includes(record.projectNo)) {
  380 + projectNo.value.push(record.projectNo);
  381 + }
  382 +
  383 + if (record.customerCode !== undefined && !customerCode.value.includes(record.customerCode)) {
  384 + customerCode.value.push(record.customerCode);
  385 + }
  386 +
  387 + if (record.innerNo !== undefined && !innerNo.value.includes(record.innerNo)) {
  388 + innerNo.value.push(record.innerNo);
  389 + }
  390 +
  391 + if (record.productionDepartment !== undefined && !productionDepartment.value.includes(record.productionDepartment)) {
  392 + productionDepartment.value.push(record.productionDepartment);
  393 + }
  394 +
  395 + if (record.detailProjectNo !== undefined && !detailProjectNoKeys.value.includes(record.detailProjectNo)) {
  396 + detailProjectNoKeys.value.push(record.detailProjectNo);
  397 + }
  398 + } else {
  399 + checkedKeys.value = checkedKeys.value.filter((key) => key !== rowKey);
  400 +
  401 + // Remove data from the deselected row from the corresponding arrays
  402 + if (record.orderId !== undefined) {
  403 + orderIds.value = orderIds.value.filter((id) => id !== record.orderId);
  404 + }
  405 +
  406 + if (record.projectNo !== undefined) {
  407 + projectNo.value = projectNo.value.filter((no) => no !== record.projectNo);
  408 + }
  409 +
  410 + if (record.customerCode !== undefined) {
  411 + customerCode.value = customerCode.value.filter((code) => code !== record.customerCode);
  412 + }
  413 +
  414 + if (record.innerNo !== undefined) {
  415 + innerNo.value = innerNo.value.filter((no) => no !== record.innerNo);
  416 + }
  417 +
  418 + if (record.productionDepartment !== undefined) {
  419 + productionDepartment.value = productionDepartment.value.filter(
  420 + (dept) => dept !== record.productionDepartment,
  421 + );
  422 + }
  423 +
  424 + if (record.detailProjectNo !== undefined) {
  425 + detailProjectNoKeys.value = detailProjectNoKeys.value.filter(
  426 + (projectNo) => projectNo !== record.detailProjectNo,
  427 + );
  428 + }
  429 + }
  430 + setSelectedRowKeys(checkedKeys.value as any);
  431 + }
  432 +
  433 + function onSelectAll(selected: boolean, selectedRows: any[]) {
  434 + if (selected) {
  435 + // First clear all previous selections to avoid duplicates
  436 + checkedKeys.value = [];
  437 + orderIds.value = [];
  438 + projectNo.value = [];
  439 + customerCode.value = [];
  440 + innerNo.value = [];
  441 + productionDepartment.value = [];
  442 + detailProjectNoKeys.value = [];
  443 +
  444 + // Add all selected rows
  445 + selectedRows.forEach((row) => {
  446 + const rowKey = row.orderId;
  447 + checkedKeys.value.push(rowKey);
  448 +
  449 + // Add data from each selected row to the corresponding arrays
  450 + if (row.orderId !== undefined) {
  451 + orderIds.value.push(row.orderId);
  452 + }
  453 +
  454 + if (row.projectNo !== undefined) {
  455 + projectNo.value.push(row.projectNo);
  456 + }
  457 +
  458 + if (row.customerCode !== undefined) {
  459 + customerCode.value.push(row.customerCode);
  460 + }
  461 +
  462 + if (row.innerNo !== undefined) {
  463 + innerNo.value.push(row.innerNo);
  464 + }
  465 +
  466 + if (row.productionDepartment !== undefined) {
  467 + productionDepartment.value.push(row.productionDepartment);
  468 + }
  469 +
  470 + if (row.detailProjectNo !== undefined) {
  471 + detailProjectNoKeys.value.push(row.detailProjectNo);
  472 + }
  473 + });
  474 + } else {
  475 + // Clear all selections when deselecting all
  476 + checkedKeys.value = [];
  477 + orderIds.value = [];
  478 + projectNo.value = [];
  479 + customerCode.value = [];
  480 + innerNo.value = [];
  481 + productionDepartment.value = [];
  482 + detailProjectNoKeys.value = [];
  483 + }
  484 + setSelectedRowKeys(checkedKeys.value as any);
  485 + }
178 </script> 486 </script>
179 <style></style> 487 <style></style>
src/views/project/finance/financeProfit/ProductProfit/InnerData/tableData.tsx
@@ -34,6 +34,13 @@ export const FIELDS_BASE_INFO = [ @@ -34,6 +34,13 @@ export const FIELDS_BASE_INFO = [
34 label: '实际发生费用', 34 label: '实际发生费用',
35 rules: [{ required: true }], 35 rules: [{ required: true }],
36 }, 36 },
  37 + {
  38 + field: 'productionDepartmentPredictUnitPrice',
  39 + component: 'Select',
  40 + labelWidth: 150,
  41 + label: '生产科预算单价',
  42 + rules: [{ required: true }],
  43 + },
37 ]; 44 ];
38 45
39 export const EDIT_INFO = [ 46 export const EDIT_INFO = [
@@ -58,5 +65,12 @@ export const EDIT_INFO = [ @@ -58,5 +65,12 @@ export const EDIT_INFO = [
58 label: '实际发生费用', 65 label: '实际发生费用',
59 rules: [{ required: true }], 66 rules: [{ required: true }],
60 }, 67 },
  68 + {
  69 + field: 'productionDepartmentPredictUnitPrice',
  70 + component: 'Select',
  71 + labelWidth: 150,
  72 + label: '生产科预算单价',
  73 + rules: [{ required: true }],
  74 + },
61 ]; 75 ];
62 76
src/views/project/finance/financeProfit/ProductProfit/InnerProduce/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 { getServiceApplyEdit } from '/@/api/project/invoice';
  21 +
  22 + const emit = defineEmits(['success']);
  23 + const input = ref('');
  24 + const baseFieldValues = ref();
  25 + const [register, { setModalProps, redoModalHeight, closeModal }] = useModalInner(async (data) => {
  26 + baseFieldValues.value = data.data;
  27 + baseFieldValues.value.projectNoPrefix = data.id;
  28 + });
  29 + async function handleOk() {
  30 + baseFieldValues.value.applyRemark = input.value;
  31 + await getServiceApplyEdit({
  32 + projectNoPrefix: baseFieldValues.value.projectNoPrefix,
  33 + projectInnerProfitInfoEndTime: baseFieldValues.value.projectInnerProfitInfoEndTime,
  34 + projectInnerProfitInfoStartTime: baseFieldValues.value.projectInnerProfitInfoStartTime,
  35 + applyRemark: baseFieldValues.value.applyRemark,
  36 + type: 'INNER_PROFIT_FIELD_EDIT_APPLY',
  37 + });
  38 + emit('success');
  39 + setTimeout(() => {
  40 + closeModal();
  41 + }, 50);
  42 + }
  43 + function handleShow() {
  44 + input.value = '';
  45 + closeModal();
  46 + }
  47 +</script>
src/views/project/finance/financeProfit/ProductProfit/InnerProduce/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 { getPackageApplyEdit } 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 id = 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 + id.value = data.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 + id: id.value,
  94 + });
  95 + };
  96 +
  97 + return {
  98 + register,
  99 + schemas,
  100 + registerForm,
  101 + handleSubmit,
  102 + handleCloseModal,
  103 + approveReasonRegister,
  104 + openApproveReasonDrawer,
  105 + ROLE,
  106 + role,
  107 + };
  108 + },
  109 + });
  110 +</script>
  111 +<style>
  112 + .container {
  113 + position: fixed; /* 或 absolute, fixed */
  114 + z-index: 10;
  115 + }
  116 +</style>
src/views/project/finance/financeProfit/ProductProfit/InnerProduce/FinanceEdit.vue
@@ -3,31 +3,57 @@ @@ -3,31 +3,57 @@
3 <BasicDrawer 3 <BasicDrawer
4 @register="register" 4 @register="register"
5 v-bind="$attrs" 5 v-bind="$attrs"
6 - title="收入款单" 6 + title="编辑"
7 width="30%" 7 width="30%"
8 :isDetail="true" 8 :isDetail="true"
9 @ok="handleSubmit" 9 @ok="handleSubmit"
10 :showDetailBack="false" 10 :showDetailBack="false"
11 okText="保存" 11 okText="保存"
  12 + @visible-change="handleShow"
12 showFooter 13 showFooter
13 :destroyOnClose="true" 14 :destroyOnClose="true"
14 > 15 >
15 <!-- <div> 16 <!-- <div>
16 <BasicForm @register="registerForm" /> 17 <BasicForm @register="registerForm" />
17 </div> --> 18 </div> -->
18 - <div style="font-size: 15px">实际收款金额1$</div>  
19 - <a-input v-model:value="input1" placeholder="请输入" :disabled="status === 10" auto-size />  
20 - <div style="margin: 16px 0"></div>  
21 - <div style="font-size: 15px">实际收款金额2$</div>  
22 - <a-input v-model:value="input2" placeholder="请输入" :disabled="status === 10" auto-size /> 19 + <!-- <div style="font-size: 15px">研发复制费合计¥</div>
  20 + <a-input
  21 + v-model:value="input1"
  22 + placeholder="请输入"
  23 + :disabled="status1 === 'LOCKED'"
  24 + auto-size
  25 + /> -->
23 <div style="margin: 16px 0"></div> 26 <div style="margin: 16px 0"></div>
24 <div style="font-size: 15px">项目开始时间</div> 27 <div style="font-size: 15px">项目开始时间</div>
25 - <a-date-picker v-model:value="input3" :disabled="status === 10" auto-size /> 28 + <a-date-picker v-model:value="input3" :disabled="status3 === 'LOCKED'" auto-size />
26 <div style="margin: 16px 0"></div> 29 <div style="margin: 16px 0"></div>
27 <div style="font-size: 15px">项目结束时间</div> 30 <div style="font-size: 15px">项目结束时间</div>
28 - <a-date-picker v-model:value="input4" :disabled="status === 10" auto-size /> 31 + <a-date-picker v-model:value="input4" :disabled="status4 === 'LOCKED'" auto-size />
  32 + <!-- <div style="margin: 16px 0"></div>
  33 + <div style="font-size: 15px">西班牙已发提成¥</div>
  34 + <a-input
  35 + v-model:value="input2"
  36 + placeholder="请输入"
  37 + :disabled="status2 === 'LOCKED'"
  38 + auto-size
  39 + />
  40 + <div style="margin: 16px 0"></div>
  41 + <div style="font-size: 15px">中国团队已发提成¥</div>
  42 + <a-input
  43 + v-model:value="input5"
  44 + placeholder="请输入"
  45 + :disabled="status5 === 'LOCKED'"
  46 + auto-size
  47 + />
  48 + <div style="margin: 16px 0"></div>
  49 + <div style="font-size: 15px">实际汇率¥</div>
  50 + <a-input
  51 + v-model:value="input6"
  52 + placeholder="请输入"
  53 + :disabled="status6 === 'LOCKED'"
  54 + auto-size
  55 + /> -->
29 <div style="margin: 16px 0"></div> 56 <div style="margin: 16px 0"></div>
30 -  
31 <!-- <template #titleToolbar> <a-button type="primary"> 申请编辑权限 </a-button></template> --> 57 <!-- <template #titleToolbar> <a-button type="primary"> 申请编辑权限 </a-button></template> -->
32 <template #appendFooter> 58 <template #appendFooter>
33 <!-- <a-button type="primary" @click="onGoCheckDetail"> 申请权限</a-button> --> 59 <!-- <a-button type="primary" @click="onGoCheckDetail"> 申请权限</a-button> -->
@@ -39,10 +65,11 @@ @@ -39,10 +65,11 @@
39 import { BasicDrawer, useDrawerInner } from '@/components/Drawer'; 65 import { BasicDrawer, useDrawerInner } from '@/components/Drawer';
40 import { BasicForm, FormSchema, useForm } from '@/components/Form'; 66 import { BasicForm, FormSchema, useForm } from '@/components/Form';
41 import { defineComponent, ref, computed, unref, toRaw, reactive } from 'vue'; 67 import { defineComponent, ref, computed, unref, toRaw, reactive } from 'vue';
42 - import { getEmailList } from '/@/api/sys/config';  
43 - import { updateAmount } from '@/api/project/invoice'; 68 + import { getServiceEdit } from '@/api/project/invoice';
44 import { useMessage } from '/@/hooks/web/useMessage'; 69 import { useMessage } from '/@/hooks/web/useMessage';
45 import { ROLE } from './type.d'; 70 import { ROLE } from './type.d';
  71 + import type { Dayjs } from 'dayjs';
  72 + import dayjs from 'dayjs';
46 73
47 const emit = defineEmits(['success']); 74 const emit = defineEmits(['success']);
48 const role = computed(() => { 75 const role = computed(() => {
@@ -59,16 +86,16 @@ @@ -59,16 +86,16 @@
59 // label: '实际应收金额', 86 // label: '实际应收金额',
60 // }, 87 // },
61 { 88 {
62 - field: 'actualPayedAmount1', 89 + field: 'developmentCopyRmbTotalPrice',
63 component: 'InputNumber', 90 component: 'InputNumber',
64 labelWidth: 250, 91 labelWidth: 250,
65 colProps: { 92 colProps: {
66 span: 23, 93 span: 23,
67 }, 94 },
68 - componentProps: () => ({  
69 - disabled: status.value === 10,  
70 - }),  
71 - label: '实际应收金额1$', 95 + // componentProps: () => ({
  96 + // disabled: status.value === 10,
  97 + // }),
  98 + label: '研发复制费合计¥',
72 }, 99 },
73 { 100 {
74 field: 'actualPayedAmount2', 101 field: 'actualPayedAmount2',
@@ -77,9 +104,7 @@ @@ -77,9 +104,7 @@
77 colProps: { 104 colProps: {
78 span: 23, 105 span: 23,
79 }, 106 },
80 - componentProps: () => ({  
81 - disabled: status.value === 10,  
82 - }), 107 +
83 label: '实际应收金额2$', 108 label: '实际应收金额2$',
84 }, 109 },
85 { 110 {
@@ -89,9 +114,7 @@ @@ -89,9 +114,7 @@
89 colProps: { 114 colProps: {
90 span: 23, 115 span: 23,
91 }, 116 },
92 - componentProps: () => ({  
93 - disabled: status.value === 10,  
94 - }), 117 +
95 label: '实际应收金额3$', 118 label: '实际应收金额3$',
96 }, 119 },
97 { 120 {
@@ -101,9 +124,7 @@ @@ -101,9 +124,7 @@
101 colProps: { 124 colProps: {
102 span: 23, 125 span: 23,
103 }, 126 },
104 - componentProps: () => ({  
105 - disabled: status.value === 10,  
106 - }), 127 +
107 label: '其他费用金额$', 128 label: '其他费用金额$',
108 }, 129 },
109 ]; 130 ];
@@ -120,21 +141,60 @@ @@ -120,21 +141,60 @@
120 const { error } = createMessage; 141 const { error } = createMessage;
121 142
122 const update = ref(); 143 const update = ref();
123 - const status = ref(); 144 + const status1 = ref();
  145 + const status2 = ref();
  146 + const status3 = ref();
  147 + const status4 = ref();
  148 + const status5 = ref();
  149 + const status6 = ref();
124 150
125 const input1 = ref(); 151 const input1 = ref();
126 const input2 = ref(); 152 const input2 = ref();
127 const input3 = ref(); 153 const input3 = ref();
128 const input4 = ref(); 154 const input4 = ref();
  155 +
  156 + const input5 = ref();
  157 + const input6 = ref();
129 const id = ref(); 158 const id = ref();
  159 + // function formatDate(dateStr: string): string {
  160 + // const date = new Date(dateStr);
  161 + // const year = date.getFullYear();
  162 + // const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始,+1
  163 + // const day = String(date.getDate()).padStart(2, '0');
  164 + // const hours = String(date.getHours()).padStart(2, '0');
  165 + // const minutes = String(date.getMinutes()).padStart(2, '0');
  166 + // const seconds = String(date.getSeconds()).padStart(2, '0');
  167 +
  168 + // // 返回格式化后的字符串:'YYYY-MM-DD HH:mm:ss'
  169 + // return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  170 + // }
  171 + // function formatDateToDateOnly(dateStr: string): string {
  172 + // const date = new Date(dateStr);
  173 + // const year = date.getFullYear();
  174 + // const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始,+1
  175 + // const day = String(date.getDate()).padStart(2, '0');
  176 +
  177 + // // 返回格式化后的日期字符串:'YYYY-MM-DD'
  178 + // return `${year}-${month}-${day}`;
  179 + // }
130 const [register, { setDrawerProps, closeDrawer }] = useDrawerInner((data) => { 180 const [register, { setDrawerProps, closeDrawer }] = useDrawerInner((data) => {
131 // 方式1 181 // 方式1
132 - status.value = data.data.invoiceStatus;  
133 - id.value = data.data.invoiceId;  
134 - input1.value = data.data.invoiceActualPayedAmount1;  
135 - input2.value = data.data.invoiceActualPayedAmount2;  
136 - input3.value = data.data.invoiceActualPayedAmount3;  
137 - input4.value = data.data.invoiceOtherAmount; 182 + if (data.data.lockFields) {
  183 + status1.value = data?.data?.lockFields?.developmentCopyRmbTotalPrice;
  184 + status2.value = data?.data?.lockFields?.spainPaidRmbCommission;
  185 + status3.value = data?.data?.lockFields?.projectInnerProfitInfoStartTime;
  186 + status4.value = data?.data?.lockFields?.projectInnerProfitInfoEndTime;
  187 + status5.value = data?.data?.lockFields?.paidRmbCommission;
  188 + status6.value = data?.data?.lockFields?.actualExchangeRate;
  189 + }
  190 + id.value = data?.data?.projectNoPrefix;
  191 + input1.value = data?.data?.developmentCopyRmbTotalPrice?.toFixed(2);
  192 + input2.value = data?.data?.spainPaidRmbCommission?.toFixed(2);
  193 + input3.value = data?.data?.produceStartTime ? dayjs(data?.data?.produceStartTime) : null;
  194 + input4.value = data?.data?.produceEndTime ? dayjs(data?.data?.produceEndTime) : null;
  195 + input5.value = data?.data?.paidRmbCommission?.toFixed(2);
  196 + input6.value = data?.data?.actualExchangeRate?.toFixed(2);
  197 +
138 resetFields(); 198 resetFields();
139 setDrawerProps({ confirmLoading: false }); 199 setDrawerProps({ confirmLoading: false });
140 setFieldsValue({ 200 setFieldsValue({
@@ -150,18 +210,26 @@ @@ -150,18 +210,26 @@
150 // id: update.value.data.id, 210 // id: update.value.data.id,
151 // bgUrl: update.value.data.bgUrl, 211 // bgUrl: update.value.data.bgUrl,
152 // }; 212 // };
153 - if (!input1.value || !input2.value || !input3.value || !input4.value) { 213 + if (!input3.value || !input4.value) {
154 error('选项不能为空'); 214 error('选项不能为空');
155 } else { 215 } else {
156 - await updateAmount({  
157 - id: id.value,  
158 - actualPayedAmount1: input1.value,  
159 - actualPayedAmount2: input2.value,  
160 - actualPayedAmount3: input3.value,  
161 - otherAmount: input4.value, 216 + await getServiceEdit({
  217 + projectNoPrefix: id.value,
  218 + projectInnerProfitInfoStartTime: input3.value,
  219 + projectInnerProfitInfoEndTime: input4.value,
162 }); 220 });
163 emit('success'); 221 emit('success');
164 closeDrawer(); 222 closeDrawer();
165 } 223 }
166 } 224 }
  225 + function handleShow(visible: boolean) {
  226 + if (!visible) {
  227 + input1.value = '';
  228 + input2.value = '';
  229 + input3.value = '';
  230 + input4.value = '';
  231 + input5.value = '';
  232 + input6.value = '';
  233 + }
  234 + }
167 </script> 235 </script>
src/views/project/finance/financeProfit/ProductProfit/InnerProduce/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, List } from 'ant-design-vue';
  68 + import { FormSchema } from '/@/components/Form/index';
  69 +
  70 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  71 + import { getProjectOptLog } 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 orderId = 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 getProjectOptLog({
  138 + projectNoPrefix: data,
  139 + type: [30],
  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 getProjectOptLog({
  148 + projectNoPrefix: data,
  149 + type: [1,3],
  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 + orderId.value = data.data.projectNoPrefix;
  160 + getOrderOptLogFunc(orderId.value, 1, 1);
  161 + getOrderOptLogFunc(orderId.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(orderId.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(orderId.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/ProductProfit/InnerProduce/data.tsx
@@ -113,14 +113,14 @@ export const COLUMNS = [ @@ -113,14 +113,14 @@ export const COLUMNS = [
113 dataIndex: 'orderCount', 113 dataIndex: 'orderCount',
114 width: 100, 114 width: 100,
115 }, 115 },
116 - {  
117 - title: '生产科单价¥',  
118 - dataIndex: 'productionDepartmentPrice',  
119 - width: 120,  
120 - customRender: (column) => {  
121 - return column.record?.productionDepartmentPrice?.toFixed(2);  
122 - },  
123 - }, 116 + // {
  117 + // title: '生产科单价¥',
  118 + // dataIndex: 'productionDepartmentPrice',
  119 + // width: 120,
  120 + // customRender: (column) => {
  121 + // return column.record?.productionDepartmentPrice?.toFixed(2);
  122 + // },
  123 + // },
124 { 124 {
125 title: '生产科总价¥', 125 title: '生产科总价¥',
126 dataIndex: 'productionDepartmentTotalPrice', 126 dataIndex: 'productionDepartmentTotalPrice',
@@ -151,7 +151,7 @@ export const COLUMNS = [ @@ -151,7 +151,7 @@ export const COLUMNS = [
151 width: 120, 151 width: 120,
152 customRender: (column) => { 152 customRender: (column) => {
153 if (column.record?.predictRatio) { 153 if (column.record?.predictRatio) {
154 - return column.record?.predictRatio?.toFixed(2) + '%'; 154 + return (column.record?.predictRatio * 100).toFixed(2) + '%';
155 } 155 }
156 return column.record?.predictRatio?.toFixed(2); 156 return column.record?.predictRatio?.toFixed(2);
157 }, 157 },
@@ -162,7 +162,7 @@ export const COLUMNS = [ @@ -162,7 +162,7 @@ export const COLUMNS = [
162 width: 190, 162 width: 190,
163 customRender: (column) => { 163 customRender: (column) => {
164 if (column.record?.predictAndActualRatio) { 164 if (column.record?.predictAndActualRatio) {
165 - return column.record?.predictAndActualRatio?.toFixed(2) + '%'; 165 + return (column.record?.predictAndActualRatio * 100).toFixed(2) + '%';
166 } 166 }
167 return column.record?.predictAndActualRatio?.toFixed(2); 167 return column.record?.predictAndActualRatio?.toFixed(2);
168 }, 168 },
@@ -181,7 +181,7 @@ export const COLUMNS = [ @@ -181,7 +181,7 @@ export const COLUMNS = [
181 width: 120, 181 width: 120,
182 customRender: (column) => { 182 customRender: (column) => {
183 if (column.record?.beforeGrossProfitRate) { 183 if (column.record?.beforeGrossProfitRate) {
184 - return column.record?.beforeGrossProfitRate?.toFixed(2) + '%'; 184 + return (column.record?.beforeGrossProfitRate * 100).toFixed(2) + '%';
185 } 185 }
186 return column.record?.beforeGrossProfitRate?.toFixed(2); 186 return column.record?.beforeGrossProfitRate?.toFixed(2);
187 }, 187 },
@@ -200,7 +200,7 @@ export const COLUMNS = [ @@ -200,7 +200,7 @@ export const COLUMNS = [
200 width: 120, 200 width: 120,
201 customRender: (column) => { 201 customRender: (column) => {
202 if (column.record?.grossProfitRate) { 202 if (column.record?.grossProfitRate) {
203 - return column.record?.grossProfitRate?.toFixed(2) + '%'; 203 + return (column.record?.grossProfitRate * 100).toFixed(2) + '%';
204 } 204 }
205 return column.record?.grossProfitRate?.toFixed(2); 205 return column.record?.grossProfitRate?.toFixed(2);
206 }, 206 },
@@ -235,12 +235,27 @@ export const COLUMNS = [ @@ -235,12 +235,27 @@ export const COLUMNS = [
235 width: 150, 235 width: 150,
236 customRender: (column) => { 236 customRender: (column) => {
237 if (column.record?.innerProductionProfitRate) { 237 if (column.record?.innerProductionProfitRate) {
238 - return column.record?.innerProductionProfitRate?.toFixed(2) + '%'; 238 + return (column.record?.innerProductionProfitRate * 100).toFixed(2) + '%';
239 } 239 }
240 return column.record?.innerProductionProfitRate?.toFixed(2); 240 return column.record?.innerProductionProfitRate?.toFixed(2);
241 }, 241 },
242 }, 242 },
243 { 243 {
  244 + title: '状态',
  245 + dataIndex: 'status',
  246 + width: 120,
  247 + customRender: (column) => {
  248 + if (column.record?.innerProductionStatus === null ||
  249 + column.record?.innerProductionStatus === -1) {
  250 + return '未完成';
  251 + } else if (column.record?.innerProductionStatus === 0) {
  252 + return '待审核';
  253 + } else if (column.record?.innerProductionStatus === 1) {
  254 + return '已审核';
  255 + }
  256 + },
  257 + },
  258 + {
244 title: '文件', 259 title: '文件',
245 dataIndex: 'fileUrl', 260 dataIndex: 'fileUrl',
246 width: 120, 261 width: 120,
src/views/project/finance/financeProfit/ProductProfit/InnerProduce/index.vue
1 <template> 1 <template>
2 <div> 2 <div>
3 <BasicTable @register="registerTable" :bordered="true"> 3 <BasicTable @register="registerTable" :bordered="true">
  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>
4 <template #bodyCell="{ column, record }"> 23 <template #bodyCell="{ column, record }">
5 <template v-if="column.key === 'picUrl'"> 24 <template v-if="column.key === 'picUrl'">
6 <img :z-index="100000" :width="50" :height="50" :src="record?.picUrl" /> 25 <img :z-index="100000" :width="50" :height="50" :src="record?.picUrl" />
7 </template> 26 </template>
8 - <!-- <template v-if="column.key === 'action'">  
9 - <TableAction :actions="createActions(record)" />  
10 - </template> --> 27 + <template v-if="column.key === 'action'">
  28 + <TableAction
  29 + :actions="createActions(record)"
  30 + :dropDownActions="createDropActions(record)"
  31 + />
  32 + </template>
11 <!-- <template v-if="column.key === 'relationValue'"> 33 <!-- <template v-if="column.key === 'relationValue'">
12 <a-input 34 <a-input
13 v-if="record.settingValue === 'A01'" 35 v-if="record.settingValue === 'A01'"
@@ -19,6 +41,15 @@ @@ -19,6 +41,15 @@
19 </span> 41 </span>
20 </template> --> 42 </template> -->
21 </template> 43 </template>
  44 + <template #toolbar>
  45 + <a-button
  46 + type="primary"
  47 + @click="handleExport"
  48 + v-if="role == ROLE.ADMIN || role == ROLE.FINANCE"
  49 + :style="{ borderRadius: '5px 5px 5px 5px' }"
  50 + >导出</a-button
  51 + >
  52 + </template>
22 </BasicTable> 53 </BasicTable>
23 <!-- <BasicModal 54 <!-- <BasicModal
24 title="拒绝原因" 55 title="拒绝原因"
@@ -32,25 +63,44 @@ @@ -32,25 +63,44 @@
32 <a-textarea :rows="6" placeholder="请输入拒绝原因" v-model:value="message" /> 63 <a-textarea :rows="6" placeholder="请输入拒绝原因" v-model:value="message" />
33 </div> 64 </div>
34 </BasicModal> --> 65 </BasicModal> -->
  66 + <CheckDetail @register="checkModalRegister" :onGoFormDetail="handleGoFormDetail" />
35 <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" /> 67 <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" />
  68 + <HistoryDetail @register="registerHistoryDetail" />
36 </div> 69 </div>
37 </template> 70 </template>
38 <script setup lang="ts"> 71 <script setup lang="ts">
39 import { BasicTable, useTable, TableAction } from '/@/components/Table'; 72 import { BasicTable, useTable, TableAction } from '/@/components/Table';
40 - import { getInnerProduceProfit } from '@/api/project/invoice'; 73 + import { getInnerProduceProfit, setInnerProfitSetStatus } from '@/api/project/invoice';
41 import { searchFormSchema, COLUMNS } from './data'; 74 import { searchFormSchema, COLUMNS } from './data';
42 import { BasicModal, useModal } from '/@/components/Modal'; 75 import { BasicModal, useModal } from '/@/components/Modal';
43 import { useMessage } from '/@/hooks/web/useMessage'; 76 import { useMessage } from '/@/hooks/web/useMessage';
44 - import { onMounted, ref } from 'vue'; 77 + import { onMounted, ref, computed } from 'vue';
  78 + import axios from 'axios';
45 import { useDrawer } from '/@/components/Drawer'; 79 import { useDrawer } from '/@/components/Drawer';
46 import FinanceEdit from './FinanceEdit.vue'; 80 import FinanceEdit from './FinanceEdit.vue';
  81 + import CheckDetail from './CheckDetail.vue';
  82 + import HistoryDetail from './HistoryDetail.vue';
47 import { useOrderStoreWithOut } from '/@/store/modules/order'; 83 import { useOrderStoreWithOut } from '/@/store/modules/order';
  84 + import { useUserStoreWithOut } from '/@/store/modules/user';
  85 + import { RoleEnum } from '/@/enums/roleEnum';
  86 + import { ROLE } from '../../../type.d';
48 87
49 const { createMessage } = useMessage(); 88 const { createMessage } = useMessage();
50 const { error } = createMessage; 89 const { error } = createMessage;
51 const message = ref(); 90 const message = ref();
  91 + const checkedKeys = ref<string[]>([]);
  92 + const invoiceIdKeys = ref<string[]>([]);
  93 + const checkIdKeys = ref<string[]>([]);
  94 + const detailProjectNoKeys = ref<string[]>([]);
52 const orderStore = useOrderStoreWithOut(); 95 const orderStore = useOrderStoreWithOut();
  96 + const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer();
53 const [registerFinanceEdit, { openDrawer: openFinanceEdit }] = useDrawer(); 97 const [registerFinanceEdit, { openDrawer: openFinanceEdit }] = useDrawer();
  98 + const [registerHistoryDetail, { openDrawer: openHistoryDetail }] = useDrawer();
  99 + const userStore = useUserStoreWithOut();
  100 + const user = userStore.getUserInfo;
  101 + const role = computed(() => {
  102 + return user?.roleSmallVO?.code;
  103 + });
54 const handleOk = (record) => { 104 const handleOk = (record) => {
55 // 修改父组件的状态 105 // 修改父组件的状态
56 closeModal(); 106 closeModal();
@@ -60,12 +110,18 @@ @@ -60,12 +110,18 @@
60 message.value = ''; 110 message.value = '';
61 } 111 }
62 }; 112 };
63 - const [registerTable, { reload }] = useTable({ 113 + const [registerTable, { reload, setSelectedRowKeys }] = useTable({
64 api: getInnerProduceProfit, 114 api: getInnerProduceProfit,
65 bordered: true, 115 bordered: true,
66 columns: COLUMNS, 116 columns: COLUMNS,
67 clickToRowSelect: false, 117 clickToRowSelect: false,
68 - rowKey: 'id', 118 + rowKey: (record) => record.projectNoPrefix || record.id || record.serialNumber,
  119 + rowSelection: {
  120 + type: 'checkbox',
  121 + selectedRowKeys: checkedKeys as any,
  122 + onSelect: onSelect,
  123 + onSelectAll: onSelectAll,
  124 + },
69 formConfig: { 125 formConfig: {
70 labelWidth: 120, 126 labelWidth: 120,
71 schemas: searchFormSchema, 127 schemas: searchFormSchema,
@@ -77,50 +133,79 @@ @@ -77,50 +133,79 @@
77 tableSetting: { 133 tableSetting: {
78 setting: false, 134 setting: false,
79 }, 135 },
  136 + actionColumn: {
  137 + width: 260,
  138 + title: 'Action',
  139 + dataIndex: 'action',
  140 + },
80 }); 141 });
81 142
82 - // function createActions(record: any): any[] {  
83 - // if (!record.editable) {  
84 - // return [  
85 - // // {  
86 - // // label: '财务编辑',  
87 - // // onClick: handleFinanceEdit.bind(null, record),  
88 - // // },  
89 - // // {  
90 - // // label: '编辑',  
91 - // // onClick: handleEdit.bind(null, record),  
92 - // // },  
93 - // // {  
94 - // // label: '删除',  
95 - // // popConfirm: {  
96 - // // title: '确认删除?',  
97 - // // confirm: handleDelete.bind(null, record),  
98 - // // },  
99 - // // },  
100 - // // {  
101 - // // label: '申请权限',  
102 - // // // popConfirm: {  
103 - // // // title: '确认申请?',  
104 - // // // confirm: handleFalse.bind(null, record),  
105 - // // // },  
106 - // // onClick: handleFalse.bind(null, record),  
107 - // // },  
108 - // ];  
109 - // }  
110 - // return [  
111 - // {  
112 - // label: '保存',  
113 - // onClick: handleSave.bind(null, record),  
114 - // },  
115 - // {  
116 - // label: '取消',  
117 - // popConfirm: {  
118 - // title: '是否取消编辑',  
119 - // confirm: handleCancel.bind(null, record),  
120 - // },  
121 - // },  
122 - // ];  
123 - // } 143 + function createActions(record: any): any[] {
  144 + if (!record.editable) {
  145 + return [
  146 + {
  147 + label: '财务编辑',
  148 + onClick: handleFinanceEdit.bind(null, record),
  149 + },
  150 + // {
  151 + // label: '编辑',
  152 + // onClick: handleEdit.bind(null, record),
  153 + // },
  154 + // {
  155 + // label: '删除',
  156 + // popConfirm: {
  157 + // title: '确认删除?',
  158 + // confirm: handleDelete.bind(null, record),
  159 + // },
  160 + // },
  161 + {
  162 + label: '申请权限',
  163 + // popConfirm: {
  164 + // title: '确认申请?',
  165 + // confirm: handleFalse.bind(null, record),
  166 + // },
  167 + onClick: handleFalse.bind(null, record),
  168 + },
  169 + {
  170 + label: '审核通过',
  171 + popConfirm: {
  172 + title: '确认审核?',
  173 + confirm: () => {
  174 + if (record.innerProductionStatus === 0 && role.value === ROLE.ADMIN) {
  175 + handleStatus(record, true);
  176 + }
  177 + return;
  178 + },
  179 + },
  180 + },
  181 + ];
  182 + }
  183 + return [
  184 + {
  185 + label: '保存',
  186 + onClick: handleSave.bind(null, record),
  187 + },
  188 + {
  189 + label: '取消',
  190 + popConfirm: {
  191 + title: '是否取消编辑',
  192 + confirm: handleCancel.bind(null, record),
  193 + },
  194 + },
  195 + ];
  196 + }
  197 +
  198 + function createDropActions(record: any) {
  199 + if (!record.editable) {
  200 + const actions = [
  201 + {
  202 + label: '历史记录',
  203 + onClick: handleHistoryDetail.bind(null, record),
  204 + },
  205 + ];
  206 + return actions;
  207 + }
  208 + }
124 209
125 onMounted(async () => { 210 onMounted(async () => {
126 await orderStore.getDict(); 211 await orderStore.getDict();
@@ -132,10 +217,11 @@ @@ -132,10 +217,11 @@
132 }); 217 });
133 } 218 }
134 219
135 - // async function handleFalse(record: any) {  
136 - // console.log(record);  
137 - // // openModal(true, { record });  
138 - // } 220 + function handleFalse(record, e) {
  221 + openCheckDetailDrawer(true, record);
  222 + e?.stopPropagation();
  223 + return false;
  224 + }
139 225
140 async function handleSave(record) { 226 async function handleSave(record) {
141 await saveConfig({ id: record.id, relationValue: record.relationValue }); 227 await saveConfig({ id: record.id, relationValue: record.relationValue });
@@ -154,8 +240,170 @@ @@ -154,8 +240,170 @@
154 record.onEdit?.(false, false); 240 record.onEdit?.(false, false);
155 } 241 }
156 242
157 - async function handleDelete(record) {  
158 - await deleteConfig({ ids: [record.id] }); 243 + // async function handleDelete(record) {
  244 + // await deleteConfig({ ids: [record.id] });
  245 + // reload();
  246 + // }
  247 + function handleSuccess() {
  248 + setTimeout(() => {
  249 + reload();
  250 + }, 50);
  251 + }
  252 +
  253 + async function handleStatus(record, status) {
  254 + try {
  255 + await setInnerProfitSetStatus({
  256 + projectNo: record.projectNoPrefix,
  257 + customerCode: record.customerCode
  258 + });
  259 + reload();
  260 + } catch (error) {
  261 + console.error(error);
  262 + }
  263 + }
  264 +
  265 + function handleHistoryDetail(record) {
  266 + openHistoryDetail(true, {
  267 + data: record,
  268 + });
  269 + }
  270 +
  271 + function handleGoFormDetail() {
  272 + // Add your logic for form detail navigation
  273 + }
  274 +
  275 + function handleClearChoose() {
  276 + checkedKeys.value = [];
  277 + detailProjectNoKeys.value = [];
  278 + invoiceIdKeys.value = [];
  279 + checkIdKeys.value = [];
  280 + }
  281 + async function onSelect(record, selected: boolean) {
  282 + const rowKey = record.projectNoPrefix || record.id || record.serialNumber;
  283 + if (selected) {
  284 + checkedKeys.value = [...checkedKeys.value, rowKey];
  285 +
  286 + // 使用projectNoPrefix作为单个值,添加到detailProjectNoKeys中
  287 + if (record.projectNoPrefix !== undefined) {
  288 + // 如果是单个值,检查是否已存在,然后添加到数组
  289 + if (!detailProjectNoKeys.value.includes(record.projectNoPrefix)) {
  290 + detailProjectNoKeys.value.push(record.projectNoPrefix);
  291 + }
  292 + }
  293 +
  294 + if (record.invoiceId !== undefined) {
  295 + invoiceIdKeys.value = [...invoiceIdKeys.value, record.invoiceId];
  296 + }
  297 +
  298 + if (record.checkId !== undefined) {
  299 + checkIdKeys.value = [...checkIdKeys.value, record.checkId];
  300 + }
  301 + } else {
  302 + checkedKeys.value = checkedKeys.value.filter((key) => key !== rowKey);
  303 +
  304 + // 从detailProjectNoKeys中移除projectNoPrefix
  305 + if (record.projectNoPrefix !== undefined) {
  306 + // 直接移除单个值
  307 + detailProjectNoKeys.value = detailProjectNoKeys.value.filter(
  308 + (projectNo) => projectNo !== record.projectNoPrefix
  309 + );
  310 + }
  311 +
  312 + if (record.invoiceId !== undefined) {
  313 + invoiceIdKeys.value = invoiceIdKeys.value.filter(
  314 + (invoiceId) => invoiceId !== record.invoiceId,
  315 + );
  316 + }
  317 +
  318 + if (record.checkId !== undefined) {
  319 + checkIdKeys.value = checkIdKeys.value.filter((checkId) => checkId !== record.checkId);
  320 + }
  321 + }
  322 + setSelectedRowKeys(checkedKeys.value as any);
  323 + }
  324 +
  325 + function onSelectAll(selected: boolean, selectedRows: any[]) {
  326 + if (selected) {
  327 + // 先清空之前的选择,避免重复添加
  328 + checkedKeys.value = [];
  329 + detailProjectNoKeys.value = [];
  330 + invoiceIdKeys.value = [];
  331 + checkIdKeys.value = [];
  332 +
  333 + // 重新添加所有选中的行
  334 + selectedRows.forEach((row) => {
  335 + const rowKey = row.projectNoPrefix || row.id || row.serialNumber;
  336 + checkedKeys.value.push(rowKey);
  337 +
  338 + // 使用projectNoPrefix作为单个值,添加到detailProjectNoKeys中
  339 + if (row.projectNoPrefix !== undefined) {
  340 + // 由于已经清空了数组,不需要检查是否存在
  341 + detailProjectNoKeys.value.push(row.projectNoPrefix);
  342 + }
  343 +
  344 + if (row.invoiceId !== undefined) {
  345 + invoiceIdKeys.value.push(row.invoiceId);
  346 + }
  347 +
  348 + if (row.checkId !== undefined) {
  349 + checkIdKeys.value.push(row.checkId);
  350 + }
  351 + });
  352 + } else {
  353 + // 取消全选时,清空所有选择
  354 + checkedKeys.value = [];
  355 + detailProjectNoKeys.value = [];
  356 + invoiceIdKeys.value = [];
  357 + checkIdKeys.value = [];
  358 + }
  359 + setSelectedRowKeys(checkedKeys.value as any);
  360 + }
  361 + function handleExport() {
  362 + if (checkedKeys.value.length <= 0) {
  363 + createMessage.warn('请选择数据!');
  364 + return;
  365 + }
  366 + const token = userStore.getToken;
  367 + axios
  368 + .post(
  369 + '/basic-api/project/innerProfitInfo/exportExcel',
  370 + { detailProjectNo: detailProjectNoKeys.value },
  371 + {
  372 + headers: {
  373 + Authorization: `${token}`, // 去掉引号
  374 + },
  375 + responseType: 'blob', // 设置响应类型为 'blob'
  376 + },
  377 + )
  378 + .then((response) => {
  379 + // 创建一个 Blob 对象来保存二进制数据
  380 + const blob = new Blob([response.data], { type: 'application/zip' });
  381 + const getFormattedDate = (): string => {
  382 + const date = new Date();
  383 +
  384 + const year = date.getFullYear();
  385 + const month = String(date.getMonth() + 1).padStart(2, '0');
  386 + const day = String(date.getDate()).padStart(2, '0');
  387 +
  388 + const hours = String(date.getHours()).padStart(2, '0');
  389 + const minutes = String(date.getMinutes()).padStart(2, '0');
  390 + const seconds = String(date.getSeconds()).padStart(2, '0');
  391 +
  392 + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  393 + };
  394 + const date = getFormattedDate();
  395 + // 创建一个链接元素用于下载
  396 + const link = document.createElement('a');
  397 + link.href = window.URL.createObjectURL(blob);
  398 + link.download = `内产生产净利润分析表${date}.xlsx`; // 你可以为文件命名
  399 + document.body.appendChild(link);
  400 + link.click(); // 自动点击链接,触发下载
  401 + document.body.removeChild(link); // 下载完成后移除链接
  402 + })
  403 + .catch((error) => {
  404 + console.error(error);
  405 + });
  406 + handleClearChoose();
159 reload(); 407 reload();
160 } 408 }
161 </script> 409 </script>
src/views/project/finance/financeProfit/ProductProfit/InnerProduce/tableData.tsx
@@ -21,74 +21,18 @@ const orderStore = useOrderStoreWithOut(); @@ -21,74 +21,18 @@ const orderStore = useOrderStoreWithOut();
21 // 基本信息 21 // 基本信息
22 export const FIELDS_BASE_INFO = [ 22 export const FIELDS_BASE_INFO = [
23 { 23 {
24 - field: 'customerCode', 24 + field: 'projectInnerProfitInfoStartTime',
25 component: 'Select', 25 component: 'Select',
26 labelWidth: 150, 26 labelWidth: 150,
27 - label: '客户编码', 27 + label: '项目开始时间',
28 rules: [{ required: true }], 28 rules: [{ required: true }],
29 }, 29 },
30 { 30 {
31 - field: 'projectNo',  
32 - component: 'Input',  
33 - labelWidth: 150,  
34 - label: '项目号',  
35 - rules: [{ required: true }],  
36 - },  
37 - {  
38 - field: 'productionDepartment', 31 + field: 'projectInnerProfitInfoEndTime',
39 component: 'Select', 32 component: 'Select',
40 - // componentProps: {  
41 - // options: productionDepartmentOptions,  
42 - // },  
43 labelWidth: 150, 33 labelWidth: 150,
44 - label: '生产科', 34 + label: '项目结束时间',
45 rules: [{ required: true }], 35 rules: [{ required: true }],
46 }, 36 },
47 -  
48 - {  
49 - field: 'innerNo',  
50 - component: 'Input',  
51 - labelWidth: 150,  
52 - label: '内部编号',  
53 - rules: [  
54 - { required: true },  
55 - {  
56 - validator: async (rule, value) => {  
57 - if (value.includes(' ')) {  
58 - return Promise.reject();  
59 - }  
60 - return Promise.resolve();  
61 - },  
62 - message: '内容存在空格,请检查',  
63 - trigger: ['change', 'blur'],  
64 - },  
65 - ],  
66 - },  
67 - {  
68 - field: 'customerPo',  
69 - component: 'Input',  
70 - labelWidth: 150,  
71 - label: '客户po号',  
72 - rules: [{ required: true }],  
73 - },  
74 - {  
75 - field: 'customerStyle',  
76 - component: 'Input',  
77 - labelWidth: 150,  
78 - label: '客户STYLE',  
79 - rules: [  
80 - { required: true },  
81 - {  
82 - validator: async (rule, value) => {  
83 - if (value.includes(' ')) {  
84 - return Promise.reject();  
85 - }  
86 - return Promise.resolve();  
87 - },  
88 - message: '内容存在空格,请检查',  
89 - trigger: ['change', 'blur'],  
90 - },  
91 - ],  
92 - },  
93 ]; 37 ];
94 38
src/views/project/finance/financeProfit/ServiceProfit/PackageProfit/ApproveReason.vue
@@ -32,7 +32,7 @@ @@ -32,7 +32,7 @@
32 orderId: baseFieldValues.value.orderId, 32 orderId: baseFieldValues.value.orderId,
33 packetActualRmbTotalPrice: baseFieldValues.value.packetActualRmbTotalPrice, 33 packetActualRmbTotalPrice: baseFieldValues.value.packetActualRmbTotalPrice,
34 applyRemark: baseFieldValues.value.applyRemark, 34 applyRemark: baseFieldValues.value.applyRemark,
35 - type: 60, 35 + type: 80,
36 }); 36 });
37 emit('success'); 37 emit('success');
38 setTimeout(() => { 38 setTimeout(() => {
src/views/project/finance/financeProfit/ServiceProfit/PackageProfit/FinanceEdit.vue
@@ -122,7 +122,7 @@ @@ -122,7 +122,7 @@
122 const [register, { setDrawerProps, closeDrawer }] = useDrawerInner((data) => { 122 const [register, { setDrawerProps, closeDrawer }] = useDrawerInner((data) => {
123 // 方式1 123 // 方式1
124 if (data.data.lockFields) { 124 if (data.data.lockFields) {
125 - status.value = data.data.lockFields?.packetActualRmbPrice; 125 + status.value = data.data.lockFields?.packetActualRmbTotalPrice;
126 } 126 }
127 id.value = data.data.orderId; 127 id.value = data.data.orderId;
128 input1.value = data.data?.packetActualRmbTotalPrice; 128 input1.value = data.data?.packetActualRmbTotalPrice;
src/views/project/finance/financeProfit/ServiceProfit/PackageProfit/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 { getOrderCostDetailedOptLog } 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 orderId = 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 getOrderCostDetailedOptLog({
  138 + orderId: data,
  139 + type: [20],
  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 getOrderCostDetailedOptLog({
  148 + orderId: data,
  149 + type: [80,81],
  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 + orderId.value = data.data.orderId;
  160 + getOrderOptLogFunc(orderId.value, 1, 1);
  161 + getOrderOptLogFunc(orderId.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(orderId.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(orderId.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/PackageProfit/data.tsx
@@ -182,9 +182,23 @@ export const COLUMNS = [ @@ -182,9 +182,23 @@ export const COLUMNS = [
182 width: 140, 182 width: 140,
183 customRender: (column) => { 183 customRender: (column) => {
184 if (column.record?.packetProfitRate) { 184 if (column.record?.packetProfitRate) {
185 - return column.record?.packetProfitRate?.toFixed(2) + '%'; 185 + return (column.record?.packetProfitRate * 100).toFixed(2) + '%';
186 } 186 }
187 return column.record?.packetProfitRate?.toFixed(2); 187 return column.record?.packetProfitRate?.toFixed(2);
188 }, 188 },
189 }, 189 },
  190 + {
  191 + title: '状态',
  192 + dataIndex: 'status',
  193 + width: 120,
  194 + customRender: (column) => {
  195 + if (column.record?.packStatus === null || column.record?.packStatus === -1) {
  196 + return '未完成';
  197 + } else if (column.record?.packStatus === 0) {
  198 + return '待审核';
  199 + } else if (column.record?.packStatus === 1) {
  200 + return '已审核';
  201 + }
  202 + },
  203 + },
190 ]; 204 ];
191 \ No newline at end of file 205 \ No newline at end of file
src/views/project/finance/financeProfit/ServiceProfit/PackageProfit/index.vue
1 <template> 1 <template>
2 <div> 2 <div>
3 <BasicTable @register="registerTable" :bordered="true"> 3 <BasicTable @register="registerTable" :bordered="true">
  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>
4 <template #bodyCell="{ column, record }"> 23 <template #bodyCell="{ column, record }">
5 <template v-if="column.key === 'picUrl'"> 24 <template v-if="column.key === 'picUrl'">
6 <img :z-index="100000" :width="50" :height="50" :src="record?.picUrl" /> 25 <img :z-index="100000" :width="50" :height="50" :src="record?.picUrl" />
7 </template> 26 </template>
8 <template v-if="column.key === 'action'"> 27 <template v-if="column.key === 'action'">
9 - <TableAction :actions="createActions(record)" /> 28 + <TableAction
  29 + :actions="createActions(record)"
  30 + :dropDownActions="createDropActions(record)"
  31 + />
10 </template> 32 </template>
11 <!-- <template v-if="column.key === 'relationValue'"> 33 <!-- <template v-if="column.key === 'relationValue'">
12 <a-input 34 <a-input
@@ -19,6 +41,15 @@ @@ -19,6 +41,15 @@
19 </span> 41 </span>
20 </template> --> 42 </template> -->
21 </template> 43 </template>
  44 + <template #toolbar>
  45 + <a-button
  46 + type="primary"
  47 + @click="handleExport"
  48 + v-if="role == ROLE.ADMIN || role == ROLE.FINANCE"
  49 + :style="{ borderRadius: '5px 5px 5px 5px' }"
  50 + >导出</a-button
  51 + >
  52 + </template>
22 </BasicTable> 53 </BasicTable>
23 <!-- <BasicModal 54 <!-- <BasicModal
24 title="拒绝原因" 55 title="拒绝原因"
@@ -34,27 +65,47 @@ @@ -34,27 +65,47 @@
34 </BasicModal> --> 65 </BasicModal> -->
35 <CheckDetail @register="checkModalRegister" :onGoFormDetail="handleGoFormDetail" /> 66 <CheckDetail @register="checkModalRegister" :onGoFormDetail="handleGoFormDetail" />
36 <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" /> 67 <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" />
  68 + <HistoryDetail @register="registerHistoryDetail" />
37 </div> 69 </div>
38 </template> 70 </template>
39 <script setup lang="ts"> 71 <script setup lang="ts">
40 import { BasicTable, useTable, TableAction } from '/@/components/Table'; 72 import { BasicTable, useTable, TableAction } from '/@/components/Table';
41 - import { getPackageProfit } from '@/api/project/invoice'; 73 + import { getPackageProfit, setPackStatus } from '@/api/project/invoice';
42 import { searchFormSchema, COLUMNS } from './data'; 74 import { searchFormSchema, COLUMNS } from './data';
43 import { BasicModal, useModal } from '/@/components/Modal'; 75 import { BasicModal, useModal } from '/@/components/Modal';
44 import { useMessage } from '/@/hooks/web/useMessage'; 76 import { useMessage } from '/@/hooks/web/useMessage';
45 - import { onMounted, ref } from 'vue'; 77 + import { onMounted, ref, computed } from 'vue';
46 import { useDrawer } from '/@/components/Drawer'; 78 import { useDrawer } from '/@/components/Drawer';
47 import FinanceEdit from './FinanceEdit.vue'; 79 import FinanceEdit from './FinanceEdit.vue';
48 import CheckDetail from './CheckDetail.vue'; 80 import CheckDetail from './CheckDetail.vue';
  81 + import HistoryDetail from './HistoryDetail.vue';
  82 + import axios from 'axios';
49 import { FilePptOutlined } from '@ant-design/icons-vue'; 83 import { FilePptOutlined } from '@ant-design/icons-vue';
50 import { useOrderStoreWithOut } from '/@/store/modules/order'; 84 import { useOrderStoreWithOut } from '/@/store/modules/order';
  85 + import { useUserStoreWithOut } from '/@/store/modules/user';
  86 + import { RoleEnum } from '/@/enums/roleEnum';
  87 + import { ROLE } from '../../../type.d';
51 88
52 const { createMessage } = useMessage(); 89 const { createMessage } = useMessage();
53 const { error } = createMessage; 90 const { error } = createMessage;
54 const message = ref(); 91 const message = ref();
  92 + const checkedKeys = ref<string[]>([]);
  93 + // Define arrays to store collected data from selected rows
  94 + const orderIds = ref<number[]>([]);
  95 + const projectNo = ref<string[]>([]);
  96 + const customerCode = ref<string[]>([]);
  97 + const innerNo = ref<string[]>([]);
  98 + const productionDepartment = ref<string[]>([]);
  99 + const detailProjectNoKeys = ref<string[]>([]);
55 const orderStore = useOrderStoreWithOut(); 100 const orderStore = useOrderStoreWithOut();
56 const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer(); 101 const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer();
57 const [registerFinanceEdit, { openDrawer: openFinanceEdit }] = useDrawer(); 102 const [registerFinanceEdit, { openDrawer: openFinanceEdit }] = useDrawer();
  103 + const [registerHistoryDetail, { openDrawer: openHistoryDetail }] = useDrawer();
  104 + const userStore = useUserStoreWithOut();
  105 + const user = userStore.getUserInfo;
  106 + const role = computed(() => {
  107 + return user?.roleSmallVO?.code;
  108 + });
58 const handleOk = (record) => { 109 const handleOk = (record) => {
59 // 修改父组件的状态 110 // 修改父组件的状态
60 closeModal(); 111 closeModal();
@@ -64,16 +115,34 @@ @@ -64,16 +115,34 @@
64 message.value = ''; 115 message.value = '';
65 } 116 }
66 }; 117 };
67 - const [registerTable, { reload }] = useTable({ 118 + const [registerTable, { reload, setSelectedRowKeys, getForm }] = useTable({
68 api: getPackageProfit, 119 api: getPackageProfit,
69 bordered: true, 120 bordered: true,
70 columns: COLUMNS, 121 columns: COLUMNS,
71 - rowKey: 'id', 122 + rowKey: (record) => record.orderId,
72 formConfig: { 123 formConfig: {
73 labelWidth: 120, 124 labelWidth: 120,
74 schemas: searchFormSchema, 125 schemas: searchFormSchema,
75 autoSubmitOnEnter: true, 126 autoSubmitOnEnter: true,
76 }, 127 },
  128 + // Add custom row props to prevent selection when clicking rows
  129 + customRow: () => {
  130 + return {
  131 + onClick: (e) => {
  132 + // Prevent row selection when clicking anywhere except checkboxes
  133 + if (!e.target.closest('.ant-checkbox-wrapper')) {
  134 + e.stopPropagation();
  135 + }
  136 + },
  137 + };
  138 + },
  139 + rowSelection: {
  140 + type: 'checkbox',
  141 + selectedRowKeys: checkedKeys as any,
  142 + onSelect: onSelect,
  143 + onSelectAll: onSelectAll,
  144 + checkStrictly: true,
  145 + },
77 useSearchForm: true, 146 useSearchForm: true,
78 showTableSetting: true, 147 showTableSetting: true,
79 showIndexColumn: false, 148 showIndexColumn: false,
@@ -81,7 +150,7 @@ @@ -81,7 +150,7 @@
81 setting: false, 150 setting: false,
82 }, 151 },
83 actionColumn: { 152 actionColumn: {
84 - width: 240, 153 + width: 260,
85 title: 'Action', 154 title: 'Action',
86 dataIndex: 'action', 155 dataIndex: 'action',
87 }, 156 },
@@ -113,6 +182,18 @@ @@ -113,6 +182,18 @@
113 // }, 182 // },
114 onClick: handleFalse.bind(null, record), 183 onClick: handleFalse.bind(null, record),
115 }, 184 },
  185 + {
  186 + label: '审核通过',
  187 + popConfirm: {
  188 + title: '确认审核?',
  189 + confirm: () => {
  190 + if (record.packStatus === 0 && role.value === ROLE.ADMIN) {
  191 + handleStatus(record, true);
  192 + }
  193 + return;
  194 + },
  195 + },
  196 + },
116 ]; 197 ];
117 } 198 }
118 return [ 199 return [
@@ -130,9 +211,17 @@ @@ -130,9 +211,17 @@
130 ]; 211 ];
131 } 212 }
132 213
133 - onMounted(async () => {  
134 - await orderStore.getDict();  
135 - }); 214 + function createDropActions(record: any) {
  215 + if (!record.editable) {
  216 + const actions = [
  217 + {
  218 + label: '历史记录',
  219 + onClick: handleHistoryDetail.bind(null, record),
  220 + },
  221 + ];
  222 + return actions;
  223 + }
  224 + }
136 225
137 function handleFinanceEdit(record) { 226 function handleFinanceEdit(record) {
138 openFinanceEdit(true, { 227 openFinanceEdit(true, {
@@ -176,5 +265,218 @@ @@ -176,5 +265,218 @@
176 // await deleteConfig({ ids: [record.id] }); 265 // await deleteConfig({ ids: [record.id] });
177 // reload(); 266 // reload();
178 // } 267 // }
  268 +
  269 + async function handleStatus(record, status) {
  270 + try {
  271 + await setPackStatus({ orderId: record.orderId });
  272 + reload();
  273 + } catch (error) {
  274 + console.error(error);
  275 + }
  276 + }
  277 +
  278 + function handleHistoryDetail(record) {
  279 + openHistoryDetail(true, {
  280 + data: record,
  281 + });
  282 + }
  283 +
  284 + function handleGoFormDetail() {
  285 + // Add your logic for form detail navigation
  286 + }
  287 +
  288 + onMounted(async () => {
  289 + await orderStore.getDict();
  290 + });
  291 +
  292 + function handleClearChoose() {
  293 + checkedKeys.value = [];
  294 + // Clear all collected data arrays
  295 + orderIds.value = [];
  296 + projectNo.value = [];
  297 + customerCode.value = [];
  298 + innerNo.value = [];
  299 + productionDepartment.value = [];
  300 + detailProjectNoKeys.value = []; // Add this line
  301 + }
  302 +
  303 + function handleExport() {
  304 + // Get current search parameters from the form
  305 + const values = getForm().getFieldsValue();
  306 +
  307 + // Create export parameters based on whether orderIds are selected
  308 + let exportParams;
  309 +
  310 + // If orderIds are selected, only use those and ignore search params
  311 + if (orderIds.value.length > 0) {
  312 + exportParams = {
  313 + orderIds: orderIds.value
  314 + };
  315 + }
  316 + // Otherwise use the search parameters
  317 + else {
  318 + exportParams = {
  319 + ...values,
  320 + projectNo: values.projectNo || undefined,
  321 + customerCode: values.customerCode || undefined,
  322 + innerNo: values.innerNo || undefined,
  323 + productionDepartment: values.productionDepartment || undefined
  324 + };
  325 + }
  326 +
  327 + console.log('Export parameters:', exportParams);
  328 +
  329 + const token = userStore.getToken;
  330 + axios
  331 + .post(
  332 + '/basic-api/order/cost/businessProfitDetail/exportExcel',
  333 + exportParams,
  334 + {
  335 + headers: {
  336 + Authorization: `${token}`, // 去掉引号
  337 + },
  338 + responseType: 'blob', // 设置响应类型为 'blob'
  339 + },
  340 + )
  341 + .then((response) => {
  342 + // 创建一个 Blob 对象来保存二进制数据
  343 + const blob = new Blob([response.data], { type: 'application/zip' });
  344 + const getFormattedDate = (): string => {
  345 + const date = new Date();
  346 +
  347 + const year = date.getFullYear();
  348 + const month = String(date.getMonth() + 1).padStart(2, '0');
  349 + const day = String(date.getDate()).padStart(2, '0');
  350 +
  351 + const hours = String(date.getHours()).padStart(2, '0');
  352 + const minutes = String(date.getMinutes()).padStart(2, '0');
  353 + const seconds = String(date.getSeconds()).padStart(2, '0');
  354 +
  355 + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  356 + };
  357 + const date = getFormattedDate();
  358 + // 创建一个链接元素用于下载
  359 + const link = document.createElement('a');
  360 + link.href = window.URL.createObjectURL(blob);
  361 + link.download = `业务利润分析表${date}.xlsx`; // 你可以为文件命名
  362 + document.body.appendChild(link);
  363 + link.click(); // 自动点击链接,触发下载
  364 + document.body.removeChild(link); // 下载完成后移除链接
  365 + })
  366 + .catch((error) => {
  367 + console.error(error);
  368 + });
  369 + handleClearChoose();
  370 + reload();
  371 + }
  372 + async function onSelect(record, selected: boolean, _selectedRows, nativeEvent) {
  373 + // Only process selection if it's coming from a checkbox click or programmatically
  374 + // This checks if the event is from clicking the row - then we ignore it
  375 + if (nativeEvent && nativeEvent.target && !nativeEvent.target.closest('.ant-checkbox-wrapper')) {
  376 + return;
  377 + }
  378 +
  379 + const rowKey = record.orderId;
  380 + if (selected) {
  381 + checkedKeys.value = [...checkedKeys.value, rowKey];
  382 +
  383 + // Add data from the selected row to the corresponding arrays
  384 + if (record.orderId !== undefined && !orderIds.value.includes(record.orderId)) {
  385 + orderIds.value.push(record.orderId);
  386 + }
  387 +
  388 + if (record.projectNo !== undefined && !projectNo.value.includes(record.projectNo)) {
  389 + projectNo.value.push(record.projectNo);
  390 + }
  391 +
  392 + if (record.customerCode !== undefined && !customerCode.value.includes(record.customerCode)) {
  393 + customerCode.value.push(record.customerCode);
  394 + }
  395 +
  396 + if (record.innerNo !== undefined && !innerNo.value.includes(record.innerNo)) {
  397 + innerNo.value.push(record.innerNo);
  398 + }
  399 +
  400 + if (record.productionDepartment !== undefined && !productionDepartment.value.includes(record.productionDepartment)) {
  401 + productionDepartment.value.push(record.productionDepartment);
  402 + }
  403 +
  404 + if (record.detailProjectNoKey !== undefined && !detailProjectNoKeys.value.includes(record.detailProjectNoKey)) {
  405 + detailProjectNoKeys.value.push(record.detailProjectNoKey);
  406 + }
  407 + } else {
  408 + checkedKeys.value = checkedKeys.value.filter((key) => key !== rowKey);
  409 +
  410 + // Remove data from the deselected row from the corresponding arrays
  411 + if (record.orderId !== undefined) {
  412 + orderIds.value = orderIds.value.filter(id => id !== record.orderId);
  413 + }
  414 +
  415 + if (record.projectNo !== undefined) {
  416 + projectNo.value = projectNo.value.filter(no => no !== record.projectNo);
  417 + }
  418 +
  419 + if (record.customerCode !== undefined) {
  420 + customerCode.value = customerCode.value.filter(code => code !== record.customerCode);
  421 + }
  422 +
  423 + if (record.innerNo !== undefined) {
  424 + innerNo.value = innerNo.value.filter(no => no !== record.innerNo);
  425 + }
  426 +
  427 + if (record.productionDepartment !== undefined) {
  428 + productionDepartment.value = productionDepartment.value.filter(dept => dept !== record.productionDepartment);
  429 + }
  430 + }
  431 + setSelectedRowKeys(checkedKeys.value as any);
  432 + }
  433 +
  434 + function onSelectAll(selected: boolean, selectedRows: any[]) {
  435 + if (selected) {
  436 + // First clear all previous selections to avoid duplicates
  437 + checkedKeys.value = [];
  438 + orderIds.value = [];
  439 + projectNo.value = [];
  440 + customerCode.value = [];
  441 + innerNo.value = [];
  442 + productionDepartment.value = [];
  443 +
  444 + // Add all selected rows
  445 + selectedRows.forEach((row) => {
  446 + const rowKey = row.orderId;
  447 + checkedKeys.value.push(rowKey);
  448 +
  449 + // Add data from each selected row to the corresponding arrays
  450 + if (row.orderId !== undefined) {
  451 + orderIds.value.push(row.orderId);
  452 + }
  453 +
  454 + if (row.projectNo !== undefined) {
  455 + projectNo.value.push(row.projectNo);
  456 + }
  457 +
  458 + if (row.customerCode !== undefined) {
  459 + customerCode.value.push(row.customerCode);
  460 + }
  461 +
  462 + if (row.innerNo !== undefined) {
  463 + innerNo.value.push(row.innerNo);
  464 + }
  465 +
  466 + if (row.productionDepartment !== undefined) {
  467 + productionDepartment.value.push(row.productionDepartment);
  468 + }
  469 + });
  470 + } else {
  471 + // Clear all selections when deselecting all
  472 + checkedKeys.value = [];
  473 + orderIds.value = [];
  474 + projectNo.value = [];
  475 + customerCode.value = [];
  476 + innerNo.value = [];
  477 + productionDepartment.value = [];
  478 + }
  479 + setSelectedRowKeys(checkedKeys.value as any);
  480 + }
179 </script> 481 </script>
180 <style></style> 482 <style></style>
src/views/project/finance/financeProfit/ServiceProfit/ServiceProfit/ApproveReason.vue
@@ -37,6 +37,7 @@ @@ -37,6 +37,7 @@
37 projectEndTime: baseFieldValues.value.projectEndTime, 37 projectEndTime: baseFieldValues.value.projectEndTime,
38 spainPaidRmbCommission: baseFieldValues.value.spainPaidRmbCommission, 38 spainPaidRmbCommission: baseFieldValues.value.spainPaidRmbCommission,
39 applyRemark: baseFieldValues.value.applyRemark, 39 applyRemark: baseFieldValues.value.applyRemark,
  40 + type: 'FIELD_EDIT_APPLY',
40 }); 41 });
41 emit('success'); 42 emit('success');
42 setTimeout(() => { 43 setTimeout(() => {
src/views/project/finance/financeProfit/ServiceProfit/ServiceProfit/FinanceEdit.vue
@@ -9,6 +9,7 @@ @@ -9,6 +9,7 @@
9 @ok="handleSubmit" 9 @ok="handleSubmit"
10 :showDetailBack="false" 10 :showDetailBack="false"
11 okText="保存" 11 okText="保存"
  12 + @visible-change="handleShow"
12 showFooter 13 showFooter
13 :destroyOnClose="true" 14 :destroyOnClose="true"
14 > 15 >
@@ -45,14 +46,6 @@ @@ -45,14 +46,6 @@
45 auto-size 46 auto-size
46 /> 47 />
47 <div style="margin: 16px 0"></div> 48 <div style="margin: 16px 0"></div>
48 - <div style="font-size: 15px">实际汇率¥</div>  
49 - <a-input  
50 - v-model:value="input6"  
51 - placeholder="请输入"  
52 - :disabled="status6 === 'LOCKED'"  
53 - auto-size  
54 - />  
55 - <div style="margin: 16px 0"></div>  
56 <!-- <template #titleToolbar> <a-button type="primary"> 申请编辑权限 </a-button></template> --> 49 <!-- <template #titleToolbar> <a-button type="primary"> 申请编辑权限 </a-button></template> -->
57 <template #appendFooter> 50 <template #appendFooter>
58 <!-- <a-button type="primary" @click="onGoCheckDetail"> 申请权限</a-button> --> 51 <!-- <a-button type="primary" @click="onGoCheckDetail"> 申请权限</a-button> -->
@@ -145,16 +138,13 @@ @@ -145,16 +138,13 @@
145 const status3 = ref(); 138 const status3 = ref();
146 const status4 = ref(); 139 const status4 = ref();
147 const status5 = ref(); 140 const status5 = ref();
148 - const status6 = ref();  
149 141
150 const input1 = ref(); 142 const input1 = ref();
151 const input2 = ref(); 143 const input2 = ref();
152 const input3 = ref(); 144 const input3 = ref();
153 - // const input4 = ref();  
154 - const input4 = ref(dayjs('2013-12-01')); 145 + const input4 = ref();
155 146
156 const input5 = ref(); 147 const input5 = ref();
157 - const input6 = ref();  
158 const id = ref(); 148 const id = ref();
159 // function formatDate(dateStr: string): string { 149 // function formatDate(dateStr: string): string {
160 // const date = new Date(dateStr); 150 // const date = new Date(dateStr);
@@ -185,16 +175,14 @@ @@ -185,16 +175,14 @@
185 status3.value = data?.data?.lockFields?.projectStartTime; 175 status3.value = data?.data?.lockFields?.projectStartTime;
186 status4.value = data?.data?.lockFields?.projectEndTime; 176 status4.value = data?.data?.lockFields?.projectEndTime;
187 status5.value = data?.data?.lockFields?.paidRmbCommission; 177 status5.value = data?.data?.lockFields?.paidRmbCommission;
188 - status6.value = data?.data?.lockFields?.actualExchangeRate;  
189 } 178 }
190 - console.log(data.data.lockFields, '5656vdata.data.lockFields');  
191 id.value = data?.data?.projectNoPrefix; 179 id.value = data?.data?.projectNoPrefix;
192 input1.value = data?.data?.developmentCopyRmbTotalPrice.toFixed(2); 180 input1.value = data?.data?.developmentCopyRmbTotalPrice.toFixed(2);
193 input2.value = data?.data?.spainPaidRmbCommission.toFixed(2); 181 input2.value = data?.data?.spainPaidRmbCommission.toFixed(2);
194 input3.value = dayjs(formatDateToDateOnly(data?.data?.projectStartTime)); 182 input3.value = dayjs(formatDateToDateOnly(data?.data?.projectStartTime));
195 input4.value = dayjs(formatDateToDateOnly(data?.data?.projectEndTime)); 183 input4.value = dayjs(formatDateToDateOnly(data?.data?.projectEndTime));
196 input5.value = data?.data?.paidRmbCommission.toFixed(2); 184 input5.value = data?.data?.paidRmbCommission.toFixed(2);
197 - input6.value = data?.data?.actualExchangeRate.toFixed(2); 185 +
198 resetFields(); 186 resetFields();
199 setDrawerProps({ confirmLoading: false }); 187 setDrawerProps({ confirmLoading: false });
200 setFieldsValue({ 188 setFieldsValue({
@@ -220,10 +208,18 @@ @@ -220,10 +208,18 @@
220 projectStartTime: input3.value, 208 projectStartTime: input3.value,
221 projectEndTime: input4.value, 209 projectEndTime: input4.value,
222 paidRmbCommission: input5.value, 210 paidRmbCommission: input5.value,
223 - actualExchangeRate: input6.value,  
224 }); 211 });
225 emit('success'); 212 emit('success');
226 closeDrawer(); 213 closeDrawer();
227 } 214 }
228 } 215 }
  216 + function handleShow(visible: boolean) {
  217 + if (!visible) {
  218 + input1.value = '';
  219 + input2.value = '';
  220 + input3.value = '';
  221 + input4.value = '';
  222 + input5.value = '';
  223 + }
  224 + }
229 </script> 225 </script>
src/views/project/finance/financeProfit/ServiceProfit/ServiceProfit/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 { getProjectOptLog } 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 orderId = 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 getProjectOptLog({
  138 + projectNoPrefix: data,
  139 + type: [10],
  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 getProjectOptLog({
  148 + projectNoPrefix: data,
  149 + type: [0,2],
  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 + orderId.value = data.data.projectNoPrefix;
  160 + getOrderOptLogFunc(orderId.value, 1, 1);
  161 + getOrderOptLogFunc(orderId.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(orderId.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(orderId.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/ServiceProfit/data.tsx
@@ -104,6 +104,14 @@ export const COLUMNS = [ @@ -104,6 +104,14 @@ export const COLUMNS = [
104 width: 100, 104 width: 100,
105 }, 105 },
106 { 106 {
  107 + title: '订单总数量',
  108 + dataIndex: 'orderCount',
  109 + width: 120,
  110 + customRender: (column) => {
  111 + return column.record?.orderCount;
  112 + },
  113 + },
  114 + {
107 title: '客户总金额¥', 115 title: '客户总金额¥',
108 width: 150, 116 width: 150,
109 dataIndex: 'customerTotalPrice', 117 dataIndex: 'customerTotalPrice',
@@ -132,7 +140,7 @@ export const COLUMNS = [ @@ -132,7 +140,7 @@ export const COLUMNS = [
132 dataIndex: 'packetTotalPrice', 140 dataIndex: 'packetTotalPrice',
133 width: 150, 141 width: 150,
134 customRender: (column) => { 142 customRender: (column) => {
135 - return column.record?.packetTotalPrice?.toFixed(2); 143 + return column.record?.packetRmbTotalPrice?.toFixed(2);
136 }, 144 },
137 }, 145 },
138 { 146 {
@@ -229,7 +237,7 @@ export const COLUMNS = [ @@ -229,7 +237,7 @@ export const COLUMNS = [
229 width: 120, 237 width: 120,
230 customRender: (column) => { 238 customRender: (column) => {
231 if (column.record?.profitRate) { 239 if (column.record?.profitRate) {
232 - return column.record?.profitRate?.toFixed(2) + '%'; 240 + return (column.record?.profitRate * 100).toFixed(2) + '%';
233 } 241 }
234 return column.record?.profitRate?.toFixed(2); 242 return column.record?.profitRate?.toFixed(2);
235 }, 243 },
@@ -248,7 +256,7 @@ export const COLUMNS = [ @@ -248,7 +256,7 @@ export const COLUMNS = [
248 width: 120, 256 width: 120,
249 customRender: (column) => { 257 customRender: (column) => {
250 if (column.record?.developmentProfitRate) { 258 if (column.record?.developmentProfitRate) {
251 - return column.record?.developmentProfitRate?.toFixed(2) + '%'; 259 + return (column.record?.developmentProfitRate * 100).toFixed(2) + '%';
252 } 260 }
253 return column.record?.developmentProfitRate?.toFixed(2); 261 return column.record?.developmentProfitRate?.toFixed(2);
254 }, 262 },
@@ -270,14 +278,6 @@ export const COLUMNS = [ @@ -270,14 +278,6 @@ export const COLUMNS = [
270 }, 278 },
271 }, 279 },
272 { 280 {
273 - title: '订单总数量',  
274 - dataIndex: 'orderCount',  
275 - width: 120,  
276 - customRender: (column) => {  
277 - return column.record?.orderCount;  
278 - },  
279 - },  
280 - {  
281 title: '实际跟单单价¥', 281 title: '实际跟单单价¥',
282 dataIndex: 'actualOrderRmbPrice', 282 dataIndex: 'actualOrderRmbPrice',
283 width: 160, 283 width: 160,
@@ -302,22 +302,6 @@ export const COLUMNS = [ @@ -302,22 +302,6 @@ export const COLUMNS = [
302 }, 302 },
303 }, 303 },
304 { 304 {
305 - title: '实际汇率¥',  
306 - dataIndex: 'actualExchangeRate',  
307 - width: 120,  
308 - customRender: (column) => {  
309 - return column.record?.actualExchangeRate?.toFixed(2);  
310 - },  
311 - },  
312 - {  
313 - title: '汇率收益¥',  
314 - dataIndex: 'exchangeRateProfit',  
315 - width: 120,  
316 - customRender: (column) => {  
317 - return column.record?.exchangeRateProfit?.toFixed(2);  
318 - },  
319 - },  
320 - {  
321 title: '综合收益¥', 305 title: '综合收益¥',
322 dataIndex: 'comprehensiveProfit', 306 dataIndex: 'comprehensiveProfit',
323 width: 120, 307 width: 120,
@@ -380,4 +364,18 @@ export const COLUMNS = [ @@ -380,4 +364,18 @@ export const COLUMNS = [
380 return <FilePptOutlined style="font-size:25px" onClick={() => handleClick()} />; 364 return <FilePptOutlined style="font-size:25px" onClick={() => handleClick()} />;
381 }, 365 },
382 }, 366 },
  367 + {
  368 + title: '状态',
  369 + dataIndex: 'status',
  370 + width: 120,
  371 + customRender: (column) => {
  372 + if (column.record?.developmentStatus === null || column.record?.developmentStatus === -1) {
  373 + return '未完成';
  374 + } else if (column.record?.developmentStatus === 0) {
  375 + return '待审核';
  376 + } else if (column.record?.developmentStatus === 1) {
  377 + return '已审核';
  378 + }
  379 + },
  380 + },
383 ]; 381 ];
384 \ No newline at end of file 382 \ No newline at end of file
src/views/project/finance/financeProfit/ServiceProfit/ServiceProfit/index.vue
1 <template> 1 <template>
2 <div> 2 <div>
3 <BasicTable @register="registerTable" :bordered="true"> 3 <BasicTable @register="registerTable" :bordered="true">
  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>
4 <template #bodyCell="{ column, record }"> 23 <template #bodyCell="{ column, record }">
5 <template v-if="column.key === 'action'"> 24 <template v-if="column.key === 'action'">
6 - <TableAction :actions="createActions(record)" />  
7 - </template>  
8 - <!-- <template v-if="column.key === 'relationValue'">  
9 - <a-input  
10 - v-if="record.settingValue === 'A01'"  
11 - v-model:value="record.settingValue"  
12 - :max-length="50" 25 + <TableAction
  26 + :actions="createActions(record)"
  27 + :dropDownActions="createDropActions(record)"
13 /> 28 />
14 - <span v-else style="color: red">  
15 - {{ record.settingValue }}  
16 - </span>  
17 - </template> --> 29 + </template>
  30 + </template>
  31 + <template #toolbar>
  32 + <a-button
  33 + type="primary"
  34 + @click="handleExport"
  35 + v-if="role == ROLE.ADMIN || role == ROLE.FINANCE"
  36 + :style="{ borderRadius: '5px 5px 5px 5px' }"
  37 + >导出</a-button
  38 + >
18 </template> 39 </template>
19 </BasicTable> 40 </BasicTable>
20 - <!-- <BasicModal  
21 - title="拒绝原因"  
22 - width="30%"  
23 - @register="registerModal"  
24 - @visible-change="handleClose"  
25 - @ok="handleOk"  
26 - wrapClassName="approve-modal"  
27 - >  
28 - <div className="pa-8">  
29 - <a-textarea :rows="6" placeholder="请输入拒绝原因" v-model:value="message" />  
30 - </div>  
31 - </BasicModal> -->  
32 <CheckDetail @register="checkModalRegister" :onGoFormDetail="handleGoFormDetail" /> 41 <CheckDetail @register="checkModalRegister" :onGoFormDetail="handleGoFormDetail" />
33 <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" /> 42 <FinanceEdit @register="registerFinanceEdit" @success="handleSuccess" />
  43 + <HistoryDetail @register="registerHistoryDetail" />
34 </div> 44 </div>
35 </template> 45 </template>
36 <script setup lang="ts"> 46 <script setup lang="ts">
37 import { BasicTable, useTable, TableAction } from '/@/components/Table'; 47 import { BasicTable, useTable, TableAction } from '/@/components/Table';
38 - import { getServiceProfit } from '@/api/project/invoice'; 48 + import { getServiceProfit, setBusinessProfitSetStatus } from '@/api/project/invoice';
39 import { searchFormSchema, COLUMNS } from './data'; 49 import { searchFormSchema, COLUMNS } from './data';
40 - import { BasicModal, useModal } from '/@/components/Modal'; 50 + import axios from 'axios';
41 import { useMessage } from '/@/hooks/web/useMessage'; 51 import { useMessage } from '/@/hooks/web/useMessage';
42 - import { onMounted, ref } from 'vue'; 52 + import { onMounted, ref, computed, unref } from 'vue';
43 import { useDrawer } from '/@/components/Drawer'; 53 import { useDrawer } from '/@/components/Drawer';
44 import FinanceEdit from './FinanceEdit.vue'; 54 import FinanceEdit from './FinanceEdit.vue';
  55 + import HistoryDetail from './HistoryDetail.vue';
45 import CheckDetail from './CheckDetail.vue'; 56 import CheckDetail from './CheckDetail.vue';
  57 + import { useUserStoreWithOut } from '/@/store/modules/user';
  58 + import { ROLE } from '../../../type.d';
46 import { useOrderStoreWithOut } from '/@/store/modules/order'; 59 import { useOrderStoreWithOut } from '/@/store/modules/order';
47 60
48 const { createMessage } = useMessage(); 61 const { createMessage } = useMessage();
49 - const { error } = createMessage;  
50 const message = ref(); 62 const message = ref();
  63 + const checkedKeys = ref<string[]>([]);
  64 + const invoiceIdKeys = ref<string[]>([]);
  65 + const checkIdKeys = ref<string[]>([]);
  66 + const detailProjectNoKeys = ref<string[]>([]);
51 const orderStore = useOrderStoreWithOut(); 67 const orderStore = useOrderStoreWithOut();
52 const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer(); 68 const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer();
53 const [registerFinanceEdit, { openDrawer: openFinanceEdit }] = useDrawer(); 69 const [registerFinanceEdit, { openDrawer: openFinanceEdit }] = useDrawer();
54 - const handleClose = (visible: boolean) => {  
55 - if (!visible) {  
56 - message.value = '';  
57 - }  
58 - };  
59 - const [registerTable, { reload }] = useTable({ 70 + const [registerHistoryDetail, { openDrawer: openHistoryDetail }] = useDrawer();
  71 + const userStore = useUserStoreWithOut();
  72 + const user = userStore.getUserInfo;
  73 + const role = computed(() => {
  74 + return user?.roleSmallVO?.code;
  75 + });
  76 + const [registerTable, { reload, getSelectRowKeys, getDataSource, setSelectedRowKeys }] = useTable({
  77 + title: '',
60 api: getServiceProfit, 78 api: getServiceProfit,
61 bordered: true, 79 bordered: true,
62 columns: COLUMNS, 80 columns: COLUMNS,
63 clickToRowSelect: false, 81 clickToRowSelect: false,
64 - rowKey: 'id',  
65 formConfig: { 82 formConfig: {
66 labelWidth: 120, 83 labelWidth: 120,
67 schemas: searchFormSchema, 84 schemas: searchFormSchema,
68 autoSubmitOnEnter: true, 85 autoSubmitOnEnter: true,
69 }, 86 },
  87 + rowKey: (record) => record.detailProjectNo || record.id || record.serialNumber,
  88 + rowSelection: {
  89 + type: 'checkbox',
  90 + selectedRowKeys: checkedKeys as any,
  91 + onSelect: onSelect,
  92 + onSelectAll: onSelectAll,
  93 + },
70 useSearchForm: true, 94 useSearchForm: true,
71 showTableSetting: true, 95 showTableSetting: true,
72 showIndexColumn: false, 96 showIndexColumn: false,
@@ -74,7 +98,7 @@ @@ -74,7 +98,7 @@
74 setting: false, 98 setting: false,
75 }, 99 },
76 actionColumn: { 100 actionColumn: {
77 - width: 240, 101 + width: 260,
78 title: 'Action', 102 title: 'Action',
79 dataIndex: 'action', 103 dataIndex: 'action',
80 }, 104 },
@@ -82,31 +106,29 @@ @@ -82,31 +106,29 @@
82 106
83 function createActions(record: any): any[] { 107 function createActions(record: any): any[] {
84 if (!record.editable) { 108 if (!record.editable) {
85 - return [ 109 + const actions = [
86 { 110 {
87 label: '财务编辑', 111 label: '财务编辑',
88 onClick: handleFinanceEdit.bind(null, record), 112 onClick: handleFinanceEdit.bind(null, record),
89 }, 113 },
90 - // {  
91 - // label: '编辑',  
92 - // onClick: handleEdit.bind(null, record),  
93 - // },  
94 - // {  
95 - // label: '删除',  
96 - // popConfirm: {  
97 - // title: '确认删除?',  
98 - // confirm: handleDelete.bind(null, record),  
99 - // },  
100 - // },  
101 { 114 {
102 label: '申请权限', 115 label: '申请权限',
103 - // popConfirm: {  
104 - // title: '确认申请?',  
105 - // confirm: handleFalse.bind(null, record),  
106 - // },  
107 onClick: handleFalse.bind(null, record), 116 onClick: handleFalse.bind(null, record),
108 }, 117 },
  118 + {
  119 + label: '审核通过',
  120 + popConfirm: {
  121 + title: '确认审核?',
  122 + confirm: () => {
  123 + if (record.developmentStatus === 0 && role.value === ROLE.ADMIN) {
  124 + handleStatus(record, true);
  125 + }
  126 + return;
  127 + },
  128 + },
  129 + },
109 ]; 130 ];
  131 + return actions;
110 } 132 }
111 return [ 133 return [
112 { 134 {
@@ -122,6 +144,17 @@ @@ -122,6 +144,17 @@
122 }, 144 },
123 ]; 145 ];
124 } 146 }
  147 + function createDropActions(record: any) {
  148 + if (!record.editable) {
  149 + const actions = [
  150 + {
  151 + label: '历史记录',
  152 + onClick: handleHistoryDetail.bind(null, record),
  153 + },
  154 + ];
  155 + return actions;
  156 + }
  157 + }
125 158
126 onMounted(async () => { 159 onMounted(async () => {
127 await orderStore.getDict(); 160 await orderStore.getDict();
@@ -139,11 +172,6 @@ @@ -139,11 +172,6 @@
139 return false; 172 return false;
140 } 173 }
141 174
142 - // async function handleFalse(record: any) {  
143 - // console.log(record);  
144 - // // openModal(true, { record });  
145 - // }  
146 -  
147 function handleSuccess() { 175 function handleSuccess() {
148 setTimeout(() => { 176 setTimeout(() => {
149 reload(); 177 reload();
@@ -155,21 +183,185 @@ @@ -155,21 +183,185 @@
155 handleCancel(record); 183 handleCancel(record);
156 reload(); 184 reload();
157 } 185 }
158 - function handleEdit(record: any) {  
159 - // if (record.settingValue == 'A01') {  
160 - // error('请勿连续点击生成按钮,需要等待三秒再点击生成');  
161 - // } else {  
162 - record.onEdit?.(true);  
163 - // }  
164 - }  
165 186
166 function handleCancel(record) { 187 function handleCancel(record) {
167 record.onEdit?.(false, false); 188 record.onEdit?.(false, false);
168 } 189 }
169 190
170 - async function handleDelete(record) {  
171 - // await deleteConfig({ ids: [record.id] }); 191 + async function handleStatus(record, status) {
  192 + try {
  193 + await setBusinessProfitSetStatus({
  194 + customerCode: record.customerCode,
  195 + projectNo: record.projectNoPrefix,
  196 + });
  197 + reload();
  198 + } catch (error) {
  199 + console.error('Error updating status:', error);
  200 + }
  201 + }
  202 +
  203 + async function handleHistoryDetail(record) {
  204 + openHistoryDetail(true, {
  205 + data: record,
  206 + });
  207 + }
  208 +
  209 + function handleExport() {
  210 + if (checkedKeys.value.length <= 0) {
  211 + createMessage.warn('请选择数据!');
  212 + return;
  213 + }
  214 + const token = userStore.getToken;
  215 + axios
  216 + .post(
  217 + '/basic-api/project/businessProfit/exportExcel',
  218 + { detailProjectNo: detailProjectNoKeys.value },
  219 + {
  220 + headers: {
  221 + Authorization: `${token}`, // 去掉引号
  222 + },
  223 + responseType: 'blob', // 设置响应类型为 'blob'
  224 + },
  225 + )
  226 + .then((response) => {
  227 + // 创建一个 Blob 对象来保存二进制数据
  228 + const blob = new Blob([response.data], { type: 'application/zip' });
  229 + const getFormattedDate = (): string => {
  230 + const date = new Date();
  231 +
  232 + const year = date.getFullYear();
  233 + const month = String(date.getMonth() + 1).padStart(2, '0');
  234 + const day = String(date.getDate()).padStart(2, '0');
  235 +
  236 + const hours = String(date.getHours()).padStart(2, '0');
  237 + const minutes = String(date.getMinutes()).padStart(2, '0');
  238 + const seconds = String(date.getSeconds()).padStart(2, '0');
  239 +
  240 + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  241 + };
  242 + const date = getFormattedDate();
  243 + // 创建一个链接元素用于下载
  244 + const link = document.createElement('a');
  245 + link.href = window.URL.createObjectURL(blob);
  246 + link.download = `业务利润分析表${date}.xlsx`; // 你可以为文件命名
  247 + document.body.appendChild(link);
  248 + link.click(); // 自动点击链接,触发下载
  249 + document.body.removeChild(link); // 下载完成后移除链接
  250 + })
  251 + .catch((error) => {
  252 + console.error(error);
  253 + });
  254 + handleClearChoose();
172 reload(); 255 reload();
173 } 256 }
  257 +
  258 + function handleClearChoose() {
  259 + checkedKeys.value = [];
  260 + detailProjectNoKeys.value = [];
  261 + invoiceIdKeys.value = [];
  262 + checkIdKeys.value = [];
  263 + }
  264 +
  265 + async function onSelect(record, selected: boolean) {
  266 + const rowKey = record.detailProjectNo || record.id || record.serialNumber;
  267 + if (selected) {
  268 + checkedKeys.value = [...checkedKeys.value, rowKey];
  269 +
  270 + // 如果detailProjectNo是数组,将每个元素添加到detailProjectNoKeys中
  271 + if (record.detailProjectNo !== undefined) {
  272 + if (Array.isArray(record.detailProjectNo)) {
  273 + record.detailProjectNo.forEach((projectNo) => {
  274 + if (!detailProjectNoKeys.value.includes(projectNo)) {
  275 + detailProjectNoKeys.value.push(projectNo);
  276 + }
  277 + });
  278 + } else {
  279 + // 如果是单个值,直接添加
  280 + if (!detailProjectNoKeys.value.includes(record.detailProjectNo)) {
  281 + detailProjectNoKeys.value.push(record.detailProjectNo);
  282 + }
  283 + }
  284 + }
  285 +
  286 + if (record.invoiceId !== undefined) {
  287 + invoiceIdKeys.value = [...invoiceIdKeys.value, record.invoiceId];
  288 + }
  289 +
  290 + if (record.checkId !== undefined) {
  291 + checkIdKeys.value = [...checkIdKeys.value, record.checkId];
  292 + }
  293 + } else {
  294 + checkedKeys.value = checkedKeys.value.filter((key) => key !== rowKey);
  295 +
  296 + // 如果detailProjectNo是数组,从detailProjectNoKeys中移除每个元素
  297 + if (record.detailProjectNo !== undefined) {
  298 + if (Array.isArray(record.detailProjectNo)) {
  299 + detailProjectNoKeys.value = detailProjectNoKeys.value.filter(
  300 + (projectNo) => !record.detailProjectNo.includes(projectNo)
  301 + );
  302 + } else {
  303 + // 如果是单个值,直接移除
  304 + detailProjectNoKeys.value = detailProjectNoKeys.value.filter(
  305 + (projectNo) => projectNo !== record.detailProjectNo
  306 + );
  307 + }
  308 + }
  309 +
  310 + if (record.invoiceId !== undefined) {
  311 + invoiceIdKeys.value = invoiceIdKeys.value.filter(
  312 + (invoiceId) => invoiceId !== record.invoiceId,
  313 + );
  314 + }
  315 +
  316 + if (record.checkId !== undefined) {
  317 + checkIdKeys.value = checkIdKeys.value.filter((checkId) => checkId !== record.checkId);
  318 + }
  319 + }
  320 + setSelectedRowKeys(checkedKeys.value as any);
  321 + }
  322 +
  323 + function onSelectAll(selected: boolean, selectedRows: any[]) {
  324 + if (selected) {
  325 + // 先清空之前的选择,避免重复添加
  326 + checkedKeys.value = [];
  327 + detailProjectNoKeys.value = [];
  328 + invoiceIdKeys.value = [];
  329 + checkIdKeys.value = [];
  330 +
  331 + // 重新添加所有选中的行
  332 + selectedRows.forEach((row) => {
  333 + const rowKey = row.detailProjectNo || row.id || row.serialNumber;
  334 + checkedKeys.value.push(rowKey);
  335 +
  336 + // 如果detailProjectNo是数组,将每个元素添加到detailProjectNoKeys中
  337 + if (row.detailProjectNo !== undefined) {
  338 + if (Array.isArray(row.detailProjectNo)) {
  339 + row.detailProjectNo.forEach((projectNo) => {
  340 + // 由于已经清空了数组,不需要检查是否存在
  341 + detailProjectNoKeys.value.push(projectNo);
  342 + });
  343 + } else {
  344 + // 如果是单个值,直接添加
  345 + detailProjectNoKeys.value.push(row.detailProjectNo);
  346 + }
  347 + }
  348 +
  349 + if (row.invoiceId !== undefined) {
  350 + invoiceIdKeys.value.push(row.invoiceId);
  351 + }
  352 +
  353 + if (row.checkId !== undefined) {
  354 + checkIdKeys.value.push(row.checkId);
  355 + }
  356 + });
  357 + } else {
  358 + // 取消全选时,清空所有选择
  359 + checkedKeys.value = [];
  360 + detailProjectNoKeys.value = [];
  361 + invoiceIdKeys.value = [];
  362 + checkIdKeys.value = [];
  363 + }
  364 + setSelectedRowKeys(checkedKeys.value as any);
  365 + }
174 </script> 366 </script>
175 <style></style> 367 <style></style>
src/views/project/finance/financeProfit/ServiceProfit/ServiceProfit/tableData.tsx
@@ -55,12 +55,4 @@ export const FIELDS_BASE_INFO = [ @@ -55,12 +55,4 @@ export const FIELDS_BASE_INFO = [
55 label: '中国团队已发提成¥', 55 label: '中国团队已发提成¥',
56 rules: [{ required: true }], 56 rules: [{ required: true }],
57 }, 57 },
58 - {  
59 - field: 'actualExchangeRate',  
60 - component: 'Select',  
61 - labelWidth: 150,  
62 - label: '实际汇率¥',  
63 - rules: [{ required: true }],  
64 - },  
65 ]; 58 ];
66 -  
src/views/project/finance/pay/index.vue
@@ -322,9 +322,6 @@ @@ -322,9 +322,6 @@
322 }); 322 });
323 } 323 }
324 324
325 - // console.log(checkedKeys.value, 565666666); // 输出当前的 selectedCustomCodes 值  
326 - // console.log(selectedCustomCodes.value, 565666666); // 输出当前的 selectedCustomCodes 值  
327 - // console.log(selectedProductionDepartment.value, 565666666); // 输出当前的 selectedCustomCodes 值  
328 } 325 }
329 326
330 function handleFinanceEdit(record) { 327 function handleFinanceEdit(record) {
src/views/project/finance/type.d.ts 0 → 100644
  1 +export enum ROLE {
  2 + ADMIN = 'admin', // 超管
  3 + CUSTOM_ADMIN = 'custom_admin', // 客户管理员
  4 + DATA_REPORT_USER = 'data_report_user', //数据分析员
  5 + BUSINESS = 'business_user', // 业务员
  6 + TRACKER = 'tracker_user', // 跟单员
  7 + INSPECT = 'inspect_user', // 质检员
  8 + PRODUCE = 'produce_user', //生产科
  9 + FINANCE = 'finance_user', //财务
  10 +}
vite.config.ts
@@ -30,26 +30,33 @@ export default defineApplicationConfig({ @@ -30,26 +30,33 @@ export default defineApplicationConfig({
30 }, 30 },
31 }, 31 },
32 '/basic-api/order': { 32 '/basic-api/order': {
33 - // target: 'http://localhost:18001',  
34 - target: 'http://47.104.8.35:18001', 33 + target: 'http://47.104.8.35:8000',
  34 + // target: 'http://localhost:18000',
  35 + // target: 'http://39.108.227.113:8000',
  36 + // target: 'http://localhost:8000',
  37 + // target: 'http://39.108.227.113:3000/mock/35',
  38 + // http://39.108.227.113:8000/order/erp/captcha/get_img_captcha_code
  39 + changeOrigin: true,
  40 + ws: true,
  41 + rewrite: (path) => path.replace(new RegExp(`^/basic-api`), ''),
  42 + },
  43 + '/basic-api/project': {
  44 + target: 'http://47.104.8.35:8000',
  45 + // target: 'http://localhost:18000',
  46 + // target: 'http://39.108.227.113:8000',
  47 + // target: 'http://localhost:8000',
  48 + // target: 'http://39.108.227.113:3000/mock/35',
  49 + // http://39.108.227.113:8000/order/erp/captcha/get_img_captcha_code
35 changeOrigin: true, 50 changeOrigin: true,
36 ws: true, 51 ws: true,
37 rewrite: (path) => path.replace(new RegExp(`^/basic-api`), ''), 52 rewrite: (path) => path.replace(new RegExp(`^/basic-api`), ''),
38 }, 53 },
39 - // '/basic-api/project': {  
40 - // target: 'http://47.104.8.35:8000',  
41 - // // target: 'http://localhost:18000',  
42 - // // target: 'http://39.108.227.113:8000',  
43 - // // target: 'http://localhost:8000',  
44 - // // target: 'http://39.108.227.113:3000/mock/35',  
45 - // // http://39.108.227.113:8000/order/erp/captcha/get_img_captcha_code  
46 - // changeOrigin: true,  
47 - // ws: true,  
48 - // rewrite: (path) => path.replace(new RegExp(`^/basic-api`), ''),  
49 - // },  
50 '/api/localStorage/upload': { 54 '/api/localStorage/upload': {
51 - // target: 'http://localhost:18001',  
52 - target: 'http://47.104.8.35:18001', 55 + target: 'http://47.104.8.35:8000',
  56 + // target: 'http://localhost:18000',
  57 + // target: 'http://39.108.227.113:8000',
  58 + // target: '192.168.31.250:18000',
  59 + // target: 'http://localhost:8000',
53 changeOrigin: true, 60 changeOrigin: true,
54 ws: true, 61 ws: true,
55 // rewrite: (path) => { 62 // rewrite: (path) => {