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,6 +262,8 @@ | ||
262 | return extractedValues.value.join(','); | 262 | return extractedValues.value.join(','); |
263 | } else if (record?.type == 50) { | 263 | } else if (record?.type == 50) { |
264 | return record?.fieldInfos?.checkBillVO?.innerNo; | 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,6 +277,8 @@ | ||
275 | return '应付账单申请'; | 277 | return '应付账单申请'; |
276 | } else if (record?.type == 50) { | 278 | } else if (record?.type == 50) { |
277 | return '生产科发票申请'; | 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,6 +293,8 @@ | ||
289 | data.value = record?.fieldInfos?.producePaymentCheckBillFieldVO; | 293 | data.value = record?.fieldInfos?.producePaymentCheckBillFieldVO; |
290 | } else if (record?.type == 50) { | 294 | } else if (record?.type == 50) { |
291 | data.value = record?.fieldInfos?.checkBillVO; | 295 | data.value = record?.fieldInfos?.checkBillVO; |
296 | + } else if (record?.type == 70) { | ||
297 | + data.value = record?.fieldInfos?.deductionUrlFieldVO; | ||
292 | } | 298 | } |
293 | return data.value?.productionName; | 299 | return data.value?.productionName; |
294 | }, | 300 | }, |
@@ -353,7 +359,7 @@ | @@ -353,7 +359,7 @@ | ||
353 | function handleProfitModal() {} | 359 | function handleProfitModal() {} |
354 | 360 | ||
355 | async function handleDetail(data) { | 361 | async function handleDetail(data) { |
356 | - if (data.type == 50) { | 362 | + if (data.type == 50 ) { |
357 | showInvoice.value = true; | 363 | showInvoice.value = true; |
358 | mockData.value = data.fieldInfos.checkBillVO; | 364 | mockData.value = data.fieldInfos.checkBillVO; |
359 | } else if (data.type == 40) { | 365 | } else if (data.type == 40) { |
@@ -361,6 +367,10 @@ | @@ -361,6 +367,10 @@ | ||
361 | mockData.value = data.fieldInfos.producePaymentCheckBillFieldVO; | 367 | mockData.value = data.fieldInfos.producePaymentCheckBillFieldVO; |
362 | financePerson.value = mockData.value?.financePerson; | 368 | financePerson.value = mockData.value?.financePerson; |
363 | trackerUser.value = mockData.value?.trackerUser; | 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 | openModal(true, { data }); | 375 | openModal(true, { data }); |
366 | id.value = data.id; | 376 | id.value = data.id; |
src/views/project/approve/ReceivePanel.vue
@@ -35,15 +35,15 @@ | @@ -35,15 +35,15 @@ | ||
35 | </template> | 35 | </template> |
36 | </BasicTable> | 36 | </BasicTable> |
37 | <BasicModal | 37 | <BasicModal |
38 | - :formFooter="!isApproved && role === ROLE.ADMIN" | 38 | + :formFooter="(!isApproved && role === ROLE.ADMIN) || showInvoice" |
39 | @register="registerModal" | 39 | @register="registerModal" |
40 | title="申请信息" | 40 | title="申请信息" |
41 | okText="通过" | 41 | okText="通过" |
42 | width="1000px" | 42 | width="1000px" |
43 | @ok="handleTrue" | 43 | @ok="handleTrue" |
44 | @visible-change="handleShow" | 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 | <!-- <Description | 48 | <!-- <Description |
49 | class="mt-4" | 49 | class="mt-4" |
@@ -104,6 +104,9 @@ | @@ -104,6 +104,9 @@ | ||
104 | </tr> | 104 | </tr> |
105 | </tbody> | 105 | </tbody> |
106 | </table> | 106 | </table> |
107 | + <a v-if="showInvoice" @click="openPic(mockData.invoiceUrl)" rel="noopener noreferrer">{{ | ||
108 | + mockData.invoiceName | ||
109 | + }}</a> | ||
107 | <template #appendFooter> | 110 | <template #appendFooter> |
108 | <a-button | 111 | <a-button |
109 | v-if="!isApproved && (role === ROLE.ADMIN || role === ROLE.FINANCE)" | 112 | v-if="!isApproved && (role === ROLE.ADMIN || role === ROLE.FINANCE)" |
@@ -111,7 +114,7 @@ | @@ -111,7 +114,7 @@ | ||
111 | > | 114 | > |
112 | 不通过</a-button | 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 | <a-button @click="handleExport"> 导出</a-button> | 118 | <a-button @click="handleExport"> 导出</a-button> |
116 | </template> | 119 | </template> |
117 | </BasicModal> | 120 | </BasicModal> |
@@ -167,7 +170,7 @@ | @@ -167,7 +170,7 @@ | ||
167 | const projectNo = ref(); | 170 | const projectNo = ref(); |
168 | const financePerson = ref(''); | 171 | const financePerson = ref(''); |
169 | const trackerUser = ref(''); | 172 | const trackerUser = ref(''); |
170 | - | 173 | + const showInvoice = ref(false); |
171 | const mockData = ref(); | 174 | const mockData = ref(); |
172 | const schema: DescItem[] = [ | 175 | const schema: DescItem[] = [ |
173 | { | 176 | { |
@@ -217,7 +220,12 @@ | @@ -217,7 +220,12 @@ | ||
217 | width: 150, | 220 | width: 150, |
218 | customRender: (column) => { | 221 | customRender: (column) => { |
219 | const { record } = column || {}; | 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,11 +234,28 @@ | ||
226 | width: 150, | 234 | width: 150, |
227 | customRender: (column) => { | 235 | customRender: (column) => { |
228 | const { record } = column || {}; | 236 | const { record } = column || {}; |
237 | + if(record?.type === 30){ | ||
229 | const extractedValues = ref<string[]>( | 238 | const extractedValues = ref<string[]>( |
230 | record?.fieldInfos?.invoiceFieldVO?.innerNo?.map((item) => item), | 239 | record?.fieldInfos?.invoiceFieldVO?.innerNo?.map((item) => item), |
231 | ); | 240 | ); |
232 | // return record?.invoiceFieldVo?.innerNo; | 241 | // return record?.invoiceFieldVo?.innerNo; |
233 | return extractedValues?.value?.join(','); | 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,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 | const [registerTable, { reload }] = useTable({ | 291 | const [registerTable, { reload }] = useTable({ |
255 | api: props.isApproved ? getApprovedListApi : getWaitListApi, | 292 | api: props.isApproved ? getApprovedListApi : getWaitListApi, |
256 | - searchInfo: { type: 30 }, | ||
257 | - // scroll: { | ||
258 | - // scrollToFirstRowOnChange: true, | ||
259 | - // }, | 293 | + searchInfo: searchInfo.value, |
260 | columns, | 294 | columns, |
261 | useSearchForm: true, | 295 | useSearchForm: true, |
262 | formConfig: getFormConfig('invoiceNo'), | 296 | formConfig: getFormConfig('invoiceNo'), |
@@ -265,7 +299,6 @@ | @@ -265,7 +299,6 @@ | ||
265 | width: 160, | 299 | width: 160, |
266 | title: 'Action', | 300 | title: 'Action', |
267 | dataIndex: 'action', | 301 | dataIndex: 'action', |
268 | - // slots: { customRender: 'action' }, | ||
269 | }, | 302 | }, |
270 | }); | 303 | }); |
271 | 304 | ||
@@ -292,10 +325,32 @@ | @@ -292,10 +325,32 @@ | ||
292 | } | 325 | } |
293 | 326 | ||
294 | function handleProfitModal() {} | 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 | async function handleDetail(data) { | 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 | openModal(true, { data }); | 353 | openModal(true, { data }); |
298 | - mockData.value = data.fieldInfos.invoiceFieldVO; | ||
299 | id.value = data.id; | 354 | id.value = data.id; |
300 | financePerson.value = mockData.value?.financePerson; | 355 | financePerson.value = mockData.value?.financePerson; |
301 | trackerUser.value = mockData.value?.trackerUser; | 356 | trackerUser.value = mockData.value?.trackerUser; |
@@ -309,6 +364,13 @@ | @@ -309,6 +364,13 @@ | ||
309 | otherAmount.value = mockData.value.otherAmount?.toFixed(2); | 364 | otherAmount.value = mockData.value.otherAmount?.toFixed(2); |
310 | invoiceNo.value = mockData.value.invoiceNo; | 365 | invoiceNo.value = mockData.value.invoiceNo; |
311 | payee.value = mockData.value.payee; | 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 | async function handleTrue() { | 376 | async function handleTrue() { |
@@ -329,10 +391,6 @@ | @@ -329,10 +391,6 @@ | ||
329 | } | 391 | } |
330 | } | 392 | } |
331 | 393 | ||
332 | - const role = computed(() => { | ||
333 | - return userStore.getUserInfo?.roleSmallVO?.code; | ||
334 | - }); | ||
335 | - | ||
336 | // 定义MsgModalClose的事件,方便子组件调用 | 394 | // 定义MsgModalClose的事件,方便子组件调用 |
337 | const handleMsgModalClose = async (data) => { | 395 | const handleMsgModalClose = async (data) => { |
338 | if (data) { | 396 | if (data) { |
@@ -418,6 +476,8 @@ | @@ -418,6 +476,8 @@ | ||
418 | msgVisible, | 476 | msgVisible, |
419 | handleMsgModalClose, | 477 | handleMsgModalClose, |
420 | handlePreview, | 478 | handlePreview, |
479 | + showInvoice, | ||
480 | + openPic, | ||
421 | mockData, | 481 | mockData, |
422 | schema, | 482 | schema, |
423 | totalPayAmount, | 483 | totalPayAmount, |
src/views/project/approve/index.vue
@@ -16,9 +16,9 @@ | @@ -16,9 +16,9 @@ | ||
16 | v-if=" | 16 | v-if=" |
17 | role == ROLE.FINANCE || | 17 | role == ROLE.FINANCE || |
18 | role == ROLE.ADMIN | 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 | <ReceivePanel /> | 24 | <ReceivePanel /> |
@@ -60,9 +60,9 @@ | @@ -60,9 +60,9 @@ | ||
60 | v-if=" | 60 | v-if=" |
61 | role == ROLE.FINANCE || | 61 | role == ROLE.FINANCE || |
62 | role == ROLE.ADMIN | 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 | <ReceivePanel isApproved /> | 68 | <ReceivePanel isApproved /> |
src/views/project/finance/financeList/finance.data.tsx
@@ -38,8 +38,9 @@ export const searchFormSchema: FormSchema[] = [ | @@ -38,8 +38,9 @@ export const searchFormSchema: FormSchema[] = [ | ||
38 | componentProps: { | 38 | componentProps: { |
39 | options: [ | 39 | options: [ |
40 | { label: '未创建', value: -1 }, | 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,35 +52,13 @@ export const searchFormSchema: FormSchema[] = [ | ||
51 | componentProps: { | 52 | componentProps: { |
52 | options: [ | 53 | options: [ |
53 | { label: '未创建', value: -1 }, | 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 | field: 'customerCode', | 63 | field: 'customerCode', |
85 | label: '客户编码', | 64 | label: '客户编码', |
@@ -324,7 +303,7 @@ export const columns: BasicColumn[] = [ | @@ -324,7 +303,7 @@ export const columns: BasicColumn[] = [ | ||
324 | width: 80, | 303 | width: 80, |
325 | customRender: (column) => { | 304 | customRender: (column) => { |
326 | const deductUrl = column.record.invoiceDeductUrl; | 305 | const deductUrl = column.record.invoiceDeductUrl; |
327 | - if (deductUrl == undefined) { | 306 | + if (deductUrl == undefined || !deductUrl) { |
328 | return; | 307 | return; |
329 | } | 308 | } |
330 | // return <FilePptOutlined style="font-size:25px" onClick={() => window.open(deductUrl[0])} />; | 309 | // return <FilePptOutlined style="font-size:25px" onClick={() => window.open(deductUrl[0])} />; |
@@ -332,6 +311,20 @@ export const columns: BasicColumn[] = [ | @@ -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 | title: '实际应收金额$', | 328 | title: '实际应收金额$', |
336 | dataIndex: 'invoiceActualReceivableAmount', | 329 | dataIndex: 'invoiceActualReceivableAmount', |
337 | width: 120, | 330 | width: 120, |
@@ -381,32 +374,23 @@ export const columns: BasicColumn[] = [ | @@ -381,32 +374,23 @@ export const columns: BasicColumn[] = [ | ||
381 | dataIndex: 'invoiceStatus', | 374 | dataIndex: 'invoiceStatus', |
382 | width: 120, | 375 | width: 120, |
383 | customRender: (column) => { | 376 | customRender: (column) => { |
377 | + let statusText=''; | ||
378 | + let statusColor='blank'; | ||
384 | if (column.record.invoiceStatus == null || column.record.invoiceStatus == undefined) { | 379 | if (column.record.invoiceStatus == null || column.record.invoiceStatus == undefined) { |
385 | - return '未创建'; | 380 | + statusText='未创建'; |
386 | } else if (column.record.invoiceStatus == 0) { | 381 | } else if (column.record.invoiceStatus == 0) { |
387 | - return '未收款'; | 382 | + statusText= '未收款'; |
388 | } else if (column.record.invoiceStatus == 10) { | 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 | title: 'Action', | 395 | title: 'Action', |
412 | key: 'action', // 对应 #bodyCell 中的 column.key | 396 | key: 'action', // 对应 #bodyCell 中的 column.key |
@@ -460,13 +444,27 @@ export const columns: BasicColumn[] = [ | @@ -460,13 +444,27 @@ export const columns: BasicColumn[] = [ | ||
460 | width: 120, | 444 | width: 120, |
461 | customRender: (column) => { | 445 | customRender: (column) => { |
462 | const deductUrl = column.record.checkDeductUrl; | 446 | const deductUrl = column.record.checkDeductUrl; |
463 | - if (deductUrl == undefined) { | 447 | + if (deductUrl == undefined || !deductUrl) { |
464 | return; | 448 | return; |
465 | } | 449 | } |
466 | return <FilePptOutlined style="font-size:25px" />; | 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 | title: '生产科实际应付金额¥', | 468 | title: '生产科实际应付金额¥', |
471 | dataIndex: 'checkActualPayedAmount', | 469 | dataIndex: 'checkActualPayedAmount', |
472 | width: 180, | 470 | width: 180, |
@@ -534,32 +532,23 @@ export const columns: BasicColumn[] = [ | @@ -534,32 +532,23 @@ export const columns: BasicColumn[] = [ | ||
534 | dataIndex: 'checkPayStatus', | 532 | dataIndex: 'checkPayStatus', |
535 | width: 120, | 533 | width: 120, |
536 | customRender: (column) => { | 534 | customRender: (column) => { |
535 | + let statusText=''; | ||
536 | + let statusColor='blank'; | ||
537 | if (column.record.checkPayStatus == null || column.record.checkPayStatus == undefined) { | 537 | if (column.record.checkPayStatus == null || column.record.checkPayStatus == undefined) { |
538 | - return '未创建'; | 538 | + statusText='未创建'; |
539 | } else if (column.record.checkPayStatus == 0) { | 539 | } else if (column.record.checkPayStatus == 0) { |
540 | - return '未付款'; | 540 | + statusText='未付款'; |
541 | } else if (column.record.checkPayStatus == 10) { | 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 | title: 'Action', | 553 | title: 'Action', |
565 | key: 'action2', // 对应 #bodyCell 中的 column.key | 554 | key: 'action2', // 对应 #bodyCell 中的 column.key |
src/views/project/finance/financeList/index.vue
@@ -171,8 +171,9 @@ | @@ -171,8 +171,9 @@ | ||
171 | ...(role == ROLE.ADMIN | 171 | ...(role == ROLE.ADMIN |
172 | ? [ | 172 | ? [ |
173 | { | 173 | { |
174 | - label: '设置invoice最终完成', | 174 | + label: '设置为已收款', |
175 | onClick: handleInvoiceSetFinishStatus.bind(null, record), | 175 | onClick: handleInvoiceSetFinishStatus.bind(null, record), |
176 | + //需要设置按钮为红色。 | ||
176 | }, | 177 | }, |
177 | ] | 178 | ] |
178 | : []), | 179 | : []), |
@@ -261,7 +262,7 @@ | @@ -261,7 +262,7 @@ | ||
261 | ...(role == ROLE.ADMIN | 262 | ...(role == ROLE.ADMIN |
262 | ? [ | 263 | ? [ |
263 | { | 264 | { |
264 | - label: '设置对账单最终完成', | 265 | + label: '设置为已付款', |
265 | onClick: handleCheckSetFinishStatus.bind(null, record), | 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,6 +118,18 @@ | ||
118 | <!-- <a-space wrap :size="[8, 16]" :style="{ marginBottom: '2px', marginLeft: '10px' }"> --> | 118 | <!-- <a-space wrap :size="[8, 16]" :style="{ marginBottom: '2px', marginLeft: '10px' }"> --> |
119 | <a-space wrap :style="{ marginBottom: '2px', marginTop: '2px' }"> | 119 | <a-space wrap :style="{ marginBottom: '2px', marginTop: '2px' }"> |
120 | <a-button | 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 | :style="{ borderRadius: '5px 5px 5px 5px' }" | 133 | :style="{ borderRadius: '5px 5px 5px 5px' }" |
122 | type="primary" | 134 | type="primary" |
123 | @click="handleProductInvoiceModal" | 135 | @click="handleProductInvoiceModal" |
@@ -231,6 +243,11 @@ | @@ -231,6 +243,11 @@ | ||
231 | :role="role" | 243 | :role="role" |
232 | :customerCodes="selectedCustomCodes" | 244 | :customerCodes="selectedCustomCodes" |
233 | /> | 245 | /> |
246 | + <Statement | ||
247 | + @register="statementModalRegister" | ||
248 | + :role="role" | ||
249 | + :customerCodes="selectedCustomCodes" | ||
250 | + /> | ||
234 | <InvoiceCreate @register="invoiceCreateModalRegister" @success="handleFormSuccess" /> | 251 | <InvoiceCreate @register="invoiceCreateModalRegister" @success="handleFormSuccess" /> |
235 | <ServiceProfit @register="serviceProfitModalRegister" /> | 252 | <ServiceProfit @register="serviceProfitModalRegister" /> |
236 | <ProductProfit @register="productProfitModalRegister" /> | 253 | <ProductProfit @register="productProfitModalRegister" /> |
@@ -250,11 +267,12 @@ | @@ -250,11 +267,12 @@ | ||
250 | import { BasicTable, useTable, TableAction } from '/@/components/Table'; | 267 | import { BasicTable, useTable, TableAction } from '/@/components/Table'; |
251 | import { FormOutlined } from '@ant-design/icons-vue'; | 268 | import { FormOutlined } from '@ant-design/icons-vue'; |
252 | import HeaderCell from '/@/components/Table/src/components/HeaderCell.vue'; | 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 | import { useDrawer } from '/@/components/Drawer'; | 272 | import { useDrawer } from '/@/components/Drawer'; |
256 | import ProfitAnalysis from './ProfitAnalysis.vue'; | 273 | import ProfitAnalysis from './ProfitAnalysis.vue'; |
257 | import ProductText from './ProductText.vue'; | 274 | import ProductText from './ProductText.vue'; |
275 | + import Statement from './Statement.vue'; | ||
258 | import RateModal from './RateModal.vue'; | 276 | import RateModal from './RateModal.vue'; |
259 | import ExportModal from './ExportModal.vue'; | 277 | import ExportModal from './ExportModal.vue'; |
260 | import PassCalculate from './PassCalculate.vue'; | 278 | import PassCalculate from './PassCalculate.vue'; |
@@ -291,6 +309,7 @@ | @@ -291,6 +309,7 @@ | ||
291 | FormDetail, | 309 | FormDetail, |
292 | ProfitAnalysis, | 310 | ProfitAnalysis, |
293 | ProductText, | 311 | ProductText, |
312 | + Statement, | ||
294 | PassCalculate, | 313 | PassCalculate, |
295 | FormOutlined, | 314 | FormOutlined, |
296 | CheckDetail, | 315 | CheckDetail, |
@@ -316,6 +335,7 @@ | @@ -316,6 +335,7 @@ | ||
316 | const [exportModalRegister, { openModal: openExportModal }] = useModal(); | 335 | const [exportModalRegister, { openModal: openExportModal }] = useModal(); |
317 | const [productModalRegister, { openModal: openProductModal }] = useModal(); | 336 | const [productModalRegister, { openModal: openProductModal }] = useModal(); |
318 | const [passModalRegister, { openModal: openPassModal }] = useModal(); | 337 | const [passModalRegister, { openModal: openPassModal }] = useModal(); |
338 | + const [statementModalRegister, { openModal: openStatementModal }] = useModal(); | ||
319 | 339 | ||
320 | const tooltipVisible = ref(false); | 340 | const tooltipVisible = ref(false); |
321 | const [formDetailRegister, { openDrawer: openFormDetailDrawer }] = useDrawer(); | 341 | const [formDetailRegister, { openDrawer: openFormDetailDrawer }] = useDrawer(); |
@@ -761,6 +781,20 @@ | @@ -761,6 +781,20 @@ | ||
761 | data: values, | 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 | function handleRateModal() { | 799 | function handleRateModal() { |
766 | const form = getForm(); | 800 | const form = getForm(); |
@@ -871,6 +905,7 @@ | @@ -871,6 +905,7 @@ | ||
871 | rateModalRegister, | 905 | rateModalRegister, |
872 | exportModalRegister, | 906 | exportModalRegister, |
873 | productModalRegister, | 907 | productModalRegister, |
908 | + statementModalRegister, | ||
874 | passModalRegister, | 909 | passModalRegister, |
875 | historyDetailRegister, | 910 | historyDetailRegister, |
876 | trackHistoryRegister, | 911 | trackHistoryRegister, |
@@ -878,6 +913,7 @@ | @@ -878,6 +913,7 @@ | ||
878 | handleProfitModal, | 913 | handleProfitModal, |
879 | handleInvoiceCreateModal, | 914 | handleInvoiceCreateModal, |
880 | handleProductInvoiceModal, | 915 | handleProductInvoiceModal, |
916 | + handleStatementModal, | ||
881 | registerTable, | 917 | registerTable, |
882 | getFormValues, | 918 | getFormValues, |
883 | checkedKeys, | 919 | checkedKeys, |
@@ -905,6 +941,7 @@ | @@ -905,6 +941,7 @@ | ||
905 | handleRateModal, | 941 | handleRateModal, |
906 | openExportModal, | 942 | openExportModal, |
907 | openProductModal, | 943 | openProductModal, |
944 | + openStatementModal, | ||
908 | openPassModal, | 945 | openPassModal, |
909 | handleDelete, | 946 | handleDelete, |
910 | handleServiceProfitModal, | 947 | handleServiceProfitModal, |