Преглед на файлове

增加客户相关模块

hurx преди 4 месеца
родител
ревизия
b70d4e9df0
променени са 35 файла, в които са добавени 6033 реда и са изтрити 5 реда
  1. 63 0
      src/api/customer/customerCategory/customerTag/index.ts
  2. 80 0
      src/api/customer/customerCategory/customerTag/types.ts
  3. 63 0
      src/api/customer/customerCategory/enterpriseScale/index.ts
  4. 75 0
      src/api/customer/customerCategory/enterpriseScale/types.ts
  5. 63 0
      src/api/customer/customerCategory/industryCategory/index.ts
  6. 75 0
      src/api/customer/customerCategory/industryCategory/types.ts
  7. 63 0
      src/api/customer/customerCategory/tagCategory/index.ts
  8. 75 0
      src/api/customer/customerCategory/tagCategory/types.ts
  9. 63 0
      src/api/customer/customerFile/businessInfo/index.ts
  10. 230 0
      src/api/customer/customerFile/businessInfo/types.ts
  11. 63 0
      src/api/customer/customerFile/customerContact/index.ts
  12. 245 0
      src/api/customer/customerFile/customerContact/types.ts
  13. 63 0
      src/api/customer/customerFile/customerInfo/index.ts
  14. 429 0
      src/api/customer/customerFile/customerInfo/types.ts
  15. 63 0
      src/api/customer/customerFile/invoiceInfo/index.ts
  16. 185 0
      src/api/customer/customerFile/invoiceInfo/types.ts
  17. 63 0
      src/api/customer/customerFile/salesInfo/index.ts
  18. 275 0
      src/api/customer/customerFile/salesInfo/types.ts
  19. 75 0
      src/api/customer/maintainInfo/index.ts
  20. 405 0
      src/api/customer/maintainInfo/types.ts
  21. 1 1
      src/layout/components/Sidebar/Logo.vue
  22. 60 0
      src/utils/customerNumber.ts
  23. 326 0
      src/views/customer/customerCategory/customerTag/index.vue
  24. 204 0
      src/views/customer/customerCategory/enterpriseScale/index.vue
  25. 210 0
      src/views/customer/customerCategory/industryCategory/index.vue
  26. 191 0
      src/views/customer/customerCategory/tagCategory/index.vue
  27. 656 0
      src/views/customer/customerFile/customerInfo/add.vue
  28. 212 0
      src/views/customer/customerFile/customerInfo/components/addContactDialog.vue
  29. 170 0
      src/views/customer/customerFile/customerInfo/components/addInvoiceDialog.vue
  30. 1 0
      src/views/customer/customerFile/customerInfo/edit.vue
  31. 365 0
      src/views/customer/customerFile/customerInfo/index.vue
  32. 425 0
      src/views/customer/maintainInfo/add.vue
  33. 124 0
      src/views/customer/maintainInfo/dialog/allotTechnicalAdviser.vue
  34. 368 0
      src/views/customer/maintainInfo/index.vue
  35. 4 4
      src/views/login.vue

+ 63 - 0
src/api/customer/customerCategory/customerTag/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { CustomerTagVO, CustomerTagForm, CustomerTagQuery } from '@/api/customer/customerCategory/customerTag/types';
+
+/**
+ * 查询客户标签列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listCustomerTag = (query?: CustomerTagQuery): AxiosPromise<CustomerTagVO[]> => {
+  return request({
+    url: '/customer/customerTag/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询客户标签详细
+ * @param id
+ */
+export const getCustomerTag = (id: string | number): AxiosPromise<CustomerTagVO> => {
+  return request({
+    url: '/customer/customerTag/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增客户标签
+ * @param data
+ */
+export const addCustomerTag = (data: CustomerTagForm) => {
+  return request({
+    url: '/customer/customerTag',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改客户标签
+ * @param data
+ */
+export const updateCustomerTag = (data: CustomerTagForm) => {
+  return request({
+    url: '/customer/customerTag',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除客户标签
+ * @param id
+ */
+export const delCustomerTag = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/customer/customerTag/' + id,
+    method: 'delete'
+  });
+};

+ 80 - 0
src/api/customer/customerCategory/customerTag/types.ts

@@ -0,0 +1,80 @@
+export interface CustomerTagVO {
+  /**
+   * ID
+   */
+  id: string | number;
+
+  /**
+   * 标签名称
+   */
+  tagName: string;
+
+  /**
+   * 商品标签
+   */
+  productTagIds: string;
+
+  /**
+   * 状态(0启用 1禁用)
+   */
+  status: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+}
+
+export interface CustomerTagForm extends BaseEntity {
+  /**
+   * ID
+   */
+  id?: string | number;
+
+  /**
+   * 标签名称
+   */
+  tagName?: string;
+
+  /**
+   * 商品标签
+   */
+  productTagIds?: string;
+
+  /**
+   * 状态(0启用 1禁用)
+   */
+  status?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+}
+
+export interface CustomerTagQuery extends PageQuery {
+  /**
+   * 标签名称
+   */
+  tagName?: string;
+
+  /**
+   * 商品标签
+   */
+  productTagIds?: string;
+
+  /**
+   * 状态(0启用 1禁用)
+   */
+  status?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+}

+ 63 - 0
src/api/customer/customerCategory/enterpriseScale/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { EnterpriseScaleVO, EnterpriseScaleForm, EnterpriseScaleQuery } from '@/api/customer/customerCategory/enterpriseScale/types';
+
+/**
+ * 查询企业规模列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listEnterpriseScale = (query?: EnterpriseScaleQuery): AxiosPromise<EnterpriseScaleVO[]> => {
+  return request({
+    url: '/customer/enterpriseScale/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询企业规模详细
+ * @param id
+ */
+export const getEnterpriseScale = (id: string | number): AxiosPromise<EnterpriseScaleVO> => {
+  return request({
+    url: '/customer/enterpriseScale/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增企业规模
+ * @param data
+ */
+export const addEnterpriseScale = (data: EnterpriseScaleForm) => {
+  return request({
+    url: '/customer/enterpriseScale',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改企业规模
+ * @param data
+ */
+export const updateEnterpriseScale = (data: EnterpriseScaleForm) => {
+  return request({
+    url: '/customer/enterpriseScale',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除企业规模
+ * @param id
+ */
+export const delEnterpriseScale = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/customer/enterpriseScale/' + id,
+    method: 'delete'
+  });
+};

+ 75 - 0
src/api/customer/customerCategory/enterpriseScale/types.ts

@@ -0,0 +1,75 @@
+export interface EnterpriseScaleVO {
+  /**
+   * ID
+   */
+  id: string | number;
+
+  /**
+   * 企业规模名称
+   */
+  enterpriseScaleName: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode: string;
+}
+
+export interface EnterpriseScaleForm extends BaseEntity {
+  /**
+   * ID
+   */
+  id?: string | number;
+
+  /**
+   * 企业规模名称
+   */
+  enterpriseScaleName?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+}
+
+export interface EnterpriseScaleQuery extends PageQuery {
+  /**
+   * 企业规模名称
+   */
+  enterpriseScaleName?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+}

+ 63 - 0
src/api/customer/customerCategory/industryCategory/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { IndustryCategoryVO, IndustryCategoryForm, IndustryCategoryQuery } from '@/api/customer/customerCategory/industryCategory/types';
+
+/**
+ * 查询所属行业列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listIndustryCategory = (query?: IndustryCategoryQuery): AxiosPromise<IndustryCategoryVO[]> => {
+  return request({
+    url: '/customer/industryCategory/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询所属行业详细
+ * @param id
+ */
+export const getIndustryCategory = (id: string | number): AxiosPromise<IndustryCategoryVO> => {
+  return request({
+    url: '/customer/industryCategory/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增所属行业
+ * @param data
+ */
+export const addIndustryCategory = (data: IndustryCategoryForm) => {
+  return request({
+    url: '/customer/industryCategory',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改所属行业
+ * @param data
+ */
+export const updateIndustryCategory = (data: IndustryCategoryForm) => {
+  return request({
+    url: '/customer/industryCategory',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除所属行业
+ * @param id
+ */
+export const delIndustryCategory = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/customer/industryCategory/' + id,
+    method: 'delete'
+  });
+};

+ 75 - 0
src/api/customer/customerCategory/industryCategory/types.ts

@@ -0,0 +1,75 @@
+export interface IndustryCategoryVO {
+  /**
+   * ID
+   */
+  id: string | number;
+
+  /**
+   * 所属行业
+   */
+  industryCategoryName: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode: string;
+}
+
+export interface IndustryCategoryForm extends BaseEntity {
+  /**
+   * ID
+   */
+  id?: string | number;
+
+  /**
+   * 所属行业
+   */
+  industryCategoryName?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+}
+
+export interface IndustryCategoryQuery extends PageQuery {
+  /**
+   * 所属行业
+   */
+  industryCategoryName?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+}

+ 63 - 0
src/api/customer/customerCategory/tagCategory/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { TagCategoryVO, TagCategoryForm, TagCategoryQuery } from '@/api/customer/customerCategory/tagCategory/types';
+
+/**
+ * 查询标签类别信息列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listTagCategory = (query?: TagCategoryQuery): AxiosPromise<TagCategoryVO[]> => {
+  return request({
+    url: '/customer/tagCategory/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询标签类别信息详细
+ * @param id
+ */
+export const getTagCategory = (id: string | number): AxiosPromise<TagCategoryVO> => {
+  return request({
+    url: '/customer/tagCategory/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增标签类别信息
+ * @param data
+ */
+export const addTagCategory = (data: TagCategoryForm) => {
+  return request({
+    url: '/customer/tagCategory',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改标签类别信息
+ * @param data
+ */
+export const updateTagCategory = (data: TagCategoryForm) => {
+  return request({
+    url: '/customer/tagCategory',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除标签类别信息
+ * @param id
+ */
+export const delTagCategory = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/customer/tagCategory/' + id,
+    method: 'delete'
+  });
+};

+ 75 - 0
src/api/customer/customerCategory/tagCategory/types.ts

@@ -0,0 +1,75 @@
+export interface TagCategoryVO {
+  /**
+   * ID
+   */
+  id: string | number;
+
+  /**
+   * 标签分类
+   */
+  tagCategoryName: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode: string;
+}
+
+export interface TagCategoryForm extends BaseEntity {
+  /**
+   * ID
+   */
+  id?: string | number;
+
+  /**
+   * 标签分类
+   */
+  tagCategoryName?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+}
+
+export interface TagCategoryQuery extends PageQuery {
+  /**
+   * 标签分类
+   */
+  tagCategoryName?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+}

+ 63 - 0
src/api/customer/customerFile/businessInfo/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { BusinessInfoVO, BusinessInfoForm, BusinessInfoQuery } from '@/api/customer/customerFile/businessInfo/types';
+
+/**
+ * 查询客户工商注册信息列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listBusinessInfo = (query?: BusinessInfoQuery): AxiosPromise<BusinessInfoVO[]> => {
+  return request({
+    url: '/customer/businessInfo/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询客户工商注册信息详细
+ * @param customerId
+ */
+export const getBusinessInfo = (customerId: string | number): AxiosPromise<BusinessInfoVO> => {
+  return request({
+    url: '/customer/businessInfo/' + customerId,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增客户工商注册信息
+ * @param data
+ */
+export const addBusinessInfo = (data: BusinessInfoForm) => {
+  return request({
+    url: '/customer/businessInfo',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改客户工商注册信息
+ * @param data
+ */
+export const updateBusinessInfo = (data: BusinessInfoForm) => {
+  return request({
+    url: '/customer/businessInfo',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除客户工商注册信息
+ * @param customerId
+ */
+export const delBusinessInfo = (customerId: string | number | Array<string | number>) => {
+  return request({
+    url: '/customer/businessInfo/' + customerId,
+    method: 'delete'
+  });
+};

+ 230 - 0
src/api/customer/customerFile/businessInfo/types.ts

@@ -0,0 +1,230 @@
+export interface BusinessInfoVO {
+  /**
+   * 关联客户ID
+   */
+  customerId: string | number;
+
+  /**
+   * 工商全称
+   */
+  businessCustomerName: string;
+
+  /**
+   * 统一社会信用代码
+   */
+  socialCreditCode: string;
+
+  /**
+   * 法人姓名
+   */
+  legalPersonName: string;
+
+  /**
+   * 注册资本
+   */
+  registeredCapital: string;
+
+  /**
+   * 实缴资本
+   */
+  paidInCapital: string | number;
+
+  /**
+   * 成立日期
+   */
+  establishmentDate: string;
+
+  /**
+   * 吊销日期
+   */
+  revocationDate: string;
+
+  /**
+   * 登记状态
+   */
+  registrationStatus: string;
+
+  /**
+   * 登记机关
+   */
+  registrationAuthority: string;
+
+  /**
+   * 经营范围
+   */
+  bussinessRange: string;
+
+  /**
+   * 营业执照路径
+   */
+  businessLicense: string;
+
+  /**
+   * 工商地址-详细地址
+   */
+  businessAddress: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+}
+
+export interface BusinessInfoForm extends BaseEntity {
+  /**
+   * 关联客户ID
+   */
+  customerId?: string | number;
+
+  /**
+   * 工商全称
+   */
+  businessCustomerName?: string;
+
+  /**
+   * 统一社会信用代码
+   */
+  socialCreditCode?: string;
+
+  /**
+   * 法人姓名
+   */
+  legalPersonName?: string;
+
+  /**
+   * 注册资本
+   */
+  registeredCapital?: string;
+
+  /**
+   * 实缴资本
+   */
+  paidInCapital?: string | number;
+
+  /**
+   * 成立日期
+   */
+  establishmentDate?: string;
+
+  /**
+   * 吊销日期
+   */
+  revocationDate?: string;
+
+  /**
+   * 登记状态
+   */
+  registrationStatus?: string;
+
+  /**
+   * 登记机关
+   */
+  registrationAuthority?: string;
+
+  /**
+   * 经营范围
+   */
+  bussinessRange?: string;
+
+  /**
+   * 营业执照路径
+   */
+  businessLicense?: string;
+
+  /**
+   * 工商地址-详细地址
+   */
+  businessAddress?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+}
+
+export interface BusinessInfoQuery extends PageQuery {
+  /**
+   * 工商全称
+   */
+  businessCustomerName?: string;
+
+  /**
+   * 统一社会信用代码
+   */
+  socialCreditCode?: string;
+
+  /**
+   * 法人姓名
+   */
+  legalPersonName?: string;
+
+  /**
+   * 注册资本
+   */
+  registeredCapital?: string;
+
+  /**
+   * 实缴资本
+   */
+  paidInCapital?: string | number;
+
+  /**
+   * 成立日期
+   */
+  establishmentDate?: string;
+
+  /**
+   * 吊销日期
+   */
+  revocationDate?: string;
+
+  /**
+   * 登记状态
+   */
+  registrationStatus?: string;
+
+  /**
+   * 登记机关
+   */
+  registrationAuthority?: string;
+
+  /**
+   * 经营范围
+   */
+  bussinessRange?: string;
+
+  /**
+   * 营业执照路径
+   */
+  businessLicense?: string;
+
+  /**
+   * 工商地址-详细地址
+   */
+  businessAddress?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+}

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { CustomerContactVO, CustomerContactForm, CustomerContactQuery } from '@/api/customer/customerFile/customerContact/types';
+
+/**
+ * 查询客户联系人信息列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listCustomerContact = (query?: CustomerContactQuery): AxiosPromise<CustomerContactVO[]> => {
+  return request({
+    url: '/customer/customerContact/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询客户联系人信息详细
+ * @param id
+ */
+export const getCustomerContact = (id: string | number): AxiosPromise<CustomerContactVO> => {
+  return request({
+    url: '/customer/customerContact/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增客户联系人信息
+ * @param data
+ */
+export const addCustomerContact = (data: CustomerContactForm) => {
+  return request({
+    url: '/customer/customerContact',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改客户联系人信息
+ * @param data
+ */
+export const updateCustomerContact = (data: CustomerContactForm) => {
+  return request({
+    url: '/customer/customerContact',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除客户联系人信息
+ * @param id
+ */
+export const delCustomerContact = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/customer/customerContact/' + id,
+    method: 'delete'
+  });
+};

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

@@ -0,0 +1,245 @@
+export interface CustomerContactVO {
+  /**
+   * 联系人ID
+   */
+  id: string | number;
+
+  /**
+   * 所属客户ID
+   */
+  customerId: string | number;
+
+  /**
+   * 联系人姓名
+   */
+  contactName: string;
+
+  /**
+   * 手机号码
+   */
+  phone: string;
+
+  /**
+   * 办公电话
+   */
+  officePhone: string;
+
+  /**
+   * 办公电话2
+   */
+  officePhoneTwo: string;
+
+  /**
+   * 性别
+   */
+  gender: string;
+
+  /**
+   * 采购角色(如:采购经理、财务)
+   */
+  roleId: string | number;
+
+  /**
+   * 是否主联系人:0=是,1=否
+   */
+  isPrimary: string;
+
+  /**
+   * 详细地址
+   */
+  addressDetail: string;
+
+  /**
+   * 所在省编码
+   */
+  addressProvince: string;
+
+  /**
+   * 所在市编码
+   */
+  addressCity: string;
+
+  /**
+   * 所在区县编码
+   */
+  addressCounty: string;
+
+  /**
+   * 省市区
+   */
+  provincialCityCounty: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+}
+
+export interface CustomerContactForm extends BaseEntity {
+  /**
+   * 联系人ID
+   */
+  id?: string | number;
+
+  /**
+   * 所属客户ID
+   */
+  customerId?: string | number;
+
+  /**
+   * 联系人姓名
+   */
+  contactName?: string;
+
+  /**
+   * 手机号码
+   */
+  phone?: string;
+
+  /**
+   * 办公电话
+   */
+  officePhone?: string;
+
+  /**
+   * 办公电话2
+   */
+  officePhoneTwo?: string;
+
+  /**
+   * 性别
+   */
+  gender?: string;
+
+  /**
+   * 采购角色(如:采购经理、财务)
+   */
+  roleId?: string | number;
+
+  /**
+   * 是否主联系人:0=是,1=否
+   */
+  isPrimary?: string;
+
+  /**
+   * 详细地址
+   */
+  addressDetail?: string;
+
+  /**
+   * 所在省编码
+   */
+  addressProvince?: string;
+
+  /**
+   * 所在市编码
+   */
+  addressCity?: string;
+
+  /**
+   * 所在区县编码
+   */
+  addressCounty?: string;
+
+  /**
+   * 省市区
+   */
+  provincialCityCounty?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+}
+
+export interface CustomerContactQuery extends PageQuery {
+  /**
+   * 所属客户ID
+   */
+  customerId?: string | number;
+
+  /**
+   * 联系人姓名
+   */
+  contactName?: string;
+
+  /**
+   * 手机号码
+   */
+  phone?: string;
+
+  /**
+   * 办公电话
+   */
+  officePhone?: string;
+
+  /**
+   * 办公电话2
+   */
+  officePhoneTwo?: string;
+
+  /**
+   * 性别
+   */
+  gender?: string;
+
+  /**
+   * 采购角色(如:采购经理、财务)
+   */
+  roleId?: string | number;
+
+  /**
+   * 是否主联系人:0=是,1=否
+   */
+  isPrimary?: string;
+
+  /**
+   * 详细地址
+   */
+  addressDetail?: string;
+
+  /**
+   * 所在省编码
+   */
+  addressProvince?: string;
+
+  /**
+   * 所在市编码
+   */
+  addressCity?: string;
+
+  /**
+   * 所在区县编码
+   */
+  addressCounty?: string;
+
+  /**
+   * 省市区
+   */
+  provincialCityCounty?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+}

+ 63 - 0
src/api/customer/customerFile/customerInfo/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { CustomerInfoVO, CustomerInfoForm, CustomerInfoQuery } from '@/api/customer/customerFile/customerInfo/types';
+
+/**
+ * 查询客户信息列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listCustomerInfo = (query?: CustomerInfoQuery): AxiosPromise<CustomerInfoVO[]> => {
+  return request({
+    url: '/customer/customerInfo/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询客户信息详细
+ * @param id
+ */
+export const getCustomerInfo = (id: string | number): AxiosPromise<CustomerInfoVO> => {
+  return request({
+    url: '/customer/customerInfo/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增客户信息
+ * @param data
+ */
+export const addCustomerInfo = (data: CustomerInfoForm) => {
+  return request({
+    url: '/customer/customerInfo',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改客户信息
+ * @param data
+ */
+export const updateCustomerInfo = (data: CustomerInfoForm) => {
+  return request({
+    url: '/customer/customerInfo',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除客户信息
+ * @param id
+ */
+export const delCustomerInfo = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/customer/customerInfo/' + id,
+    method: 'delete'
+  });
+};

+ 429 - 0
src/api/customer/customerFile/customerInfo/types.ts

@@ -0,0 +1,429 @@
+import type { BusinessInfoVO, BusinessInfoForm } from '../businessInfo/types';
+import type { CustomerContactVO, CustomerContactForm } from '../customerContact/types';
+import type { SalesInfoVO, SalesInfoForm } from '../salesInfo/types';
+import type { InvoiceInfoVO, InvoiceInfoForm } from '../invoiceInfo/types';
+
+export interface CustomerInfoVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 客户编号
+   */
+  customerNo: string;
+
+  /**
+   * 所属公司
+   */
+  belongCompanyId: string | number;
+
+  /**
+   * 客户名称
+   */
+  companyName: string;
+
+  /**
+   * 工商名称
+   */
+  businessCustomerName: string;
+
+  /**
+   * 企业简称
+   */
+  shortName: string;
+
+  /**
+   * 开票类型
+   */
+  invoiceTypeId: string | number;
+
+  /**
+   * 企业规模
+   */
+  enterpriseScaleId: string | number;
+
+  enterpriseScale: string;
+
+  /**
+   * 客户类别
+   */
+  customerTypeId: string | number;
+
+  /**
+   * 行业类别
+   */
+  industryCategoryId: string | number;
+
+  industryCategory: string;
+
+  /**
+   * 客户等级
+   */
+  customerLevelId: string | number;
+
+  /**
+   * 固定电话
+   */
+  landline: string;
+
+  /**
+   * 传真
+   */
+  fax: string;
+
+  /**
+   * 网址
+   */
+  url: string;
+
+  /**
+   * 邮政编码
+   */
+  postCode: string;
+
+  /**
+   * 开始时间
+   */
+  validityFromDate: string | number;
+
+  /**
+   * 结束时间
+   */
+  validityToDate: string | number;
+
+  /**
+   * 发票抬头
+   */
+  invoiceTop: string;
+
+  /**
+   * 详细地址(注册地址)
+   */
+  address: string;
+
+  /**
+   * 省份编码
+   */
+  regProvincialNo: string;
+
+  /**
+   * 城市编码
+   */
+  regCityNo: string;
+
+  /**
+   * 区县编码
+   */
+  regCountyNo: string;
+
+  /**
+   * 省市区
+   */
+  provincialCityCounty: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+  /**
+   * 工商信息
+   */
+  customerBusinessInfoVo?: BusinessInfoVO;
+
+  /**
+   * 销售信息
+   */
+  customerSalesInfoVo?: SalesInfoVO;
+
+  /**
+   * 联系人列表
+   */
+  customerContactVoList?: CustomerContactVO[];
+
+  /**
+   * 开票信息列表
+   */
+  customerInvoiceInfoVoList?: InvoiceInfoVO[];
+}
+
+export interface CustomerInfoForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 客户编号
+   */
+  customerNo?: string;
+
+  /**
+   * 所属公司
+   */
+  belongCompanyId?: string | number;
+
+  /**
+   * 客户名称
+   */
+  companyName?: string;
+
+  /**
+   * 工商名称
+   */
+  businessCustomerName?: string;
+
+  /**
+   * 企业简称
+   */
+  shortName?: string;
+
+  /**
+   * 开票类型
+   */
+  invoiceTypeId?: string | number;
+
+  /**
+   * 企业规模
+   */
+  enterpriseScaleId?: string | number;
+
+  /**
+   * 客户类别
+   */
+  customerTypeId?: string | number;
+
+  /**
+   * 行业类别
+   */
+  industryCategoryId?: string | number;
+
+  /**
+   * 客户等级
+   */
+  customerLevelId?: string | number;
+
+  /**
+   * 固定电话
+   */
+  landline?: string;
+
+  /**
+   * 传真
+   */
+  fax?: string;
+
+  /**
+   * 网址
+   */
+  url?: string;
+
+  /**
+   * 邮政编码
+   */
+  postCode?: string;
+
+  /**
+   * 开始时间
+   */
+  validityFromDate?: string | number;
+
+  /**
+   * 结束时间
+   */
+  validityToDate?: string | number;
+
+  /**
+   * 发票抬头
+   */
+  invoiceTop?: string;
+
+  /**
+   * 详细地址(注册地址)
+   */
+  address?: string;
+
+  /**
+   * 省份编码
+   */
+  regProvincialNo?: string;
+
+  /**
+   * 城市编码
+   */
+  regCityNo?: string;
+
+  /**
+   * 区县编码
+   */
+  regCountyNo?: string;
+
+  /**
+   * 省市区
+   */
+  provincialCityCounty?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+  /**
+   * 工商信息
+   */
+  customerBusinessBo?: BusinessInfoForm;
+
+  /**
+   * 销售信息
+   */
+  customerSalesInfoBo?: SalesInfoForm;
+
+  /**
+   * 联系人列表
+   */
+  customerContactBoList?: CustomerContactForm[];
+
+  /**
+   * 开票信息列表
+   */
+  customerInvoiceInfoBoList?: InvoiceInfoForm[];
+}
+
+export interface CustomerInfoQuery extends PageQuery {
+  /**
+   * 客户编号
+   */
+  customerNo?: string;
+
+  /**
+   * 所属公司
+   */
+  belongCompanyId?: string | number;
+
+  /**
+   * 客户名称
+   */
+  companyName?: string;
+
+  /**
+   * 工商名称
+   */
+  businessCustomerName?: string;
+
+  /**
+   * 企业简称
+   */
+  shortName?: string;
+
+  /**
+   * 开票类型
+   */
+  invoiceTypeId?: string | number;
+
+  /**
+   * 企业规模
+   */
+  enterpriseScaleId?: string | number;
+
+  /**
+   * 客户类别
+   */
+  customerTypeId?: string | number;
+
+  /**
+   * 行业类别
+   */
+  industryCategoryId?: string | number;
+
+  /**
+   * 客户等级
+   */
+  customerLevelId?: string | number;
+
+  /**
+   * 固定电话
+   */
+  landline?: string;
+
+  /**
+   * 传真
+   */
+  fax?: string;
+
+  /**
+   * 网址
+   */
+  url?: string;
+
+  /**
+   * 邮政编码
+   */
+  postCode?: string;
+
+  /**
+   * 开始时间
+   */
+  validityFromDate?: string | number;
+
+  /**
+   * 结束时间
+   */
+  validityToDate?: string | number;
+
+  /**
+   * 发票抬头
+   */
+  invoiceTop?: string;
+
+  /**
+   * 详细地址(注册地址)
+   */
+  address?: string;
+
+  /**
+   * 省份编码
+   */
+  regProvincialNo?: string;
+
+  /**
+   * 城市编码
+   */
+  regCityNo?: string;
+
+  /**
+   * 区县编码
+   */
+  regCountyNo?: string;
+
+  /**
+   * 省市区
+   */
+  provincialCityCounty?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+}

+ 63 - 0
src/api/customer/customerFile/invoiceInfo/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { InvoiceInfoVO, InvoiceInfoForm, InvoiceInfoQuery } from '@/api/customer/customerFile/invoiceInfo/types';
+
+/**
+ * 查询客户开票信息列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listInvoiceInfo = (query?: InvoiceInfoQuery): AxiosPromise<InvoiceInfoVO[]> => {
+  return request({
+    url: '/customer/invoiceInfo/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询客户开票信息详细
+ * @param id
+ */
+export const getInvoiceInfo = (id: string | number): AxiosPromise<InvoiceInfoVO> => {
+  return request({
+    url: '/customer/invoiceInfo/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增客户开票信息
+ * @param data
+ */
+export const addInvoiceInfo = (data: InvoiceInfoForm) => {
+  return request({
+    url: '/customer/invoiceInfo',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改客户开票信息
+ * @param data
+ */
+export const updateInvoiceInfo = (data: InvoiceInfoForm) => {
+  return request({
+    url: '/customer/invoiceInfo',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除客户开票信息
+ * @param id
+ */
+export const delInvoiceInfo = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/customer/invoiceInfo/' + id,
+    method: 'delete'
+  });
+};

+ 185 - 0
src/api/customer/customerFile/invoiceInfo/types.ts

@@ -0,0 +1,185 @@
+export interface InvoiceInfoVO {
+  /**
+   * 开票信息ID
+   */
+  id: string | number;
+
+  /**
+   * 所属客户ID
+   */
+  customerId: string | number;
+
+  /**
+   * 纳税人识别号
+   */
+  taxId: string | number;
+
+  /**
+   * 开户行行号
+   */
+  bankCode: string;
+
+  /**
+   * 开户行
+   */
+  bankId: string | number;
+
+  /**
+   * 开户行名称
+   */
+  bankName: string;
+
+  /**
+   * 银行账户
+   */
+  bankAccount: string;
+
+  /**
+   * 联系电话
+   */
+  phone: string;
+
+  /**
+   * 开户行地址
+   */
+  address: string;
+
+  /**
+   * 是否主账号:0=是,1=否
+   */
+  isPrimaryAccount: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+}
+
+export interface InvoiceInfoForm extends BaseEntity {
+  /**
+   * 开票信息ID
+   */
+  id?: string | number;
+
+  /**
+   * 所属客户ID
+   */
+  customerId?: string | number;
+
+  /**
+   * 纳税人识别号
+   */
+  taxId?: string | number;
+
+  /**
+   * 开户行行号
+   */
+  bankCode?: string;
+
+  /**
+   * 开户行
+   */
+  bankId?: string | number;
+
+  /**
+   * 开户行名称
+   */
+  bankName?: string;
+
+  /**
+   * 银行账户
+   */
+  bankAccount?: string;
+
+  /**
+   * 联系电话
+   */
+  phone?: string;
+
+  /**
+   * 开户行地址
+   */
+  address?: string;
+
+  /**
+   * 是否主账号:0=是,1=否
+   */
+  isPrimaryAccount?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+}
+
+export interface InvoiceInfoQuery extends PageQuery {
+  /**
+   * 所属客户ID
+   */
+  customerId?: string | number;
+
+  /**
+   * 纳税人识别号
+   */
+  taxId?: string | number;
+
+  /**
+   * 开户行行号
+   */
+  bankCode?: string;
+
+  /**
+   * 开户行
+   */
+  bankId?: string | number;
+
+  /**
+   * 开户行名称
+   */
+  bankName?: string;
+
+  /**
+   * 银行账户
+   */
+  bankAccount?: string;
+
+  /**
+   * 联系电话
+   */
+  phone?: string;
+
+  /**
+   * 开户行地址
+   */
+  address?: string;
+
+  /**
+   * 是否主账号:0=是,1=否
+   */
+  isPrimaryAccount?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+}

+ 63 - 0
src/api/customer/customerFile/salesInfo/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { SalesInfoVO, SalesInfoForm, SalesInfoQuery } from '@/api/customer/customerFile/salesInfo/types';
+
+/**
+ * 查询客户销售信息列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listSalesInfo = (query?: SalesInfoQuery): AxiosPromise<SalesInfoVO[]> => {
+  return request({
+    url: '/customer/salesInfo/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询客户销售信息详细
+ * @param id
+ */
+export const getSalesInfo = (id: string | number): AxiosPromise<SalesInfoVO> => {
+  return request({
+    url: '/customer/salesInfo/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增客户销售信息
+ * @param data
+ */
+export const addSalesInfo = (data: SalesInfoForm) => {
+  return request({
+    url: '/customer/salesInfo',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改客户销售信息
+ * @param data
+ */
+export const updateSalesInfo = (data: SalesInfoForm) => {
+  return request({
+    url: '/customer/salesInfo',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除客户销售信息
+ * @param id
+ */
+export const delSalesInfo = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/customer/salesInfo/' + id,
+    method: 'delete'
+  });
+};

+ 275 - 0
src/api/customer/customerFile/salesInfo/types.ts

@@ -0,0 +1,275 @@
+export interface SalesInfoVO {
+  /**
+   * 销售信息ID
+   */
+  id: string | number;
+
+  /**
+   * 关联客户ID
+   */
+  customerId: string | number;
+
+  /**
+   * 信用额度
+   */
+  creditAmount: number;
+
+  /**
+   * 剩余额度
+   */
+  remainingQuota: number;
+
+  /**
+   * 临时额度
+   */
+  temporaryQuota: number;
+
+  /**
+   * 账期(如:30天)
+   */
+  accountPeriod: string;
+
+  /**
+   * 账单日(每月几号)
+   */
+  billDate: number;
+
+  /**
+   * 计费日(如:每月1日)
+   */
+  billingDay: number;
+
+  /**
+   * 订单审核方式
+   */
+  orderAudit: string;
+
+  /**
+   * 信用管理方式
+   */
+  creditManagement: string;
+
+  /**
+   * 信用支付密码
+   */
+  creditPaymentPassword: string;
+
+  /**
+   * 付款天数
+   */
+  payDays: number;
+
+  /**
+   * 销售人员
+   */
+  salesPersonId: string | number;
+
+  /**
+   * 服务人员
+   */
+  serviceStaffId: string | number;
+
+  /**
+   * 所属部门
+   */
+  belongingDepartmentId: string | number;
+
+  /**
+   * 应收账款
+   */
+  accountsReceivable: number;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+}
+
+export interface SalesInfoForm extends BaseEntity {
+  /**
+   * 销售信息ID
+   */
+  id?: string | number;
+
+  /**
+   * 关联客户ID
+   */
+  customerId?: string | number;
+
+  /**
+   * 信用额度
+   */
+  creditAmount?: number;
+
+  /**
+   * 剩余额度
+   */
+  remainingQuota?: number;
+
+  /**
+   * 临时额度
+   */
+  temporaryQuota?: number;
+
+  /**
+   * 账期(如:30天)
+   */
+  accountPeriod?: string;
+
+  /**
+   * 账单日(每月几号)
+   */
+  billDate?: number;
+
+  /**
+   * 计费日(如:每月1日)
+   */
+  billingDay?: number;
+
+  /**
+   * 订单审核方式
+   */
+  orderAudit?: string;
+
+  /**
+   * 信用管理方式
+   */
+  creditManagement?: string;
+
+  /**
+   * 信用支付密码
+   */
+  creditPaymentPassword?: string;
+
+  /**
+   * 付款天数
+   */
+  payDays?: number;
+
+  /**
+   * 销售人员
+   */
+  salesPersonId?: string | number;
+
+  /**
+   * 服务人员
+   */
+  serviceStaffId?: string | number;
+
+  /**
+   * 所属部门
+   */
+  belongingDepartmentId?: string | number;
+
+  /**
+   * 应收账款
+   */
+  accountsReceivable?: number;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+}
+
+export interface SalesInfoQuery extends PageQuery {
+  /**
+   * 关联客户ID
+   */
+  customerId?: string | number;
+
+  /**
+   * 信用额度
+   */
+  creditAmount?: number;
+
+  /**
+   * 剩余额度
+   */
+  remainingQuota?: number;
+
+  /**
+   * 临时额度
+   */
+  temporaryQuota?: number;
+
+  /**
+   * 账期(如:30天)
+   */
+  accountPeriod?: string;
+
+  /**
+   * 账单日(每月几号)
+   */
+  billDate?: number;
+
+  /**
+   * 计费日(如:每月1日)
+   */
+  billingDay?: number;
+
+  /**
+   * 订单审核方式
+   */
+  orderAudit?: string;
+
+  /**
+   * 信用管理方式
+   */
+  creditManagement?: string;
+
+  /**
+   * 信用支付密码
+   */
+  creditPaymentPassword?: string;
+
+  /**
+   * 付款天数
+   */
+  payDays?: number;
+
+  /**
+   * 销售人员
+   */
+  salesPersonId?: string | number;
+
+  /**
+   * 服务人员
+   */
+  serviceStaffId?: string | number;
+
+  /**
+   * 所属部门
+   */
+  belongingDepartmentId?: string | number;
+
+  /**
+   * 应收账款
+   */
+  accountsReceivable?: number;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+}

+ 75 - 0
src/api/customer/maintainInfo/index.ts

@@ -0,0 +1,75 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { MaintainInfoVO, MaintainInfoForm, MaintainInfoQuery, AllotTechnicalAdviserForm } from '@/api/customer/maintainInfo/types';
+
+/**
+ * 查询维保记录列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listMaintainInfo = (query?: MaintainInfoQuery): AxiosPromise<MaintainInfoVO[]> => {
+  return request({
+    url: '/customer/maintainInfo/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询维保记录详细
+ * @param id
+ */
+export const getMaintainInfo = (id: string | number): AxiosPromise<MaintainInfoVO> => {
+  return request({
+    url: '/customer/maintainInfo/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增维保记录
+ * @param data
+ */
+export const addMaintainInfo = (data: MaintainInfoForm) => {
+  return request({
+    url: '/customer/maintainInfo',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改维保记录
+ * @param data
+ */
+export const updateMaintainInfo = (data: MaintainInfoForm) => {
+  return request({
+    url: '/customer/maintainInfo',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除维保记录
+ * @param id
+ */
+export const delMaintainInfo = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/customer/maintainInfo/' + id,
+    method: 'delete'
+  });
+};
+
+/**
+ * 分配技术顾问
+ * @param data
+ */
+export const allotTechnicalAdviser = (data: AllotTechnicalAdviserForm) => {
+  return request({
+    url: '/customer/maintainInfo/allotTechnicalAdviser',
+    method: 'post',
+    data: data
+  });
+};

+ 405 - 0
src/api/customer/maintainInfo/types.ts

@@ -0,0 +1,405 @@
+export interface MaintainInfoVO {
+  /**
+   * ID
+   */
+  id: string | number;
+
+  /**
+   * 关联客户ID
+   */
+  customerId: string | number;
+
+  /**
+   * 维保单号
+   */
+  maintainNo: string;
+
+  /**
+   * 客户编号
+   */
+  customerNo: string;
+
+  /**
+   * 申请人姓名
+   */
+  applicantName: string;
+
+  /**
+   * 申请人电话
+   */
+  applicantPhone: string;
+
+  /**
+   * 服务时长
+   */
+  serviceTime: string;
+
+  /**
+   * 每月维保次数
+   */
+  monthMainten: number;
+
+  /**
+   * 剩余维保次数
+   */
+  remainingMainten: number;
+
+  /**
+   * 维保总次数限制
+   */
+  maintenLimit: number;
+
+  /**
+   * 服务内容
+   */
+  serviceContent: string;
+
+  /**
+   * 其他服务内容
+   */
+  otherService: string;
+
+  /**
+   * 服务开始时间
+   */
+  serviceStartTime: string;
+
+  /**
+   * 服务结束时间
+   */
+  serviceEndTime: string;
+
+  /**
+   * 维保状态
+   */
+  maintainStatus: string;
+
+  /**
+   * 服务工程师
+   */
+  serviceEngineerId: string | number;
+
+  /**
+   * 服务工程师姓名
+   */
+  serviceEngineer: string;
+
+  /**
+   * 工程师联系电话
+   */
+  engineerPhone: string;
+
+  /**
+   * 技术顾问
+   */
+  technicalAdviserId: string | number;
+
+  /**
+   * 技术顾问姓名
+   */
+  technicalAdviser: string;
+
+  /**
+   * 技术顾问联系电话
+   */
+  technicalAdviserPhone: string;
+
+  /**
+   * 维保附件路径或文件名
+   */
+  maintainFile: string;
+
+  /**
+   * 维保类型
+   */
+  maintainType: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+}
+
+export interface MaintainInfoForm extends BaseEntity {
+  /**
+   * ID
+   */
+  id?: string | number;
+
+  /**
+   * 关联客户ID
+   */
+  customerId?: string | number;
+
+  /**
+   * 维保单号
+   */
+  maintainNo?: string;
+
+  /**
+   * 客户编号
+   */
+  customerNo?: string;
+
+  /**
+   * 申请人姓名
+   */
+  applicantName?: string;
+
+  /**
+   * 申请人电话
+   */
+  applicantPhone?: string;
+
+  /**
+   * 服务时长
+   */
+  serviceTime?: string;
+
+  /**
+   * 每月维保次数
+   */
+  monthMainten?: number;
+
+  /**
+   * 剩余维保次数
+   */
+  remainingMainten?: number;
+
+  /**
+   * 维保总次数限制
+   */
+  maintenLimit?: number;
+
+  /**
+   * 服务内容
+   */
+  serviceContent?: string;
+
+  /**
+   * 其他服务内容
+   */
+  otherService?: string;
+
+  /**
+   * 服务开始时间
+   */
+  serviceStartTime?: string;
+
+  /**
+   * 服务结束时间
+   */
+  serviceEndTime?: string;
+
+  /**
+   * 维保状态
+   */
+  maintainStatus?: string;
+
+  /**
+   * 服务工程师
+   */
+  serviceEngineerId?: string | number;
+
+  /**
+   * 服务工程师姓名
+   */
+  serviceEngineer?: string;
+
+  /**
+   * 工程师联系电话
+   */
+  engineerPhone?: string;
+
+  /**
+   * 技术顾问
+   */
+  technicalAdviserId?: string | number;
+
+  /**
+   * 技术顾问姓名
+   */
+  technicalAdviser?: string;
+
+  /**
+   * 技术顾问联系电话
+   */
+  technicalAdviserPhone?: string;
+
+  /**
+   * 维保附件路径或文件名
+   */
+  maintainFile?: string;
+
+  /**
+   * 维保类型
+   */
+  maintainType?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+}
+
+export interface MaintainInfoQuery extends PageQuery {
+  /**
+   * 关联客户ID
+   */
+  customerId?: string | number;
+
+  /**
+   * 维保单号
+   */
+  maintainNo?: string;
+
+  /**
+   * 客户编号
+   */
+  customerNo?: string;
+
+  /**
+   * 申请人姓名
+   */
+  applicantName?: string;
+
+  /**
+   * 申请人电话
+   */
+  applicantPhone?: string;
+
+  /**
+   * 服务时长
+   */
+  serviceTime?: string;
+
+  /**
+   * 每月维保次数
+   */
+  monthMainten?: number;
+
+  /**
+   * 剩余维保次数
+   */
+  remainingMainten?: number;
+
+  /**
+   * 维保总次数限制
+   */
+  maintenLimit?: number;
+
+  /**
+   * 服务内容
+   */
+  serviceContent?: string;
+
+  /**
+   * 其他服务内容
+   */
+  otherService?: string;
+
+  /**
+   * 服务开始时间
+   */
+  serviceStartTime?: string;
+
+  /**
+   * 服务结束时间
+   */
+  serviceEndTime?: string;
+
+  /**
+   * 维保状态
+   */
+  maintainStatus?: string;
+
+  /**
+   * 服务工程师
+   */
+  serviceEngineerId?: string | number;
+
+  /**
+   * 服务工程师姓名
+   */
+  serviceEngineer?: string;
+
+  /**
+   * 工程师联系电话
+   */
+  engineerPhone?: string;
+
+  /**
+   * 技术顾问
+   */
+  technicalAdviserId?: string | number;
+
+  /**
+   * 技术顾问姓名
+   */
+  technicalAdviser?: string;
+
+  /**
+   * 技术顾问联系电话
+   */
+  technicalAdviserPhone?: string;
+
+  /**
+   * 维保附件路径或文件名
+   */
+  maintainFile?: string;
+
+  /**
+   * 维保类型
+   */
+  maintainType?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+}
+
+/**
+ * 分配技术顾问表单
+ */
+export interface AllotTechnicalAdviserForm {
+  /**
+   * 维保记录ID
+   */
+  id: string | number;
+
+  /**
+   * 技术顾问ID
+   */
+  technicalAdviserId: string | number;
+
+  /**
+   * 技术顾问姓名
+   */
+  technicalAdviser: string;
+
+  /**
+   * 技术顾问联系电话
+   */
+  technicalAdviserPhone: string;
+}

+ 1 - 1
src/layout/components/Sidebar/Logo.vue

@@ -20,7 +20,7 @@
       <router-link key="collapse" class="sidebar-logo-link" to="/">
         <!-- <img v-if="logo" :src="logo" class="sidebar-logo" /> -->
         <h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">
-          优易达-OMS订单管理系统
+          优易商城-客户营销智能化管理平台
         </h1>
       </router-link>
     </transition>

+ 60 - 0
src/utils/customerNumber.ts

@@ -0,0 +1,60 @@
+/**
+ * 客户编号生成工具
+ */
+
+const CUSTOMER_NUMBER_KEY = 'customer_number_counter';
+
+/**
+ * 获取当前客户编号计数器
+ */
+const getCounter = (): number => {
+  const counter = localStorage.getItem(CUSTOMER_NUMBER_KEY);
+  return counter ? parseInt(counter, 10) : 1;
+};
+
+/**
+ * 保存客户编号计数器
+ */
+const saveCounter = (counter: number): void => {
+  localStorage.setItem(CUSTOMER_NUMBER_KEY, counter.toString());
+};
+
+/**
+ * 生成新的客户编号
+ * 格式:6位数字,从 000001 开始自增
+ * @returns 格式化的客户编号,如:000001, 000002, 000003...
+ */
+export const generateCustomerNumber = (): string => {
+  const currentCounter = getCounter();
+  const newCounter = currentCounter + 1;
+  saveCounter(newCounter);
+
+  // 格式化为6位数字,不足补0
+  return newCounter.toString().padStart(6, '0');
+};
+
+/**
+ * 获取下一个客户编号(不自增,仅预览)
+ * @returns 下一个客户编号
+ */
+export const getNextCustomerNumber = (): string => {
+  const currentCounter = getCounter();
+  const nextCounter = currentCounter + 1;
+  return nextCounter.toString().padStart(6, '0');
+};
+
+/**
+ * 重置客户编号计数器
+ * @param startNumber 起始编号,默认 1
+ */
+export const resetCustomerNumberCounter = (startNumber: number = 1): void => {
+  saveCounter(startNumber - 1);
+};
+
+/**
+ * 设置客户编号计数器
+ * @param counter 当前计数器值
+ */
+export const setCustomerNumberCounter = (counter: number): void => {
+  saveCounter(counter);
+};

+ 326 - 0
src/views/customer/customerCategory/customerTag/index.vue

@@ -0,0 +1,326 @@
+<template>
+  <div class="p-2">
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="21">
+            <span>标签类别信息列表</span>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['customer:customerTag:add']">新增</el-button>
+          </el-col>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="customerTagList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="ID" align="center" prop="id" v-if="true" />
+        <el-table-column label="标签名称" align="center" prop="tagName" />
+        <el-table-column label="匹配商品标签" align="center" prop="productTagIds">
+          <template #default="scope">
+            <span v-if="scope.row.productTagIds">
+              {{ formatProductTags(scope.row.productTagIds) }}
+            </span>
+            <span v-else class="text-gray-400">-</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="状态" align="center" prop="status">
+          <template #default="scope">
+            <span>{{ scope.row.status == '0' ? '启用' : '不启用' }} </span>
+          </template>
+        </el-table-column>
+        <el-table-column label="备注" align="center" prop="remark" />
+        <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)" v-hasPermi="['customer:customerTag:edit']">编辑</el-button>
+            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['customer:customerTag:remove']"
+              >删除</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改客户标签对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="600px" append-to-body>
+      <el-form ref="customerTagFormRef" :model="form" :rules="rules" label-width="120px">
+        <el-form-item label="标签名称" prop="tagName">
+          <el-input v-model="form.tagName" placeholder="请输入标签名称" />
+        </el-form-item>
+        <el-form-item label="关联产品标签" prop="productTagIds">
+          <div class="w-full">
+            <!-- 已选择的标签 -->
+            <div class="mb-2" v-if="selectedProductTags.length > 0">
+              <el-tag v-for="tagId in selectedProductTags" :key="tagId" closable @close="removeTag(tagId)" class="mr-2 mb-2" type="primary">
+                {{ getTagName(tagId) }}
+              </el-tag>
+            </div>
+            <!-- 搜索框 -->
+            <div class="flex gap-2 mb-2">
+              <el-input v-model="searchKeyword" placeholder="请输入关联名称" clearable />
+              <el-button type="primary" @click="handleSearch">搜索</el-button>
+            </div>
+            <div class="text-sm text-gray-500 mb-2">
+              已选择 <span class="text-red-500">{{ selectedProductTags.length }}</span> 条
+            </div>
+            <!-- 可选标签列表 -->
+            <div class="border rounded bg-gray-50" style="min-height: 200px; max-height: 300px; overflow-y: auto">
+              <!-- 表头 -->
+              <div class="bg-gray-100 px-4 py-3 border-b flex items-center">
+                <el-checkbox v-model="selectAll" @change="handleSelectAll" class="mr-3" />
+                <span class="font-medium">可选标签</span>
+              </div>
+              <!-- 内容区 -->
+              <div class="p-4">
+                <div class="text-center text-gray-400 py-4" v-if="filteredProductTags.length === 0">暂无数据</div>
+                <el-checkbox-group v-else v-model="selectedProductTags" @change="handleProductTagChange" class="flex flex-wrap gap-2">
+                  <el-checkbox v-for="tag in filteredProductTags" :key="tag.id" :value="tag.id">
+                    {{ tag.name }}
+                  </el-checkbox>
+                </el-checkbox-group>
+              </div>
+            </div>
+          </div>
+        </el-form-item>
+        <el-form-item label="是否启用" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio v-for="dict in is_enabled" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="CustomerTag" lang="ts">
+import { listCustomerTag, getCustomerTag, delCustomerTag, addCustomerTag, updateCustomerTag } from '@/api/customer/customerCategory/customerTag';
+import { CustomerTagVO, CustomerTagQuery, CustomerTagForm } from '@/api/customer/customerCategory/customerTag/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { is_enabled } = toRefs<any>(proxy?.useDict('is_enabled'));
+
+const customerTagList = ref<CustomerTagVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+// 商品标签假数据
+const productTagList = ref([
+  { id: 1, name: '热销商品' },
+  { id: 2, name: '旅游首选' },
+  { id: 3, name: '物美价廉' },
+  { id: 4, name: '性价比高' },
+  { id: 5, name: '价格便宜' }
+]);
+
+const searchKeyword = ref('');
+const selectedProductTags = ref<number[]>([]);
+const selectAll = ref(false);
+const filteredProductTags = computed(() => {
+  if (!searchKeyword.value) {
+    return productTagList.value;
+  }
+  return productTagList.value.filter((tag) => tag.name.toLowerCase().includes(searchKeyword.value.toLowerCase()));
+});
+
+const queryFormRef = ref<ElFormInstance>();
+const customerTagFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: CustomerTagForm = {
+  id: undefined,
+  tagName: undefined,
+  productTagIds: undefined,
+  status: '0',
+  remark: undefined
+};
+const data = reactive<PageData<CustomerTagForm, CustomerTagQuery>>({
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    tagName: undefined,
+    productTagIds: undefined,
+    status: undefined,
+    platformCode: undefined,
+    params: {}
+  },
+  rules: {
+    tagName: [{ required: true, message: '标签名称不能为空', trigger: 'blur' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询客户标签列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listCustomerTag(queryParams.value);
+  customerTagList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData };
+  customerTagFormRef.value?.resetFields();
+  selectedProductTags.value = [];
+  searchKeyword.value = '';
+  selectAll.value = false;
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+};
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: CustomerTagVO[]) => {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加客户标签';
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: CustomerTagVO) => {
+  reset();
+  const _id = row?.id || ids.value[0];
+  const res = await getCustomerTag(_id);
+  Object.assign(form.value, res.data);
+  // 回显已选择的商品标签
+  if (res.data.productTagIds) {
+    selectedProductTags.value = res.data.productTagIds.split(',').map(Number);
+  }
+  dialog.visible = true;
+  dialog.title = '修改客户标签';
+};
+
+/** 搜索商品标签 */
+const handleSearch = () => {
+  // 搜索逻辑已通过 computed 实现
+};
+
+/** 商品标签选择变化 */
+const handleProductTagChange = (value: number[]) => {
+  form.value.productTagIds = value.join(',');
+  updateSelectAllState();
+};
+
+/** 根据标签ID获取标签名称 */
+const getTagName = (tagId: number) => {
+  const tag = productTagList.value.find((t) => t.id === tagId);
+  return tag ? tag.name : '';
+};
+
+/** 移除已选择的标签 */
+const removeTag = (tagId: number) => {
+  selectedProductTags.value = selectedProductTags.value.filter((id) => id !== tagId);
+  form.value.productTagIds = selectedProductTags.value.join(',');
+  updateSelectAllState();
+};
+
+/** 全选/取消全选 */
+const handleSelectAll = (checked: boolean) => {
+  if (checked) {
+    selectedProductTags.value = filteredProductTags.value.map((tag) => tag.id);
+  } else {
+    selectedProductTags.value = [];
+  }
+  form.value.productTagIds = selectedProductTags.value.join(',');
+};
+
+/** 更新全选状态 */
+const updateSelectAllState = () => {
+  selectAll.value = filteredProductTags.value.length > 0 && selectedProductTags.value.length === filteredProductTags.value.length;
+};
+
+/** 格式化商品标签显示(将ID转换为名称) */
+const formatProductTags = (productTagIds: string) => {
+  if (!productTagIds) return '-';
+  const ids = productTagIds.split(',').map(Number);
+  const names = ids
+    .map((id) => {
+      const tag = productTagList.value.find((t) => t.id === id);
+      return tag ? tag.name : '';
+    })
+    .filter((name) => name);
+  return names.join('、') || '-';
+};
+
+/** 提交按钮 */
+const submitForm = () => {
+  customerTagFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateCustomerTag(form.value).finally(() => (buttonLoading.value = false));
+      } else {
+        await addCustomerTag(form.value).finally(() => (buttonLoading.value = false));
+      }
+      proxy?.$modal.msgSuccess('操作成功');
+      dialog.visible = false;
+      await getList();
+    }
+  });
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: CustomerTagVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除客户标签编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delCustomerTag(_ids);
+  proxy?.$modal.msgSuccess('删除成功');
+  await getList();
+};
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download(
+    'customer/customerTag/export',
+    {
+      ...queryParams.value
+    },
+    `customerTag_${new Date().getTime()}.xlsx`
+  );
+};
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 204 - 0
src/views/customer/customerCategory/enterpriseScale/index.vue

@@ -0,0 +1,204 @@
+<template>
+  <div class="p-2">
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="21">
+            <span>标签类别信息列表</span>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['customer:enterpriseScale:remove']"
+              >批量删除</el-button
+            >
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['customer:enterpriseScale:add']">新增</el-button>
+          </el-col>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="enterpriseScaleList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="企业规模" align="center" prop="enterpriseScaleName" />
+        <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)" v-hasPermi="['customer:enterpriseScale:edit']"
+              >编辑</el-button
+            >
+            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['customer:enterpriseScale:remove']"
+              >删除</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改企业规模对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="enterpriseScaleFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="企业规模" prop="enterpriseScaleName">
+          <el-input v-model="form.enterpriseScaleName" placeholder="请输入企业规模" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="EnterpriseScale" lang="ts">
+import {
+  listEnterpriseScale,
+  getEnterpriseScale,
+  delEnterpriseScale,
+  addEnterpriseScale,
+  updateEnterpriseScale
+} from '@/api/customer/customerCategory/enterpriseScale';
+import { EnterpriseScaleVO, EnterpriseScaleQuery, EnterpriseScaleForm } from '@/api/customer/customerCategory/enterpriseScale/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const enterpriseScaleList = ref<EnterpriseScaleVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const enterpriseScaleFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: EnterpriseScaleForm = {
+  id: undefined,
+  enterpriseScaleName: undefined,
+  status: undefined,
+  remark: undefined,
+  platformCode: undefined
+};
+const data = reactive<PageData<EnterpriseScaleForm, EnterpriseScaleQuery>>({
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    enterpriseScaleName: undefined,
+    status: undefined,
+    platformCode: undefined,
+    params: {}
+  },
+  rules: {
+    enterpriseScaleName: [{ required: true, message: '企业规模不能为空', trigger: 'blur' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询企业规模列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listEnterpriseScale(queryParams.value);
+  enterpriseScaleList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData };
+  enterpriseScaleFormRef.value?.resetFields();
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+};
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: EnterpriseScaleVO[]) => {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加企业规模';
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: EnterpriseScaleVO) => {
+  reset();
+  const _id = row?.id || ids.value[0];
+  const res = await getEnterpriseScale(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = '修改企业规模';
+};
+
+/** 提交按钮 */
+const submitForm = () => {
+  enterpriseScaleFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateEnterpriseScale(form.value).finally(() => (buttonLoading.value = false));
+      } else {
+        await addEnterpriseScale(form.value).finally(() => (buttonLoading.value = false));
+      }
+      proxy?.$modal.msgSuccess('操作成功');
+      dialog.visible = false;
+      await getList();
+    }
+  });
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: EnterpriseScaleVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除企业规模编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delEnterpriseScale(_ids);
+  proxy?.$modal.msgSuccess('删除成功');
+  await getList();
+};
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download(
+    'customer/enterpriseScale/export',
+    {
+      ...queryParams.value
+    },
+    `enterpriseScale_${new Date().getTime()}.xlsx`
+  );
+};
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 210 - 0
src/views/customer/customerCategory/industryCategory/index.vue

@@ -0,0 +1,210 @@
+<template>
+  <div class="p-2">
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="21">
+            <span>标签类别信息列表</span>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button
+              type="danger"
+              plain
+              icon="Delete"
+              :disabled="multiple"
+              @click="handleDelete()"
+              v-hasPermi="['customer:industryCategory:remove']"
+              >批量删除</el-button
+            >
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['customer:industryCategory:add']">新增</el-button>
+          </el-col>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="industryCategoryList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="所属行业" align="center" prop="industryCategoryName" />
+        <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)" v-hasPermi="['customer:industryCategory:edit']"
+              >编辑</el-button
+            >
+            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['customer:industryCategory:remove']"
+              >删除</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改所属行业对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="industryCategoryFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="所属行业" prop="industryCategoryName">
+          <el-input v-model="form.industryCategoryName" placeholder="请输入所属行业" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="IndustryCategory" lang="ts">
+import {
+  listIndustryCategory,
+  getIndustryCategory,
+  delIndustryCategory,
+  addIndustryCategory,
+  updateIndustryCategory
+} from '@/api/customer/customerCategory/industryCategory';
+import { IndustryCategoryVO, IndustryCategoryQuery, IndustryCategoryForm } from '@/api/customer/customerCategory/industryCategory/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const industryCategoryList = ref<IndustryCategoryVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const industryCategoryFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: IndustryCategoryForm = {
+  id: undefined,
+  industryCategoryName: undefined,
+  status: undefined,
+  remark: undefined,
+  platformCode: undefined
+};
+const data = reactive<PageData<IndustryCategoryForm, IndustryCategoryQuery>>({
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    industryCategoryName: undefined,
+    status: undefined,
+    platformCode: undefined,
+    params: {}
+  },
+  rules: {
+    industryCategoryName: [{ required: true, message: '所属行业不能为空', trigger: 'blur' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询所属行业列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listIndustryCategory(queryParams.value);
+  industryCategoryList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData };
+  industryCategoryFormRef.value?.resetFields();
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+};
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: IndustryCategoryVO[]) => {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加所属行业';
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: IndustryCategoryVO) => {
+  reset();
+  const _id = row?.id || ids.value[0];
+  const res = await getIndustryCategory(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = '修改所属行业';
+};
+
+/** 提交按钮 */
+const submitForm = () => {
+  industryCategoryFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateIndustryCategory(form.value).finally(() => (buttonLoading.value = false));
+      } else {
+        await addIndustryCategory(form.value).finally(() => (buttonLoading.value = false));
+      }
+      proxy?.$modal.msgSuccess('操作成功');
+      dialog.visible = false;
+      await getList();
+    }
+  });
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: IndustryCategoryVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除所属行业编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delIndustryCategory(_ids);
+  proxy?.$modal.msgSuccess('删除成功');
+  await getList();
+};
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download(
+    'customer/industryCategory/export',
+    {
+      ...queryParams.value
+    },
+    `industryCategory_${new Date().getTime()}.xlsx`
+  );
+};
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 191 - 0
src/views/customer/customerCategory/tagCategory/index.vue

@@ -0,0 +1,191 @@
+<template>
+  <div class="p-2">
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="22">
+            <span>标签类别信息列表</span>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['customer:tagCategory:add']">新增</el-button>
+          </el-col>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="tagCategoryList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="标签类别" align="center" prop="tagCategoryName" />
+        <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)" v-hasPermi="['customer:tagCategory:edit']">编辑</el-button>
+            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['customer:tagCategory:remove']"
+              >删除</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改标签类别信息对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="tagCategoryFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="类别名称" prop="tagCategoryName">
+          <el-input v-model="form.tagCategoryName" placeholder="请输入类别名称" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="TagCategory" lang="ts">
+import { listTagCategory, getTagCategory, delTagCategory, addTagCategory, updateTagCategory } from '@/api/customer/customerCategory/tagCategory';
+import { TagCategoryVO, TagCategoryQuery, TagCategoryForm } from '@/api/customer/customerCategory/tagCategory/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const tagCategoryList = ref<TagCategoryVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const tagCategoryFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: TagCategoryForm = {
+  id: undefined,
+  tagCategoryName: undefined,
+  status: undefined,
+  remark: undefined,
+  platformCode: undefined
+};
+const data = reactive<PageData<TagCategoryForm, TagCategoryQuery>>({
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    tagCategoryName: undefined,
+    status: undefined,
+    platformCode: undefined,
+    params: {}
+  },
+  rules: {
+    tagCategoryName: [{ required: true, message: '标签分类不能为空', trigger: 'blur' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询标签类别信息列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listTagCategory(queryParams.value);
+  tagCategoryList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData };
+  tagCategoryFormRef.value?.resetFields();
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+};
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: TagCategoryVO[]) => {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加标签类别信息';
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: TagCategoryVO) => {
+  reset();
+  const _id = row?.id || ids.value[0];
+  const res = await getTagCategory(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = '修改标签类别信息';
+};
+
+/** 提交按钮 */
+const submitForm = () => {
+  tagCategoryFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateTagCategory(form.value).finally(() => (buttonLoading.value = false));
+      } else {
+        await addTagCategory(form.value).finally(() => (buttonLoading.value = false));
+      }
+      proxy?.$modal.msgSuccess('操作成功');
+      dialog.visible = false;
+      await getList();
+    }
+  });
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: TagCategoryVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除标签类别信息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delTagCategory(_ids);
+  proxy?.$modal.msgSuccess('删除成功');
+  await getList();
+};
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download(
+    'customer/tagCategory/export',
+    {
+      ...queryParams.value
+    },
+    `tagCategory_${new Date().getTime()}.xlsx`
+  );
+};
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 656 - 0
src/views/customer/customerFile/customerInfo/add.vue

@@ -0,0 +1,656 @@
+<template>
+  <div class="p-4">
+    <!-- 企业基本信息 -->
+    <el-card shadow="never" class="mb-4">
+      <template #header>
+        <span class="font-medium"
+          >企业基本信息/ <span style="color: #ff0033"> 客户编号:{{ customerNumber }} </span></span
+        >
+        <el-button style="float: right" type="primary" @click="handleSubmit" :loading="submitLoading">保存</el-button>
+      </template>
+      <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="所属公司" prop="belongCompanyId">
+              <el-select v-model="form.belongCompanyId" placeholder="请选择所属公司" class="w-full" filterable>
+                <el-option label="公司A" value="1" />
+                <el-option label="公司B" value="2" />
+                <el-option label="公司C" value="3" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="客户名称" prop="companyName">
+              <el-input v-model="form.companyName" placeholder="请输入客户名称" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="工商名称" prop="businessCustomerName">
+              <el-input v-model="form.businessCustomerName" placeholder="请输入工商名称" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="企业简称" prop="shortName">
+              <el-input v-model="form.shortName" placeholder="请输入企业简称" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="开票类型" prop="invoiceTypeId">
+              <el-select v-model="form.invoiceTypeId" placeholder="请选择开票类型" class="w-full">
+                <el-option label="增值税专用发票" value="1" />
+                <el-option label="增值税普通发票" value="2" />
+                <el-option label="电子发票" value="3" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="企业规模" prop="enterpriseScaleId">
+              <el-select v-model="form.enterpriseScaleId" placeholder="请选择企业规模" class="w-full" filterable>
+                <el-option v-for="item in enterpriseScaleList" :key="item.id" :label="item.enterpriseScaleName" :value="item.id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="客户类别" prop="customerTypeId">
+              <el-select v-model="form.customerTypeId" placeholder="请选择客户类别" class="w-full">
+                <el-option label="重点客户" value="1" />
+                <el-option label="普通客户" value="2" />
+                <el-option label="潜在客户" value="3" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="行业类别" prop="industryCategoryId">
+              <el-select v-model="form.industryCategoryId" placeholder="请选择行业类别" class="w-full" filterable>
+                <el-option v-for="item in industryCategoryList" :key="item.id" :label="item.industryCategoryName" :value="item.id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="客户等级" prop="customerLevelId">
+              <el-select v-model="form.customerLevelId" placeholder="请选择客户等级" class="w-full">
+                <el-option label="A级" value="1" />
+                <el-option label="B级" value="2" />
+                <el-option label="C级" value="3" />
+                <el-option label="D级" value="4" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="固定电话" prop="landline">
+              <el-input v-model="form.landline" placeholder="请输入固定电话" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="传真" prop="fax">
+              <el-input v-model="form.fax" placeholder="请输入传真" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="网址" prop="url">
+              <el-input v-model="form.url" placeholder="请输入网址" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="邮政编码" prop="postCode">
+              <el-input v-model="form.postCode" placeholder="请输入邮政编码" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="开始时间" prop="validityFromDate">
+              <el-date-picker v-model="form.validityFromDate" type="date" placeholder="请选择开始时间" class="w-full" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="结束时间" prop="validityToDate">
+              <el-date-picker v-model="form.validityToDate" type="date" placeholder="请选择结束时间" class="w-full" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="发票抬头" prop="invoiceTop">
+              <el-input v-model="form.invoiceTop" placeholder="请输入发票抬头" />
+            </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>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item prop="address">
+              <el-input v-model="form.address" placeholder="请输入详细地址" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+    </el-card>
+
+    <!-- 工商信息 -->
+    <el-card shadow="never" class="mb-4">
+      <template #header>
+        <span class="font-medium">工商信息</span>
+      </template>
+      <el-form :model="businessForm" label-width="120px">
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="企业工商名称" prop="businessCustomerName">
+              <el-input v-model="businessForm.businessCustomerName" placeholder="请输入企业工商名称" :disabled="true" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="社会信用代码" prop="socialCreditCode">
+              <el-input v-model="businessForm.socialCreditCode" placeholder="请输入社会信用代码" :disabled="true" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="法人姓名" prop="legalPersonName">
+              <el-input v-model="businessForm.legalPersonName" placeholder="请输入法人姓名" :disabled="true" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="注册资本" prop="registeredCapital">
+              <el-input v-model="businessForm.registeredCapital" placeholder="请输入注册资本" :disabled="true" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="登记机关" prop="registrationAuthority">
+              <el-input v-model="businessForm.registrationAuthority" placeholder="请输入登记机关" :disabled="true" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="成立日期" prop="establishmentDate">
+              <el-input v-model="businessForm.establishmentDate" class="w-full" :disabled="true" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="吊销日期" prop="revocationDate">
+              <el-input v-model="businessForm.revocationDate" class="w-full" :disabled="true" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="登记状态" prop="registrationStatus">
+              <el-input v-model="businessForm.registrationStatus" placeholder="请输入登记状态" :disabled="true" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="实缴资本" prop="paidInCapital">
+              <el-input v-model="businessForm.paidInCapital" placeholder="请输入实缴资本" :disabled="true" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="16">
+            <el-form-item label="详细地址" prop="businessAddress">
+              <el-input v-model="businessForm.businessAddress" placeholder="请输入详细地址" :disabled="true" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="营业执照" prop="businessLicense">
+              <el-upload action="#" :auto-upload="false">
+                <el-button icon="Plus">上传</el-button>
+              </el-upload>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+    </el-card>
+
+    <!-- 联系人信息列表 -->
+    <el-card shadow="never" class="mb-4">
+      <template #header>
+        <div class="flex justify-between items-center">
+          <span class="font-medium">联系人信息列表</span>
+          <el-button type="primary" @click="handleAddContact">添加联系人</el-button>
+        </div>
+      </template>
+      <el-table :data="contactList" border>
+        <el-table-column type="index" label="序号" align="center" width="60" />
+        <el-table-column label="联系人姓名" align="center" prop="contactName" min-width="120" />
+        <el-table-column label="职位" align="center" prop="roleId" min-width="120">
+          <template #default="{ row }">
+            <span>{{ getRoleName(row.roleId) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="手机号" align="center" prop="phone" min-width="150" />
+        <el-table-column label="固定电话" align="center" prop="officePhone" min-width="150" />
+        <el-table-column label="邮箱地址" align="center" prop="email" min-width="180" />
+        <el-table-column label="备注信息" align="center" prop="remark" min-width="180" />
+        <el-table-column label="操作" align="center" width="150" fixed="right">
+          <template #default="{ row, $index }">
+            <el-button link type="primary" @click="handleEditContact(row, $index)">编辑</el-button>
+            <el-button link type="danger" @click="removeContact($index)">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </el-card>
+
+    <!-- 添加/编辑联系人对话框 -->
+    <add-contact-dialog v-model="contactDialogVisible" :edit-data="currentContact" @confirm="handleContactConfirm" />
+
+    <!-- 销售信息 -->
+    <el-card shadow="never" class="mb-4">
+      <template #header>
+        <div class="flex justify-between items-center">
+          <span class="font-medium">销售信息</span>
+          <el-button type="primary" @click="handleSubmit" :loading="submitLoading">保存</el-button>
+        </div>
+      </template>
+      <el-form :model="salesForm" label-width="120px">
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="业务人员" prop="salesPersonId">
+              <el-select v-model="salesForm.salesPersonId" placeholder="请选择业务人员" class="w-full" filterable>
+                <el-option label="张三" value="1" />
+                <el-option label="李四" value="2" />
+                <el-option label="王五" value="3" />
+                <el-option label="赵六" value="4" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="客服人员" prop="serviceStaffId">
+              <el-select v-model="salesForm.serviceStaffId" placeholder="请选择客服人员" class="w-full" filterable>
+                <el-option label="客服A" value="1" />
+                <el-option label="客服B" value="2" />
+                <el-option label="客服C" value="3" />
+                <el-option label="客服D" value="4" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="所属部门" prop="belongingDepartmentId">
+              <el-select v-model="salesForm.belongingDepartmentId" placeholder="请选择所属部门" class="w-full" filterable>
+                <el-option label="销售部" value="1" />
+                <el-option label="市场部" value="2" />
+                <el-option label="客服部" value="3" />
+                <el-option label="技术部" value="4" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+    </el-card>
+
+    <!-- 企业开票信息 -->
+    <el-card shadow="never" class="mb-4">
+      <template #header>
+        <div class="flex justify-between items-center">
+          <span class="font-medium">企业开票信息</span>
+          <el-button type="primary" @click="handleAddInvoice">新增</el-button>
+        </div>
+      </template>
+      <el-table :data="invoiceList" border>
+        <el-table-column type="index" label="序号" align="center" width="60" />
+        <el-table-column label="纳税人识别号" align="center" prop="taxId" min-width="180" />
+        <el-table-column label="开户行名称" align="center" prop="bankName" min-width="180" />
+        <el-table-column label="银行账户" align="center" prop="bankAccount" min-width="180" />
+        <el-table-column label="是否主账号" align="center" prop="isPrimaryAccount" min-width="120">
+          <template #default="{ row }">
+            <span>{{ row.isPrimaryAccount === '0' ? '是' : '否' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="备注" align="center" prop="remark" min-width="180" />
+        <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>
+          </template>
+        </el-table-column>
+      </el-table>
+    </el-card>
+
+    <!-- 添加/编辑开票信息对话框 -->
+    <add-invoice-dialog v-model="invoiceDialogVisible" :edit-data="currentInvoice" @confirm="handleInvoiceConfirm" />
+  </div>
+</template>
+
+<script setup lang="ts" name="CustomerInfoAdd">
+import { listCustomerInfo, getCustomerInfo, delCustomerInfo, addCustomerInfo, updateCustomerInfo } from '@/api/customer/customerFile/customerInfo';
+import { CustomerInfoVO, CustomerInfoQuery, CustomerInfoForm } from '@/api/customer/customerFile/customerInfo/types';
+import { generateCustomerNumber } from '@/utils/customerNumber';
+import type { CustomerContactForm } from '@/api/customer/customerFile/customerContact/types';
+import type { InvoiceInfoForm } from '@/api/customer/customerFile/invoiceInfo/types';
+import type { SalesInfoForm } from '@/api/customer/customerFile/salesInfo/types';
+import type { BusinessInfoForm } from '@/api/customer/customerFile/businessInfo/types';
+import AddContactDialog from './components/addContactDialog.vue';
+import AddInvoiceDialog from './components/addInvoiceDialog.vue';
+import { regionData } from 'element-china-area-data';
+import { listEnterpriseScale } from '@/api/customer/customerCategory/enterpriseScale';
+import { listIndustryCategory } from '@/api/customer/customerCategory/industryCategory';
+import type { EnterpriseScaleVO } from '@/api/customer/customerCategory/enterpriseScale/types';
+import type { IndustryCategoryVO } from '@/api/customer/customerCategory/industryCategory/types';
+
+const route = useRoute();
+const router = useRouter();
+
+const formRef = ref<any>(null);
+const submitLoading = ref(false);
+
+// 生成客户编号
+const customerNumber = ref('');
+const isEdit = ref(false);
+const customerId = ref<string>('');
+const codeArr = ref([]);
+
+// 下拉框数据列表
+const enterpriseScaleList = ref<EnterpriseScaleVO[]>([]);
+const industryCategoryList = ref<IndustryCategoryVO[]>([]);
+
+// 初始化
+onMounted(async () => {
+  // 加载下拉框数据
+  await loadEnterpriseScaleList();
+  await loadIndustryCategoryList();
+
+  // 判断是新增还是编辑
+  const id = route.query.id;
+  if (id) {
+    // 编辑模式
+    isEdit.value = true;
+    customerId.value = id as string;
+    await loadCustomerData(id);
+  } else {
+    // 新增模式,生成客户编号
+    customerNumber.value = generateCustomerNumber();
+  }
+});
+
+// 加载客户数据(编辑模式)
+const loadCustomerData = async (id: string) => {
+  try {
+    const res = await getCustomerInfo(id);
+    const data = res.data;
+
+    // 填充基本信息
+    Object.assign(form, data);
+    customerNumber.value = data.customerNo || '';
+
+    // 填充工商信息
+    if (data.customerBusinessInfoVo) {
+      Object.assign(businessForm, data.customerBusinessInfoVo);
+    }
+
+    // 填充销售信息
+    if (data.customerSalesInfoVo) {
+      Object.assign(salesForm, data.customerSalesInfoVo);
+    }
+
+    // 填充联系人列表
+    if (data.customerContactVoList) {
+      contactList.value = data.customerContactVoList;
+    }
+
+    // 填充开票信息列表
+    if (data.customerInvoiceInfoVoList) {
+      invoiceList.value = data.customerInvoiceInfoVoList;
+    }
+
+    // 如果有省市区编码,回显到级联选择器
+    if (data.regProvincialNo && data.regCityNo && data.regCountyNo) {
+      codeArr.value = [data.regProvincialNo, data.regCityNo, data.regCountyNo] as any;
+    }
+  } catch (error) {
+    console.error('加载客户数据失败:', error);
+    ElMessage.error('加载客户数据失败');
+  }
+};
+
+// 加载企业规模列表
+const loadEnterpriseScaleList = async () => {
+  try {
+    const res = await listEnterpriseScale();
+    enterpriseScaleList.value = res.rows || [];
+  } catch (error) {
+    console.error('加载企业规模列表失败:', error);
+  }
+};
+
+// 加载行业类别列表
+const loadIndustryCategoryList = async () => {
+  try {
+    const res = await listIndustryCategory();
+    industryCategoryList.value = res.rows || [];
+  } catch (error) {
+    console.error('加载行业类别列表失败:', error);
+  }
+};
+
+// 企业基本信息表单
+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 = {
+  companyName: [{ required: true, message: '请输入客户名称', trigger: 'blur' }]
+};
+
+// 获取角色名称
+const getRoleName = (roleId: string | number | undefined) => {
+  const roleMap: Record<string, string> = {
+    '1': '采购经理',
+    '2': '财务',
+    '3': '其他'
+  };
+  return roleMap[String(roleId)] || '-';
+};
+
+// 打开添加联系人对话框
+const handleAddContact = () => {
+  currentContact.value = undefined;
+  currentContactIndex.value = -1;
+  contactDialogVisible.value = true;
+};
+/** 处理区域选择变化 */
+const handleChange = (val: string[]) => {
+  // 保存编码
+  form.regProvincialNo = val[0];
+  form.regCityNo = val[1];
+  form.regCountyNo = val[2];
+
+  // 根据编码获取名称
+  const names: string[] = [];
+  if (val[0]) {
+    const province = regionData.find((item: any) => item.value === val[0]);
+    if (province) {
+      names.push(province.label);
+
+      if (val[1] && province.children) {
+        const city = province.children.find((item: any) => item.value === val[1]);
+        if (city) {
+          names.push(city.label);
+
+          if (val[2] && city.children) {
+            const county = city.children.find((item: any) => item.value === val[2]);
+            if (county) {
+              names.push(county.label);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  // 将省市区名称用斜杠连接
+  form.provincialCityCounty = names.join('/');
+};
+// 编辑联系人
+const handleEditContact = (row: CustomerContactForm, index: number) => {
+  currentContact.value = { ...row };
+  currentContactIndex.value = index;
+  contactDialogVisible.value = true;
+};
+
+// 确认添加/编辑联系人
+const handleContactConfirm = (data: CustomerContactForm) => {
+  if (currentContactIndex.value >= 0) {
+    // 编辑
+    contactList.value[currentContactIndex.value] = data;
+  } else {
+    // 新增
+    contactList.value.push(data);
+  }
+};
+
+// 删除联系人
+const removeContact = (index: number) => {
+  ElMessageBox.confirm('确定要删除该联系人吗?', '提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning'
+  })
+    .then(() => {
+      contactList.value.splice(index, 1);
+      ElMessage.success('删除成功');
+    })
+    .catch(() => {});
+};
+
+// 打开添加开票信息对话框
+const handleAddInvoice = () => {
+  currentInvoice.value = undefined;
+  currentInvoiceIndex.value = -1;
+  invoiceDialogVisible.value = true;
+};
+
+// 编辑开票信息
+const handleEditInvoice = (row: InvoiceInfoForm, index: number) => {
+  currentInvoice.value = { ...row };
+  currentInvoiceIndex.value = index;
+  invoiceDialogVisible.value = true;
+};
+
+// 确认添加/编辑开票信息
+const handleInvoiceConfirm = (data: InvoiceInfoForm) => {
+  if (currentInvoiceIndex.value >= 0) {
+    // 编辑
+    invoiceList.value[currentInvoiceIndex.value] = data;
+  } else {
+    // 新增
+    invoiceList.value.push(data);
+  }
+};
+
+// 删除开票信息
+const removeInvoice = (index: number) => {
+  ElMessageBox.confirm('确定要删除该开票信息吗?', '提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning'
+  })
+    .then(() => {
+      invoiceList.value.splice(index, 1);
+      ElMessage.success('删除成功');
+    })
+    .catch(() => {});
+};
+
+// 提交表单
+const handleSubmit = async () => {
+  try {
+    await formRef.value?.validate();
+    submitLoading.value = true;
+
+    // 将客户编号赋值到表单
+    form.customerNo = customerNumber.value;
+
+    // 组装提交数据,按照后端要求的结构
+    const submitData: CustomerInfoForm = {
+      ...form,
+      customerBusinessBo: businessForm,
+      customerSalesInfoBo: salesForm,
+      customerContactBoList: contactList.value,
+      customerInvoiceInfoBoList: invoiceList.value
+    };
+
+    await addCustomerInfo(submitData);
+    ElMessage.success('添加成功');
+
+    router.back();
+  } catch (error) {
+    console.error('保存失败:', error);
+    ElMessage.error('保存失败,请重试');
+  } finally {
+    submitLoading.value = false;
+  }
+};
+</script>

+ 212 - 0
src/views/customer/customerFile/customerInfo/components/addContactDialog.vue

@@ -0,0 +1,212 @@
+<template>
+  <el-dialog v-model="visible" title="添加联系人" width="800px" @close="handleClose">
+    <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="联系人姓名" prop="contactName">
+            <el-input v-model="form.contactName" placeholder="请输入联系人姓名" />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="手机号码" prop="phone">
+            <el-input v-model="form.phone" placeholder="请输入手机号码" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="办公电话" prop="officePhone">
+            <el-input v-model="form.officePhone" placeholder="请输入办公电话" />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="办公电话1" prop="officePhoneTwo">
+            <el-input v-model="form.officePhoneTwo" placeholder="请输入办公电话" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="采购角色" prop="roleId">
+            <el-select v-model="form.roleId" placeholder="请选择" class="w-full">
+              <el-option label="采购经理" value="1" />
+              <el-option label="财务" value="2" />
+              <el-option label="其他" value="3" />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="性别" prop="gender">
+            <el-radio-group v-model="form.gender">
+              <el-radio value="">保密</el-radio>
+              <el-radio value="0">男</el-radio>
+              <el-radio value="1">女</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="主联系人" prop="isPrimary">
+            <el-radio-group v-model="form.isPrimary">
+              <el-radio value="0">是</el-radio>
+              <el-radio value="1">否</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="详细地址" prop="addressDetail">
+            <el-cascader v-model="codeArr" :options="regionData" placeholder="请选择" @change="handleChange" style="width: 100%"></el-cascader>
+            <el-input v-model="form.addressDetail" type="textarea" :rows="3" placeholder="请输入详细地址" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button type="primary" @click="handleConfirm">确认</el-button>
+        <el-button @click="handleClose">取消</el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup lang="ts">
+import type { CustomerContactForm } from '@/api/customer/customerFile/customerContact/types';
+import { regionData } from 'element-china-area-data';
+interface Props {
+  modelValue: boolean;
+  editData?: CustomerContactForm;
+}
+
+interface Emits {
+  (e: 'update:modelValue', value: boolean): void;
+  (e: 'confirm', data: CustomerContactForm): void;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  modelValue: false,
+  editData: undefined
+});
+
+const emit = defineEmits<Emits>();
+const codeArr = ref([]);
+const formRef = ref<any>(null);
+
+const visible = computed({
+  get: () => props.modelValue,
+  set: (val) => emit('update:modelValue', val)
+});
+
+const form = reactive<CustomerContactForm>({
+  contactName: '',
+  phone: '',
+  officePhone: '',
+  officePhoneTwo: '',
+  gender: '',
+  roleId: undefined,
+  isPrimary: '1',
+  addressDetail: '',
+  addressProvince: '',
+  addressCity: '',
+  addressCounty: '',
+  provincialCityCounty: '',
+  status: '0',
+  remark: ''
+});
+
+const rules = {
+  contactName: [{ required: true, message: '请输入联系人姓名', trigger: 'blur' }],
+  phone: [
+    { required: true, message: '请输入手机号码', trigger: 'blur' },
+    { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
+  ],
+  roleId: [{ required: true, message: '请选择采购角色', trigger: 'change' }],
+  addressDetail: [{ required: true, message: '请输入详细地址', trigger: 'blur' }]
+};
+
+// 监听编辑数据
+watch(
+  () => props.editData,
+  (newVal) => {
+    if (newVal) {
+      Object.assign(form, newVal);
+    }
+  },
+  { immediate: true, deep: true }
+);
+
+/** 处理区域选择变化 */
+const handleChange = (val: string[]) => {
+  // 保存编码
+  form.addressProvince = val[0];
+  form.addressCity = val[1];
+  form.addressCounty = val[2];
+
+  // 根据编码获取名称
+  const names: string[] = [];
+  if (val[0]) {
+    const province = regionData.find((item: any) => item.value === val[0]);
+    if (province) {
+      names.push(province.label);
+
+      if (val[1] && province.children) {
+        const city = province.children.find((item: any) => item.value === val[1]);
+        if (city) {
+          names.push(city.label);
+
+          if (val[2] && city.children) {
+            const county = city.children.find((item: any) => item.value === val[2]);
+            if (county) {
+              names.push(county.label);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  // 将省市区名称用斜杠连接
+  form.provincialCityCounty = names.join('/');
+};
+
+// 确认
+const handleConfirm = async () => {
+  try {
+    await formRef.value?.validate();
+    emit('confirm', { ...form });
+    handleClose();
+  } catch (error) {
+    console.error('表单验证失败:', error);
+  }
+};
+
+// 关闭
+const handleClose = () => {
+  formRef.value?.resetFields();
+  Object.assign(form, {
+    contactName: '',
+    phone: '',
+    officePhone: '',
+    officePhoneTwo: '',
+    gender: '',
+    roleId: undefined,
+    isPrimary: '1',
+    addressDetail: '',
+    addressProvince: '',
+    addressCity: '',
+    addressCounty: '',
+    provincialCityCounty: '',
+    status: '0',
+    remark: ''
+  });
+  emit('update:modelValue', false);
+};
+</script>

+ 170 - 0
src/views/customer/customerFile/customerInfo/components/addInvoiceDialog.vue

@@ -0,0 +1,170 @@
+<template>
+  <el-dialog v-model="visible" title="新增开票信息" width="800px" @close="handleClose">
+    <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="纳税人识别号" prop="taxId">
+            <el-input v-model="form.taxId" placeholder="">
+              <template #append>
+                <el-button>还原</el-button>
+              </template>
+            </el-input>
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="开户行行号" prop="bankCode">
+            <el-input v-model="form.bankCode" placeholder="请输入开户行行号" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="开户行名称" prop="bankName">
+            <el-select v-model="form.bankName" placeholder="请选择" class="w-full" filterable>
+              <el-option label="中国工商银行" value="中国工商银行" />
+              <el-option label="中国农业银行" value="中国农业银行" />
+              <el-option label="中国银行" value="中国银行" />
+              <el-option label="中国建设银行" value="中国建设银行" />
+              <el-option label="交通银行" value="交通银行" />
+              <el-option label="招商银行" value="招商银行" />
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="银行账户" prop="bankAccount">
+            <el-input v-model="form.bankAccount" placeholder="请输入银行账户" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="电话" prop="phone">
+            <el-input v-model="form.phone" placeholder="请输入电话" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="地址" prop="address">
+            <el-input v-model="form.address" placeholder="" />
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row :gutter="20">
+        <el-col :span="24">
+          <el-form-item label="是否主账号" prop="isPrimaryAccount">
+            <el-radio-group v-model="form.isPrimaryAccount">
+              <el-radio value="0">是</el-radio>
+              <el-radio value="1">否</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button type="primary" @click="handleConfirm">确认</el-button>
+        <el-button @click="handleClose">取消</el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup lang="ts">
+import type { InvoiceInfoForm } from '@/api/customer/customerFile/invoiceInfo/types';
+
+interface Props {
+  modelValue: boolean;
+  editData?: InvoiceInfoForm;
+}
+
+interface Emits {
+  (e: 'update:modelValue', value: boolean): void;
+  (e: 'confirm', data: InvoiceInfoForm): void;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  modelValue: false,
+  editData: undefined
+});
+
+const emit = defineEmits<Emits>();
+
+const formRef = ref<any>(null);
+
+const visible = computed({
+  get: () => props.modelValue,
+  set: (val) => emit('update:modelValue', val)
+});
+
+const form = reactive<InvoiceInfoForm>({
+  taxId: undefined,
+  bankCode: '',
+  bankId: undefined,
+  bankName: '',
+  bankAccount: '',
+  phone: '',
+  address: '',
+  isPrimaryAccount: '0',
+  status: '0',
+  remark: ''
+});
+
+const rules = {
+  bankCode: [{ required: true, message: '请输入开户行行号', trigger: 'blur' }],
+  bankName: [{ required: true, message: '请选择开户行名称', trigger: 'change' }],
+  bankAccount: [{ required: true, message: '请输入银行账户', trigger: 'blur' }],
+  phone: [{ required: true, message: '请输入电话', trigger: 'blur' }]
+};
+
+// 监听编辑数据
+watch(
+  () => props.editData,
+  (newVal) => {
+    if (newVal) {
+      Object.assign(form, newVal);
+    }
+  },
+  { immediate: true, deep: true }
+);
+
+// 确认
+const handleConfirm = async () => {
+  try {
+    await formRef.value?.validate();
+    emit('confirm', { ...form });
+    handleClose();
+  } catch (error) {
+    console.error('表单验证失败:', error);
+  }
+};
+
+// 关闭
+const handleClose = () => {
+  formRef.value?.resetFields();
+  Object.assign(form, {
+    taxId: undefined,
+    bankCode: '',
+    bankId: undefined,
+    bankName: '',
+    bankAccount: '',
+    phone: '',
+    address: '',
+    isPrimaryAccount: '0',
+    status: '0',
+    remark: ''
+  });
+  emit('update:modelValue', false);
+};
+</script>

+ 1 - 0
src/views/customer/customerFile/customerInfo/edit.vue

@@ -0,0 +1 @@
+<template>测试</template>

+ 365 - 0
src/views/customer/customerFile/customerInfo/index.vue

@@ -0,0 +1,365 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="所属公司" prop="belongCompanyId">
+              <el-select v-model="queryParams.belongCompanyId" placeholder="请选择所属公司" clearable filterable style="width: 200px">
+                <el-option label="公司A" value="1" />
+                <el-option label="公司B" value="2" />
+                <el-option label="公司C" value="3" />
+              </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.companyName" 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 label="A级" value="1" />
+                <el-option label="B级" value="2" />
+                <el-option label="C级" value="3" />
+                <el-option label="D级" value="4" />
+              </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 label="制造业" value="1" />
+                <el-option label="服务业" value="2" />
+                <el-option label="贸易" value="3" />
+                <el-option label="科技" value="4" />
+                <el-option label="金融" value="5" />
+                <el-option label="其他" value="6" />
+              </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 label="张三" value="1" />
+                <el-option label="李四" value="2" />
+                <el-option label="王五" value="3" />
+                <el-option label="赵六" value="4" />
+              </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 label="客服A" value="1" />
+                <el-option label="客服B" value="2" />
+                <el-option label="客服C" value="3" />
+                <el-option label="客服D" value="4" />
+              </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 label="销售部" value="1" />
+                <el-option label="市场部" value="2" />
+                <el-option label="客服部" value="3" />
+                <el-option label="技术部" value="4" />
+              </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 label="VIP客户" value="1" />
+                <el-option label="重点客户" value="2" />
+                <el-option label="优质客户" value="3" />
+                <el-option label="普通客户" value="4" />
+                <el-option label="潜在客户" value="5" />
+              </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-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['customer:customerInfo:add']">新增</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="20"><span>客户信息列表</span> </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['customer:customerInfo:edit']"
+              >修改</el-button
+            >
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['customer:customerInfo:remove']"
+              >删除</el-button
+            >
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['customer:customerInfo:export']">导出</el-button>
+          </el-col>
+        </el-row>
+      </template>
+
+      <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="companyName" min-width="200" show-overflow-tooltip />
+        <el-table-column label="归属公司" align="center" prop="belongCompanyId" min-width="150">
+          <template #default="scope">
+            <span>{{ getCompanyName(scope.row.belongCompanyId) }}</span>
+          </template>
+        </el-table-column>
+        <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" prop="salesPersonId" min-width="100">
+          <template #default="scope">
+            <span>{{ getSalesPersonName(scope.row.customerSalesInfoVo?.salesPersonId) }}</span>
+          </template>
+        </el-table-column>
+
+        <el-table-column label="客服人员" align="center" prop="serviceStaffId" min-width="100">
+          <template #default="scope">
+            <span>{{ getServiceStaffName(scope.row.customerSalesInfoVo?.serviceStaffId) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="归属部门" align="center" prop="belongingDepartmentId" min-width="120">
+          <template #default="scope">
+            <span>{{ getDepartmentName(scope.row.customerSalesInfoVo?.belongingDepartmentId) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="信用额" align="center" prop="creditAmount" min-width="80"> </el-table-column>
+        <el-table-column label="状态" align="center" prop="status" min-width="80">
+          <template #default="scope">
+            <el-tag :type="scope.row.status === '0' ? 'success' : 'danger'">
+              {{ scope.row.status === '0' ? '正常' : '停用' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" align="center" width="150" fixed="right">
+          <template #default="scope">
+            <el-button link type="primary" @click="handleUpdate(scope.row)" v-hasPermi="['customer:customerInfo:edit']">编辑</el-button>
+            <el-button link type="danger" @click="handleDelete(scope.row)" v-hasPermi="['customer:customerInfo:remove']">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+  </div>
+</template>
+
+<script setup name="CustomerInfo" lang="ts">
+import { listCustomerInfo, getCustomerInfo, delCustomerInfo, addCustomerInfo, updateCustomerInfo } from '@/api/customer/customerFile/customerInfo';
+import { CustomerInfoVO, CustomerInfoQuery, CustomerInfoForm } from '@/api/customer/customerFile/customerInfo/types';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const router = useRouter();
+const customerInfoList = ref<CustomerInfoVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const customerInfoFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: CustomerInfoForm = {
+  id: undefined,
+  customerNo: undefined,
+  belongCompanyId: undefined,
+  companyName: undefined,
+  businessCustomerName: undefined,
+  shortName: undefined,
+  invoiceTypeId: undefined,
+  enterpriseScaleId: undefined,
+  customerTypeId: undefined,
+  industryCategoryId: undefined,
+  customerLevelId: undefined,
+  landline: undefined,
+  fax: undefined,
+  url: undefined,
+  postCode: undefined,
+  validityFromDate: undefined,
+  validityToDate: undefined,
+  invoiceTop: undefined,
+  address: undefined,
+  regProvincialNo: undefined,
+  regCityNo: undefined,
+  regCountyNo: undefined,
+  provincialCityCounty: undefined,
+  status: undefined,
+  remark: undefined
+};
+const data = reactive<PageData<CustomerInfoForm, CustomerInfoQuery>>({
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    belongCompanyId: undefined,
+    customerNo: undefined,
+    companyName: undefined,
+    customerLevelId: undefined,
+    industryCategoryId: undefined,
+    salesPersonId: undefined,
+    serviceStaffId: undefined,
+    belongingDepartmentId: undefined,
+    customerTag: undefined,
+    platformCode: undefined,
+    params: {}
+  },
+  rules: {
+    customerNo: [{ required: true, message: '客户编号不能为空', trigger: 'blur' }],
+    belongCompanyId: [{ required: true, message: '所属公司不能为空', trigger: 'change' }],
+    companyName: [{ 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' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+// 格式化方法
+const getCompanyName = (id: string | number | undefined) => {
+  const map: Record<string, string> = { '1': '公司A', '2': '公司B', '3': '公司C' };
+  return map[String(id)] || '-';
+};
+
+const getCustomerLevelName = (id: string | number | undefined) => {
+  const map: Record<string, string> = { '1': 'A级', '2': 'B级', '3': 'C级', '4': 'D级' };
+  return map[String(id)] || '-';
+};
+
+const getIndustryName = (id: string | number | undefined) => {
+  const map: Record<string, string> = {
+    '1': '制造业',
+    '2': '服务业',
+    '3': '贸易',
+    '4': '科技',
+    '5': '金融',
+    '6': '其他'
+  };
+  return map[String(id)] || '-';
+};
+
+const getSalesPersonName = (id: string | number | undefined) => {
+  const map: Record<string, string> = { '1': '张三', '2': '李四', '3': '王五', '4': '赵六' };
+  return map[String(id)] || '-';
+};
+
+const getServiceStaffName = (id: string | number | undefined) => {
+  const map: Record<string, string> = { '1': '客服A', '2': '客服B', '3': '客服C', '4': '客服D' };
+  return map[String(id)] || '-';
+};
+
+const getDepartmentName = (id: string | number | undefined) => {
+  const map: Record<string, string> = { '1': '销售部', '2': '市场部', '3': '客服部', '4': '技术部' };
+  return map[String(id)] || '-';
+};
+
+/** 查询客户信息列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listCustomerInfo(queryParams.value);
+  customerInfoList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData };
+  customerInfoFormRef.value?.resetFields();
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+};
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: CustomerInfoVO[]) => {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  router.push({
+    path: '/customer/customer-add'
+  });
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: CustomerInfoVO) => {
+  const _id = row?.customerNo || ids.value[0];
+  router.push({
+    path: '/customer/customer-overview',
+    query: { id: _id, status: 'edit' }
+  });
+};
+
+/** 提交按钮 */
+const submitForm = () => {
+  customerInfoFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateCustomerInfo(form.value).finally(() => (buttonLoading.value = false));
+      } else {
+        await addCustomerInfo(form.value).finally(() => (buttonLoading.value = false));
+      }
+      proxy?.$modal.msgSuccess('操作成功');
+      dialog.visible = false;
+      await getList();
+    }
+  });
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: CustomerInfoVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除客户信息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delCustomerInfo(_ids);
+  proxy?.$modal.msgSuccess('删除成功');
+  await getList();
+};
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download(
+    'customer/customerInfo/export',
+    {
+      ...queryParams.value
+    },
+    `customerInfo_${new Date().getTime()}.xlsx`
+  );
+};
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 425 - 0
src/views/customer/maintainInfo/add.vue

@@ -0,0 +1,425 @@
+<template>
+  <div class="p-4">
+    <!-- 页面标题和按钮 -->
+    <div class="flex justify-between items-center mb-4">
+      <div class="flex items-center gap-2">
+        <el-button icon="ArrowLeft" @click="router.back()">返回</el-button>
+        <span class="text-lg font-medium">{{ isEdit ? '编辑' : '新增' }}维保</span>
+      </div>
+    </div>
+
+    <!-- 企业基本信息 -->
+    <el-card shadow="never" class="mb-4">
+      <template #header>
+        <span class="font-medium">企业基本信息</span>
+      </template>
+      <el-form :model="form" label-width="140px">
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="企业名称" prop="customerId">
+              <el-select v-model="form.customerId" placeholder="请选择企业" class="w-full" filterable @change="handleCustomerChange">
+                <el-option v-for="customer in customerList" :key="customer.id" :label="customer.companyName" :value="customer.id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="企业规模">
+              <el-input v-model="customerInfo.enterpriseScale" disabled />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="所属行业">
+              <el-input v-model="customerInfo.industryCategory" disabled />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="合作等级">
+              <el-input v-model="customerInfo.cooperationLevel" disabled />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="会员等级">
+              <el-input v-model="customerInfo.memberLevel" disabled />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="固定电话">
+              <el-input v-model="customerInfo.phone" disabled />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="办公地址">
+              <el-input v-model="customerInfo.provincialCityCounty" disabled />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item>
+              <el-input v-model="customerInfo.address" disabled />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+    </el-card>
+
+    <!-- 销售信息 -->
+    <el-card shadow="never" class="mb-4">
+      <template #header>
+        <span class="font-medium">销售信息</span>
+      </template>
+      <el-form :model="form" label-width="140px">
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="业务员">
+              <el-input v-model="customerInfo.salesPerson" disabled placeholder="请选择" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="客服人员">
+              <el-input v-model="customerInfo.servicePerson" disabled placeholder="请选择" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+    </el-card>
+
+    <!-- 维保信息 -->
+    <el-card shadow="never" class="mb-4">
+      <template #header>
+        <span class="font-medium">维保信息</span>
+      </template>
+      <el-form ref="maintainFormRef" :model="form" :rules="rules" label-width="140px">
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="申请人名称" prop="applicantName">
+              <el-input v-model="form.applicantName" placeholder="请输入申请人名称" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="申请人手机号" prop="applicantPhone">
+              <el-input v-model="form.applicantPhone" placeholder="请输入申请人手机号" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="服务时间(月)" prop="serviceTime">
+              <el-select v-model="form.serviceTime" placeholder="请选择服务时间" class="w-full" filterable>
+                <el-option v-for="dict in service_time_type" :key="dict.value" :label="dict.label" :value="dict.value" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="月度维保次数" prop="monthMainten">
+              <el-input-number
+                v-model="form.monthMainten"
+                :min="0"
+                :controls="false"
+                class="w-full"
+                placeholder="请输入月度维保次数"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="剩余维保次数" prop="remainingMainten">
+              <el-input
+                v-model="form.remainingMainten"
+                :min="0"
+                :controls="false"
+                class="w-full"
+                placeholder="请输入剩余维保次数"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="维保次数限制" prop="maintenLimit">
+              <el-input v-model="form.maintenLimit" :min="0" class="w-full" :controls="false" placeholder="请输入维保次数限制" style="width: 100%" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="服务工程师" prop="serviceEngineer">
+              <el-select v-model="form.serviceEngineer" placeholder="请选择" class="w-full" filterable>
+                <el-option label="工程师A" value="工程师A" />
+                <el-option label="工程师B" value="工程师B" />
+                <el-option label="工程师C" value="工程师C" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="工程师电话" prop="engineerPhone">
+              <el-input v-model="form.engineerPhone" placeholder="请输入工程师电话" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="开始时间" prop="serviceStartTime">
+              <el-date-picker
+                v-model="form.serviceStartTime"
+                type="date"
+                placeholder="请选择"
+                class="w-full"
+                value-format="YYYY-MM-DD"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="结束时间" prop="serviceEndTime">
+              <el-date-picker
+                v-model="form.serviceEndTime"
+                type="date"
+                placeholder="请选择"
+                class="w-full"
+                value-format="YYYY-MM-DD"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="维保类型" prop="maintainType">
+              <el-select v-model="form.maintainType" placeholder="请选择" class="w-full" filterable>
+                <el-option v-for="dict in maintenance_type" :key="dict.value" :label="dict.label" :value="dict.value" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="服务内容" prop="serviceContent">
+              <el-checkbox-group v-model="form.serviceContent">
+                <el-checkbox v-for="dict in service_content" :key="dict.value" :value="dict.value">{{ dict.label }}</el-checkbox>
+              </el-checkbox-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="维保合同" prop="maintainFile">
+              <el-upload action="#" :auto-upload="false" :file-list="fileList" :on-change="handleFileChange">
+                <el-button type="primary">点击上传</el-button>
+              </el-upload>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="其他服务" prop="otherService">
+              <el-input v-model="form.otherService" type="textarea" :rows="3" placeholder="请输入其他服务" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <el-button type="primary" @click="handleSubmit" :loading="submitLoading">提交</el-button>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts" name="MaintainInfoAdd">
+import { addMaintainInfo, updateMaintainInfo, getMaintainInfo } from '@/api/customer/maintainInfo';
+import { listCustomerInfo, getCustomerInfo } from '@/api/customer/customerFile/customerInfo';
+import { getEnterpriseScale } from '@/api/customer/customerCategory/enterpriseScale';
+import { getIndustryCategory } from '@/api/customer/customerCategory/industryCategory';
+import { CustomerInfoVO } from '@/api/customer/customerFile/customerInfo/types';
+import type { MaintainInfoForm } from '@/api/customer/maintainInfo/types';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { service_content, service_time_type, maintenance_type } = toRefs<any>(
+  proxy?.useDict('service_content', 'service_time_type', 'maintenance_type')
+);
+
+const route = useRoute();
+const router = useRouter();
+
+const formRef = ref<any>(null);
+const maintainFormRef = ref<any>(null);
+const submitLoading = ref(false);
+const isEdit = ref(false);
+const fileList = ref<any[]>([]);
+const customerList = ref<CustomerInfoVO[]>([]);
+
+// 客户信息(选择企业后自动带出)
+const customerInfo = reactive({
+  customerNo: '',
+  enterpriseScale: '',
+  industryCategory: '',
+  cooperationLevel: '',
+  memberLevel: '',
+  phone: '',
+  address: '',
+  provincialCityCounty: '',
+  salesPerson: '',
+  servicePerson: ''
+});
+
+// 表单数据
+const form = reactive<any>({
+  customerId: undefined,
+  applicantName: '',
+  applicantPhone: '',
+  serviceTime: '',
+  monthMainten: undefined,
+  remainingMainten: undefined,
+  maintenLimit: undefined,
+  serviceEngineer: '',
+  engineerPhone: '',
+  serviceStartTime: '',
+  serviceEndTime: '',
+  maintainType: '',
+  serviceContent: [],
+  maintainFile: '',
+  otherService: '',
+  status: '0'
+});
+
+// 表单验证规则
+const rules = {
+  customerId: [{ required: true, message: '请选择企业名称', trigger: 'change' }],
+  applicantName: [{ required: true, message: '请输入申请人名称', trigger: 'blur' }],
+  applicantPhone: [
+    { required: true, message: '请输入申请人手机号', trigger: 'blur' },
+    { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
+  ],
+  serviceEngineer: [{ required: true, message: '请选择服务工程师', trigger: 'change' }]
+};
+
+// 初始化
+onMounted(async () => {
+  // 加载客户列表
+  await loadCustomerList();
+  const _id = route.query.id;
+  if (_id) {
+    isEdit.value = true;
+    await loadMaintainData(_id);
+  }
+});
+
+// 加载客户列表
+const loadCustomerList = async () => {
+  try {
+    const res = await listCustomerInfo();
+    customerList.value = res.rows || [];
+  } catch (error) {
+    console.error('加载客户列表失败:', error);
+    ElMessage.error('加载客户列表失败');
+  }
+};
+
+// 选择企业后加载企业信息
+const handleCustomerChange = async (customerId: string | number) => {
+  if (!customerId) return;
+
+  try {
+    const res = await getCustomerInfo(customerId);
+    const data = res.data;
+
+    // 填充企业基本信息 - 使用API获取真实数据
+    customerInfo.customerNo = data.customerNo;
+    customerInfo.cooperationLevel = getCustomerLevelName(data.customerLevelId);
+    customerInfo.memberLevel = getCustomerLevelName(data.customerLevelId);
+    customerInfo.phone = data.landline || '';
+    customerInfo.address = data.address || '';
+    customerInfo.provincialCityCounty = data.provincialCityCounty || '';
+    customerInfo.industryCategory = data.industryCategory || '-';
+    customerInfo.enterpriseScale = data.enterpriseScale || '-';
+
+    // 填充销售信息
+    if (data.customerSalesInfoVo) {
+      customerInfo.salesPerson = getSalesPersonName(data.customerSalesInfoVo.salesPersonId);
+      customerInfo.servicePerson = getServiceStaffName(data.customerSalesInfoVo.serviceStaffId);
+    }
+  } catch (error) {
+    console.error('加载企业信息失败:', error);
+    ElMessage.error('加载企业信息失败');
+  }
+};
+
+// 格式化方法
+const getCustomerLevelName = (id: string | number | undefined) => {
+  const map: Record<string, string> = { '1': 'A级', '2': 'B级', '3': 'C级', '4': 'D级' };
+  return map[String(id)] || '-';
+};
+
+const getSalesPersonName = (id: string | number | undefined) => {
+  const map: Record<string, string> = { '1': '张三', '2': '李四', '3': '王五', '4': '赵六' };
+  return map[String(id)] || '-';
+};
+
+const getServiceStaffName = (id: string | number | undefined) => {
+  const map: Record<string, string> = { '1': '客服A', '2': '客服B', '3': '客服C', '4': '客服D' };
+  return map[String(id)] || '-';
+};
+
+// 加载维保数据
+const loadMaintainData = async (id: string | number) => {
+  try {
+    const res = await getMaintainInfo(id);
+    const data = res.data;
+    
+    // 将服务内容字符串转换为数组
+    if (data.serviceContent && typeof data.serviceContent === 'string') {
+      data.serviceContent = data.serviceContent.split(',').filter((item: string) => item.trim());
+    }
+    
+    Object.assign(form, data);
+
+    // 如果有客户ID,加载客户信息
+    if (form.customerId) {
+      await handleCustomerChange(form.customerId);
+    }
+  } catch (error) {
+    console.error('加载维保数据失败:', error);
+    ElMessage.error('加载维保数据失败');
+  }
+};
+
+// 文件变化
+const handleFileChange = (file: any, uploadFileList: any[]) => {
+  fileList.value = uploadFileList;
+  console.log('文件变化:', file, uploadFileList);
+};
+
+// 提交表单
+const handleSubmit = async () => {
+  try {
+    await maintainFormRef.value?.validate();
+    submitLoading.value = true;
+
+    // 准备提交数据,将 serviceContent 数组转换为逗号分隔的字符串
+    const submitData = {
+      ...form,
+      serviceContent: Array.isArray(form.serviceContent) ? form.serviceContent.join(',') : form.serviceContent
+    };
+
+    if (isEdit.value) {
+      await updateMaintainInfo(submitData);
+      ElMessage.success('修改成功');
+    } else {
+      await addMaintainInfo(submitData);
+      ElMessage.success('添加成功');
+    }
+    router.back();
+  } catch (error) {
+    console.error('保存失败:', error);
+    ElMessage.error('保存失败,请重试');
+  } finally {
+    submitLoading.value = false;
+  }
+};
+</script>

+ 124 - 0
src/views/customer/maintainInfo/dialog/allotTechnicalAdviser.vue

@@ -0,0 +1,124 @@
+<template>
+  <el-dialog v-model="visible" title="分配技术顾问" width="600px" @close="handleClose">
+    <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
+      <el-form-item label="技术顾问" prop="technicalAdviserId">
+        <el-select v-model="form.technicalAdviserId" placeholder="请选择" clearable filterable class="w-full">
+          <el-option v-for="item in technicalAdviserList" :key="item.value" :label="item.label" :value="item.value" />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item label="联系电话" prop="contactPhone">
+        <el-input v-model="form.contactPhone" placeholder="请输入技术顾问电话" clearable />
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button type="primary" @click="handleConfirm">确认</el-button>
+        <el-button @click="handleClose">取消</el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup lang="ts">
+interface TechnicalAdviserForm {
+  technicalAdviserId?: string | number;
+  technicalAdviser?: string;
+  contactPhone?: string;
+}
+
+interface Props {
+  modelValue: boolean;
+  editData?: TechnicalAdviserForm;
+}
+
+interface Emits {
+  (e: 'update:modelValue', value: boolean): void;
+  (e: 'confirm', data: TechnicalAdviserForm): void;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  modelValue: false,
+  editData: undefined
+});
+
+const emit = defineEmits<Emits>();
+
+const formRef = ref<any>(null);
+
+const visible = computed({
+  get: () => props.modelValue,
+  set: (val) => emit('update:modelValue', val)
+});
+
+const form = reactive<TechnicalAdviserForm>({
+  technicalAdviserId: undefined,
+  technicalAdviser: '',
+  contactPhone: ''
+});
+
+// 技术顾问列表(模拟数据,实际应从接口获取)
+const technicalAdviserList = ref([
+  { label: '技术顾问A', value: '1' },
+  { label: '技术顾问B', value: '2' },
+  { label: '技术顾问C', value: '3' },
+  { label: '技术顾问D', value: '4' }
+]);
+
+const rules = {
+  technicalAdviserId: [{ required: true, message: '请选择技术顾问', trigger: 'change' }],
+  contactPhone: [
+    { required: true, message: '请输入联系电话', trigger: 'blur' },
+    { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
+  ]
+};
+
+// 监听编辑数据
+watch(
+  () => props.editData,
+  (newVal) => {
+    if (newVal) {
+      Object.assign(form, newVal);
+    }
+  },
+  { immediate: true, deep: true }
+);
+
+// 获取技术顾问名称
+const getTechnicalAdviserName = (id: string | number | undefined) => {
+  if (!id) return '';
+  const adviser = technicalAdviserList.value.find((item) => item.value === id);
+  return adviser ? adviser.label : '';
+};
+
+// 确认
+const handleConfirm = async () => {
+  try {
+    await formRef.value?.validate();
+    // 获取技术顾问名称
+    form.technicalAdviser = getTechnicalAdviserName(form.technicalAdviserId);
+    emit('confirm', { ...form });
+    handleClose();
+  } catch (error) {
+    console.error('表单验证失败:', error);
+  }
+};
+
+// 关闭
+const handleClose = () => {
+  formRef.value?.resetFields();
+  Object.assign(form, {
+    technicalAdviserId: undefined,
+    technicalAdviser: '',
+    contactPhone: ''
+  });
+  emit('update:modelValue', false);
+};
+</script>
+
+<style scoped lang="scss">
+.w-full {
+  width: 100%;
+}
+</style>

+ 368 - 0
src/views/customer/maintainInfo/index.vue

@@ -0,0 +1,368 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="客户编号" prop="customerNo">
+              <el-input v-model="queryParams.customerNo" placeholder="请输入客户编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="客户名称" prop="customerNo">
+              <el-input v-model="queryParams.customerNo" placeholder="请输入客户名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="申请状态" prop="serviceTime">
+              <el-select v-model="queryParams.serviceTime" placeholder="请选择服务时长" clearable>
+                <el-option v-for="dict in service_time_type" :key="dict.value" :label="dict.label" :value="dict.value" />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="开始时间" prop="serviceStartTime">
+              <el-date-picker
+                clearable
+                v-model="queryParams.serviceStartTime"
+                type="date"
+                value-format="YYYY-MM-DD"
+                placeholder="请选择服务开始时间"
+              />
+            </el-form-item>
+            <el-form-item label="开始时间" prop="serviceEndTime">
+              <el-date-picker clearable v-model="queryParams.serviceEndTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择服务开始时间" />
+            </el-form-item>
+            <el-form-item label="技术顾问" prop="technicalAdviser">
+              <el-input v-model="queryParams.technicalAdviser" placeholder="请输入技术顾问姓名" clearable @keyup.enter="handleQuery" />
+            </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>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="20"><span>维保客户信息列表</span> </el-col>
+          <el-col :span="1.5">
+            <el-button style="float: right" type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['customer:maintainInfo:add']"
+              >新增维保</el-button
+            >
+          </el-col>
+          <el-col :span="1.5">
+            <el-button
+              style="float: right"
+              type="primary"
+              plain
+              icon="User"
+              @click="handleAllotAdviser()"
+              v-hasPermi="['customer:maintainInfo:allot']"
+              >分配技术顾问</el-button
+            >
+          </el-col>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="maintainInfoList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="企业名称" align="center" prop="customerName" />
+        <el-table-column label="维保类型" align="center" prop="maintainType">
+          <template #default="scope">
+            <dict-tag :options="maintenance_type" :value="scope.row.maintainType" />
+          </template>
+        </el-table-column>
+        <el-table-column label="起始时间" align="center" prop="serviceStartTime" width="180">
+          <template #default="scope">
+            <span>{{ parseTime(scope.row.serviceStartTime, '{y}-{m}-{d}') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="结束时间" align="center" prop="serviceEndTime" width="180">
+          <template #default="scope">
+            <span>{{ parseTime(scope.row.serviceEndTime, '{y}-{m}-{d}') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="维保次数限制" align="center" prop="maintenLimit" />
+        <el-table-column label="维保次数" align="center" prop="maintainCount" />
+        <el-table-column label="主要技术顾问" align="center" prop="technicalAdviser" />
+        <el-table-column label="主要维保项目" align="center" prop="serviceContent">
+          <template #default="scope">
+            <dict-tag :options="service_content" :value="scope.row.serviceContent ? scope.row.serviceContent.split(',') : []" />
+          </template>
+        </el-table-column>
+        <el-table-column label="状态" align="center" prop="status">
+          <template #default="scope">
+            <dict-tag :options="sys_normal_disable" :value="scope.row.status" />
+          </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="User" @click="handleAllotAdviser(scope.row)" v-hasPermi="['customer:maintainInfo:add']"
+              >分配技术顾问</el-button
+            >
+            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['customer:maintainInfo:edit']">编辑</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+
+    <!-- 分配技术顾问对话框 -->
+    <allot-technical-adviser-dialog v-model="allotDialogVisible" :edit-data="currentAdviserData" @confirm="handleAllotConfirm" />
+  </div>
+</template>
+
+<script setup name="MaintainInfo" lang="ts">
+import {
+  listMaintainInfo,
+  getMaintainInfo,
+  delMaintainInfo,
+  addMaintainInfo,
+  updateMaintainInfo,
+  allotTechnicalAdviser
+} from '@/api/customer/maintainInfo';
+import { MaintainInfoVO, MaintainInfoQuery, MaintainInfoForm, AllotTechnicalAdviserForm } from '@/api/customer/maintainInfo/types';
+import AllotTechnicalAdviserDialog from './dialog/allotTechnicalAdviser.vue';
+const router = useRouter();
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { service_content, service_time_type, maintenance_type, sys_normal_disable } = toRefs<any>(
+  proxy?.useDict('service_content', 'service_time_type', 'maintenance_type', 'sys_normal_disable')
+);
+
+const maintainInfoList = ref<MaintainInfoVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const maintainInfoFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+// 分配技术顾问对话框
+const allotDialogVisible = ref(false);
+const currentAdviserData = ref<any>(null);
+const currentMaintainId = ref<string | number>();
+
+const initFormData: MaintainInfoForm = {
+  id: undefined,
+  customerId: undefined,
+  maintainNo: undefined,
+  customerNo: undefined,
+  applicantName: undefined,
+  applicantPhone: undefined,
+  serviceTime: undefined,
+  monthMainten: undefined,
+  remainingMainten: undefined,
+  maintenLimit: undefined,
+  serviceContent: [],
+  otherService: undefined,
+  serviceStartTime: undefined,
+  serviceEndTime: undefined,
+  maintainStatus: undefined,
+  serviceEngineerId: undefined,
+  serviceEngineer: undefined,
+  engineerPhone: undefined,
+  technicalAdviserId: undefined,
+  technicalAdviser: undefined,
+  technicalAdviserPhone: undefined,
+  maintainFile: undefined,
+  maintainType: undefined,
+  status: undefined,
+  remark: undefined
+};
+const data = reactive<PageData<MaintainInfoForm, MaintainInfoQuery>>({
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    customerId: undefined,
+    maintainNo: undefined,
+    customerNo: undefined,
+    applicantName: undefined,
+    applicantPhone: undefined,
+    serviceTime: undefined,
+    monthMainten: undefined,
+    remainingMainten: undefined,
+    maintenLimit: undefined,
+    serviceContent: undefined,
+    otherService: undefined,
+    serviceStartTime: undefined,
+    serviceEndTime: undefined,
+    maintainStatus: undefined,
+    serviceEngineerId: undefined,
+    serviceEngineer: undefined,
+    engineerPhone: undefined,
+    technicalAdviserId: undefined,
+    technicalAdviser: undefined,
+    technicalAdviserPhone: undefined,
+    maintainFile: undefined,
+    maintainType: undefined,
+    status: undefined,
+    platformCode: undefined,
+    params: {}
+  },
+  rules: {}
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询维保记录列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listMaintainInfo(queryParams.value);
+  maintainInfoList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData };
+  maintainInfoFormRef.value?.resetFields();
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+};
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: MaintainInfoVO[]) => {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  router.push({
+    path: '/customer/increment-add'
+  });
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: MaintainInfoVO) => {
+  const _id = row?.id || ids.value[0];
+  router.push({
+    path: '/customer/increment-add',
+    query: { id: _id, status: 'edit' }
+  });
+};
+
+/** 提交按钮 */
+const submitForm = () => {
+  maintainInfoFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      form.value.serviceContent = form.value.serviceContent.join(',');
+      if (form.value.id) {
+        await updateMaintainInfo(form.value).finally(() => (buttonLoading.value = false));
+      } else {
+        await addMaintainInfo(form.value).finally(() => (buttonLoading.value = false));
+      }
+      proxy?.$modal.msgSuccess('操作成功');
+      dialog.visible = false;
+      await getList();
+    }
+  });
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: MaintainInfoVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除维保记录编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delMaintainInfo(_ids);
+  proxy?.$modal.msgSuccess('删除成功');
+  await getList();
+};
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download(
+    'customer/maintainInfo/export',
+    {
+      ...queryParams.value
+    },
+    `maintainInfo_${new Date().getTime()}.xlsx`
+  );
+};
+
+/** 打开分配技术顾问对话框 */
+const handleAllotAdviser = (row?: MaintainInfoVO) => {
+  if (row) {
+    // 单行操作
+    currentMaintainId.value = row.id;
+    currentAdviserData.value = {
+      technicalAdviserId: row.technicalAdviserId,
+      contactPhone: row.technicalAdviserPhone
+    };
+  } else {
+    // 批量操作
+    if (ids.value.length === 0) {
+      proxy?.$modal.msgWarning('请选择要分配技术顾问的维保记录');
+      return;
+    }
+    currentMaintainId.value = undefined;
+    currentAdviserData.value = null;
+  }
+  allotDialogVisible.value = true;
+};
+
+/** 确认分配技术顾问 */
+const handleAllotConfirm = async (data: any) => {
+  try {
+    // 单行操作
+    if (currentMaintainId.value) {
+      const params: AllotTechnicalAdviserForm = {
+        id: currentMaintainId.value,
+        technicalAdviserId: data.technicalAdviserId,
+        technicalAdviser: data.technicalAdviser,
+        technicalAdviserPhone: data.contactPhone
+      };
+      await allotTechnicalAdviser(params);
+      proxy?.$modal.msgSuccess('分配技术顾问成功');
+    } else {
+      // 批量操作
+      const promises = ids.value.map((id) => {
+        const params: AllotTechnicalAdviserForm = {
+          id: id,
+          technicalAdviserId: data.technicalAdviserId,
+          technicalAdviser: data.technicalAdviser,
+          technicalAdviserPhone: data.contactPhone
+        };
+        return allotTechnicalAdviser(params);
+      });
+      await Promise.all(promises);
+      proxy?.$modal.msgSuccess('批量分配技术顾问成功');
+    }
+    await getList();
+  } catch (error) {
+    console.error('分配技术顾问失败:', error);
+    proxy?.$modal.msgError('分配技术顾问失败');
+  }
+};
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 4 - 4
src/views/login.vue

@@ -5,12 +5,12 @@
         <h3 class="title">{{ title }}</h3>
         <lang-select />
       </div>
-      <el-form-item v-if="tenantEnabled" prop="tenantId">
+      <!-- <el-form-item v-if="tenantEnabled" prop="tenantId">
         <el-select v-model="loginForm.tenantId" filterable :placeholder="proxy.$t('login.selectPlaceholder')" style="width: 100%">
           <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"></el-option>
           <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
         </el-select>
-      </el-form-item>
+      </el-form-item> -->
       <el-form-item prop="username">
         <el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" :placeholder="proxy.$t('login.username')">
           <template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
@@ -96,8 +96,8 @@ const { t } = useI18n();
 
 const loginForm = ref<LoginData>({
   tenantId: '000000',
-  username: 'admin',
-  password: 'admin123',
+  username: 'marketadmin',
+  password: '123456',
   rememberMe: false,
   code: '',
   uuid: ''