1.3.2前端:

feat(开票信息):完成开票申请初版
dev
xs 1 week ago
parent 46b495a86a
commit 9653c49f20

@ -0,0 +1,76 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { FinInvoiceDetailVO, FinInvoiceDetailForm, FinInvoiceDetailQuery } from '@/api/oa/erp/finInvoiceDetail/types';
/**
*
* @param query
* @returns {*}
*/
export const listFinInvoiceDetail = (query?: FinInvoiceDetailQuery): AxiosPromise<FinInvoiceDetailVO[]> => {
return request({
url: '/oa/erp/finInvoiceDetail/list',
method: 'get',
params: query
});
};
/**
*
* @param invoiceDetailId
*/
export const getFinInvoiceDetail = (invoiceDetailId: string | number): AxiosPromise<FinInvoiceDetailVO> => {
return request({
url: '/oa/erp/finInvoiceDetail/' + invoiceDetailId,
method: 'get'
});
};
/**
*
* @param data
*/
export const addFinInvoiceDetail = (data: FinInvoiceDetailForm) => {
return request({
url: '/oa/erp/finInvoiceDetail',
method: 'post',
data: data
});
};
/**
*
* @param data
*/
export const updateFinInvoiceDetail = (data: FinInvoiceDetailForm) => {
return request({
url: '/oa/erp/finInvoiceDetail',
method: 'put',
data: data
});
};
/**
*
* @param invoiceDetailId
*/
export const delFinInvoiceDetail = (invoiceDetailId: string | number | Array<string | number>) => {
return request({
url: '/oa/erp/finInvoiceDetail/' + invoiceDetailId,
method: 'delete'
});
};
/**
*
* @param query
* @returns {*}
*/
export function getErpFinInvoiceDetailList (query) {
return request({
url: '/oa/erp/finInvoiceDetail/getErpFinInvoiceDetailList',
method: 'get',
params: query
});
};

@ -0,0 +1,161 @@
export interface FinInvoiceDetailVO {
/**
* ID
*/
invoiceDetailId: string | number;
/**
* ID
*/
invoiceId: string | number;
/**
*
*/
billingItems: string;
/**
*
*/
specificationModel: string;
/**
*
*/
unitName: string;
/**
*
*/
quantity: number;
/**
*
*/
unitPrice: number;
/**
*
*/
totalPrice: number;
/**
* /13%
*/
taxRate: number;
/**
*
*/
taxPrice: number;
}
export interface FinInvoiceDetailForm extends BaseEntity {
/**
* ID
*/
invoiceDetailId?: string | number;
/**
* ID
*/
invoiceId?: string | number;
/**
*
*/
billingItems?: string;
/**
*
*/
specificationModel?: string;
/**
*
*/
unitName?: string;
/**
*
*/
quantity?: number;
/**
*
*/
unitPrice?: number;
/**
*
*/
totalPrice?: number;
/**
* /13%
*/
taxRate?: number;
/**
*
*/
taxPrice?: number;
}
export interface FinInvoiceDetailQuery extends PageQuery {
/**
* ID
*/
invoiceId?: string | number;
/**
*
*/
billingItems?: string;
/**
*
*/
specificationModel?: string;
/**
*
*/
unitName?: string;
/**
*
*/
quantity?: number;
/**
*
*/
unitPrice?: number;
/**
*
*/
totalPrice?: number;
/**
* /13%
*/
taxRate?: number;
/**
*
*/
taxPrice?: number;
/**
*
*/
params?: any;
}

@ -0,0 +1,109 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { FinInvoiceInfoVO, FinInvoiceInfoForm, FinInvoiceInfoQuery } from '@/api/oa/erp/finInvoiceInfo/types';
import { ContractPaymentMethodVO } from '@/api/oa/erp/contractPaymentMethod/types';
/**
*
* @param query
* @returns {*}
*/
export const listFinInvoiceInfo = (query?: FinInvoiceInfoQuery): AxiosPromise<FinInvoiceInfoVO[]> => {
return request({
url: '/oa/erp/finInvoiceInfo/list',
method: 'get',
params: query
});
};
/**
*
*/
export const getBaseInfo = (): AxiosPromise<FinInvoiceInfoVO> => {
return request({
url: '/oa/erp/finInvoiceInfo/getBaseInfo',
method: 'get'
});
};
/**
*
* @param invoiceId
*/
export const getFinInvoiceInfo = (invoiceId: string | number): AxiosPromise<FinInvoiceInfoVO> => {
return request({
url: '/oa/erp/finInvoiceInfo/' + invoiceId,
method: 'get'
});
};
/**
*
* @param data
*/
export const addFinInvoiceInfo = (data: FinInvoiceInfoForm) => {
return request({
url: '/oa/erp/finInvoiceInfo',
method: 'post',
data: data
});
};
/**
*
* @param data
*/
export const updateFinInvoiceInfo = (data: FinInvoiceInfoForm) => {
return request({
url: '/oa/erp/finInvoiceInfo',
method: 'put',
data: data
});
};
/**
*
* @param invoiceId
*/
export const delFinInvoiceInfo = (invoiceId: string | number | Array<string | number>) => {
return request({
url: '/oa/erp/finInvoiceInfo/' + invoiceId,
method: 'delete'
});
};
/**
*
* @param query
* @returns {*}
*/
export function getErpFinInvoiceInfoList (query) {
return request({
url: '/oa/erp/finInvoiceInfo/getErpFinInvoiceInfoList',
method: 'get',
params: query
});
};
/**
*
* @param invoiceId
*/
export const getContractPaymentMethodList = (contractId: string | number): AxiosPromise<ContractPaymentMethodVO> => {
return request({
url: '/oa/erp/finInvoiceInfo/getContractPaymentMethodList/' + contractId,
method: 'get'
});
};
/**
*
* @param data
*/
export const updateInvoiceAttach = (data: FinInvoiceInfoForm) => {
return request({
url: '/oa/erp/finInvoiceInfo/updateInvoiceAttach',
method: 'post',
data: data
});
};

@ -0,0 +1,522 @@
import { FinInvoiceDetailVO } from '../finInvoiceDetail/types';
export interface FinInvoiceInfoVO {
/**
* ID
*/
invoiceId: string | number;
/**
*
*/
invoiceCode: string;
/**
* (10)
*/
earlyFlag: string;
/**
* 1 2
*/
invoiceType: string;
/**
* ()
*/
issueAmount: number;
/**
*
*/
issuancePercentage: number;
/**
* 10
*/
redInkFlag: string;
/**
* ID
*/
projectId: string | number;
/**
*
*/
projectCode: string;
/**
*
*/
projectName: string;
/**
* erp_project_acceptanceacceptance_date
*/
acceptanceDate: string;
/**
*
*/
deliveryDate: string;
/**
* erp_project_receivingarrival_date
*/
arrivalDate: string;
/**
* +1
*/
invoiceVersion: number;
/**
* (12)
*/
invoiceCategory: string;
/**
* ID
*/
contractId: string | number;
/**
*
*/
totalPrice: number;
/**
* ID
*/
customerId: string | number;
/**
*
*/
customerName: string;
/**
*
*/
paymentMethod: string;
/**
*
*/
returnedMoney: number;
/**
*
*/
returnedRate: number;
/**
* 1 0
*/
feedingFlag: string;
/**
* 1 0
*/
costCompleteFlag: string;
/**
* 1 0
*/
saleOrderCreateFlag: string;
/**
*
*/
flowStatus: string;
/**
* (1 2 3)
*/
invoiceStatus: string;
/**
*
*/
remark: string;
/**
*
*/
earlyReason: string;
/**
* ID
*/
requestBy: number;
/**
* ID
*/
requestDept: number;
/**
* ,nickname
*/
requestByName: string;
/**
*
*/
requestDeptName: string;
/**
*
*/
issueDate?: string;
}
export interface FinInvoiceInfoForm extends BaseEntity {
/**
* ID
*/
invoiceId?: string | number;
/**
*
*/
invoiceCode?: string;
/**
* (10)
*/
earlyFlag?: string;
/**
* 1 2
*/
invoiceType?: string;
/**
* ()
*/
issueAmount?: number;
/**
*
*/
issuancePercentage?: number;
/**
* 10
*/
redInkFlag?: string;
/**
* ID
*/
projectId?: string | number;
/**
*
*/
projectCode?: string;
/**
*
*/
projectName?: string;
/**
* erp_project_acceptanceacceptance_date
*/
acceptanceDate?: string;
/**
*
*/
deliveryDate?: string;
/**
* erp_project_receivingarrival_date
*/
arrivalDate?: string;
/**
* +1
*/
invoiceVersion?: number;
/**
* (12)
*/
invoiceCategory?: string;
/**
* ID
*/
contractId?: string | number;
/**
*
*/
totalPrice?: number;
/**
* ID
*/
customerId?: string | number;
/**
*
*/
customerName?: string;
/**
*
*/
paymentMethod?: string;
/**
*
*/
returnedMoney?: number;
/**
*
*/
returnedRate?: number;
/**
* 1 0
*/
feedingFlag?: string;
/**
* 1 0
*/
costCompleteFlag?: string;
/**
* 1 0
*/
saleOrderCreateFlag?: string;
/**
*
*/
flowStatus?: string;
/**
* (1 2 3)
*/
invoiceStatus?: string;
/**
*
*/
remark?: string;
/**
*
*/
earlyReason?: string;
/**
* ID
*/
requestBy?: number;
/**
* ID
*/
requestDept?: number;
/**
* ,nickname
*/
requestByName?: string;
/**
*
*/
requestDeptName?: string;
/**
*
*/
issueDate?: string;
/**
*
*/
erpFinInvoiceDetailList?: Array<FinInvoiceDetailVO>;
/**
* ID
*/
toDeletedInvoiceDetailIdList?: Array<number>;
}
export interface FinInvoiceInfoQuery extends PageQuery {
/**
*
*/
invoiceCode?: string;
/**
* (10)
*/
earlyFlag?: string;
/**
* 1 2
*/
invoiceType?: string;
/**
* ()
*/
issueAmount?: number;
/**
*
*/
issuancePercentage?: number;
/**
* 10
*/
redInkFlag?: string;
/**
* ID
*/
projectId?: string | number;
/**
*
*/
projectCode?: string;
/**
*
*/
projectName?: string;
/**
* erp_project_acceptanceacceptance_date
*/
acceptanceDate?: string;
/**
*
*/
deliveryDate?: string;
/**
* erp_project_receivingarrival_date
*/
arrivalDate?: string;
/**
* +1
*/
invoiceVersion?: number;
/**
* (12)
*/
invoiceCategory?: string;
/**
* ID
*/
contractId?: string | number;
/**
*
*/
totalPrice?: number;
/**
* ID
*/
customerId?: string | number;
/**
*
*/
customerName?: string;
/**
*
*/
paymentMethod?: string;
/**
*
*/
returnedMoney?: number;
/**
*
*/
returnedRate?: number;
/**
* 1 0
*/
feedingFlag?: string;
/**
* 1 0
*/
costCompleteFlag?: string;
/**
* 1 0
*/
saleOrderCreateFlag?: string;
/**
*
*/
flowStatus?: string;
/**
* (1 2 3)
*/
invoiceStatus?: string;
/**
*
*/
earlyReason?: string;
/**
* ID
*/
requestBy?: number;
/**
* ID
*/
requestDept?: number;
/**
* ,nickname
*/
requestByName?: string;
/**
*
*/
requestDeptName?: string;
/**
*
*/
issueDate?: string;
/**
*
*/
params?: any;
}

@ -93,9 +93,9 @@ export function getErpProjectInfoList(query) {
* @param query
* @returns {*}
*/
export function getErpProjectInfoJoinList(query) {
export function getErpProjectWithProjectList(query) {
return request({
url: '/oa/erp/projectInfo/getErpProjectInfoJoinList',
url: '/oa/erp/projectInfo/getErpProjectWithProjectList',
method: 'get',
params: query
});

@ -232,6 +232,18 @@ export const listUserByDeptAndRole = (query: any): AxiosPromise<any> => {
});
};
/**
* ,join dept
* @param query
*/
export const getUserJoinDeptList = (query: UserQuery): AxiosPromise<UserVO[]> => {
return request({
url: '/system/user/getUserJoinDeptList',
method: 'get',
params: query
});
};
export default {
listUser,
getUser,
@ -250,5 +262,6 @@ export default {
deptTreeSelect,
listUserByDeptId,
getUserList,
listUserByDeptAndRole
listUserByDeptAndRole,
getUserJoinDeptList
};

@ -32,6 +32,7 @@
<dict-tag :options="business_direction" :value="scope.row.businessDirection" />
</template>
</el-table-column>
<el-table-column prop="oneCustomerName" label="客户名称" width="150" />
<el-table-column prop="contractStatus" label="合同状态" width="100">
<template #default="scope">
<dict-tag :options="contract_status" :value="scope.row.contractStatus" />
@ -61,7 +62,7 @@
<script setup lang="ts" name="ContractSelectDialog">
import { ref, reactive, toRefs, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import { getErpContractInfoList } from '@/api/oa/erp/contractInfo';
import { listContractInfo } from '@/api/oa/erp/contractInfo';
import { ContractInfoVO, ContractInfoQuery } from '@/api/oa/erp/contractInfo/types';
const props = defineProps({
@ -139,7 +140,7 @@ const resetQuery = () => {
const getContractList = async () => {
contractLoading.value = true;
console.log(queryParams.value)
const res = await getErpContractInfoList(queryParams.value);
const res = await listContractInfo(queryParams.value);
console.log(res)
contractList.value = res.rows;
contractTotal.value = res.total;

@ -1,5 +1,5 @@
<template>
<el-dialog v-model="dialogVisible" title="选择项目" width="880px">
<el-dialog v-model="dialogVisible" title="选择项目" width="980px">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="mb-[10px]">
<el-card shadow="hover">
@ -24,7 +24,69 @@
</div>
</transition>
<el-table :data="projectList" border @row-click="selectProject" style="width: 100%" v-loading="projectLoading" highlight-current-row>
<el-table
:data="projectList"
border
style="width: 100%"
v-loading="projectLoading"
row-key="projectId"
:row-class-name="tableRowClassName"
@row-click="handleRowClick"
@expand-change="handleExpandChange"
>
<el-table-column type="expand" width="50">
<template #default="props">
<div v-if="props.row.contractFlag === '1'" class="p-3 bg-gray-50">
<el-table
:data="props.row.erpContractInfoVoList"
border
size="small"
@row-click="handleContractRowClick($event, props.row)"
highlight-current-row
>
<el-table-column width="50">
<template #default="scope">
<el-radio
v-model="selectedContractMap[props.row.contractId]"
:label="scope.row.contractId"
@click.stop="selectContract(props.row, scope.row)"
>
<span></span>
</el-radio>
</template>
</el-table-column>
<el-table-column prop="contractCode" label="合同编号" width="150" />
<el-table-column prop="contractName" label="合同名称" width="150" />
<el-table-column prop="oneCustomerName" label="客户名称" min-width="150" />
<el-table-column prop="totalPrice" label="合同金额" width="120">
</el-table-column>
<el-table-column prop="contractDate" label="签订日期" width="150" />
<el-table-column prop="contractStatus" label="合同状态" width="100">
<template #default="props">
<dict-tag :options="contract_status" :value="props.row.contractStatus" />
</template>
</el-table-column>
</el-table>
</div>
<div v-else class="p-3 text-center text-gray-500">
暂无合同信息
</div>
</template>
</el-table-column>
<el-table-column width="50">
<template #default="scope">
<el-radio
v-model="selectedProjectId"
:label="scope.row.projectId"
@click.stop="selectProject(scope.row)"
:disabled="scope.row.contractFlag === '1'"
>
<span></span>
</el-radio>
</template>
</el-table-column>
<el-table-column prop="projectCode" label="项目号" width="150" />
<el-table-column prop="projectName" label="项目名称" min-width="160" />
<el-table-column prop="businessDirection" label="业务方向" width="120">
@ -32,9 +94,11 @@
<dict-tag :options="business_direction" :value="scope.row.businessDirection" />
</template>
</el-table-column>
<el-table-column prop="contractCode" label="合同编号" width="150" />
<el-table-column prop="contractName" label="合同名称" width="150" />
<el-table-column prop="contractFlag" label="有无合同" min-width="120">
<template #default="scope">
<dict-tag :options="contract_flag" :value="scope.row.contractFlag" />
</template>
</el-table-column>
<el-table-column prop="projectStatus" label="项目状态" width="100">
<template #default="scope">
<dict-tag :options="project_status" :value="scope.row.projectStatus" />
@ -64,8 +128,7 @@
<script setup lang="ts" name="ProjectSelectDialog">
import { ref, reactive, toRefs, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import { getErpProjectInfoJoinList } from '@/api/oa/erp/projectInfo';
import { getErpContractInfoList } from '@/api/oa/erp/contractInfo';
import { getErpProjectWithProjectList } from '@/api/oa/erp/projectInfo';
import { ProjectInfoVO, ProjectInfoQuery } from '@/api/oa/erp/projectInfo/types';
const props = defineProps({
@ -82,13 +145,17 @@ const props = defineProps({
const emit = defineEmits(['update:visible', 'project-selected']);
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { business_direction, project_status, project_category } = toRefs<any>(
proxy?.useDict('business_direction', 'project_status', 'project_category')
const { business_direction, project_status, project_category, contract_status, contract_flag } = toRefs<any>(
proxy?.useDict('business_direction', 'project_status', 'project_category', 'contract_status', 'contract_flag')
);
//
const dialogVisible = ref(props.visible);
const selectedProject = ref<ProjectInfoVO | null>(null);
const selectedContract = ref<any>(null);
const selectedProjectId = ref<number | null>(null);
const selectedContractMap = ref<Record<number, number>>({});
const expandedRows = ref<number[]>([]);
const projectList = ref<ProjectInfoVO[]>([]);
const projectTotal = ref(0);
const projectLoading = ref(true);
@ -127,7 +194,7 @@ const queryFormRef = ref<ElFormInstance>();
watch(() => props.visible, (newVal) => {
dialogVisible.value = newVal;
if (newVal) {
selectedProject.value = null;
resetSelection();
queryParams.value.projectCategory = props.projectCategory;
getProjectList();
}
@ -138,6 +205,15 @@ watch(dialogVisible, (newVal) => {
emit('update:visible', newVal);
});
//
const resetSelection = () => {
selectedProject.value = null;
selectedContract.value = null;
selectedProjectId.value = null;
selectedContractMap.value = {};
expandedRows.value = [];
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
@ -154,27 +230,106 @@ const resetQuery = () => {
/** 查询项目信息列表 */
const getProjectList = async () => {
projectLoading.value = true;
console.log(queryParams.value)
const res = await getErpProjectInfoJoinList(queryParams.value);
console.log(res)
projectList.value = res.rows;
projectTotal.value = res.total;
projectLoading.value = false;
try {
const res = await getErpProjectWithProjectList(queryParams.value);
console.log(res)
projectList.value = res.rows;
projectTotal.value = res.total;
//
expandedRows.value = [];
resetSelection();
} catch (error) {
console.error('获取项目列表失败:', error);
} finally {
projectLoading.value = false;
}
};
//
const tableRowClassName = ({ row }: { row: ProjectInfoVO }) => {
if (row.contractFlag === '1' && row.erpContractInfoVoList?.length) {
return 'has-contract-row';
}
return '';
};
// /
const handleRowClick = (row: ProjectInfoVO, column: any, event: Event) => {
//
if (column.type === 'expand') return;
//
if (row.contractFlag === '1' && row.erpContractInfoVoList?.length) {
const index = expandedRows.value.indexOf(row.id);
if (index === -1) {
expandedRows.value.push(row.id);
} else {
expandedRows.value.splice(index, 1);
}
}
};
//
const handleExpandChange = (row: ProjectInfoVO, expanded: boolean) => {
if (expanded) {
if (!expandedRows.value.includes(row.id)) {
expandedRows.value.push(row.id);
}
} else {
const index = expandedRows.value.indexOf(row.id);
if (index > -1) {
expandedRows.value.splice(index, 1);
}
}
};
//
const selectProject = (row: ProjectInfoVO) => {
//
if (row.contractFlag === '1' && row.erpContractInfoVoList?.length) {
ElMessage.warning('该项目包含合同,请选择具体合同');
return;
}
selectedProject.value = row;
selectedContract.value = null;
selectedProjectId.value = row.id;
//
if (selectedContractMap.value[row.id]) {
delete selectedContractMap.value[row.id];
}
};
//
const selectContract = (project: ProjectInfoVO, contract: any) => {
selectedProject.value = project;
selectedContract.value = contract;
selectedProjectId.value = null; //
selectedContractMap.value[project.id] = contract.id;
};
//
const handleContractRowClick = (contract: any, project: ProjectInfoVO) => {
selectContract(project, contract);
};
//
const confirmProjectSelection = () => {
if (!selectedProject.value) {
ElMessage.warning('请选择一个项目');
ElMessage.warning('请选择一个项目或合同');
return;
}
emit('project-selected', selectedProject.value);
//
const result = {
project: selectedProject.value,
contract: selectedContract.value || null,
type: selectedContract.value ? 'contract' : 'project'
};
emit('project-selected', result);
dialogVisible.value = false;
};
@ -185,5 +340,19 @@ const handleCancel = () => {
</script>
<style scoped>
/* 可以添加组件特定的样式 */
:deep(.has-contract-row) {
cursor: pointer;
}
:deep(.el-table__expanded-cell) {
padding: 0 !important;
}
:deep(.el-radio) {
margin-right: 0;
}
:deep(.el-radio__label) {
display: none;
}
</style>

@ -0,0 +1,811 @@
<template>
<div class="p-3">
<el-card shadow="never" style="margin-top: 0; margin-bottom: 10px">
<!-- <template #header>-->
<!-- <div style="text-align: left; font-weight: bold; font-size: 24px">合同{{ form.contractId ? ' - 修改' : ' - 新增' }}</div>-->
<!-- </template>-->
<!-- 审批按钮组件 -->
<approvalButton
@submitForm="handleSave"
@approvalVerifyOpen="approvalVerifyOpen"
@handleApprovalRecord="handleApprovalRecord"
:buttonLoading="buttonLoading"
:id="form.invoiceId"
:status="form.flowStatus"
:pageType="routeParams.type"
:mode="false"
/>
</el-card>
<el-card shadow="never" class="mb-[15px]" header="开票信息">
<el-form ref="formRef" :model="form" :rules="rules" label-width="130px" status-icon>
<el-row :gutter="24">
<!-- 第一行 -->
<el-col :span="8">
<el-form-item label="发出人员" prop="requestBy">
<el-select v-model="form.requestBy" placeholder="请选择发出人员" clearable filterable class="w-full" @change="handleUserChange">
<el-option v-for="user in userOptions" :key="user.userId" :label="user.nickName" :value="user.userId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="发出部门" prop="requestDeptName">
<el-input v-model="form.requestDeptName" readonly />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="发出日期" prop="issueDate">
<el-date-picker v-model="form.issueDate" type="date" placeholder="请选择发出日期" value-format="YYYY-MM-DD" class="w-full" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<!-- 第二行项目信息 -->
<el-col :span="8">
<el-form-item label="项目编号" prop="projectCode">
<el-input v-model="form.projectCode" placeholder="请选择项目编号" @click="handleSelectProject" readonly suffix-icon="Search">
</el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目名称" prop="projectName">
<el-input v-model="form.projectName" placeholder="项目名称" readonly />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="合同编号" prop="contractCode">
<el-input
v-if="form.projectId && form.projectId !== '' && form.contractFlag === CONTRACT_FLAG.NO"
v-model="form.contractCode"
placeholder="请选择合同"
readonly
@click="showContractSelectDialog"
suffix-icon="Search"
/>
<el-input v-else v-model="form.contractCode" readonly />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="8">
<el-form-item label="客户名称" prop="customerName">
<el-input v-model="form.customerName" placeholder="客户名称" readonly />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="合同金额" prop="totalPrice">
<el-input v-model="form.totalPrice" placeholder="合同金额" readonly></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="本次开具发票比例" prop="issuancePercentage">
<el-input-number
v-model="form.issuancePercentage"
:precision="2"
:min="1"
:max="100"
placeholder="请输入开具发票比例"
style="width: 210px"
>
</el-input-number>
<span style="margin-left: 5px">%</span>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="24">
<el-form-item label="合同付款条款" prop="paymentMethod">
<span class="el-input__wrapper" style="padding: 0 11px; min-height: 32px; display: flex; align-items: center">
{{ paymentDescription }}
</span>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="8">
<el-form-item label="项目类型" prop="invoiceCategory">
<el-radio-group v-model="form.invoiceCategory">
<el-radio v-for="dict in invoice_category" :key="dict.value" :value="dict.value">{{ dict.label }} </el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="累计回款金额" prop="returnedMoney">
<el-input-number v-model="form.returnedMoney" :precision="2" placeholder="请输入累计回款金额" style="width: 210px"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="累计回款比例" prop="returnedRate">
<el-input v-model="form.returnedRate" placeholder="累计回款比例" readonly>
<template #append>%</template>
</el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="8">
<el-form-item label="提前开票" prop="earlyFlag">
<el-radio-group v-model="form.earlyFlag">
<el-radio v-for="dict in early_flag" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="验收日期" prop="acceptanceDate" v-if="form.earlyFlag !== EARLY_FLAG.YES">
<el-date-picker v-model="form.acceptanceDate" type="date" placeholder="请选择验收日期" value-format="YYYY-MM-DD" class="w-full" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="发货日期" prop="deliveryDate" v-if="form.earlyFlag !== EARLY_FLAG.YES">
<el-date-picker v-model="form.deliveryDate" type="date" placeholder="请选择发货日期" value-format="YYYY-MM-DD" class="w-full" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="24">
<el-form-item label="提前开票原因" prop="earlyReason" v-if="form.earlyFlag === EARLY_FLAG.YES">
<el-input v-model="form.earlyReason" placeholder="请输入提前开票原因" type="textarea" :rows="1" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="发票备注信息" prop="remark">
<el-input v-model="form.remark" placeholder="请输入发票需备注的信息内容" type="textarea" :rows="1" />
</el-form-item>
</el-col>
</el-row>
<el-col :span="12">
<el-form-item
label="发票附件"
prop="ossId"
v-if="routeParams.type === 'update' || routeParams.type === 'view' || routeParams.type === 'approval'"
>
<!-- <el-button type="primary" plain icon="Upload" @click="handleFile"></el-button>-->
<FileUpload
v-model="ossIdString"
:limit="5"
:fileSize="20"
:fileType="['png', 'jpg', 'pdf', 'ofd', 'xml']"
:isShowTip="true"
:disabled="!hasInvoiceAttachPer"
/>
</el-form-item>
</el-col>
</el-form>
</el-card>
<!-- 开票明细 -->
<el-card shadow="never" class="mb-[15px]" header="开票明细">
<template #header>
<div class="flex justify-between items-center">
<span class="font-medium">开票明细</span>
<div>
<el-button type="primary" plain size="small" icon="Plus" @click="handleAddItem"></el-button>
<el-button type="danger" plain size="small" icon="Delete" @click="handleDeleteItems" :disabled="selectedItems.length === 0"
>删除
</el-button>
</div>
</div>
</template>
<el-table :data="form.erpFinInvoiceDetailList" border stripe @selection-change="handleSelectionChange" max-height="400">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column label="开票内容" prop="billingItems" min-width="160">
<template #default="{ row, $index }">
<el-input v-model="row.billingItems" placeholder="请输入开票内容" @change="handleItemChange($index)" />
</template>
</el-table-column>
<el-table-column label="规格型号" prop="specificationModel" min-width="140">
<template #default="{ row }">
<el-input v-model="row.specificationModel" placeholder="请输入规格型号" />
</template>
</el-table-column>
<el-table-column label="单位" prop="unitName" width="120">
<template #default="{ row }">
<el-input v-model="row.unitName" placeholder="请输入单位" />
</template>
</el-table-column>
<el-table-column label="数量" prop="quantity" width="145">
<template #default="{ row, $index }">
<el-input-number
v-model="row.quantity"
:min="0"
:precision="2"
controls-position="right"
@change="calculateItemAmount($index)"
style="width: 120px"
/>
</template>
</el-table-column>
<el-table-column label="税率(%)" prop="taxRate" width="145">
<template #default="{ row, $index }">
<el-input-number v-model="row.taxRate" :min="0" :max="100" :precision="2" controls-position="right" style="width: 120px" />
</template>
</el-table-column>
<el-table-column label="单价(含税)" prop="unitPrice" width="145">
<template #default="{ row, $index }">
<el-input-number
v-model="row.unitPrice"
:min="0"
:precision="2"
controls-position="right"
@change="calculateItemAmount($index)"
style="width: 120px"
/>
</template>
</el-table-column>
<el-table-column label="金额(含税)" prop="totalPrice" width="140">
<template #default="{ row }">
<span class="text-red-500 font-medium">{{ row.totalPrice?.toFixed(2) || '0.00' }}</span>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="80" align="center">
<template #default="{ row, $index }">
<el-button link type="danger" icon="Delete" @click="handleRemoveItem($index, row)" />
</template>
</el-table-column>
</el-table>
<div class="flex justify-end mt-3 text-sm">
<div class="mr-4">
合计金额(含税)<span class="text-red-500 font-bold text-base">{{ totalInvoiceAmount }}</span>
</div>
</div>
</el-card>
<!-- 项目选择弹窗 -->
<!-- 项目选择弹窗组件 -->
<ProjectSelectDialog v-model:visible="projectSelectDialogVisible" projectCategory="1" @project-selected="handleProjectSelected" />
<!-- 合同选择弹窗组件 -->
<ContractSelectDialog v-model:visible="contractSelectDialogVisible" @contract-selected="handleContractSelected" />
<!-- 部门选择弹窗 (可根据实际组件调整) -->
<el-dialog v-model="deptDialogVisible" title="选择部门" width="600px" append-to-body>
<div class="p-3 text-center text-gray-500">请根据实际项目集成部门选择组件</div>
<template #footer>
<el-button @click="deptDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleDeptSelected"></el-button>
</template>
</el-dialog>
<!-- 人员选择弹窗 (可根据实际组件调整) -->
<el-dialog v-model="userDialogVisible" title="选择人员" width="600px" append-to-body>
<div class="p-3 text-center text-gray-500">请根据实际项目集成人员选择组件</div>
<template #footer>
<el-button @click="userDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleUserSelected"></el-button>
</template>
</el-dialog>
<!-- 提交审批组件 -->
<submitVerify ref="submitVerifyRef" @submit-callback="submitCallback" />
<!-- 审批记录 -->
<approvalRecord ref="approvalRecordRef" />
</div>
</template>
<script setup lang="ts">
import api from '@/api/system/user';
import { ref, reactive, computed, onMounted } from 'vue';
import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
import { useRoute, useRouter } from 'vue-router';
import ProjectSelectDialog from '@/views/oa/components/ProjectSelectDialog.vue';
import {
getFinInvoiceInfo,
getBaseInfo,
addFinInvoiceInfo,
updateFinInvoiceInfo,
getContractPaymentMethodList,
updateInvoiceAttach
} from '@/api/oa/erp/finInvoiceInfo';
import { FinInvoiceInfoForm, FinInvoiceInfoQuery } from '@/api/oa/erp/finInvoiceInfo/types';
import ApprovalButton from '@/components/Process/approvalButton.vue';
import { FinInvoiceDetailVO } from '@/api/oa/erp/finInvoiceDetail/types';
import SubmitVerify from '@/components/Process/submitVerify.vue';
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
import { DeptTreeVO } from '@/api/system/dept/types';
import { ContractPaymentMethodVO } from '@/api/oa/erp/contractPaymentMethod/types';
import { UserVO } from '@/api/system/user/types';
import ContractSelectDialog from '@/views/oa/components/ContractSelectDialog.vue';
import FileUpload from '@/components/FileUpload/index.vue';
import { checkPermi } from '@/utils/permission';
const userOptions = ref<UserVO[]>([]);
const deptOptions = ref<DeptTreeVO[]>([]);
const enabledDeptOptions = ref<DeptTreeVO[]>([]);
const contractPaymentMethodVoList = ref<ContractPaymentMethodVO[]>([]);
const route = useRoute();
const router = useRouter();
const routeParams = ref<Record<string, any>>({ ...(route.query as Record<string, any>) });
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const buttonLoading = ref(false);
const formRef = ref<FormInstance>();
const BUSINESS_STATUS = reactive({
DRAFT: '1', //
WAITING: '2', //
AVAILABLE: '3' //
});
const { early_flag, invoice_category } = toRefs<any>(proxy?.useDict('early_flag', 'invoice_category'));
const EARLY_FLAG = reactive({
YES: '1', //
NO: '0' //
});
const CONTRACT_FLAG = {
YES: '1',
NO: '2'
};
const hasInvoiceAttachPer = checkPermi(['oa/erp:finInvoiceInfo:invoiceAttach']);
console.log(hasInvoiceAttachPer);
//
const projectSelectDialogVisible = ref(false);
const deptDialogVisible = ref(false);
const userDialogVisible = ref(false);
//
const selectedItems = ref<FinInvoiceDetailVO[]>([]);
const toDeletedInvoiceDetailIdList = ref([]);
const initFormData: FinInvoiceInfoForm = {
invoiceId: undefined,
invoiceCode: undefined,
earlyFlag: undefined,
invoiceType: undefined,
issueAmount: undefined,
issuancePercentage: undefined,
redInkFlag: undefined,
projectId: undefined,
projectCode: undefined,
projectName: undefined,
acceptanceDate: undefined,
deliveryDate: undefined,
arrivalDate: undefined,
invoiceVersion: undefined,
invoiceCategory: undefined,
contractId: undefined,
totalPrice: undefined,
customerId: undefined,
customerName: undefined,
paymentMethod: undefined,
returnedMoney: undefined,
returnedRate: undefined,
feedingFlag: undefined,
costCompleteFlag: undefined,
saleOrderCreateFlag: undefined,
flowStatus: undefined,
invoiceStatus: undefined,
remark: undefined,
earlyReason: undefined,
erpFinInvoiceDetailList: []
};
const data = reactive<PageData<FinInvoiceInfoForm, FinInvoiceInfoQuery>>({
form: { ...initFormData },
queryParams: {
params: {}
},
rules: {
projectCode: [{ required: true, message: '项目不能为空', trigger: 'blur' }],
invoiceCategory: [{ required: true, message: '项目类型不能为空', trigger: 'blur' }],
earlyFlag: [{ required: true, message: '提前开票不能为空', trigger: 'blur' }]
}
});
const { form, rules } = toRefs(data);
// IDFileUpload
const ossIdString = computed({
get: () => {
if (form.value.ossId === undefined || form.value.ossId === null) {
return '';
}
return String(form.value.ossId);
},
set: (val: string) => {
form.value.ossId = val || undefined;
}
});
watch(
() => form.value.ossId,
async (newVal, oldVal) => {
// 使 ?? null undefined 'empty'
// ossId ()
if (isInitialized.value) {
const normalizedOld = oldVal ?? 'empty';
const normalizedNew = newVal ?? 'empty';
console.log(normalizedOld + '---' + normalizedNew);
if (normalizedOld !== normalizedNew) {
try {
buttonLoading.value = true;
console.log('附件发生变化,旧值:', oldVal, '新值:', newVal);
//
const invoiceAttachForm = {
invoiceId: form.value.invoiceId,
ossId: form.value.ossId
};
await updateInvoiceAttach(invoiceAttachForm);
} finally {
buttonLoading.value = false;
}
}
}
},
{ immediate: false }
);
const getUserList = async () => {
const query = {};
const res = await api.getUserList(query);
userOptions.value = res.data;
};
const handleUserChange = async (newUserId) => {
const userOption = userOptions.value.find((item) => item.userId == newUserId);
form.value.requestDeptName = userOption.deptName;
form.value.requestDept = userOption.deptId;
form.value.requestByName = userOption.nickName;
};
const getContractPaymentMethods = async (contractId) => {
const res = await getContractPaymentMethodList(contractId);
contractPaymentMethodVoList.value = res.data;
};
const paymentDescription = computed(() => {
return contractPaymentMethodVoList.value.map((item) => `${item.paymentDescription}`).join('.'); // 使.
});
/** 查询部门下拉树结构 */
const getDeptTree = async () => {
const res = await api.deptTreeSelect();
deptOptions.value = res.data;
enabledDeptOptions.value = filterDisabledDept(res.data);
};
/** 过滤禁用的部门 */
const filterDisabledDept = (deptList: DeptTreeVO[]) => {
return deptList.filter((dept) => {
if (dept.disabled) {
return false;
}
if (dept.children && dept.children.length) {
dept.children = filterDisabledDept(dept.children);
}
return true;
});
};
// - issueAmount issuancePercentage
const totalInvoiceAmount = computed(() => {
const total = form.value.erpFinInvoiceDetailList.reduce((sum, item) => sum + (item.totalPrice || 0), 0).toFixed(2);
//
form.value.issueAmount = total;
// 0
if (form.value.totalPrice && form.value.totalPrice > 0) {
form.value.issuancePercentage = Number(((total / form.value.totalPrice) * 100).toFixed(2));
} else {
form.value.issuancePercentage = undefined;
}
return total;
});
//
watch(
() => form.value.totalPrice,
(newTotalPrice) => {
//
if (newTotalPrice && newTotalPrice > 0 && form.value.issueAmount) {
form.value.issuancePercentage = Number(((form.value.issueAmount / newTotalPrice) * 100).toFixed(2));
} else {
form.value.issuancePercentage = undefined;
}
calculateReturnedRate();
}
);
//
watch(
() => form.value.returnedMoney,
(newReturnedMoney) => {
//
calculateReturnedRate();
}
);
//
const calculateReturnedRate = () => {
if (form.value.totalPrice && form.value.totalPrice > 0 && form.value.returnedMoney) {
form.value.returnedRate = Number(((form.value.returnedMoney / form.value.totalPrice) * 100).toFixed(2));
} else {
form.value.returnedRate = undefined;
}
};
const isInitialized = ref(false);
onMounted(async () => {
nextTick(async () => {
getUserList(); //
//
routeParams.value = route.query;
console.log(route.query);
const id = routeParams.value.id as string | number;
try {
proxy?.$modal.loading('正在加载数据,请稍后...');
if (id && (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval')) {
const res = await getFinInvoiceInfo(id);
console.log(res);
Object.assign(form.value, res.data);
Object.assign(form.value.erpFinInvoiceDetailList, res.data.erpFinInvoiceDetailVoList);
} else {
const res = await getBaseInfo();
Object.assign(form.value, res.data);
handleAddItem();
}
// true
await nextTick();
isInitialized.value = true;
} finally {
proxy?.$modal.closeLoading();
}
});
});
// onMounted(() => {
// const id = route.params?.id
// if (id) {
// getDetail(Number(id))
// } else {
// //
// handleAddItem()
// }
// })
//
const handleSelectProject = () => {
projectSelectDialogVisible.value = true;
};
//
const handleProjectSelected = (result: any) => {
const project = result.project;
Object.assign(form.value, {
contractId: result.contract?.contractId,
contractFlag: project.contractFlag,
projectId: project.projectId,
projectName: project.projectName,
projectCode: project.projectCode,
contractCode: result.contract?.contractCode,
contractName: result.contract?.contractName,
customerName: result.contract?.oneCustomerName,
totalPrice: result.contract?.totalPrice
});
if (project.contractFlag === CONTRACT_FLAG.YES && result.contract?.contractId) {
getContractPaymentMethods(result.contract?.contractId);
}
};
//
const contractSelectDialogVisible = ref(false);
//
const showContractSelectDialog = () => {
contractSelectDialogVisible.value = true;
};
//
const handleContractSelected = (contract: any) => {
Object.assign(form.value, {
contractId: contract.contractId,
contractCode: contract.contractCode,
contractName: contract.contractName,
customerName: contract.oneCustomerName,
totalPrice: contract.totalPrice
});
getContractPaymentMethods(contract.contractId);
};
//
const handleSelectDept = () => {
deptDialogVisible.value = true;
};
const handleDeptSelected = () => {
// form.deptName = ''; //
// form.deptId = 1;
deptDialogVisible.value = false;
};
//
const handleSelectUser = () => {
userDialogVisible.value = true;
};
const handleUserSelected = () => {
// form.userName = ''; //
// form.userId = 1;
userDialogVisible.value = false;
};
//
const handleAddItem = () => {
form.value.erpFinInvoiceDetailList.push({
billingItems: '',
specificationModel: '',
unitName: '',
quantity: undefined,
taxRate: undefined,
unitPrice: undefined,
totalPrice: 0
});
};
const handleRemoveItem = (index: number, row: FinInvoiceDetailVO) => {
form.value.erpFinInvoiceDetailList.splice(index, 1);
if (row.invoiceDetailId) {
toDeletedInvoiceDetailIdList.value.push(row.invoiceDetailId);
}
};
const handleDeleteItems = () => {
if (selectedItems.value.length === 0) return;
const remainingItems = form.value.erpFinInvoiceDetailList.filter((item) => !selectedItems.value.includes(item));
form.value.erpFinInvoiceDetailList = remainingItems;
selectedItems.value.forEach((row) => {
if (row.invoiceDetailId) {
toDeletedInvoiceDetailIdList.value.push(row.invoiceDetailId);
}
});
selectedItems.value = [];
};
const handleSelectionChange = (selection: FinInvoiceDetailVO[]) => {
selectedItems.value = selection;
};
//
const calculateItemAmount = (index: number) => {
const item = form.value.erpFinInvoiceDetailList[index];
if (item.quantity && item.unitPrice) {
item.totalPrice = Number((item.quantity * item.unitPrice).toFixed(2));
} else {
item.totalPrice = 0;
}
};
//
const handleItemChange = (index: number) => {
calculateItemAmount(index);
};
//
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
//
const handleApprovalRecord = () => {
approvalRecordRef.value.init(form.value.invoiceId);
};
//
const submitCallback = async () => {
await proxy.$tab.closePage(route);
router.go(-1);
};
//
const approvalVerifyOpen = async () => {
await submitVerifyRef.value.openDialog(routeParams.value.taskId);
};
//
const handleSave = async (status: string, mode: boolean) => {
if (!formRef.value) return;
try {
buttonLoading.value = true;
await formRef.value.validate(async (valid) => {
if (valid) {
if (form.value.erpFinInvoiceDetailList.length === 0) {
ElMessage.warning('请至少添加一条开票明细');
return;
}
//
const hasEmpty = form.value.erpFinInvoiceDetailList.some(
(item) => !item.billingItems || !item.unitName || !item.taxRate || item.quantity <= 0 || item.unitPrice <= 0
);
if (hasEmpty) {
ElMessage.warning('请填写完整的开票明细信息');
return;
}
//
if (form.value.returnedMoney && form.value.totalPrice && form.value.returnedMoney > form.value.totalPrice) {
ElMessage.warning('累计回款金额不能大于合同金额');
return;
}
if (form.value.earlyFlag === EARLY_FLAG.YES) {
form.value.acceptanceDate = undefined;
form.value.deliveryDate = undefined;
} else {
form.value.earlyReason = undefined;
}
form.value.invoiceStatus = getInvoiceStatus(status);
form.value.flowStatus = getFlowStatus(status);
//
if (form.value.invoiceId) {
form.value.toDeletedInvoiceDetailIdList = toDeletedInvoiceDetailIdList.value;
await updateFinInvoiceInfo(form.value);
} else {
await addFinInvoiceInfo(form.value);
}
ElMessage.success('保存成功');
//
goBack();
}
});
} finally {
buttonLoading.value = false;
}
};
const getInvoiceStatus = (status: string): string => {
return status === 'draft' ? BUSINESS_STATUS.DRAFT : BUSINESS_STATUS.WAITING;
};
const getFlowStatus = (status: string): string => {
return status === 'draft' ? 'draft' : 'waiting';
};
const goBack = () => {
const obj = {
path: '/fin/finInvoiceInfo',
query: {
t: Date.now(),
pageNum: routeParams.value.pageNum
}
};
proxy?.$tab.closeOpenPage(obj);
};
//
const handleCancel = () => {
router.push('/oa/erp/finInvoiceInfo');
};
</script>

@ -0,0 +1,414 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="100px">
<el-form-item label="项目号" prop="projectCode">
<el-input v-model="queryParams.projectCode" placeholder="请输入项目号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="项目名称" prop="projectName">
<el-input v-model="queryParams.projectName" placeholder="请输入项目名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="项目类型" prop="invoiceCategory">
<el-select v-model="queryParams.invoiceCategory" placeholder="请选择项目类型" clearable @keyup.enter="handleQuery">
<el-option v-for="dict in invoice_category" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="提前开票标识" prop="earlyFlag">
<el-select v-model="queryParams.earlyFlag" placeholder="请选择提前开票标识" clearable @keyup.enter="handleQuery">
<el-option v-for="dict in early_flag" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="客户名称" prop="customerName">
<el-input v-model="queryParams.customerName" placeholder="请输入客户名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-form-item label="开票状态" prop="invoiceStatus">
<el-select v-model="queryParams.invoiceStatus" placeholder="请选择开票状态" clearable @keyup.enter="handleQuery">
<el-option v-for="dict in invoice_status" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
</el-select>
</el-form-item>
<!-- <el-form-item label="流程状态" prop="flowStatus">-->
<!-- <el-select v-model="queryParams.flowStatus" placeholder="请选择流程状态" clearable @keyup.enter="handleQuery">-->
<!-- <el-option v-for="dict in wf_business_status" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<el-button type="primary" icon="Search" @click="handleQuery"></el-button>
<el-button icon="Refresh" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['oa/erp:finInvoiceInfo:add']"> </el-button>
</el-col>
<!-- <el-col :span="1.5">-->
<!-- <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['oa/erp:finInvoiceInfo:edit']"-->
<!-- >修改-->
<!-- </el-button>-->
<!-- </el-col>-->
<!-- <el-col :span="1.5">-->
<!-- <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['oa/erp:finInvoiceInfo:remove']"-->
<!-- >删除-->
<!-- </el-button>-->
<!-- </el-col>-->
<!-- <el-col :span="1.5">-->
<!-- <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['oa/erp:finInvoiceInfo:export']"> </el-button>-->
<!-- </el-col>-->
<!-- <right-toolbar v-model:showSearch="showSearch" :columns="columns" :search="true" @queryTable="getList"></right-toolbar>-->
</el-row>
</template>
<el-table v-loading="loading" border :data="finInvoiceInfoList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="项目号" align="center" prop="projectCode" v-if="columns[9].visible" />
<el-table-column label="项目名称" align="center" prop="projectName" v-if="columns[10].visible" />
<el-table-column label="项目类型" align="center" prop="invoiceCategory" v-if="columns[15].visible">
<template #default="scope">
<dict-tag :options="invoice_category" :value="scope.row.invoiceCategory" />
</template>
</el-table-column>
<el-table-column label="提前开票标识" align="center" prop="earlyFlag" v-if="columns[3].visible">
<template #default="scope">
<dict-tag :options="early_flag" :value="scope.row.earlyFlag" />
</template>
</el-table-column>
<el-table-column label="本次开具金额" align="center" prop="issueAmount" v-if="columns[5].visible" />
<el-table-column label="本次开具比例" align="center" prop="issuancePercentage" v-if="columns[6].visible" />
<el-table-column label="验收日期" align="center" prop="acceptanceDate" width="180" v-if="columns[11].visible">
<template #default="scope">
<span>{{ parseTime(scope.row.acceptanceDate, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="发货日期" align="center" prop="deliveryDate" width="180" v-if="columns[12].visible">
<template #default="scope">
<span>{{ parseTime(scope.row.deliveryDate, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="合同总价" align="center" prop="totalPrice" v-if="columns[17].visible" />
<el-table-column label="客户名称" align="center" prop="customerName" v-if="columns[19].visible" />
<el-table-column label="累计回款金额" align="center" prop="returnedMoney" v-if="columns[21].visible" />
<el-table-column label="累计回款比例" align="center" prop="returnedRate" v-if="columns[22].visible" />
<el-table-column label="流程状态" align="center" prop="flowStatus" v-if="columns[26].visible">
<template #default="scope">
<dict-tag :options="wf_business_status" :value="scope.row.flowStatus" />
</template>
</el-table-column>
<el-table-column label="开票状态" align="center" prop="invoiceStatus" v-if="columns[27].visible">
<template #default="scope">
<dict-tag :options="invoice_status" :value="scope.row.invoiceStatus" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="查看详情" placement="top" v-if="scope.row.invoiceStatus !== INVOICE_STATUS.DRAFT">
<el-button
link
type="primary"
size="small"
icon="View"
@click="handleUpdate(scope.row, 'view')"
v-hasPermi="['oa:erp/budgetInfo:view']"
>
</el-button>
</el-tooltip>
<el-tooltip content="修改" placement="top">
<el-button
link
size="small"
type="primary"
icon="Edit"
@click="handleUpdate(scope.row, 'update')"
v-hasPermi="['oa/erp:finInvoiceInfo:edit']"
></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button
link
type="danger"
v-if="scope.row.invoiceStatus === INVOICE_STATUS.DRAFT"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['oa/erp:finInvoiceInfo:remove']"
></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
</div>
</template>
<script setup name="FinInvoiceInfo" lang="ts">
import { useRouter } from 'vue-router';
import { listFinInvoiceInfo, delFinInvoiceInfo, addFinInvoiceInfo, updateFinInvoiceInfo } from '@/api/oa/erp/finInvoiceInfo';
import { FinInvoiceInfoVO, FinInvoiceInfoQuery, FinInvoiceInfoForm } from '@/api/oa/erp/finInvoiceInfo/types';
import { reactive } from 'vue';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const router = useRouter();
const route = useRoute();
const { early_flag, invoice_category, invoice_status, wf_business_status } = toRefs<any>(
proxy?.useDict('early_flag', 'invoice_category', 'invoice_status', 'wf_business_status')
);
const finInvoiceInfoList = ref<FinInvoiceInfoVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const queryFormRef = ref<ElFormInstance>();
const finInvoiceInfoFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const INVOICE_STATUS = reactive({
DRAFT: '1', //稿
AUDITING: '2', //
AVAILABLE: '3' //
});
//
const columns = ref<FieldOption[]>([
{ key: 0, label: `开票ID`, visible: true },
{ key: 1, label: `租户编号`, visible: true },
{ key: 2, label: `开票申请编号`, visible: true },
{ key: 3, label: `提前开票标识(1是0否)`, visible: true },
{ key: 4, label: `发票类型`, visible: true },
{ key: 5, label: `本次开具金额(自动计算)`, visible: true },
{ key: 6, label: `本次开具比例`, visible: true },
{ key: 7, label: `冲红标识`, visible: true },
{ key: 8, label: `项目ID`, visible: true },
{ key: 9, label: `冗余,项目号`, visible: true },
{ key: 10, label: `冗余,项目名称`, visible: true },
{ key: 11, label: `冗余,验收日期,冗余`, visible: true },
{ key: 12, label: `发货日期,发货单中是分批发记录的`, visible: true },
{ key: 13, label: `冗余,收货日期,冗余`, visible: true },
{ key: 14, label: `版本,新版本+1`, visible: true },
{ key: 15, label: `项目类型(1、实施类2备件类)`, visible: true },
{ key: 16, label: `合同ID`, visible: true },
{ key: 17, label: `冗余,合同总价`, visible: true },
{ key: 18, label: `冗余客户ID`, visible: true },
{ key: 19, label: `冗余,客户名称`, visible: true },
{ key: 20, label: `冗余,合同付款条款`, visible: true },
{ key: 21, label: `累计回款金额`, visible: true },
{ key: 22, label: `累计回款比例`, visible: true },
{ key: 23, label: `是否全部投料`, visible: true },
{ key: 24, label: `成本是否归集完整`, visible: true },
{ key: 25, label: `是否建立销售订单`, visible: true },
{ key: 26, label: `流程状态`, visible: true },
{ key: 27, label: `开票状态(1暂存 2审批中 3可用)`, visible: true },
{ key: 28, label: `发票备注`, visible: true },
{ key: 29, label: `提前开票原因`, visible: true },
{ key: 30, label: `删除标志`, visible: true },
{ key: 31, label: `创建部门`, visible: true },
{ key: 32, label: `创建人`, visible: true },
{ key: 33, label: `创建时间`, visible: true },
{ key: 34, label: `更新人`, visible: true },
{ key: 35, label: `更新时间`, visible: true }
]);
const initFormData: FinInvoiceInfoForm = {
invoiceId: undefined,
invoiceCode: undefined,
earlyFlag: undefined,
invoiceType: undefined,
issueAmount: undefined,
issuancePercentage: undefined,
redInkFlag: undefined,
projectId: undefined,
projectCode: undefined,
projectName: undefined,
acceptanceDate: undefined,
deliveryDate: undefined,
arrivalDate: undefined,
invoiceVersion: undefined,
invoiceCategory: undefined,
contractId: undefined,
totalPrice: undefined,
customerId: undefined,
customerName: undefined,
paymentMethod: undefined,
returnedMoney: undefined,
returnedRate: undefined,
feedingFlag: undefined,
costCompleteFlag: undefined,
saleOrderCreateFlag: undefined,
flowStatus: undefined,
invoiceStatus: undefined,
remark: undefined,
earlyReason: undefined
};
const data = reactive<PageData<FinInvoiceInfoForm, FinInvoiceInfoQuery>>({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
invoiceCode: undefined,
earlyFlag: undefined,
invoiceType: undefined,
issueAmount: undefined,
issuancePercentage: undefined,
redInkFlag: undefined,
projectId: undefined,
projectCode: undefined,
projectName: undefined,
acceptanceDate: undefined,
deliveryDate: undefined,
arrivalDate: undefined,
invoiceVersion: undefined,
invoiceCategory: undefined,
contractId: undefined,
totalPrice: undefined,
customerId: undefined,
customerName: undefined,
paymentMethod: undefined,
returnedMoney: undefined,
returnedRate: undefined,
feedingFlag: undefined,
costCompleteFlag: undefined,
saleOrderCreateFlag: undefined,
flowStatus: undefined,
invoiceStatus: undefined,
earlyReason: undefined,
params: {}
},
rules: {
invoiceId: [{ required: true, message: '开票ID不能为空', trigger: 'blur' }],
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
projectCode: [{ required: true, message: '冗余,项目号不能为空', trigger: 'blur' }],
projectName: [{ required: true, message: '冗余,项目名称不能为空', trigger: 'blur' }],
invoiceCategory: [{ required: true, message: '项目类型(1、实施类2备件类)不能为空', trigger: 'blur' }]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询开票信息列表 */
const getList = async () => {
loading.value = true;
const res = await listFinInvoiceInfo(queryParams.value);
finInvoiceInfoList.value = res.rows;
total.value = res.total;
loading.value = false;
};
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
};
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
finInvoiceInfoFormRef.value?.resetFields();
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: FinInvoiceInfoVO[]) => {
ids.value = selection.map((item) => item.invoiceId);
single.value = selection.length != 1;
multiple.value = !selection.length;
};
/** 新增按钮操作 */
const handleAdd = () => {
// proxy.$tab.closePage(route);
router.push({
path: '/fin/finInvoiceInfo/edit',
query: {
type: 'add'
}
});
};
/** 修改按钮操作 */
const handleUpdate = async (row?: FinInvoiceInfoVO, type?: string) => {
const _invoiceId = row?.invoiceId || ids.value[0];
router.push({
path: '/fin/finInvoiceInfo/edit',
query: {
type: type,
id: _invoiceId
}
});
};
/** 提交按钮 */
const submitForm = () => {
finInvoiceInfoFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.invoiceId) {
await updateFinInvoiceInfo(form.value).finally(() => (buttonLoading.value = false));
} else {
await addFinInvoiceInfo(form.value).finally(() => (buttonLoading.value = false));
}
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
}
});
};
/** 删除按钮操作 */
const handleDelete = async (row?: FinInvoiceInfoVO) => {
const _invoiceIds = row?.invoiceId || ids.value;
await proxy?.$modal.confirm('是否确认删除开票信息编号为"' + _invoiceIds + '"的数据项?').finally(() => (loading.value = false));
await delFinInvoiceInfo(_invoiceIds);
proxy?.$modal.msgSuccess('删除成功');
await getList();
};
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download(
'oa/erp/finInvoiceInfo/export',
{
...queryParams.value
},
`finInvoiceInfo_${new Date().getTime()}.xlsx`
);
};
onMounted(() => {
getList();
});
onActivated(() => {
getList();
});
</script>
Loading…
Cancel
Save