发票开出

szh-new
sunzehua 2 months ago
parent d0db0838cd
commit 8796baeec1

@ -197,13 +197,14 @@ const [registerTable2, { getSelectRows: getSelectRows2, clearSelectedRowKeys: cl
//
param.forEach(row => {
if (!isNaN(row[column.dataIndex])) {
console.log(row[column.dataIndex])
sums[column.dataIndex] += Number(row[column.dataIndex])
}
})
}
})
sums.taxAmount = (Number(sums.taxAmount)).toFixed(2)
sums.amount = (Number(sums.taxAmount)).toFixed(2)
sums.amount = (Number(sums.amount)).toFixed(2)
sums.name = '合计'
//
return [sums]
@ -313,7 +314,7 @@ function applySuccess() {
}
Audit(data).then(res => {
if (res.succeeded) {
createMessage.error('操作成功')
createMessage.success('操作成功')
reload()
}
})
@ -344,8 +345,9 @@ function sureRefuse() {
}
Audit(data).then(res => {
if (res.succeeded) {
createMessage.error('操作成功')
createMessage.success('操作成功')
reload()
refuseFlag.value = false
}
})
}

@ -31,17 +31,21 @@
<template #title>
<span>提交审核</span>
</template>
<span class="ds-action-svg-btn" @click="handleApply">
<img src="../../../../assets/svg/infoclient/tijiao.svg" class="SvgImg" />
</span>
<a-popconfirm title="确认提交审核吗?" ok-text="" cancel-text="" @confirm="handleApply">
<span class="ds-action-svg-btn" >
<img src="../../../../assets/svg/infoclient/tijiao.svg" class="SvgImg" />
</span>
</a-popconfirm>
</a-tooltip>
<a-tooltip placement="top" :mouseEnterDelay="0.5">
<template #title>
<span>撤销审核</span>
</template>
<span class="ds-action-svg-btn" @click="handleWithdraw">
<img src="../../../../assets/svg/infoclient/chexiaotijiao.svg" class="SvgImg" />
</span>
<a-popconfirm title="确认撤销审核吗?" ok-text="" cancel-text="" @confirm="handleWithdraw">
<span class="ds-action-svg-btn" >
<img src="../../../../assets/svg/infoclient/chexiaotijiao.svg" class="SvgImg" />
</span>
</a-popconfirm>
</a-tooltip>
<a-dropdown>
<a class="ant-dropdown-link">
@ -554,7 +558,7 @@ const bottomForm = [
api: () => {
return new Promise((resolve) => {
GetOrgList().then((res) => {
res.data.forEach(item=>{
res.data.forEach(item => {
item.id = item.value
})
resolve(res)
@ -878,6 +882,7 @@ function handleAddLabel(val) {
const details = ref([])
//
function getDetail() {
loading.value = true
InvoiceApplicationGet({ id: id.value }).then((res) => {
if (res.succeeded) {
setFieldsValue(res.data)
@ -911,6 +916,9 @@ function getDetail() {
}
feeTableRef.value.init(res.data)
}
loading.value = false
}).catch(() => {
loading.value = false
})
}
function openTempName() {

@ -37,7 +37,7 @@
<span class="iconfont icon-liebiao IconColor"></span>
显示工作流
</a-button>
<a-button v-repeat type="link">
<a-button @click="ExportExcel" v-repeat type="link">
<span class="iconfont icon-a-17Btuichu IconColor"></span>
导出EXCEL
</a-button>
@ -63,6 +63,10 @@
},
]" />
</template>
<template v-if="column.key === 'currency'">
<span v-if="!record.currency" >原币申请</span>
<span v-else>{{ record.currency }}</span>
</template>
</template>
</BasicTable>
</div>
@ -158,6 +162,7 @@ function FnDel() {
}
})
}
function handleApply() {
let ids = []
ids = getSelectRows().map((item) => {
@ -195,24 +200,15 @@ function handleWithdraw() {
// EXCEL
function ExportExcel() {
let Data: any = []
let DelData = ['id', 'bsno', 'ctnCode']
let DelData = ['id']
console.log(getRawDataSource())
getRawDataSource().forEach((item, index) => {
let Obj = {}
Object.keys(item).forEach((item2) => {
if (!DelData.includes(item2)) {
columns.forEach((e) => {
if (e.dataIndex == item2) {
if (e.title == '收付类型') {
let data = ''
billTypeData.forEach((d) => {
if (d.code == item[item2]) {
data = d.value
}
})
Obj[e.title] = data
} else {
Obj[e.title] = item[item2]
}
Obj[e.title] = item[item2]
}
})
}
@ -234,7 +230,7 @@ function ExportExcel() {
// a
const a = document.createElement('a')
a.href = url
a.download = '客户对账.xlsx'
a.download = '发票申请.xlsx'
document.body.appendChild(a)
a.click()

@ -32,3 +32,140 @@ export function GetInvoiceCodeList() {
})
}
export function GetUserListAll(parameter) {
return request({
url: '/mainApi/Common/GetUserList',
method: 'get',
params: parameter
})
}
export function GeneralInvoiceGetList(parameter) {
return request({
url: '/feeApi/GeneralInvoice/GetList',
method: 'post',
data: parameter
})
}
export function GetApplicationList(parameter) {
return request({
url: '/feeApi/GeneralInvoice/GetApplicationList',
method: 'post',
data: parameter
})
}
export function GetApplicationDetails(parameter) {
return request({
url: '/feeApi/GeneralInvoice/GetApplicationDetails',
method: 'post',
data: parameter
})
}
export function GeneralInvoiceSave(parameter) {
return request({
url: '/feeApi/GeneralInvoice/Save',
method: 'post',
data: parameter
})
}
export function GetExchangeRate(params) {
return request({
url: '/feeApi/FeeCurrencyExchange/GetExchangeRate',
method: 'get',
params
})
}
export function GeneralInvoiceGet(params) {
return request({
url: '/feeApi/GeneralInvoice/Get',
method: 'get',
params
})
}
export function GetOpFileList(parameter) {
return request({
url: '/mainApi/OpFile/GetOpFileList',
method: 'get',
params:parameter
})
}
export function BatchDelFiles(parameter) {
return request({
url: '/mainApi/OpFile/BatchDelFiles',
method: 'post',
data: parameter,
})
}
export function DownloadOpFile(params) {
return request({
url: '/mainApi/OpFile/DownloadOpFileInfo',
responseType: 'blob',
method: 'get',
params
})
}
export function GeneralInvoiceInitiate(parameter) {
return request({
url: '/feeApi/GeneralInvoice/Initiate',
method: 'post',
data: parameter,
})
}
export function GeneralInvoiceSetLock(parameter) {
return request({
url: '/feeApi/GeneralInvoice/SetLock',
method: 'post',
data: parameter,
})
}
export function GeneralInvoiceDelete(parameter) {
return request({
url: '/feeApi/GeneralInvoice/Delete',
method: 'post',
data: parameter,
})
}
export function DeleteInvoiceDetail(parameter) {
return request({
url: '/feeApi/GeneralInvoice/DeleteInvoiceDetail',
method: 'post',
data: parameter,
})
}
export function FreeInvoiceGetBizList(parameter) {
return request({
url: '/feeApi/FreeInvoice/GetBizList',
method: 'post',
data: parameter,
})
}
export function GetOrgList() {
return request({
url: '/mainApi/Common/GetOrgList',
method: 'get',
})
}
export function FreeInvoiceGetFees(parameter) {
return request({
url: '/feeApi/FreeInvoice/GetFees',
method: 'post',
data: parameter,
})
}

@ -1,11 +1,32 @@
import { ref } from 'vue'
import { BasicColumn, FormSchema } from '/@/components/Table'
import { GetFeeCurrencySelectList,GetFeeCodeSelectList,GetClientListByCode } from '/@/api/common'
import { getOptions } from '/@/hooks/dict'
import {
GetControllerClientList,
GetCustomerServiceList,
} from '/@/views/operation/seaexport/api/BookingLedger'
import { GetOrgList } from './api'
export const billTypeData = [
{ value: '', label: '全部' },
{ value: 1, label: '待审核' },
{ value: 2, label: '已审核' },
]
export const businessTypeList = [
{ value: 1, label: '海运出口' },
]
const FeeRangeList = [
{ value: 0, label: '全部费用' },
{ value: 1, label: '未结费用' },
{ value: 2, label: '已结费用' },
{ value: 3, label: '已付未收' },
{ value: 4, label: '已收未付' },
{ value: 5, label: '未申请未结算' },
{ value: 6, label: '未对账未结算' },
{ value: 7, label: '未开票未结算' },
{ value: 8, label: '已对账未结算' },
{ value: 9, label: '未收未付' },
]
export const searchFormSchema: FormSchema[] = [
{
field: 'applicationNO',
@ -42,229 +63,211 @@ export const searchFormSchema: FormSchema[] = [
export const columns: BasicColumn[] = [
{
title: '发票类别',
dataIndex: 'applicationNO',
dataIndex: 'modeText',
width: 120,
align: 'left',
},
{
title: '发票锁定',
dataIndex: 'statusText',
dataIndex: 'isLocked',
width: 70,
align: 'left',
},
{
title: '发票业务编号',
dataIndex: 'customerName',
dataIndex: 'billNO',
width: 100,
align: 'left',
},
{
title: '发票号',
dataIndex: 'invoiceHeader',
dataIndex: 'invoiceNO',
width: 100,
align: 'left',
},
{
title: '开票单位',
dataIndex: 'currency',
dataIndex: 'customerName',
width: 100,
align: 'left',
},
{
title: '发票抬头',
dataIndex: 'categoryText',
dataIndex: 'invoiceHeader',
width: 100,
align: 'left',
},
{
title: '币别',
dataIndex: 'originalAmount',
dataIndex: 'currency',
width: 100,
align: 'left',
},
{
title: '开票金额',
dataIndex: 'createByName',
dataIndex: 'invoiceAmount',
width: 100,
align: 'left',
},
{
title: '申请金额',
dataIndex: 'applyDate',
dataIndex: 'applyAmount',
width: 100,
align: 'left',
},
{
title: '是否打印',
dataIndex: 'categoryText',
dataIndex: 'isPrinted',
width: 100,
align: 'left',
},
{
title: '结算',
dataIndex: 'createTime',
title: '是否结算',
dataIndex: 'isSettled',
width: 100,
align: 'left',
},
{
title: '实收币别',
dataIndex: 'taxRate',
dataIndex: 'receiptCurrency',
width: 100,
align: 'left',
},
{
title: '原币金额',
dataIndex: 'invoiceNO',
dataIndex: 'originalAmountText',
width: 100,
align: 'left',
},
{
title: '开票日期',
dataIndex: 'invoiceNO',
dataIndex: 'invoiceDate',
width: 100,
align: 'left',
},
{
title: '开票人',
dataIndex: 'invoiceNO',
dataIndex: 'operatorName',
width: 100,
align: 'left',
},
{
title: '申请人',
dataIndex: 'invoiceNO',
dataIndex: 'createByName',
width: 100,
align: 'left',
},
{
title: '锁定人',
dataIndex: 'invoiceNO',
dataIndex: 'lockUserName',
width: 100,
align: 'left',
},
{
title: '锁定时间',
dataIndex: 'invoiceNO',
dataIndex: 'lockTime',
width: 100,
align: 'left',
},
{
title: '所属分部',
dataIndex: 'invoiceNO',
dataIndex: 'saleDeptName',
width: 100,
align: 'left',
},
{
title: '备注',
dataIndex: 'invoiceNO',
width: 100,
align: 'left',
},
{
title: '是否作废',
dataIndex: 'invoiceNO',
dataIndex: 'note',
width: 100,
align: 'left',
},
{
title: '电子发票',
dataIndex: 'invoiceNO',
width: 100,
align: 'left',
},
{
title: '作废人',
dataIndex: 'invoiceNO',
width: 100,
align: 'left',
},
{
title: '作废时间',
dataIndex: 'invoiceNO',
dataIndex: 'pdfUrl',
width: 100,
align: 'left',
},
{
title: '购方电话',
dataIndex: 'invoiceNO',
dataIndex: 'cellPhoneNO1',
width: 100,
align: 'left',
},
{
title: '购方地址',
dataIndex: 'invoiceNO',
dataIndex: 'customerAddressTel1',
width: 100,
align: 'left',
},
{
title: '对应蓝票代码',
dataIndex: 'invoiceNO',
dataIndex: 'invoiceNO1',
width: 100,
align: 'left',
},
{
title: '对应蓝票号码',
dataIndex: 'invoiceNO',
dataIndex: 'invoiceNO2',
width: 100,
align: 'left',
},
{
title: '通知手机',
dataIndex: 'invoiceNO',
dataIndex: 'cellPhoneNO',
width: 100,
align: 'left',
},
{
title: '通知邮箱',
dataIndex: 'invoiceNO',
dataIndex: 'email',
width: 100,
align: 'left',
},
{
title: '发票详情',
dataIndex: 'invoiceNO',
dataIndex: 'invoiceDetails',
width: 100,
align: 'left',
},
{
title: '发票PDF',
dataIndex: 'invoiceNO',
dataIndex: 'pdfUrl',
width: 100,
align: 'left',
},
{
title: '开票类型',
dataIndex: 'invoiceNO',
dataIndex: 'invoiceNO1',
width: 100,
align: 'left',
},
{
title: '被冲红',
dataIndex: 'invoiceNO',
dataIndex: 'isSetRed',
width: 100,
align: 'left',
},
{
title: '通知推送方式',
dataIndex: 'invoiceNO',
dataIndex: 'pushMode',
width: 100,
align: 'left',
},
{
title: '发票种类',
dataIndex: 'invoiceNO',
dataIndex: 'category',
width: 100,
align: 'left',
},
{
title: '开票状态',
dataIndex: 'invoiceNO',
dataIndex: 'status',
width: 100,
align: 'left',
},
{
title: '录入人',
dataIndex: 'invoiceNO',
dataIndex: 'createByName',
width: 100,
align: 'left',
},
@ -404,4 +407,633 @@ export const feeColumnsSum: BasicColumn[] = [
dataIndex: 'amount',
width: 100,
},
]
]
export const detailColumnsRight: BasicColumn[] = [
{
title: '申请单号',
dataIndex: 'name',
width: 80,
align: 'left',
},
{
title: '状态',
dataIndex: 'specification',
width: 70,
align: 'left',
},
{
title: '币别',
dataIndex: 'unit',
width: 50,
align: 'left',
},
{
title: '申请金额',
dataIndex: 'quantity',
width: 80,
align: 'left',
},
{
title: '开票要求',
dataIndex: 'taxUnitPrice',
width: 80,
align: 'left',
},
{
title: '申请人',
dataIndex: 'unitPrice',
width: 80,
align: 'left',
},
]
export const applyColums: BasicColumn[] = [
{
title: '申请单号',
dataIndex: 'applicationNO',
width: 100,
},
{
title: '发票抬头',
dataIndex: 'invoiceHeader',
width: 100,
},
{
title: '币别',
dataIndex: 'currency',
width: 100,
},
{
title: '备注',
dataIndex: 'note',
width: 100,
},
{
title: '申请金额',
dataIndex: 'applyAmount',
width: 100,
},
{
title: '开票金额',
dataIndex: 'invoiceAmount',
width: 100,
},
{
title: '原币金额',
dataIndex: 'originalAmount',
width: 100,
},
{
title: '申请类型',
dataIndex: 'feeType',
width: 100,
},
{
title: '申请日期',
dataIndex: 'createTime',
width: 100,
},
{
title: '申请人',
dataIndex: 'createByName',
width: 100,
},
{
title: '通知推送类型',
dataIndex: 'pushModeText',
width: 100,
},
{
title: '推送手机',
dataIndex: 'cellPhoneNO',
width: 100,
},
{
title: '推送邮箱',
dataIndex: 'email',
width: 100,
},
{
title: '所属部门',
dataIndex: 'orgName',
width: 100,
},
{
title: '所属分部',
dataIndex: 'saleDeptName',
width: 100,
},
]
export const applySearch: FormSchema[] = [
{
field: 'applicationNO',
label: '申请编号',
component: 'Input',
colProps: { span: 4 },
},
{
field: 'applicationNO',
label: '编号',
component: 'Input',
colProps: { span: 4 },
},
{
label: '开票单位',
field: 'customerId',
required: false,
component: 'ApiSelect',
dynamicDisabled: false,
colProps: { span: 4 },
componentProps: () => {
return {
api: () => {
return new Promise((resolve) => {
GetControllerClientList().then((res) => {
resolve(res)
})
})
},
immediate: false,
labelField: 'shortName',
valueField: 'id',
resultField: 'data',
filterOption: (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
},
}
},
},
{
field: 'createTime',
label: '申请日期',
component: 'RangePicker',
required: false,
dynamicDisabled: false,
colProps: { span: 6 },
componentProps: {
allowClear: true,
},
},
{
label: '申请人',
component: 'Input',
field: 'feeType',
colProps: { span: 4 },
width: 100,
},
{
label: '申请类型',
component: 'Input',
colProps: { span: 4 },
field: 'feeType',
width: 100,
},
]
export const applyColumsDetail: BasicColumn[] = [
{
title: '委托编号',
dataIndex: 'customerNo',
width: 100,
},
{
title: '主提单号',
dataIndex: 'mblno',
width: 100,
},
{
title: '分提单号',
dataIndex: 'hblno',
width: 100,
},
{
title: '委托单位',
dataIndex: 'clientName',
width: 100,
},
{
title: '开船日期',
dataIndex: 'etd',
width: 100,
},
{
title: '业务来源',
dataIndex: 'sourceName',
width: 100,
},
{
title: '费用名称',
dataIndex: 'feeName',
width: 100,
},
{
title: '收付',
dataIndex: 'feeType',
width: 100,
},
{
title: '申请金额',
dataIndex: 'orderAmount',
width: 100,
},
{
title: '原始币别',
dataIndex: 'originalCurrency',
width: 100,
},
{
title: '原始金额',
dataIndex: 'originalAmount',
width: 100,
},
{
title: '折算汇率',
dataIndex: 'exchangeRate',
width: 100,
},
{
title: '审核日期',
dataIndex: 'auditTime',
width: 100,
},
{
title: '揽货人',
dataIndex: 'saleName',
width: 100,
},
{
title: '所属分部',
dataIndex: 'saleDeptName',
width: 100,
},
]
export const feeColumnsDetail: BasicColumn[] = [
{
title: '委托编号',
dataIndex: 'customerNo',
width: 100,
},
{
title: '主提单号',
dataIndex: 'mblno',
width: 100,
},
{
title: '订舱编号',
dataIndex: 'bookingNo',
width: 100,
},
{
title: '委托单位',
dataIndex: 'customerName',
width: 100,
},
{
title: '开船日期',
dataIndex: 'etd',
width: 150,
},
{
title: '业务来源',
dataIndex: 'sourceName',
width: 80,
},
{
title: '费用名称',
dataIndex: 'feeName',
width: 80,
},
{
title: '收付',
dataIndex: 'feeType',
width: 50,
},
{
title: '申请金额',
dataIndex: 'orderAmount',
width: 80,
},
{
title: '原始币别',
dataIndex: 'originalCurrency',
width: 80,
},
{
title: '原始汇率',
dataIndex: 'originalRate',
width: 80,
},
{
title: '折算汇率',
dataIndex: 'exchangeRate',
width: 80,
},
{
title: '原始金额',
dataIndex: 'originalAmount',
width: 80,
},
{
title: '揽货人',
dataIndex: 'saleName',
width: 80,
},
{
title: '船名航次',
dataIndex: 'vessel',
width: 80,
},
{
title: '装货港',
dataIndex: 'saleName',
width: 80,
},
{
title: '卸货港',
dataIndex: 'saleName',
width: 80,
},
]
export const freeColums: BasicColumn[] = [
{
title: '委托编号',
dataIndex: 'customerNo',
width: 100,
align: 'left',
},
{
title: '主提单号',
dataIndex: 'mblno',
width: 100,
align: 'left',
},
{
title: '结费单位',
dataIndex: 'customerName',
width: 100,
align: 'left',
},
{
title: 'RMB未开',
dataIndex: 'unBilledRMB',
width: 80,
align: 'left',
},
{
title: 'USD未开',
dataIndex: 'unBilledUSD',
width: 80,
align: 'left',
},
{
title: '其他未开',
dataIndex: 'unBilledOther',
width: 80,
align: 'left',
},
{
title: '业务类别',
dataIndex: 'businessType',
width: 80,
align: 'left',
},
{
title: '分提单号',
dataIndex: 'hblno',
width: 80,
align: 'left',
},
{
title: '委托单位',
dataIndex: 'clientName',
width: 100,
align: 'left',
},
{
title: '开船日期',
dataIndex: 'etd',
width: 100,
align: 'left',
},
{
title: '揽货人',
dataIndex: 'saleName',
width: 80,
align: 'left',
},
{
title: '会计期间',
dataIndex: 'accountDate',
width: 80,
align: 'left',
},
{
title: '操作',
dataIndex: 'operator',
width: 80,
align: 'left',
},
{
title: '录入人',
dataIndex: 'createByName',
width: 80,
align: 'left',
},
{
title: '起运港',
dataIndex: 'loadPort',
width: 80,
align: 'left',
},
{
title: '目的港',
dataIndex: 'dischargePort',
width: 80,
align: 'left',
},
{
title: '船名',
dataIndex: 'vessel',
width: 80,
align: 'left',
},
{
title: '航次',
dataIndex: 'voyage',
width: 80,
align: 'left',
},
{
title: '备注',
dataIndex: 'note',
width: 80,
align: 'left',
},
]
export const freeSearch: FormSchema[] = [
{
label: '费用对象',
field: 'customerId',
component: 'ApiSelect',
required: false,
dynamicDisabled: false,
colProps: { span: 4 },
componentProps: ({ formModel }) => {
return {
allowClear: true,
showSearch: true,
api: () => {
return new Promise((resolve) => {
const arr = getOptions('controller')
resolve(arr)
})
},
labelField: 'name',
valueField: 'id',
showName: 'shortName',
resultField: 'data',
filterOption: (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
},
onChange: (e, obj) => {
},
}
},
},
{
field: 'businessType',
label: '业务类别',
component: 'Select',
colProps: { span: 4 },
componentProps: {
options: businessTypeList,
},
},
{
field: 'etd',
label: '业务日期',
component: 'RangePicker',
required: false,
dynamicDisabled: false,
colProps: { span: 4 },
componentProps: {
allowClear: true,
},
},
{
field: 'debitNo',
label: '编号检索',
component: 'Input',
show: true,
colProps: { span: 4 },
},
{
field: 'feeType',
label: '收付',
component: 'Select',
colProps: { span: 4 },
componentProps: {
options: [
{
label: '收',
value: '1',
},
{
label: '付',
value: '2',
}
],
},
},
{
field: 'currency',
label: '币别',
component: 'ApiSelect',
colProps: { span: 4 },
componentProps: () => {
return {
api: GetFeeCurrencySelectList,
labelField: 'name',
valueField: 'codeName',
resultField: 'data',
}
},
},
{
field: 'feeName',
label: '费用名称',
component: 'ApiSelect',
colProps: { span: 4 },
componentProps: () => {
return {
api: GetFeeCodeSelectList,
labelField: 'name',
valueField: 'code',
resultField: 'data',
}
},
},
{
field: 'accountDate',
label: '会计期间',
component: 'RangePicker',
required: false,
dynamicDisabled: false,
colProps: { span: 4 },
componentProps: {
allowClear: true,
},
},
{
field: 'FeeRange',
label: '费用范围',
component: 'Select',
colProps: { span: 4 },
componentProps: {
options: FeeRangeList,
},
},
{
field: 'saleDeptId',
label: '所属分部',
defaultValue: '',
component: 'ApiSelect',
colProps: { span: 4 },
componentProps: () => {
return {
api: GetOrgList,
resultField: 'data',
}
},
},
{
label: '操作',
field: 'operator',
component: 'ApiSelect',
required: false,
dynamicDisabled: false,
colProps: { span: 4 },
componentProps: ({ formModel }) => {
return {
api: GetCustomerServiceList,
labelField: 'pinYinCode',
valueField: 'userName',
showName: 'userName',
allowClear: true,
showSearch: true,
immediate: false,
resultField: 'data',
onChange: (e, obj) => {
}
}
},
},
]

@ -0,0 +1,473 @@
<template>
<div>
<a-modal width="1600px" @cancel="open = false" :visible="open" title="添加发票申请明细" :footer="null">
<div style="padding-bottom:5px ;">
<div>
<BasicTable class="ds-table" @row-click="handleClick" @register="registerTable" >
<template #right>
<div style="width: 40%;margin-left: 10px;margin-top:10px;">
<div>
<BasicTable class="ds-table" @register="registerTable1">
<template #tableTitle>
<div>
<span class="bold">发票申请明细</span>
</div>
</template>
<template v-slot:bodyCell="{ column, record }">
<template v-if="column.dataIndex == 'applyAmount'">
<a-input-number @change="onSelectAmount" :precision="2" size="small"
:controls="false" :max="record.restAmount"
v-model:value="record.applyAmount" />
</template>
<template v-if="column.dataIndex == 'feeType'">
<span v-if="record.feeType == 1"></span>
<span v-if="record.feeType == 2"></span>
</template>
</template>
</BasicTable>
</div>
</div>
</template>
<template #tableTitle>
<div>
<div>
<span class="bold">发票申请</span>
<a-button v-repeat type="link" @click="addDetailed()">
<span class="iconfont icon-jia"></span>
添加申请明细
</a-button>
</div>
</div>
</template>
<template v-slot:bodyCell="{ column, record }">
<template v-if="column.dataIndex == 'businessType'">
<span v-if="record.businessType == 1"></span>
</template>
</template>
</BasicTable>
</div>
</div>
</a-modal>
<a-modal width="400px" @cancel="exchangeFlag = false" @ok="handleSureExhange" :visible="exchangeFlag"
title="币别汇率折算">
<div v-for="(item, index) in exchangarr" :key="index">
<div style="margin-bottom: 15px;margin-top: 10px">
<span class="bold" style="margin-right: 10px;width:46px;display: inline-block">1{{ item.currencyTo
}}
=</span>
<a-input-number addon-after="RMB" :precision="4" size="small" :controls="false"
v-model:value="item.reverseRate" />
</div>
</div>
</a-modal>
<a-modal width="1600px" @cancel="freeFlag = false" :visible="freeFlag" title="添加发票申请明细" :footer="null">
<div style="padding-bottom:5px ;">
<div>
<BasicTable class="ds-table" @row-click="handleClickFree" @register="registerTableFree">
<template #right>
<div style="width: 40%;margin-left: 10px;margin-top:10px;">
<div>
<BasicTable class="ds-table" @register="registerTable1">
<template #tableTitle>
<div>
<span class="bold">发票申请明细</span>
</div>
</template>
<template v-slot:bodyCell="{ column, record }">
<template v-if="column.dataIndex == 'applyAmount'">
<a-input-number @change="onSelectAmount" :precision="2" size="small"
:controls="false" :max="record.restAmount"
v-model:value="record.applyAmount" />
</template>
<template v-if="column.dataIndex == 'feeType'">
<span v-if="record.feeType == 1"></span>
<span v-if="record.feeType == 2"></span>
</template>
</template>
</BasicTable>
</div>
</div>
</template>
<template #tableTitle>
<div>
<div>
<span class="bold">发票申请</span>
<a-button v-repeat type="link" @click="addDetailed()">
<span class="iconfont icon-jia"></span>
添加申请明细
</a-button>
</div>
</div>
</template>
<template v-slot:bodyCell="{ column, record }">
<template v-if="column.dataIndex == 'businessType'">
<span v-if="record.businessType == 1"></span>
</template>
</template>
</BasicTable>
</div>
</div>
</a-modal>
</div>
</template>
<script lang="ts" setup>
import { formatParams } from '/@/hooks/web/common'
import { ref, defineExpose, watch } from 'vue'
import { BasicTable, useTable, TableAction } from '/@/components/Table'
import { applyColums, applySearch, applyColumsDetail,freeSearch,freeColums } from '../columns'
import { GetApplicationList, GetApplicationDetails, GetExchangeRate,FreeInvoiceGetBizList,FreeInvoiceGetFees } from '../api.js'
import { useMessage } from '/@/hooks/web/useMessage'
const { createMessage } = useMessage()
import { useRoute } from 'vue-router'
const route = useRoute()
const open = ref(false)
const dataSource = ref([]) as any
const [registerTable, { getForm, setSelectedRowKeys, getSelectRows, setProps, getRawDataSource, setLoading }] = useTable({
api: async (p) => {
const res: API.DataResult = await GetApplicationList(p)
return new Promise((resolve) => {
resolve({ data: [...res.data], total: res.count })
})
},
beforeFetch: (p) => {
return formatParams(p)
},
columns: applyColums,
formConfig: {
labelWidth: 120,
schemas: applySearch,
},
useSearchForm: true,
showIndexColumn: false,
maxHeight: '600',
pagination: true,
rowSelection: {},
striped: true,
bordered: true,
indexColumnProps: {
width: 60,
},
canResize: true,
immediate: false,
})
const [registerTable1, { getSelectRows: getSelectRowsFee, setProps: setPropsFee, setTableData }] = useTable({
columns: applyColumsDetail,
useSearchForm: false,
showIndexColumn: false,
maxHeight: '600',
pagination: false,
dataSource: dataSource.value,
striped: true,
rowKey: 'recordId',
bordered: true,
indexColumnProps: {
width: 60,
},
canResize: true,
immediate: false,
})
const [registerTableFree, { getForm:getFormFree, setSelectedRowKeys:setSelectedRowKeysFree, getSelectRows:getSelectRowsFree }] = useTable({
api: async (p) => {
const res: API.DataResult = await FreeInvoiceGetBizList(p)
return new Promise((resolve) => {
resolve({ data: [...res.data], total: res.count })
})
},
beforeFetch: (p) => {
return formatParams(p)
},
columns: freeColums,
formConfig: {
labelWidth: 120,
schemas: freeSearch,
},
useSearchForm: true,
showIndexColumn: false,
maxHeight: '600',
pagination: true,
rowSelection: {},
striped: true,
bordered: true,
indexColumnProps: {
width: 60,
},
canResize: true,
immediate: false,
})
const exchangeFlag = ref(false)
const freeFlag = ref(false)
const loading = ref(false)
const emits = defineEmits(['updateList', 'addLeft'])
// RMB
function handleSureExhange() {
applications.value.forEach(item => {
if (item.currency != 'RMB') {
exchangarr.value.forEach(ite => {
if (item.currency == ite.currencyTo) {
item.exchangeRate = ite.reverseRate
}
})
} else {
item.exchangeRate = 1
}
})
const resultMap = new Map();
applications.value.forEach(item => {
const { applicationId, currency, exchangeRate } = item;
if (!resultMap.has(applicationId)) {
resultMap.set(applicationId, {
applicationId,
exchangeRates: []
});
}
const entry = resultMap.get(applicationId);
entry.exchangeRates.push({
currency,
exchangeRate
});
});
const result = Array.from(resultMap.values());
emits('updateList', result)
open.value = false
exchangeFlag.value = false
}
function handleClick(record, index) {
setSelectedRowKeys([record.id])
const data = {
ids: [record.id],
businessType: record.businessType,
}
loading.value = true
GetApplicationDetails(data).then(res => {
if (res.succeeded) {
dataSource.value = res.data
dataSource.value.forEach(item => {
item.applyAmount = item.restAmount ? item.restAmount : 0
item.applyAmount = item.applyAmount.toFixed(2)
})
setTableData(dataSource.value)
}
loading.value = false
})
}
function handleClickFree(record, index) {
setSelectedRowKeysFree([record.id])
const data = {
id: record.id,
businessType: record.businessType,
// customerId: record.customerId
}
loading.value = true
FreeInvoiceGetFees(data).then(res => {
if (res.succeeded) {
}
loading.value = false
})
}
function init(data) {
if(route.query.type=='apply'){
open.value = true
}
if(route.query.type=='free'){
freeFlag.value = true
}
}
const amountArr = ref([]) as any
//
function onSelectAmount() {
const arr = getSelectRowsFee()
amountArr.value = []
arr.forEach(item => {
amountArr.value.push({
currency: item.currency,
applyAmount: item.applyAmount ? Number(item.applyAmount).toFixed(2) : 0
})
})
amountArr.value = mergeByCurrency(amountArr.value)
}
//
function mergeByCurrency(arr) {
const result = {};
arr.forEach(item => {
if (result[item.currency]) {
result[item.currency].applyAmount += item.applyAmount;
} else {
result[item.currency] = { currency: item.currency, applyAmount: item.applyAmount };
}
});
return Object.values(result);
}
const applications = ref([]) as any
const exchangarr = ref([]) as any
//
function addDetailed() {
const arrRight = getSelectRows() ? getSelectRows() : []
const arr1 = []
exchangarr.value = []
applications.value = []
const firstCustomerId = arrRight[0].customerId;
if (arrRight.length == 0) {
createMessage.error('请选择一条数据')
return false
}
for (let i = 1; i < arrRight.length; i++) {
if (arrRight[i].customerId !== firstCustomerId) {
createMessage.error('请选择同一客户')
throw new Error('customerId值不一致');
}
}
arrRight.forEach(item => {
if (item.customerId != customerIdP.value) {
arr1.push(1)
}
if (item.currency) {
const arr = item.currency.split(' ')
arr.forEach(ite => {
applications.value.push({
applicationId: item.id,
currency: ite,
exchangeRate: 0
})
})
}
})
const currencySet = new Set();
const arr = [] as any
applications.value.forEach(item => {
if (item.currency != 'RMB') {
arr.push(item)
}
})
const uniqueData = arr.filter(item => {
if (!currencySet.has(item.currency)) {
currencySet.add(item.currency);
return true;
}
return false;
});
const promises = uniqueData.map(item => {
return new Promise((resolve) => {
const data = {
currencyFrom: 'RMB',
currencyTo: item.currency,
}
GetExchangeRate(data).then(res => {
exchangarr.value.push(res.data)
resolve(true);
})
});
});
return Promise.all(promises).then(() => {
applications.value.forEach(item => {
exchangarr.value.forEach(ite => {
if (item.currency == ite.currencyTo) {
item.exchangeRate = ite.reverseRate
}
})
})
exchangeFlag.value = true
});
}
const customerIdP = ref('')
function changeCustIn(id) {
customerIdP.value = id
}
defineExpose({ init, changeCustIn })
</script>
<style lang="less" scoped>
.total {
padding-left: 10px;
text-align: right;
margin-top: 20px;
border-top: 1px solid rgba(230, 236, 241, 1);
padding-top: 5px;
.total-item {
background: rgba(245, 249, 252, 1);
padding: 3px 10px;
font-size: 12px;
margin-right: 10px;
.number {
color: rgba(37, 122, 250, 1);
margin-left: 15px;
}
}
}
/deep/ .ant-table-footer {
padding: 0px !important;
background: white;
}
/deep/ .ant-table-container {
padding: 0px;
}
.bold {
font-size: 12px;
font-weight: bold;
color: black;
}
.apply {
background-color: #f5f9fc;
cursor: pointer;
padding: 4px 10px;
margin-right: 20px;
border: 1px solid white;
/deep/ .ant-checkbox-wrapper {
font-size: 12px !important;
}
&.active {
border: 1px solid #5396fa;
}
}
.rmb {
color: #ba3849;
font-weight: bold;
margin: 0 10px;
}
.yb {
color: #17a6a3;
font-weight: bold;
margin: 0 10px;
}
/deep/ .ant-checkbox-wrapper-checked .ant-checkbox-inner {
background-color: #257afa;
border-color: #257afa;
}
/deep/ .ant-checkbox-disabled.ant-checkbox-checked .ant-checkbox-inner::after {
border-color: #f5f5f5;
}
/deep/ .ant-checkbox-wrapper-checked .ant-checkbox-disabled+span {
color: #257afa;
}
</style>

@ -43,5 +43,8 @@ const props = defineProps({
margin-right: 5px;
font-weight: 400;
color: rgba(158, 83, 9, 1);
flex-shrink: 1;
display: inline-block;
min-width: 27px;
}
</style>

@ -15,11 +15,11 @@
<template #title>
<span>保存</span>
</template>
<span class="ds-action-svg-btn">
<span class="ds-action-svg-btn" @click="handleSave">
<img src="../../../../assets/svg/infoclient/baocun.svg" class="SvgImg" />
</span>
</a-tooltip>
<a-tooltip placement="top" :mouseEnterDelay="0.5">
<a-tooltip placement="top" :mouseEnterDelay="0.5" v-if="route.query.id">
<template #title>
<span>上一条</span>
</template>
@ -27,7 +27,7 @@
<img src="../../../../assets/svg/infoclient/shangxia.svg" class="SvgImg rotate" />
</span>
</a-tooltip>
<a-tooltip placement="top" :mouseEnterDelay="0.5">
<a-tooltip placement="top" :mouseEnterDelay="0.5" v-if="route.query.id">
<template #title>
<span>下一条</span>
</template>
@ -35,41 +35,41 @@
<img src="../../../../assets/svg/infoclient/shangxia.svg" class="SvgImg" />
</span>
</a-tooltip>
</div>
<div style="color: #17a6a3" class="right-b">
<div style="color: #17a6a3" class="right-b" v-if="route.query.id">
<span class="iconfont icon-locksuo"></span>锁定
</div>
<div style="color: #7a8798" class="right-b">
<div style="color: #7a8798" class="right-b" v-if="!route.query.id">
<span class="iconfont icon-a-jiesuo1_jiesuo"></span>未锁定
</div>
<div style="color: #3081fa" class="right-b">
<div style="color: #3081fa" class="right-b" v-if="route.query.type == 'apply'">
<span class="iconfont icon-dingdan"></span>申请开票
</div>
<div style="color: #3081fa" class="right-b">
<div style="color: #3081fa" class="right-b" v-if="route.query.type == 'free'">
<span class="iconfont icon-touzijilu"></span>自由开票
</div>
<div style="color: rgba(122, 135, 152, 1)" class="right-b">
<div style="color: rgba(122, 135, 152, 1)" class="right-b" v-if="!route.query.id">
<span class="iconfont icon-a-xiaopiaofapiao-01"></span>普票
</div>
<div style="color: rgba(37, 122, 250, 1)" class="right-b">
<div style="color: rgba(37, 122, 250, 1)" class="right-b" v-if="route.query.id">
<span class="iconfont icon-a-xiaopiaofapiao-01"></span>红票
</div>
<div style="color: rgba(186, 56, 73, 1)" class="right-b">
<div style="color: rgba(186, 56, 73, 1)" class="right-b" v-if="route.query.id">
<span class="iconfont icon-a-xiaopiaofapiao-01"></span>蓝票
</div>
<div>
<a-button v-repeat type="link">
<span class="iconfont icon-touzijilu"></span>开票
</a-button>
<a-button v-repeat type="link">
<a-popconfirm title="确定申请开票吗?" ok-text="" cancel-text="" @confirm="handleIssue">
<a-button v-repeat type="link" v-if="route.query.id">
<span class="iconfont icon-touzijilu"></span>开票
</a-button>
</a-popconfirm>
<a-button v-repeat type="link" v-if="route.query.id">
<span class="iconfont icon-dengjizongshu"></span>冲红
</a-button>
<a-button v-repeat type="link">
<a-button v-repeat type="link" v-if="route.query.id">
<span class="iconfont icon-youjian"></span>邮件转发
</a-button>
<a-button v-repeat type="link">
<a-button v-repeat type="link" v-if="route.query.id">
<span class="iconfont icon-ic_search24px"></span>查看发票
</a-button>
</div>
@ -128,14 +128,9 @@
<span>{{ form.invoiceNO }}</span>
</template>
</editCompent>
<editCompent :showEdit="false" ref="editCompentRef" label="发票代码:">
<template #text>
<span>{{ form.invoiceNO }}</span>
</template>
</editCompent>
<editCompent :showEdit="false" ref="editCompentRef" label="发票流水号:">
<template #text>
<span>{{ form.invoiceNO }}</span>
<span>{{ form.sn }}</span>
</template>
</editCompent>
</div>
@ -143,44 +138,45 @@
<div class="box">
<div class="box-top">
<div class="box-top-item" style="border-right: 1px solid rgba(158, 83, 9, 1)">
<editCompent ref="editCompentRef" label="购买方名称:">
<editCompent :showEdit="false" ref="editCompentRef" label="购买方名称:">
<template #text>
<span> {{ form.customerName }}</span>
<span> {{ form.invoiceHeader }}</span>
</template>
<template #content>
<a-select size="small" v-model:value="form.customerId" style="width: 90%">
<a-select size="small" v-model:value="form.invoiceHeader" style="width: 90%">
<a-select-option :key="index" v-for="(item, index) in customerList"
:value="item.id">{{ item.pinYinCode }}</a-select-option>
</a-select>
</template>
</editCompent>
<editCompent ref="editCompentRef" label="纳税人识别号/统一社会信用代码:">
<editCompent :showEdit="false" ref="editCompentRef" label="纳税人识别号/统一社会信用代码:">
<template #text>
<span> {{ form.taxID }}</span>
<span> {{ form.customerTaxID }}</span>
</template>
<template #content>
<a-input v-model:value="form.taxID" size="small"></a-input>
<a-input v-model:value="form.customerTaxID" style="width: 90%"
size="small"></a-input>
</template>
</editCompent>
</div>
<div class="box-top-item">
<editCompent ref="editCompentRef" label="销售方名称:">
<editCompent :showEdit="false" ref="editCompentRef" label="销售方名称:">
<template #text>
<span> {{ form.customerName }}</span>
<span> {{ form.orgName }}</span>
</template>
<template #content>
<a-select size="small" v-model:value="form.customerId" style="width: 90%">
<a-select size="small" v-model:value="form.orgName" style="width: 90%">
<a-select-option :key="index" v-for="(item, index) in customerList"
:value="item.id">{{ item.pinYinCode }}</a-select-option>
</a-select>
</template>
</editCompent>
<editCompent ref="editCompentRef" label="纳税人识别号/统一社会信用代码:">
<editCompent :showEdit="false" ref="editCompentRef" label="纳税人识别号/统一社会信用代码:">
<template #text>
<span> {{ form.taxID }}</span>
</template>
<template #content>
<a-input v-model:value="form.taxID" size="small"></a-input>
<a-input v-model:value="form.taxID" style="width: 90%" size="small"></a-input>
</template>
</editCompent>
</div>
@ -190,43 +186,145 @@
<a-button v-repeat type="link" @click="add">
<span class="iconfont icon-jia"></span>添加
</a-button>
<a-button v-repeat type="link">
<span class="iconfont icon-shanchu1"></span>删除
<a-button v-repeat type="link" @click="handleInto">
<span class="iconfont icon-jia"></span>引用
</a-button>
<a-button v-repeat type="link">
<a-popconfirm title="确定要删除勾选的数据?" ok-text="" cancel-text="" @confirm="deleteRow">
<a-button v-repeat type="link">
<span class="iconfont icon-shanchu1"></span>删除
</a-button>
</a-popconfirm>
<a-button v-repeat type="link" @click="openFee">
<span class="iconfont icon-peizhitubiaosvg-"></span>费用明细
</a-button>
<a-button v-repeat type="link">
<a-button v-repeat type="link" @click="openFile">
<span class="iconfont icon-fujian1"></span>附件
</a-button>
</div>
<div class="invoiceIssue-table" >
<div class="invoiceIssue-table">
<input class="ds-tb-check" type="checkbox" v-model="allCheck" :indeterminate="someCheck" />
<hot-table ref="hotTb" :data="list" :settings="settings">
<img v-show="!list.length" class="hot-tb-no-data"
src="../../../../assets/images/nodata.png" alt="" />
</hot-table>
</div>
<div>
<span>合计</span>
<span>金额:</span>
<span>税额:</span>
<div class="line">
<span style="color: rgba(158, 83, 9, 1);margin-left: 20px">合计</span>
<span style="margin: 0 20px 0 40px">金额:{{ noTaxAmountTotal }}</span>
<span>税额:{{ taxAmountTotal }}</span>
</div>
<div class="line">
<span style="margin-left: 20px">
<span style="color: rgba(158, 83, 9, 1)">价税合计(大写):</span>
{{ taxUnitPriceTotalBig }}</span>
<span style="margin: 0 20px 0 40px">
<span style="color: rgba(158, 83, 9, 1)"> 小写:</span>
{{ taxUnitPriceTotal }}</span>
</div>
<div style="padding:5px 20px;display: flex;height: 140px">
<div style="width: 80%;">
<editCompent ref="editCompentRef" label="备注:">
<template #text>
<span> {{ form.note }}</span>
</template>
<template #content>
<a-textarea :auto-size="{ minRows: 6, maxRows: 8 }" v-model:value="form.note"
size="small"></a-textarea>
</template>
</editCompent>
</div>
<div>
<a-button type="link">
<i class="icon-a-17Btuichu iconfont"></i> 提取备注</a-button>
<a-button type="link"><i class="icon-jichupeizhi iconfont"></i>模板设置</a-button>
</div>
</div>
</div>
<div style="display: flex;padding-left: 20px;padding-top: 10px;">
<editCompent ref="editCompentRef" label="收款人:">
<template #text>
<span> {{ form.payee }}</span>
</template>
<template #content>
<a-select show-search style="width: 90%;" size="small" :filter-option="false"
@search="handleSearchUser" v-model:value="form.payee">
<a-select-option v-for="item in UserList" :label="item.label" :key="item.value"
:value="item.label">
{{ item.label }}
</a-select-option>
</a-select>
</template>
</editCompent>
<editCompent ref="editCompentRef" label="复核人:">
<template #text>
<span> {{ form.checker }}</span>
</template>
<template #content>
<a-select show-search style="width: 90%;" size="small" :filter-option="false"
@search="handleSearchUser" v-model:value="form.checker">
<a-select-option v-for="item in UserList" :label="item.label" :key="item.value"
:value="item.label">
{{ item.label }}
</a-select-option>
</a-select>
</template>
</editCompent>
<editCompent ref="editCompentRef" label="开票人:">
<template #text>
<span> {{ form.operatorName }}</span>
</template>
<template #content>
<a-select show-search style="width: 90%;" size="small" :filter-option="false"
@search="handleSearchUser" v-model:value="form.operatorId">
<a-select-option v-for="item in UserList" :label="item.label" :key="item.value"
:value="item.value">
{{ item.label }}
</a-select-option>
</a-select>
</template>
</editCompent>
</div>
</div>
<div class="right">
<BasicForm @register="registerForm">
</BasicForm>
<BasicTable @register="registerTable">
</BasicTable>
</div>
</div>
</a-spin>
<applyInvoice @updateList="handleUpdate" ref="applyInvoiceRef"></applyInvoice>
<a-modal width="1400px" @cancel="feeFlag = false" :visible="feeFlag" title="费用明细" :footer="null">
<BasicTable @register="registerTableFee">
<template v-slot:bodyCell="{ column, record }">
<template v-if="column.dataIndex == 'feeType'">
<span v-if="record.feeType == 1"></span>
<span v-if="record.feeType == 2"></span>
</template>
<template v-if="column.dataIndex == 'vessel'">
<span>{{ record.vessel }}/{{ record.voyage }}</span>
</template>
</template>
</BasicTable>
</a-modal>
<invoiceFile ref="invoiceFileRef"></invoiceFile>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, defineComponent, nextTick } from 'vue'
import { ref, onMounted, defineComponent, nextTick, watchEffect, watch } from 'vue'
import editCompent from './editCompent.vue'
import { BasicForm, useForm } from '/@/components/Form/index'
import { AutoComplete } from 'ant-design-vue'
import feeTable from './feeTable.vue'
import applyInvoice from './applyInvoice.vue'
import invoiceFile from './invoiceFile.vue'
import { DownOutlined } from '@ant-design/icons-vue'
import {
GetInvoiceCodeList
GetInvoiceCodeList, GetUserListAll, DeleteInvoiceDetail,
GeneralInvoiceSave, GeneralInvoiceGet,
GeneralInvoiceGetList, GeneralInvoiceInitiate
} from '../api'
import { useMessage } from '/@/hooks/web/useMessage'
import { useRoute, useRouter } from 'vue-router'
@ -236,21 +334,270 @@ import {
} from '/@/views/operation/seaexport/api/BookingLedger'
import { GetFeeCurrencySelectList, GetClientListByCode } from '/@/api/common'
import dayjs from 'dayjs'
import { BasicTable, useTable, TableAction } from '/@/components/Table'
import { useGo } from '/@/hooks/web/usePage'
import { useUserStore } from '/@/store/modules/user'
import { isNamedTupleMember } from 'typescript'
import { detailColumns } from '../columns'
import { detailColumnsRight, feeColumnsDetail } from '../columns'
import { HotTable } from '@handsontable/vue3'
import { useMultipleTabStore } from '/@/store/modules/multipleTab'
const tabStore = useMultipleTabStore()
const userStore = useUserStore()
import { registerAllModules } from 'handsontable/registry'
import 'handsontable/dist/handsontable.full.min.css'
defineComponent({
HotTable,
})
registerAllModules()
const tabStore = useMultipleTabStore()
const userStore = useUserStore()
const go = useGo()
const detailForm = [
{
field: 'divider-selects',
component: 'Divider',
label: '基本信息',
colProps: {
span: 24,
},
},
{
field: 'isSettledName',
label: '是否结算',
component: 'Input',
dynamicDisabled: true,
colProps: { span: 12 },
},
{
field: 'status',
label: '开票状态',
component: 'Input',
dynamicDisabled: true,
colProps: { span: 12 },
},
{
label: '系统客户',
field: 'autualCustomerName1',
component: 'ApiSelect',
dynamicDisabled: false,
colProps: { span: 12 },
componentProps: () => {
return {
api: () => {
return new Promise((resolve) => {
GetControllerClientList().then((res) => {
resolve(res)
})
})
},
immediate: false,
labelField: 'shortName',
valueField: 'shortName',
resultField: 'data',
filterOption: (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
},
}
},
},
{
label: '代开客户',
field: 'autualCustomerName',
component: 'ApiSelect',
dynamicDisabled: false,
colProps: { span: 12 },
componentProps: () => {
return {
api: () => {
return new Promise((resolve) => {
GetControllerClientList().then((res) => {
resolve(res)
})
})
},
immediate: false,
labelField: 'shortName',
valueField: 'shortName',
resultField: 'data',
filterOption: (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
},
}
},
},
{
field: 'divider-selects1',
component: 'Divider',
label: '金额信息',
colProps: {
span: 24,
},
},
{
field: 'applyAmount',
label: '申请金额',
component: 'InputNumber',
colProps: { span: 12 },
},
{
field: 'invoiceAmount',
label: '开票金额',
component: 'InputNumber',
colProps: { span: 12 },
},
{
field: 'taxRate',
label: '开票税率',
component: 'InputNumber',
colProps: { span: 12 },
},
{
field: 'otherInvoiceAmount',
label: '外币金额',
component: 'InputNumber',
colProps: { span: 12 },
},
{
field: 'divider-selects2',
component: 'Divider',
label: '开票通知和推送',
colProps: {
span: 24,
},
},
{
field: 'email',
label: '邮箱',
component: 'InputNumber',
colProps: { span: 24 },
},
{
field: 'cellPhoneNO',
label: '手机',
component: 'InputNumber',
colProps: { span: 24 },
},
{
field: 'divider-selects4',
component: 'Divider',
label: '冲红信息',
colProps: {
span: 24,
},
},
{
field: 'isSetRed',
label: '是否冲红',
component: 'Input',
dynamicDisabled: true,
colProps: { span: 12 },
},
{
field: 'redNO',
label: '被冲红发票号码',
component: 'Input',
dynamicDisabled: true,
colProps: { span: 12 },
},
{
field: 'redReason',
label: '冲红理由',
component: 'Input',
dynamicDisabled: true,
colProps: { span: 12 },
},
{
field: 'redCode',
label: '被冲红发票代码',
component: 'Input',
dynamicDisabled: true,
colProps: { span: 12 },
},
{
field: 'divider-selects5',
component: 'Divider',
label: '申请明细',
colProps: {
span: 24,
},
},
]
const [registerForm, { resetFields, setFieldsValue, validate, updateSchema, getFieldsValue, }] = useForm({
labelWidth: 100,
schemas: detailForm,
showActionButtonGroup: false,
readonly: true,
})
const [registerTable, { setTableData }] = useTable({
columns: detailColumnsRight,
isTreeTable: false,
maxHeight: 600,
pagination: false,
striped: false,
useSearchForm: false,
showTableSetting: false,
bordered: true,
showIndexColumn: false,
indexColumnProps: {
width: 60,
},
canResize: true,
immediate: true,
})
import { useAppStore } from '/@/store/modules/app'
const appStore = useAppStore()
function ClickLast(type) {
const data = {
"queryCondition": "[]",
"pageCondition": {
"pageIndex": 1,
"pageSize": 100,
"sortConditions": []
}
}
let indexQuery = 0
let list = []
GeneralInvoiceGetList(data).then(res => {
list = res.data.list
res.data.list.forEach((item, index) => {
if (item.id == route.query.id) {
indexQuery = index
}
})
console.log(indexQuery, list)
if (type == 'next') {
if (indexQuery == 0) {
createMessage.warning('已经是第一条了')
} else {
go("/invoiceIssueDetail?id=" + list[indexQuery - 1].id + '&type=' + route.query.type)
}
}
if (type == 'last') {
if (indexQuery == list.length - 1) {
createMessage.warning('已经是最后一条了')
} else {
go("/invoiceIssueDetail?id=" + list[indexQuery + 1].id + '&type=' + route.query.type)
}
}
})
}
const applyInvoiceRef = ref(null) as any
function open() {
applyInvoiceRef.value.init()
}
function handleIssue() {
const data = {
ids: [route.query.id]
}
loading.value = true
GeneralInvoiceInitiate(data).then(res => {
if (res.succeeded) {
createMessage.success('操作成功')
getDetail()
}
loading.value = false
}).catch(() => {
loading.value = false
})
}
const route = useRoute()
const { createMessage } = useMessage()
const id = ref(route.query.id)
@ -270,11 +617,196 @@ onMounted(() => {
GetClientListByCode().then(res => {
customerList.value = res.data
})
//
GetUserListAll().then((res) => {
UserList.value = res.data
})
if (!route.query.id) {
open()
} else {
getDetail()
}
})
function handleInto() {
if (route.query.type = 'apply') {
applyInvoiceRef.value.init()
}
}
function handleSave() {
const data = {
invoice: {
...form.value,
...getFieldsValue()
},
invoiceDetails: list.value,
}
loading.value = true
GeneralInvoiceSave(data).then(res => {
if (res.succeeded) {
getDetail()
createMessage.success('保存成功')
}
loading.value = false
}).catch(() => {
loading.value = false
})
}
function getDetail() {
loading.value = true
GeneralInvoiceGet({ id: route.query.id }).then(res => {
if (res.succeeded) {
form.value = res.data
list.value = res.data.invoiceDetails ? res.data.invoiceDetails : []
hotTb.value.hotInstance.loadData(res.data.invoiceDetails ? res.data.invoiceDetails : [])
if (res.data.isSettled) {
res.data.isSettledName = '是'
} else {
res.data.isSettledName = '否'
}
setTableData(res.data.applications)
setFieldsValue(res.data)
}
loading.value = false
}).catch(() => {
loading.value = false
})
}
const invoiceFileRef = ref('')
function openFile() {
invoiceFileRef.value.init()
}
const router = useRouter()
const go = useGo()
function handleUpdate(val) {
const data = {
invoice: {
...form.value,
...getFieldsValue()
},
invoiceDetails: list.value,
applications: val,
}
GeneralInvoiceSave(data).then(res => {
if (res.succeeded) {
createMessage.success('保存成功')
if (!route.query.id) {
const { fullPath } = route //
tabStore.closeTabByKey(fullPath, router)
setTimeout(() => {
go(`/invoiceIssueDetail?id=${res.data.id}&type=${route.query.type}`)
}, 50)
} else {
getDetail()
}
}
})
}
//
const deleteRow = async () => {
const ids = [] as any
list.value.forEach((item) => {
if (item.selected && item.id) ids.push(item.id)
})
if (ids.length == 0) {
const res = list.value.filter((item) => {
return !item.selected
})
list.value = res
hotTb.value.hotInstance.loadData(res)
} else {
loading.value = true
const data = {
ids: ids
}
DeleteInvoiceDetail(data).then(res => {
if (res.succeeded) {
createMessage.success(res.message)
const data = list.value.filter((item) => {
return !item.selected
})
list.value = data
hotTb.value.hotInstance.loadData(data)
}
loading.value = false
})
}
}
const [registerTableFee, { setTableData: setTableDataFee, }] = useTable({
columns: feeColumnsDetail,
formConfig: {
labelWidth: 120,
},
useSearchForm: false,
showIndexColumn: false,
pagination: false,
showTableSetting: true,
striped: true,
rowKey: 'id',
bordered: true,
indexColumnProps: {
width: 60,
},
canResize: true,
immediate: false,
})
const feeFlag = ref(false)
function openFee() {
feeFlag.value = true
setTimeout(() => {
setTableDataFee(form.value.details)
}, 100)
}
function handleBlur() {
editCompentRef.value.invoiceEditFlag = true
}
const taxUnitPriceTotal = ref(0) as any
const taxUnitPriceTotalBig = ref(0) as any
const taxAmountTotal = ref(0) as any
const amountTotal = ref(0) as any
const noTaxAmountTotal = ref(0) as any
const list = ref([]) as any
watch(
list,
(val) => {
let a = 0
let b = 0
let taxUnitPriceTotalStr = 0
let taxAmountStr = 0
let amountStr = 0
let noTaxAmountStr = 0
val.forEach((item) => {
if (item.selected) {
a += 1
} else {
b += 1
}
item.noTaxAmount = (Number(item.quantity) * Number(item.unitPrice)).toFixed(2)
taxUnitPriceTotalStr += item.taxUnitPrice
taxAmountStr += Number(item.taxAmount)
amountStr += Number(item.amount)
noTaxAmountStr += item.noTaxAmount ? Number(item.noTaxAmount) : 0
})
if (a == 0) {
allCheck.value = false
}
if (b == 0) {
allCheck.value = true
}
if (a != 0 && b != 0) {
someCheck.value = true
} else {
someCheck.value = false
}
taxUnitPriceTotal.value = Number(taxUnitPriceTotalStr).toFixed(2)
taxAmountTotal.value = Number(taxAmountStr).toFixed(2)
amountTotal.value = Number(amountStr).toFixed(2)
noTaxAmountTotal.value = Number(noTaxAmountStr).toFixed(2)
taxUnitPriceTotalBig.value = numberToChineseUpper(taxUnitPriceTotal.value)
},
{
deep: true,
},
)
const row = {
selected: false,
name: '',
@ -297,7 +829,12 @@ const add = () => {
hot.selectCell(list.value.length - 1, 1)
})
}
const UserList = ref([]) as any
function handleSearchUser(val) {
GetUserListAll({ queryKey: val }).then((res) => {
UserList.value = res.data
})
}
function onClick({ key }) {
form.value.categoryCode = key
CategoryData.forEach((item) => {
@ -328,7 +865,7 @@ function getCategory() {
//
const feeDict = ref([])
//
const list = ref([]) as any
const hotTb = ref(null) as any
const activeKey = ref('1')
//
@ -336,6 +873,7 @@ const allCheck = ref(false)
//
const someCheck = ref(false)
import { feeUnitDict } from '/@/hooks/dict/index'
import { t } from 'vxe-table'
const unitDict = ref([]) as any
//
const columns = [
@ -458,6 +996,67 @@ const columns = [
]
function numberToChineseUpper(num) {
//
const chineseNums = ["零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"];
//
const units = ["", "拾", "佰", "仟", "万", "亿"];
//
const decimalUnits = ["角", "分"];
//
let parts = num.toString().split('.');
let integerPart = parts[0];
let decimalPart = parts[1] ? parts[1] : '';
// 0
if (integerPart === '0') {
return `零元整`;
}
//
let result = '';
let unitIndex = 0;
let hasZero = false;
for (let i = integerPart.length - 1; i >= 0; i--) {
let digit = integerPart[i];
let digitStr = chineseNums[digit];
if (digitStr === "零") {
if (hasZero) continue; //
hasZero = true;
} else {
hasZero = false;
}
if (digit !== '0' || (digit === '0' && (result[result.length - 1] !== '零'))) {
result = digitStr + units[unitIndex] + result;
} else {
result = digitStr + result;
}
unitIndex++;
}
//
result += '元';
//
if (decimalPart.length > 0) {
for (let i = 0; i < decimalPart.length; i++) {
let digit = decimalPart[i];
result += chineseNums[digit] + decimalUnits[i];
}
} else {
//
result += '整';
}
return result;
}
//
const settings = {
height: '350',
@ -538,6 +1137,19 @@ const settings = {
},
}
watchEffect(() => {
//
if (allCheck.value) {
list.value.forEach((item) => {
item.selected = true
})
} else {
//
list.value.forEach((item) => {
item.selected = false
})
}
})
</script>
@ -577,11 +1189,14 @@ const settings = {
.content {
padding-left: 15px;
display: flex;
.left {
background-color: #fffbf7;
padding: 15px 10px;
width: 60%;
padding-bottom: 0px;
margin-bottom: 40px;
.left-top {
padding: 0 20px;
@ -629,28 +1244,52 @@ const settings = {
left: 35px;
}
/deep/ .ant-divider-inner-text {
font-size: 12px;
font-weight: bold;
}
/deep/ .ant-divider-horizontal.ant-divider-with-text {
margin: 3px;
}
/deep/ .vben-basic-table {
height: auto;
}
.right {
width: 39%;
margin-left: 1%;
}
</style>
<style lang="less">
.invoiceIssue-table {
.handsontable {
.wtHider {
max-height: 240px!important;
min-height: 160px;
.handsontable {
.wtHider {
max-height: 240px !important;
min-height: 160px;
}
.htCheckboxRendererInput {
position: relative;
z-index: 999;
}
}
.htCheckboxRendererInput {
position: relative;
z-index: 999;
.handsontable .htCore tbody tr td {
background: #fffbf7;
border-bottom: 1px solid #ebeaea;
}
.handsontable .htCore thead tr th {
background: #fffbf7;
color: rgba(158, 83, 9, 1);
}
}
.handsontable .htCore tbody tr td{
background: #fffbf7;
border-color: #fffbf7;
border-bottom: 1px solid #ebeaea;
}
.handsontable .htCore thead tr th {
background: #fffbf7;
border-color: #fffbf7;
color: rgba(158, 83, 9, 1);
}
.line {
font-size: 12px;
border-bottom: 1px solid rgba(158, 83, 9, 1);
padding: 5px 0;
}
</style>

@ -0,0 +1,145 @@
<template>
<div>
<a-modal width="800px" @cancel="openFileFlag = false" :visible="openFileFlag" title="文件列表" :footer="null">
<div style="padding-bottom: 20px">
<div style="display: flex;">
<DsFile @handleSuccess="fileSuccess" ref="dsFile" :showFileList="false" :id="route.query.id"
:show="false" height="300">
<a-button type="link" @click="addFile">
<span class="iconfont icon-jia"></span>
附件上传
</a-button>
</DsFile>
<a-button type="link" @click="delFile">
<span class="iconfont icon-shanchu1"></span>
删除文件
</a-button>
</div>
<a-table :loading="fileloading" size="small" :pagination="false" rowKey="id"
:row-selection="{ selectedRowKeys: selectedRowKeysFile, onChange: onSelectChangeFile }"
:columns="columnsFile" :data-source="fileData" bordered>
<template v-slot:bodyCell="{ column, record }">
<template v-if="column.dataIndex == 'fileName'">
<a @click="download(record)">{{ record.fileName }}</a>
</template>
<template v-if="column.dataIndex == 'caozuo'">
<a @click="lookFile(record)"></a>
</template>
</template>
</a-table>
</div>
</a-modal>
<a-modal width="800px" @cancel="fileFlag = false" :visible="fileFlag" title="预览文件" :footer="null">
<img v-if="!pdfFlag" :src="fileSrc" alt="">
<iframe v-if="pdfFlag" :src="fileSrc" style="height: 800px;width: 100%;" frameborder="0"></iframe>
</a-modal>
</div>
</template>
<script lang="ts" setup >
import {
GetOpFileList, BatchDelFiles, DownloadOpFile
} from '../api'
import DsFile from '/@/components/File/index.vue'
import { useRoute, useRouter } from 'vue-router'
import { ref, onMounted, defineComponent, nextTick, watchEffect, watch } from 'vue'
import { useMessage } from '/@/hooks/web/useMessage'
const { createMessage } = useMessage()
const route = useRoute()
const columnsFile = [
{
title: '文件名称',
width: 150,
dataIndex: 'fileName',
},
{
title: '上传日期',
width: 150,
dataIndex: 'createTime',
},
{
title: '上传者',
width: 150,
dataIndex: 'createUserName',
},
{
title: '操作',
width: 150,
dataIndex: 'caozuo',
},
]
const openFileFlag = ref(false)
const dsFile = ref('')
function download(item) {
DownloadOpFile({ id: item.id }).then(res => {
const pdfUrl = window.URL.createObjectURL(new Blob([res.data], { type: 'application/txt;charset=utf-8' }))
const fname = item.fileName //
const link = document.createElement('a')
link.href = pdfUrl
link.setAttribute('download', fname)
document.body.appendChild(link)
link.click()
})
}
const pdfFlag = ref(false)
function lookFile(item) {
fileFlag.value = true
if (item.fileType == '.pdf') {
pdfFlag.value = true
} else {
pdfFlag.value = false
}
DownloadOpFile({ id: item.id }).then(res => {
if (res.data.size > 150) {
fileSrc.value = window.URL.createObjectURL(new Blob([res.data], { type: 'application/pdf;charset=utf-8' }))
}
})
}
function fileSuccess() {
getfileList()
}
function addFile() {
dsFile.value.init()
}
function init() {
getfileList()
openFileFlag.value = true
}
const fileSrc = ref('')
const fileFlag = ref(false)
const fileData = ref([]) as any
const fileloading = ref(false)
const getfileList = () => {
fileloading.value = true
GetOpFileList({ id: route.query.id }).then(res => {
fileloading.value = false
res.data.forEach(item => {
if (item.createTime) {
item.createTime = new Date(item.createTime)
item.createTime = item.createTime.getFullYear() + '-' + (item.createTime.getMonth() + 1) + '-' + (item.createTime.getDate())
}
item['type'] = item?.filePath?.split('.')[1]
fileData.value = res.data
})
if (res.data.length == 0) {
fileData.value = []
}
}).catch(() => {
fileloading.value = false
})
}
const selectedRowKeysFile = ref([]) as any
function onSelectChangeFile(selectedRowKeys) {
selectedRowKeysFile.value = selectedRowKeys
}
function delFile() {
fileloading.value = true
BatchDelFiles({ ids: selectedRowKeysFile.value }).then(res => {
if (res.succeeded) {
createMessage.success('删除成功')
getfileList()
}
fileloading.value = false
})
}
defineExpose({init})
</script>

@ -1,6 +1,6 @@
<template>
<div class="main">
<BasicTable class="ds-table" @register="registerTable">
<BasicTable @row-dbClick="(e) => { GoDetailed(e) }" class="ds-table" @register="registerTable">
<template #tableTitle>
<div class="tableTitleBox">
<a-tooltip placement="top" :mouseEnterDelay="0.5">
@ -17,18 +17,20 @@
<template #title>
<span>删除</span>
</template>
<span class="ds-action-svg-btn">
<a-button v-repeat type="link">
<img src="../../../assets/svg/infoclient/shanchu.svg" class="SvgImg" />
</a-button>
</span>
<a-popconfirm title="确定删除当前选中数据?" @confirm="FnDel" ok-text="" cancel-text="">
<span class="ds-action-svg-btn">
<a-button v-repeat type="link">
<img src="../../../assets/svg/infoclient/shanchu.svg" class="SvgImg" />
</a-button>
</span>
</a-popconfirm>
</a-tooltip>
<a-tooltip placement="top" :mouseEnterDelay="0.5">
<template #title>
<span>提交锁定</span>
</template>
<span class="ds-action-svg-btn">
<a-button v-repeat type="link">
<a-button v-repeat type="link" @click="handleLock">
<img src="../../../assets/icons/lock.svg" class="SvgImg" />
</a-button>
</span>
@ -38,7 +40,7 @@
<span>解除锁定</span>
</template>
<span class="ds-action-svg-btn">
<a-button v-repeat type="link">
<a-button v-repeat type="link" @click="handleLock">
<img src="../../../assets/icons/openLock.svg" class="SvgImg" />
</a-button>
</span>
@ -54,7 +56,7 @@
</span>
</a-tooltip>
</div>
<a-button v-repeat type="link" @click="goDetail('free')" >
<a-button v-repeat type="link" @click="goDetail('free')">
<span class="iconfont icon-touzijilu"></span>
自由开票
</a-button>
@ -75,6 +77,18 @@
},
]" />
</template>
<template v-if="column.key === 'isLocked'">
<span v-if="record.isLocked"></span>
<span v-else></span>
</template>
<template v-if="column.key === 'isPrinted'">
<span v-if="record.isPrinted"></span>
<span v-else></span>
</template>
<template v-if="column.key === 'isSettled'">
<span v-if="record.isSettled"></span>
<span v-else></span>
</template>
</template>
</BasicTable>
@ -82,7 +96,7 @@
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, defineExpose, computed } from 'vue'
import { GetList, InvoiceApplicationGet, Audit } from './api.js'
import { GeneralInvoiceGetList, GeneralInvoiceSetLock, GeneralInvoiceDelete } from './api.js'
import { BasicTable, useTable, TableAction } from '/@/components/Table'
import { formatParams } from '/@/hooks/web/common'
import { columns, searchFormSchema, detailColumns, feeColumns, feeColumnsSum } from './columns'
@ -90,11 +104,11 @@ import { useMessage } from '/@/hooks/web/useMessage'
const { createMessage } = useMessage()
import { useGo } from '/@/hooks/web/usePage'
const go = useGo()
const [registerTable, { reload, getPaginationRef, getSelectRows, getRawDataSource }] = useTable({
const [registerTable, { reload, setLoading, getSelectRows, getRawDataSource }] = useTable({
api: async (p) => {
const res: API.DataResult = await GetList(p)
const res: API.DataResult = await GeneralInvoiceGetList(p)
return new Promise((resolve) => {
resolve({ data: [...res.data], total: res.count })
resolve({ data: [...res.data.list], total: res.count })
})
},
beforeFetch: (p) => {
@ -125,8 +139,61 @@ const [registerTable, { reload, getPaginationRef, getSelectRows, getRawDataSourc
fixed: 'right',
},
})
function goDetail(type){
go(`/invoiceIssueDetail?type=add&type=`+type)
function FnDel(){
let ids = []
ids = getSelectRows().map((item) => {
return item.id
})
if (ids.length == 0) {
createMessage.error('请选择数据')
return false
}
const data = {
ids: [...ids]
}
setLoading(true)
GeneralInvoiceDelete(data).then(res => {
if (res.succeeded) {
createMessage.success('删除成功')
reload()
}
setLoading(false)
}).catch(() => {
setLoading(false)
})
}
function goDetail(type) {
go(`/invoiceIssueDetail?type=` + type)
}
function handleLock() {
let ids = []
ids = getSelectRows().map((item) => {
return item.id
})
if (ids.length == 0) {
createMessage.error('请选择数据')
return false
}
const data = {
ids: [...ids]
}
setLoading(true)
GeneralInvoiceSetLock(data).then(res => {
if (res.succeeded) {
createMessage.success('操作成功')
reload()
}
setLoading(false)
}).catch(() => {
setLoading(false)
})
}
function GoDetailed(row) {
if (row.modeText == '申请发票') {
go("/invoiceIssueDetail?id=" + row.id + '&type=apply')
} else {
go("/invoiceIssueDetail?id=" + row.id + '&type=free')
}
}

Loading…
Cancel
Save