Commit 522f7be02bbd6225eb25f2e53c8f0fe2602faf25
1 parent
cf269d58
feat(project): add new feature for approve
1. 添加扣款单状态 2. 添加对账单
Showing
7 changed files
with
431 additions
and
96 deletions
src/views/project/approve/PayPanel.vue
... | ... | @@ -262,6 +262,8 @@ |
262 | 262 | return extractedValues.value.join(','); |
263 | 263 | } else if (record?.type == 50) { |
264 | 264 | return record?.fieldInfos?.checkBillVO?.innerNo; |
265 | + }else if (record?.type == 70) { | |
266 | + return record?.fieldInfos?.deductionUrlFieldVO?.innerNo; | |
265 | 267 | } |
266 | 268 | }, |
267 | 269 | }, |
... | ... | @@ -275,6 +277,8 @@ |
275 | 277 | return '应付账单申请'; |
276 | 278 | } else if (record?.type == 50) { |
277 | 279 | return '生产科发票申请'; |
280 | + }else if (record?.type == 70) { | |
281 | + return `生产科扣款单申请${record?.fieldInfos?.deductionUrlFieldVO?.deductAmount ? `(¥${record?.fieldInfos?.deductionUrlFieldVO?.deductAmount?.toFixed(2)})` : ''}`; | |
278 | 282 | } |
279 | 283 | }, |
280 | 284 | }, |
... | ... | @@ -289,6 +293,8 @@ |
289 | 293 | data.value = record?.fieldInfos?.producePaymentCheckBillFieldVO; |
290 | 294 | } else if (record?.type == 50) { |
291 | 295 | data.value = record?.fieldInfos?.checkBillVO; |
296 | + } else if (record?.type == 70) { | |
297 | + data.value = record?.fieldInfos?.deductionUrlFieldVO; | |
292 | 298 | } |
293 | 299 | return data.value?.productionName; |
294 | 300 | }, |
... | ... | @@ -353,7 +359,7 @@ |
353 | 359 | function handleProfitModal() {} |
354 | 360 | |
355 | 361 | async function handleDetail(data) { |
356 | - if (data.type == 50) { | |
362 | + if (data.type == 50 ) { | |
357 | 363 | showInvoice.value = true; |
358 | 364 | mockData.value = data.fieldInfos.checkBillVO; |
359 | 365 | } else if (data.type == 40) { |
... | ... | @@ -361,6 +367,10 @@ |
361 | 367 | mockData.value = data.fieldInfos.producePaymentCheckBillFieldVO; |
362 | 368 | financePerson.value = mockData.value?.financePerson; |
363 | 369 | trackerUser.value = mockData.value?.trackerUser; |
370 | + }else if(data.type == 70){ | |
371 | + showInvoice.value = true; | |
372 | + mockData.value = data.fieldInfos.deductionUrlFieldVO; | |
373 | + mockData.value.invoiceUrl = mockData.value.deductUrl; | |
364 | 374 | } |
365 | 375 | openModal(true, { data }); |
366 | 376 | id.value = data.id; | ... | ... |
src/views/project/approve/ReceivePanel.vue
... | ... | @@ -35,15 +35,15 @@ |
35 | 35 | </template> |
36 | 36 | </BasicTable> |
37 | 37 | <BasicModal |
38 | - :formFooter="!isApproved && role === ROLE.ADMIN" | |
38 | + :formFooter="(!isApproved && role === ROLE.ADMIN) || showInvoice" | |
39 | 39 | @register="registerModal" |
40 | 40 | title="申请信息" |
41 | 41 | okText="通过" |
42 | 42 | width="1000px" |
43 | 43 | @ok="handleTrue" |
44 | 44 | @visible-change="handleShow" |
45 | - :showCancelBtn="!isApproved && role === ROLE.ADMIN" | |
46 | - :showOkBtn="!isApproved && role === ROLE.ADMIN" | |
45 | + :showCancelBtn="(!isApproved && role === ROLE.ADMIN) || (showInvoice && role === ROLE.FINANCE)" | |
46 | + :showOkBtn="(!isApproved && role === ROLE.ADMIN) || (showInvoice && role === ROLE.FINANCE)" | |
47 | 47 | > |
48 | 48 | <!-- <Description |
49 | 49 | class="mt-4" |
... | ... | @@ -104,6 +104,9 @@ |
104 | 104 | </tr> |
105 | 105 | </tbody> |
106 | 106 | </table> |
107 | + <a v-if="showInvoice" @click="openPic(mockData.invoiceUrl)" rel="noopener noreferrer">{{ | |
108 | + mockData.invoiceName | |
109 | + }}</a> | |
107 | 110 | <template #appendFooter> |
108 | 111 | <a-button |
109 | 112 | v-if="!isApproved && (role === ROLE.ADMIN || role === ROLE.FINANCE)" |
... | ... | @@ -111,7 +114,7 @@ |
111 | 114 | > |
112 | 115 | 不通过</a-button |
113 | 116 | > |
114 | - <a-button v-if="isApproved && role === ROLE.ADMIN" @click="handleFalse"> 驳回重填</a-button> | |
117 | + <a-button v-if="(isApproved && role === ROLE.ADMIN) || (isApproved && showInvoice && role === ROLE.FINANCE)" @click="handleFalse"> 驳回重填</a-button> | |
115 | 118 | <a-button @click="handleExport"> 导出</a-button> |
116 | 119 | </template> |
117 | 120 | </BasicModal> |
... | ... | @@ -167,7 +170,7 @@ |
167 | 170 | const projectNo = ref(); |
168 | 171 | const financePerson = ref(''); |
169 | 172 | const trackerUser = ref(''); |
170 | - | |
173 | + const showInvoice = ref(false); | |
171 | 174 | const mockData = ref(); |
172 | 175 | const schema: DescItem[] = [ |
173 | 176 | { |
... | ... | @@ -217,7 +220,12 @@ |
217 | 220 | width: 150, |
218 | 221 | customRender: (column) => { |
219 | 222 | const { record } = column || {}; |
220 | - return record?.fieldInfos?.invoiceFieldVO?.invoiceNo; | |
223 | + if(record?.type === 30){ | |
224 | + return record?.fieldInfos?.invoiceFieldVO?.invoiceNo; | |
225 | + }else if(record?.type === 60){ | |
226 | + return record?.fieldInfos?.deductionUrlFieldVO?.invoiceNo; | |
227 | + } | |
228 | + | |
221 | 229 | }, |
222 | 230 | }, |
223 | 231 | { |
... | ... | @@ -226,11 +234,28 @@ |
226 | 234 | width: 150, |
227 | 235 | customRender: (column) => { |
228 | 236 | const { record } = column || {}; |
237 | + if(record?.type === 30){ | |
229 | 238 | const extractedValues = ref<string[]>( |
230 | 239 | record?.fieldInfos?.invoiceFieldVO?.innerNo?.map((item) => item), |
231 | 240 | ); |
232 | 241 | // return record?.invoiceFieldVo?.innerNo; |
233 | 242 | return extractedValues?.value?.join(','); |
243 | + }else if(record?.type === 60){ | |
244 | + return record?.fieldInfos?.deductionUrlFieldVO?.innerNo; | |
245 | + } | |
246 | + }, | |
247 | + }, | |
248 | + { | |
249 | + title: '审核类型', | |
250 | + dataIndex: 'productionDepartment', | |
251 | + width: 150, | |
252 | + customRender: (column) => { | |
253 | + const { record } = column || {}; | |
254 | + if (record?.type === 30) { | |
255 | + return '应收账单申请'; | |
256 | + } else if (record?.type == 60) { | |
257 | + return `Invoice扣款单申请${record?.fieldInfos?.deductionUrlFieldVO?.deductAmount ? `(¥${record?.fieldInfos?.deductionUrlFieldVO?.deductAmount?.toFixed(2)})` : ''}`; | |
258 | + } | |
234 | 259 | }, |
235 | 260 | }, |
236 | 261 | ]; |
... | ... | @@ -251,12 +276,21 @@ |
251 | 276 | ]); |
252 | 277 | } |
253 | 278 | |
279 | + const role = computed(() => { | |
280 | + return userStore.getUserInfo?.roleSmallVO?.code; | |
281 | + }); | |
282 | + | |
283 | + // 根据角色动态设置 searchInfo | |
284 | + const searchInfo = computed(() => { | |
285 | + if (role.value === ROLE.BUSINESS || role.value === ROLE.TRACKER) { | |
286 | + return { type: 60 }; // 只显示 invoice 扣款单类型 | |
287 | + } | |
288 | + return { type: 30 }; // 显示所有类型 | |
289 | + }); | |
290 | + | |
254 | 291 | const [registerTable, { reload }] = useTable({ |
255 | 292 | api: props.isApproved ? getApprovedListApi : getWaitListApi, |
256 | - searchInfo: { type: 30 }, | |
257 | - // scroll: { | |
258 | - // scrollToFirstRowOnChange: true, | |
259 | - // }, | |
293 | + searchInfo: searchInfo.value, | |
260 | 294 | columns, |
261 | 295 | useSearchForm: true, |
262 | 296 | formConfig: getFormConfig('invoiceNo'), |
... | ... | @@ -265,7 +299,6 @@ |
265 | 299 | width: 160, |
266 | 300 | title: 'Action', |
267 | 301 | dataIndex: 'action', |
268 | - // slots: { customRender: 'action' }, | |
269 | 302 | }, |
270 | 303 | }); |
271 | 304 | |
... | ... | @@ -292,10 +325,32 @@ |
292 | 325 | } |
293 | 326 | |
294 | 327 | function handleProfitModal() {} |
328 | + // 打开图片或 PDF | |
329 | + function openPic(url: string) { | |
330 | + const baseUrl = url.split('?')[0]; // 获取问号前的部分 | |
331 | + if (isImageUrl(baseUrl)) { | |
332 | + window.open('', '', '').document.write(`<!DOCTYPE html> | |
333 | + <html> | |
334 | + <body style="display: flex; justify-content: center; align-items: center;"> | |
335 | + <img src='${url}' width="300px" height="auto"/> | |
336 | + </body> | |
337 | + </html>`); | |
338 | + } else if (isPdfUrl(baseUrl)) { | |
339 | + view(url); // 新标签页打开 PDF | |
340 | + } else { | |
341 | + console.log('不支持的文件类型'); | |
342 | + } | |
343 | + } | |
295 | 344 | |
296 | 345 | async function handleDetail(data) { |
346 | + if(data.type == 60){ | |
347 | + showInvoice.value = true; | |
348 | + mockData.value = data.fieldInfos.deductionUrlFieldVO; | |
349 | + }else if(data.type == 30){ | |
350 | + showInvoice.value=false; | |
351 | + mockData.value=data.fieldInfos.invoiceFieldVO; | |
352 | + } | |
297 | 353 | openModal(true, { data }); |
298 | - mockData.value = data.fieldInfos.invoiceFieldVO; | |
299 | 354 | id.value = data.id; |
300 | 355 | financePerson.value = mockData.value?.financePerson; |
301 | 356 | trackerUser.value = mockData.value?.trackerUser; |
... | ... | @@ -309,6 +364,13 @@ |
309 | 364 | otherAmount.value = mockData.value.otherAmount?.toFixed(2); |
310 | 365 | invoiceNo.value = mockData.value.invoiceNo; |
311 | 366 | payee.value = mockData.value.payee; |
367 | + const match = mockData.value?.deductUrl?.match(/aliyuncs\.com\/(.*?)\?/); | |
368 | + if (match && match[1]) { | |
369 | + // 对提取的部分进行解码 | |
370 | + mockData.value.invoiceName = decodeURIComponent(match[1]); | |
371 | + } else { | |
372 | + mockData.value.invoiceName = mockData.value?.deductUrl; | |
373 | + } | |
312 | 374 | } |
313 | 375 | |
314 | 376 | async function handleTrue() { |
... | ... | @@ -329,10 +391,6 @@ |
329 | 391 | } |
330 | 392 | } |
331 | 393 | |
332 | - const role = computed(() => { | |
333 | - return userStore.getUserInfo?.roleSmallVO?.code; | |
334 | - }); | |
335 | - | |
336 | 394 | // 定义MsgModalClose的事件,方便子组件调用 |
337 | 395 | const handleMsgModalClose = async (data) => { |
338 | 396 | if (data) { |
... | ... | @@ -418,6 +476,8 @@ |
418 | 476 | msgVisible, |
419 | 477 | handleMsgModalClose, |
420 | 478 | handlePreview, |
479 | + showInvoice, | |
480 | + openPic, | |
421 | 481 | mockData, |
422 | 482 | schema, |
423 | 483 | totalPayAmount, | ... | ... |
src/views/project/approve/index.vue
... | ... | @@ -16,9 +16,9 @@ |
16 | 16 | v-if=" |
17 | 17 | role == ROLE.FINANCE || |
18 | 18 | role == ROLE.ADMIN |
19 | - // || | |
20 | - // role == ROLE.BUSINESS || | |
21 | - // role == ROLE.TRACKER | |
19 | + || | |
20 | + role == ROLE.BUSINESS || | |
21 | + role == ROLE.TRACKER | |
22 | 22 | " |
23 | 23 | > |
24 | 24 | <ReceivePanel /> |
... | ... | @@ -60,9 +60,9 @@ |
60 | 60 | v-if=" |
61 | 61 | role == ROLE.FINANCE || |
62 | 62 | role == ROLE.ADMIN |
63 | - // || | |
64 | - // role == ROLE.BUSINESS || | |
65 | - // role == ROLE.TRACKER | |
63 | + || | |
64 | + role == ROLE.BUSINESS || | |
65 | + role == ROLE.TRACKER | |
66 | 66 | " |
67 | 67 | > |
68 | 68 | <ReceivePanel isApproved /> | ... | ... |
src/views/project/finance/financeList/finance.data.tsx
... | ... | @@ -38,8 +38,9 @@ export const searchFormSchema: FormSchema[] = [ |
38 | 38 | componentProps: { |
39 | 39 | options: [ |
40 | 40 | { label: '未创建', value: -1 }, |
41 | - { label: '未收款', value: 0 }, | |
42 | - { label: '已收款', value: 10 }, | |
41 | + { label: '未收款(已创建未提交审核)', value: 0 }, | |
42 | + { label: '待收款(审核通过,未手动确认)', value: 10 }, | |
43 | + { label: '已收款(手动确认)', value: 40 }, | |
43 | 44 | ], |
44 | 45 | }, |
45 | 46 | }, |
... | ... | @@ -51,35 +52,13 @@ export const searchFormSchema: FormSchema[] = [ |
51 | 52 | componentProps: { |
52 | 53 | options: [ |
53 | 54 | { label: '未创建', value: -1 }, |
54 | - { label: '未付款', value: 0 }, | |
55 | - { label: '已付款', value: 10 }, | |
56 | - ], | |
57 | - }, | |
58 | - }, | |
59 | - { | |
60 | - field: 'invoiceFinishStatus', | |
61 | - label: 'invoice最终状态', | |
62 | - component: 'Select', | |
63 | - colProps: { span: 8 }, | |
64 | - componentProps: { | |
65 | - options: [ | |
66 | - { label: '未完成', value: 0 }, | |
67 | - { label: '已完成', value: 10 }, | |
68 | - ], | |
69 | - }, | |
70 | - }, | |
71 | - { | |
72 | - field: 'checkFinishStatus', | |
73 | - label: 'checkNo最终状态', | |
74 | - component: 'Select', | |
75 | - colProps: { span: 8 }, | |
76 | - componentProps: { | |
77 | - options: [ | |
78 | - { label: '未完成', value: 0 }, | |
79 | - { label: '已完成', value: 10 }, | |
55 | + { label: '未付款(已创建未提交审核)', value: 0 }, | |
56 | + { label: '待付款(审核通过,未手动确认)', value: 10 }, | |
57 | + { label: '已付款(手动确认)', value: 40 }, | |
80 | 58 | ], |
81 | 59 | }, |
82 | 60 | }, |
61 | + | |
83 | 62 | { |
84 | 63 | field: 'customerCode', |
85 | 64 | label: '客户编码', |
... | ... | @@ -324,7 +303,7 @@ export const columns: BasicColumn[] = [ |
324 | 303 | width: 80, |
325 | 304 | customRender: (column) => { |
326 | 305 | const deductUrl = column.record.invoiceDeductUrl; |
327 | - if (deductUrl == undefined) { | |
306 | + if (deductUrl == undefined || !deductUrl) { | |
328 | 307 | return; |
329 | 308 | } |
330 | 309 | // return <FilePptOutlined style="font-size:25px" onClick={() => window.open(deductUrl[0])} />; |
... | ... | @@ -332,6 +311,20 @@ export const columns: BasicColumn[] = [ |
332 | 311 | }, |
333 | 312 | }, |
334 | 313 | { |
314 | + title: '扣款单状态', | |
315 | + dataIndex: 'invoiceDeductUrlStatus', | |
316 | + width: 120, | |
317 | + customRender: (column) => { | |
318 | + if(column.record.invoiceDeductUrlStatus == 0){ | |
319 | + return '待审核' | |
320 | + }else if(column.record.invoiceDeductUrlStatus == 10){ | |
321 | + return '已通过' | |
322 | + }else if(column.record.invoiceDeductUrlStatus == 20){ | |
323 | + return '已驳回' | |
324 | + } | |
325 | + }, | |
326 | + }, | |
327 | + { | |
335 | 328 | title: '实际应收金额$', |
336 | 329 | dataIndex: 'invoiceActualReceivableAmount', |
337 | 330 | width: 120, |
... | ... | @@ -381,32 +374,23 @@ export const columns: BasicColumn[] = [ |
381 | 374 | dataIndex: 'invoiceStatus', |
382 | 375 | width: 120, |
383 | 376 | customRender: (column) => { |
377 | + let statusText=''; | |
378 | + let statusColor='blank'; | |
384 | 379 | if (column.record.invoiceStatus == null || column.record.invoiceStatus == undefined) { |
385 | - return '未创建'; | |
380 | + statusText='未创建'; | |
386 | 381 | } else if (column.record.invoiceStatus == 0) { |
387 | - return '未收款'; | |
382 | + statusText= '未收款'; | |
388 | 383 | } else if (column.record.invoiceStatus == 10) { |
389 | - return '已收款'; | |
384 | + statusText= '待收款'; | |
385 | + statusColor='red'; | |
386 | + }else if (column.record.invoiceStatus == 40) { | |
387 | + statusText= '已收款'; | |
388 | + statusColor='green'; | |
390 | 389 | } |
390 | + return <span style={{color:statusColor}}>{statusText}</span> | |
391 | 391 | }, |
392 | 392 | }, |
393 | - { | |
394 | - title: '最终状态', | |
395 | - dataIndex: 'invoiceFinishStatus', | |
396 | - width: 120, | |
397 | - customRender: (column) => { | |
398 | - let statusText = ''; | |
399 | - let statusColor = ''; | |
400 | - if (column.record.invoiceFinishStatus == null || column.record.invoiceFinishStatus == undefined || column.record.invoiceFinishStatus == 0) { | |
401 | - statusText = '未完成'; | |
402 | - statusColor = 'red'; // 设置红色 | |
403 | - } else if (column.record.checkFinishStatus == 10) { | |
404 | - statusText = '已完成'; | |
405 | - statusColor = 'green'; // 设置绿色 | |
406 | - } | |
407 | - return <span style={{ color: statusColor }}>{statusText}</span>; | |
408 | - }, | |
409 | - }, | |
393 | + | |
410 | 394 | { |
411 | 395 | title: 'Action', |
412 | 396 | key: 'action', // 对应 #bodyCell 中的 column.key |
... | ... | @@ -460,13 +444,27 @@ export const columns: BasicColumn[] = [ |
460 | 444 | width: 120, |
461 | 445 | customRender: (column) => { |
462 | 446 | const deductUrl = column.record.checkDeductUrl; |
463 | - if (deductUrl == undefined) { | |
447 | + if (deductUrl == undefined || !deductUrl) { | |
464 | 448 | return; |
465 | 449 | } |
466 | 450 | return <FilePptOutlined style="font-size:25px" />; |
467 | 451 | }, |
468 | 452 | }, |
469 | 453 | { |
454 | + title: '扣款单状态', | |
455 | + dataIndex: 'checkDeductUrlStatus', | |
456 | + width: 120, | |
457 | + customRender: (column) => { | |
458 | + if(column.record.checkDeductUrlStatus == 0){ | |
459 | + return '待审核' | |
460 | + }else if(column.record.checkDeductUrlStatus == 10){ | |
461 | + return '已通过' | |
462 | + }else if(column.record.checkDeductUrlStatus == 20){ | |
463 | + return '已驳回' | |
464 | + } | |
465 | + }, | |
466 | + }, | |
467 | + { | |
470 | 468 | title: '生产科实际应付金额¥', |
471 | 469 | dataIndex: 'checkActualPayedAmount', |
472 | 470 | width: 180, |
... | ... | @@ -534,32 +532,23 @@ export const columns: BasicColumn[] = [ |
534 | 532 | dataIndex: 'checkPayStatus', |
535 | 533 | width: 120, |
536 | 534 | customRender: (column) => { |
535 | + let statusText=''; | |
536 | + let statusColor='blank'; | |
537 | 537 | if (column.record.checkPayStatus == null || column.record.checkPayStatus == undefined) { |
538 | - return '未创建'; | |
538 | + statusText='未创建'; | |
539 | 539 | } else if (column.record.checkPayStatus == 0) { |
540 | - return '未付款'; | |
540 | + statusText='未付款'; | |
541 | 541 | } else if (column.record.checkPayStatus == 10) { |
542 | - return '已付款'; | |
542 | + statusText='待付款'; | |
543 | + statusColor='red'; | |
544 | + }else if (column.record.checkPayStatus == 40) { | |
545 | + statusText='已付款'; | |
546 | + statusColor='green'; | |
543 | 547 | } |
548 | + return <span style={{color:statusColor}}>{statusText}</span> | |
544 | 549 | }, |
545 | 550 | }, |
546 | - { | |
547 | - title: '最终状态', | |
548 | - dataIndex: 'checkFinishStatus', | |
549 | - width: 120, | |
550 | - customRender: (column) => { | |
551 | - let statusText = ''; | |
552 | - let statusColor = ''; | |
553 | - if (column.record.checkFinishStatus == null || column.record.checkFinishStatus == undefined || column.record.checkFinishStatus == 0) { | |
554 | - statusText = '未完成'; | |
555 | - statusColor = 'red'; // 设置红色 | |
556 | - } else if (column.record.checkFinishStatus == 10) { | |
557 | - statusText = '已完成'; | |
558 | - statusColor = 'green'; // 设置绿色 | |
559 | - } | |
560 | - return <span style={{ color: statusColor }}>{statusText}</span>; | |
561 | - }, | |
562 | - }, | |
551 | + | |
563 | 552 | { |
564 | 553 | title: 'Action', |
565 | 554 | key: 'action2', // 对应 #bodyCell 中的 column.key | ... | ... |
src/views/project/finance/financeList/index.vue
... | ... | @@ -171,8 +171,9 @@ |
171 | 171 | ...(role == ROLE.ADMIN |
172 | 172 | ? [ |
173 | 173 | { |
174 | - label: '设置invoice最终完成', | |
174 | + label: '设置为已收款', | |
175 | 175 | onClick: handleInvoiceSetFinishStatus.bind(null, record), |
176 | + //需要设置按钮为红色。 | |
176 | 177 | }, |
177 | 178 | ] |
178 | 179 | : []), |
... | ... | @@ -261,7 +262,7 @@ |
261 | 262 | ...(role == ROLE.ADMIN |
262 | 263 | ? [ |
263 | 264 | { |
264 | - label: '设置对账单最终完成', | |
265 | + label: '设置为已付款', | |
265 | 266 | onClick: handleCheckSetFinishStatus.bind(null, record), |
266 | 267 | }, |
267 | 268 | ] | ... | ... |
src/views/project/order/Statement.vue
0 → 100644
1 | +<template> | |
2 | + | |
3 | + <BasicModal | |
4 | + v-bind="$attrs" | |
5 | + destroyOnClose | |
6 | + @register="register" | |
7 | + title="LOACL对账单" | |
8 | + width="1100px" | |
9 | + @visible-change="handleShow" | |
10 | + :footer="null" | |
11 | + :bodyStyle="{ height: '650px', overflow: 'hidden' }" | |
12 | + > | |
13 | + <div class="container"> | |
14 | + <div v-if="isShow1 == true" style="margin-top: 30px"> | |
15 | + <RadioGroup v-model:value="selectedCompany" :options="companyOptions" style="display: flex; gap: 200px;"/> | |
16 | + </div> | |
17 | + <!-- 代垫费用区域 --> | |
18 | + <div class="table-container" style="display: flex; flex-wrap: wrap; justify-content: space-between; margin-top: 30px" > | |
19 | + <div class="table-box" style="flex: 0.5; margin-right: -20px;"> | |
20 | + <h3>代垫费用</h3> | |
21 | + <div class="input-row" style="display: flex; align-items: center;"> | |
22 | + <a-button type="primary" style="margin-left: 10px;" @click="addAdvanceCost">添加费用</a-button> | |
23 | + </div> | |
24 | + <div v-for="(item, index) in advanceCosts" :key="'advance-' + index" class="input-row" style="margin-top: 10px; display: flex;"> | |
25 | + <a-input v-model:value="item.name" placeholder="请输入费用名称" style="width: 200px;" /> | |
26 | + <a-input-number v-model:value="item.value" placeholder="请输入费用金额" style="width: 150px !important; margin-left: 10px;" /> | |
27 | + <a-button type="danger" style="margin-left: 10px;" @click="removeAdvanceCost(index)">删除</a-button> | |
28 | + </div> | |
29 | + </div> | |
30 | + <div class="table-box" style="flex: 1;"> | |
31 | + <h3>费用支出</h3> | |
32 | + <div class="input-row" style="display: flex; align-items: center;"> | |
33 | + <a-button type="primary" style="margin-left: 10px;" @click="addExpenseCost">添加费用</a-button> | |
34 | + </div> | |
35 | + <div v-for="(item, index) in expenseCosts" :key="'expense-' + index" class="input-row" style="margin-top: 10px; display: flex;"> | |
36 | + <a-input v-model:value="item.name" placeholder="请输入费用名称" style="width: 200px;" /> | |
37 | + <a-input-number v-model:value="item.value" placeholder="请输入费用金额" style="width: 150px !important; margin-left: 10px;" /> | |
38 | + <a-button type="danger" style="margin-left: 10px;" @click="removeExpenseCost(index)">删除</a-button> | |
39 | + </div> | |
40 | + </div> | |
41 | + </div> | |
42 | + | |
43 | + <div class="bottom"> | |
44 | + <a-button type="primary" @click="handleAccountStatement" className="ml-4" v-if="isShow1 == true" | |
45 | + >生成</a-button | |
46 | + > | |
47 | + <a-button type="primary" @click="handleCancel" className="ml-4" style="margin-left: 6px" | |
48 | + >取消</a-button | |
49 | + > | |
50 | + </div> | |
51 | + </div> | |
52 | + </BasicModal> | |
53 | + </template> | |
54 | + <script lang="ts"> | |
55 | + import { defineComponent, ref, computed } from 'vue'; | |
56 | + import { BasicModal, useModalInner } from '/@/components/Modal'; | |
57 | + import { RadioGroup } from 'ant-design-vue'; | |
58 | + import { useMessage } from '@/hooks/web/useMessage'; | |
59 | + import axios from 'axios'; | |
60 | + | |
61 | + export default defineComponent({ | |
62 | + props: { | |
63 | + role: { | |
64 | + type: String, | |
65 | + }, | |
66 | + customerCodes: { | |
67 | + type: Array<string | number>, | |
68 | + }, | |
69 | + }, | |
70 | + components: { BasicModal, RadioGroup }, | |
71 | + setup(props) { | |
72 | + const loading = ref(true); | |
73 | + const choose = ref(); | |
74 | + const checkedKeys=ref(); | |
75 | + const isShow1 = ref(true); | |
76 | + const advanceCostValue = ref(0); | |
77 | + const expenseCostValue = ref(0); | |
78 | + const advanceCosts = ref<{ name: string; value: number }[]>([]); | |
79 | + const expenseCosts = ref<{ name: string; value: number }[]>([]); | |
80 | + const [register, { setModalProps, closeModal }] = useModalInner(async (data)=>{ | |
81 | + checkedKeys.value=data.checkedKeys; | |
82 | + }); | |
83 | + const { createMessage } = useMessage(); | |
84 | + const { error } = createMessage; | |
85 | + const selectedCompany = ref(); | |
86 | + const companyOptions = ref([ | |
87 | + { label: '翱特逸格饰品有限公司', value: '翱特逸格饰品有限公司' }, | |
88 | + { label: '吉庆天成饰品有限公司', value: '吉庆天成饰品有限公司' } | |
89 | + ]); | |
90 | + | |
91 | + function addAdvanceCost() { | |
92 | + advanceCosts.value.push({ name: '', value: advanceCostValue.value }); | |
93 | + } | |
94 | + | |
95 | + function addExpenseCost() { | |
96 | + expenseCosts.value.push({ name: '', value: expenseCostValue.value }); | |
97 | + } | |
98 | + | |
99 | + function removeAdvanceCost(index: number) { | |
100 | + advanceCosts.value.splice(index, 1); | |
101 | + } | |
102 | + | |
103 | + function removeExpenseCost(index: number) { | |
104 | + expenseCosts.value.splice(index, 1); | |
105 | + } | |
106 | + | |
107 | + function handleCancel() { | |
108 | + loading.value = true; | |
109 | + choose.value = ''; | |
110 | + setModalProps({ loading: false, confirmLoading: false }); | |
111 | + isShow1.value = true; | |
112 | + advanceCosts.value = []; | |
113 | + expenseCosts.value = []; | |
114 | + closeModal(); | |
115 | + } | |
116 | + | |
117 | + function handleShow(visible: boolean) { | |
118 | + if (visible) { | |
119 | + loading.value = true; | |
120 | + choose.value = ''; | |
121 | + setModalProps({ loading: false, confirmLoading: false }); | |
122 | + isShow1.value = true; | |
123 | + } else { | |
124 | + advanceCosts.value = []; | |
125 | + expenseCosts.value = []; | |
126 | + } | |
127 | + } | |
128 | + async function handleAccountStatement() { | |
129 | + if (!selectedCompany.value) { | |
130 | + error('请选择公司'); // 提示用户选择公司 | |
131 | + return; // 结束函数执行 | |
132 | + } | |
133 | + | |
134 | + axios | |
135 | + .post( | |
136 | + '/basic-api/order/erp/order/accountStatement', | |
137 | + { | |
138 | + ids: checkedKeys.value, | |
139 | + disbursement: advanceCosts.value.map(item => ({ [item.name]: item.value })), | |
140 | + deduction: expenseCosts.value.map(item => ({ [item.name]: item.value })), | |
141 | + titleCompany: selectedCompany.value | |
142 | + }, | |
143 | + { | |
144 | + responseType: 'blob', // 设置响应类型为 'blob' | |
145 | + }, | |
146 | + ) | |
147 | + .then((response) => { | |
148 | + // 创建一个 Blob 对象来保存二进制数据 | |
149 | + const blob = new Blob([response.data], { type: 'application/octet-stream' }); | |
150 | + const getFormattedDate = (): string => { | |
151 | + const date = new Date(); | |
152 | + | |
153 | + const year = date.getFullYear(); | |
154 | + const month = String(date.getMonth() + 1).padStart(2, '0'); | |
155 | + const day = String(date.getDate()).padStart(2, '0'); | |
156 | + | |
157 | + const hours = String(date.getHours()).padStart(2, '0'); | |
158 | + const minutes = String(date.getMinutes()).padStart(2, '0'); | |
159 | + const seconds = String(date.getSeconds()).padStart(2, '0'); | |
160 | + | |
161 | + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; | |
162 | + }; | |
163 | + const date = getFormattedDate(); | |
164 | + // 创建一个链接元素用于下载 | |
165 | + const link = document.createElement('a'); | |
166 | + link.href = window.URL.createObjectURL(blob); | |
167 | + link.download = `${selectedCompany.value}对账单${date}.xlsx`; // 你可以为文件命名 | |
168 | + document.body.appendChild(link); | |
169 | + link.click(); // 自动点击链接,触发下载 | |
170 | + document.body.removeChild(link); // 下载完成后移除链接 | |
171 | + }) | |
172 | + .catch((error) => { | |
173 | + console.error(error); | |
174 | + }); | |
175 | + closeModal(); | |
176 | + } | |
177 | + return { | |
178 | + register, | |
179 | + loading, | |
180 | + choose, | |
181 | + handleShow, | |
182 | + handleCancel, | |
183 | + advanceCostValue, | |
184 | + expenseCostValue, | |
185 | + advanceCosts, | |
186 | + expenseCosts, | |
187 | + addAdvanceCost, | |
188 | + addExpenseCost, | |
189 | + isShow1, | |
190 | + selectedCompany, | |
191 | + companyOptions, | |
192 | + removeAdvanceCost, | |
193 | + removeExpenseCost, | |
194 | + handleAccountStatement, | |
195 | + }; | |
196 | + }, | |
197 | + }); | |
198 | + </script> | |
199 | + <style scoped> | |
200 | + /* .container { | |
201 | + position: relative; | |
202 | + } | |
203 | + .bottom { | |
204 | + position: absolute; | |
205 | + bottom: 0; | |
206 | + } */ | |
207 | + .container { | |
208 | + display: flex; | |
209 | + flex-direction: column; | |
210 | + /* min-height: 20vh; */ | |
211 | + } | |
212 | + | |
213 | + .bottom { | |
214 | + margin-top: 40px; | |
215 | + /* margin-right: auto; */ | |
216 | + margin-left: 150px; | |
217 | + } | |
218 | + | |
219 | + .showPdf { | |
220 | + display: flex; | |
221 | + position: relative; | |
222 | + height: 30px; | |
223 | + width: 470px; | |
224 | + border: 2px solid; | |
225 | + border-radius: 5px; | |
226 | + border-color: #d8d8d8; | |
227 | + } | |
228 | + | |
229 | + .FilePptOutlined { | |
230 | + margin-top: 3px; | |
231 | + margin-left: 30px; | |
232 | + } | |
233 | + | |
234 | + .EyeOutlined { | |
235 | + margin-top: 3px; | |
236 | + margin-left: 290px; | |
237 | + } | |
238 | + </style> | ... | ... |
src/views/project/order/index.vue
... | ... | @@ -118,6 +118,18 @@ |
118 | 118 | <!-- <a-space wrap :size="[8, 16]" :style="{ marginBottom: '2px', marginLeft: '10px' }"> --> |
119 | 119 | <a-space wrap :style="{ marginBottom: '2px', marginTop: '2px' }"> |
120 | 120 | <a-button |
121 | + :style="{backgroundColor: '#ff69b4', borderColor: '#ff69b4', color: 'white',borderRadius: '5px 5px 5px 5px' }" | |
122 | + shape="default" | |
123 | + type="primary" | |
124 | + @click=" handleStatementModal" | |
125 | + v-if=" | |
126 | + role === ROLE.ADMIN || | |
127 | + role === ROLE.BUSINESS || | |
128 | + role === ROLE.TRACKER | |
129 | + " | |
130 | + >LOACL对账单</a-button | |
131 | + > | |
132 | + <a-button | |
121 | 133 | :style="{ borderRadius: '5px 5px 5px 5px' }" |
122 | 134 | type="primary" |
123 | 135 | @click="handleProductInvoiceModal" |
... | ... | @@ -231,6 +243,11 @@ |
231 | 243 | :role="role" |
232 | 244 | :customerCodes="selectedCustomCodes" |
233 | 245 | /> |
246 | + <Statement | |
247 | + @register="statementModalRegister" | |
248 | + :role="role" | |
249 | + :customerCodes="selectedCustomCodes" | |
250 | + /> | |
234 | 251 | <InvoiceCreate @register="invoiceCreateModalRegister" @success="handleFormSuccess" /> |
235 | 252 | <ServiceProfit @register="serviceProfitModalRegister" /> |
236 | 253 | <ProductProfit @register="productProfitModalRegister" /> |
... | ... | @@ -250,11 +267,12 @@ |
250 | 267 | import { BasicTable, useTable, TableAction } from '/@/components/Table'; |
251 | 268 | import { FormOutlined } from '@ant-design/icons-vue'; |
252 | 269 | import HeaderCell from '/@/components/Table/src/components/HeaderCell.vue'; |
253 | - import { Alert } from 'ant-design-vue'; | |
270 | + import { Alert } from 'ant-design-vue' | |
254 | 271 | |
255 | 272 | import { useDrawer } from '/@/components/Drawer'; |
256 | 273 | import ProfitAnalysis from './ProfitAnalysis.vue'; |
257 | 274 | import ProductText from './ProductText.vue'; |
275 | + import Statement from './Statement.vue'; | |
258 | 276 | import RateModal from './RateModal.vue'; |
259 | 277 | import ExportModal from './ExportModal.vue'; |
260 | 278 | import PassCalculate from './PassCalculate.vue'; |
... | ... | @@ -291,6 +309,7 @@ |
291 | 309 | FormDetail, |
292 | 310 | ProfitAnalysis, |
293 | 311 | ProductText, |
312 | + Statement, | |
294 | 313 | PassCalculate, |
295 | 314 | FormOutlined, |
296 | 315 | CheckDetail, |
... | ... | @@ -316,6 +335,7 @@ |
316 | 335 | const [exportModalRegister, { openModal: openExportModal }] = useModal(); |
317 | 336 | const [productModalRegister, { openModal: openProductModal }] = useModal(); |
318 | 337 | const [passModalRegister, { openModal: openPassModal }] = useModal(); |
338 | + const [statementModalRegister, { openModal: openStatementModal }] = useModal(); | |
319 | 339 | |
320 | 340 | const tooltipVisible = ref(false); |
321 | 341 | const [formDetailRegister, { openDrawer: openFormDetailDrawer }] = useDrawer(); |
... | ... | @@ -761,6 +781,20 @@ |
761 | 781 | data: values, |
762 | 782 | }); |
763 | 783 | } |
784 | + //对账单 | |
785 | + function handleStatementModal(record) { | |
786 | + const form = getForm(); | |
787 | + const values = form.getFieldsValue(); | |
788 | + if (checkedKeys.value.length == 0) { | |
789 | + error('请选择订单'); | |
790 | + return; | |
791 | + } | |
792 | + openStatementModal(true, { | |
793 | + checkedKeys: checkedKeys.value, | |
794 | + customers: selectedCustomCodes.value, | |
795 | + data: values, | |
796 | + }); | |
797 | + } | |
764 | 798 | |
765 | 799 | function handleRateModal() { |
766 | 800 | const form = getForm(); |
... | ... | @@ -871,6 +905,7 @@ |
871 | 905 | rateModalRegister, |
872 | 906 | exportModalRegister, |
873 | 907 | productModalRegister, |
908 | + statementModalRegister, | |
874 | 909 | passModalRegister, |
875 | 910 | historyDetailRegister, |
876 | 911 | trackHistoryRegister, |
... | ... | @@ -878,6 +913,7 @@ |
878 | 913 | handleProfitModal, |
879 | 914 | handleInvoiceCreateModal, |
880 | 915 | handleProductInvoiceModal, |
916 | + handleStatementModal, | |
881 | 917 | registerTable, |
882 | 918 | getFormValues, |
883 | 919 | checkedKeys, |
... | ... | @@ -905,6 +941,7 @@ |
905 | 941 | handleRateModal, |
906 | 942 | openExportModal, |
907 | 943 | openProductModal, |
944 | + openStatementModal, | |
908 | 945 | openPassModal, |
909 | 946 | handleDelete, |
910 | 947 | handleServiceProfitModal, | ... | ... |