feat:财税-报销单 添加支付操作逻辑

dev
yujinlong 2 weeks ago
parent 831d6ae746
commit 750cd388b5

@ -0,0 +1,76 @@
<template>
<BasicModal v-bind="$attrs" title="支付" width="500px" @register="registerModal">
<BasicForm @register="registerForm" />
<!--右下角按钮-->
<template #footer>
<a-button
pre-icon="ant-design:close-outlined"
type="warning"
:loading="loading"
ghost
style="margin-right: 0.8rem"
@click="closeModal"
>
取消
</a-button>
<a-button
type="success"
:loading="loading"
pre-icon="ant-design:check-outlined"
style="margin-right: 0.8rem"
@click="payNowHandle"
>
立即打款
</a-button>
</template>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { BasicModal, useModalInner } from '/@/components/Modal'
import { BasicForm, useForm } from '/@/components/Form/index'
import { useMessage } from '/@/hooks/web/useMessage'
import { modalFormSchema } from './columns'
import { BankPaymentApi } from './api'
const { createMessage } = useMessage()
const loading = ref(false)
const emit = defineEmits(['success'])
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
labelWidth: 100,
schemas: modalFormSchema,
showActionButtonGroup: false,
})
const reimbursementId = ref('')
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
resetFields()
reimbursementId.value = data.id
})
const payNowHandle = async () => {
try {
const values = await validate()
loading.value = true
setModalProps({ confirmLoading: true, loading: true })
const postData = {
...values,
reimbursementId: reimbursementId.value,
}
const res = await BankPaymentApi(postData)
loading.value = false
if (res.succeeded) {
createMessage.success(res.message)
emit('success')
}
closeModal()
} catch (err) {
console.log('err', err)
} finally {
setModalProps({ confirmLoading: false, loading: false })
}
}
</script>

@ -11,6 +11,7 @@ enum Api {
invoiceList = '/feeApi/InInvoicet/GetInInvoicet', invoiceList = '/feeApi/InInvoicet/GetInInvoicet',
bankList = '/mainApi/ClientBank/GetClientBankList', bankList = '/mainApi/ClientBank/GetClientBankList',
getUser = '/mainApi/User/GetUserInfo', getUser = '/mainApi/User/GetUserInfo',
BankPayment = '/feeApi/Reimbursement/BankPayment',
} }
// 获取报销单列表 (Auth) // 获取报销单列表 (Auth)
export function ReimbursementGetList(data: PageRequest) { export function ReimbursementGetList(data: PageRequest) {
@ -80,7 +81,7 @@ export function GetInvoiceList(data: PageRequest) {
return request<DataResult>({ return request<DataResult>({
url: Api.invoiceList, url: Api.invoiceList,
method: 'post', method: 'post',
data data,
}) })
} }
@ -89,7 +90,7 @@ export function GetClientBankList(data) {
return request<DataResult>({ return request<DataResult>({
url: Api.bankList, url: Api.bankList,
method: 'post', method: 'post',
data data,
}) })
} }
@ -98,6 +99,15 @@ export function GetUserInfo(query: { id: string }) {
return request<DataResult>({ return request<DataResult>({
url: Api.getUser, url: Api.getUser,
method: 'get', method: 'get',
params: query params: query,
})
}
// 支付
export function BankPaymentApi(data) {
return request<DataResult>({
url: Api.BankPayment,
method: 'post',
data,
}) })
} }

@ -1,3 +1,4 @@
import { getBankList } from '/@/api/system/org'
import { BasicColumn, FormSchema } from '/@/components/Table' import { BasicColumn, FormSchema } from '/@/components/Table'
import { numberThousandFormat } from '/@/utils/commonUtil' import { numberThousandFormat } from '/@/utils/commonUtil'
@ -114,4 +115,56 @@ export const searchFormSchema: FormSchema[] = [
colProps: { span: 4 }, colProps: { span: 4 },
component: 'Input', component: 'Input',
}, },
{
field: 'reimbursementType',
label: '状态',
colProps: { span: 4 },
component: 'Select',
componentProps: () => {
return {
options: statusList,
allowClear: true,
}
},
},
]
export const modalFormSchema: FormSchema[] = [
{
field: 'bankId',
label: '支付账户',
colProps: { span: 24 },
rules: [{ required: true }],
component: 'ApiSelect',
isEdit: 0,
componentProps: ({ formModel }) => {
return {
immediate: true,
api: () => {
return new Promise((resolve) => {
getBankList({
pageCondition: { pageIndex: 1, pageSize: 100, sortConditions: [] },
queryCondition:
'[{"FieldName":"paymentAccount","FieldValue":"1","ConditionalType":0}]',
}).then((res) => {
const dataResult = res?.data || []
resolve(dataResult)
})
})
},
labelField: 'bankName',
valueField: 'id',
getPopupContainer: () => document.body,
}
},
},
{
field: 'ledgerAccount',
label: '会计科目',
rules: [{ required: true }],
colProps: { span: 24 },
isEdit: 0,
component: 'Input',
},
] ]

@ -4,6 +4,7 @@ import { numberThousandFormat, digitUppercase } from '/@/utils/commonUtil'
import { BillItem } from '../columns' import { BillItem } from '../columns'
import { GetClientBankList } from '../api' import { GetClientBankList } from '../api'
import { h, nextTick } from 'vue' import { h, nextTick } from 'vue'
import { getDictDropDown } from '/@/api/common'
export type PageType = '' | 'ADD' | 'EDIT' | 'VIEW' | 'AUDIT' export type PageType = '' | 'ADD' | 'EDIT' | 'VIEW' | 'AUDIT'
@ -15,6 +16,15 @@ export interface BillDetail extends BillItem {
data: Recordable[] data: Recordable[]
} }
let feeTypeList: LabelValueOptions = []
const res2: API.DataResult = await getDictDropDown({ code: 'Reimbursement_Expense_Ategory' })
if (res2.succeeded) {
feeTypeList = []
res2.data.forEach((e) => {
feeTypeList.push({ label: e.name, value: e.value })
})
}
export const invoiceCodeList: LabelValueOptions = [ export const invoiceCodeList: LabelValueOptions = [
{ label: '全电发票(铁路电子客票)', value: '51' }, { label: '全电发票(铁路电子客票)', value: '51' },
{ label: '全电发票(航空运输电子客票行程单)', value: '61' }, { label: '全电发票(航空运输电子客票行程单)', value: '61' },
@ -153,6 +163,14 @@ export const getDetailForm = (type: PageType): FormSchema[] => {
colProps: { span: 4 }, colProps: { span: 4 },
show: false, show: false,
}, },
{
field: 'payeeName',
label: '收款人名称',
colProps: { span: 4 },
isEdit: 1,
dynamicDisabled: true,
component: 'Input',
},
{ {
field: 'bankName', field: 'bankName',
label: '开户行', label: '开户行',
@ -199,16 +217,34 @@ export const getDetailForm = (type: PageType): FormSchema[] => {
}, },
}, },
{ {
field: 'payeeName', field: 'payeeAccountNumber',
label: '收款人名称', label: '收款人账号',
colProps: { span: 4 }, colProps: { span: 4 },
isEdit: 1, isEdit: 1,
dynamicDisabled: true, dynamicDisabled: true,
component: 'Input', component: 'Input',
}, },
{ {
field: 'payeeAccountNumber', field: 'amount',
label: '收款人账号', label: '金额',
colProps: { span: 4 },
isEdit: 1,
dynamicDisabled: ['VIEW', 'AUDIT'].includes(type),
component: 'InputNumber',
componentProps: ({ formModel }) => {
return {
precision: 2,
onChange: (e) => {
nextTick(() => {
formModel.amountUppercase = digitUppercase(formModel?.amount || 0)
})
},
}
},
},
{
field: 'amountUppercase',
label: '金额大写',
colProps: { span: 4 }, colProps: { span: 4 },
isEdit: 1, isEdit: 1,
dynamicDisabled: true, dynamicDisabled: true,
@ -231,31 +267,24 @@ export const getDetailForm = (type: PageType): FormSchema[] => {
component: 'Input', component: 'Input',
}, },
{ {
field: 'amount', field: 'expenseCategory',
label: '金额', label: '费用类别',
colProps: { span: 4 }, colProps: { span: 4 },
isEdit: 1, rules: [{ required: true }],
dynamicDisabled: ['VIEW', 'AUDIT'].includes(type), dynamicDisabled: ['VIEW', 'AUDIT'].includes(type),
component: 'InputNumber', component: 'Select',
isEdit: 1,
componentProps: ({ formModel }) => { componentProps: ({ formModel }) => {
return { return {
precision: 2, allowClear: true,
onChange: (e) => { showSearch: true,
nextTick(() => { options: feeTypeList,
formModel.amountUppercase = digitUppercase(formModel?.amount || 0) getPopupContainer: () => document.body,
}) labelField: 'bankName',
}, valueField: 'bankName',
} }
}, },
}, },
{
field: 'amountUppercase',
label: '金额大写',
colProps: { span: 4 },
isEdit: 1,
dynamicDisabled: true,
component: 'Input',
},
{ {
show: ['VIEW', 'AUDIT'].includes(type), show: ['VIEW', 'AUDIT'].includes(type),
field: 'ledgerAccount', field: 'ledgerAccount',

@ -141,8 +141,14 @@ export const columns: BasicColumn[] = [
export const searchFormSchema: FormSchema[] = [ export const searchFormSchema: FormSchema[] = [
{ {
field: 'buyerInvoiceName', label: '销方开票名称',
label: '购方开票名称', field: 'sellerInvoiceName',
colProps: { span: 4 },
component: 'Input',
},
{
label: '销方开票税号',
field: 'sellerInvoiceTaxNumber',
colProps: { span: 4 }, colProps: { span: 4 },
component: 'Input', component: 'Input',
}, },
@ -156,14 +162,14 @@ export const searchFormSchema: FormSchema[] = [
}, },
}, },
{ {
field: 'invoiceNumber', field: 'totalAmount',
label: '发票号码', label: '开票金额',
colProps: { span: 4 }, colProps: { span: 4 },
component: 'Input', component: 'InputNumber',
}, },
{ {
field: 'buyerInvoiceTaxNumber', field: 'invoiceNumber',
label: '购方开票税号', label: '发票号码',
colProps: { span: 4 }, colProps: { span: 4 },
component: 'Input', component: 'Input',
}, },

@ -86,7 +86,7 @@
</a-spin> </a-spin>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed, unref } from 'vue' import { ref, computed, unref, h } from 'vue'
import { Divider } from 'ant-design-vue' import { Divider } from 'ant-design-vue'
import { BasicTable, useTable, TableAction, ActionItem } from '/@/components/Table' import { BasicTable, useTable, TableAction, ActionItem } from '/@/components/Table'
import SearchTable from './components/SearchTable.vue' import SearchTable from './components/SearchTable.vue'
@ -198,6 +198,12 @@
canResize: true, canResize: true,
resizeHeightOffset: 80, resizeHeightOffset: 80,
immediate: true, immediate: true,
actionColumn: {
width: 80,
title: '操作',
dataIndex: 'action',
fixed: 'right',
},
}) })
const copyHandle = (row) => { const copyHandle = (row) => {
@ -250,6 +256,7 @@
ledgerAccount: res.data.ledgerAccount, ledgerAccount: res.data.ledgerAccount,
voucherNo: res.data.voucherNo, voucherNo: res.data.voucherNo,
reason: res.data.reason, reason: res.data.reason,
expenseCategory: res.data.expenseCategory,
}) })
expenseAccountDetail.value = res.data expenseAccountDetail.value = res.data
billTableData.value = res.data?.data || [] billTableData.value = res.data?.data || []
@ -270,12 +277,11 @@
const getActionOptList = (record): ActionItem[] => { const getActionOptList = (record): ActionItem[] => {
return [ return [
{ {
/* icon: h('i', { customIcon: h('i', {
class: 'iconfont icon-xiazai', class: 'iconfont icon-xiazai',
style: { color: '#257afa', fontSize: '14px' }, style: { color: '#257afa', fontSize: '14px' },
}), }),
isCustomIcon: true, */ isCustomIcon: true,
icon: 'ant-design:cloud-download-outlined',
tooltip: '下载', tooltip: '下载',
onClick: handleDownload.bind(null, record), onClick: handleDownload.bind(null, record),
}, },
@ -288,6 +294,7 @@
if (!filePath) { if (!filePath) {
return createMessage.warning('暂未获取到相关文件') return createMessage.warning('暂未获取到相关文件')
} }
window.open(filePath, '_blank') window.open(filePath, '_blank')
} }
@ -488,6 +495,11 @@
.fill-form-wrapper { .fill-form-wrapper {
margin-top: 14px; margin-top: 14px;
} }
:deep(.ds-table) {
.table-wrapper {
padding: 0;
}
}
.table-title-box { .table-title-box {
.flex_arrange(row, flex-start); .flex_arrange(row, flex-start);
padding: 16px 0 6px 0; padding: 16px 0 6px 0;

@ -53,11 +53,12 @@
</template> </template>
</template> </template>
</BasicTable> </BasicTable>
<PayModal @register="registerModal" @success="handleSuccess" />
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { unref, h } from 'vue' import { unref, h, computed, ref } from 'vue'
import { ReimbursementGetList, ReimbursementDelete } from './api.js' import { ReimbursementGetList, ReimbursementDelete, GetUserInfo } from './api.js'
import { BasicTable, useTable, TableAction, ActionItem } from '/@/components/Table' import { BasicTable, useTable, TableAction, ActionItem } from '/@/components/Table'
import { formatParams } from '/@/hooks/web/common' import { formatParams } from '/@/hooks/web/common'
import { BillItem, columns, searchFormSchema, statusList } from './columns' import { BillItem, columns, searchFormSchema, statusList } from './columns'
@ -66,7 +67,14 @@
import { useGo } from '/@/hooks/web/usePage' import { useGo } from '/@/hooks/web/usePage'
import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard' import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard'
import { useAppStore } from '/@/store/modules/app' import { useAppStore } from '/@/store/modules/app'
import { useUserStore } from '/@/store/modules/user'
import { useModal } from '/@/components/Modal'
import PayModal from './PayModal.vue'
const [registerModal, { openModal }] = useModal()
const appStore = useAppStore() const appStore = useAppStore()
const userStore = useUserStore()
const go = useGo() const go = useGo()
const [registerTable, { reload, setLoading, getSelectRows }] = useTable({ const [registerTable, { reload, setLoading, getSelectRows }] = useTable({
@ -119,9 +127,22 @@
return (item?.[key] as string) || '' return (item?.[key] as string) || ''
} }
const userInfo = computed(() => userStore.getUserInfo)
const userInfoDetail = ref<any>({})
const getUserInfo = async () => {
try {
const userRes = await GetUserInfo({ id: userInfo.value.userId as string })
userInfoDetail.value = userRes.data
} catch (error) {}
}
getUserInfo()
const getActionOptList = (record: BillItem): ActionItem[] => { const getActionOptList = (record: BillItem): ActionItem[] => {
const canEditable = [0, 4].includes(record.reimbursementType) const canEditable = [0, 4].includes(record.reimbursementType)
return [ const canPayable = userInfoDetail.value.isFinancialStaff && record.reimbursementType === 2
const optList = [
{ {
customIcon: h('i', { customIcon: h('i', {
class: 'iconfont icon-chakan', class: 'iconfont icon-chakan',
@ -133,6 +154,20 @@
onClick: GoDetailed.bind(null, record), onClick: GoDetailed.bind(null, record),
}, },
] ]
return canPayable
? [
...optList,
{
customIcon: h('i', {
class: 'iconfont icon-peizhitubiaosvg-',
style: { color: '#257afa', fontSize: '16px' },
}),
isCustomIcon: true,
tooltip: '支付',
onClick: ToPayHandle.bind(null, record),
},
]
: optList
} }
function FnDel() { function FnDel() {
if (getSelectRows().length == 0) { if (getSelectRows().length == 0) {
@ -184,6 +219,13 @@
}, },
}) })
} }
const ToPayHandle = (row: BillItem) => {
openModal(true, row)
}
const handleSuccess = () => {
reload()
}
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.SvgImg { .SvgImg {

Loading…
Cancel
Save