林小张 2 mesiacov pred
rodič
commit
c26a69eabb
31 zmenil súbory, kde vykonal 2989 pridanie a 725 odobranie
  1. 11 0
      src/api/pc/enterprise/address.ts
  2. 146 0
      src/api/pc/enterprise/index.ts
  3. 12 0
      src/api/pc/enterprise/invoice.ts
  4. 79 0
      src/api/pc/enterprise/order.ts
  5. 60 0
      src/api/pc/enterprise/orderReturn.ts
  6. 70 0
      src/api/pc/enterprise/orderReturnTypes.ts
  7. 69 0
      src/api/pc/enterprise/orderTypes.ts
  8. 23 0
      src/api/pc/enterprise/servicePerson.ts
  9. 88 0
      src/api/pc/enterprise/statement.ts
  10. 76 0
      src/api/pc/enterprise/statementTypes.ts
  11. 44 0
      src/api/pc/enterprise/types.ts
  12. 13 0
      src/api/pc/index.ts
  13. 186 0
      src/api/pc/organization/index.ts
  14. 67 0
      src/api/pc/organization/types.ts
  15. 47 0
      src/api/pc/system/announcement.ts
  16. 30 0
      src/api/pc/system/dict.ts
  17. 4 1
      src/utils/auth.ts
  18. 158 23
      src/views/enterprise/addressManage/index.vue
  19. 43 5
      src/views/enterprise/companyInfo/edit.vue
  20. 77 19
      src/views/enterprise/companyInfo/index.vue
  21. 62 15
      src/views/enterprise/invoiceManage/index.vue
  22. 97 49
      src/views/organization/deptManage/index.vue
  23. 109 13
      src/views/organization/personalInfo/index.vue
  24. 142 152
      src/views/organization/roleManage/index.vue
  25. 167 55
      src/views/reconciliation/billManage/index.vue
  26. 167 300
      src/views/reconciliation/invoiceManage/index.vue
  27. 71 10
      src/views/trade/afterSale/index.vue
  28. 176 56
      src/views/trade/orderAudit/index.vue
  29. 101 8
      src/views/trade/orderManage/detail.vue
  30. 269 19
      src/views/trade/orderManage/index.vue
  31. 325 0
      yoe-shop-web接口文档.md

+ 11 - 0
src/api/pc/enterprise/address.ts

@@ -0,0 +1,11 @@
+import request from '@/utils/request';
+
+/**
+ * 查询收货地址详情
+ */
+export function getAddressInfo(id: number | string) {
+  return request({
+    url: `/pc/enterprise/address/${id}`,
+    method: 'get'
+  });
+}

+ 146 - 0
src/api/pc/enterprise/index.ts

@@ -0,0 +1,146 @@
+import request from '@/utils/request';
+import { EnterpriseInfo, ShippingAddress, InvoiceInfo } from './types';
+
+// ==================== 企业信息管理 ====================
+
+/**
+ * 查询当前企业信息
+ */
+export function getEnterpriseInfo() {
+  return request({
+    url: '/pc/enterprise/info',
+    method: 'get'
+  });
+}
+
+/**
+ * 修改当前企业信息
+ */
+export function updateEnterpriseInfo(data: EnterpriseInfo) {
+  return request({
+    url: '/pc/enterprise/info',
+    method: 'put',
+    data: data
+  });
+}
+
+// ==================== 收货地址管理 ====================
+
+/**
+ * 查询收货地址列表
+ */
+export function getAddressList(params?: any) {
+  return request({
+    url: '/pc/enterprise/address/list',
+    method: 'get',
+    params: params
+  });
+}
+
+/**
+ * 查询收货地址详情
+ */
+export function getAddressInfo(id: number) {
+  return request({
+    url: `/pc/enterprise/address/${id}`,
+    method: 'get'
+  });
+}
+
+/**
+ * 新增收货地址
+ */
+export function addAddress(data: ShippingAddress) {
+  return request({
+    url: '/pc/enterprise/address',
+    method: 'post',
+    data: data
+  });
+}
+
+/**
+ * 修改收货地址
+ */
+export function updateAddress(data: ShippingAddress) {
+  return request({
+    url: '/pc/enterprise/address',
+    method: 'put',
+    data: data
+  });
+}
+
+/**
+ * 删除收货地址
+ */
+export function deleteAddress(ids: number[]) {
+  return request({
+    url: `/pc/enterprise/address/${ids.join(',')}`,
+    method: 'delete'
+  });
+}
+
+/**
+ * 设置默认地址
+ */
+export function setDefaultAddress(data: { id: number }) {
+  return request({
+    url: '/pc/enterprise/address/default',
+    method: 'put',
+    data: data
+  });
+}
+
+// ==================== 发票信息管理 ====================
+
+/**
+ * 查询发票信息列表
+ */
+export function getInvoiceList(params?: any) {
+  return request({
+    url: '/pc/enterprise/invoice/list',
+    method: 'get',
+    params: params
+  });
+}
+
+/**
+ * 查询发票信息详情
+ */
+export function getInvoiceInfo(id: number) {
+  return request({
+    url: `/pc/enterprise/invoice/${id}`,
+    method: 'get'
+  });
+}
+
+/**
+ * 新增发票信息
+ */
+export function addInvoice(data: InvoiceInfo) {
+  return request({
+    url: '/pc/enterprise/invoice',
+    method: 'post',
+    data: data
+  });
+}
+
+/**
+ * 修改发票信息
+ */
+export function updateInvoice(data: InvoiceInfo) {
+  return request({
+    url: '/pc/enterprise/invoice',
+    method: 'put',
+    data: data
+  });
+}
+
+/**
+ * 删除发票信息
+ */
+export function deleteInvoice(ids: number[]) {
+  return request({
+    url: `/pc/enterprise/invoice/${ids.join(',')}`,
+    method: 'delete'
+  });
+}

+ 12 - 0
src/api/pc/enterprise/invoice.ts

@@ -0,0 +1,12 @@
+import request from '@/utils/request';
+
+/**
+ * 查询当前企业的发票信息列表
+ */
+export function getInvoiceList(params?: any) {
+  return request({
+    url: '/pc/enterprise/invoice/list',
+    method: 'get',
+    params: params
+  });
+}

+ 79 - 0
src/api/pc/enterprise/order.ts

@@ -0,0 +1,79 @@
+import request from '@/utils/request';
+import { OrderMain, OrderProduct, OrderStatusStats } from './orderTypes';
+
+// ==================== 订单管理 ====================
+
+/**
+ * 查询当前企业的订单列表
+ */
+export function getOrderList(params?: any) {
+  return request({
+    url: '/pc/enterprise/order/list',
+    method: 'get',
+    params: params
+  });
+}
+
+/**
+ * 查询订单状态统计
+ */
+export function getOrderStatusStats() {
+  return request({
+    url: '/pc/enterprise/order/statusStats',
+    method: 'get'
+  });
+}
+
+/**
+ * 查询订单详情
+ */
+export function getOrderInfo(id: number) {
+  return request({
+    url: `/pc/enterprise/order/${id}`,
+    method: 'get'
+  });
+}
+
+/**
+ * 根据订单ID查询订单商品明细
+ */
+export function getOrderProducts(orderIds: number[]) {
+  return request({
+    url: '/pc/enterprise/order/products',
+    method: 'get',
+    params: { orderIds: orderIds.join(',') }
+  });
+}
+
+/**
+ * 取消订单
+ */
+export function cancelOrder(data: { id: number; orderStatus?: string }) {
+  return request({
+    url: '/pc/enterprise/order/cancel',
+    method: 'put',
+    data: data
+  });
+}
+
+/**
+ * 审核订单
+ * 企业客户审核自己企业的订单
+ */
+export function checkOrderStatus(data: { id: number; checkStatus: string }) {
+  return request({
+    url: '/pc/enterprise/order/checkStatus',
+    method: 'put',
+    data: data
+  });
+}
+
+/**
+ * 删除订单
+ */
+export function deleteOrder(ids: number[]) {
+  return request({
+    url: `/pc/enterprise/order/${ids.join(',')}`,
+    method: 'delete'
+  });
+}

+ 60 - 0
src/api/pc/enterprise/orderReturn.ts

@@ -0,0 +1,60 @@
+import request from '@/utils/request';
+import { OrderReturn } from './orderReturnTypes';
+
+// ==================== 售后服务管理 ====================
+
+/**
+ * 查询当前企业的售后申请列表
+ */
+export function getOrderReturnList(params?: any) {
+  return request({
+    url: '/pc/enterprise/orderReturn/list',
+    method: 'get',
+    params: params
+  });
+}
+
+/**
+ * 查询售后申请详情
+ */
+export function getOrderReturnInfo(id: number) {
+  return request({
+    url: `/pc/enterprise/orderReturn/${id}`,
+    method: 'get'
+  });
+}
+
+/**
+ * 新增售后申请
+ * 企业客户申请退货/售后服务
+ */
+export function addOrderReturn(data: OrderReturn) {
+  return request({
+    url: '/pc/enterprise/orderReturn',
+    method: 'post',
+    data: data
+  });
+}
+
+/**
+ * 修改售后申请
+ * 企业客户修改自己的售后申请(仅限未审核状态)
+ */
+export function updateOrderReturn(data: OrderReturn) {
+  return request({
+    url: '/pc/enterprise/orderReturn',
+    method: 'put',
+    data: data
+  });
+}
+
+/**
+ * 删除售后申请
+ * 企业客户删除自己的售后申请(仅限未审核状态)
+ */
+export function deleteOrderReturn(ids: number[]) {
+  return request({
+    url: `/pc/enterprise/orderReturn/${ids.join(',')}`,
+    method: 'delete'
+  });
+}

+ 70 - 0
src/api/pc/enterprise/orderReturnTypes.ts

@@ -0,0 +1,70 @@
+/**
+ * 售后服务相关类型定义
+ * 字段严格以后端返回的OrderReturnVo为准
+ */
+
+/**
+ * 退货/售后申请主信息
+ * 对应后端: OrderReturnVo
+ */
+export interface OrderReturn {
+  id?: number;
+  orderId?: number;
+  orderNo?: string;
+  serviceType?: string;
+  returnTime?: string;
+  returnNo?: string;
+  customerId?: number;
+  customerNo?: string;
+  customerName?: string;
+  afterSaleAmount?: number;
+  returnStatus?: string;
+  returnProductNum?: number;
+  processingTime?: string;
+  returnReasonId?: number;
+  returnReason?: string;
+  problemDescription?: string;
+  voucherPhoto?: string;
+  shippingFee?: number;
+  isShippingFee?: string;
+  orderAmount?: number;
+  returnAmount?: number;
+  afterSalesRemarks?: string;
+  returnMethod?: string;
+  chargebackName?: string;
+  chargebackPhone?: string;
+  chargebackPickupTime?: string;
+  chargebackProvincial?: string;
+  chargebackCity?: string;
+  chargebackCounty?: string;
+  provincialCityCounty?: string;
+  chargebackAddress?: string;
+  pushStatus?: string;
+  logisticsId?: number;
+  logisticsName?: string;
+  logisticsNo?: string;
+  status?: string;
+  remark?: string;
+  createTime?: string;
+  orderReturnItemList?: OrderReturnItem[];
+  [key: string]: any;
+}
+
+/**
+ * 退货商品明细
+ * 对应后端: OrderReturnItemVo
+ */
+export interface OrderReturnItem {
+  id?: number;
+  returnId?: number;
+  orderProductId?: number;
+  productId?: number;
+  productNo?: string;
+  productName?: string;
+  productSpec?: string;
+  returnQuantity?: number;
+  unitPrice?: number;
+  returnAmount?: number;
+  remark?: string;
+  [key: string]: any;
+}

+ 69 - 0
src/api/pc/enterprise/orderTypes.ts

@@ -0,0 +1,69 @@
+/**
+ * 订单主信息
+ * 字段以后端返回的数据结构为准
+ */
+export interface OrderMain {
+  id?: number;
+  parentOrderId?: number;
+  orderNo?: string;
+  shipmentNo?: string;
+  subOrderNo?: string;
+  companyId?: number;
+  customerId?: number;
+  customerCode?: string;
+  userId?: number;
+  shippingAddressId?: number;
+  purchaseReason?: string;
+  invoiceType?: string;
+  payType?: string;
+  warehouseId?: number;
+  orderStatus?: string;
+  checkStatus?: string;
+  payStatus?: string;
+  deliveryStatus?: string;
+  totalAmount?: number;
+  discountAmount?: number;
+  actualAmount?: number;
+  freight?: number;
+  remark?: string;
+  createTime?: string;
+  updateTime?: string;
+  [key: string]: any;
+}
+
+/**
+ * 订单商品明细
+ * 字段以后端返回的数据结构为准
+ */
+export interface OrderProduct {
+  id?: number;
+  orderId?: number;
+  orderNo?: string;
+  shipmentNo?: string;
+  productId?: number;
+  productNo?: string;
+  productName?: string;
+  productSpec?: string;
+  productBrand?: string;
+  productUnit?: string;
+  quantity?: number;
+  unitPrice?: number;
+  totalPrice?: number;
+  discountAmount?: number;
+  actualPrice?: number;
+  remark?: string;
+  [key: string]: any;
+}
+
+/**
+ * 订单状态统计
+ * 字段以后端返回的数据结构为准
+ */
+export interface OrderStatusStats {
+  pendingPaymentCount?: number;
+  pendingShipmentCount?: number;
+  shippedCount?: number;
+  completedCount?: number;
+  closedCount?: number;
+  totalCount?: number;
+}

+ 23 - 0
src/api/pc/enterprise/servicePerson.ts

@@ -0,0 +1,23 @@
+import request from '@/utils/request';
+
+/**
+ * 服务人员视图对象
+ */
+export interface ServicePersonVO {
+  name: string;
+  type: string;
+  department: string;
+  phone: string;
+  avatar: string;
+}
+
+/**
+ * 查询当前企业的专属服务人员
+ * PC端接口
+ */
+export function getServicePersons() {
+  return request({
+    url: '/pc/enterprise/servicePerson/list',
+    method: 'get'
+  });
+}

+ 88 - 0
src/api/pc/enterprise/statement.ts

@@ -0,0 +1,88 @@
+import request from '@/utils/request';
+
+/**
+ * 查询对账单列表
+ */
+export function getStatementList(params?: any) {
+  return request({
+    url: '/pc/enterprise/statement/list',
+    method: 'get',
+    params: params
+  });
+}
+
+/**
+ * 查询对账单详情
+ */
+export function getStatementInfo(id: number | string) {
+  return request({
+    url: `/pc/enterprise/statement/${id}`,
+    method: 'get'
+  });
+}
+
+/**
+ * 查询对账单明细列表
+ */
+export function getStatementDetails(params?: any) {
+  return request({
+    url: '/pc/enterprise/statement/details',
+    method: 'get',
+    params: params
+  });
+}
+
+/**
+ * 确认对账单
+ */
+export function confirmStatement(data: { id: number; remark?: string }) {
+  return request({
+    url: '/pc/enterprise/statement/confirm',
+    method: 'put',
+    data: data
+  });
+}
+
+/**
+ * 驳回对账单
+ */
+export function rejectStatement(data: { id: number; rejectRemark?: string }) {
+  return request({
+    url: '/pc/enterprise/statement/reject',
+    method: 'put',
+    data: data
+  });
+}
+
+/**
+ * 查询对账单明细列表
+ */
+export function getStatementDetailList(params?: any) {
+  return request({
+    url: '/pc/enterprise/statementDetail/list',
+    method: 'get',
+    params: params
+  });
+}
+
+/**
+ * 查询对账单商品列表
+ */
+export function getStatementProductList(params?: any) {
+  return request({
+    url: '/pc/enterprise/statementProduct/list',
+    method: 'get',
+    params: params
+  });
+}
+
+/**
+ * 查询对账单发票列表
+ */
+export function getStatementInvoiceList(params?: any) {
+  return request({
+    url: '/pc/enterprise/statementInvoice/list',
+    method: 'get',
+    params: params
+  });
+}

+ 76 - 0
src/api/pc/enterprise/statementTypes.ts

@@ -0,0 +1,76 @@
+/**
+ * 对账单主表
+ */
+export interface StatementOrder {
+  id: number;
+  statementOrderNo: string; // 对账单编号
+  customerId: number; // 客户ID
+  customerNo: string; // 客户编号
+  customerName: string; // 客户名称
+  amount: number; // 对账总金额
+  statementSelfId: number; // 对账人ID
+  statementSelf: string; // 对账人姓名
+  statementSelfPhone: string; // 对账人电话
+  statementStatus: string; // 对账状态(0-待确认, 1-待对账, 2-已对账, 3-驳回, 4-作废)
+  isPaymentStatus: string; // 是否已付款
+  isInvoiceStatus: string; // 是否已开票
+  statementDate: string; // 对账日期
+  annexAddress: string; // 附件存储路径
+  rejectRemark: string; // 驳回原因
+  remark: string; // 备注
+  detailList?: StatementDetail[]; // 对账明细列表
+  productList?: StatementProduct[]; // 商品清单列表
+}
+
+/**
+ * 对账单明细
+ */
+export interface StatementDetail {
+  id: number;
+  statementOrderId: number; // 对账单ID
+  statementOrderNo: string; // 对账单编号
+  type: string; // 明细类型
+  orderId: number; // 订单ID
+  orderNo: string; // 订单编号
+  amount: number; // 明细金额
+  orderTime: string; // 订单时间
+  signingDate: string; // 签收日期
+  userId: number; // 操作用户ID
+  userName: string; // 操作用户
+  userDeptId: number; // 用户部门ID
+  userDept: string; // 用户所属部门
+  remark: string; // 备注
+}
+
+/**
+ * 对账单商品
+ */
+export interface StatementProduct {
+  id: number;
+  statementOrderId: number; // 对账单ID
+  orderId: number; // 订单ID
+  productId: number; // 商品ID
+  productName: string; // 商品名称
+  productNo: string; // 商品编号
+  productUnit: string; // 商品单位
+  orderPrice: number; // 订单价格
+  orderQuantity: number; // 订单数量
+  amount: number; // 金额
+  remark: string; // 备注
+}
+
+/**
+ * 对账单发票
+ */
+export interface StatementInvoice {
+  id: number;
+  statementInvoiceNo: string; // 发票编号
+  customerId: number; // 客户ID
+  customerNo: string; // 客户编号
+  customerName: string; // 客户名称
+  invoiceAmount: number; // 发票金额
+  invoiceStatus: string; // 发票状态
+  invoiceTime: string; // 开票时间
+  rejectRemark: string; // 驳回备注
+  remark: string; // 备注
+}

+ 44 - 0
src/api/pc/enterprise/types.ts

@@ -0,0 +1,44 @@
+/**
+ * 企业信息
+ */
+export interface EnterpriseInfo {
+  id?: number;
+  enterpriseName?: string;
+  creditCode?: string;
+  legalPerson?: string;
+  contactPhone?: string;
+  address?: string;
+  [key: string]: any;
+}
+
+/**
+ * 收货地址
+ */
+export interface ShippingAddress {
+  id?: number;
+  customerId?: number;
+  consignee?: string;
+  phone?: string;
+  province?: string;
+  city?: string;
+  district?: string;
+  detailAddress?: string;
+  isDefault?: number;
+  [key: string]: any;
+}
+
+/**
+ * 发票信息
+ */
+export interface InvoiceInfo {
+  id?: number;
+  customerId?: number;
+  invoiceType?: string;
+  invoiceTitle?: string;
+  taxNumber?: string;
+  bankName?: string;
+  bankAccount?: string;
+  companyAddress?: string;
+  companyPhone?: string;
+  [key: string]: any;
+}

+ 13 - 0
src/api/pc/index.ts

@@ -0,0 +1,13 @@
+/**
+ * PC端API统一导出
+ */
+
+// 系统模块
+export * from './system/dict';
+export * from './system/announcement';
+
+// 企业账户模块
+export * from './enterprise';
+
+// 组织管理模块
+export * from './organization';

+ 186 - 0
src/api/pc/organization/index.ts

@@ -0,0 +1,186 @@
+import request from '@/utils/request';
+
+// ==================== 部门管理 ====================
+
+/**
+ * 查询部门树
+ */
+export function getDeptTree() {
+  return request({
+    url: '/pc/organization/dept/tree',
+    method: 'get'
+  });
+}
+
+/**
+ * 查询部门列表
+ */
+export function getDeptList(params?: any) {
+  return request({
+    url: '/pc/organization/dept/list',
+    method: 'get',
+    params: params
+  });
+}
+
+/**
+ * 查询部门详情
+ */
+export function getDeptInfo(id: number) {
+  return request({
+    url: `/pc/organization/dept/${id}`,
+    method: 'get'
+  });
+}
+
+/**
+ * 新增部门
+ */
+export function addDept(data: any) {
+  return request({
+    url: '/pc/organization/dept',
+    method: 'post',
+    data: data
+  });
+}
+
+/**
+ * 修改部门
+ */
+export function updateDept(data: any) {
+  return request({
+    url: '/pc/organization/dept',
+    method: 'put',
+    data: data
+  });
+}
+
+/**
+ * 删除部门
+ */
+export function deleteDept(ids: number[]) {
+  return request({
+    url: `/pc/organization/dept/${ids.join(',')}`,
+    method: 'delete'
+  });
+}
+
+// ==================== 人员管理 ====================
+
+/**
+ * 获取当前登录用户的个人信息
+ */
+export function getCurrentUserInfo() {
+  return request({
+    url: '/pc/organization/contact/current',
+    method: 'get'
+  });
+}
+
+/**
+ * 查询联系人列表
+ */
+export function getContactList(params?: any) {
+  return request({
+    url: '/pc/organization/contact/list',
+    method: 'get',
+    params: params
+  });
+}
+
+/**
+ * 查询联系人详情
+ */
+export function getContactInfo(id: number) {
+  return request({
+    url: `/pc/organization/contact/${id}`,
+    method: 'get'
+  });
+}
+
+/**
+ * 新增联系人
+ */
+export function addContact(data: any) {
+  return request({
+    url: '/pc/organization/contact',
+    method: 'post',
+    data: data
+  });
+}
+
+/**
+ * 修改联系人
+ */
+export function updateContact(data: any) {
+  return request({
+    url: '/pc/organization/contact',
+    method: 'put',
+    data: data
+  });
+}
+
+/**
+ * 删除联系人
+ */
+export function deleteContact(ids: number[]) {
+  return request({
+    url: `/pc/organization/contact/${ids.join(',')}`,
+    method: 'delete'
+  });
+}
+
+// ==================== 角色管理 ====================
+
+/**
+ * 查询角色列表
+ */
+export function getRoleList(params?: any) {
+  return request({
+    url: '/pc/organization/role/list',
+    method: 'get',
+    params: params
+  });
+}
+
+/**
+ * 查询角色详情
+ */
+export function getRoleInfo(id: number) {
+  return request({
+    url: `/pc/organization/role/${id}`,
+    method: 'get'
+  });
+}
+
+/**
+ * 新增角色
+ */
+export function addRole(data: any) {
+  return request({
+    url: '/pc/organization/role',
+    method: 'post',
+    data: data
+  });
+}
+
+/**
+ * 修改角色
+ */
+export function updateRole(data: any) {
+  return request({
+    url: '/pc/organization/role',
+    method: 'put',
+    data: data
+  });
+}
+
+/**
+ * 删除角色
+ */
+export function deleteRole(ids: number[]) {
+  return request({
+    url: `/pc/organization/role/${ids.join(',')}`,
+    method: 'delete'
+  });
+}

+ 67 - 0
src/api/pc/organization/types.ts

@@ -0,0 +1,67 @@
+// 部门信息
+export interface DeptInfo {
+  deptId: number;           // 部门ID
+  deptNo?: string;          // 部门编号
+  deptName: string;         // 部门名称
+  parentId?: number;        // 父部门ID
+  ancestors?: string;       // 祖级列表
+  customerId: number;       // 客户ID
+  yearlyBudget?: number;    // 年度预算
+  usedBudget?: number;      // 已使用预算
+  monthLimit?: number;      // 月度限额
+  monthUsedBudget?: number; // 月度已用预算
+  bindStatus?: string;      // 绑定状态
+  bindAddress?: string;     // 绑定地址
+  deptManage?: string;      // 部门负责人
+  isLimit?: string;         // 是否限制预算
+  selectYear?: string;      // 所选年份
+  expenseType?: string;     // 费用类型
+  residueYearlyBudget?: number; // 年度剩余预算
+  recharge?: number;        // 充值金额
+  status?: string;          // 状态
+  remark?: string;          // 备注
+  createTime?: string;      // 创建时间
+}
+
+// 部门树节点
+export interface DeptTreeNode {
+  deptId: number;
+  deptName: string;
+  parentId?: number;
+  children?: DeptTreeNode[];
+}
+
+// 联系人信息
+export interface ContactInfo {
+  id: number;               // 联系人ID
+  customerId: number;       // 客户ID
+  contactName: string;      // 联系人姓名
+  customLoginName?: string; // 自定义登录名
+  phone: string;            // 手机号码
+  officePhone?: string;     // 办公电话
+  officePhoneTwo?: string;  // 办公电话2
+  gender?: string;          // 性别
+  roleId?: number;          // 角色ID
+  deptId?: number;          // 部门ID
+  email?: string;           // 邮箱
+  birthday?: string;        // 生日
+  isPrimary?: string;       // 是否主联系人
+  addressDetail?: string;   // 详细地址
+  addressProvince?: string; // 所在省编码
+  addressCity?: string;     // 所在市编码
+  addressCounty?: string;   // 所在区县编码
+  provincialCityCounty?: string; // 省市区
+  status?: string;          // 状态
+  remark?: string;          // 备注
+}
+
+// 角色信息
+export interface RoleInfo {
+  roleId: number;           // 角色ID
+  roleName: string;         // 角色名称
+  roleKey?: string;         // 角色权限字符
+  roleSort?: number;        // 排序
+  dataScope?: string;       // 数据范围
+  status?: string;          // 状态
+  remark?: string;          // 备注
+}

+ 47 - 0
src/api/pc/system/announcement.ts

@@ -0,0 +1,47 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+
+/**
+ * 平台公告查询对象
+ */
+export interface AnnouncementQuery {
+  pageNum?: number;
+  pageSize?: number;
+  title?: string;
+  status?: string;
+}
+
+/**
+ * 平台公告视图对象
+ */
+export interface AnnouncementVO {
+  id: number;
+  title: string;
+  content: string;
+  status: string;
+  createTime: string;
+  updateTime?: string;
+}
+
+/**
+ * 查询平台公告列表
+ * PC端接口
+ */
+export function getAnnouncementList(query?: AnnouncementQuery): AxiosPromise<AnnouncementVO[]> {
+  return request({
+    url: '/pc/announcement/list',
+    method: 'get',
+    params: query
+  });
+}
+
+/**
+ * 查询平台公告详情
+ * PC端接口
+ */
+export function getAnnouncementInfo(id: number | string): AxiosPromise<AnnouncementVO> {
+  return request({
+    url: `/pc/announcement/${id}`,
+    method: 'get'
+  });
+}

+ 30 - 0
src/api/pc/system/dict.ts

@@ -0,0 +1,30 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+
+/**
+ * 字典数据视图对象
+ */
+export interface DictDataVO {
+  dictCode?: number;
+  dictSort?: number;
+  dictLabel: string;
+  dictValue: string;
+  dictType: string;
+  cssClass?: string;
+  listClass?: string;
+  isDefault?: string;
+  status?: string;
+  createTime?: string;
+  remark?: string;
+}
+
+/**
+ * 根据字典类型查询字典数据信息
+ * PC端接口
+ */
+export function getDictByType(dictType: string): AxiosPromise<DictDataVO[]> {
+  return request({
+    url: '/pc/dict/type/' + dictType,
+    method: 'get'
+  });
+}

+ 4 - 1
src/utils/auth.ts

@@ -2,7 +2,10 @@ const TokenKey = 'Admin-Token';
 
 const tokenStorage = useStorage<null | string>(TokenKey, null);
 
-export const getToken = () => tokenStorage.value;
+// TODO: 临时测试用的固定token,正式环境需要删除
+const TEST_TOKEN = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiJzeXNfdXNlcjoyMDE1NjA0NzkwMzAxNzA0MTk0Iiwicm5TdHIiOiI4MGpNM1B4cUJtbTRqdWg0MHZFeFI4elp5TjVCQzltYiIsImNsaWVudGlkIjoiZTVjZDdlNDg5MWJmOTVkMWQxOTIwNmNlMjRhN2IzMmUiLCJ0ZW5hbnRJZCI6IjAwMDAwMCIsInVzZXJJZCI6MjAxNTYwNDc5MDMwMTcwNDE5NCwidXNlck5hbWUiOiJjc3VzZXIifQ.6f7V67ZUfMplyC9Am2mOAD8LeY9eBhS44oVUe-gkOPc';
+
+export const getToken = () => tokenStorage.value || TEST_TOKEN;
 
 export const setToken = (access_token: string) => (tokenStorage.value = access_token);
 

+ 158 - 23
src/views/enterprise/addressManage/index.vue

@@ -12,16 +12,16 @@
       <div v-for="(item, index) in addressList" :key="index" class="address-item">
         <div class="address-info">
           <div class="address-name">
-            <span>{{ item.name }}</span>
-            <el-tag v-if="item.isDefault" type="danger" size="small">默认地址</el-tag>
+            <span>{{ item.consignee }}</span>
+            <el-tag v-if="item.defaultAddress === '1'" type="danger" size="small">默认地址</el-tag>
           </div>
-          <div class="address-detail">{{ item.province }} {{ item.city }} {{ item.district }}{{ item.address }}</div>
+          <div class="address-detail">{{ item.provincialCityCountry }} {{ item.address }}</div>
           <div class="address-phone">{{ item.phone }}</div>
         </div>
         <div class="address-actions">
           <el-button type="primary" link @click="handleEdit(item)">编辑</el-button>
           <el-button type="danger" link @click="handleDelete(item)">删除</el-button>
-          <el-button v-if="!item.isDefault" type="danger" link @click="handleSetDefault(item)">设为默认</el-button>
+          <el-button v-if="item.defaultAddress !== '1'" type="danger" link @click="handleSetDefault(item)">设为默认</el-button>
         </div>
       </div>
       <el-empty v-if="addressList.length === 0" description="暂无收货地址" />
@@ -36,12 +36,15 @@
         <el-form-item label="联系电话" prop="phone">
           <el-input v-model="form.phone" placeholder="请输入联系电话" />
         </el-form-item>
-        <el-form-item label="所在地区" prop="province">
-          <el-row :gutter="10">
-            <el-col :span="8"><el-select v-model="form.province" placeholder="省份" style="width: 100%"><el-option label="广东省" value="广东省" /><el-option label="北京市" value="北京市" /></el-select></el-col>
-            <el-col :span="8"><el-select v-model="form.city" placeholder="城市" style="width: 100%"><el-option label="广州市" value="广州市" /><el-option label="深圳市" value="深圳市" /></el-select></el-col>
-            <el-col :span="8"><el-select v-model="form.district" placeholder="区县" style="width: 100%"><el-option label="萝岗区" value="萝岗区" /><el-option label="天河区" value="天河区" /></el-select></el-col>
-          </el-row>
+        <el-form-item label="所在地区" prop="region">
+          <el-cascader
+            v-model="form.regionCodes"
+            :options="regionOptions"
+            :props="{ value: 'code', label: 'name', children: 'children' }"
+            placeholder="请选择省/市/区"
+            style="width: 100%"
+            @change="handleRegionChange"
+          />
         </el-form-item>
         <el-form-item label="详细地址" prop="address">
           <el-input v-model="form.address" type="textarea" :rows="2" placeholder="请输入详细地址" />
@@ -57,36 +60,168 @@
 </template>
 
 <script setup lang="ts">
-import { ref, reactive } from 'vue'
+import { ref, reactive, onMounted } from 'vue'
 import { Plus } from '@element-plus/icons-vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import { PageTitle } from '@/components'
+import { getAddressList, addAddress, updateAddress, deleteAddress, setDefaultAddress } from '@/api/pc/enterprise'
 
 const dialogVisible = ref(false)
 const dialogTitle = ref('新增收货地址')
 const formRef = ref()
 const editingId = ref<number | null>(null)
 
-const form = reactive({ name: '', phone: '', province: '', city: '', district: '', address: '', isDefault: false })
+const form = reactive({ name: '', phone: '', regionCodes: [], region: '', address: '', isDefault: false })
+
+// 省市区数据(示例数据,需要替换为完整数据)
+const regionOptions = ref([
+  {
+    code: '14',
+    name: '山西省',
+    children: [
+      {
+        code: '1405',
+        name: '晋城市',
+        children: [
+          { code: '140524', name: '陵川县' },
+          { code: '140525', name: '泽州县' }
+        ]
+      }
+    ]
+  },
+  {
+    code: '44',
+    name: '广东省',
+    children: [
+      {
+        code: '4401',
+        name: '广州市',
+        children: [
+          { code: '440103', name: '荔湾区' },
+          { code: '440104', name: '越秀区' }
+        ]
+      },
+      {
+        code: '4403',
+        name: '深圳市',
+        children: [
+          { code: '440303', name: '罗湖区' },
+          { code: '440304', name: '福田区' }
+        ]
+      }
+    ]
+  }
+])
 const rules = {
   name: [{ required: true, message: '请输入收货人姓名', trigger: 'blur' }],
   phone: [{ required: true, message: '请输入联系电话', trigger: 'blur' }, { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }],
-  province: [{ required: true, message: '请选择省份', trigger: 'change' }],
   address: [{ required: true, message: '请输入详细地址', trigger: 'blur' }]
 }
 
-const addressList = ref([
-  { id: 1, name: '中国南方电网有限公司', phone: '18062697722', province: '广东省', city: '广州市', district: '萝岗区', address: '科学城11号', isDefault: true },
-  { id: 2, name: '中国南方电网有限公司', phone: '18062697722', province: '广东省', city: '广州市', district: '萝岗区', address: '科学城11号', isDefault: false },
-  { id: 3, name: '中国南方电网有限公司', phone: '18062697722', province: '广东省', city: '广州市', district: '萝岗区', address: '科学城11号', isDefault: false }
-])
+const addressList = ref([])
+
+// 加载地址列表
+const loadAddressList = async () => {
+  try {
+    const res = await getAddressList()
+    if (res.code === 200) {
+      addressList.value = res.rows || []
+    }
+  } catch (error) {
+    console.error('加载地址列表失败:', error)
+    ElMessage.error('加载地址列表失败')
+  }
+}
 
-const resetForm = () => { form.name = ''; form.phone = ''; form.province = ''; form.city = ''; form.district = ''; form.address = ''; form.isDefault = false; editingId.value = null }
+onMounted(() => {
+  loadAddressList()
+})
+
+const resetForm = () => { form.name = ''; form.phone = ''; form.regionCodes = []; form.region = ''; form.address = ''; form.isDefault = false; editingId.value = null }
+
+// 处理地区选择变化
+const handleRegionChange = (value: string[]) => {
+  if (value && value.length === 3) {
+    // 根据选中的代码查找对应的名称
+    const province = regionOptions.value.find(p => p.code === value[0])
+    const city = province?.children?.find(c => c.code === value[1])
+    const district = city?.children?.find(d => d.code === value[2])
+
+    if (province && city && district) {
+      form.region = `${province.name}/${city.name}/${district.name}`
+    }
+  }
+}
 const handleAdd = () => { resetForm(); dialogTitle.value = '新增收货地址'; dialogVisible.value = true }
-const handleEdit = (item: any) => { editingId.value = item.id; form.name = item.name; form.phone = item.phone; form.province = item.province; form.city = item.city; form.district = item.district; form.address = item.address; form.isDefault = item.isDefault; dialogTitle.value = '编辑收货地址'; dialogVisible.value = true }
-const handleSave = async () => { const valid = await formRef.value?.validate(); if (!valid) return; ElMessage.success(editingId.value ? '修改成功' : '新增成功'); dialogVisible.value = false }
-const handleDelete = (item: any) => { ElMessageBox.confirm('确定要删除该收货地址吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { const index = addressList.value.findIndex(i => i.id === item.id); if (index > -1) addressList.value.splice(index, 1); ElMessage.success('删除成功') }) }
-const handleSetDefault = (item: any) => { addressList.value.forEach(i => { i.isDefault = i.id === item.id }); ElMessage.success('设置成功') }
+const handleEdit = (item: any) => {
+  editingId.value = item.id
+  form.name = item.consignee
+  form.phone = item.phone
+  form.region = item.provincialCityCountry || ''
+  form.address = item.address || ''
+  form.isDefault = item.defaultAddress === '1'
+
+  // 尝试根据省市区代码设置级联选择器的值
+  if (item.provincialNo && item.cityNo && item.countryNo) {
+    form.regionCodes = [item.provincialNo, item.cityNo, item.countryNo]
+  } else {
+    form.regionCodes = []
+  }
+
+  dialogTitle.value = '编辑收货地址'
+  dialogVisible.value = true
+}
+const handleSave = async () => {
+  const valid = await formRef.value?.validate();
+  if (!valid) return;
+  try {
+    const data: any = {
+      consignee: form.name,
+      phone: form.phone,
+      address: form.address,
+      isDefault: form.isDefault ? 1 : 0
+    }
+
+    // 如果选择了省市区,发送代码
+    if (form.regionCodes && form.regionCodes.length === 3) {
+      data.provincialNo = form.regionCodes[0]
+      data.cityNo = form.regionCodes[1]
+      data.countryNo = form.regionCodes[2]
+    }
+
+    if (editingId.value) {
+      data.id = editingId.value
+      await updateAddress(data)
+    } else {
+      await addAddress(data)
+    }
+    ElMessage.success(editingId.value ? '修改成功' : '新增成功')
+    dialogVisible.value = false
+    loadAddressList()
+  } catch (error) {
+    ElMessage.error('操作失败')
+  }
+}
+const handleDelete = (item: any) => {
+  ElMessageBox.confirm('确定要删除该收货地址吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(async () => {
+    try {
+      await deleteAddress([item.id])
+      ElMessage.success('删除成功')
+      loadAddressList()
+    } catch (error) {
+      ElMessage.error('删除失败')
+    }
+  })
+}
+const handleSetDefault = async (item: any) => {
+  try {
+    await setDefaultAddress({ id: item.id })
+    ElMessage.success('设置成功')
+    loadAddressList()
+  } catch (error) {
+    ElMessage.error('设置失败')
+  }
+}
 </script>
 
 <style scoped lang="scss">

+ 43 - 5
src/views/enterprise/companyInfo/edit.vue

@@ -187,10 +187,11 @@
 </template>
 
 <script setup lang="ts">
-import { ref, reactive } from 'vue'
+import { ref, reactive, onMounted } from 'vue'
 import { useRouter } from 'vue-router'
 import { ArrowLeft, Plus } from '@element-plus/icons-vue'
 import { ElMessage } from 'element-plus'
+import { getEnterpriseInfo, updateEnterpriseInfo } from '@/api/pc/enterprise'
 
 const router = useRouter()
 const formRef = ref()
@@ -218,6 +219,39 @@ const rules = {
   creditCode: [{ required: true, message: '请输入统一社会信用代码', trigger: 'blur' }]
 }
 
+// 加载企业信息
+const loadEnterpriseInfo = async () => {
+  try {
+    const res = await getEnterpriseInfo()
+    if (res.code === 200 && res.data) {
+      const data = res.data
+      const businessInfo = data.customerBusinessInfoVo || {}
+
+      form.companyName = data.customerName || data.businessCustomerName || ''
+      form.creditCode = businessInfo.socialCreditCode || ''
+      form.legalPerson = businessInfo.legalPersonName || ''
+      form.registeredCapital = businessInfo.registeredCapital || ''
+      form.detailAddress = businessInfo.businessAddress || ''
+      form.businessScope = businessInfo.bussinessRange || ''
+      form.officeAddress = data.address || ''
+      form.industry = data.industryCategory || ''
+      form.scale = data.enterpriseScale || ''
+      form.phone = data.landline || ''
+      form.email = businessInfo.email || data.email || ''
+      form.website = businessInfo.website || ''
+      form.businessLicense = businessInfo.businessLicense || ''
+      form.idCard = businessInfo.idCard || ''
+    }
+  } catch (error) {
+    console.error('加载企业信息失败:', error)
+    ElMessage.error('加载企业信息失败')
+  }
+}
+
+onMounted(() => {
+  loadEnterpriseInfo()
+})
+
 const handleBack = () => {
   router.push('/enterprise/companyInfo')
 }
@@ -233,10 +267,14 @@ const handleUpload = (file: any, field: string) => {
 const handleSave = async () => {
   const valid = await formRef.value?.validate()
   if (!valid) return
-  
-  // TODO: 调用保存接口
-  ElMessage.success('保存成功')
-  handleBack()
+
+  try {
+    await updateEnterpriseInfo(form as any)
+    ElMessage.success('保存成功')
+    handleBack()
+  } catch (error) {
+    ElMessage.error('保存失败')
+  }
 }
 </script>
 

+ 77 - 19
src/views/enterprise/companyInfo/index.vue

@@ -131,9 +131,13 @@
 </template>
 
 <script setup lang="ts">
-import { ref, reactive } from 'vue'
+import { ref, reactive, onMounted } from 'vue'
 import { useRouter } from 'vue-router'
 import { OfficeBuilding, Grid, ArrowRight, Edit, Bell, User, Ticket } from '@element-plus/icons-vue'
+import { getEnterpriseInfo } from '@/api/pc/enterprise'
+import { getAnnouncementList } from '@/api/pc/system/announcement'
+import { getServicePersons } from '@/api/pc/enterprise/servicePerson'
+import { ElMessage } from 'element-plus'
 
 const router = useRouter()
 const activeTab = ref('companyInfo')
@@ -148,30 +152,84 @@ const tabs = [
 ]
 
 const companyData = reactive({
-  companyName: '中国南方电网有限责任公司',
-  companyCode: '123456789',
+  companyName: '加载中...',
+  companyCode: '-',
   customerType: '品牌客户',
   availableAmount: '0.00',
-  creditAmount: '29000.88',
-  creditCode: '内容内容',
+  creditAmount: '0.00',
+  creditCode: '-',
   industry: '-',
-  scale: '5000人以上',
-  phone: '020-22222222',
-  email: '2222222@163.com',
-  address: '内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容'
+  scale: '-',
+  phone: '-',
+  email: '-',
+  address: '-'
 })
 
-const noticeList = ref([
-  { title: '主标题主标题', description: '副标题副标题副标题副标题副标题副标题副标题', date: '08.27' },
-  { title: '主标题主标题主标题主标题', description: '副标题副标题副标题副标题副标题副标题', date: '08.27' },
-  { title: '主标题主标题主标题主标题主标题主标...', description: '副标题副标题副标题', date: '08.27' },
-  { title: '主标题主标题主标题主标题主标题主标题', description: '副标题副标题副标题副标题副标题', date: '08.27' }
-])
+// 加载企业信息
+const loadEnterpriseInfo = async () => {
+  try {
+    const res = await getEnterpriseInfo()
+    console.log('企业信息完整数据:', res.data) // 调试用,查看完整数据结构
+    if (res.code === 200 && res.data) {
+      const data = res.data
+      const salesInfo = data.customerSalesInfoVo || {}
+      const businessInfo = data.customerBusinessInfoVo || {}
+
+      // 辅助函数:处理空值,空字符串也转为 '-'
+      const formatValue = (value: any) => (value && value !== '' ? value : '-')
+
+      companyData.companyName = formatValue(data.customerName || data.businessCustomerName)
+      companyData.companyCode = formatValue(data.customerNo)
+      companyData.creditCode = formatValue(businessInfo.socialCreditCode)
+      companyData.industry = formatValue(data.industryCategory)
+      companyData.scale = formatValue(data.enterpriseScale)
+      companyData.phone = formatValue(data.landline)
+      companyData.email = formatValue(businessInfo.email || data.email)
+      companyData.address = formatValue(data.address)
+      companyData.availableAmount = salesInfo.remainingQuota || '0.00'
+      companyData.creditAmount = salesInfo.creditAmount || '0.00'
+    }
+  } catch (error) {
+    console.error('加载企业信息失败:', error)
+    ElMessage.error('加载企业信息失败')
+  }
+}
 
-const servicePersons = ref([
-  { name: '刘洋', type: '专属采购顾问', department: '品牌中心', phone: '15783782783', avatar: '' },
-  { name: '刘洋', type: '客服人员', department: '027-5233893', phone: '15783782783', avatar: '' }
-])
+// 加载公告列表
+const noticeList = ref([])
+const loadAnnouncementList = async () => {
+  try {
+    const res = await getAnnouncementList({ pageNum: 1, pageSize: 4 })
+    if (res.code === 200 && res.rows) {
+      noticeList.value = res.rows.map((item: any) => ({
+        title: item.announcementTitle,
+        description: item.announcementContent?.substring(0, 50) || '',
+        date: item.createTime ? new Date(item.createTime).toLocaleDateString('zh-CN', { month: '2-digit', day: '2-digit' }) : ''
+      }))
+    }
+  } catch (error) {
+    console.error('加载公告失败:', error)
+  }
+}
+
+onMounted(() => {
+  loadEnterpriseInfo()
+  loadAnnouncementList()
+  loadServicePersons()
+})
+
+// 加载专属服务人员
+const servicePersons = ref([])
+const loadServicePersons = async () => {
+  try {
+    const res = await getServicePersons()
+    if (res.code === 200 && res.data) {
+      servicePersons.value = res.data
+    }
+  } catch (error) {
+    console.error('加载服务人员失败:', error)
+  }
+}
 
 const privileges = ref([
   { name: '满免运费', description: '会员购买商品订单总金额达到标准后可免运费。' },

+ 62 - 15
src/views/enterprise/invoiceManage/index.vue

@@ -15,10 +15,9 @@
     </div>
     <!-- 表格 -->
     <el-table :data="tableData" border style="width: 100%" :resizable="false">
-      <el-table-column prop="invoiceTitle" label="发票抬头" width="140" show-overflow-tooltip :resizable="false" />
-      <el-table-column prop="taxNo" label="纳税人识别号" width="130" :resizable="false" />
-      <el-table-column prop="bankName" label="开户银行" width="120" :resizable="false" />
+      <el-table-column prop="bankName" label="开户银行" width="140" show-overflow-tooltip :resizable="false" />
       <el-table-column prop="bankAccount" label="开户账户" width="140" :resizable="false" />
+      <el-table-column prop="taxId" label="纳税人识别号" width="160" :resizable="false" />
       <el-table-column prop="address" label="地址" min-width="140" show-overflow-tooltip :resizable="false" />
       <el-table-column prop="phone" label="电话" width="120" :resizable="false" />
       <el-table-column label="操作" width="120" fixed="right" :resizable="false">
@@ -59,6 +58,7 @@
 import { ref, reactive, onMounted } from 'vue'
 import { Search } from '@element-plus/icons-vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
+import { getInvoiceList, addInvoice, updateInvoice, deleteInvoice } from '@/api/pc/enterprise'
 
 const dialogVisible = ref(false)
 const dialogTitle = ref('新增开票信息')
@@ -67,7 +67,7 @@ const editingId = ref<number | null>(null)
 const total = ref(0)
 
 const queryParams = reactive({ pageNum: 1, pageSize: 10, keyword: '', searchType: 'accountName' })
-const form = reactive({ invoiceTitle: '', taxNo: '', bankName: '', bankAccount: '', address: '', phone: '' })
+const form = reactive({ invoiceTitle: '', taxNo: '', bankName: '', bankAccount: '', address: '', phone: '', bankId: null, bankCode: '' })
 const rules = {
   invoiceTitle: [{ required: true, message: '请输入发票抬头', trigger: 'blur' }],
   taxNo: [{ required: true, message: '请输入纳税人识别号', trigger: 'blur' }],
@@ -75,19 +75,66 @@ const rules = {
   bankAccount: [{ required: true, message: '请输入开户账户', trigger: 'blur' }]
 }
 
-const tableData = ref([
-  { id: 1, invoiceTitle: '北京吉浪文化传...', taxNo: '23455a2121', bankName: '湖北交通银行', bankAccount: '3273237283723', address: '福建省泉州市金...', phone: '18525220957' },
-  { id: 2, invoiceTitle: '北京志荣煤拓科...', taxNo: '23455a2121', bankName: '中国银行', bankAccount: '3273237283723', address: '陕西省榆林市神...', phone: '13513660470' },
-  { id: 3, invoiceTitle: '高诚美恒公司', taxNo: '23455a2121', bankName: '中国建设银行', bankAccount: '3273237283723', address: '宁夏回族自治区...', phone: '13881559836' }
-])
+const tableData = ref([])
 
-onMounted(() => { total.value = 500 })
-const handleQuery = () => {}
-const resetForm = () => { form.invoiceTitle = ''; form.taxNo = ''; form.bankName = ''; form.bankAccount = ''; form.address = ''; form.phone = ''; editingId.value = null }
+// 加载发票列表
+const loadInvoiceList = async () => {
+  try {
+    const res = await getInvoiceList(queryParams)
+    if (res.code === 200) {
+      tableData.value = res.rows || []
+      total.value = res.total || 0
+    }
+  } catch (error) {
+    console.error('加载发票列表失败:', error)
+    ElMessage.error('加载发票列表失败')
+  }
+}
+
+onMounted(() => { loadInvoiceList() })
+const handleQuery = () => { loadInvoiceList() }
+const resetForm = () => { form.invoiceTitle = ''; form.taxNo = ''; form.bankName = ''; form.bankAccount = ''; form.address = ''; form.phone = ''; form.bankId = null; form.bankCode = ''; editingId.value = null }
 const handleAdd = () => { resetForm(); dialogTitle.value = '新增开票信息'; dialogVisible.value = true }
-const handleEdit = (row: any) => { editingId.value = row.id; form.invoiceTitle = row.invoiceTitle; form.taxNo = row.taxNo; form.bankName = row.bankName; form.bankAccount = row.bankAccount; form.address = row.address; form.phone = row.phone; dialogTitle.value = '编辑开票信息'; dialogVisible.value = true }
-const handleSave = async () => { const valid = await formRef.value?.validate(); if (!valid) return; ElMessage.success(editingId.value ? '修改成功' : '新增成功'); dialogVisible.value = false }
-const handleDelete = (row: any) => { ElMessageBox.confirm('确定要删除该开票信息吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { const index = tableData.value.findIndex(i => i.id === row.id); if (index > -1) tableData.value.splice(index, 1); ElMessage.success('删除成功') }) }
+const handleEdit = (row: any) => { editingId.value = row.id; form.invoiceTitle = row.invoiceTitle || ''; form.taxNo = row.taxId; form.bankName = row.bankName; form.bankAccount = row.bankAccount; form.address = row.address; form.phone = row.phone; form.bankId = row.bankId; form.bankCode = row.bankCode || ''; dialogTitle.value = '编辑开票信息'; dialogVisible.value = true }
+const handleSave = async () => {
+  const valid = await formRef.value?.validate();
+  if (!valid) return;
+  try {
+    const data: any = {
+      taxId: form.taxNo,
+      bankName: form.bankName,
+      bankAccount: form.bankAccount,
+      address: form.address,
+      phone: form.phone,
+      bankId: form.bankId || 0,
+      bankCode: form.bankCode || 'DEFAULT'
+    }
+    console.log('发送的数据:', data)
+    if (editingId.value) {
+      data.id = editingId.value
+      await updateInvoice(data)
+    } else {
+      await addInvoice(data)
+    }
+    ElMessage.success(editingId.value ? '修改成功' : '新增成功')
+    dialogVisible.value = false
+    loadInvoiceList()
+  } catch (error) {
+    console.error('保存失败:', error)
+    ElMessage.error('操作失败')
+  }
+}
+const handleDelete = (row: any) => {
+  ElMessageBox.confirm('确定要删除该开票信息吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(async () => {
+    try {
+      await deleteInvoice([row.id])
+      ElMessage.success('删除成功')
+      loadInvoiceList()
+    } catch (error) {
+      ElMessage.error('删除失败')
+    }
+  })
+}
 </script>
 
 <style scoped lang="scss">

+ 97 - 49
src/views/organization/deptManage/index.vue

@@ -5,12 +5,28 @@
       <el-button type="danger" @click="handleAdd(null)">+ 新增部门</el-button>
     </div>
 
-    <el-table :data="deptList" row-key="id" default-expand-all :tree-props="{ children: 'children' }" :indent="24">
-      <el-table-column prop="name" label="部门" min-width="250" />
-      <el-table-column prop="status" label="状态" width="100" align="center" />
-      <el-table-column prop="currentQuota" label="现有额度(年)" width="130" align="center" />
-      <el-table-column prop="usedQuota" label="已用额度(年)" width="130" align="center" />
-      <el-table-column prop="remainQuota" label="剩余额度(年)" width="130" align="center" />
+    <el-table :data="deptList" row-key="deptId" default-expand-all :tree-props="{ children: 'children' }" :indent="24">
+      <el-table-column prop="deptName" label="部门" min-width="250" />
+      <el-table-column prop="status" label="状态" width="100" align="center">
+        <template #default="{ row }">
+          {{ row.status === '0' ? '启用' : '停用' }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="yearlyBudget" label="现有额度(年)" width="130" align="center">
+        <template #default="{ row }">
+          {{ row.yearlyBudget || '0.00' }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="usedBudget" label="已用额度(年)" width="130" align="center">
+        <template #default="{ row }">
+          {{ row.usedBudget || '0.00' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="剩余额度(年)" width="130" align="center">
+        <template #default="{ row }">
+          {{ (row.yearlyBudget || 0) - (row.usedBudget || 0) }}
+        </template>
+      </el-table-column>
       <el-table-column label="操作" width="180" align="center">
         <template #default="{ row }">
           <el-button type="primary" link size="small" @click="handleEdit(row)">编辑</el-button>
@@ -26,17 +42,17 @@
         <el-form-item label="上级部门">
           <el-input :value="formData.parentName || '无(顶级部门)'" disabled />
         </el-form-item>
-        <el-form-item label="部门名称" prop="name">
-          <el-input v-model="formData.name" placeholder="请输入部门名称" />
+        <el-form-item label="部门名称" prop="deptName">
+          <el-input v-model="formData.deptName" placeholder="请输入部门名称" />
         </el-form-item>
         <el-form-item label="状态" prop="status">
           <el-radio-group v-model="formData.status">
-            <el-radio label="启用">启用</el-radio>
-            <el-radio label="停用">停用</el-radio>
+            <el-radio label="0">启用</el-radio>
+            <el-radio label="1">停用</el-radio>
           </el-radio-group>
         </el-form-item>
         <el-form-item label="年度额度">
-          <el-input-number v-model="formData.currentQuota" :min="0" :precision="2" controls-position="right" style="width: 200px" />
+          <el-input-number v-model="formData.yearlyBudget" :min="0" :precision="2" controls-position="right" style="width: 200px" />
         </el-form-item>
       </el-form>
       <template #footer>
@@ -48,9 +64,10 @@
 </template>
 
 <script setup lang="ts">
-import { ref, reactive, computed } from 'vue'
+import { ref, reactive, computed, onMounted } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import { PageTitle } from '@/components'
+import { getDeptTree, addDept, updateDept, deleteDept } from '@/api/pc/organization'
 
 const dialogVisible = ref(false)
 const formRef = ref()
@@ -58,78 +75,109 @@ const editingRow = ref<any>(null)
 const parentRow = ref<any>(null)
 
 const formData = reactive({
-  name: '',
-  status: '启用',
-  currentQuota: 0,
+  deptId: undefined,
+  deptName: '',
+  parentId: undefined,
+  status: '0',
+  yearlyBudget: 0,
   parentName: ''
 })
 
 const formRules = {
-  name: [{ required: true, message: '请输入部门名称', trigger: 'blur' }]
+  deptName: [{ required: true, message: '请输入部门名称', trigger: 'blur' }]
 }
 
 const dialogTitle = computed(() => editingRow.value ? '编辑部门' : '新增部门')
 
-const deptList = ref([
-  {
-    id: 1, name: '技术部', status: '启用', currentQuota: '0.00', usedQuota: '0.00', remainQuota: '0.00',
-    children: [
-      { id: 11, name: '前端组', status: '启用', currentQuota: '0.00', usedQuota: '0.00', remainQuota: '0.00' },
-      { id: 12, name: '后端组', status: '启用', currentQuota: '0.00', usedQuota: '0.00', remainQuota: '0.00' }
-    ]
-  },
-  { id: 2, name: '财务部', status: '启用', currentQuota: '0.00', usedQuota: '0.00', remainQuota: '0.00' },
-  { id: 3, name: '设计部', status: '启用', currentQuota: '0.00', usedQuota: '0.00', remainQuota: '0.00' },
-  { id: 4, name: '财务部', status: '启用', currentQuota: '0.00', usedQuota: '0.00', remainQuota: '0.00' },
-  {
-    id: 5, name: '人事部...', status: '启用', currentQuota: '0.00', usedQuota: '0.00', remainQuota: '0.00',
-    children: [
-      { id: 51, name: '人事部01', status: '启用', currentQuota: '0.00', usedQuota: '0.00', remainQuota: '0.00' },
-      { id: 52, name: '人事部02', status: '启用', currentQuota: '0.00', usedQuota: '0.00', remainQuota: '0.00' }
-    ]
+const deptList = ref([])
+
+// 加载部门树
+const loadDeptTree = async () => {
+  try {
+    const res = await getDeptTree()
+    if (res.code === 200 && res.data) {
+      deptList.value = res.data
+    }
+  } catch (error) {
+    console.error('获取部门树失败:', error)
+    ElMessage.error('获取部门树失败')
   }
-])
+}
 
 const handleAdd = (parent: any) => {
   editingRow.value = null
   parentRow.value = parent
-  formData.name = ''
-  formData.status = '启用'
-  formData.currentQuota = 0
-  formData.parentName = parent ? parent.name : ''
+  formData.deptId = undefined
+  formData.deptName = ''
+  formData.parentId = parent ? parent.deptId : undefined
+  formData.status = '0'
+  formData.yearlyBudget = 0
+  formData.parentName = parent ? parent.deptName : ''
   dialogVisible.value = true
 }
 
 const handleEdit = (row: any) => {
   editingRow.value = row
   parentRow.value = null
-  formData.name = row.name
-  formData.status = row.status
-  formData.currentQuota = parseFloat(row.currentQuota) || 0
+  formData.deptId = row.deptId
+  formData.deptName = row.deptName
+  formData.parentId = row.parentId
+  formData.status = row.status || '0'
+  formData.yearlyBudget = row.yearlyBudget || 0
   formData.parentName = ''
   dialogVisible.value = true
 }
 
 const handleDelete = (row: any) => {
-  ElMessageBox.confirm(`确定要删除部门"${row.name}"吗?`, '提示', {
+  ElMessageBox.confirm(`确定要删除部门"${row.deptName}"吗?`, '提示', {
     confirmButtonText: '确定',
     cancelButtonText: '取消',
     type: 'warning'
-  }).then(() => {
-    ElMessage.success('删除成功')
+  }).then(async () => {
+    try {
+      await deleteDept([row.deptId])
+      ElMessage.success('删除成功')
+      await loadDeptTree()
+    } catch (error) {
+      console.error('删除失败:', error)
+      ElMessage.error('删除失败')
+    }
   })
 }
 
 const handleSubmit = async () => {
   const valid = await formRef.value?.validate()
   if (!valid) return
-  if (editingRow.value) {
-    ElMessage.success('编辑成功')
-  } else {
-    ElMessage.success('新增成功')
+
+  try {
+    const data = {
+      deptId: formData.deptId,
+      deptName: formData.deptName,
+      parentId: formData.parentId,
+      status: formData.status,
+      yearlyBudget: formData.yearlyBudget
+    }
+
+    if (editingRow.value) {
+      await updateDept(data)
+      ElMessage.success('编辑成功')
+    } else {
+      await addDept(data)
+      ElMessage.success('新增成功')
+    }
+
+    dialogVisible.value = false
+    await loadDeptTree()
+  } catch (error) {
+    console.error('保存失败:', error)
+    ElMessage.error('保存失败')
   }
-  dialogVisible.value = false
 }
+
+// 页面加载时获取部门树
+onMounted(() => {
+  loadDeptTree()
+})
 </script>
 
 <style scoped lang="scss">

+ 109 - 13
src/views/organization/personalInfo/index.vue

@@ -25,12 +25,20 @@
       <div class="form-row">
         <el-form-item label="性别" prop="gender">
           <el-select v-model="formData.gender" placeholder="请选择" style="width: 100%">
-            <el-option label="男" value="male" />
-            <el-option label="女" value="female" />
+            <el-option label="男" value="0" />
+            <el-option label="女" value="1" />
+            <el-option label="未知" value="2" />
           </el-select>
         </el-form-item>
         <el-form-item label="角色" prop="role">
-          <el-input v-model="formData.role" placeholder="请输入" />
+          <el-select v-model="formData.role" placeholder="请选择" style="width: 100%">
+            <el-option
+              v-for="role in roleList"
+              :key="role.roleId"
+              :label="role.roleName"
+              :value="role.roleId.toString()"
+            />
+          </el-select>
         </el-form-item>
       </div>
 
@@ -49,19 +57,19 @@
         </el-form-item>
         <el-form-item label="所属部门" prop="department">
           <el-select v-model="formData.department" placeholder="请选择" style="width: 100%">
-            <el-option label="技术部" value="tech" />
-            <el-option label="销售部" value="sales" />
-            <el-option label="财务部" value="finance" />
+            <el-option
+              v-for="dept in deptList"
+              :key="dept.deptId"
+              :label="dept.deptName"
+              :value="dept.deptId.toString()"
+            />
           </el-select>
         </el-form-item>
       </div>
 
       <div class="form-row single">
-        <el-form-item label="所属部门" prop="subDepartment">
-          <el-select v-model="formData.subDepartment" placeholder="请选择" style="width: 100%">
-            <el-option label="研发组" value="dev" />
-            <el-option label="测试组" value="test" />
-          </el-select>
+        <el-form-item label="所在地区" prop="subDepartment">
+          <el-input v-model="formData.subDepartment" placeholder="请输入省市区" />
         </el-form-item>
       </div>
 
@@ -85,13 +93,17 @@
 </template>
 
 <script setup lang="ts">
-import { ref, reactive } from 'vue'
+import { ref, reactive, onMounted } from 'vue'
 import { ElMessage } from 'element-plus'
 import { PageTitle } from '@/components'
+import { getCurrentUserInfo, updateContact, getDeptList, getRoleList } from '@/api/pc/organization'
 
 const formRef = ref()
+const deptList = ref<any[]>([])
+const roleList = ref<any[]>([])
 
 const formData = reactive({
+  id: 0,
   userId: '',
   phone: '',
   realName: '',
@@ -112,11 +124,95 @@ const rules = {
   phone: [{ required: true, message: '请输入手机号码', trigger: 'blur' }]
 }
 
+// 获取当前用户信息
+const loadUserInfo = async () => {
+  try {
+    const res = await getCurrentUserInfo()
+    if (res.code === 200 && res.data) {
+      // 映射后端字段到前端字段
+      formData.id = res.data.id
+      formData.userId = res.data.id?.toString() || ''
+      formData.phone = res.data.phone || ''
+      formData.realName = res.data.contactName || ''
+      formData.officePhone = res.data.officePhone || ''
+      formData.gender = res.data.gender || ''
+      formData.role = res.data.roleId?.toString() || ''
+      formData.birthday = res.data.birthday || ''
+      formData.wechat = res.data.customLoginName || ''  // 微信号映射到customLoginName
+      formData.email = res.data.email || ''
+      formData.department = res.data.deptId?.toString() || ''  // 部门ID
+      formData.subDepartment = res.data.provincialCityCounty || ''  // 省市区
+      formData.address = res.data.addressDetail || ''
+      formData.remark = res.data.remark || ''
+    }
+  } catch (error) {
+    console.error('获取用户信息失败:', error)
+    ElMessage.error('获取用户信息失败')
+  }
+}
+
 const handleSave = async () => {
   const valid = await formRef.value?.validate()
   if (!valid) return
-  ElMessage.success('保存成功')
+
+  try {
+    // 映射前端字段到后端字段
+    const data = {
+      id: formData.id,
+      contactName: formData.realName,
+      phone: formData.phone,
+      officePhone: formData.officePhone,
+      gender: formData.gender,
+      roleId: formData.role || undefined,
+      deptId: formData.department || undefined,
+      birthday: formData.birthday,
+      customLoginName: formData.wechat,
+      email: formData.email,
+      provincialCityCounty: formData.subDepartment,
+      addressDetail: formData.address,
+      remark: formData.remark
+    }
+
+    await updateContact(data)
+    ElMessage.success('保存成功')
+  } catch (error) {
+    console.error('保存失败:', error)
+    ElMessage.error('保存失败')
+  }
 }
+
+// 加载部门列表
+const loadDeptList = async () => {
+  try {
+    const res = await getDeptList()
+    console.log('部门列表响应:', res)
+    if (res.code === 200 && res.data) {
+      deptList.value = res.data
+      console.log('部门列表加载成功:', deptList.value)
+    }
+  } catch (error) {
+    console.error('获取部门列表失败:', error)
+  }
+}
+
+// 加载角色列表
+const loadRoleList = async () => {
+  try {
+    const res = await getRoleList()
+    if (res.code === 200 && res.data) {
+      roleList.value = res.data
+    }
+  } catch (error) {
+    console.error('获取角色列表失败:', error)
+  }
+}
+
+// 页面加载时获取用户信息、部门列表和角色列表
+onMounted(async () => {
+  // 先加载部门和角色列表,再加载用户信息
+  await Promise.all([loadDeptList(), loadRoleList()])
+  await loadUserInfo()
+})
 </script>
 
 <style scoped lang="scss">

+ 142 - 152
src/views/organization/roleManage/index.vue

@@ -1,27 +1,24 @@
 <template>
-  <div class="role-manage-container">
-    <PageTitle title="角色管理" />
-
-    <!-- 角色Tab + 新增按钮 -->
-    <div class="role-header">
-      <div class="role-tabs">
-        <div v-for="tab in roleTabs" :key="tab.key" :class="['tab-item', { active: activeRole === tab.key }]" @click="activeRole = tab.key">
-          {{ tab.label }}
-        </div>
-      </div>
-      <el-button type="danger" link @click="handleAddRole"><el-icon><Plus /></el-icon>新增角色</el-button>
+  <div class="page-container">
+    <div class="page-header">
+      <PageTitle title="角色管理" />
+      <el-button type="danger" @click="handleAdd">新增角色</el-button>
     </div>
 
-    <!-- 人员表格 -->
-    <el-table :data="staffList" border>
-      <el-table-column prop="name" label="姓名" min-width="120" align="center" />
-      <el-table-column prop="phone" label="手机号" min-width="150" align="center" />
-      <el-table-column prop="status" label="状态" min-width="100" align="center">
+    <el-table :data="paginatedRoleList" border>
+      <el-table-column prop="roleName" label="角色名称" min-width="150" align="center" />
+      <el-table-column prop="roleKey" label="权限字符" min-width="150" align="center" />
+      <el-table-column prop="roleSort" label="显示顺序" width="100" align="center" />
+      <el-table-column prop="status" label="状态" width="100" align="center">
         <template #default="{ row }">
-          <span :class="['status-text', row.status === '启用' ? 'active' : '']">{{ row.status }}</span>
+          <span :style="{ color: row.status === '0' ? '#67c23a' : '#999' }">
+            {{ row.status === '0' ? '正常' : '停用' }}
+          </span>
         </template>
       </el-table-column>
-      <el-table-column label="操作" min-width="120" align="center">
+      <el-table-column prop="createTime" label="创建时间" width="180" align="center" />
+      <el-table-column prop="remark" label="备注" min-width="150" align="center" show-overflow-tooltip />
+      <el-table-column label="操作" width="150" align="center" fixed="right">
         <template #default="{ row }">
           <el-button type="primary" link size="small" @click="handleEdit(row)">编辑</el-button>
           <el-button type="danger" link size="small" @click="handleDelete(row)">删除</el-button>
@@ -29,186 +26,187 @@
       </el-table-column>
     </el-table>
 
+    <el-pagination
+      v-model:current-page="currentPage"
+      v-model:page-size="pageSize"
+      :page-sizes="[10, 20, 50, 100]"
+      :total="total"
+      layout="total, sizes, prev, pager, next, jumper"
+      @size-change="handleSizeChange"
+      @current-change="handleCurrentChange"
+      style="margin-top: 20px; justify-content: flex-end"
+    />
+
     <!-- 新增/编辑角色弹窗 -->
-    <el-dialog v-model="roleDialogVisible" :title="roleDialogTitle" width="500px" destroy-on-close>
-      <el-form ref="roleFormRef" :model="roleFormData" :rules="roleFormRules" label-width="100px">
-        <el-form-item label="角色名称" prop="name">
-          <el-input v-model="roleFormData.name" placeholder="请输入角色名称" />
+    <el-dialog v-model="dialogVisible" :title="dialogTitle" width="500px" destroy-on-close>
+      <el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px">
+        <el-form-item label="角色名称" prop="roleName">
+          <el-input v-model="formData.roleName" placeholder="请输入角色名称" />
         </el-form-item>
-        <el-form-item label="角色描述">
-          <el-input v-model="roleFormData.description" type="textarea" :rows="3" placeholder="请输入角色描述" />
+        <el-form-item label="权限字符" prop="roleKey">
+          <el-input v-model="formData.roleKey" placeholder="请输入权限字符" />
         </el-form-item>
-        <el-form-item label="状态">
-          <el-radio-group v-model="roleFormData.status">
-            <el-radio label="启用">启用</el-radio>
-            <el-radio label="停用">停用</el-radio>
-          </el-radio-group>
-        </el-form-item>
-      </el-form>
-      <template #footer>
-        <el-button @click="roleDialogVisible = false">取消</el-button>
-        <el-button type="danger" @click="handleRoleSubmit">确定</el-button>
-      </template>
-    </el-dialog>
-
-    <!-- 编辑人员弹窗 -->
-    <el-dialog v-model="staffDialogVisible" title="编辑人员" width="500px" destroy-on-close>
-      <el-form ref="staffFormRef" :model="staffFormData" :rules="staffFormRules" label-width="100px">
-        <el-form-item label="姓名" prop="name">
-          <el-input v-model="staffFormData.name" placeholder="请输入姓名" />
-        </el-form-item>
-        <el-form-item label="手机号" prop="phone">
-          <el-input v-model="staffFormData.phone" placeholder="请输入手机号" />
+        <el-form-item label="显示顺序" prop="roleSort">
+          <el-input-number v-model="formData.roleSort" :min="0" />
         </el-form-item>
         <el-form-item label="状态">
-          <el-radio-group v-model="staffFormData.status">
-            <el-radio label="启用">启用</el-radio>
-            <el-radio label="停用">停用</el-radio>
+          <el-radio-group v-model="formData.status">
+            <el-radio label="0">正常</el-radio>
+            <el-radio label="1">停用</el-radio>
           </el-radio-group>
         </el-form-item>
+        <el-form-item label="备注">
+          <el-input v-model="formData.remark" type="textarea" :rows="3" placeholder="请输入备注" />
+        </el-form-item>
       </el-form>
       <template #footer>
-        <el-button @click="staffDialogVisible = false">取消</el-button>
-        <el-button type="danger" @click="handleStaffSubmit">确定</el-button>
+        <el-button @click="dialogVisible = false">取消</el-button>
+        <el-button type="danger" @click="handleSubmit">确定</el-button>
       </template>
     </el-dialog>
   </div>
 </template>
 
 <script setup lang="ts">
-import { ref, reactive, computed } from 'vue'
-import { Plus } from '@element-plus/icons-vue'
+import { ref, reactive, computed, onMounted } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import { PageTitle } from '@/components'
-
-const activeRole = ref('role01')
-const roleDialogVisible = ref(false)
-const staffDialogVisible = ref(false)
-const roleFormRef = ref()
-const staffFormRef = ref()
-const editingRole = ref<any>(null)
-
-const roleFormData = reactive({
-  name: '',
-  description: '',
-  status: '启用'
+import { getRoleList, addRole, updateRole, deleteRole } from '@/api/pc/organization'
+
+const roleList = ref([])
+const currentPage = ref(1)
+const pageSize = ref(10)
+const dialogVisible = ref(false)
+const formRef = ref()
+const editingRow = ref<any>(null)
+
+const formData = reactive({
+  roleId: undefined,
+  roleName: '',
+  roleKey: '',
+  roleSort: 0,
+  status: '0',
+  remark: ''
 })
 
-const staffFormData = reactive({
-  name: '',
-  phone: '',
-  status: '启用'
+const formRules = {
+  roleName: [{ required: true, message: '请输入角色名称', trigger: 'blur' }],
+  roleKey: [{ required: true, message: '请输入权限字符', trigger: 'blur' }]
+}
+
+const total = computed(() => roleList.value.length)
+const dialogTitle = computed(() => editingRow.value ? '编辑角色' : '新增角色')
+
+const paginatedRoleList = computed(() => {
+  const start = (currentPage.value - 1) * pageSize.value
+  const end = start + pageSize.value
+  return roleList.value.slice(start, end)
 })
 
-const roleFormRules = {
-  name: [{ required: true, message: '请输入角色名称', trigger: 'blur' }]
+const loadRoleList = async () => {
+  try {
+    const res = await getRoleList()
+    if (res.code === 200 && res.data) {
+      roleList.value = res.data
+    }
+  } catch (error) {
+    console.error('获取角色列表失败:', error)
+    ElMessage.error('获取角色列表失败')
+  }
 }
 
-const staffFormRules = {
-  name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
-  phone: [{ required: true, message: '请输入手机号', trigger: 'blur' }]
+const handleSizeChange = (val: number) => {
+  pageSize.value = val
+  currentPage.value = 1
 }
 
-const roleDialogTitle = computed(() => editingRole.value ? '编辑角色' : '新增角色')
-
-const roleTabs = ref([
-  { key: 'role01', label: '角色01' },
-  { key: 'role02', label: '角色02' },
-  { key: 'role03', label: '角色03' },
-  { key: 'role04', label: '角色04' },
-  { key: 'role05', label: '角色05' },
-  { key: 'role06', label: '角色06' }
-])
-
-const staffList = ref([
-  { id: 1, name: '郑婷雅', phone: '137 8651 5262', status: '启用' },
-  { id: 2, name: '冯艺莲', phone: '158 6084 7617', status: '启用' },
-  { id: 3, name: '吴彦琛', phone: '158 0598 5923', status: '启用' },
-  { id: 4, name: '吴彦漆', phone: '137 8231 8088', status: '启用' },
-  { id: 5, name: '周碰', phone: '180 6243 3980', status: '启用' },
-  { id: 6, name: '吴萱萱', phone: '131 1251 9348', status: '启用' },
-  { id: 7, name: '王凡玄', phone: '185 3264 9149', status: '启用' },
-  { id: 8, name: '冯启彬', phone: '184 5857 8572', status: '启用' },
-  { id: 9, name: '郑文锦', phone: '189 2860 9388', status: '启用' },
-  { id: 10, name: '赵吾光', phone: '181 0834 1643', status: '启用' }
-])
-
-const handleAddRole = () => {
-  editingRole.value = null
-  roleFormData.name = ''
-  roleFormData.description = ''
-  roleFormData.status = '启用'
-  roleDialogVisible.value = true
+const handleCurrentChange = (val: number) => {
+  currentPage.value = val
 }
 
-const handleRoleSubmit = async () => {
-  const valid = await roleFormRef.value?.validate()
-  if (!valid) return
-  if (editingRole.value) {
-    ElMessage.success('编辑成功')
-  } else {
-    // 添加新角色到tabs
-    const newKey = 'role' + (roleTabs.value.length + 1).toString().padStart(2, '0')
-    roleTabs.value.push({ key: newKey, label: roleFormData.name })
-    ElMessage.success('新增成功')
-  }
-  roleDialogVisible.value = false
+const handleAdd = () => {
+  editingRow.value = null
+  Object.assign(formData, {
+    roleId: undefined,
+    roleName: '',
+    roleKey: '',
+    roleSort: 0,
+    status: '0',
+    remark: ''
+  })
+  dialogVisible.value = true
 }
 
 const handleEdit = (row: any) => {
-  staffFormData.name = row.name
-  staffFormData.phone = row.phone
-  staffFormData.status = row.status
-  staffDialogVisible.value = true
+  editingRow.value = row
+  Object.assign(formData, {
+    roleId: row.roleId,
+    roleName: row.roleName,
+    roleKey: row.roleKey,
+    roleSort: row.roleSort,
+    status: row.status,
+    remark: row.remark
+  })
+  dialogVisible.value = true
 }
 
-const handleStaffSubmit = async () => {
-  const valid = await staffFormRef.value?.validate()
+const handleSubmit = async () => {
+  const valid = await formRef.value?.validate()
   if (!valid) return
-  ElMessage.success('编辑成功')
-  staffDialogVisible.value = false
+
+  try {
+    if (editingRow.value) {
+      await updateRole(formData)
+      ElMessage.success('编辑成功')
+    } else {
+      await addRole(formData)
+      ElMessage.success('新增成功')
+    }
+    dialogVisible.value = false
+    await loadRoleList()
+  } catch (error) {
+    console.error('操作失败:', error)
+    ElMessage.error('操作失败')
+  }
 }
 
 const handleDelete = (row: any) => {
-  ElMessageBox.confirm(`确定要删除"${row.name}"吗?`, '提示', {
+  ElMessageBox.confirm(`确定要删除角色"${row.roleName}"吗?`, '提示', {
     confirmButtonText: '确定',
     cancelButtonText: '取消',
     type: 'warning'
-  }).then(() => {
-    ElMessage.success('删除成功')
+  }).then(async () => {
+    try {
+      await deleteRole([row.roleId])
+      ElMessage.success('删除成功')
+      await loadRoleList()
+    } catch (error) {
+      console.error('删除失败:', error)
+      ElMessage.error('删除失败')
+    }
   })
 }
+
+onMounted(() => {
+  loadRoleList()
+})
 </script>
 
 <style scoped lang="scss">
-.role-manage-container {
+.page-container {
   padding: 20px;
   background: #fff;
   min-height: 100%;
 }
 
-.role-header {
+.page-header {
   display: flex;
   justify-content: space-between;
   align-items: center;
   margin-bottom: 20px;
-}
 
-.role-tabs {
-  display: flex;
-  gap: 10px;
-
-  .tab-item {
-    padding: 6px 16px;
-    border-radius: 4px;
-    cursor: pointer;
-    font-size: 13px;
-    color: #666;
-    background: #f5f5f5;
-    transition: all 0.2s;
-
-    &:hover { color: #e60012; }
-    &.active { background: #e60012; color: #fff; }
+  :deep(.page-title) {
+    margin-bottom: 0;
   }
 }
 
@@ -218,13 +216,5 @@ const handleDelete = (row: any) => {
     font-weight: 500;
     color: #333;
   }
-  .el-table__cell {
-    padding: 10px 0;
-  }
-}
-
-.status-text {
-  color: #999;
-  &.active { color: #67c23a; }
 }
 </style>

+ 167 - 55
src/views/reconciliation/billManage/index.vue

@@ -1,46 +1,53 @@
 <template>
   <div class="page-container">
     <PageTitle title="对账单管理" />
-    
+
     <SearchBar :form="searchForm" :filters="filters" placeholder="对账编号" />
 
-    <el-table :data="tableData" border style="width: 100%">
-      <el-table-column type="index" label="序号" width="60" align="center" />
+    <el-table v-loading="loading" :data="tableData" border style="width: 100%">
       <el-table-column prop="billNo" label="对账编号" min-width="130" align="center" />
       <el-table-column prop="billDate" label="对账日期" min-width="110" align="center" />
       <el-table-column prop="amount" label="对账单金额" min-width="110" align="center">
         <template #default="{ row }">¥{{ row.amount.toFixed(2) }}</template>
       </el-table-column>
       <el-table-column prop="billStatus" label="对账状态" min-width="90" align="center">
-        <template #default="{ row }">{{ row.billStatus === '1' ? '已对账' : '未对账' }}</template>
+        <template #default="{ row }">
+          {{ billStatusMap[row.billStatus] || '-' }}
+        </template>
       </el-table-column>
       <el-table-column prop="invoiceStatus" label="开票状态" min-width="90" align="center">
         <template #default="{ row }">
           <span :style="{ color: row.invoiceStatus === '1' ? '#e60012' : '' }">
-            {{ row.invoiceStatus === '1' ? '已开票' : '-' }}
+            {{ invoiceStatusMap[row.invoiceStatus] || '-' }}
           </span>
         </template>
       </el-table-column>
       <el-table-column prop="payStatus" label="支付状态" min-width="90" align="center">
-        <template #default="{ row }">{{ row.payStatus === '1' ? '已支付' : '-' }}</template>
+        <template #default="{ row }">
+          {{ payStatusMap[row.payStatus] || '-' }}
+        </template>
       </el-table-column>
       <el-table-column label="操作" width="100" align="center">
         <template #default="{ row }">
           <el-button type="primary" link size="small" @click="handleView(row)">查看</el-button>
-          <el-button type="danger" link size="small" @click="handleConfirm(row)" :disabled="row.billStatus === '1'">确认</el-button>
+          <el-button type="danger" link size="small" @click="handleConfirm(row)" :disabled="row.billStatus !== '1'">确认</el-button>
         </template>
       </el-table-column>
     </el-table>
 
-    <TablePagination v-model:page="pagination.page" v-model:pageSize="pagination.pageSize" :total="pagination.total" />
+    <div class="pagination-wrapper">
+      <TablePagination v-model:page="pagination.page" v-model:pageSize="pagination.pageSize" :total="pagination.total" />
+    </div>
   </div>
 </template>
 
 <script setup lang="ts">
-import { reactive, ref, computed } from 'vue'
+import { reactive, ref, onMounted, watch } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import { PageTitle, SearchBar, TablePagination } from '@/components'
-import { BILL_STATUS_OPTIONS, INVOICE_STATUS_OPTIONS, PAY_STATUS_OPTIONS } from '@/constants/status'
+import { getStatementList, confirmStatement } from '@/api/pc/enterprise/statement'
+import type { StatementOrder } from '@/api/pc/enterprise/statementTypes'
+import { getDictByType } from '@/api/pc/system/dict'
 
 const searchForm = reactive({
   keyword: '',  // 对账编号
@@ -50,63 +57,168 @@ const searchForm = reactive({
   payStatus: ''
 })
 
-const filters = [
-  { field: 'billStatus', label: '对账状态', options: BILL_STATUS_OPTIONS },
-  { field: 'invoiceStatus', label: '开票状态', options: INVOICE_STATUS_OPTIONS },
-  { field: 'payStatus', label: '支付状态', options: PAY_STATUS_OPTIONS }
-]
-
-const pagination = reactive({ page: 1, pageSize: 10, total: 100 })
-
-// 原始数据
-const rawData = ref([
-  { id: 1, billNo: '2323232323', billDate: '2025-11-22', amount: 2115.97, billStatus: '1', invoiceStatus: '1', payStatus: '1' },
-  { id: 2, billNo: '2323412123', billDate: '2025-12-09', amount: 4476.12, billStatus: '1', invoiceStatus: '1', payStatus: '1' },
-  { id: 3, billNo: '4566784543', billDate: '2025-11-21', amount: 7751.34, billStatus: '', invoiceStatus: '1', payStatus: '1' },
-  { id: 4, billNo: '2356565654', billDate: '2025-11-27', amount: 7936.37, billStatus: '1', invoiceStatus: '1', payStatus: '1' },
-  { id: 5, billNo: '2323412123', billDate: '2025-12-11', amount: 3931.45, billStatus: '', invoiceStatus: '1', payStatus: '1' },
-  { id: 6, billNo: '2323232323', billDate: '2025-11-27', amount: 6132.75, billStatus: '1', invoiceStatus: '1', payStatus: '1' },
-  { id: 7, billNo: '2356565654', billDate: '2025-11-25', amount: 3189.56, billStatus: '1', invoiceStatus: '1', payStatus: '1' },
-  { id: 8, billNo: '2323232323', billDate: '2025-11-20', amount: 993.66, billStatus: '', invoiceStatus: '1', payStatus: '1' },
-  { id: 9, billNo: '2323412123', billDate: '2025-11-17', amount: 2763.35, billStatus: '1', invoiceStatus: '1', payStatus: '1' },
-  { id: 10, billNo: '2323232323', billDate: '2025-12-05', amount: 9286.45, billStatus: '', invoiceStatus: '1', payStatus: '0' }
+const billStatusOptions = ref([{ label: '全部', value: '' }])
+const invoiceStatusOptions = ref([{ label: '全部', value: '' }])
+const payStatusOptions = ref([{ label: '全部', value: '' }])
+
+// 状态值到文本的映射
+const billStatusMap = ref<Record<string, string>>({})
+const invoiceStatusMap = ref<Record<string, string>>({})
+const payStatusMap = ref<Record<string, string>>({})
+
+const filters = ref([
+  { field: 'billStatus', label: '对账状态', options: billStatusOptions.value },
+  { field: 'invoiceStatus', label: '开票状态', options: invoiceStatusOptions.value },
+  { field: 'payStatus', label: '支付状态', options: payStatusOptions.value }
 ])
 
-// 过滤后的数据
-const tableData = computed(() => {
-  return rawData.value.filter(item => {
-    // 按对账编号过滤
-    if (searchForm.keyword && !item.billNo.includes(searchForm.keyword)) {
-      return false
+const pagination = reactive({ page: 1, pageSize: 5, total: 0 })
+const tableData = ref<any[]>([])
+const loading = ref(false)
+
+// 加载对账单列表
+const loadStatementList = async () => {
+  try {
+    loading.value = true
+    const res = await getStatementList({
+      pageNum: pagination.page,
+      pageSize: pagination.pageSize,
+      statementOrderNo: searchForm.keyword,
+      statementStatus: searchForm.billStatus,
+      isInvoiceStatus: searchForm.invoiceStatus,
+      isPaymentStatus: searchForm.payStatus
+    })
+
+    if (res.code === 200 && res.rows) {
+      tableData.value = res.rows.map((item: StatementOrder) => ({
+        id: item.id,
+        billNo: item.statementOrderNo,
+        billDate: item.statementDate,
+        amount: parseFloat(item.amount as any) || 0,
+        billStatus: item.statementStatus,
+        invoiceStatus: item.isInvoiceStatus,
+        payStatus: item.isPaymentStatus
+      }))
+      pagination.total = res.total || 0
     }
-    // 按对账状态过滤
-    if (searchForm.billStatus && item.billStatus !== searchForm.billStatus) {
-      return false
+  } catch (error) {
+    console.error('加载对账单列表失败:', error)
+    ElMessage.error('加载对账单列表失败')
+  } finally {
+    loading.value = false
+  }
+}
+
+// 监听分页变化
+watch(() => [pagination.page, pagination.pageSize], () => {
+  loadStatementList()
+})
+
+// 监听搜索条件变化
+watch(() => [searchForm.keyword, searchForm.billStatus, searchForm.invoiceStatus, searchForm.payStatus], () => {
+  pagination.page = 1
+  loadStatementList()
+})
+
+// 加载字典数据
+const loadDictData = async () => {
+  try {
+    // 加载对账状态
+    const statementRes = await getDictByType('statement_status')
+    if (statementRes.data) {
+      billStatusOptions.value = [
+        { label: '全部', value: '' },
+        ...statementRes.data.map(item => ({
+          label: item.dictLabel,
+          value: item.dictValue
+        }))
+      ]
+      filters.value[0].options = billStatusOptions.value
+
+      // 构建状态值到文本的映射
+      billStatusMap.value = statementRes.data.reduce((map, item) => {
+        map[item.dictValue] = item.dictLabel
+        return map
+      }, {} as Record<string, string>)
     }
-    // 按开票状态过滤
-    if (searchForm.invoiceStatus && item.invoiceStatus !== searchForm.invoiceStatus) {
-      return false
+
+    // 加载开票状态
+    const invoiceRes = await getDictByType('invoice_issuance_status')
+    if (invoiceRes.data) {
+      invoiceStatusOptions.value = [
+        { label: '全部', value: '' },
+        ...invoiceRes.data.map(item => ({
+          label: item.dictLabel,
+          value: item.dictValue
+        }))
+      ]
+      filters.value[1].options = invoiceStatusOptions.value
+
+      // 构建状态值到文本的映射
+      invoiceStatusMap.value = invoiceRes.data.reduce((map, item) => {
+        map[item.dictValue] = item.dictLabel
+        return map
+      }, {} as Record<string, string>)
     }
-    // 按支付状态过滤
-    if (searchForm.payStatus && item.payStatus !== searchForm.payStatus) {
-      return false
+
+    // 加载支付状态
+    const payRes = await getDictByType('payment_status')
+    if (payRes.data) {
+      payStatusOptions.value = [
+        { label: '全部', value: '' },
+        ...payRes.data.map(item => ({
+          label: item.dictLabel,
+          value: item.dictValue
+        }))
+      ]
+      filters.value[2].options = payStatusOptions.value
+
+      // 构建状态值到文本的映射
+      payStatusMap.value = payRes.data.reduce((map, item) => {
+        map[item.dictValue] = item.dictLabel
+        return map
+      }, {} as Record<string, string>)
     }
-    return true
-  })
+  } catch (error) {
+    console.error('加载字典数据失败:', error)
+  }
+}
+
+// 页面加载时获取数据
+onMounted(() => {
+  loadDictData()
+  loadStatementList()
 })
 
 const handleView = (row: any) => {
   ElMessage.info(`查看对账单:${row.billNo}`)
 }
 
-const handleConfirm = (row: any) => {
-  ElMessageBox.confirm(`确定要确认对账单"${row.billNo}"吗?`, '提示', {
-    confirmButtonText: '确定',
-    cancelButtonText: '取消',
-    type: 'warning'
-  }).then(() => {
-    row.billStatus = '1'
+const handleConfirm = async (row: any) => {
+  try {
+    await ElMessageBox.confirm(`确定要确认对账单"${row.billNo}"吗?`, '提示', {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning'
+    })
+
+    await confirmStatement({ id: row.id })
+    row.billStatus = '2'
     ElMessage.success('确认成功')
-  })
+    loadStatementList()
+  } catch (error) {
+    if (error !== 'cancel') {
+      console.error('确认对账单失败:', error)
+      ElMessage.error('确认对账单失败')
+    }
+  }
 }
 </script>
+
+<style scoped>
+.pagination-wrapper {
+  margin-top: 16px;
+  display: flex;
+  justify-content: flex-end;
+}
+</style>

+ 167 - 300
src/views/reconciliation/invoiceManage/index.vue

@@ -1,346 +1,213 @@
 <template>
-  <div class="invoice-manage-container">
+  <div class="page-container">
     <PageTitle title="开票管理" />
-    
-    <!-- 搜索栏 -->
-    <div class="search-bar">
-      <el-input v-model="searchForm.keyword" placeholder="搜索" clearable style="width: 180px">
-        <template #prefix>
-          <el-icon><Search /></el-icon>
-        </template>
-      </el-input>
-      <div class="date-filter">
-        <span class="label">订单下单时间</span>
-        <el-date-picker
-          v-model="searchForm.orderDateRange"
-          type="daterange"
-          start-placeholder="开始日期"
-          end-placeholder="结束日期"
-          value-format="YYYY-MM-DD"
-          style="width: 240px"
-        />
-      </div>
-      <div class="date-filter">
-        <span class="label">订单完成时间</span>
-        <el-date-picker
-          v-model="searchForm.completeDateRange"
-          type="daterange"
-          start-placeholder="开始日期"
-          end-placeholder="结束日期"
-          value-format="YYYY-MM-DD"
-          style="width: 240px"
-        />
-      </div>
-    </div>
 
-    <!-- 操作按钮 -->
-    <div class="action-bar">
-      <el-button>订单导出</el-button>
-      <el-button>Excel批量导入开票</el-button>
-    </div>
-
-    <!-- 未开发票订单列表 -->
-    <div class="order-list-title">未开发票订单列表</div>
-    
-    <div class="order-list">
-      <div v-for="order in orderList" :key="order.id" class="order-card">
-        <div class="order-header">
-          <el-checkbox v-model="order.checked" />
-          <span class="order-time">{{ order.orderTime }}</span>
-          <span class="order-no">订单号:{{ order.orderNo }}</span>
-        </div>
-        <div class="order-content">
-          <el-checkbox v-model="order.checked" class="item-checkbox" />
-          <img :src="order.productImg" class="product-img" />
-          <div class="product-info">
-            <div class="product-name">{{ order.productName }}</div>
-            <div class="product-spec">
-              <span>{{ order.spec1 }}</span>
-              <span>{{ order.spec2 }}</span>
-              <span class="quantity">x{{ order.quantity }}</span>
-            </div>
-            <div class="product-price">¥{{ order.price }}</div>
-          </div>
-          <div class="pay-info">
-            <div class="pay-amount">实付款 <span class="amount">¥{{ order.payAmount }}</span></div>
-            <div class="pay-method">{{ order.payMethod }}</div>
-          </div>
-          <div class="order-status">
-            <span class="status-text">{{ order.status }}</span>
-          </div>
-        </div>
-      </div>
-    </div>
+    <SearchBar :form="searchForm" :filters="filters" placeholder="对账编号" />
+
+    <el-table v-loading="loading" :data="tableData" border style="width: 100%" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column prop="billNo" label="对账编号" min-width="130" align="center" />
+      <el-table-column prop="billDate" label="对账日期" min-width="110" align="center" />
+      <el-table-column prop="amount" label="对账单金额" min-width="110" align="center">
+        <template #default="{ row }">¥{{ row.amount.toFixed(2) }}</template>
+      </el-table-column>
+      <el-table-column prop="billStatus" label="对账状态" min-width="90" align="center">
+        <template #default="{ row }">
+          <span v-if="row.billStatus === '0'">待确认</span>
+          <span v-else-if="row.billStatus === '1'">已确认</span>
+          <span v-else-if="row.billStatus === '2'">已驳回</span>
+          <span v-else>-</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="100" align="center">
+        <template #default="{ row }">
+          <el-button type="primary" link size="small" @click="handleView(row)">查看</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
 
-    <!-- 底部操作栏 -->
     <div class="bottom-bar">
-      <div class="select-all">
-        <el-checkbox v-model="selectAll" @change="handleSelectAll">全选</el-checkbox>
-      </div>
       <div class="summary">
-        <span>已勾选 <em>{{ selectedCount }}/{{ orderList.length }}</em> 个订单</span>
-        <span class="total">共计 <em>¥{{ totalAmount.toFixed(2) }}</em></span>
-        <el-button type="danger" :disabled="selectedCount === 0">申请开票</el-button>
+        <span>已选择 <em>{{ selectedCount }}</em> 个对账单</span>
+        <span class="total">合计金额 <em>¥{{ totalAmount.toFixed(2) }}</em></span>
+        <el-button type="primary" :disabled="selectedCount === 0" @click="handleApplyInvoice">申请开票</el-button>
       </div>
     </div>
+
+    <div class="pagination-wrapper">
+      <TablePagination v-model:page="pagination.page" v-model:pageSize="pagination.pageSize" :total="pagination.total" />
+    </div>
   </div>
 </template>
 
 <script setup lang="ts">
-import { reactive, ref, computed } from 'vue'
-import { Search } from '@element-plus/icons-vue'
-import { PageTitle } from '@/components'
-import type { CheckboxValueType } from 'element-plus'
+import { reactive, ref, computed, onMounted, watch } from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { PageTitle, SearchBar, TablePagination } from '@/components'
+import { getStatementList } from '@/api/pc/enterprise/statement'
+import type { StatementOrder } from '@/api/pc/enterprise/statementTypes'
+import { getDictByType } from '@/api/pc/system/dict'
 
-// 搜索表单
 const searchForm = reactive({
   keyword: '',
-  orderDateRange: [],
-  completeDateRange: []
+  dateRange: [],
+  invoiceStatus: ''
 })
 
-// 全选
-const selectAll = ref(false)
+const invoiceStatusOptions = ref([{ label: '全部', value: '' }])
 
-// 模拟订单数据
-const orderList = ref([
-  {
-    id: 1,
-    checked: true,
-    orderTime: '2025/12/05 16:15:06',
-    orderNo: '489283929283298392',
-    productImg: 'https://via.placeholder.com/80',
-    productName: '清华同方超越E500台式机电脑超越E500台式机电脑(i3-6100/4G/1T/19.5寸)',
-    spec1: '规格02',
-    spec2: '规格01',
-    quantity: 1,
-    price: 181,
-    payAmount: 181,
-    payMethod: '微信支付',
-    status: '已完成'
-  },
-  {
-    id: 2,
-    checked: false,
-    orderTime: '2025/12/05 16:15:06',
-    orderNo: '489283929283298392',
-    productImg: 'https://via.placeholder.com/80',
-    productName: '清华同方超越E500台式机电脑超越E500台式机电脑(i3-6100/4G/1T/19.5寸)',
-    spec1: '规格02',
-    spec2: '规格01',
-    quantity: 1,
-    price: 181,
-    payAmount: 181,
-    payMethod: '微信支付',
-    status: '已完成'
-  },
-  {
-    id: 3,
-    checked: false,
-    orderTime: '2025/12/05 16:15:06',
-    orderNo: '489283929283298392',
-    productImg: 'https://via.placeholder.com/80',
-    productName: '清华同方超越E500台式机电脑超越E500台式机电脑(i3-6100/4G/1T/19.5寸)',
-    spec1: '规格02',
-    spec2: '规格01',
-    quantity: 1,
-    price: 181,
-    payAmount: 181,
-    payMethod: '微信支付',
-    status: '已完成'
-  }
+const filters = ref([
+  { field: 'invoiceStatus', label: '开票状态', options: invoiceStatusOptions.value }
 ])
 
-// 计算选中数量
-const selectedCount = computed(() => orderList.value.filter(item => item.checked).length)
+const pagination = reactive({ page: 1, pageSize: 5, total: 0 })
+const tableData = ref<any[]>([])
+const loading = ref(false)
+const selectedRows = ref<any[]>([])
+
+// 加载对账单列表
+const loadStatementList = async () => {
+  try {
+    loading.value = true
+    const res = await getStatementList({
+      pageNum: pagination.page,
+      pageSize: pagination.pageSize,
+      statementOrderNo: searchForm.keyword,
+      statementStatus: '1', // 只查询已确认的对账单
+      isInvoiceStatus: searchForm.invoiceStatus || '0' // 默认查询未开票的对账单
+    })
+
+    if (res.code === 200 && res.rows) {
+      tableData.value = res.rows.map((item: StatementOrder) => ({
+        id: item.id,
+        billNo: item.statementOrderNo,
+        billDate: item.statementDate,
+        amount: parseFloat(item.amount as any) || 0,
+        billStatus: item.statementStatus
+      }))
+      pagination.total = res.total || 0
+    }
+  } catch (error) {
+    console.error('加载对账单列表失败:', error)
+    ElMessage.error('加载对账单列表失败')
+  } finally {
+    loading.value = false
+  }
+}
 
-// 计算总金额
-const totalAmount = computed(() => {
-  return orderList.value.filter(item => item.checked).reduce((sum, item) => sum + item.payAmount, 0)
+// 监听分页变化
+watch(() => [pagination.page, pagination.pageSize], () => {
+  loadStatementList()
 })
 
-// 全选处理
-const handleSelectAll = (val: CheckboxValueType) => {
-  orderList.value.forEach(item => {
-    item.checked = !!val
-  })
-}
-</script>
-
-<style scoped lang="scss">
-.invoice-manage-container {
-  padding: 20px;
-  background: #fff;
-  min-height: 100%;
-}
+// 监听搜索条件变化
+watch(() => [searchForm.keyword, searchForm.invoiceStatus], () => {
+  pagination.page = 1
+  loadStatementList()
+})
 
-.search-bar {
-  display: flex;
-  align-items: center;
-  gap: 20px;
-  margin-bottom: 16px;
-  
-  .date-filter {
-    display: flex;
-    align-items: center;
-    gap: 8px;
-    
-    .label {
-      color: #666;
-      font-size: 14px;
-      white-space: nowrap;
+// 加载字典数据
+const loadDictData = async () => {
+  try {
+    const res = await getDictByType('invoice_issuance_status')
+    if (res.data) {
+      invoiceStatusOptions.value = [
+        { label: '全部', value: '' },
+        ...res.data.map(item => ({
+          label: item.dictLabel,
+          value: item.dictValue
+        }))
+      ]
+      filters.value[0].options = invoiceStatusOptions.value
     }
+  } catch (error) {
+    console.error('加载字典数据失败:', error)
   }
 }
 
-.action-bar {
-  margin-bottom: 20px;
+// 页面加载时获取数据
+onMounted(() => {
+  loadDictData()
+  loadStatementList()
+})
+
+// 处理选择变化
+const handleSelectionChange = (selection: any[]) => {
+  selectedRows.value = selection
 }
 
-.order-list-title {
-  font-size: 14px;
-  color: #333;
-  margin-bottom: 16px;
+// 计算选中数量
+const selectedCount = computed(() => selectedRows.value.length)
+
+// 计算总金额
+const totalAmount = computed(() => {
+  return selectedRows.value.reduce((sum, item) => sum + item.amount, 0)
+})
+
+const handleView = (row: any) => {
+  ElMessage.info(`查看对账单:${row.billNo}`)
 }
 
-.order-list {
-  .order-card {
-    border: 1px solid #eee;
-    margin-bottom: 16px;
-    
-    .order-header {
-      display: flex;
-      align-items: center;
-      gap: 16px;
-      padding: 12px 16px;
-      background: #fafafa;
-      border-bottom: 1px solid #eee;
-      
-      .order-time {
-        color: #666;
-        font-size: 14px;
-      }
-      
-      .order-no {
-        color: #666;
-        font-size: 14px;
-      }
-    }
-    
-    .order-content {
-      display: flex;
-      align-items: center;
-      padding: 16px;
-      gap: 16px;
-      
-      .item-checkbox {
-        display: none;
-      }
-      
-      .product-img {
-        width: 80px;
-        height: 80px;
-        object-fit: cover;
-        border: 1px solid #eee;
-      }
-      
-      .product-info {
-        flex: 1;
-        
-        .product-name {
-          font-size: 14px;
-          color: #333;
-          margin-bottom: 8px;
-          line-height: 1.4;
-        }
-        
-        .product-spec {
-          font-size: 12px;
-          color: #999;
-          margin-bottom: 8px;
-          display: flex;
-          gap: 12px;
-          
-          .quantity {
-            color: #666;
-          }
-        }
-        
-        .product-price {
-          font-size: 14px;
-          color: #e60012;
-          font-weight: bold;
-        }
-      }
-      
-      .pay-info {
-        width: 120px;
-        text-align: center;
-        
-        .pay-amount {
-          font-size: 14px;
-          color: #333;
-          margin-bottom: 4px;
-          
-          .amount {
-            color: #e60012;
-            font-weight: bold;
-          }
-        }
-        
-        .pay-method {
-          font-size: 12px;
-          color: #999;
-        }
-      }
-      
-      .order-status {
-        width: 80px;
-        text-align: center;
-        
-        .status-text {
-          color: #e60012;
-          font-size: 14px;
-        }
+const handleApplyInvoice = async () => {
+  try {
+    const billNos = selectedRows.value.map(row => row.billNo).join('、')
+    await ElMessageBox.confirm(
+      `确定要为以下对账单申请开票吗?\n${billNos}`,
+      '提示',
+      {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
       }
+    )
+
+    // TODO: 调用申请开票接口
+    ElMessage.success('申请开票成功')
+    loadStatementList()
+  } catch (error) {
+    if (error !== 'cancel') {
+      console.error('申请开票失败:', error)
+      ElMessage.error('申请开票失败')
     }
   }
 }
+</script>
 
+<style scoped>
 .bottom-bar {
-  margin-top: 20px;
+  margin-top: 16px;
   padding: 16px;
   background: #fafafa;
   border: 1px solid #eee;
   border-radius: 4px;
+  display: flex;
+  justify-content: flex-end;
+}
+
+.summary {
   display: flex;
   align-items: center;
-  justify-content: space-between;
-  
-  .select-all {
-    display: flex;
-    align-items: center;
-  }
-  
-  .summary {
-    display: flex;
-    align-items: center;
-    gap: 20px;
-    
-    span {
-      font-size: 14px;
-      color: #666;
-      
-      em {
-        color: #e60012;
-        font-style: normal;
-      }
-    }
-    
-    .total em {
-      font-size: 16px;
-      font-weight: bold;
-    }
-  }
+  gap: 20px;
+}
+
+.summary span {
+  font-size: 14px;
+  color: #666;
+}
+
+.summary em {
+  color: #e60012;
+  font-style: normal;
+  font-weight: bold;
+}
+
+.summary .total em {
+  font-size: 16px;
+}
+
+.pagination-wrapper {
+  margin-top: 16px;
+  display: flex;
+  justify-content: flex-end;
 }
 </style>

+ 71 - 10
src/views/trade/afterSale/index.vue

@@ -14,7 +14,7 @@
 
     <template v-if="activeMainTab !== 'complaint'">
       <div class="status-tabs">
-        <div v-for="tab in statusTabs" :key="tab.key" :class="['status-tab', { active: activeStatusTab === tab.key }]" @click="activeStatusTab = tab.key">
+        <div v-for="tab in statusTabs" :key="tab.key" :class="['status-tab', { active: activeStatusTab === tab.key }]" @click="handleStatusTabChange(tab.key)">
           {{ tab.label }}
         </div>
       </div>
@@ -45,7 +45,7 @@
         <div class="col-action">操作</div>
       </div>
 
-      <div class="after-sale-list">
+      <div v-loading="loading" class="after-sale-list">
         <div v-for="(item, index) in afterSaleList" :key="index" class="after-sale-card">
           <div class="card-header">
             <span class="service-no">服务单号:{{ item.serviceNo }}</span>
@@ -144,10 +144,12 @@
 </template>
 
 <script setup lang="ts">
-import { ref, reactive, computed } from 'vue'
+import { ref, reactive, computed, onMounted } from 'vue'
 import { useRouter } from 'vue-router'
 import { Search, RefreshRight, Tools, ChatLineSquare, Picture } from '@element-plus/icons-vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
+import { getOrderReturnList, getOrderReturnInfo, addOrderReturn, updateOrderReturn, deleteOrderReturn } from '@/api/pc/enterprise/orderReturn'
+import type { OrderReturn } from '@/api/pc/enterprise/orderReturnTypes'
 
 const router = useRouter()
 const activeMainTab = ref('return')
@@ -156,6 +158,7 @@ const complaintDialogVisible = ref(false)
 const complaintDialogTitle = ref('新增投诉与建议')
 const complaintFormRef = ref()
 const currentComplaint = ref<any>(null)
+const loading = ref(false)
 
 const mainTabs = [
   { key: 'return', label: '退换货', icon: RefreshRight },
@@ -188,12 +191,53 @@ const complaintRules = {
   content: [{ required: true, message: '请输入反馈内容', trigger: 'blur' }]
 }
 
-const allAfterSaleData = ref([
-  { serviceNo: '2232323', orderNo: '489283929283298392', productImage: '', productName: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)', quantity: 1, applyTime: '2021-10-23 10:00:34', serviceType: '退货', status: 'completed', statusText: '已完成', type: 'return' },
-  { serviceNo: '2232324', orderNo: '489283929283298393', productImage: '', productName: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)', quantity: 1, applyTime: '2021-10-23 10:00:34', serviceType: '退货', status: 'cancelled', statusText: '已取消', type: 'return' },
-  { serviceNo: '2232325', orderNo: '489283929283298394', productImage: '', productName: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)', quantity: 1, applyTime: '2021-10-23 10:00:34', serviceType: '返修/维修', status: 'completed', statusText: '已完成', type: 'repair' },
-  { serviceNo: '2232326', orderNo: '489283929283298395', productImage: '', productName: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)', quantity: 1, applyTime: '2021-10-23 10:00:34', serviceType: '返修/维修', status: 'completed', statusText: '已完成', type: 'repair' }
-])
+// 售后数据列表
+const allAfterSaleData = ref<any[]>([])
+
+// 加载售后数据
+const loadAfterSaleData = async () => {
+  try {
+    loading.value = true
+    const res = await getOrderReturnList({
+      returnStatus: activeStatusTab.value === 'all' ? '' : activeStatusTab.value,
+      serviceType: '0'
+    })
+
+    if (res.code === 200 && res.rows) {
+      // 将后端数据转换为前端展示格式
+      allAfterSaleData.value = res.rows.map((item: OrderReturn) => ({
+        id: item.id,
+        serviceNo: item.returnNo,
+        orderNo: item.orderNo,
+        productImage: '',
+        productName: item.orderReturnItemList?.[0]?.productName || '商品名称',
+        quantity: item.returnProductNum || 1,
+        applyTime: item.returnTime,
+        serviceType: item.serviceType,
+        status: item.returnStatus,
+        statusText: getStatusText(item.returnStatus),
+        type: item.serviceType === '0' ? 'return' : 'repair'
+      }))
+    }
+  } catch (error) {
+    console.error('加载售后数据失败:', error)
+    ElMessage.error('加载售后数据失败')
+  } finally {
+    loading.value = false
+  }
+}
+
+// 获取状态文本
+const getStatusText = (status?: string) => {
+  const statusMap: Record<string, string> = {
+    'applying': '申请中',
+    'returned': '已退货',
+    'rejected': '已拒绝',
+    'completed': '已完成',
+    'cancelled': '已取消'
+  }
+  return statusMap[status || ''] || status || '未知'
+}
 
 const allComplaintData = ref([
   { id: 1, submitTime: '2025-11-30 22:16', submitter: '李豫卓', feedbackType: '', handleTime: '2025-12-10 23:04', handler: '李豫卓', handleResult: '已处理' },
@@ -211,7 +255,24 @@ const afterSaleList = computed(() => {
 
 const complaintList = computed(() => allComplaintData.value)
 
-const handleMainTabChange = (key: string) => { activeMainTab.value = key; activeStatusTab.value = 'all' }
+const handleMainTabChange = (key: string) => {
+  activeMainTab.value = key
+  activeStatusTab.value = 'all'
+  if (key !== 'complaint') {
+    loadAfterSaleData()
+  }
+}
+
+// 状态切换时刷新数据
+const handleStatusTabChange = (key: string) => {
+  activeStatusTab.value = key
+  loadAfterSaleData()
+}
+
+// 页面加载时获取数据
+onMounted(() => {
+  loadAfterSaleData()
+})
 const getStatusClass = (status: string) => {
   const map: Record<string, string> = { applying: 'warning', returned: 'success', rejected: 'danger', completed: 'success', cancelled: 'info' }
   return map[status] || 'info'

+ 176 - 56
src/views/trade/orderAudit/index.vue

@@ -6,7 +6,7 @@
     <StatusTabs v-model="activeMainTab" :tabs="mainTabs" type="line" @change="handleMainTabChange" />
 
     <!-- 状态Tab切换 -->
-    <StatusTabs v-model="activeStatusTab" :tabs="currentStatusTabs" type="pill" />
+    <StatusTabs v-model="activeStatusTab" :tabs="currentStatusTabs" type="pill" @change="handleStatusTabChange" />
 
     <!-- 搜索栏 -->
     <div class="search-bar">
@@ -53,21 +53,33 @@
         <div class="product-list">
           <div class="product-row">
             <div class="product-cell product-info-cell">
-              <div class="product-image">
-                <el-image :src="order.products[0].image" fit="contain">
-                  <template #error>
-                    <div class="image-placeholder">
-                      <el-icon :size="30" color="#ccc"><Picture /></el-icon>
-                    </div>
-                  </template>
-                </el-image>
-              </div>
-              <div class="product-detail">
-                <div class="product-name">{{ order.products[0].name }}</div>
-                <div class="product-spec">{{ order.products[0].spec1 }} {{ order.products[0].spec2 }}</div>
-                <div class="product-price">¥{{ order.products[0].price }}</div>
-              </div>
-              <div class="product-quantity">x{{ order.products[0].quantity }}</div>
+              <template v-if="order.products && order.products.length > 0">
+                <div class="product-image">
+                  <el-image :src="order.products[0].image" fit="contain">
+                    <template #error>
+                      <div class="image-placeholder">
+                        <el-icon :size="30" color="#ccc"><Picture /></el-icon>
+                      </div>
+                    </template>
+                  </el-image>
+                </div>
+                <div class="product-detail">
+                  <div class="product-name">{{ order.products[0].name }}</div>
+                  <div class="product-spec">{{ order.products[0].spec1 }} {{ order.products[0].spec2 }}</div>
+                  <div class="product-price">¥{{ order.products[0].price }}</div>
+                </div>
+                <div class="product-quantity">x{{ order.products[0].quantity }}</div>
+              </template>
+              <template v-else>
+                <div class="product-image">
+                  <div class="image-placeholder">
+                    <el-icon :size="30" color="#ccc"><Picture /></el-icon>
+                  </div>
+                </div>
+                <div class="product-detail">
+                  <div class="product-name">暂无商品信息</div>
+                </div>
+              </template>
             </div>
             <div class="product-cell amount-cell">
               <div class="amount-info">
@@ -79,15 +91,14 @@
               </div>
             </div>
             <div class="product-cell status-cell">
-              <span :class="['status-text', getStatusClass(order.auditStatus)]">{{ getStatusText(order.auditStatus) }}</span>
+              <span :class="['status-text', getStatusClass(order.checkStatus)]">{{ getStatusText(order.checkStatus) }}</span>
               <el-button type="primary" link size="small">查看订单轨迹</el-button>
-              <template v-if="order.auditStatus !== 'pending' && activeMainTab === 'myAudit'">
+              <template v-if="order.checkStatus !== '0' && activeMainTab === 'myAudit'">
                 <el-button type="primary" link size="small">查看审批流</el-button>
               </template>
               <template v-if="activeMainTab === 'myApply'">
-                <span v-if="order.auditStatus === 'approved'" class="result-text success">审批通过</span>
-                <span v-else-if="order.auditStatus === 'rejected'" class="result-text danger">审批驳回</span>
-                <span v-else-if="order.auditStatus === 'cancelled'" class="result-text danger">审批取消</span>
+                <span v-if="order.checkStatus === '1'" class="result-text success">审批通过</span>
+                <span v-else-if="order.checkStatus === '2'" class="result-text danger">审批驳回</span>
                 <el-button type="primary" link size="small">查看审批流</el-button>
               </template>
               <el-button v-if="order.fileCount" type="primary" link size="small">
@@ -95,11 +106,11 @@
               </el-button>
             </div>
             <div class="product-cell action-cell">
-              <template v-if="activeMainTab === 'myAudit' && order.auditStatus === 'pending'">
+              <template v-if="activeMainTab === 'myAudit' && order.checkStatus === '0'">
                 <el-button type="primary" link size="small" @click="handleApprove(order)">同意</el-button>
                 <el-button type="danger" link size="small" @click="handleReject(order)">拒绝</el-button>
               </template>
-              <template v-if="activeMainTab === 'myApply' && order.auditStatus === 'pending'">
+              <template v-if="activeMainTab === 'myApply' && order.checkStatus === '0'">
                 <el-button type="primary" link size="small" @click="handleCancelApply(order)">取消申请</el-button>
               </template>
             </div>
@@ -109,6 +120,19 @@
       <el-empty v-if="orderList.length === 0" description="暂无审核订单" />
     </div>
 
+    <!-- 分页 -->
+    <div class="pagination-container">
+      <el-pagination
+        v-model:current-page="pageNum"
+        v-model:page-size="pageSize"
+        :total="displayTotal"
+        :page-sizes="[10, 20, 50, 100]"
+        layout="total, sizes, prev, pager, next, jumper"
+        @size-change="handleSizeChange"
+        @current-change="handlePageChange"
+      />
+    </div>
+
     <!-- 审批弹窗 -->
     <el-dialog v-model="auditDialogVisible" :title="auditDialogTitle" width="450px">
       <el-form ref="auditFormRef" :model="auditForm" :rules="auditRules" label-width="80px">
@@ -125,11 +149,12 @@
 </template>
 
 <script setup lang="ts">
-import { ref, reactive, computed } from 'vue'
+import { ref, reactive, computed, onMounted } from 'vue'
 import { useRouter } from 'vue-router'
 import { Search, Document, User, ArrowRight, Picture } from '@element-plus/icons-vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import { PageTitle, StatusTabs } from '@/components'
+import { getOrderList, getOrderProducts, checkOrderStatus } from '@/api/pc/enterprise/order'
 
 const router = useRouter()
 
@@ -140,6 +165,11 @@ const auditDialogTitle = ref('审批')
 const auditFormRef = ref()
 const currentAuditOrder = ref<any>(null)
 const currentAuditAction = ref('')
+const loading = ref(false)
+const allOrders = ref<any[]>([])
+const pageNum = ref(1)
+const pageSize = ref(5)
+const total = ref(0)
 
 const mainTabs = [
   { key: 'myAudit', label: '我审批的', icon: Document },
@@ -149,7 +179,8 @@ const mainTabs = [
 const auditStatusTabs = [
   { key: 'all', label: '全部订单' },
   { key: 'pending', label: '待审批' },
-  { key: 'approved', label: '已审批' }
+  { key: 'approved', label: '已通过' },
+  { key: 'rejected', label: '已驳回' }
 ]
 
 const applyStatusTabs = [
@@ -174,47 +205,129 @@ const queryParams = reactive({
 const auditForm = reactive({ opinion: '' })
 const auditRules = { opinion: [{ required: true, message: '请输入审批意见', trigger: 'blur' }] }
 
-const myAuditOrders = ref([
-  { orderTime: '2025/12/05 16:15:06', orderNo: '489283929283298392', payAmount: '181', payMethod: '微信支付', auditStatus: 'pending', fileCount: 1, checked: false, products: [{ id: 1, name: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)', spec1: '规格02', spec2: '规格01', price: '181', quantity: 1, image: '' }] },
-  { orderTime: '2025/12/05 16:15:06', orderNo: '489283929283298393', payAmount: '181', payMethod: '微信支付', auditStatus: 'approved', fileCount: 1, checked: false, products: [{ id: 1, name: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)', spec1: '规格02', spec2: '规格01', price: '181', quantity: 1, image: '' }] },
-  { orderTime: '2025/12/05 16:15:06', orderNo: '489283929283298394', payAmount: '181', payMethod: '微信支付', auditStatus: 'rejected', fileCount: 1, checked: false, products: [{ id: 1, name: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)', spec1: '规格02', spec2: '规格01', price: '181', quantity: 1, image: '' }] }
-])
+// 加载订单列表数据
+const loadOrderList = async () => {
+  try {
+    loading.value = true
 
-const myApplyOrders = ref([
-  { orderTime: '2025/12/05 16:15:06', orderNo: '489283929283298392', payAmount: '181', payMethod: '微信支付', auditStatus: 'approved', fileCount: 1, checked: false, products: [{ id: 1, name: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)', spec1: '规格02', spec2: '规格01', price: '181', quantity: 1, image: '' }] },
-  { orderTime: '2025/12/05 16:15:06', orderNo: '489283929283298393', payAmount: '181', payMethod: '微信支付', auditStatus: 'pending', fileCount: 1, checked: false, products: [{ id: 1, name: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)', spec1: '规格02', spec2: '规格01', price: '181', quantity: 1, image: '' }] },
-  { orderTime: '2025/12/05 16:15:06', orderNo: '489283929283298394', payAmount: '181', payMethod: '微信支付', auditStatus: 'rejected', fileCount: 1, checked: false, products: [{ id: 1, name: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)', spec1: '规格02', spec2: '规格01', price: '181', quantity: 1, image: '' }] },
-  { orderTime: '2025/12/05 16:15:06', orderNo: '489283929283298395', payAmount: '181', payMethod: '微信支付', auditStatus: 'cancelled', fileCount: 1, checked: false, products: [{ id: 1, name: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)', spec1: '规格02', spec2: '规格01', price: '181', quantity: 1, image: '' }] }
-])
+    // 根据状态tab设置checkStatus参数
+    const params: any = {
+      pageNum: pageNum.value,
+      pageSize: pageSize.value
+    }
 
-const orderList = computed(() => {
-  const orders = activeMainTab.value === 'myAudit' ? myAuditOrders.value : myApplyOrders.value
-  if (activeStatusTab.value === 'all') return orders
-  if (activeMainTab.value === 'myAudit' && activeStatusTab.value === 'approved') {
-    return orders.filter(order => order.auditStatus === 'approved' || order.auditStatus === 'rejected')
+    // 根据不同状态设置checkStatus参数
+    if (activeStatusTab.value === 'pending') {
+      params.checkStatus = '0'
+    } else if (activeStatusTab.value === 'approved') {
+      params.checkStatus = '1'
+    } else if (activeStatusTab.value === 'rejected') {
+      params.checkStatus = '2'
+    }
+
+    const res = await getOrderList(params)
+    if (res.code === 200 && res.rows) {
+      allOrders.value = res.rows.map((item: any) => ({
+        id: item.id,
+        orderTime: item.createTime,
+        orderNo: item.orderNo,
+        payAmount: item.payAmount,
+        payMethod: item.payMethod,
+        checkStatus: item.checkStatus,
+        fileCount: 0,
+        checked: false,
+        products: []
+      }))
+      total.value = res.total || 0
+
+      // 获取所有订单的商品信息
+      if (allOrders.value.length > 0) {
+        const orderIds = allOrders.value.map(order => order.id)
+        const productsRes = await getOrderProducts(orderIds)
+        if (productsRes.code === 200 && productsRes.rows) {
+          // 将商品信息按订单ID分组
+          const productsByOrderId = new Map()
+          productsRes.rows.forEach((p: any) => {
+            if (!productsByOrderId.has(p.orderId)) {
+              productsByOrderId.set(p.orderId, [])
+            }
+            productsByOrderId.get(p.orderId).push({
+              image: p.productImage || '',
+              name: p.productName || '',
+              spec1: p.productUnit || '',
+              spec2: p.productNo || '',
+              price: p.orderPrice || 0,
+              quantity: p.orderQuantity || 0
+            })
+          })
+          // 将商品信息赋值给对应的订单
+          allOrders.value.forEach(order => {
+            order.products = productsByOrderId.get(order.id) || []
+          })
+        }
+      }
+    }
+  } catch (error) {
+    console.error('加载订单列表失败:', error)
+    ElMessage.error('加载订单列表失败')
+  } finally {
+    loading.value = false
   }
-  return orders.filter(order => order.auditStatus === activeStatusTab.value)
+}
+
+// 每页条数变化
+const handleSizeChange = () => {
+  pageNum.value = 1
+  loadOrderList()
+}
+
+// 页码变化
+const handlePageChange = () => {
+  loadOrderList()
+}
+
+const orderList = computed(() => {
+  // 所有状态都由后端过滤,前端直接返回数据
+  return allOrders.value
+})
+
+// 使用后端返回的总数
+const displayTotal = computed(() => {
+  return total.value
 })
 
 const handleMainTabChange = () => {
   activeStatusTab.value = 'all'
+  pageNum.value = 1
+  loadOrderList()
+}
+
+// 状态 tab 切换
+const handleStatusTabChange = () => {
+  pageNum.value = 1
+  loadOrderList()
 }
 
-const getStatusText = (status: string) => {
+onMounted(() => {
+  loadOrderList()
+})
+
+const getStatusText = (checkStatus: string) => {
   const map: Record<string, string> = {
-    pending: activeMainTab.value === 'myAudit' ? '待审批' : '审批中',
-    approved: '已完成', rejected: '已完成', cancelled: '已完成'
+    '0': '待审批',
+    '1': '已完成',
+    '2': '已完成'
   }
-  return map[status] || status
+  return map[checkStatus] || checkStatus
 }
 
-const getStatusClass = (status: string) => {
-  if (status === 'approved' || status === 'rejected' || status === 'cancelled') return 'success'
+const getStatusClass = (checkStatus: string) => {
+  if (checkStatus === '1' || checkStatus === '2') return 'success'
   return 'warning'
 }
 
 const handleViewDetail = (order: any) => {
-  router.push(`/trade/orderManage/detail/${order.orderNo}`)
+  router.push(`/trade/orderManage/detail/${order.id}`)
 }
 
 const handleApprove = (order: any) => {
@@ -245,14 +358,21 @@ const handleCancelApply = (order: any) => {
 const handleSubmitAudit = async () => {
   const valid = await auditFormRef.value?.validate()
   if (!valid) return
-  if (currentAuditAction.value === 'approve') {
-    currentAuditOrder.value.auditStatus = 'approved'
-    ElMessage.success('审批通过')
-  } else {
-    currentAuditOrder.value.auditStatus = 'rejected'
-    ElMessage.success('已拒绝')
+
+  try {
+    const checkStatus = currentAuditAction.value === 'approve' ? '1' : '2'
+    await checkOrderStatus({
+      id: currentAuditOrder.value.id,
+      checkStatus: checkStatus
+    })
+
+    ElMessage.success(currentAuditAction.value === 'approve' ? '审批通过' : '已拒绝')
+    auditDialogVisible.value = false
+    loadOrderList()
+  } catch (error) {
+    console.error('审批失败:', error)
+    ElMessage.error('审批失败,请重试')
   }
-  auditDialogVisible.value = false
 }
 </script>
 

+ 101 - 8
src/views/trade/orderManage/detail.vue

@@ -78,11 +78,16 @@
 import { ref, reactive, onMounted } from 'vue'
 import { useRouter, useRoute } from 'vue-router'
 import { ArrowLeft, Document, Search, CircleCheck, Picture } from '@element-plus/icons-vue'
+import { getOrderInfo, getOrderProducts } from '@/api/pc/enterprise/order'
+import { getAddressInfo } from '@/api/pc/enterprise/address'
+import { getInvoiceList } from '@/api/pc/enterprise/invoice'
+import { ElMessage } from 'element-plus'
 
 const router = useRouter()
 const route = useRoute()
-const orderNo = ref('')
+const orderId = ref<number | string>(0)
 const currentStep = ref(1)
+const loading = ref(false)
 
 const progressSteps = ref([
   { title: '提交审核', icon: Document, desc: '采购一部提交订单审核', time: '2025/02/10 15:51:21' },
@@ -90,15 +95,103 @@ const progressSteps = ref([
   { title: '审核完成', icon: CircleCheck, desc: '交易完成', time: '2025/02/10 15:51:21' }
 ])
 
-const productList = ref([
-  { id: 1, name: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)', spec1: '规格01', spec2: '规格02', price: '180.00', quantity: 1, subtotal: '230.00', image: '' },
-  { id: 2, name: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)', spec1: '规格01', spec2: '规格02', price: '180.00', quantity: 1, subtotal: '230.00', image: '' }
-])
+const productList = ref<any[]>([])
+
+const orderInfo = reactive({
+  freight: '0.00',
+  totalAmount: '0.00',
+  address: '',
+  receiverName: '',
+  receiverPhone: '',
+  deliveryTime: '',
+  purchaseReason: '',
+  costType: '',
+  remark: ''
+})
+
+const invoiceInfo = reactive({
+  type: '',
+  title: '',
+  taxNo: '',
+  registerAddress: '',
+  registerPhone: '',
+  bankName: '',
+  bankAccount: ''
+})
+
+// 加载订单详情
+const loadOrderDetail = async () => {
+  try {
+    loading.value = true
+    const res = await getOrderInfo(orderId.value)
+    if (res.code === 200 && res.data) {
+      const order = res.data
+      // 映射订单信息
+      orderInfo.freight = order.shippingFee || '0.00'
+      orderInfo.totalAmount = order.payableAmount || '0.00'
+      orderInfo.deliveryTime = order.expectedDeliveryTime || ''
+      orderInfo.purchaseReason = order.purchaseReason || ''
+      orderInfo.remark = order.remark || ''
+
+      // 获取商品信息
+      const productsRes = await getOrderProducts([orderId.value])
+      if (productsRes.code === 200 && productsRes.rows) {
+        productList.value = productsRes.rows.map((p: any) => ({
+          id: p.id,
+          name: p.productName || '',
+          spec1: p.productUnit || '',
+          spec2: p.productNo || '',
+          price: p.orderPrice || '0.00',
+          quantity: p.orderQuantity || 1,
+          subtotal: (parseFloat(p.orderPrice || '0') * (p.orderQuantity || 1)).toFixed(2),
+          image: p.productImage || ''
+        }))
+      }
+
+      // 获取收货地址信息
+      if (order.shippingAddressId) {
+        const addressRes = await getAddressInfo(order.shippingAddressId)
+        if (addressRes.code === 200 && addressRes.data) {
+          orderInfo.address = addressRes.data.address || ''
+          orderInfo.receiverName = addressRes.data.consignee || ''
+          orderInfo.receiverPhone = addressRes.data.phone || ''
+        }
+      }
 
-const orderInfo = reactive({ freight: '23.00', totalAmount: '0.00', address: '广东省 广州市 萝岗区科学城11号', receiverName: '中国南方电网有限公司', receiverPhone: '18062697722', deliveryTime: '2025/12/12 15:23:22', purchaseReason: '111', costType: '', remark: '' })
-const invoiceInfo = reactive({ type: '', title: '', taxNo: '', registerAddress: '', registerPhone: '', bankName: '', bankAccount: '' })
+      // 获取发票信息
+      const invoiceRes = await getInvoiceList({ pageNum: 1, pageSize: 1 })
+      if (invoiceRes.code === 200 && invoiceRes.rows && invoiceRes.rows.length > 0) {
+        const invoice = invoiceRes.rows[0]
+        invoiceInfo.type = order.invoiceType || ''
+        invoiceInfo.title = order.customerName || ''
+        invoiceInfo.taxNo = invoice.taxId || ''
+        invoiceInfo.registerAddress = invoice.address || ''
+        invoiceInfo.registerPhone = invoice.phone || ''
+        invoiceInfo.bankName = invoice.bankName || ''
+        invoiceInfo.bankAccount = invoice.bankAccount || ''
+      }
+    }
+  } catch (error) {
+    console.error('加载订单详情失败:', error)
+    ElMessage.error('加载订单详情失败')
+  } finally {
+    loading.value = false
+  }
+}
 
-onMounted(() => { orderNo.value = route.params.orderNo as string || '' })
+onMounted(() => {
+  const paramId = route.params.orderNo || route.params.id
+  console.log('路由参数:', route.params)
+  console.log('获取到的参数:', paramId)
+  // 直接使用字符串,不转换为数字,避免精度丢失
+  orderId.value = paramId as string
+  console.log('订单ID:', orderId.value)
+  if (orderId.value) {
+    loadOrderDetail()
+  } else {
+    console.error('订单ID无效,无法加载订单详情')
+  }
+})
 const handleBack = () => { router.push('/trade/orderManage') }
 </script>
 

+ 269 - 19
src/views/trade/orderManage/index.vue

@@ -3,10 +3,12 @@
     <div class="page-title"><i class="title-bar"></i><span>订单管理</span></div>
     <!-- 搜索栏 -->
     <div class="search-bar">
-      <el-input v-model="queryParams.keyword" placeholder="搜索" style="width: 150px" clearable>
+      <el-input v-model="queryParams.keyword" placeholder="搜索订单号" style="width: 200px" clearable @keyup.enter="handleQuery">
         <template #prefix><el-icon><Search /></el-icon></template>
       </el-input>
       <el-date-picker v-model="queryParams.dateRange" type="daterange" range-separator="—" start-placeholder="开始日期" end-placeholder="结束日期" style="width: 240px" />
+      <el-button type="primary" @click="handleQuery">搜索</el-button>
+      <el-button @click="handleReset">重置</el-button>
     </div>
     <!-- 筛选栏 -->
     <div class="filter-bar">
@@ -33,14 +35,14 @@
     </div>
     <!-- 订单列表 -->
     <div class="order-list">
-      <div v-for="(order, orderIndex) in orderList" :key="orderIndex" class="order-card">
+      <div v-for="(order, orderIndex) in orderList" :key="order.id" class="order-card">
         <div class="order-header">
           <el-checkbox v-model="order.checked" @change="handleOrderCheck" />
           <span class="order-time">{{ order.orderTime }}</span>
           <span class="order-info">订单号:{{ order.orderNo }}</span>
           <span class="order-info">下单人:{{ order.orderPerson }}</span>
           <span class="order-info">部门:{{ order.department }}</span>
-          <el-button type="primary" link class="expand-btn" @click="order.expanded = !order.expanded">{{ order.expanded ? '收起' : '展开' }} <el-icon><ArrowDown /></el-icon></el-button>
+          <el-button type="primary" link class="expand-btn" @click="handleExpand(order)">{{ order.expanded ? '收起' : '展开' }} <el-icon><ArrowDown /></el-icon></el-button>
         </div>
         <div v-if="order.countdown" class="countdown-bar">订单锁定剩余时间:{{ order.countdown }}</div>
         <div class="product-list">
@@ -65,7 +67,7 @@
               <el-button v-if="order.fileCount" type="primary" link size="small">审核文件({{ order.fileCount }})</el-button>
             </div>
             <div class="product-cell action-cell" v-if="itemIndex === 0">
-              <el-button v-for="action in getOrderActions(order)" :key="action" type="primary" link size="small">{{ action }}</el-button>
+              <el-button v-for="action in getOrderActions(order)" :key="action" type="primary" link size="small" @click="handleAction(action, order)">{{ action }}</el-button>
             </div>
           </div>
         </div>
@@ -88,15 +90,19 @@
 </template>
 
 <script setup lang="ts">
-import { ref, reactive, computed } from 'vue'
+import { ref, reactive, computed, onMounted, watch } from 'vue'
 import { useRouter } from 'vue-router'
 import { Search, ArrowDown, Delete, Document, Clock, Box, CircleCheck, CircleClose, Picture } from '@element-plus/icons-vue'
 import type { CheckboxValueType } from 'element-plus'
 import { TablePagination } from '@/components'
+import { getOrderList, getOrderStatusStats, getOrderProducts, cancelOrder, deleteOrder } from '@/api/pc/enterprise/order'
+import type { OrderMain, OrderStatusStats } from '@/api/pc/enterprise/orderTypes'
+import { ElMessage, ElMessageBox } from 'element-plus'
 
 const router = useRouter()
 const activeTab = ref('all')
 const selectAll = ref(false)
+const loading = ref(false)
 
 const statusTabs = [
   { key: 'all', label: '全部订单', icon: Document },
@@ -106,18 +112,121 @@ const statusTabs = [
   { key: 'cancelled', label: '已取消', icon: CircleClose }
 ]
 
-const queryParams = reactive({ keyword: '', dateRange: null, department: '', status: '', payType: '', pageNum: 1, pageSize: 10 })
-const total = ref(100)
+// 监听标签页切换,重置页码并重新获取数据
+watch(activeTab, (newTab) => {
+  queryParams.pageNum = 1
+  // 根据标签页设置后端查询的状态参数
+  if (newTab === 'all') {
+    queryParams.status = ''
+  } else {
+    // 将前端标签页key映射回后端状态值
+    const tabToStatusMap: Record<string, string> = {
+      'preOrder': '0,1',      // 待支付,待确认
+      'shipping': '2,3,4',    // 待发货,部分发货,发货完成
+      'completed': '5',       // 已完成
+      'cancelled': '6,7'      // 已关闭,已取消
+    }
+    queryParams.status = tabToStatusMap[newTab] || ''
+  }
+  fetchOrderList()
+})
+
+const queryParams = reactive({ keyword: '', dateRange: null, department: '', status: '', payType: '', pageNum: 1, pageSize: 5 })
+const total = ref(0)
+const allOrders = ref<any[]>([])
+
+// 将后端状态映射为前端标签页key
+const mapBackendStatusToTabKey = (backendStatus: string) => {
+  const statusMap: Record<string, string> = {
+    '0': 'preOrder',      // 待支付
+    '1': 'preOrder',      // 待确认
+    '2': 'shipping',      // 待发货
+    '3': 'shipping',      // 部分发货
+    '4': 'shipping',      // 发货完成
+    '5': 'completed',     // 已完成
+    '6': 'cancelled',     // 已关闭
+    '7': 'cancelled'      // 已取消
+  }
+  return statusMap[backendStatus] || backendStatus
+}
+
+// 根据订单状态获取状态文本
+const getStatusText = (status: string) => {
+  const statusMap: Record<string, string> = {
+    '0': '待支付',
+    '1': '待确认',
+    '2': '待发货',
+    '3': '部分发货',
+    '4': '发货完成',
+    '5': '已完成',
+    '6': '已关闭',
+    '7': '已取消'
+  }
+  return statusMap[status] || status
+}
+
+// 获取订单列表
+const fetchOrderList = async () => {
+  loading.value = true
+  try {
+    const params: any = {
+      pageNum: queryParams.pageNum,
+      pageSize: queryParams.pageSize
+    }
 
-const allOrders = ref([
-  { orderTime: '2025/12/05 16:15:06', orderNo: '489283929283298392', orderPerson: '某某某', department: '某某部门', payAmount: '181', freight: '12', status: 'preOrder', statusText: '待支付', countdown: '13天 0:16:49', auditStatus: '', fileCount: 0, checked: false, expanded: false, products: [{ id: 1, name: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)', spec1: '规格02', spec2: '规格01', price: '181', quantity: 1, image: '' }] },
-  { orderTime: '2025/12/05 16:15:06', orderNo: '489283929283298393', orderPerson: '某某某', department: '某某部门', payAmount: '181', freight: '12', status: 'shipping', statusText: '待确认', countdown: '13天 0:16:49', auditStatus: '待审批', fileCount: 0, checked: false, expanded: false, products: [{ id: 1, name: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)', spec1: '规格02', spec2: '规格01', price: '181', quantity: 1, image: '' }] },
-  { orderTime: '2025/12/05 16:15:06', orderNo: '489283929283298394', orderPerson: '某某某', department: '某某部门', payAmount: '181', freight: '12', status: 'completed', statusText: '已完成', countdown: '', auditStatus: '审批通过', fileCount: 1, checked: false, expanded: false, products: [{ id: 1, name: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)', spec1: '规格02', spec2: '规格01', price: '181', quantity: 1, image: '' }] },
-  { orderTime: '2025/12/05 16:15:06', orderNo: '489283929283298395', orderPerson: '某某某', department: '某某部门', payAmount: '181', freight: '12', status: 'cancelled', statusText: '已取消', countdown: '', auditStatus: '审批驳回', fileCount: 1, checked: false, expanded: false, products: [{ id: 1, name: '清华同方超越E500台式机电脑(i3-6100/4G/1T/19.5寸)', spec1: '规格02', spec2: '规格01', price: '181', quantity: 1, image: '' }] }
-])
+    // 添加筛选条件
+    if (queryParams.keyword) params.orderNo = queryParams.keyword
+    if (queryParams.department) params.department = queryParams.department
+    if (queryParams.status) params.orderStatuses = queryParams.status  // 使用orderStatuses支持多状态查询
+    if (queryParams.payType) params.payType = queryParams.payType
+    if (queryParams.dateRange && queryParams.dateRange.length === 2) {
+      params.beginTime = queryParams.dateRange[0]
+      params.endTime = queryParams.dateRange[1]
+    }
 
-const orderList = computed(() => activeTab.value === 'all' ? allOrders.value : allOrders.value.filter(order => order.status === activeTab.value))
-const totalOrders = computed(() => orderList.value.length)
+    console.log('发送到后端的参数:', params)
+    const res = await getOrderList(params)
+    console.log('后端返回的数据:', res)
+    if (res.code === 200) {
+      // 调试:打印后端返回的第一条订单数据
+      if (res.rows && res.rows.length > 0) {
+        console.log('后端���回的订单状态值:', res.rows[0].orderStatus)
+        console.log('完整的订单数据:', res.rows[0])
+      }
+
+      // 将后端数据转换为前端需要的格式
+      allOrders.value = (res.rows || []).map((order: OrderMain) => ({
+        id: order.id,
+        orderTime: order.createTime,
+        orderNo: order.orderNo,
+        orderPerson: order.userId, // 需要关联用户信息
+        department: order.customerId, // 需要关联部门信息
+        payAmount: order.payableAmount || 0,
+        freight: order.shippingFee || 0,
+        status: mapBackendStatusToTabKey(order.orderStatus || ''),
+        statusText: getStatusText(order.orderStatus || ''),
+        countdown: '',
+        auditStatus: order.checkStatus,
+        fileCount: 0,
+        checked: false,
+        expanded: false,
+        products: [] // 商品信息需要单独加载
+      }))
+
+      // 调试:打印转换后的订单状态
+      console.log('转换后的订单状态分布:', allOrders.value.map(o => o.status))
+
+      total.value = res.total || 0
+    }
+  } catch (error) {
+    console.error('获取订单列表失败:', error)
+  } finally {
+    loading.value = false
+  }
+}
+
+const orderList = computed(() => allOrders.value)
+const totalOrders = computed(() => total.value)
 const selectedCount = computed(() => orderList.value.filter(o => o.checked).length)
 const selectedAmount = computed(() => orderList.value.filter(o => o.checked).reduce((sum, o) => sum + parseFloat(o.payAmount), 0).toFixed(2))
 
@@ -133,19 +242,160 @@ const getOrderActions = (order: any) => {
   }
   return actions
 }
+const handleExpand = async (order: any) => {
+  console.log('handleExpand 被调用, order.id:', order.id, 'order.expanded:', order.expanded)
+
+  const orderIndex = allOrders.value.findIndex(o => o.id === order.id)
+  if (orderIndex === -1) return
+
+  const currentOrder = allOrders.value[orderIndex]
+  console.log('找到订单, currentOrder.expanded:', currentOrder.expanded)
+
+  if (!currentOrder.expanded && currentOrder.products.length === 0) {
+    console.log('需要加载商品')
+    try {
+      const res = await getOrderProducts([order.id])
+      if (res.code === 200 && res.rows) {
+        console.log('后端返回的商品数据:', res.rows)
+        const products = res.rows.map((p: any) => ({
+          image: p.productImage || '',
+          name: p.productName || '',
+          spec1: p.productUnit || '',
+          spec2: p.productNo || '',
+          price: p.orderPrice || 0,
+          quantity: p.orderQuantity || 0
+        }))
+        console.log('商品加载完成, products.length:', products.length)
+
+        // 替换整个数组以触发响应式更新
+        allOrders.value = allOrders.value.map((o, i) =>
+          i === orderIndex ? { ...o, expanded: true, products } : o
+        )
+        console.log('已更新数组,expanded 设置为 true')
+        return
+      }
+    } catch (error) {
+      console.error('加载商品失败:', error)
+      return
+    }
+  }
+
+  console.log('切换 expanded 状态, 从', currentOrder.expanded, '到', !currentOrder.expanded)
+  // 替换整个数组以触发响应式更新
+  allOrders.value = allOrders.value.map((o, i) =>
+    i === orderIndex ? { ...o, expanded: !o.expanded } : o
+  )
+  console.log('已更新数组,expanded 已切换')
+}
 const handleSelectAll = (val: CheckboxValueType) => { orderList.value.forEach(order => { order.checked = !!val }) }
 const handleOrderCheck = () => { selectAll.value = orderList.value.every(order => order.checked) }
 const handleViewDetail = (order: any) => { router.push(`/trade/orderManage/detail/${order.orderNo}`) }
-const handleQuery = () => {}
+const handleQuery = () => {
+  queryParams.pageNum = 1
+  fetchOrderList()
+}
+const handleReset = () => {
+  queryParams.keyword = ''
+  queryParams.dateRange = null
+  queryParams.department = ''
+  queryParams.payType = ''
+  queryParams.pageNum = 1
+  fetchOrderList()
+}
+const handleAction = (action: string, order: any) => {
+  switch (action) {
+    case '取消订单':
+      handleCancelOrder(order)
+      break
+    case '删除订单':
+      handleDeleteOrder(order)
+      break
+    case '查看详情':
+      handleViewDetail(order)
+      break
+    default:
+      ElMessage.info(`${action}功能开发中`)
+  }
+}
+const handleCancelOrder = async (order: any) => {
+  try {
+    await ElMessageBox.confirm('确定要取消该订单吗?', '提示', {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning'
+    })
+    const res = await cancelOrder({ id: order.id, orderStatus: '7' })
+    if (res.code === 200) {
+      ElMessage.success('订单已取消')
+      fetchOrderList()
+    } else {
+      ElMessage.error(res.msg || '取消订单失败')
+    }
+  } catch (error: any) {
+    if (error !== 'cancel') {
+      ElMessage.error('取消订单失败')
+    }
+  }
+}
+const handleDeleteOrder = async (order: any) => {
+  try {
+    await ElMessageBox.confirm('确定要删除该订单吗?删除后无法恢复。', '提示', {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning'
+    })
+    const res = await deleteOrder([order.id])
+    if (res.code === 200) {
+      ElMessage.success('订单已删除')
+      fetchOrderList()
+    } else {
+      ElMessage.error(res.msg || '删除订单失败')
+    }
+  } catch (error: any) {
+    if (error !== 'cancel') {
+      ElMessage.error('删除订单失败')
+    }
+  }
+}
+
+// 页面加载时获取订单列表
+onMounted(() => {
+  fetchOrderList()
+})
 </script>
 
 <style scoped lang="scss">
-.order-manage-container { padding: 20px; background: #fff; min-height: 100%; }
+.order-manage-container {
+  padding: 20px;
+  background: #fff;
+  min-height: 100%;
+  display: flex;
+  flex-direction: column;
+  max-height: calc(100vh - 120px); // 减去顶部导航栏和其他元素高度
+}
 .page-title { font-size: 16px; font-weight: bold; display: flex; align-items: center; gap: 8px; margin-bottom: 20px; }
 .title-bar { display: inline-block; width: 3px; height: 16px; background: #e60012; border-radius: 2px; }
 .search-bar { display: flex; align-items: center; gap: 15px; margin-bottom: 15px; }
 .filter-bar { display: flex; align-items: center; gap: 10px; margin-bottom: 15px; .filter-label { font-size: 14px; color: #666; } .filter-right { flex: 1; display: flex; justify-content: flex-end; gap: 10px; } }
 .tab-bar { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #eee; margin-bottom: 15px; .tab-left { display: flex; gap: 25px; } .tab-item { display: flex; align-items: center; gap: 5px; padding: 12px 0; cursor: pointer; color: #666; font-size: 14px; border-bottom: 2px solid transparent; margin-bottom: -1px; &:hover, &.active { color: #333; } &.active { border-bottom-color: #e60012; } } }
-.order-list { .order-card { border: 1px solid #eee; border-radius: 4px; margin-bottom: 15px; overflow: hidden; .order-header { display: flex; align-items: center; gap: 15px; padding: 12px 15px; background: #f9f9f9; border-bottom: 1px solid #eee; font-size: 13px; color: #666; .order-time { color: #333; } .expand-btn { margin-left: auto; } } .countdown-bar { background: #fff5e6; color: #e6a23c; padding: 8px 15px; font-size: 13px; border-bottom: 1px solid #eee; } .product-list { .product-row { display: flex; border-bottom: 1px solid #f5f5f5; &:last-child { border-bottom: none; } } .product-cell { padding: 15px; display: flex; flex-direction: column; justify-content: center; } .product-info-cell { flex: 1; flex-direction: row; align-items: center; gap: 15px; .product-image { width: 80px; height: 80px; background: #f5f5f5; border-radius: 4px; overflow: hidden; flex-shrink: 0; .el-image { width: 100%; height: 100%; } .image-placeholder { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; } } .product-detail { flex: 1; .product-name { font-size: 14px; color: #333; margin-bottom: 5px; line-height: 1.4; } .product-spec { font-size: 12px; color: #999; margin-bottom: 5px; } .product-price { font-size: 16px; font-weight: bold; color: #e60012; } } .product-quantity { font-size: 13px; color: #666; } } .amount-cell { width: 120px; border-left: 1px solid #f5f5f5; .amount-info { margin-bottom: 5px; .label { font-size: 12px; color: #999; } .value { font-size: 14px; color: #333; &.highlight { font-size: 16px; font-weight: bold; color: #e60012; } } } } .status-cell { width: 120px; border-left: 1px solid #f5f5f5; align-items: flex-start; gap: 5px; .status-text { font-size: 14px; font-weight: 500; } .audit-status { font-size: 12px; &.success { color: #e60012; } &.warning { color: #e6a23c; } &.danger { color: #e60012; } } } .action-cell { width: 100px; border-left: 1px solid #f5f5f5; align-items: flex-start; gap: 3px; } } } }
-.bottom-bar { background: #fafafa; border: 1px solid #eee; border-radius: 4px; padding: 15px 20px; margin-top: 15px; display: flex; justify-content: space-between; align-items: center; .bottom-right { display: flex; align-items: center; gap: 15px; .selected-info { font-size: 14px; color: #666; em { color: #e60012; font-style: normal; font-weight: bold; } } } }
+.order-list {
+  flex: 1;
+  overflow-y: auto;
+  margin-bottom: 15px;
+  .order-card { border: 1px solid #eee; border-radius: 4px; margin-bottom: 15px; overflow: hidden; .order-header { display: flex; align-items: center; gap: 15px; padding: 12px 15px; background: #f9f9f9; border-bottom: 1px solid #eee; font-size: 13px; color: #666; .order-time { color: #333; } .expand-btn { margin-left: auto; } } .countdown-bar { background: #fff5e6; color: #e6a23c; padding: 8px 15px; font-size: 13px; border-bottom: 1px solid #eee; } .product-list { .product-row { display: flex; border-bottom: 1px solid #f5f5f5; &:last-child { border-bottom: none; } } .product-cell { padding: 15px; display: flex; flex-direction: column; justify-content: center; } .product-info-cell { flex: 1; flex-direction: row; align-items: center; gap: 15px; .product-image { width: 80px; height: 80px; background: #f5f5f5; border-radius: 4px; overflow: hidden; flex-shrink: 0; .el-image { width: 100%; height: 100%; } .image-placeholder { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; } } .product-detail { flex: 1; .product-name { font-size: 14px; color: #333; margin-bottom: 5px; line-height: 1.4; } .product-spec { font-size: 12px; color: #999; margin-bottom: 5px; } .product-price { font-size: 16px; font-weight: bold; color: #e60012; } } .product-quantity { font-size: 13px; color: #666; } } .amount-cell { width: 120px; border-left: 1px solid #f5f5f5; .amount-info { margin-bottom: 5px; .label { font-size: 12px; color: #999; } .value { font-size: 14px; color: #333; &.highlight { font-size: 16px; font-weight: bold; color: #e60012; } } } } .status-cell { width: 120px; border-left: 1px solid #f5f5f5; align-items: flex-start; gap: 5px; .status-text { font-size: 14px; font-weight: 500; } .audit-status { font-size: 12px; &.success { color: #e60012; } &.warning { color: #e6a23c; } &.danger { color: #e60012; } } } .action-cell { width: 100px; border-left: 1px solid #f5f5f5; align-items: flex-start; gap: 3px; } } } }
+.bottom-bar {
+  background: #fafafa;
+  border: 1px solid #eee;
+  border-radius: 4px;
+  padding: 15px 20px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  flex-shrink: 0;
+  .bottom-right { display: flex; align-items: center; gap: 15px; .selected-info { font-size: 14px; color: #666; em { color: #e60012; font-style: normal; font-weight: bold; } } }
+}
+:deep(.table-pagination) {
+  flex-shrink: 0;
+  margin-top: 15px;
+}
 </style>

+ 325 - 0
yoe-shop-web接口文档.md

@@ -0,0 +1,325 @@
+# yoe-shop-web 企业工作台接口文档
+
+## 项目概述
+
+## 张林的交接文档。
+## 有一个问题:你记得我们写的pc接口的gateway可能会和之前的后台管理系统有冲突导致404,你得去gateway.yml文件里专门配置一下。
+
+
+## 技术栈
+
+- Vue 3.5.22
+- TypeScript 5.9.3
+- Element Plus 2.11.7
+- Vite 6.4.1
+- Axios 1.13.1
+
+## API 文件结构
+
+```
+src/api/pc/
+├── enterprise/          # 企业相关接口
+│   ├── index.ts        # 企业信息、地址、发票
+│   ├── order.ts        # 订单管理
+│   ├── orderReturn.ts  # 售后服务
+│   ├── statement.ts    # 对账单管理
+│   └── invoice.ts      # 发票信息
+├── organization/        # 组织管理接口
+│   └── index.ts        # 部门、人员、角色
+└── system/             # 系统接口
+    ├── dict.ts         # 字典数据
+    └── announcement.ts # 平台公告
+```
+
+---
+
+## 一、企业账户模块
+
+### 1.1 企业信息页面
+
+**页面路径**: `src/views/enterprise/companyInfo/index.vue`
+
+**API 文件**: `src/api/pc/enterprise/index.ts`
+
+**接口列表**:
+
+| 接口路径 | 方法 | 功能 | 函数名 |
+|---------|------|------|--------|
+| `/pc/enterprise/info` | GET | 查询企业信息 | `getEnterpriseInfo()` |
+| `/pc/enterprise/info` | PUT | 修改企业信息 | `updateEnterpriseInfo(data)` |
+
+### 1.2 收货地址管理
+
+**页面路径**: `src/views/enterprise/addressManage/index.vue`
+
+**API 文件**: `src/api/pc/enterprise/index.ts`
+
+**接口列表**:
+
+| 接口路径 | 方法 | 功能 | 函数名 |
+|---------|------|------|--------|
+| `/pc/enterprise/address/list` | GET | 查询收货地址列表 | `getAddressList(params)` |
+| `/pc/enterprise/address/{id}` | GET | 查询收货地址详情 | `getAddressInfo(id)` |
+| `/pc/enterprise/address` | POST | 新增收货地址 | `addAddress(data)` |
+| `/pc/enterprise/address` | PUT | 修改收货地址 | `updateAddress(data)` |
+| `/pc/enterprise/address/{ids}` | DELETE | 删除收货地址 | `deleteAddress(ids)` |
+| `/pc/enterprise/address/default` | PUT | 设置默认地址 | `setDefaultAddress(id)` |
+
+### 1.3 发票信息管理
+
+**页面路径**: `src/views/enterprise/invoiceManage/index.vue`
+
+**API 文件**: `src/api/pc/enterprise/index.ts`
+
+**接口列表**:
+
+| 接口路径 | 方法 | 功能 | 函数名 |
+|---------|------|------|--------|
+| `/pc/enterprise/invoice/list` | GET | 查询发票信息列表 | `getInvoiceList(params)` |
+| `/pc/enterprise/invoice/{id}` | GET | 查询发票详情 | `getInvoiceInfo(id)` |
+| `/pc/enterprise/invoice` | POST | 新增发票 | `addInvoice(data)` |
+| `/pc/enterprise/invoice` | PUT | 修改发票 | `updateInvoice(data)` |
+| `/pc/enterprise/invoice/{ids}` | DELETE | 删除发票 | `deleteInvoice(ids)` |
+
+### 1.4 专属服务人员
+
+**API 文件**: `src/api/pc/enterprise/servicePerson.ts`
+
+**接口列表**:
+
+| 接口路径 | 方法 | 功能 | 函数名 |
+|---------|------|------|--------|
+| `/pc/enterprise/servicePerson/list` | GET | 查询专属服务人员 | `getServicePersons()` |
+
+---
+
+## 二、交易管理模块
+
+### 2.1 订单管理
+
+**页面路径**: `src/views/trade/orderManage/index.vue`
+
+**API 文件**: `src/api/pc/enterprise/order.ts`
+
+**接口列表**:
+
+| 接口路径 | 方法 | 功能 | 函数名 |
+|---------|------|------|--------|
+| `/pc/enterprise/order/list` | GET | 查询订单列表 | `getOrderList(params)` |
+| `/pc/enterprise/order/statusStats` | GET | 查询订单状态统计 | `getOrderStatusStats()` |
+| `/pc/enterprise/order/{id}` | GET | 查询订单详情 | `getOrderInfo(id)` |
+| `/pc/enterprise/order/products` | GET | 查询订单商品明细 | `getOrderProducts(orderIds)` |
+| `/pc/enterprise/order/cancel` | PUT | 取消订单 | `cancelOrder(data)` |
+| `/pc/enterprise/order/checkStatus` | PUT | 审核订单 | `checkOrderStatus(data)` |
+| `/pc/enterprise/order/{ids}` | DELETE | 删除订单 | `deleteOrder(ids)` |
+
+### 2.2 售后服务
+
+**页面路径**: `src/views/trade/afterSale/index.vue`
+
+**API 文件**: `src/api/pc/enterprise/orderReturn.ts`
+
+**接口列表**:
+
+| 接口路径 | 方法 | 功能 | 函数名 |
+|---------|------|------|--------|
+| `/pc/enterprise/orderReturn/list` | GET | 查询售后申请列表 | `getOrderReturnList(params)` |
+| `/pc/enterprise/orderReturn/{id}` | GET | 查询售后详情 | `getOrderReturnInfo(id)` |
+| `/pc/enterprise/orderReturn` | POST | 新增售后申请 | `addOrderReturn(data)` |
+| `/pc/enterprise/orderReturn` | PUT | 修改售后申请 | `updateOrderReturn(data)` |
+| `/pc/enterprise/orderReturn/{ids}` | DELETE | 删除售后申请 | `deleteOrderReturn(ids)` |
+
+---
+
+## 三、组织管理模块
+
+### 3.1 部门管理
+
+**页面路径**: `src/views/organization/deptManage/index.vue`
+
+**API 文件**: `src/api/pc/organization/index.ts`
+
+**接口列表**:
+
+| 接口路径 | 方法 | 功能 | 函数名 |
+|---------|------|------|--------|
+| `/pc/organization/dept/tree` | GET | 查询部门树 | `getDeptTree()` |
+| `/pc/organization/dept/list` | GET | 查询部门列表 | `getDeptList(params)` |
+| `/pc/organization/dept/{id}` | GET | 查询部门详情 | `getDeptInfo(id)` |
+| `/pc/organization/dept` | POST | 新增部门 | `addDept(data)` |
+| `/pc/organization/dept` | PUT | 修改部门 | `updateDept(data)` |
+| `/pc/organization/dept/{ids}` | DELETE | 删除部门 | `deleteDept(ids)` |
+
+### 3.2 人员管理
+
+**页面路径**: `src/views/organization/staffManage/index.vue`
+
+**API 文件**: `src/api/pc/organization/index.ts`
+
+**接口列表**:
+
+| 接口路径 | 方法 | 功能 | 函数名 |
+|---------|------|------|--------|
+| `/pc/organization/contact/current` | GET | 获取当前用户信息 | `getCurrentUserInfo()` |
+| `/pc/organization/contact/list` | GET | 查询联系人列表 | `getContactList(params)` |
+| `/pc/organization/contact/{id}` | GET | 查询联系人详情 | `getContactInfo(id)` |
+| `/pc/organization/contact` | POST | 新增联系人 | `addContact(data)` |
+| `/pc/organization/contact` | PUT | 修改联系人 | `updateContact(data)` |
+| `/pc/organization/contact/{ids}` | DELETE | 删除联系人 | `deleteContact(ids)` |
+
+### 3.3 角色管理
+
+**页面路径**: `src/views/organization/roleManage/index.vue`
+
+**API 文件**: `src/api/pc/organization/index.ts`
+
+**接口列表**:
+
+| 接口路径 | 方法 | 功能 | 函数名 |
+|---------|------|------|--------|
+| `/pc/organization/role/list` | GET | 查询角色列表 | `getRoleList(params)` |
+| `/pc/organization/role/{id}` | GET | 查询角色详情 | `getRoleInfo(id)` |
+| `/pc/organization/role` | POST | 新增角色 | `addRole(data)` |
+| `/pc/organization/role` | PUT | 修改角色 | `updateRole(data)` |
+| `/pc/organization/role/{ids}` | DELETE | 删除角色 | `deleteRole(ids)` |
+
+---
+
+## 四、对账管理模块
+
+### 4.1 对账单管理
+
+**页面路径**: `src/views/reconciliation/billManage/index.vue`
+
+**API 文件**: `src/api/pc/enterprise/statement.ts`
+
+**接口列表**:
+
+| 接口路径 | 方法 | 功能 | 函数名 |
+|---------|------|------|--------|
+| `/pc/enterprise/statement/list` | GET | 查询对账单列表 | `getStatementList(params)` |
+| `/pc/enterprise/statement/{id}` | GET | 查询对账单详情 | `getStatementInfo(id)` |
+| `/pc/enterprise/statement/details` | GET | 查询对账单明细列表 | `getStatementDetails(params)` |
+| `/pc/enterprise/statement/confirm` | PUT | 确认对账单 | `confirmStatement(data)` |
+| `/pc/enterprise/statement/reject` | PUT | 驳回对账单 | `rejectStatement(data)` |
+| `/pc/enterprise/statementDetail/list` | GET | 查询对账单明细 | `getStatementDetailList(params)` |
+| `/pc/enterprise/statementProduct/list` | GET | 查询对账单商品列表 | `getStatementProductList(params)` |
+| `/pc/enterprise/statementInvoice/list` | GET | 查询对账单发票列表 | `getStatementInvoiceList(params)` |
+
+**对账状态说明**:
+
+| 状态值 | 状态名称 | 说明 |
+|-------|---------|------|
+| 0 | 待确认 | 后台生成对账单,等待企业确认 |
+| 1 | 待对账 | 企业可以点击确认按钮 |
+| 2 | 已对账 | 对账完成,按钮禁用 |
+| 3 | 驳回 | 对账被驳回 |
+| 4 | 作废 | 对账单作废 |
+
+### 4.2 开票管理
+
+**页面路径**: `src/views/reconciliation/invoiceManage/index.vue`
+
+**API 文件**: `src/api/pc/enterprise/statement.ts`
+
+**接口列表**: 同对账单管理接口
+
+---
+
+## 五、系统功能模块
+
+### 5.1 字典数据
+
+**API 文件**: `src/api/pc/system/dict.ts`
+
+**接口列表**:
+
+| 接口路径 | 方法 | 功能 | 函数名 |
+|---------|------|------|--------|
+| `/pc/dict/type/{dictType}` | GET | 根据字典类型查询字典数据 | `getDictByType(dictType)` |
+
+**常用字典类型**:
+- `statement_status` - 对账状态
+- `invoice_issuance_status` - 开票状态
+- `payment_status` - 支付状态
+
+### 5.2 平台公告
+
+**API 文件**: `src/api/pc/system/announcement.ts`
+
+**接口列表**:
+
+| 接口路径 | 方法 | 功能 | 函数名 |
+|---------|------|------|--------|
+| `/pc/announcement/list` | GET | 查询平台公告列表 | `getAnnouncementList(params)` |
+| `/pc/announcement/{id}` | GET | 查询平台公告详情 | `getAnnouncementInfo(id)` |
+
+---
+
+## 六、后端控制器说明
+
+### 6.1 对账单控制器
+
+**后端文件**: `yoe-core/ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/pc/controller/PcStatementOrderController.java`
+
+**权限控制**:
+- PC 端用户只能查询自己企业的对账单
+- 只允许查询状态为 1(待对账)、2(已对账)、3(驳回) 的对账单
+- 不允许查询状态为 0(待确认)、4(作废) 的对账单
+
+**核心方法**:
+- `list()` - 查询对账单列表(带权限过滤)
+- `getInfo()` - 查询对账单详情(验证企业权限)
+- `confirm()` - 确认对账单(将状态从 1 改为 2)
+- `reject()` - 驳回对账单(将状态改为 3)
+
+---
+
+## 七、开发环境配置
+
+### 7.1 环境变量
+
+**开发环境** (`.env.development`):
+```
+VITE_APP_BASE_API=/dev-api
+VITE_APP_CONTEXT_PATH=/
+```
+
+**代理配置** (`vite.config.ts`):
+```typescript
+proxy: {
+  '/dev-api': {
+    target: 'http://localhost:8080',
+    changeOrigin: true,
+    rewrite: (path) => path.replace(/^\/dev-api/, '')
+  }
+}
+```
+
+### 7.2 启动命令
+
+```bash
+# 安装依赖
+npm install
+
+# 启动开发服务器
+npm run dev
+
+# 构建生产版本
+npm run build:prod
+```
+
+---
+
+## 八、注意事项
+
+1. **接口前缀**: 所有 PC 端接口都以 `/pc` 开头
+2. **权限控制**: 后端会根据登录用户的企业 ID 自动过滤数据
+3. **状态管理**: 对账状态、开票状态、支付状态都通过字典管理
+4. **错误处理**: 统一使用 Element Plus 的 `ElMessage` 显示错误信息
+5. **数据刷新**: 操作成功后会自动刷新列表数据
+
+---
+
+## 九、常见问题
+