hurx 1 ay önce
ebeveyn
işleme
f42b61b0a6

+ 16 - 0
src/api/customer/customerFile/customerContact/index.ts

@@ -61,3 +61,19 @@ export const delCustomerContact = (id: string | number | Array<string | number>)
     method: 'delete'
   });
 };
+
+/**
+ * 修改主联系人
+ * @param id
+ */
+export function changeIsPrimary(id: string | number, isPrimary: string) {
+  const data = {
+    id,
+    isPrimary
+  };
+  return request({
+    url: '/customer/customerContact/changeIsPrimary',
+    method: 'put',
+    data: data
+  });
+}

+ 4 - 0
src/api/customer/customerFile/customerContact/types.ts

@@ -9,6 +9,8 @@ export interface CustomerContactVO {
    */
   customerId: string | number;
 
+  contactNo: string;
+
   /**
    * 联系人姓名
    */
@@ -101,6 +103,8 @@ export interface CustomerContactForm extends BaseEntity {
    */
   customerId?: string | number;
 
+  contactNo?: string;
+
   /**
    * 联系人姓名
    */

+ 6 - 6
src/api/customer/customerFile/customerDept/types.ts

@@ -67,7 +67,7 @@ export interface CustomerDeptVO {
   /**
    * 部门负责人
    */
-  deptManage: string;
+  deptManage: number | string;
 
   /**
    * 是否限制预算
@@ -82,7 +82,7 @@ export interface CustomerDeptVO {
   /**
    * 费用类型
    */
-  expenseType: string;
+  expenseTypeId: string;
 
   /**
    * 年度剩余预算
@@ -179,7 +179,7 @@ export interface CustomerDeptForm extends BaseEntity {
   /**
    * 部门负责人
    */
-  deptManage?: string;
+  deptManage?: number | string;
 
   /**
    * 是否限制预算
@@ -194,7 +194,7 @@ export interface CustomerDeptForm extends BaseEntity {
   /**
    * 费用类型
    */
-  expenseType?: string;
+  expenseTypeId?: string;
 
   /**
    * 年度剩余预算
@@ -281,7 +281,7 @@ export interface CustomerDeptQuery {
   /**
    * 部门负责人
    */
-  deptManage?: string;
+  deptManage?: number | string;
 
   /**
    * 是否限制预算
@@ -296,7 +296,7 @@ export interface CustomerDeptQuery {
   /**
    * 费用类型
    */
-  expenseType?: string;
+  expenseTypeId?: string;
 
   /**
    * 年度剩余预算

+ 63 - 0
src/api/customer/expenseType/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { ExpenseTypeVO, ExpenseTypeForm, ExpenseTypeQuery } from '@/api/customer/expenseType/types';
+
+/**
+ * 查询客户费用类型列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listExpenseType = (query?: ExpenseTypeQuery): AxiosPromise<ExpenseTypeVO[]> => {
+  return request({
+    url: '/customer/expenseType/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询客户费用类型详细
+ * @param id
+ */
+export const getExpenseType = (id: string | number): AxiosPromise<ExpenseTypeVO> => {
+  return request({
+    url: '/customer/expenseType/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增客户费用类型
+ * @param data
+ */
+export const addExpenseType = (data: ExpenseTypeForm) => {
+  return request({
+    url: '/customer/expenseType',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改客户费用类型
+ * @param data
+ */
+export const updateExpenseType = (data: ExpenseTypeForm) => {
+  return request({
+    url: '/customer/expenseType',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除客户费用类型
+ * @param id
+ */
+export const delExpenseType = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/customer/expenseType/' + id,
+    method: 'delete'
+  });
+};

+ 116 - 0
src/api/customer/expenseType/types.ts

@@ -0,0 +1,116 @@
+export interface ExpenseTypeVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 客户编号
+   */
+  customerId: string | number;
+
+  /**
+   * 客户编号
+   */
+  customerNo: string;
+
+  /**
+   * 费用名称
+   */
+  expenseName: string;
+
+  /**
+   * 费用类型(业务自定义)
+   */
+  type: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface ExpenseTypeForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 客户编号
+   */
+  customerId?: string | number;
+
+  /**
+   * 客户编号
+   */
+  customerNo?: string;
+
+  /**
+   * 费用名称
+   */
+  expenseName?: string;
+
+  /**
+   * 费用类型(业务自定义)
+   */
+  type?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface ExpenseTypeQuery extends PageQuery {
+
+  /**
+   * 客户编号
+   */
+  customerId?: string | number;
+
+  /**
+   * 客户编号
+   */
+  customerNo?: string;
+
+  /**
+   * 费用名称
+   */
+  expenseName?: string;
+
+  /**
+   * 费用类型(业务自定义)
+   */
+  type?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 115 - 105
src/views/customer/customerFile/customerInfo/add.vue

@@ -19,16 +19,12 @@
           </el-col>
           <el-col :span="8">
             <el-form-item label="客户名称" prop="customerName">
-              <el-input v-model="form.customerName" placeholder="请输入客户名称">
-                <template #append>
-                  <el-button @click="selectBusinessBtn">查询工商信息</el-button>
-                </template>
-              </el-input>
+              <el-input v-model="form.customerName" placeholder="请输入客户名称"> </el-input>
             </el-form-item>
           </el-col>
           <el-col :span="8">
             <el-form-item label="工商名称" prop="businessCustomerName">
-              <el-input v-model="form.businessCustomerName" placeholder="请输入工商名称" />
+              <el-input v-model="form.businessCustomerName" placeholder="请输入工商名称" @blur="selectBusinessBtn"> </el-input>
             </el-form-item>
           </el-col>
         </el-row>
@@ -140,7 +136,7 @@
         <el-row :gutter="20">
           <el-col :span="8">
             <el-form-item label="发票抬头" prop="invoiceTop">
-              <el-input v-model="form.invoiceTop" placeholder="请输入发票抬头" />
+              <el-input v-model="form.invoiceTop" placeholder="请输入发票抬头" disabled />
             </el-form-item>
           </el-col>
           <el-col :span="8">
@@ -248,8 +244,6 @@
                   cursor: pointer;
                   transition: all 0.3s;
                 "
-                @mouseenter="(e) => (e.currentTarget.style.borderColor = '#409eff')"
-                @mouseleave="(e) => (e.currentTarget.style.borderColor = '#d9d9d9')"
               >
                 <div style="text-align: center; color: #8c939d">
                   <el-icon :size="40" style="margin-bottom: 8px">
@@ -446,6 +440,100 @@ const customerTypeList = ref<CustomerTypeVO[]>([]);
 const comStaffList = ref<ComStaffVO[]>([]);
 const comDeptList = ref<DeptVO[]>([]);
 
+// 企业基本信息表单
+const form = reactive<CustomerInfoForm>({
+  customerNo: '',
+  belongCompanyId: undefined,
+  companyName: '',
+  businessCustomerName: '',
+  shortName: '',
+  invoiceTypeId: undefined,
+  enterpriseScaleId: undefined,
+  customerTypeId: undefined,
+  industryCategoryId: undefined,
+  customerLevelId: undefined,
+  landline: '',
+  fax: '',
+  url: '',
+  postCode: '',
+  validityFromDate: undefined,
+  validityToDate: undefined,
+  invoiceTop: '',
+  address: '',
+  status: '0',
+  remark: ''
+});
+
+// 工商信息
+const businessForm = reactive<BusinessInfoForm>({
+  businessCustomerName: '',
+  socialCreditCode: '',
+  legalPersonName: '',
+  registeredCapital: '',
+  registrationAuthority: '',
+  establishmentDate: '',
+  revocationDate: '',
+  registrationStatus: '',
+  paidInCapital: undefined,
+  businessAddress: '',
+  businessLicense: '',
+  status: '0'
+});
+
+// 联系人列表
+const contactList = ref<CustomerContactForm[]>([]);
+const contactDialogVisible = ref(false);
+const currentContact = ref<CustomerContactForm | undefined>(undefined);
+const currentContactIndex = ref<number>(-1);
+
+// 销售信息
+const salesForm = reactive<SalesInfoForm>({
+  salesPersonId: undefined,
+  serviceStaffId: undefined,
+  belongingDepartmentId: undefined,
+  status: '0'
+});
+
+// 开票信息列表
+const invoiceList = ref<InvoiceInfoForm[]>([]);
+const invoiceDialogVisible = ref(false);
+const currentInvoice = ref<InvoiceInfoForm | undefined>(undefined);
+const currentInvoiceIndex = ref<number>(-1);
+
+// 表单验证规则
+const rules = {
+  belongCompanyId: [{ required: true, message: '请选择所属公司', trigger: 'change' }],
+  customerName: [{ required: true, message: '请输入客户名称', trigger: 'blur' }],
+  businessCustomerName: [
+    { required: true, message: '请输入工商名称', trigger: 'blur' },
+    {
+      // 允许:中文 + 常见标点 (括号、中圆点、横杠)
+      // 禁止:数字、字母、空格、@#$%等其他符号
+      pattern: /^[\u4e00-\u9fa5()()·\-]+$/,
+      message: '名称不能包含数字、字母或特殊符号,仅限中文及常用标点',
+      trigger: 'blur'
+    }
+  ],
+  shortName: [{ required: true, message: '请输入企业简称', trigger: 'blur' }],
+  invoiceTypeId: [{ required: true, message: '请选择开票类型', trigger: 'change' }],
+  enterpriseScaleId: [{ required: true, message: '请选择企业规模', trigger: 'change' }],
+  customerTypeId: [{ required: true, message: '请选择客户类别', trigger: 'change' }],
+  industryCategoryId: [{ required: true, message: '请选择行业类别', trigger: 'change' }],
+  customerLevelId: [{ required: true, message: '请选择客户等级', trigger: 'change' }],
+  address: [{ required: true, message: '请输入详细地址', trigger: 'blur' }]
+};
+
+// 销售信息表单验证规则
+const salesRules = {
+  salesPersonId: [{ required: true, message: '请选择业务人员', trigger: 'change' }],
+  serviceStaffId: [{ required: true, message: '请选择客服人员', trigger: 'change' }]
+};
+
+// 获取角色名称
+// const getRoleName = (roleId: string | number | undefined) => {
+//   return roleMap[String(roleId)] || '-';
+// };
+
 // Logo选择器相关
 const logoSelectorVisible = ref(false);
 const businessLicenseSelectorVisible = ref(false);
@@ -476,7 +564,7 @@ const handleBusinessLicenseSelected = (files: any[]) => {
     const file = files[0]; // 取第一个文件
     if (file && (file.url || file.path)) {
       businessForm.businessLicense = file.url || file.path;
-      ElMessage.success('营业执照选择成功');
+      // ElMessage.success('营业执照选择成功');
 
       // 选择完成后清理表单验证状态
       nextTick(() => {
@@ -528,14 +616,16 @@ onMounted(async () => {
 
 const selectBusinessBtn = async () => {
   try {
-    const res = await getBusinessInfoBycustomerName(form.customerName);
+    // 验证基本信息表单
+    await formRef.value.validateField('businessCustomerName');
+    const res = await getBusinessInfoBycustomerName(form.businessCustomerName);
     const data = res.data;
     // 填充信息
     Object.assign(businessForm, data);
+    form.invoiceTop = data.businessCustomerName;
     form.businessCustomerName = data.businessCustomerName;
   } catch (error) {
-    console.error('查询工商信息失败:', error);
-    ElMessage.error('查询工商信息失败');
+    // ElMessage.error('查询工商信息失败');
   }
 };
 
@@ -582,7 +672,7 @@ const loadCustomerData = async (id: string) => {
 // 加载企业规模列表
 const loadEnterpriseScaleList = async () => {
   try {
-    const res = await listEnterpriseScale();
+    const res = await listEnterpriseScale({ dataSource: 'A10' } as any);
     enterpriseScaleList.value = res.rows || [];
   } catch (error) {
     console.error('加载企业规模列表失败:', error);
@@ -592,7 +682,7 @@ const loadEnterpriseScaleList = async () => {
 // 加载行业类别列表
 const loadIndustryCategoryList = async () => {
   try {
-    const res = await listIndustryCategory();
+    const res = await listIndustryCategory({ dataSource: 'A10' } as any);
     industryCategoryList.value = res.rows || [];
   } catch (error) {
     console.error('加载行业类别列表失败:', error);
@@ -602,7 +692,7 @@ const loadIndustryCategoryList = async () => {
 // 加载开票类型列表
 const loadInvoiceTypeList = async () => {
   try {
-    const res = await listInvoiceType();
+    const res = await listInvoiceType({ dataSource: 'A10' } as any);
     invoiceTypeList.value = res.rows || [];
   } catch (error) {
     console.error('加载开票类型列表失败:', error);
@@ -612,7 +702,7 @@ const loadInvoiceTypeList = async () => {
 // 加载公司列表
 const loadCompanyList = async () => {
   try {
-    const query: any = { isShow: '0' };
+    const query: any = { isShow: '0', dataSource: 'A10' };
     const res = await listCompany(query);
     companyList.value = res.rows || [];
   } catch (error) {
@@ -634,7 +724,7 @@ const loadSettlementMethodList = async () => {
 // 加载客户等级列表
 const loadCustomerLevelList = async () => {
   try {
-    const res = await listCustomerLevel();
+    const res = await listCustomerLevel({ dataSource: 'A10' } as any);
     customerLevelList.value = res.rows || [];
   } catch (error) {
     console.error('加载客户等级列表失败:', error);
@@ -644,7 +734,7 @@ const loadCustomerLevelList = async () => {
 // 加载客户类别列表
 const loadCustomerTypeList = async () => {
   try {
-    const res = await listCustomerType();
+    const res = await listCustomerType({ dataSource: 'A10' } as any);
     customerTypeList.value = res.rows || [];
   } catch (error) {
     console.error('加载客户类别列表失败:', error);
@@ -654,7 +744,7 @@ const loadCustomerTypeList = async () => {
 // 加载员工列表
 const loadComStaffList = async () => {
   try {
-    const query: ComStaffQuery = { status: '0' };
+    const query: any = { status: '0' };
     const res = await listComStaff(query);
     comStaffList.value = res.rows || [];
   } catch (error) {
@@ -673,91 +763,6 @@ const loadComDeptList = async () => {
   }
 };
 
-// 企业基本信息表单
-const form = reactive<CustomerInfoForm>({
-  customerNo: '',
-  belongCompanyId: undefined,
-  companyName: '',
-  businessCustomerName: '',
-  shortName: '',
-  invoiceTypeId: undefined,
-  enterpriseScaleId: undefined,
-  customerTypeId: undefined,
-  industryCategoryId: undefined,
-  customerLevelId: undefined,
-  landline: '',
-  fax: '',
-  url: '',
-  postCode: '',
-  validityFromDate: undefined,
-  validityToDate: undefined,
-  invoiceTop: '',
-  address: '',
-  status: '0',
-  remark: ''
-});
-
-// 工商信息
-const businessForm = reactive<BusinessInfoForm>({
-  businessCustomerName: '',
-  socialCreditCode: '',
-  legalPersonName: '',
-  registeredCapital: '',
-  registrationAuthority: '',
-  establishmentDate: '',
-  revocationDate: '',
-  registrationStatus: '',
-  paidInCapital: undefined,
-  businessAddress: '',
-  businessLicense: '',
-  status: '0'
-});
-
-// 联系人列表
-const contactList = ref<CustomerContactForm[]>([]);
-const contactDialogVisible = ref(false);
-const currentContact = ref<CustomerContactForm | undefined>(undefined);
-const currentContactIndex = ref<number>(-1);
-
-// 销售信息
-const salesForm = reactive<SalesInfoForm>({
-  salesPersonId: undefined,
-  serviceStaffId: undefined,
-  belongingDepartmentId: undefined,
-  status: '0'
-});
-
-// 开票信息列表
-const invoiceList = ref<InvoiceInfoForm[]>([]);
-const invoiceDialogVisible = ref(false);
-const currentInvoice = ref<InvoiceInfoForm | undefined>(undefined);
-const currentInvoiceIndex = ref<number>(-1);
-
-// 表单验证规则
-const rules = {
-  belongCompanyId: [{ required: true, message: '请选择所属公司', trigger: 'change' }],
-  customerName: [{ required: true, message: '请输入客户名称', trigger: 'blur' }],
-  businessCustomerName: [{ required: true, message: '请输入工商名称', trigger: 'blur' }],
-  shortName: [{ required: true, message: '请输入企业简称', trigger: 'blur' }],
-  invoiceTypeId: [{ required: true, message: '请选择开票类型', trigger: 'change' }],
-  enterpriseScaleId: [{ required: true, message: '请选择企业规模', trigger: 'change' }],
-  customerTypeId: [{ required: true, message: '请选择客户类别', trigger: 'change' }],
-  industryCategoryId: [{ required: true, message: '请选择行业类别', trigger: 'change' }],
-  customerLevelId: [{ required: true, message: '请选择客户等级', trigger: 'change' }],
-  address: [{ required: true, message: '请输入详细地址', trigger: 'blur' }]
-};
-
-// 销售信息表单验证规则
-const salesRules = {
-  salesPersonId: [{ required: true, message: '请选择业务人员', trigger: 'change' }],
-  serviceStaffId: [{ required: true, message: '请选择客服人员', trigger: 'change' }]
-};
-
-// 获取角色名称
-const getRoleName = (roleId: string | number | undefined) => {
-  return roleMap[String(roleId)] || '-';
-};
-
 // 打开添加联系人对话框
 const handleAddContact = () => {
   currentContact.value = undefined;
@@ -948,3 +953,8 @@ const handleSubmit = async () => {
   }
 };
 </script>
+<style scoped>
+.upload-box:hover {
+  border-color: #409eff !important; /* 鼠标悬停时变蓝 */
+}
+</style>

+ 13 - 7
src/views/customer/customerFile/customerInfo/components/addInvoiceDialog.vue

@@ -4,10 +4,10 @@
       <el-row :gutter="20">
         <el-col :span="24">
           <el-form-item label="纳税人识别号" prop="taxId">
-            <el-input v-model="form.taxId" placeholder="">
-              <template #append>
+            <el-input v-model="form.taxId" placeholder="" disabled>
+              <!-- <template #append>
                 <el-button @click="handleResetTaxId">还原</el-button>
-              </template>
+              </template> -->
             </el-input>
           </el-form-item>
         </el-col>
@@ -121,12 +121,18 @@ const form = reactive<InvoiceInfoForm>({
 });
 
 const rules = {
-  bankCode: [{ required: true, message: '请输入开户行行号', trigger: 'blur' }],
-  bankName: [{ required: true, message: '请选择开户行名称', trigger: 'change' }],
-  bankAccount: [{ required: true, message: '请输入银行账户', trigger: 'blur' }],
+  bankCode: [
+    { required: true, message: '请输入开户行行号', trigger: 'blur' },
+    { pattern: /^[0-9]+$/, message: '开户行行号只能包含数字', trigger: 'blur' }
+  ],
+  bankId: [{ required: true, message: '请选择开户行名称', trigger: 'change' }],
+  bankAccount: [
+    { required: true, message: '请输入银行账户', trigger: 'blur' },
+    { pattern: /^[0-9]+$/, message: '银行账户只能包含数字', trigger: 'blur' }
+  ],
   phone: [
     { required: true, message: '请输入电话', trigger: 'blur' },
-    { pattern: /^1[3-9]\d{9}$/ as RegExp, message: '请输入正确的手机号格式', trigger: 'blur' }
+    { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号格式', trigger: 'blur' } // 去掉 as RegExp
   ]
 };
 

+ 116 - 56
src/views/customer/customerFile/customerInfo/index.vue

@@ -3,53 +3,96 @@
     <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">
-            <el-form-item label="所属公司" prop="belongCompanyId">
-              <el-select v-model="queryParams.belongCompanyId" placeholder="请选择所属公司" clearable filterable style="width: 200px">
-                <el-option v-for="item in companyList" :key="item.id" :label="`${item.companyCode} - ${item.companyName}`" :value="item.id" />
-              </el-select>
-            </el-form-item>
-            <el-form-item label="客户编码" prop="customerNo">
-              <el-input v-model="queryParams.customerNo" placeholder="请输入客户编码" clearable style="width: 200px" @keyup.enter="handleQuery" />
-            </el-form-item>
-            <el-form-item label="客户名称" prop="companyName">
-              <el-input v-model="queryParams.customerName" placeholder="请输入客户名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
-            </el-form-item>
-            <el-form-item label="客户等级" prop="customerLevelId">
-              <el-select v-model="queryParams.customerLevelId" placeholder="请选择客户等级" clearable style="width: 200px">
-                <el-option v-for="dict in customer_level" :key="dict.value" :label="dict.label" :value="dict.value" />
-              </el-select>
-            </el-form-item>
-            <el-form-item label="行业" prop="industryCategoryId">
-              <el-select v-model="queryParams.industryCategoryId" placeholder="请选择行业" clearable filterable style="width: 200px">
-                <el-option v-for="industry in industryCategoryList" :key="industry.id" :label="industry.industryCategoryName" :value="industry.id" />
-              </el-select>
-            </el-form-item>
-            <el-form-item label="业务员" prop="salesPersonId">
-              <el-select v-model="queryParams.salesPersonId" placeholder="请选择业务员" clearable filterable style="width: 200px">
-                <el-option v-for="item in comStaffList" :key="item.staffId" :label="`${item.staffCode} , ${item.staffName}`" :value="item.staffId" />
-              </el-select>
-            </el-form-item>
-            <el-form-item label="客服人员" prop="serviceStaffId">
-              <el-select v-model="queryParams.serviceStaffId" placeholder="请选择客服人员" clearable filterable style="width: 200px">
-                <el-option v-for="item in comStaffList" :key="item.staffId" :label="`${item.staffCode} , ${item.staffName}`" :value="item.staffId" />
-              </el-select>
-            </el-form-item>
-            <el-form-item label="归属部门" prop="belongingDepartmentId">
-              <el-select v-model="queryParams.belongingDepartmentId" placeholder="请选择归属部门" clearable filterable style="width: 200px">
-                <el-option v-for="item in comDeptList" :key="item.id" :label="item.deptName" :value="item.id" />
-              </el-select>
-            </el-form-item>
-            <el-form-item label="客户标签" prop="customerTag">
-              <el-select v-model="queryParams.customerTag" placeholder="请选择客户标签" clearable filterable style="width: 200px">
-                <el-option v-for="tag in customerTagList" :key="tag.id" :label="tag.tagName" :value="tag.id" />
-              </el-select>
-            </el-form-item>
-
-            <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 ref="queryFormRef" :model="queryParams" :inline="true" label-width="80px">
+            <el-row :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="所属公司" prop="belongCompanyId" style="width: 100%; margin-right: 0">
+                  <el-select v-model="queryParams.belongCompanyId" placeholder="请选择所属公司" clearable filterable style="width: 100%">
+                    <el-option v-for="item in companyList" :key="item.id" :label="`${item.companyCode} - ${item.companyName}`" :value="item.id" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="客户编码" prop="customerNo" style="width: 100%; margin-right: 0">
+                  <el-input v-model="queryParams.customerNo" placeholder="请输入客户编码" clearable style="width: 100%" @keyup.enter="handleQuery" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="客户名称" prop="companyName" style="width: 100%; margin-right: 0">
+                  <el-input
+                    v-model="queryParams.customerName"
+                    placeholder="请输入客户名称"
+                    clearable
+                    style="width: 100%"
+                    @keyup.enter="handleQuery"
+                  />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="客户等级" prop="customerLevelId" style="width: 100%; margin-right: 0">
+                  <el-select v-model="queryParams.customerLevelId" placeholder="请选择客户等级" clearable style="width: 100%">
+                    <el-option v-for="level in customerLevelList" :key="level.id" :label="level.levelName" :value="level.id" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="行业" prop="industryCategoryId" style="width: 100%; margin-right: 0">
+                  <el-select v-model="queryParams.industryCategoryId" placeholder="请选择行业" clearable filterable style="width: 100%">
+                    <el-option
+                      v-for="industry in industryCategoryList"
+                      :key="industry.id"
+                      :label="industry.industryCategoryName"
+                      :value="industry.id"
+                    />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="业务员" prop="salesPersonId" style="width: 100%; margin-right: 0">
+                  <el-select v-model="queryParams.salesPersonId" placeholder="请选择业务员" clearable filterable style="width: 100%">
+                    <el-option
+                      v-for="item in comStaffList"
+                      :key="item.staffId"
+                      :label="`${item.staffCode} , ${item.staffName}`"
+                      :value="item.staffId"
+                    />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="客服人员" prop="serviceStaffId" style="width: 100%; margin-right: 0">
+                  <el-select v-model="queryParams.serviceStaffId" placeholder="请选择客服人员" clearable filterable style="width: 100%">
+                    <el-option
+                      v-for="item in comStaffList"
+                      :key="item.staffId"
+                      :label="`${item.staffCode} , ${item.staffName}`"
+                      :value="item.staffId"
+                    />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="归属部门" prop="belongingDepartmentId" style="width: 100%; margin-right: 0">
+                  <el-select v-model="queryParams.belongingDepartmentId" placeholder="请选择归属部门" clearable filterable style="width: 100%">
+                    <el-option v-for="item in comDeptList" :key="item.id" :label="item.deptName" :value="item.id" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="客户标签" prop="customerTag" style="width: 100%; margin-right: 0">
+                  <el-select v-model="queryParams.customerTag" placeholder="请选择客户标签" clearable filterable style="width: 100%">
+                    <el-option v-for="tag in customerTagList" :key="tag.id" :label="tag.tagName" :value="tag.id" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+
+              <el-col :span="6">
+                <el-form-item style="width: 100%; margin-right: 0">
+                  <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                  <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+                </el-form-item>
+              </el-col>
+            </el-row>
           </el-form>
         </el-card>
       </div>
@@ -86,8 +129,8 @@
 
       <el-table v-loading="loading" border :data="customerInfoList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="客户名称" align="center" prop="customerName" min-width="200" show-overflow-tooltip />
-        <el-table-column label="归属公司" align="center" prop="companyName" min-width="150" />
+        <el-table-column label="客户名称" align="left" prop="customerName" min-width="200" />
+        <el-table-column label="归属公司" align="left" prop="companyName" min-width="150" />
         <el-table-column label="客户编号" align="center" prop="customerNo" min-width="120" />
         <el-table-column label="行业" align="center" prop="industryCategory" min-width="120"> </el-table-column>
         <el-table-column label="业务员" align="center" min-width="100">
@@ -192,19 +235,20 @@ import { listCustomerTag } from '@/api/customer/customerCategory/customerTag';
 import { CustomerTagVO } from '@/api/customer/customerCategory/customerTag/types';
 import { listIndustryCategory } from '@/api/customer/customerCategory/industryCategory';
 import { IndustryCategoryVO } from '@/api/customer/customerCategory/industryCategory/types';
-import { listSysCompany } from '@/api/company/sysCompany';
-import type { SysCompanyVO } from '@/api/company/sysCompany/types';
+import { listCompany } from '@/api/company/company';
+import { listCustomerLevel } from '@/api/customer/customerLevel';
+import { CustomerLevelVO, CustomerLevelQuery } from '@/api/customer/customerLevel/types';
+import { CompanyVO } from '@/api/company/company/types';
 import { listComStaff, getComStaff } from '@/api/company/comStaff';
 import { ComStaffVO, ComStaffQuery, ComStaffForm } from '@/api/company/comStaff/types';
 import { listComDept, getComDept } from '@/api/company/comDept';
 import { ComDeptVO } from '@/api/company/comDept/types';
-const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { sys_check_status, customer_type, customer_level } = toRefs<any>(proxy?.useDict('sys_check_status', 'customer_type', 'customer_level'));
 const router = useRouter();
 const customerInfoList = ref<CustomerInfoVO[]>([]);
 const customerTagList = ref<CustomerTagVO[]>([]);
+const customerLevelList = ref<CustomerLevelVO[]>([]);
 const industryCategoryList = ref<IndustryCategoryVO[]>([]);
-const companyList = ref<SysCompanyVO[]>([]);
+const companyList = ref<CompanyVO[]>([]);
 const comStaffList = ref<ComStaffVO[]>([]);
 const comDeptList = ref<ComDeptVO[]>([]);
 const buttonLoading = ref(false);
@@ -215,6 +259,9 @@ const single = ref(true);
 const multiple = ref(true);
 const total = ref(0);
 
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { sys_check_status, customer_type, customer_level } = toRefs<any>(proxy?.useDict('sys_check_status', 'customer_type', 'customer_level'));
+
 const queryFormRef = ref<ElFormInstance>();
 const customerInfoFormRef = ref<ElFormInstance>();
 
@@ -370,6 +417,7 @@ const handleQuery = () => {
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
+  queryParams.value.customerName = undefined;
   handleQuery();
 };
 
@@ -526,17 +574,28 @@ const loadCustomerTags = async () => {
 /** 加载行业分类列表 */
 const loadIndustryCategories = async () => {
   try {
-    const res = await listIndustryCategory({ status: '0' } as any); // 只获取启用状态的行业
+    const res = await listIndustryCategory({ status: '0', dataSource: 'A10' } as any); // 只获取启用状态的行业
     industryCategoryList.value = res.rows;
   } catch (error) {
     console.error('加载行业分类失败:', error);
   }
 };
 
+// 加载客户等级列表
+const loadCustomerLevelList = async () => {
+  try {
+    const res = await listCustomerLevel({ dataSource: 'A10' } as any);
+    customerLevelList.value = res.rows || [];
+  } catch (error) {
+    console.error('加载客户等级列表失败:', error);
+  }
+};
+
 /** 加载公司列表 */
 const loadCompanyList = async () => {
   try {
-    const res = await listSysCompany();
+    const query: any = { isShow: '0', dataSource: 'A10' };
+    const res = await listCompany(query);
     companyList.value = res.rows || [];
   } catch (error) {
     console.error('加载公司列表失败:', error);
@@ -571,6 +630,7 @@ onMounted(() => {
   loadCompanyList();
   loadComStaffList();
   loadComDeptList();
+  loadCustomerLevelList();
 });
 onActivated(() => {
   getList();

+ 85 - 41
src/views/customer/customerFile/customerInfo/overview/baseInfo.vue

@@ -21,16 +21,12 @@
           </el-col>
           <el-col :span="8">
             <el-form-item label="客户名称" prop="customerName">
-              <el-input v-model="form.customerName" placeholder="请输入客户名称">
-                <template #append>
-                  <el-button @click="selectBusinessBtn">查询工商信息</el-button>
-                </template>
-              </el-input>
+              <el-input v-model="form.customerName" placeholder="请输入客户名称"> </el-input>
             </el-form-item>
           </el-col>
           <el-col :span="8">
             <el-form-item label="工商名称" prop="businessCustomerName">
-              <el-input v-model="form.businessCustomerName" placeholder="请输入工商名称" />
+              <el-input v-model="form.businessCustomerName" placeholder="请输入工商名称" @blur="selectBusinessBtn"> </el-input>
             </el-form-item>
           </el-col>
         </el-row>
@@ -154,12 +150,18 @@
             </el-form-item>
           </el-col>
           <el-col :span="8">
-            <el-form-item label="办公地址">
-              <el-cascader v-model="codeArr" :options="regionData" placeholder="请选择" @change="handleChange" style="width: 100%"></el-cascader>
+            <el-form-item label="详细地址" prop="address">
+              <el-cascader
+                v-model="codeArr"
+                :options="regionData as any"
+                placeholder="请选择"
+                @change="handleChange"
+                style="width: 100%"
+              ></el-cascader>
             </el-form-item>
           </el-col>
           <el-col :span="8">
-            <el-form-item prop="address">
+            <el-form-item>
               <el-input v-model="form.address" placeholder="请输入详细地址" />
             </el-form-item>
           </el-col>
@@ -257,8 +259,6 @@
                   cursor: pointer;
                   transition: all 0.3s;
                 "
-                @mouseenter="(e) => (e.currentTarget.style.borderColor = '#409eff')"
-                @mouseleave="(e) => (e.currentTarget.style.borderColor = '#d9d9d9')"
               >
                 <div style="text-align: center; color: #8c939d">
                   <el-icon :size="40" style="margin-bottom: 8px">
@@ -406,7 +406,7 @@
         <el-table-column label="操作" align="center" width="150" fixed="right">
           <template #default="{ row, $index }">
             <el-button link type="primary" @click="handleEditInvoice(row, $index)">编辑</el-button>
-            <el-button link type="danger" @click="removeInvoice($index)">删除</el-button>
+            <el-button link type="danger" @click="removeInvoice(row)">删除</el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -433,12 +433,13 @@ import type { CustomerInfoForm } from '@/api/customer/customerFile/customerInfo/
 import type { BusinessInfoForm } from '@/api/customer/customerFile/businessInfo/types';
 import type { SalesInfoForm } from '@/api/customer/customerFile/salesInfo/types';
 import type { InvoiceInfoForm } from '@/api/customer/customerFile/invoiceInfo/types';
+import { listInvoiceInfo, getInvoiceInfo, addInvoiceInfo, updateInvoiceInfo, delInvoiceInfo } from '@/api/customer/customerFile/invoiceInfo';
 import { listSettlementMethod } from '@/api/customer/settlementMethod';
-import { SettlementMethodVO, SettlementMethodQuery, SettlementMethodForm } from '@/api/customer/settlementMethod/types';
-import { listCustomerLevel, getCustomerLevel } from '@/api/customer/customerLevel';
-import { CustomerLevelVO, CustomerLevelQuery, CustomerLevelForm } from '@/api/customer/customerLevel/types';
-import { listCustomerType, getCustomerType } from '@/api/customer/customerType';
-import { CustomerTypeVO, CustomerTypeQuery, CustomerTypeForm } from '@/api/customer/customerType/types';
+import { SettlementMethodVO } from '@/api/customer/settlementMethod/types';
+import { listCustomerLevel } from '@/api/customer/customerLevel';
+import { CustomerLevelVO } from '@/api/customer/customerLevel/types';
+import { listCustomerType } from '@/api/customer/customerType';
+import { CustomerTypeVO, CustomerTypeQuery } from '@/api/customer/customerType/types';
 import { getBusinessInfoBycustomerName } from '@/api/customer/customerFile/businessInfo';
 import { listCreditLevel } from '@/api/customer/creditLevel';
 import { CreditLevelVO, CreditLevelQuery } from '@/api/customer/creditLevel/types';
@@ -591,7 +592,16 @@ const uploadHeaders = ref({
 const rules = {
   belongCompanyId: [{ required: true, message: '请选择所属公司', trigger: 'change' }],
   customerName: [{ required: true, message: '请输入客户名称', trigger: 'blur' }],
-  businessCustomerName: [{ required: true, message: '请输入工商名称', trigger: 'blur' }],
+  businessCustomerName: [
+    { required: true, message: '请输入工商名称', trigger: 'blur' },
+    {
+      // 允许:中文 + 常见标点 (括号、中圆点、横杠)
+      // 禁止:数字、字母、空格、@#$%等其他符号
+      pattern: /^[\u4e00-\u9fa5()()·\-]+$/,
+      message: '名称不能包含数字、字母或特殊符号,仅限中文及常用标点',
+      trigger: 'blur'
+    }
+  ],
   shortName: [{ required: true, message: '请输入企业简称', trigger: 'blur' }],
   invoiceTypeId: [{ required: true, message: '请选择开票类型', trigger: 'change' }],
   enterpriseScaleId: [{ required: true, message: '请选择企业规模', trigger: 'change' }],
@@ -642,21 +652,23 @@ watch(
 
 const selectBusinessBtn = async () => {
   try {
-    const res = await getBusinessInfoBycustomerName(form.customerName);
+    // 验证基本信息表单
+    await formRef.value.validateField('businessCustomerName');
+    const res = await getBusinessInfoBycustomerName(form.businessCustomerName);
     const data = res.data;
     // 填充信息
     Object.assign(businessInfo, data);
+    form.invoiceTop = data.businessCustomerName;
     form.businessCustomerName = data.businessCustomerName;
   } catch (error) {
-    console.error('查询工商信息失败:', error);
-    ElMessage.error('查询工商信息失败');
+    // ElMessage.error('查询工商信息失败');
   }
 };
 
 // 加载企业规模列表
 const loadEnterpriseScaleList = async () => {
   try {
-    const res = await listEnterpriseScale();
+    const res = await listEnterpriseScale({ dataSource: 'A10' } as any);
     enterpriseScaleList.value = res.rows || [];
   } catch (error) {
     console.error('加载企业规模列表失败:', error);
@@ -666,7 +678,7 @@ const loadEnterpriseScaleList = async () => {
 // 加载行业类别列表
 const loadIndustryCategoryList = async () => {
   try {
-    const res = await listIndustryCategory();
+    const res = await listIndustryCategory({ dataSource: 'A10' } as any);
     industryCategoryList.value = res.rows || [];
   } catch (error) {
     console.error('加载行业类别列表失败:', error);
@@ -676,7 +688,7 @@ const loadIndustryCategoryList = async () => {
 // 加载开票类型列表
 const loadInvoiceTypeList = async () => {
   try {
-    const res = await listInvoiceType();
+    const res = await listInvoiceType({ dataSource: 'A10' } as any);
     invoiceTypeList.value = res.rows || [];
   } catch (error) {
     console.error('加载开票类型列表失败:', error);
@@ -686,8 +698,8 @@ const loadInvoiceTypeList = async () => {
 // 加载公司列表
 const loadCompanyList = async () => {
   try {
-    const query: any = { isShow: '0' };
-    const res = await listCompany();
+    const query: any = { isShow: '0', dataSource: 'A10' };
+    const res = await listCompany(query);
     companyList.value = res.rows || [];
   } catch (error) {
     console.error('加载公司列表失败:', error);
@@ -708,7 +720,7 @@ const loadSettlementMethodList = async () => {
 // 加载信用等级列表
 const loadCreditLevelList = async () => {
   try {
-    const query: CreditLevelQuery = { isShow: '0' };
+    const query: any = { dataSource: 'A10' };
     const res = await listCreditLevel(query);
     creditLevelList.value = res.rows || [];
   } catch (error) {
@@ -719,7 +731,7 @@ const loadCreditLevelList = async () => {
 // 加载客户等级列表
 const loadCustomerLevelList = async () => {
   try {
-    const res = await listCustomerLevel();
+    const res = await listCustomerLevel({ dataSource: 'A10' } as any);
     customerLevelList.value = res.rows || [];
   } catch (error) {
     console.error('加载客户等级列表失败:', error);
@@ -729,7 +741,7 @@ const loadCustomerLevelList = async () => {
 // 加载客户类别列表
 const loadCustomerTypeList = async () => {
   try {
-    const res = await listCustomerType();
+    const res = await listCustomerType({ dataSource: 'A10' } as any);
     customerTypeList.value = res.rows || [];
   } catch (error) {
     console.error('加载客户类别列表失败:', error);
@@ -739,7 +751,7 @@ const loadCustomerTypeList = async () => {
 // 加载员工列表
 const loadComStaffList = async () => {
   try {
-    const query: ComStaffQuery = { status: '0' };
+    const query: any = { status: '0' };
     const res = await listComStaff(query);
     comStaffList.value = res.rows || [];
   } catch (error) {
@@ -820,9 +832,7 @@ const loadCustomerData = async (id: any) => {
     }
 
     // 填充开票信息列表
-    if (data.customerInvoiceInfoVoList) {
-      invoiceList.value = data.customerInvoiceInfoVoList;
-    }
+    loadInvoiceList(id);
   } catch (error) {
     console.error('加载客户数据失败:', error);
     ElMessage.error('加载客户数据失败');
@@ -951,7 +961,9 @@ const handleSalesPersonChange = async (staffId: any) => {
 
 // 打开添加开票信息对话框
 const handleAddInvoice = () => {
-  currentInvoice.value = undefined;
+  currentInvoice.value = {};
+  currentInvoice.value.taxId = businessInfo.socialCreditCode;
+  currentInvoice.value.address = businessInfo.businessAddress;
   currentInvoiceIndex.value = -1;
   invoiceDialogVisible.value = true;
 };
@@ -1032,24 +1044,51 @@ const handleEditInvoice = (row: InvoiceInfoForm, index: number) => {
 
 // 确认添加/编辑开票信息
 const handleInvoiceConfirm = (data: InvoiceInfoForm) => {
-  if (currentInvoiceIndex.value >= 0) {
-    // 编辑
-    invoiceList.value[currentInvoiceIndex.value] = data;
+  // if (currentInvoiceIndex.value >= 0) {
+  //   // 编辑
+  //   invoiceList.value[currentInvoiceIndex.value] = data;
+  // } else {
+  //   // 新增
+  //   invoiceList.value.push(data);
+  // }
+  data.customerId = custId.value;
+  if (data.id) {
+    updateInvoiceInfo(data).then(() => {
+      ElMessage.success('修改成功');
+      // 刷新列表
+      loadInvoiceList(custId.value);
+    });
   } else {
-    // 新增
-    invoiceList.value.push(data);
+    addInvoiceInfo(data).then(() => {
+      ElMessage.success('保存成功');
+      // 刷新列表
+      loadInvoiceList(custId.value);
+    });
   }
 };
 
+const loadInvoiceList = (customerId: string | number) => {
+  const params = {
+    customerId,
+    pageNum: 1,
+    pageSize: 50
+  };
+  listInvoiceInfo(params).then((res) => {
+    invoiceList.value = res.rows;
+  });
+};
+
 // 删除开票信息
-const removeInvoice = (index: number) => {
+const removeInvoice = (data: any) => {
   ElMessageBox.confirm('确定要删除该开票信息吗?', '提示', {
     confirmButtonText: '确定',
     cancelButtonText: '取消',
     type: 'warning'
   })
     .then(() => {
-      invoiceList.value.splice(index, 1);
+      delInvoiceInfo(data.id).then(() => {
+        loadInvoiceList(custId.value);
+      });
       ElMessage.success('删除成功');
     })
     .catch(() => {});
@@ -1086,3 +1125,8 @@ const handleSave = async () => {
   }
 };
 </script>
+<style scoped>
+.upload-box:hover {
+  border-color: #409eff !important; /* 鼠标悬停时变蓝 */
+}
+</style>

+ 18 - 5
src/views/customer/customerFile/customerInfo/overview/contactInfo.vue

@@ -14,8 +14,7 @@
 
       <el-table v-loading="loading" border :data="customerContactList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="用户ID" align="center" prop="customerId" />
-        <el-table-column label="A10标识" align="center" />
+        <el-table-column label="用户ID" align="center" prop="contactNo" />
         <el-table-column label="员工姓名" align="center" prop="contactName" />
         <el-table-column label="性别" align="center" prop="gender">
           <template #default="scope">
@@ -33,13 +32,13 @@
         </el-table-column>
         <el-table-column label="主联系人" align="center" prop="isPrimary">
           <template #default="scope">
-            <dict-tag :options="sys_platform_yes_no" :value="scope.row.isPrimary" />
+            <el-switch v-model="scope.row.isPrimary" active-value="0" inactive-value="1" @change="handlePrimaryChange(scope.row)"></el-switch>
           </template>
         </el-table-column>
         <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
           <template #default="scope">
-            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
-            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
+            <el-button link type="primary" @click="handleUpdate(scope.row)">编辑</el-button>
+            <el-button link type="primary" @click="handleDelete(scope.row)">删除</el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -149,6 +148,7 @@
 import {
   listCustomerContact,
   getCustomerContact,
+  changeIsPrimary,
   delCustomerContact,
   addCustomerContact,
   updateCustomerContact
@@ -302,6 +302,19 @@ const loadCustomerDeptList = async () => {
   }
 };
 
+/** 状态修改  */
+const handlePrimaryChange = async (row: any) => {
+  //   const text = row.status === '0' ? '是' : '否';
+  try {
+    // await proxy?.$modal.confirm('确认要"' + text + '"吗?');
+    await changeIsPrimary(row.id, row.isPrimary);
+    proxy?.$modal.msgSuccess('操作成功');
+    getList();
+  } catch (err) {
+    row.status = row.status === '0' ? '1' : '0';
+  }
+};
+
 /** 取消按钮 */
 const cancel = () => {
   reset();

+ 3 - 3
src/views/customer/customerFile/customerInfo/overview/contractManagement.vue

@@ -82,7 +82,7 @@
       <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
     </el-card>
     <!-- 添加或修改客户合同对话框 -->
-    <el-dialog :title="dialog.title" v-model="dialog.visible" width="50%" append-to-body>
+    <el-drawer :title="dialog.title" v-model="dialog.visible" size="70%" direction="rtl" :close-on-click-modal="true" append-to-body>
       <el-form ref="contractFormRef" :model="form" :rules="rules" label-width="120px">
         <el-row :gutter="20">
           <el-col :span="8">
@@ -105,7 +105,7 @@
         </el-row>
         <el-row :gutter="20">
           <el-col :span="8">
-            <el-form-item label="合同金额(万元)" prop="contractAmount">
+            <el-form-item label="合同金额" prop="contractAmount">
               <el-input v-model="form.contractAmount" placeholder="请输入合同金额" :disabled="isViewMode" />
             </el-form-item>
           </el-col>
@@ -178,7 +178,7 @@
           <el-button @click="cancel">{{ isViewMode ? '关 闭' : '取 消' }}</el-button>
         </div>
       </template>
-    </el-dialog>
+    </el-drawer>
   </div>
 </template>
 

+ 13 - 8
src/views/customer/customerFile/customerInfo/overview/operationLog.vue

@@ -20,21 +20,24 @@
       >
         <el-table-column type="selection" width="50" align="center" />
         <el-table-column label="日志编号" align="center" prop="operId" />
-        <el-table-column label="操作日期" align="center" prop="operTime" width="180" sortable="custom" :sort-orders="['descending', 'ascending']">
+        <el-table-column label="操作日期" align="center" prop="operTime" sortable="custom" :sort-orders="['descending', 'ascending']">
           <template #default="scope">
             <span>{{ proxy.parseTime(scope.row.operTime) }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="操作状态" align="center" prop="status">
+        <el-table-column label="操作人" align="center" prop="operName" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
           <template #default="scope">
-            <dict-tag :options="sys_common_status" :value="scope.row.status" />
+            {{ scope.row.title }}/ {{ typeFormat(scope.row) }}
+            <!-- <el-tooltip content="详细" placement="top">
+              <el-button v-hasPermi="['monitor:operlog:query']" link type="primary" icon="View" @click="handleView(scope.row)"> </el-button>
+            </el-tooltip> -->
           </template>
         </el-table-column>
-        <el-table-column label="操作" fixed="right" align="center" class-name="small-padding fixed-width">
+
+        <el-table-column label="操作状态" align="center" prop="status">
           <template #default="scope">
-            <el-tooltip content="详细" placement="top">
-              <el-button v-hasPermi="['monitor:operlog:query']" link type="primary" icon="View" @click="handleView(scope.row)"> </el-button>
-            </el-tooltip>
+            <dict-tag :options="sys_common_status" :value="scope.row.status" />
           </template>
         </el-table-column>
       </el-table>
@@ -50,6 +53,7 @@
 import { list, delOperlog, cleanOperlog } from '@/api/monitor/operlog';
 import { OperLogForm, OperLogQuery, OperLogVO } from '@/api/monitor/operlog/types';
 import OperInfoDialog from '../../../../monitor/operlog/oper-info-dialog.vue';
+import { useUserStore } from '@/store/modules/user';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { sys_oper_type, sys_common_status } = toRefs<any>(proxy?.useDict('sys_oper_type', 'sys_common_status'));
@@ -65,6 +69,7 @@ const defaultSort = ref<any>({ prop: 'operTime', order: 'descending' });
 
 const operLogTableRef = ref<ElTableInstance>();
 const queryFormRef = ref<ElFormInstance>();
+const userStore = useUserStore();
 
 const data = reactive<PageData<OperLogForm, OperLogQuery>>({
   form: {
@@ -93,7 +98,7 @@ const data = reactive<PageData<OperLogForm, OperLogQuery>>({
     pageSize: 10,
     operIp: '',
     title: '',
-    operName: '',
+    operName: userStore.nickname,
     businessType: '',
     status: '',
     orderByColumn: defaultSort.value.prop,

+ 112 - 32
src/views/customer/customerFile/customerInfo/overview/orgStructure.vue

@@ -13,7 +13,7 @@
       </template>
 
       <el-table v-loading="loading" :data="customerDeptList" row-key="deptId" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }">
-        <el-table-column prop="deptName" label="部门名称" width="200" />
+        <el-table-column prop="deptName" label="部门名称" min-width="260" />
         <el-table-column prop="yearlyBudget" label="年度预算" align="center" />
         <el-table-column prop="monthLimit" label="月采限额" align="center" />
         <el-table-column prop="usedBudget" label="已用预算" align="center" />
@@ -21,7 +21,7 @@
         <el-table-column label="状态" align="center">
           <template #default="scope">
             <el-tag v-if="scope.row.status === '0'" type="success">启用</el-tag>
-            <el-tag v-else type="info">未启用</el-tag>
+            <el-tag v-else type="info">用</el-tag>
           </template>
         </el-table-column>
         <el-table-column label="操作" align="center" width="200">
@@ -35,8 +35,8 @@
     </el-card>
 
     <!-- 新增/编辑部门对话框 -->
-    <el-dialog :title="dialog.title" v-model="dialog.visible" width="700px" append-to-body>
-      <el-form ref="customerDeptFormRef" :model="form" :rules="rules" label-width="100px">
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body>
+      <el-form ref="customerDeptFormRef" :model="form" :rules="rules" label-width="120px">
         <el-form-item label="上级部门" prop="parentId">
           <el-tree-select
             v-model="form.parentId"
@@ -46,27 +46,65 @@
             placeholder="请选择"
             check-strictly
             :render-after-expand="false"
-            style="width: 100%"
+            style="width: 240px"
           />
         </el-form-item>
         <el-form-item label="部门名称" prop="deptName">
-          <el-input v-model="form.deptName" placeholder="请输入部门名称" />
+          <el-input v-model="form.deptName" placeholder="请输入部门名称" style="width: 240px" />
         </el-form-item>
-        <el-form-item label="年度预算" prop="yearlyBudget">
-          <el-input v-model="form.yearlyBudget" placeholder="请输入年度预算" />
+        <el-form-item label="部门主管" prop="deptManage">
+          <el-select v-model="form.deptManage" placeholder="请选择" clearable style="width: 240px">
+            <el-option v-for="manage in customerContactList" :key="manage.id" :label="manage.contactName" :value="manage.id" />
+          </el-select>
+        </el-form-item>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="是否启用部门">
+              <el-radio-group v-model="form.status">
+                <el-radio v-for="dict in sys_platform_yes_no" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="是否额度控制">
+              <el-radio-group v-model="form.isLimit">
+                <el-radio v-for="dict in sys_platform_yes_no" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="选择年度" prop="selectYear">
+          <el-date-picker
+            v-model="form.selectYear"
+            type="year"
+            placeholder="请选择年度"
+            value-format="YYYY"
+            style="width: 240px"
+            :disabled="form.isLimit == '1'"
+          />
+        </el-form-item>
+        <div style="color: #999; font-size: 12px; margin-left: 120px; margin-bottom: 18px">
+          只能对当期年度进行额度设置,往期年度,显示最后一日数据,无法充值额度。
+        </div>
+        <el-form-item v-if="form.isLimit === '0'" label="分项费用类型" prop="expenseTypeId">
+          <el-select v-model="form.expenseTypeId" placeholder="请选择" style="width: 240px" @change="expenseTypeChange">
+            <el-option v-for="item in expenseTypeList" :key="item.id" :label="item.expenseName" :value="item.id" />
+          </el-select>
+          <!-- <el-button type="primary" link style="margin-left: 12px">查询其他分项费用情况</el-button> -->
         </el-form-item>
-        <el-form-item label="月采限额" prop="monthLimit">
-          <el-input v-model="form.monthLimit" placeholder="请输入月采限额" />
+        <el-form-item label="现有额度(年)" prop="yearlyBudget">
+          <el-input v-model="form.yearlyBudget" style="width: 240px" disabled />
         </el-form-item>
-        <el-form-item label="已用预算" prop="usedBudget">
-          <el-input v-model="form.usedBudget" placeholder="请输入已用预算" />
+        <el-form-item label="已用额度(年)" prop="usedBudget">
+          <el-input v-model="form.usedBudget" style="width: 240px" disabled />
         </el-form-item>
-        <el-form-item label="是否启用">
-          <el-radio-group v-model="form.status">
-            <el-radio v-for="dict in sys_platform_yes_no" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
-          </el-radio-group>
+        <el-form-item label="剩余额度" prop="residueYearlyBudget">
+          <el-input v-model="form.residueYearlyBudget" style="width: 240px" disabled />
         </el-form-item>
-        <el-form-item label="是否绑定">
+        <el-form-item v-if="form.isLimit === '0'" label="充值额度" prop="recharge">
+          <el-input v-model="form.recharge" style="width: 240px" />
+        </el-form-item>
+        <el-form-item label="绑定状态">
           <el-switch v-model="form.bindStatus" :active-value="'0'" :inactive-value="'1'" />
         </el-form-item>
         <el-form-item v-if="form.bindStatus === '0'" label="绑定地址" prop="bindAddress">
@@ -79,6 +117,14 @@
             />
           </el-select>
         </el-form-item>
+        <div style="margin-left: 120px; margin-top: 10px">
+          <div style="font-weight: bold; margin-bottom: 8px">充值说明:</div>
+          <div style="color: #666; font-size: 13px; line-height: 1.8">
+            1. 需要给当前部门进行额度充值时,请在充值额度中填写"正数"即可。<br />
+            2. 需要给当前部门进行额度扣减时请在充值额度中填写"负数"即可,扣减额度不能高于剩余额度。<br />
+            3. 当现有额度为0时,则该部门的此项费用不能进行采购。
+          </div>
+        </div>
       </el-form>
       <template #footer>
         <div class="dialog-footer">
@@ -94,9 +140,12 @@
 import { listCustomerDept, getCustomerDept, delCustomerDept, addCustomerDept, updateCustomerDept } from '@/api/customer/customerFile/customerDept';
 import { CustomerDeptVO, CustomerDeptQuery, CustomerDeptForm } from '@/api/customer/customerFile/customerDept/types';
 import { listShippingAddress, getShippingAddress } from '@/api/customer/customerFile/shippingAddress';
+import { listExpenseType } from '@/api/customer/expenseType';
+import { ExpenseTypeVO } from '@/api/customer/expenseType/types';
 import { ShippingAddressVO, ShippingAddressQuery, ShippingAddressForm } from '@/api/customer/customerFile/shippingAddress/types';
 import { delDept } from '@/api/system/dept';
-
+import { listCustomerContact } from '@/api/customer/customerFile/customerContact';
+import { CustomerContactVO } from '@/api/customer/customerFile/customerContact/types';
 type CustomerDeptOption = {
   deptId: number;
   deptName: string;
@@ -117,8 +166,9 @@ const { sys_platform_yes_no } = toRefs<any>(proxy?.useDict('sys_platform_yes_no'
 const customerDeptList = ref<CustomerDeptVO[]>([]);
 const customerDeptOptions = ref<CustomerDeptOption[]>([]);
 const shippingAddressList = ref<ShippingAddressVO[]>([]);
+const expenseTypeList = ref<ExpenseTypeVO[]>([]);
 const buttonLoading = ref(false);
-const showSearch = ref(true);
+const customerContactList = ref<CustomerContactVO[]>([]);
 const isExpandAll = ref(true);
 const loading = ref(false);
 
@@ -147,7 +197,7 @@ const initFormData: CustomerDeptForm = {
   deptManage: undefined,
   isLimit: undefined,
   selectYear: undefined,
-  expenseType: undefined,
+  expenseTypeId: undefined,
   residueYearlyBudget: undefined,
   recharge: undefined,
   status: '0',
@@ -170,7 +220,7 @@ const data = reactive<PageData<CustomerDeptForm, CustomerDeptQuery>>({
     deptManage: undefined,
     isLimit: undefined,
     selectYear: undefined,
-    expenseType: undefined,
+    expenseTypeId: undefined,
     residueYearlyBudget: undefined,
     recharge: undefined,
     status: undefined,
@@ -178,12 +228,10 @@ const data = reactive<PageData<CustomerDeptForm, CustomerDeptQuery>>({
     params: {}
   },
   rules: {
+    parentId: [{ required: true, message: '上级部门不能为空', trigger: 'change' }],
     deptName: [{ required: true, message: '部门名称不能为空', trigger: 'blur' }],
-    customerId: [{ required: true, message: '客户编号不能为空', trigger: 'blur' }],
-    yearlyBudget: [{ required: true, message: '年度预算不能为空', trigger: 'blur' }],
-    usedBudget: [{ required: true, message: '已使用预算不能为空', trigger: 'blur' }],
-    monthLimit: [{ required: true, message: '月度限额不能为空', trigger: 'blur' }],
-    bindStatus: [{ required: true, message: '绑定状态不能为空', trigger: 'change' }]
+    deptManage: [{ required: true, message: '部门主管不能为空', trigger: 'blur' }],
+    customerId: [{ required: true, message: '客户编号不能为空', trigger: 'blur' }]
   }
 });
 
@@ -207,6 +255,22 @@ const getList = async () => {
   }
 };
 
+const expenseTypeChange = async () => {
+  form.value.yearlyBudget = 0.0;
+  form.value.usedBudget = 0.0;
+  form.value.residueYearlyBudget = 0.0;
+};
+/** 查询客户联系人信息列表 */
+const getContactList = async () => {
+  loading.value = true;
+  // 使用props传递的customerId进行查询
+  if (props.customerId) {
+    queryParams.value.customerId = props.customerId;
+  }
+  const res = await listCustomerContact(queryParams.value as any);
+  customerContactList.value = res.rows;
+};
+
 /** 查询客户部门信息下拉树结构 */
 const getTreeselect = async () => {
   const query: CustomerDeptQuery = {
@@ -216,6 +280,21 @@ const getTreeselect = async () => {
   customerDeptOptions.value = proxy?.handleTree<CustomerDeptOption>(res.data, 'deptId', 'parentId') || [];
 };
 
+/** 获取费用类型列表 */
+const getExpenseTypeList = async () => {
+  if (!props.customerId) {
+    expenseTypeList.value = [];
+    return;
+  }
+  try {
+    const res = await listExpenseType({ customerId: props.customerId, pageNum: 1, pageSize: 100 });
+    expenseTypeList.value = res.rows || res.data || [];
+  } catch (error) {
+    console.error('获取费用类型列表失败:', error);
+    expenseTypeList.value = [];
+  }
+};
+
 /** 获取客户收货地址列表 */
 const getShippingAddressList = async () => {
   if (!props.customerId) {
@@ -261,15 +340,14 @@ const resetQuery = () => {
 
 /** 新增按钮操作 */
 const handleAdd = async (row?: CustomerDeptVO) => {
-  reset();
-  await getTreeselect();
-  await getShippingAddressList();
   if (row != null && row.deptId) {
     form.value.parentId = row.deptId;
   }
   // 设置客户ID
   form.value.customerId = props.customerId;
   form.value.bindStatus = '1';
+  form.value.isLimit = '1';
+  form.value.selectYear = new Date().getFullYear().toString();
   dialog.visible = true;
   dialog.title = '新增部门';
 };
@@ -290,9 +368,6 @@ const toggleExpandAll = (data: CustomerDeptVO[], status: boolean) => {
 
 /** 修改按钮操作 */
 const handleUpdate = async (row: CustomerDeptVO) => {
-  reset();
-  await getTreeselect();
-  await getShippingAddressList();
   const res = await getCustomerDept(row.deptId);
   Object.assign(form.value, res.data);
   // 修正数据:如果 parentId 等于自己的 id,说明是顶级部门,将 parentId 设为 0
@@ -323,6 +398,7 @@ const submitForm = () => {
         }
         dialog.visible = false;
         await getList();
+        reset();
       } finally {
         buttonLoading.value = false;
       }
@@ -340,5 +416,9 @@ const handleDelete = async (row: CustomerDeptVO) => {
 
 onMounted(() => {
   getList();
+  getTreeselect();
+  getContactList();
+  getExpenseTypeList();
+  getShippingAddressList();
 });
 </script>

+ 4 - 0
src/views/customer/customerFile/customerInfo/overview/shippingAddress.vue

@@ -222,6 +222,7 @@ const handleDefaultAddressChange = async (row: ShippingAddressVO) => {
     // await proxy?.$modal.confirm('确认要"' + text + '"吗?');
     await changeDefaultAddress(row.id, row.defaultAddress);
     proxy?.$modal.msgSuccess('操作成功');
+    getList();
   } catch (err) {
     row.status = row.status === '0' ? '1' : '0';
   }
@@ -237,6 +238,8 @@ const cancel = () => {
 const reset = () => {
   form.value = { ...initFormData };
   shippingAddressFormRef.value?.resetFields();
+  form.value.provincialCityCountry = '';
+  codeArr.value = [];
 };
 
 /** 搜索按钮操作 */
@@ -292,6 +295,7 @@ const submitForm = () => {
       }
       proxy?.$modal.msgSuccess('操作成功');
       dialog.visible = false;
+      reset();
       await getList();
     }
   });