|
@@ -0,0 +1,390 @@
|
|
|
+<script setup lang="ts">
|
|
|
+import { ref } from "vue";
|
|
|
+import { ElMessage } from "element-plus";
|
|
|
+import { execlUpload } from "/@/components/execlUpload";
|
|
|
+import { httpBatchAdd } from "/@/api/purchase/ticketReturn";
|
|
|
+import { useResponseHandle } from "/@/hooks";
|
|
|
+import { useCompany } from "/@/hooks/core/useCompany";
|
|
|
+
|
|
|
+import {
|
|
|
+ initheaders,
|
|
|
+ columns,
|
|
|
+ mapProp,
|
|
|
+ requireHeaders
|
|
|
+} from "./columns-config";
|
|
|
+import { cg_inv_type_list } from "/@/utils/status";
|
|
|
+
|
|
|
+const visible = ref(false);
|
|
|
+const loading = ref(false);
|
|
|
+const tableData = ref([]);
|
|
|
+const columnsConfig = columns();
|
|
|
+const emit = defineEmits(["onSuccess"]);
|
|
|
+
|
|
|
+const allTypes = cg_inv_type_list.map(({ label }) => label);
|
|
|
+
|
|
|
+const row = ref(1);
|
|
|
+
|
|
|
+const createInvErrorMessage = (row: string) =>
|
|
|
+ `导入数据第 ${row} 行 发票类型格式不正确,发票类型必须为${allTypes.join(",")}`;
|
|
|
+
|
|
|
+const { currentCompany } = useCompany();
|
|
|
+
|
|
|
+const responseHandle = useResponseHandle();
|
|
|
+
|
|
|
+const Uploadsuccess = ({ results, header }) => {
|
|
|
+ loading.value = true;
|
|
|
+
|
|
|
+ if (results.length === 0) {
|
|
|
+ ElMessage.error("表格无有效数据!");
|
|
|
+ loading.value = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ let headok = true;
|
|
|
+ if (header.length !== initheaders.length) {
|
|
|
+ headok = false;
|
|
|
+ } else {
|
|
|
+ initheaders.forEach((si, sii) => {
|
|
|
+ if (si !== header[sii]) {
|
|
|
+ headok = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!headok) {
|
|
|
+ ElMessage.error("表头与导入模板不匹配!");
|
|
|
+ loading.value = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ tableData.value = [];
|
|
|
+
|
|
|
+ for (const v1 of results) {
|
|
|
+ const b = Object.values(v1);
|
|
|
+ let model = {};
|
|
|
+ b.forEach((si, sii) => {
|
|
|
+ model["value" + sii] = si + "";
|
|
|
+ });
|
|
|
+ tableData.value.push(model);
|
|
|
+ row.value = row.value + 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ const data = [];
|
|
|
+ tableData.value.forEach((key, index) => {
|
|
|
+ const obj: Record<string, string> = {};
|
|
|
+
|
|
|
+ for (let i in key) {
|
|
|
+ const prop = mapProp[i];
|
|
|
+ const value = key[i];
|
|
|
+ obj[prop] = value;
|
|
|
+ }
|
|
|
+
|
|
|
+ data.push(obj);
|
|
|
+ });
|
|
|
+
|
|
|
+ const typeErrors: string[] = [];
|
|
|
+ const checkErrors: string[] = [];
|
|
|
+ const codeErrors: string[] = [];
|
|
|
+ const numberErrors: string[] = [];
|
|
|
+ const priceErrors: string[] = [];
|
|
|
+
|
|
|
+ data.forEach((row, index) => {
|
|
|
+ const source = row.invoiceType.trim();
|
|
|
+ const target = cg_inv_type_list.find(({ label }) => label === source);
|
|
|
+
|
|
|
+ if (!target) {
|
|
|
+ typeErrors.push(String(index + 1));
|
|
|
+ } else {
|
|
|
+ row.invoiceType = target.value;
|
|
|
+
|
|
|
+ if (
|
|
|
+ (target.value === "normal" || target.value === "electronic") &&
|
|
|
+ !row.checkNumber
|
|
|
+ ) {
|
|
|
+ checkErrors.push(String(index + 1));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const reg = /^\d+(\.\d+)?$/;
|
|
|
+
|
|
|
+ if (!reg.test(row.invoiceCode)) {
|
|
|
+ codeErrors.push(String(index + 1));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (!reg.test(row.invoiceNumber)) {
|
|
|
+ numberErrors.push(String(index + 1));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!reg.test(row.inv_subtotal_amount) || Number(row.inv_subtotal_amount) < 0) {
|
|
|
+ priceErrors.push(String(index + 1));
|
|
|
+ }
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ if (typeErrors.length > 0) {
|
|
|
+ ElMessage({
|
|
|
+ type: "error",
|
|
|
+ message: createInvErrorMessage(typeErrors.join(","))
|
|
|
+ });
|
|
|
+ loading.value = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (checkErrors.length > 0) {
|
|
|
+ ElMessage({
|
|
|
+ type: "error",
|
|
|
+ message: `第 ${checkErrors.join(",")} 行,校验码不能为空。`
|
|
|
+ });
|
|
|
+ loading.value = false;
|
|
|
+ tableData.value = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (codeErrors.length > 0) {
|
|
|
+ ElMessage({
|
|
|
+ type: "error",
|
|
|
+ message: `第 ${codeErrors.join(",")} 行,发票代码必须为数字。`
|
|
|
+ });
|
|
|
+ loading.value = false;
|
|
|
+ tableData.value = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (numberErrors.length > 0) {
|
|
|
+ ElMessage({
|
|
|
+ type: "error",
|
|
|
+ message: `第 ${numberErrors.join(",")} 行,发票号码必须为数字。`
|
|
|
+ });
|
|
|
+ loading.value = false;
|
|
|
+ tableData.value = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (priceErrors.length > 0) {
|
|
|
+ ElMessage({
|
|
|
+ type: "error",
|
|
|
+ message: `第 ${priceErrors.join(",")} 行,发票税前金额必须为数字且不能是负数`
|
|
|
+ });
|
|
|
+ loading.value = false;
|
|
|
+ tableData.value = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ loading.value = false;
|
|
|
+};
|
|
|
+
|
|
|
+//提交
|
|
|
+const handleSubmit = async () => {
|
|
|
+ try {
|
|
|
+ if (loading.value) return;
|
|
|
+ loading.value = true;
|
|
|
+
|
|
|
+ const data = [];
|
|
|
+
|
|
|
+ tableData.value.forEach((key, index) => {
|
|
|
+ const obj: Record<string, string> = {};
|
|
|
+
|
|
|
+ for (let i in key) {
|
|
|
+ const prop = mapProp[i];
|
|
|
+ const value = key[i];
|
|
|
+ obj[prop] = value;
|
|
|
+ }
|
|
|
+ data.push(obj);
|
|
|
+ });
|
|
|
+
|
|
|
+ const typeErrors: string[] = [];
|
|
|
+ const checkErrors: string[] = [];
|
|
|
+ const codeErrors: string[] = [];
|
|
|
+ const numberErrors: string[] = [];
|
|
|
+ const priceErrors: string[] = [];
|
|
|
+
|
|
|
+ data.forEach((row, index) => {
|
|
|
+ const source = row.invoiceType.trim();
|
|
|
+ const target = cg_inv_type_list.find(({ label }) => label === source);
|
|
|
+
|
|
|
+ if (!target) {
|
|
|
+ typeErrors.push(String(index + 1));
|
|
|
+ } else {
|
|
|
+ row.invoiceType = target.value;
|
|
|
+
|
|
|
+ if (
|
|
|
+ (target.value === "normal" || target.value === "electronic") &&
|
|
|
+ !row.checkNumber
|
|
|
+ ) {
|
|
|
+ checkErrors.push(String(index + 1));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const reg = /^\d+(\.\d+)?$/;
|
|
|
+
|
|
|
+ if (!reg.test(row.invoiceCode)) {
|
|
|
+ codeErrors.push(String(index + 1));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (!reg.test(row.invoiceNumber)) {
|
|
|
+ numberErrors.push(String(index + 1));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!reg.test(row.inv_subtotal_amount) || Number(row.inv_subtotal_amount) < 0) {
|
|
|
+ priceErrors.push(String(index + 1));
|
|
|
+ }
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ if (typeErrors.length > 0) {
|
|
|
+ ElMessage({
|
|
|
+ type: "error",
|
|
|
+ message: createInvErrorMessage(typeErrors.join(","))
|
|
|
+ });
|
|
|
+ loading.value = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (checkErrors.length > 0) {
|
|
|
+ ElMessage({
|
|
|
+ type: "error",
|
|
|
+ message: `第 ${checkErrors.join(",")} 行,校验码不能为空。`
|
|
|
+ });
|
|
|
+ loading.value = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (codeErrors.length > 0) {
|
|
|
+ ElMessage({
|
|
|
+ type: "error",
|
|
|
+ message: `第 ${codeErrors.join(",")} 行,发票代码必须为数字。`
|
|
|
+ });
|
|
|
+ loading.value = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (numberErrors.length > 0) {
|
|
|
+ ElMessage({
|
|
|
+ type: "error",
|
|
|
+ message: `第 ${numberErrors.join(",")} 行,发票号码必须为数字。`
|
|
|
+ });
|
|
|
+ loading.value = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (priceErrors.length > 0) {
|
|
|
+ ElMessage({
|
|
|
+ type: "error",
|
|
|
+ message: `第 ${priceErrors.join(",")} 行,发票税前金额必须为数字且不能是负数`
|
|
|
+ });
|
|
|
+ loading.value = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const buyers = data.map(({ supplierNo }) => supplierNo);
|
|
|
+ const setBuyers = [...new Set(buyers)];
|
|
|
+
|
|
|
+ if (setBuyers.length > 1) {
|
|
|
+ ElMessage.error("卖方公司编码不一致");
|
|
|
+ loading.value = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const supplierNo = data[0].supplierNo;
|
|
|
+
|
|
|
+ data.forEach(item => {
|
|
|
+ delete item["supplierNo"];
|
|
|
+ });
|
|
|
+
|
|
|
+ const { code, message } = await httpBatchAdd({
|
|
|
+ list: data,
|
|
|
+ supplierNo,
|
|
|
+ companyNo:currentCompany.value.companyNo,
|
|
|
+ relaComNo: currentCompany.value.companyNo
|
|
|
+ });
|
|
|
+
|
|
|
+ loading.value = false;
|
|
|
+
|
|
|
+ responseHandle({
|
|
|
+ code,
|
|
|
+ message,
|
|
|
+ noMessage: false,
|
|
|
+ handler: () => {
|
|
|
+ ElMessage.success("数据导入成功!");
|
|
|
+ emit("onSuccess");
|
|
|
+ visible.value = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } catch (err) {
|
|
|
+ console.log(err)
|
|
|
+ }
|
|
|
+};
|
|
|
+const cancel = () => {
|
|
|
+ tableData.value = [];
|
|
|
+};
|
|
|
+defineExpose({
|
|
|
+ onDisplay: () => ((visible.value = true), (tableData.value = []))
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <el-dialog
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ v-model="visible"
|
|
|
+ title="批量导入开票数据"
|
|
|
+ width="1040px"
|
|
|
+ top="8vh"
|
|
|
+ center
|
|
|
+ >
|
|
|
+ <execlUpload @on-success="Uploadsuccess" v-if="tableData.length === 0" />
|
|
|
+
|
|
|
+ <el-table
|
|
|
+ :data="tableData"
|
|
|
+ stripe
|
|
|
+ border
|
|
|
+ max-height="500px"
|
|
|
+ size="small"
|
|
|
+ style="width: 100%"
|
|
|
+ >
|
|
|
+ <el-table-column
|
|
|
+ v-for="(si, sii) in columnsConfig"
|
|
|
+ :type="si.type"
|
|
|
+ :minWidth="si.minWidth"
|
|
|
+ :fixed="si.fixed"
|
|
|
+ :key="sii"
|
|
|
+ :prop="si.prop"
|
|
|
+ show-overflow-tooltip
|
|
|
+ >
|
|
|
+ <template #header>
|
|
|
+ <span
|
|
|
+ v-if="
|
|
|
+ !requireHeaders.includes(mapProp[si.prop]) || si.label === '序号'
|
|
|
+ "
|
|
|
+ >{{ si.label }}</span
|
|
|
+ >
|
|
|
+ <p v-else>
|
|
|
+ <span style="color: #f56c6c; font-size: 14px">* </span>
|
|
|
+ {{ si.label }}
|
|
|
+ </p>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ <div
|
|
|
+ flex
|
|
|
+ justify-end
|
|
|
+ gap-2
|
|
|
+ v-if="tableData.length !== 0"
|
|
|
+ style="padding: 10px 0 0 0"
|
|
|
+ >
|
|
|
+ <el-button size="small" @click="cancel">取消</el-button>
|
|
|
+ <el-button
|
|
|
+ size="small"
|
|
|
+ type="primary"
|
|
|
+ :loading="loading"
|
|
|
+ @click="handleSubmit"
|
|
|
+ >保存</el-button
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style lang="scss" scoped></style>
|