|
|
@@ -1,5 +1,5 @@
|
|
|
<template>
|
|
|
- <el-dialog :title="dialog.title" v-model="dialog.visible" width="900px" append-to-body>
|
|
|
+ <el-dialog :title="dialog.title" v-model="dialog.visible" width="960px" append-to-body>
|
|
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
|
|
|
<el-divider content-position="left">基本信息</el-divider>
|
|
|
<el-row :gutter="20">
|
|
|
@@ -178,6 +178,58 @@
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
|
|
|
+ <el-divider content-position="left">开票信息</el-divider>
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="单位名称(章)">
|
|
|
+ <el-input v-model="invoiceForm.companyName" placeholder="选填;填写任意开票项时此项必填" maxlength="200" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="单位地址">
|
|
|
+ <el-input v-model="invoiceForm.companyAddress" placeholder="请输入单位地址" maxlength="500" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="法定代表人">
|
|
|
+ <el-input v-model="invoiceForm.legalRepresentative" placeholder="请输入法定代表人" maxlength="100" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="代理人">
|
|
|
+ <el-input v-model="invoiceForm.agent" placeholder="请输入代理人" maxlength="100" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="电话/传真">
|
|
|
+ <el-input v-model="invoiceForm.phoneFax" placeholder="请输入电话/传真" maxlength="100" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="开户银行">
|
|
|
+ <el-input v-model="invoiceForm.bankName" placeholder="请输入开户银行" maxlength="200" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="账号">
|
|
|
+ <el-input v-model="invoiceForm.bankAccount" placeholder="请输入账号" maxlength="100" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="是否默认">
|
|
|
+ <el-radio-group v-model="invoiceForm.isDefault">
|
|
|
+ <el-radio label="1">是</el-radio>
|
|
|
+ <el-radio label="0">否</el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="开票备注">
|
|
|
+ <el-input v-model="invoiceForm.remark" type="textarea" placeholder="请输入开票相关备注" maxlength="500" :rows="2" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
<el-row>
|
|
|
<el-col :span="24">
|
|
|
<el-form-item label="备注" prop="remark">
|
|
|
@@ -200,6 +252,8 @@ import { ref, reactive, getCurrentInstance, toRefs } from 'vue';
|
|
|
import type { FormItemRule } from 'element-plus';
|
|
|
import { getCustomer, addCustomer, updateCustomer } from '@/api/crm/customer';
|
|
|
import type { CustomerForm as CustomerFormType } from '@/api/crm/customer/types';
|
|
|
+import { getInvoiceInfoByCustomerId, addInvoiceInfo, updateInvoiceInfo } from '@/api/crm/invoiceInfo';
|
|
|
+import type { InvoiceInfoForm } from '@/api/crm/invoiceInfo';
|
|
|
import { ComponentInternalInstance } from 'vue';
|
|
|
import { listUser } from '@/api/system/user';
|
|
|
import { useDict } from '@/utils/dict';
|
|
|
@@ -244,6 +298,108 @@ const form = ref<CustomerFormType>({
|
|
|
otherCertImages: undefined
|
|
|
});
|
|
|
|
|
|
+/** 弹窗内维护的一条开票信息(与详情页「开票信息」字段一致;编辑时加载默认或第一条) */
|
|
|
+const invoiceForm = ref({
|
|
|
+ id: undefined as number | string | undefined,
|
|
|
+ companyName: '',
|
|
|
+ companyAddress: '',
|
|
|
+ legalRepresentative: '',
|
|
|
+ agent: '',
|
|
|
+ phoneFax: '',
|
|
|
+ bankName: '',
|
|
|
+ bankAccount: '',
|
|
|
+ isDefault: '1',
|
|
|
+ remark: ''
|
|
|
+});
|
|
|
+
|
|
|
+function resetInvoiceForm() {
|
|
|
+ invoiceForm.value = {
|
|
|
+ id: undefined,
|
|
|
+ companyName: '',
|
|
|
+ companyAddress: '',
|
|
|
+ legalRepresentative: '',
|
|
|
+ agent: '',
|
|
|
+ phoneFax: '',
|
|
|
+ bankName: '',
|
|
|
+ bankAccount: '',
|
|
|
+ isDefault: '1',
|
|
|
+ remark: ''
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+/** 是否填写了任意开票字段(含单位名称) */
|
|
|
+function isInvoiceBlockFilled(): boolean {
|
|
|
+ const f = invoiceForm.value;
|
|
|
+ const keys = [
|
|
|
+ 'companyName',
|
|
|
+ 'companyAddress',
|
|
|
+ 'legalRepresentative',
|
|
|
+ 'agent',
|
|
|
+ 'phoneFax',
|
|
|
+ 'bankName',
|
|
|
+ 'bankAccount',
|
|
|
+ 'remark'
|
|
|
+ ] as const;
|
|
|
+ return keys.some((k) => {
|
|
|
+ const v = f[k];
|
|
|
+ return v != null && String(v).trim() !== '';
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+function buildInvoicePayload(customerId: number | string): InvoiceInfoForm {
|
|
|
+ const f = invoiceForm.value;
|
|
|
+ // 必须字符串提交:JS Number 无法安全表示雪花 Long,JSON 会变成错误数值
|
|
|
+ const cid = String(customerId);
|
|
|
+ return {
|
|
|
+ id: f.id,
|
|
|
+ customerId: cid,
|
|
|
+ companyName: f.companyName.trim(),
|
|
|
+ companyAddress: f.companyAddress?.trim() || undefined,
|
|
|
+ legalRepresentative: f.legalRepresentative?.trim() || undefined,
|
|
|
+ agent: f.agent?.trim() || undefined,
|
|
|
+ phoneFax: f.phoneFax?.trim() || undefined,
|
|
|
+ bankName: f.bankName?.trim() || undefined,
|
|
|
+ bankAccount: f.bankAccount?.trim() || undefined,
|
|
|
+ isDefault: f.isDefault,
|
|
|
+ remark: f.remark?.trim() || undefined
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+async function loadInvoiceForEdit(customerId: number | string) {
|
|
|
+ resetInvoiceForm();
|
|
|
+ try {
|
|
|
+ const res = await getInvoiceInfoByCustomerId(customerId);
|
|
|
+ const rows = (res as { data?: any[] }).data || [];
|
|
|
+ const row = rows.find((i) => i.isDefault === '1') || rows[0];
|
|
|
+ if (row) {
|
|
|
+ invoiceForm.value = {
|
|
|
+ id: row.id,
|
|
|
+ companyName: row.companyName ?? '',
|
|
|
+ companyAddress: row.companyAddress ?? '',
|
|
|
+ legalRepresentative: row.legalRepresentative ?? '',
|
|
|
+ agent: row.agent ?? '',
|
|
|
+ phoneFax: row.phoneFax ?? '',
|
|
|
+ bankName: row.bankName ?? '',
|
|
|
+ bankAccount: row.bankAccount ?? '',
|
|
|
+ isDefault: row.isDefault ?? '1',
|
|
|
+ remark: row.remark ?? ''
|
|
|
+ };
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error(e);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+async function syncInvoiceAfterCustomerSave(customerId: number | string) {
|
|
|
+ if (!isInvoiceBlockFilled()) return;
|
|
|
+ const payload = buildInvoicePayload(customerId);
|
|
|
+ if (invoiceForm.value.id) {
|
|
|
+ await updateInvoiceInfo({ ...payload, id: invoiceForm.value.id });
|
|
|
+ } else {
|
|
|
+ await addInvoiceInfo({ ...payload, id: undefined });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// 表单校验规则
|
|
|
const rules = ref<Record<string, FormItemRule[]>>({
|
|
|
customerName: [{ required: true, message: '客户名称不能为空', trigger: 'blur' }],
|
|
|
@@ -296,7 +452,7 @@ const dialog = reactive({
|
|
|
const formRef = ref();
|
|
|
|
|
|
/** 打开对话框 */
|
|
|
-const open = async (id?: number) => {
|
|
|
+const open = async (id?: number | string) => {
|
|
|
reset();
|
|
|
dialog.visible = true;
|
|
|
|
|
|
@@ -308,11 +464,13 @@ const open = async (id?: number) => {
|
|
|
try {
|
|
|
const res = await getCustomer(id);
|
|
|
Object.assign(form.value, res.data);
|
|
|
+ await loadInvoiceForEdit(id);
|
|
|
} catch (error) {
|
|
|
console.error(error);
|
|
|
}
|
|
|
} else {
|
|
|
dialog.title = '新增客户';
|
|
|
+ resetInvoiceForm();
|
|
|
// 默认负责人为当前用户
|
|
|
form.value.ownerUserId = userStore.userId;
|
|
|
}
|
|
|
@@ -331,20 +489,28 @@ const loadUserList = async () => {
|
|
|
/** 提交表单 */
|
|
|
const submitForm = () => {
|
|
|
formRef.value?.validate(async (valid: boolean) => {
|
|
|
- if (valid) {
|
|
|
- try {
|
|
|
- if (form.value.id) {
|
|
|
- await updateCustomer(form.value);
|
|
|
- proxy?.$modal.msgSuccess('修改成功');
|
|
|
- } else {
|
|
|
- await addCustomer(form.value);
|
|
|
- proxy?.$modal.msgSuccess('新增成功');
|
|
|
+ if (!valid) return;
|
|
|
+ if (isInvoiceBlockFilled() && !invoiceForm.value.companyName?.trim()) {
|
|
|
+ proxy?.$modal.msgWarning('已填写开票信息时,单位名称(章)不能为空');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ if (form.value.id) {
|
|
|
+ await updateCustomer(form.value);
|
|
|
+ await syncInvoiceAfterCustomerSave(form.value.id);
|
|
|
+ proxy?.$modal.msgSuccess('修改成功');
|
|
|
+ } else {
|
|
|
+ const res = await addCustomer(form.value);
|
|
|
+ const newId = (res as { data?: string | number }).data;
|
|
|
+ if (newId != null && isInvoiceBlockFilled()) {
|
|
|
+ await syncInvoiceAfterCustomerSave(String(newId));
|
|
|
}
|
|
|
- dialog.visible = false;
|
|
|
- emit('success');
|
|
|
- } catch (error) {
|
|
|
- console.error(error);
|
|
|
+ proxy?.$modal.msgSuccess('新增成功');
|
|
|
}
|
|
|
+ dialog.visible = false;
|
|
|
+ emit('success');
|
|
|
+ } catch (error) {
|
|
|
+ console.error(error);
|
|
|
}
|
|
|
});
|
|
|
};
|
|
|
@@ -383,6 +549,7 @@ const reset = () => {
|
|
|
businessPermitImages: undefined,
|
|
|
otherCertImages: undefined
|
|
|
};
|
|
|
+ resetInvoiceForm();
|
|
|
formRef.value?.resetFields();
|
|
|
};
|
|
|
|