|
|
@@ -0,0 +1,361 @@
|
|
|
+<template>
|
|
|
+ <div class="ticket">
|
|
|
+ <div class="search-list">
|
|
|
+ <div class="search-left">
|
|
|
+ <el-select v-model="logicJudge">
|
|
|
+ <el-option value="and" label="并且"></el-option>
|
|
|
+ <el-option value="or" label="或者"></el-option>
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ <div class="search-right">
|
|
|
+ <div class="search-type" v-for="(item, index) in searchList">
|
|
|
+ <el-select v-model="item.name" style="margin-right: 20px; width: 220px" disabled>
|
|
|
+ <el-option value="companyId" label="保险公司"></el-option>
|
|
|
+ <el-option value="signYear" label="年份"></el-option>
|
|
|
+ </el-select>
|
|
|
+ <el-select v-model="item.type" v-if="item.name != 'signDate'" style="margin-right: 20px; width: 150px"
|
|
|
+ @change="val => signDateSelectChange(index, val)">
|
|
|
+ <el-option value="等于" label="等于"></el-option>
|
|
|
+ <el-option value="包含" label="包含"></el-option>
|
|
|
+ </el-select>
|
|
|
+ <el-select class="w-350px" v-if="item.name == 'companyId'" v-model="item.search" placeholder="请选择" clearable
|
|
|
+ filterable :disabled="item.type == '为空'">
|
|
|
+ <el-option v-for="item in companyList" :key="item.id" :value="item.id" :label="item.name"></el-option>
|
|
|
+ </el-select>
|
|
|
+ <el-date-picker v-if="item.name == 'signYear'" style="width: 350px" format="YYYY" value-format="YYYY"
|
|
|
+ v-model="yearrangesearch" type="yearrange" range-separator="-" :disabled="item.type == '为空'"
|
|
|
+ @change="handlePtlAgreementChange(index, $event)" />
|
|
|
+ </div>
|
|
|
+ <el-button type="primary" class="w-88px" @click="initData">搜索</el-button>
|
|
|
+
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <el-table :data="tableData" ref="tableRef" style="height: calc(100% - 160px)" @select="handleSelection"
|
|
|
+ @select-all="handleSelectAll">
|
|
|
+ <el-table-column type="selection" width="50" fixed="left" :selectable="selectable"></el-table-column>
|
|
|
+ <el-table-column prop="partnerCompanyName" label="保险公司"></el-table-column>
|
|
|
+ <el-table-column prop="year" label="年"></el-table-column>
|
|
|
+ <el-table-column prop="month" label="月"></el-table-column>
|
|
|
+ <el-table-column prop="receivablePremium" label="应收总额"></el-table-column>
|
|
|
+ <el-table-column prop="invoiced" label="已开票"></el-table-column>
|
|
|
+ <el-table-column prop="uninvoiced" label="未开票"></el-table-column>
|
|
|
+ </el-table>
|
|
|
+ <div class="footer">
|
|
|
+ <el-button plain @click="router.back()">取消</el-button>
|
|
|
+ <el-button plain type="primary" @click="handleTicket(true)">开票并结算</el-button>
|
|
|
+ <el-button type="primary" @click="handleTicket(false)">开票</el-button>
|
|
|
+ </div>
|
|
|
+ <el-dialog :close-on-click-modal="false" v-model="countShow" width="600" :title="isSettlement ? '开票并结算' : '开票'">
|
|
|
+ <el-form ref="CountForm" :model="countForm" :rules="countRules" label-width="120">
|
|
|
+ <el-form-item prop="invoiceParty" label="开票方">
|
|
|
+ <el-select v-model="countForm.invoiceParty" placeholder="请选择开票方">
|
|
|
+ <el-option label="我方开票" value="1"></el-option>
|
|
|
+ <el-option label="保司开票" value="2"></el-option>
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item prop="invoiceNo" label="开票号" v-if="countForm.invoiceParty == '1'">
|
|
|
+ <el-input v-model="countForm.invoiceNo" placeholder="请输入"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item prop="taxPoint" label="税点">
|
|
|
+ <el-input v-model="countForm.taxPoint" placeholder="请输入"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item prop="receivableSupervisePremium" label="应收金额">
|
|
|
+ <el-input v-model="receivableSupervisePremium" placeholder="请输入" disabled></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item prop="receivableSupervisePremium" label="开票金额">
|
|
|
+ <el-input-number :disabled="selectedList.length > 1" v-model="countForm.receivableSupervisePremium"
|
|
|
+ style="width: 100%;" :min="0" :precision="2" controls-position="right"
|
|
|
+ @change="handleChange(); handleChange1()" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item prop="overinflatedAmount" label="虚增金额">
|
|
|
+ <el-input v-model="countForm.overinflatedAmount" disabled></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item prop="paymentReason" label="虚增金额原因">
|
|
|
+ <el-input v-model="countForm.paymentReason" placeholder="请输入"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item v-if="isSettlement" prop="actualReceivedAmount" label="实收金额">
|
|
|
+ <el-input-number v-model="countForm.actualReceivedAmount" style="width: 100%;" :min="0"
|
|
|
+ :max="countForm.receivableSupervisePremium" :precision="2" controls-position="right"
|
|
|
+ @change="handleChange" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item v-if="isSettlement" prop="settlementPaymentDifference" label="回款差额">
|
|
|
+ <el-input v-model="countForm.settlementPaymentDifference" disabled></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item v-if="isSettlement" prop="settlementPaymentReason" label="差额原因">
|
|
|
+ <el-input v-model="countForm.settlementPaymentReason" placeholder="请输入"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item prop="invoiceTime" label="开票日期">
|
|
|
+ <el-date-picker v-model="countForm.invoiceTime" style="width: 100%;" type="date"
|
|
|
+ value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item v-if="isSettlement" prop="receivePaymentDate" label="收款日期">
|
|
|
+ <el-date-picker v-model="countForm.receivePaymentDate" style="width: 100%;" type="date"
|
|
|
+ value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item v-if="isSettlement" prop="attachmentIds" label="收款凭证" class="upload-btn">
|
|
|
+ <el-upload action="https://tennat.baoxianzhanggui.com/api/file/upload" drag
|
|
|
+ v-model:file-list="countForm.attachmentIds" multiple list-type="picture-card">
|
|
|
+ <el-icon>
|
|
|
+ <Plus />
|
|
|
+ </el-icon>
|
|
|
+ </el-upload>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <el-button class="border-[#0083FF] color-[#0083FF]" plain @click="countShow = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="handelComfirm()">确定</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import api from '@/api'
|
|
|
+import { useRoute, useRouter } from 'vue-router'
|
|
|
+
|
|
|
+import { ElMessage } from "element-plus";
|
|
|
+import { getLeft } from '@imengyu/vue3-context-menu/lib/ContextMenuUtils';
|
|
|
+
|
|
|
+let route = useRoute()
|
|
|
+let router = useRouter()
|
|
|
+const selectedList = ref([])//选中的应收单据
|
|
|
+const companyList = ref()//保险公司
|
|
|
+const year = new Date().getFullYear() + ''
|
|
|
+const yearrangesearch = ref([year, year])
|
|
|
+
|
|
|
+const countShow = ref(false)
|
|
|
+const countForm = ref({})
|
|
|
+
|
|
|
+const tableRef = ref('')
|
|
|
+
|
|
|
+const selCompanyId = ref('')
|
|
|
+/** 处理选择变更,更新选中的公司ID和选中列表 */
|
|
|
+const handleSelection = (val: any) => {
|
|
|
+ if (val.length) selCompanyId.value = val[0].partnerCompanyId
|
|
|
+ if (!val.length) selCompanyId.value = ''
|
|
|
+ selectedList.value = val
|
|
|
+}
|
|
|
+/** 处理全选/多选操作,确保所选行仅限于同一合作公司:选取首项的公司ID作为当前选中公司,过滤掉不同公司的选项并取消其选中状态 */
|
|
|
+const handleSelectAll = (val: any) => {
|
|
|
+ if (val.length) selCompanyId.value = val[0].partnerCompanyId
|
|
|
+ if (!val.length) selCompanyId.value = ''
|
|
|
+ selectedList.value = val.filter(v => v.partnerCompanyId === selCompanyId.value)
|
|
|
+ val.filter(v => v.partnerCompanyId !== selCompanyId.value).forEach(v => tableRef.value.toggleRowSelection(v, false));
|
|
|
+}
|
|
|
+
|
|
|
+const selectable = (row: any, index: number) => {
|
|
|
+ if (!selCompanyId.value) return true
|
|
|
+ if (row.partnerCompanyId == selCompanyId.value) return true
|
|
|
+ return false
|
|
|
+}
|
|
|
+
|
|
|
+//保险公司协议
|
|
|
+
|
|
|
+let logicJudge = ref('and')
|
|
|
+let searchList = ref([
|
|
|
+ {
|
|
|
+ name: 'companyId',
|
|
|
+ type: '等于',
|
|
|
+ search: ''
|
|
|
+ }, {
|
|
|
+ name: 'signYear',
|
|
|
+ type: '等于',
|
|
|
+ search: ''
|
|
|
+ }
|
|
|
+])
|
|
|
+const datesearch = ref('')
|
|
|
+
|
|
|
+// 出单协议多选转换
|
|
|
+const handlePtlAgreementChange = (index: any, e: any) => {
|
|
|
+ if (Array.isArray(e)) {
|
|
|
+ searchList.value[index].search = e.join(',') || ''
|
|
|
+ } else {
|
|
|
+ searchList.value[index].search = e || ''
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 签单时间选择器改变时触发
|
|
|
+const signDateSelectChange = (index: any, e: any) => {
|
|
|
+ switch (e) {
|
|
|
+ case '为空':
|
|
|
+ searchList.value[index].search = ''
|
|
|
+ break;
|
|
|
+ case '大于等于':
|
|
|
+ case '小于等于':
|
|
|
+ searchList.value[index].search = ''
|
|
|
+ datesearch.value = ''
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+let tableData = ref([])
|
|
|
+const receivableSupervisePremium = ref('')
|
|
|
+const isSettlement = ref(false)
|
|
|
+const handleTicket = async (bool: boolean) => {
|
|
|
+ if (selectedList.value.length == 0) {
|
|
|
+ ElMessage.error('请选择应收单据')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ isSettlement.value = bool
|
|
|
+ const arr = selectedList.value.map(v => v.uninvoiced)
|
|
|
+ const res = await api.financeApi.calculateTotalSum(arr.join())
|
|
|
+ if (res.code == 200) {
|
|
|
+ openCountForm()
|
|
|
+ countForm.value.companyId = selectedList.value[0].companyId
|
|
|
+ receivableSupervisePremium.value = res.data
|
|
|
+ if (selectedList.value.length > 1) countForm.value.receivableSupervisePremium = res.data
|
|
|
+ if (selectedList.value.length === 1) countForm.value.selectFlag = 0
|
|
|
+ handleChange1()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/** 计算实收金额与应收监管保费的差值,并将结果赋值给付款差额字段 */
|
|
|
+const handleChange = async () => {
|
|
|
+ const num = await calSub(countForm.value.actualReceivedAmount, countForm.value.receivableSupervisePremium)
|
|
|
+ countForm.value.settlementPaymentDifference = num
|
|
|
+}
|
|
|
+/** 计算应收监管保费差额并更新虚增金额 */
|
|
|
+
|
|
|
+const handleChange1 = async () => {
|
|
|
+ const num = await calSub(countForm.value.receivableSupervisePremium, receivableSupervisePremium.value)
|
|
|
+ countForm.value.overinflatedAmount = num
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 计算两个数值的差值(被减数 - 减数)
|
|
|
+ * @param minuend 被减数
|
|
|
+ * @param subtrahend 减数
|
|
|
+ * @returns 差值,若接口无数据则返回 0
|
|
|
+ */
|
|
|
+const calSub = async (minuend: number = 0, subtrahend: number) => {
|
|
|
+ const res = await api.financeApi.calSub({ minuend, subtrahend })
|
|
|
+ return res.data || 0
|
|
|
+}
|
|
|
+
|
|
|
+const openCountForm = () => {
|
|
|
+ countForm.value = {
|
|
|
+ selectFlag: 1
|
|
|
+ }
|
|
|
+ countShow.value = true
|
|
|
+}
|
|
|
+const handelComfirm = () => {
|
|
|
+ const attachmentIds = countForm.value.attachmentIds?.map(v => v.response.data.id)
|
|
|
+ let params: any = {
|
|
|
+ details: selectedList.value,
|
|
|
+ ...countForm.value,
|
|
|
+ attachmentIds
|
|
|
+ }
|
|
|
+ let apiFn = api.financeApi.followInvoicing
|
|
|
+ if (isSettlement.value) {
|
|
|
+ apiFn = api.financeApi.followInvoiceAndSettlement
|
|
|
+ params = {
|
|
|
+ invoiceVO: params,
|
|
|
+ ...countForm.value,
|
|
|
+ attachmentIds
|
|
|
+ }
|
|
|
+ }
|
|
|
+ apiFn(params).then((sub: any) => {
|
|
|
+ if (sub.code == 200) {
|
|
|
+ countShow.value = false
|
|
|
+ ElMessage({
|
|
|
+ message: sub.msg,
|
|
|
+ type: 'success'
|
|
|
+ })
|
|
|
+ initData()
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const initData = () => {
|
|
|
+ handlePtlAgreementChange(1, yearrangesearch.value)
|
|
|
+ const params = {
|
|
|
+ searchList: searchList.value,
|
|
|
+ logicJudge: logicJudge.value,
|
|
|
+ }
|
|
|
+ api.financeApi.followInvoicePageList(params).then((res: any) => {
|
|
|
+ if (res.code == 200) {
|
|
|
+ tableData.value = res.data
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+// 保险公司
|
|
|
+const initCompany = () => {
|
|
|
+ api.insuranceApi.leftList('').then((res: any) => {
|
|
|
+ if (res.code == 200) {
|
|
|
+ companyList.value = res.data
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ initData()
|
|
|
+ initCompany()
|
|
|
+})
|
|
|
+
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+.ticket {
|
|
|
+ height: calc(100vh - 135px);
|
|
|
+ width: calc(100% - 24px);
|
|
|
+ margin: 12px auto;
|
|
|
+ padding: 12px;
|
|
|
+ background: #FFFFFF;
|
|
|
+ overflow-y: auto;
|
|
|
+
|
|
|
+ .search-list {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: flex-start;
|
|
|
+
|
|
|
+ .search-left {
|
|
|
+ width: 150px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ margin-right: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .search-right {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(1, 1fr);
|
|
|
+ gap: 0 12px;
|
|
|
+
|
|
|
+ .search-type {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: flex-start;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .tips {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: flex-start;
|
|
|
+
|
|
|
+ p {
|
|
|
+ margin-right: 30px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .footer {
|
|
|
+ width: 100%;
|
|
|
+ position: fixed;
|
|
|
+ left: 0;
|
|
|
+ bottom: 0;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ height: 80px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.el-upload-dragger) {
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+</style>
|