Răsfoiți Sursa

feat: 转账功能

husenlin 1 lună în urmă
părinte
comite
362beb25a2

+ 16 - 7
backend/app/plugin/module_payment/account/controller.py

@@ -66,18 +66,19 @@ async def create_account_controller(
 
 
 @AccountRouter.get(
-    "/{enterprise_id}",
+    "/query/{enterprise_id}",
     summary="查询资金专户",
     description="根据企业ID查询资金专户(调用支付宝接口)",
     response_model=ResponseSchema[list[Any]],
 )
 async def query_account_controller(
-    data: AccountQuerySchema,
+    # data: AccountQuerySchema,
+    enterprise_id: Annotated[str, Path(description="企业ID")],
     auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:account:detail"]))],
 ) -> JSONResponse:
     """查询资金专户"""
-    result = await AccountService.query_account_service(auth=auth, data=data)
-    log.info(f"查询资金专户成功: {data.enterprise_id}")
+    result = await AccountService.query_account_service(auth=auth, data=AccountQuerySchema(enterprise_id=enterprise_id))
+    log.info(f"查询资金专户成功: {enterprise_id}")
     return SuccessResponse(data=result, msg="查询资金专户成功")
 
 
@@ -153,12 +154,20 @@ async def transfer_detail_controller(
 )
 async def transfer_list_controller(
     auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:account:transfer:list"]))],
-    page: Annotated[PaginationQueryParam, Depends()],
-    search: Annotated[Dict, Depends()],
+    page_no: Annotated[int, Query(description="页码")] = 1,
+    page_size: Annotated[int, Query(description="每页数量")] = 20,
+    out_biz_no: Annotated[str | None, Query(description="订单号")] = None,
+    status: Annotated[str | None, Query(description="状态")] = None,
 ) -> JSONResponse:
     """查询转账记录列表"""
+    search = {}
+    if out_biz_no:
+        search["out_biz_no"] = out_biz_no
+    if status:
+        search["status"] = status
+    
     result = await AccountService.transfer_list_service(
-        auth=auth, page_no=page.page_no, page_size=page.page_size, order_by=page.order_by, search=search
+        auth=auth, page_no=page_no, page_size=page_size, search=search
     )
     return SuccessResponse(data=result, msg="查询转账记录列表成功")
 

+ 1 - 0
backend/app/plugin/module_payment/account/schema.py

@@ -287,6 +287,7 @@ class TransferListOutSchema(BaseModel):
     status: str = Field(description="转账状态")
     order_no: Optional[str] = Field(default=None, description="支付宝转账单号")
     fund_order_id: Optional[str] = Field(default=None, description="宝支付资金流水号")
+    payee_info: Optional[dict] = Field(default=None, description="收款方信息")
     created_time: datetime = Field(description="创建时间")
 
 

+ 11 - 3
backend/app/plugin/module_payment/account/service.py

@@ -378,6 +378,9 @@ class AccountService:
         from alipay.aop.api.response.AlipayCommerceEcTransAccountQueryResponse import (
             AlipayCommerceEcTransAccountQueryResponse,
         )
+        from alipay.aop.api.domain.FundAccountApiDTO import (
+            FundAccountApiDTO,
+        )
 
         model = AlipayCommerceEcTransAccountQueryModel()
         model.enterprise_id = data.enterprise_id
@@ -398,7 +401,12 @@ class AccountService:
             log.error(f"支付宝接口调用失败: {result.code} - {result.msg}")
             raise CustomException(msg=f"查询资金专户失败: {result.msg}")
 
-        return result.account_list or []
+        collect = []
+        for v in list(result.account_list or []):
+            account = FundAccountApiDTO.to_alipay_dict(v)
+            collect.append(account)
+        
+        return collect
 
     @classmethod
     async def transfer_detail_service(
@@ -423,18 +431,18 @@ class AccountService:
         auth: AuthSchema,
         page_no: int = 1,
         page_size: int = 20,
-        order_by: list[dict[str, str]] | None = None,
         search: dict | None = None,
     ) -> dict:
         """
         查询转账记录列表
         """
+        log.info(f"查询转账记录列表: {page_no}, {page_size}, {search}")
         crud = TransferCRUD(auth)
         offset = (page_no - 1) * page_size
         return await crud.page(
             offset=offset,
             limit=page_size,
-            order_by=order_by or [{"id": "desc"}],
+            order_by=[{"id": "desc"}],
             search=search or {},
             out_schema=TransferListOutSchema,
         )

+ 2 - 5
backend/app/plugin/module_payment/department/model.py

@@ -1,8 +1,8 @@
 from datetime import datetime
 from typing import List, Optional
 
-from sqlalchemy import Column, String, Integer, ForeignKey, DateTime, JSON
-from sqlalchemy.orm import Mapped, mapped_column, relationship
+from sqlalchemy import Column, String, Integer, DateTime
+from sqlalchemy.orm import Mapped, mapped_column
 
 from app.common.enums import PermissionFilterStrategy
 from app.core.base_model import EnterpriseMixin, PaymentModelMixin, TenantMixin
@@ -27,8 +27,5 @@ class DepartmentModel(PaymentModelMixin, TenantMixin, EnterpriseMixin):
     created_time: Mapped[datetime] = mapped_column(DateTime, default=datetime.now, comment="创建时间")
     updated_time: Mapped[datetime] = mapped_column(DateTime, default=datetime.now, onupdate=datetime.now, comment="更新时间")
 
-    # 关联关系
-    parent_department = relationship("DepartmentModel", remote_side=[department_id], backref="sub_departments", primaryjoin="DepartmentModel.parent_department_id == DepartmentModel.department_id")
-
     def __repr__(self):
         return f"<DepartmentModel(department_id={self.department_id}, department_name={self.department_name})>"

+ 10 - 5
backend/app/plugin/module_payment/employee/controller.py

@@ -9,13 +9,10 @@ from app.core.dependencies import AuthPermission, get_current_user
 from app.core.logger import log
 from app.core.router_class import OperationLogRoute
 
-from alipay.aop.api.domain.EmployeeInfoDTO import EmployeeInfoDTO
-
 from .schema import (
     EmployeeCreateOrUpdateSchema,
     EmployeeListOutSchema,
     EmployeeOperationOutSchema,
-    EmployeeOutSchema,
     EmployeeInviteQuerySchema,
     EmployeeInviteQueryOutSchema,
 )
@@ -41,7 +38,13 @@ async def info_employee_controller(
     employee_mobile: Annotated[Optional[str], Query(description="员工手机号")] = None,
 ) -> JSONResponse:
     """查询员工详情"""
-    result = await EmployeeService.info_service(auth=auth, employee_id=employee_id, employee_email=employee_email, employee_mobile=employee_mobile, enterprise_id=enterprise_id)
+    result = await EmployeeService.info_service(
+        auth=auth, 
+        employee_id=employee_id, 
+        employee_email=employee_email, 
+        employee_mobile=employee_mobile, 
+        enterprise_id=enterprise_id
+    )
     return SuccessResponse(data=result, msg="查询员工详情成功")
 
 
@@ -123,7 +126,9 @@ async def delete_employee_controller(
     auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:employee:delete"]))],
 ) -> JSONResponse:
     """删除员工"""
-    result = await EmployeeService.delete_employee_service(auth=auth, employee_id=employee_id, enterprise_id=enterprise_id)
+    result = await EmployeeService.delete_employee_service(
+        auth=auth, employee_id=employee_id, enterprise_id=enterprise_id
+    )
     log.info(f"删除员工成功: {employee_id}, enterprise_id={enterprise_id}")
     return SuccessResponse(data=result, msg="删除员工成功")
 

+ 1 - 1
backend/app/plugin/module_payment/employee/crud.py

@@ -5,7 +5,7 @@ from app.core.base_crud import CRUDBase
 from app.core.exceptions import CustomException
 
 from .model import EmployeeModel
-from .schema import EmployeeCreateOrUpdateSchema, EmployeeOutSchema
+from .schema import EmployeeCreateOrUpdateSchema
 
 
 class EmployeeCRUD(CRUDBase[EmployeeModel, EmployeeCreateOrUpdateSchema, EmployeeCreateOrUpdateSchema]):

+ 1 - 1
backend/app/plugin/module_payment/employee/schema.py

@@ -1,7 +1,7 @@
 from datetime import datetime
 from typing import Optional
 
-from pydantic import BaseModel, ConfigDict, Field, model_validator
+from pydantic import BaseModel, ConfigDict, Field
 
 
 class EmployeeCreateOrUpdateSchema(BaseModel):

+ 151 - 0
frontend/src/api/module_payment/account.ts

@@ -0,0 +1,151 @@
+import request from "@/utils/request";
+
+const API_PATH = "/payment/account";
+
+export const AccountAPI = {
+  authorizeApply(data: { enterprise_id: string }) {
+    return request<ApiResponse<{ sign_url: string }>>({
+      url: `${API_PATH}/authorize/apply`,
+      method: "post",
+      data,
+    });
+  },
+
+  create(data: {
+    enterprise_id: string;
+    account_type?: string;
+    scene?: string;
+    account_book_id?: string;
+    remark?: string;
+  }) {
+    return request<ApiResponse<{ enterprise_id: string; account_book_id: string }>>({
+      url: `${API_PATH}`,
+      method: "post",
+      data,
+    });
+  },
+
+  query(enterpriseId: string) {
+    return request<ApiResponse<any[]>>({
+      url: `${API_PATH}/query/${enterpriseId}`,
+      method: "get",
+    });
+  },
+
+  deposit(data: {
+    enterprise_id: string;
+    account_book_id: string;
+    amount: number;
+    out_biz_no?: string;
+    remark?: string;
+  }) {
+    return request<ApiResponse<{ url: string }>>({
+      url: `${API_PATH}/deposit`,
+      method: "post",
+      data,
+    });
+  },
+
+  transfer(data: {
+    enterprise_id: string;
+    account_book_id?: string;
+    out_biz_no?: string;
+    amount: number;
+    order_title?: string;
+    remark?: string;
+    payee_info: {
+      identity_type: string;
+      name: string;
+      identity: string;
+      bankcard_ext_info?: {
+        account_type: string;
+        inst_name?: string;
+        inst_province?: string;
+        inst_city?: string;
+        inst_branch_name?: string;
+        bank_code?: string;
+      };
+    };
+    employee_id?: string;
+    priority?: string;
+    ext_info?: Record<string, any>;
+  }) {
+    return request<ApiResponse<{ status: string; order_no?: string; fund_order_id?: string }>>({
+      url: `${API_PATH}/transfer`,
+      method: "post",
+      data,
+    });
+  },
+
+  transferDetail(outBizNo: string) {
+    return request<ApiResponse<TransferOutSchema>>({
+      url: `${API_PATH}/transfer/${outBizNo}`,
+      method: "get",
+    });
+  },
+
+  transferList(params: {
+    page_no?: number;
+    page_size?: number;
+    out_biz_no?: string;
+    status?: string;
+  }) {
+    return request<ApiResponse<TransferListResp>>({
+      url: `${API_PATH}/transfer`,
+      method: "get",
+      params,
+    });
+  },
+
+  consumeDetail(params: {
+    pay_no: string;
+    enterprise_id?: string;
+    ant_shop_id?: string;
+    query_options?: string[];
+  }) {
+    return request<ApiResponse<any>>({
+      url: `${API_PATH}/consume-detail`,
+      method: "get",
+      params,
+    });
+  },
+};
+
+export interface TransferOutSchema {
+  out_biz_no?: string;
+  enterprise_id?: string;
+  account_book_id?: string;
+  amount?: string;
+  order_title?: string;
+  payee_info?: {
+    identity_type: string;
+    name: string;
+    identity: string;
+    bankcard_ext_info?: any;
+  };
+  status?: string;
+  order_no?: string;
+  fund_order_id?: string;
+  created_time?: string;
+  updated_time?: string;
+}
+
+export interface TransferListResp {
+  total: number;
+  items: TransferOutSchema[];
+}
+
+export interface ConsumeDetailSchema {
+  pay_no?: string;
+  enterprise_id?: string;
+  amount?: string;
+  status?: string;
+  created_time?: string;
+  pay_type?: string;
+  payee_info?: any;
+  refund_info?: any;
+  order_info?: any;
+  ticket_info?: any;
+}
+
+export default AccountAPI;

+ 2 - 2
frontend/src/layouts/components/NavBar/components/EnterpriseSwitcher.vue

@@ -14,11 +14,11 @@
             v-for="ent in enterpriseList"
             :key="ent.enterprise_id"
             :command="ent.enterprise_id"
-            :class="{ 'is-active': ent.enterprise_id === currentEnterprise.value?.enterprise_id }"
+            :class="{ 'is-active': ent.enterprise_id === currentEnterprise?.enterprise_id }"
           >
             <div class="enterprise-item">
               <span class="enterprise-item__name">{{ ent.name }}</span>
-              <el-icon v-if="ent.enterprise_id === currentEnterprise.value?.enterprise_id" class="enterprise-item__check">
+              <el-icon v-if="ent.enterprise_id === currentEnterprise?.enterprise_id" class="enterprise-item__check">
                 <Check />
               </el-icon>
             </div>

+ 1 - 1
frontend/src/layouts/components/NavBar/components/NavbarActions.vue

@@ -4,7 +4,7 @@
     <template v-if="isDesktop">
 
       <!-- 企业切换器 -->
-      <div v-if="showEnterpriseSwitcher" class="navbar-actions__item">
+      <div v-if="showEnterpriseSwitcher && !userStore.is_platform_user" class="navbar-actions__item">
         <EnterpriseSwitcher />
       </div>
 

+ 449 - 0
frontend/src/views/module_payment/account/components/AccountOverview.vue

@@ -0,0 +1,449 @@
+<template>
+  <div class="account-overview">
+    <el-card>
+      <template #header>
+        <div class="card-header">
+          <span>账户状态流程</span>
+          <el-button type="primary" link :icon="Refresh" @click="handleRefresh">刷新</el-button>
+        </div>
+      </template>
+
+      <el-steps :active="currentStep" align-center finish-status="success" class="mb-6">
+        <el-step title="转账授权签约" :description="authorizeStatusText" />
+        <el-step title="开通资金专户" :description="accountStatusText" />
+        <el-step title="账户充值" :description="depositStatusText" />
+        <el-step title="进行转账" />
+      </el-steps>
+
+      <div v-if="!accountData.account_book_id && authorizeStatus !== 'AUTHORIZED'" class="warning-box">
+        <el-alert
+          title="您还未完成转账授权签约,无法开通资金专户"
+          type="warning"
+          :closable="false"
+          show-icon
+        >
+          <template #default>
+            请先完成
+            <el-button type="primary" link @click="$emit('goTab', 'authorize')">转账授权签约</el-button>
+          </template>
+        </el-alert>
+      </div>
+    </el-card>
+
+    <el-row :gutter="16" class="mt-4">
+      <el-col :span="6">
+        <el-card shadow="hover">
+          <div class="stat-item">
+            <div class="stat-label">签约状态</div>
+            <div class="stat-value">
+              <el-tag :type="getAuthorizeStatusType(authorizeStatus)">
+                {{ authorizeStatusText }}
+              </el-tag>
+            </div>
+          </div>
+        </el-card>
+      </el-col>
+
+      <!-- <el-col :span="6">
+        <el-card shadow="hover">
+          <div class="stat-item">
+            <div class="stat-label">专户状态</div>
+            <div class="stat-value">
+              <el-tag :type="getAccountStatusType(accountData.status)">
+                {{ accountData.status || '未开通' }}
+              </el-tag>
+            </div>
+          </div>
+        </el-card>
+      </el-col> -->
+
+      <el-col :span="6">
+        <el-card shadow="hover">
+          <div class="stat-item">
+            <div class="stat-label">专户ID</div>
+            <div class="stat-value text-truncate">
+              {{ accountData.account_book_id || '-' }}
+            </div>
+          </div>
+        </el-card>
+      </el-col>
+
+      <el-col :span="6">
+        <el-card shadow="hover">
+          <div class="stat-item">
+            <div class="stat-label">账户余额</div>
+            <div class="stat-value balance-value">
+              ¥{{ accountData.balance || '0.00' }}
+            </div>
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+
+    <el-card class="mt-4">
+      <template #header>
+        <div class="card-header">
+          <span>快捷操作</span>
+        </div>
+      </template>
+
+      <div class="quick-actions">
+        <div class="action-item" :class="{ disabled: authorizeStatus !== 'AUTHORIZED' }">
+          <div class="action-icon">
+            <el-icon :size="32"><Document /></el-icon>
+          </div>
+          <div class="action-title">转账授权签约</div>
+          <div class="action-desc">
+            {{ authorizeStatus === 'AUTHORIZED' ? '已签约' : '前往签约' }}
+          </div>
+          <el-button
+            v-hasPerm="['module_payment:account:authorize']"
+            type="primary"
+            :disabled="authorizeStatus === 'AUTHORIZED'"
+            @click="$emit('goTab', 'authorize')"
+          >
+            {{ authorizeStatus === 'AUTHORIZED' ? '已完成' : '去签约' }}
+          </el-button>
+        </div>
+
+        <div class="action-item" :class="{ disabled: authorizeStatus !== 'AUTHORIZED' || !!accountData.account_book_id }">
+          <div class="action-icon">
+            <el-icon :size="32"><Coin /></el-icon>
+          </div>
+          <div class="action-title">开通资金专户</div>
+          <div class="action-desc">
+            <template v-if="accountData.account_book_id">已开通</template>
+            <template v-else-if="authorizeStatus !== 'AUTHORIZED'">需先签约</template>
+            <template v-else>立即开通</template>
+          </div>
+          <el-button
+            v-hasPerm="['module_payment:account:create']"
+            type="primary"
+            :disabled="authorizeStatus !== 'AUTHORIZED' || !!accountData.account_book_id"
+            @click="$emit('goTab', 'create')"
+          >
+            {{ accountData.account_book_id ? '已开通' : '去开通' }}
+          </el-button>
+        </div>
+
+        <div class="action-item" :class="{ disabled: !accountData.account_book_id || accountData.status !== 'ACTIVE' }">
+          <div class="action-icon">
+            <el-icon :size="32"><Wallet /></el-icon>
+          </div>
+          <div class="action-title">账户充值</div>
+          <div class="action-desc">
+            <template v-if="!accountData.account_book_id">需先开通专户</template>
+            <template v-else-if="accountData.status !== 'ACTIVE'">专户状态异常</template>
+            <template v-else>立即充值</template>
+          </div>
+          <el-button
+            v-hasPerm="['module_payment:account:deposit']"
+            type="primary"
+            :disabled="!accountData.account_book_id || accountData.status !== 'ACTIVE'"
+            @click="$emit('goTab', 'deposit')"
+          >
+            去充值
+          </el-button>
+        </div>
+
+        <div class="action-item" :class="{ disabled: !accountData.account_book_id || accountData.balance <= 0 }">
+          <div class="action-icon">
+            <el-icon :size="32"><Money /></el-icon>
+          </div>
+          <div class="action-title">发起转账</div>
+          <div class="action-desc">
+            <template v-if="!accountData.account_book_id">需先开通专户</template>
+            <template v-else-if="accountData.balance <= 0">余额不足</template>
+            <template v-else>立即转账</template>
+          </div>
+          <el-button
+            v-hasPerm="['module_payment:account:transfer']"
+            type="primary"
+            :disabled="!accountData.account_book_id || accountData.balance <= 0"
+            @click="$emit('goTab', 'transfer')"
+          >
+            去转账
+          </el-button>
+        </div>
+      </div>
+    </el-card>
+
+    <el-card class="mt-4">
+      <template #header>
+        <div class="card-header">
+          <span>最近交易记录</span>
+          <!-- <el-button type="primary" link @click="$emit('goTab', 'transfer')">查看更多</el-button> -->
+        </div>
+      </template>
+
+      <el-table :data="recentTransfers" border stripe v-loading="loading">
+        <template #empty>
+          <el-empty description="暂无交易记录" />
+        </template>
+        <el-table-column prop="out_biz_no" label="订单号" min-width="180" show-overflow-tooltip />
+        <el-table-column prop="amount" label="金额" min-width="100">
+          <template #default="{ row }">
+            <span :class="row.payee_info ? 'expense' : 'income'">
+              {{ row.payee_info ? '-' : '+' }}¥{{ row.amount }}
+            </span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="payee_info.name" label="对方" min-width="120" show-overflow-tooltip>
+          <template #default="{ row }">
+            {{ row.payee_info?.name || '-' }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="status" label="状态" min-width="100">
+          <template #default="{ row }">
+            <el-tag :type="getTransferStatusType(row.status)">
+              {{ row.status }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="created_time" label="时间" min-width="160" />
+      </el-table>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { useEnterpriseStore } from "@/store/modules/enterprise.store";
+import AccountAPI from "@/api/module_payment/account";
+import { Refresh, Document, Coin, Wallet, Money } from "@element-plus/icons-vue";
+import { ref, computed, onMounted } from "vue";
+
+const props = defineProps<{
+  enterpriseId?: string;
+}>();
+
+const emit = defineEmits<{
+  (e: "goTab", tab: string): void;
+  (e: "refresh", data: any): void;
+}>();
+
+const enterpriseStore = useEnterpriseStore();
+
+const loading = ref(false);
+const accountData = ref<{
+  account_book_id?: string;
+  status?: string;
+  balance?: number;
+  scene?: string;
+}>({});
+const recentTransfers = ref<any[]>([]);
+
+const currentEnterpriseId = computed(() => props.enterpriseId || enterpriseStore.getCurrentEnterprise?.enterprise_id);
+
+const authorizeStatus = computed(() => 'ACTIVE');
+
+const currentStep = computed(() => {
+  if (authorizeStatus.value !== "AUTHORIZED") return 0;
+  if (!accountData.value.account_book_id) return 1;
+  if (!accountData.value.balance || accountData.value.balance <= 0) return 2;
+  return 3;
+});
+
+const authorizeStatusText = computed(() => {
+  const map: Record<string, string> = {
+    PENDING: "待签约",
+    AUTHORIZED: "已签约",
+    AUTHORIZE_FAILED: "签约失败",
+    UNAUTHORIZED: "已解约",
+  };
+  return map[authorizeStatus.value] || authorizeStatus.value;
+});
+
+const accountStatusText = computed(() => {
+  if (!accountData.value.account_book_id) return "未开通";
+  const map: Record<string, string> = {
+    ACTIVE: "正常",
+    FROZEN: "冻结",
+    CLOSED: "关闭",
+  };
+  return map[accountData.value.status] || accountData.value.status;
+});
+
+const depositStatusText = computed(() => {
+  if (!accountData.value.balance || accountData.value.balance <= 0) return "未充值";
+  return `¥${accountData.value.balance.toFixed(2)}`;
+});
+
+function getAuthorizeStatusType(status: string) {
+  const map: Record<string, any> = {
+    PENDING: "info",
+    AUTHORIZED: "success",
+    AUTHORIZE_FAILED: "danger",
+    UNAUTHORIZED: "warning",
+  };
+  return map[status] || "info";
+}
+
+function getAccountStatusType(status: string) {
+  const map: Record<string, any> = {
+    ACTIVE: "success",
+    FROZEN: "warning",
+    CLOSED: "danger",
+  };
+  return map[status] || "info";
+}
+
+function getTransferStatusType(status: string) {
+  const map: Record<string, any> = {
+    DEALING: "warning",
+    SUCCESS: "success",
+    FAIL: "danger",
+    REFUND: "warning",
+  };
+  return map[status] || "info";
+}
+
+async function fetchAccountInfo() {
+  if (!currentEnterpriseId.value) return;
+
+  loading.value = true;
+  try {
+    const res = await AccountAPI.query(currentEnterpriseId.value);
+    if (res.data.data && res.data.data.length > 0) {
+      const account = res.data.data[0];
+      accountData.value = {
+        account_book_id: account.account_book_id,
+        // account.available_amount转换成number保留两位小数显示
+        balance: Number(account.available_amount),
+        status: account.enable_status,
+        scene: account.scene,
+      };
+    }
+
+    const transferRes = await AccountAPI.transferList({
+      page_no: 1,
+      page_size: 5,
+    });
+    recentTransfers.value = transferRes.data.data?.items || [];
+
+    emit("refresh", {
+      account_book_id: accountData.value.account_book_id,
+      status: accountData.value.status,
+      balance: accountData.value.balance || 0,
+      authorize_status: authorizeStatus.value,
+    });
+  } catch (error) {
+    console.error("获取账户信息失败:", error);
+  } finally {
+    loading.value = false;
+  }
+}
+
+function handleRefresh() {
+  fetchAccountInfo();
+}
+
+function refresh() {
+  fetchAccountInfo();
+}
+
+defineExpose({ refresh });
+
+onMounted(() => {
+  fetchAccountInfo();
+});
+</script>
+
+<style lang="scss" scoped>
+.account-overview {
+  padding: 0;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.mb-6 {
+  margin-bottom: 24px;
+}
+
+.mt-4 {
+  margin-top: 16px;
+}
+
+.stat-item {
+  text-align: center;
+
+  .stat-label {
+    font-size: 14px;
+    color: #909399;
+    margin-bottom: 12px;
+  }
+
+  .stat-value {
+    font-size: 20px;
+    font-weight: 600;
+    color: #303133;
+  }
+
+  .balance-value {
+    color: #67c23a;
+  }
+}
+
+.text-truncate {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.quick-actions {
+  display: grid;
+  grid-template-columns: repeat(4, 1fr);
+  gap: 16px;
+
+  .action-item {
+    text-align: center;
+    padding: 20px;
+    border: 1px solid #ebeef5;
+    border-radius: 8px;
+    transition: all 0.3s;
+
+    &:hover:not(.disabled) {
+      border-color: #409eff;
+      box-shadow: 0 2px 12px rgba(64, 158, 255, 0.2);
+    }
+
+    &.disabled {
+      opacity: 0.5;
+      pointer-events: none;
+    }
+
+    .action-icon {
+      margin-bottom: 12px;
+      color: #409eff;
+    }
+
+    .action-title {
+      font-size: 16px;
+      font-weight: 600;
+      color: #303133;
+      margin-bottom: 8px;
+    }
+
+    .action-desc {
+      font-size: 12px;
+      color: #909399;
+      margin-bottom: 16px;
+    }
+  }
+}
+
+.warning-box {
+  padding: 16px 0;
+}
+
+.expense {
+  color: #f56c6c;
+}
+
+.income {
+  color: #67c23a;
+}
+</style>

+ 137 - 0
frontend/src/views/module_payment/account/components/ConsumeDetail.vue

@@ -0,0 +1,137 @@
+<template>
+  <div class="consume-detail">
+    <el-descriptions :column="2" border>
+      <el-descriptions-item label="账单号">
+        {{ data.pay_no || '-' }}
+      </el-descriptions-item>
+      <el-descriptions-item label="企业ID">
+        {{ data.enterprise_id || '-' }}
+      </el-descriptions-item>
+      <el-descriptions-item label="金额">
+        <span class="amount">¥{{ data.amount || '0.00' }}</span>
+      </el-descriptions-item>
+      <el-descriptions-item label="状态">
+        <el-tag :type="getStatusType(data.status)">
+          {{ data.status || '-' }}
+        </el-tag>
+      </el-descriptions-item>
+      <el-descriptions-item label="支付类型">
+        {{ data.pay_type || '-' }}
+      </el-descriptions-item>
+      <el-descriptions-item label="创建时间">
+        {{ data.created_time || '-' }}
+      </el-descriptions-item>
+    </el-descriptions>
+
+    <template v-if="data.payee_info">
+      <el-divider content-position="left">付款方信息</el-divider>
+      <el-descriptions :column="2" border>
+        <el-descriptions-item label="付款方类型">
+          {{ data.payee_info.identity_type || '-' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="付款方名称">
+          {{ data.payee_info.name || '-' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="付款方账号" :span="2">
+          {{ data.payee_info.identity || '-' }}
+        </el-descriptions-item>
+      </el-descriptions>
+    </template>
+
+    <template v-if="data.refund_info">
+      <el-divider content-position="left">退款信息</el-divider>
+      <el-descriptions :column="2" border>
+        <el-descriptions-item label="退款状态">
+          {{ data.refund_info.status || '-' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="退款金额">
+          ¥{{ data.refund_info.amount || '0.00' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="退款时间">
+          {{ data.refund_info.refund_time || '-' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="退款原因">
+          {{ data.refund_info.reason || '-' }}
+        </el-descriptions-item>
+      </el-descriptions>
+    </template>
+
+    <template v-if="data.order_info">
+      <el-divider content-position="left">订单信息</el-divider>
+      <el-descriptions :column="2" border>
+        <el-descriptions-item label="订单号">
+          {{ data.order_info.order_no || '-' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="订单状态">
+          {{ data.order_info.status || '-' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="订单金额">
+          ¥{{ data.order_info.amount || '0.00' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="下单时间">
+          {{ data.order_info.created_time || '-' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="商品名称" :span="2">
+          {{ data.order_info.goods_name || '-' }}
+        </el-descriptions-item>
+      </el-descriptions>
+    </template>
+
+    <template v-if="data.ticket_info">
+      <el-divider content-position="left">票据信息</el-divider>
+      <el-descriptions :column="2" border>
+        <el-descriptions-item label="票据号">
+          {{ data.ticket_info.ticket_no || '-' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="票据类型">
+          {{ data.ticket_info.ticket_type || '-' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="开票金额">
+          ¥{{ data.ticket_info.amount || '0.00' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="开票时间">
+          {{ data.ticket_info.created_time || '-' }}
+        </el-descriptions-item>
+      </el-descriptions>
+    </template>
+  </div>
+</template>
+
+<script setup lang="ts">
+defineProps<{
+  data: {
+    pay_no?: string;
+    enterprise_id?: string;
+    amount?: string;
+    status?: string;
+    pay_type?: string;
+    created_time?: string;
+    payee_info?: any;
+    refund_info?: any;
+    order_info?: any;
+    ticket_info?: any;
+  };
+}>();
+
+function getStatusType(status: string) {
+  const map: Record<string, any> = {
+    SUCCESS: "success",
+    PENDING: "warning",
+    FAIL: "danger",
+    REFUND: "warning",
+  };
+  return map[status] || "info";
+}
+</script>
+
+<style lang="scss" scoped>
+.consume-detail {
+  padding: 16px;
+
+  .amount {
+    font-size: 16px;
+    font-weight: 600;
+    color: #67c23a;
+  }
+}
+</style>

+ 183 - 0
frontend/src/views/module_payment/account/components/TransferDetail.vue

@@ -0,0 +1,183 @@
+<template>
+  <el-drawer
+    :model-value="modelValue"
+    title="转账记录详情"
+    direction="rtl"
+    size="500px"
+    @close="handleClose"
+  >
+    <div v-loading="loading" class="transfer-detail">
+      <el-descriptions :column="1" border>
+        <el-descriptions-item label="商家订单号">
+          {{ detailData.out_biz_no || '-' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="支付宝转账单号">
+          {{ detailData.order_no || '-' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="企业ID">
+          {{ detailData.enterprise_id || '-' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="资金专户号">
+          {{ detailData.account_book_id || '-' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="转账金额">
+          <span class="amount">¥{{ detailData.amount || '0.00' }}</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="转账标题">
+          {{ detailData.order_title || '-' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="状态">
+          <el-tag :type="getStatusType(detailData.status)">
+            {{ getStatusLabel(detailData.status) }}
+          </el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="创建时间">
+          {{ detailData.created_time || '-' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="更新时间">
+          {{ detailData.updated_time || '-' }}
+        </el-descriptions-item>
+      </el-descriptions>
+
+      <el-divider content-position="left">收款方信息</el-divider>
+
+      <el-descriptions :column="1" border>
+        <el-descriptions-item label="收款方类型">
+          {{ getPayeeTypeLabel(detailData.payee_info?.identity_type) }}
+        </el-descriptions-item>
+        <el-descriptions-item label="收款方姓名">
+          {{ detailData.payee_info?.name || '-' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="收款方账号">
+          {{ detailData.payee_info?.identity || '-' }}
+        </el-descriptions-item>
+        <template v-if="detailData.payee_info?.bankcard_ext_info">
+          <el-descriptions-item label="账户类型">
+            {{ detailData.payee_info.bankcard_ext_info.account_type === '1' ? '对公' : '对私' }}
+          </el-descriptions-item>
+          <el-descriptions-item label="银行名称">
+            {{ detailData.payee_info.bankcard_ext_info.inst_name || '-' }}
+          </el-descriptions-item>
+          <el-descriptions-item label="开户省份">
+            {{ detailData.payee_info.bankcard_ext_info.inst_province || '-' }}
+          </el-descriptions-item>
+          <el-descriptions-item label="开户城市">
+            {{ detailData.payee_info.bankcard_ext_info.inst_city || '-' }}
+          </el-descriptions-item>
+          <el-descriptions-item label="支行名称">
+            {{ detailData.payee_info.bankcard_ext_info.inst_branch_name || '-' }}
+          </el-descriptions-item>
+          <el-descriptions-item label="联行号">
+            {{ detailData.payee_info.bankcard_ext_info.bank_code || '-' }}
+          </el-descriptions-item>
+        </template>
+      </el-descriptions>
+    </div>
+
+    <template #footer>
+      <div class="drawer-footer">
+        <el-button @click="handleClose">关闭</el-button>
+        <el-button type="primary" @click="handleRefresh">刷新</el-button>
+      </div>
+    </template>
+  </el-drawer>
+</template>
+
+<script setup lang="ts">
+import AccountAPI from "@/api/module_payment/account";
+import { ref, watch } from "vue";
+
+const props = defineProps<{
+  modelValue: boolean;
+  outBizNo: string;
+}>();
+
+const emit = defineEmits<{
+  (e: "update:modelValue", value: boolean): void;
+  (e: "refresh"): void;
+}>();
+
+const loading = ref(false);
+const detailData = ref<any>({});
+
+watch(
+  () => [props.modelValue, props.outBizNo],
+  async ([val, outBizNo]) => {
+    if (val && outBizNo) {
+      await fetchDetail();
+    }
+  },
+  { immediate: true }
+);
+
+async function fetchDetail() {
+  if (!props.outBizNo) return;
+
+  loading.value = true;
+  try {
+    const res = await AccountAPI.transferDetail(props.outBizNo);
+    console.log(res);
+    detailData.value = res.data.data || {};
+  } catch (error) {
+    console.error("获取转账详情失败:", error);
+  } finally {
+    loading.value = false;
+  }
+}
+
+function getStatusType(status: string) {
+  const map: Record<string, any> = {
+    DEALING: "warning",
+    SUCCESS: "success",
+    FAIL: "danger",
+    REFUND: "warning",
+  };
+  return map[status] || "info";
+}
+
+function getStatusLabel(status: string) {
+  const map: Record<string, string> = {
+    DEALING: "处理中",
+    SUCCESS: "成功",
+    FAIL: "失败",
+    REFUND: "退票",
+  };
+  return map[status] || status;
+}
+
+function getPayeeTypeLabel(type: string) {
+  const map: Record<string, string> = {
+    ALIPAY_ACCOUNT: "支付宝账户",
+    BANK_CARD: "银行卡",
+    BOOK: "资金专户",
+  };
+  return map[type] || type;
+}
+
+function handleClose() {
+  emit("update:modelValue", false);
+}
+
+function handleRefresh() {
+  fetchDetail();
+  emit("refresh");
+}
+</script>
+
+<style lang="scss" scoped>
+.transfer-detail {
+  padding: 16px;
+
+  .amount {
+    font-size: 18px;
+    font-weight: 600;
+    color: #67c23a;
+  }
+}
+
+.drawer-footer {
+  display: flex;
+  justify-content: flex-end;
+  gap: 12px;
+}
+</style>

+ 911 - 0
frontend/src/views/module_payment/account/index.vue

@@ -0,0 +1,911 @@
+<template>
+  <div v-loading="pageLoading" class="app-container" :element-loading-text="loadingText">
+    <el-tabs v-model="activeTab" class="account-tabs">
+      <el-tab-pane label="账户概览" name="overview">
+        <AccountOverview
+          ref="overviewRef"
+          :enterprise-id="currentEnterpriseId"
+          @refresh="handleOverviewRefresh"
+        />
+      </el-tab-pane>
+
+      <el-tab-pane label="转账授权签约" name="authorize">
+        <div class="tab-content">
+          <el-card>
+            <template #header>
+              <div class="card-header">
+                <span>转账授权签约</span>
+              </div>
+            </template>
+            <el-form
+              ref="authorizeFormRef"
+              :model="authorizeForm"
+              :rules="authorizeRules"
+              label-width="120px"
+            >
+              <el-form-item label="企业ID" prop="enterprise_id">
+                <el-input
+                  v-model="authorizeForm.enterprise_id"
+                  placeholder="请输入企业ID"
+                  :disabled="!!currentEnterpriseId"
+                />
+              </el-form-item>
+              <el-form-item>
+                <el-button
+                  v-hasPerm="['module_payment:account:authorize']"
+                  type="primary"
+                  :loading="authorizeLoading"
+                  @click="handleAuthorize"
+                >
+                  申请签约
+                </el-button>
+                <el-button @click="handleAuthorizeReset">重置</el-button>
+              </el-form-item>
+            </el-form>
+            <div v-if="authorizeResult.sign_url" class="authorize-result">
+              <el-alert title="签约链接已生成,请在支付宝中完成签约" type="success" :closable="false">
+                <template #default>
+                  <el-link :href="authorizeResult.sign_url" target="_blank" type="primary">
+                    点击前往签约 →
+                  </el-link>
+                </template>
+              </el-alert>
+            </div>
+          </el-card>
+        </div>
+      </el-tab-pane>
+
+      <el-tab-pane label="开通资金专户" name="create">
+        <div class="tab-content">
+          <el-card>
+            <template #header>
+              <div class="card-header">
+                <span>开通资金专户</span>
+                <el-tag v-if="authorizeStatus !== 'AUTHORIZED'" type="danger">
+                  请先完成转账授权签约
+                </el-tag>
+              </div>
+            </template>
+            <el-form
+              ref="createFormRef"
+              :model="createForm"
+              :rules="createRules"
+              label-width="140px"
+            >
+              <el-form-item label="企业ID" prop="enterprise_id">
+                <el-input
+                  v-model="createForm.enterprise_id"
+                  placeholder="请输入企业ID"
+                  :disabled="!!currentEnterpriseId"
+                />
+              </el-form-item>
+              <el-form-item label="账户类型" prop="account_type">
+                <el-select v-model="createForm.account_type" placeholder="请选择账户类型">
+                  <el-option label="收支全能户" value="ALL" />
+                  <el-option label="收入户" value="INCOME" />
+                  <el-option label="支出户" value="DISBURSE" />
+                </el-select>
+              </el-form-item>
+              <el-form-item label="场景类型" prop="scene">
+                <el-select v-model="createForm.scene" placeholder="请选择场景类型">
+                  <el-option label="ToB转账" value="B2B_TRANS" />
+                  <el-option label="企业信用" value="ENT_CREDIT" />
+                </el-select>
+              </el-form-item>
+              <el-form-item label="备注" prop="remark">
+                <el-input v-model="createForm.remark" type="textarea" placeholder="请输入备注" />
+              </el-form-item>
+              <el-form-item>
+                <el-button
+                  v-hasPerm="['module_payment:account:create']"
+                  type="primary"
+                  :loading="createLoading"
+                  :disabled="authorizeStatus !== 'AUTHORIZED'"
+                  @click="handleCreate"
+                >
+                  开通专户
+                </el-button>
+                <el-button @click="handleCreateReset">重置</el-button>
+              </el-form-item>
+            </el-form>
+            <div v-if="createResult.account_book_id" class="create-result">
+              <el-alert title="资金专户开通成功" type="success" :closable="false">
+                <template #default>
+                  <div>专户ID: {{ createResult.account_book_id }}</div>
+                </template>
+              </el-alert>
+            </div>
+          </el-card>
+        </div>
+      </el-tab-pane>
+
+      <el-tab-pane label="账户充值" name="deposit">
+        <div class="tab-content">
+          <el-card>
+            <template #header>
+              <div class="card-header">
+                <span>资金专户充值</span>
+                <el-tag v-if="!accountInfo.account_book_id" type="danger">
+                  请先开通资金专户
+                </el-tag>
+                <el-tag v-else-if="accountInfo.status !== 'ACTIVE'" type="warning">
+                  资金专户状态异常
+                </el-tag>
+              </div>
+            </template>
+            <el-form
+              ref="depositFormRef"
+              :model="depositForm"
+              :rules="depositRules"
+              label-width="140px"
+            >
+              <el-form-item label="企业ID" prop="enterprise_id">
+                <el-input
+                  v-model="depositForm.enterprise_id"
+                  placeholder="请输入企业ID"
+                  :disabled="!!currentEnterpriseId"
+                />
+              </el-form-item>
+              <el-form-item label="资金专户号" prop="account_book_id">
+                <el-input
+                  v-model="depositForm.account_book_id"
+                  :placeholder="accountInfo.account_book_id || '请先开通资金专户'"
+                  :disabled="!!accountInfo.account_book_id"
+                />
+              </el-form-item>
+              <el-form-item label="充值金额" prop="amount">
+                <el-input-number
+                  v-model="depositForm.amount"
+                  :min="0.01"
+                  :precision="2"
+                  :controls="false"
+                  placeholder="请输入充值金额"
+                  style="width: 300px"
+                />
+                <span class="ml-2">元</span>
+              </el-form-item>
+              <el-form-item label="备注" prop="remark">
+                <el-input v-model="depositForm.remark" type="textarea" placeholder="请输入备注" />
+              </el-form-item>
+              <el-form-item>
+                <el-button
+                  v-hasPerm="['module_payment:account:deposit']"
+                  type="primary"
+                  :loading="depositLoading"
+                  :disabled="!accountInfo.account_book_id || accountInfo.status !== 'ACTIVE'"
+                  @click="handleDeposit"
+                >
+                  发起充值
+                </el-button>
+                <el-button @click="handleDepositReset">重置</el-button>
+              </el-form-item>
+            </el-form>
+            <div v-if="depositResult.url" class="deposit-result">
+              <el-alert title="充值页面已生成,请在支付宝中完成支付" type="success" :closable="false">
+                <template #default>
+                  <el-link :href="depositResult.url" target="_blank" type="primary">
+                    点击前往充值 →
+                  </el-link>
+                </template>
+              </el-alert>
+            </div>
+          </el-card>
+
+          <el-card class="mt-4">
+            <template #header>
+              <span>充值记录</span>
+            </template>
+            <el-table :data="depositList" border stripe>
+              <el-table-column prop="out_biz_no" label="订单号" min-width="180" />
+              <el-table-column prop="amount" label="充值金额" min-width="100">
+                <template #default="{ row }">
+                  ¥{{ row.amount }}
+                </template>
+              </el-table-column>
+              <el-table-column prop="status" label="状态" min-width="100">
+                <template #default="{ row }">
+                  <el-tag :type="getDepositStatusType(row.status)">
+                    {{ row.status }}
+                  </el-tag>
+                </template>
+              </el-table-column>
+              <el-table-column prop="created_time" label="创建时间" min-width="160" />
+            </el-table>
+          </el-card>
+        </div>
+      </el-tab-pane>
+
+      <el-tab-pane label="转账管理" name="transfer">
+        <div class="tab-content">
+          <el-card>
+            <template #header>
+              <div class="card-header">
+                <span>发起转账</span>
+                <el-tag v-if="!accountInfo.account_book_id" type="danger">
+                  请先开通资金专户
+                </el-tag>
+                <el-tag v-else-if="accountInfo.balance <= 0" type="warning">
+                  账户余额不足,请先充值
+                </el-tag>
+              </div>
+            </template>
+            <el-form
+              ref="transferFormRef"
+              :model="transferForm"
+              :rules="transferRules"
+              label-width="140px"
+            >
+              <el-form-item label="企业ID" prop="enterprise_id">
+                <el-input
+                  v-model="transferForm.enterprise_id"
+                  placeholder="请输入企业ID"
+                  :disabled="!!currentEnterpriseId"
+                />
+              </el-form-item>
+              <el-form-item label="付款专户号" prop="account_book_id">
+                <el-input
+                  v-model="transferForm.account_book_id"
+                  :placeholder="accountInfo.account_book_id || '请先开通资金专户'"
+                  :disabled="!!accountInfo.account_book_id"
+                />
+              </el-form-item>
+              <el-form-item label="转账金额" prop="amount">
+                <el-input-number
+                  v-model="transferForm.amount"
+                  :min="0.01"
+                  :precision="2"
+                  :controls="false"
+                  placeholder="请输入转账金额"
+                  style="width: 300px"
+                />
+                <span class="ml-2">元</span>
+              </el-form-item>
+              <el-form-item label="转账标题" prop="order_title">
+                <el-input v-model="transferForm.order_title" placeholder="请输入转账标题" />
+              </el-form-item>
+              <el-form-item label="收款方类型" prop="payee_info.identity_type">
+                <el-select v-model="transferForm.payee_info.identity_type" placeholder="请选择收款方类型">
+                  <el-option label="支付宝账户" value="alipay" />
+                  <el-option label="银行卡" value="bank" />
+                  <el-option label="资金专户" value="book" />
+                </el-select>
+              </el-form-item>
+              <el-form-item label="收款方姓名" prop="payee_info.name">
+                <el-input v-model="transferForm.payee_info.name" placeholder="请输入收款方姓名" />
+              </el-form-item>
+              <el-form-item label="收款方账号" prop="payee_info.identity">
+                <el-input v-model="transferForm.payee_info.identity" placeholder="请输入收款方账号" />
+              </el-form-item>
+              <template v-if="transferForm.payee_info.identity_type === 'bank'">
+                <el-form-item label="账户类型" prop="payee_info.bankcard_ext_info.account_type">
+                  <el-select v-model="transferForm.payee_info.bankcard_ext_info!.account_type" placeholder="请选择账户类型">
+                    <el-option label="对公" value="1" />
+                    <el-option label="对私" value="2" />
+                  </el-select>
+                </el-form-item>
+                <el-form-item label="银行名称" prop="payee_info.bankcard_ext_info.inst_name">
+                  <el-input v-model="transferForm.payee_info.bankcard_ext_info!.inst_name" placeholder="请输入银行名称" />
+                </el-form-item>
+                <el-form-item label="开户省份" prop="payee_info.bankcard_ext_info.inst_province">
+                  <el-input v-model="transferForm.payee_info.bankcard_ext_info!.inst_province" placeholder="请输入开户省份" />
+                </el-form-item>
+                <el-form-item label="开户城市" prop="payee_info.bankcard_ext_info.inst_city">
+                  <el-input v-model="transferForm.payee_info.bankcard_ext_info!.inst_city" placeholder="请输入开户城市" />
+                </el-form-item>
+                <el-form-item label="支行名称" prop="payee_info.bankcard_ext_info.inst_branch_name">
+                  <el-input v-model="transferForm.payee_info.bankcard_ext_info!.inst_branch_name" placeholder="请输入支行名称" />
+                </el-form-item>
+                <el-form-item label="联行号" prop="payee_info.bankcard_ext_info.bank_code">
+                  <el-input v-model="transferForm.payee_info.bankcard_ext_info!.bank_code" placeholder="请输入联行号" />
+                </el-form-item>
+              </template>
+              <el-form-item label="备注" prop="remark">
+                <el-input v-model="transferForm.remark" type="textarea" placeholder="请输入备注" />
+              </el-form-item>
+              <el-form-item>
+                <el-button
+                  v-hasPerm="['module_payment:account:transfer']"
+                  type="primary"
+                  :loading="transferLoading"
+                  :disabled="!accountInfo.account_book_id || accountInfo.balance <= 0"
+                  @click="handleTransfer"
+                >
+                  发起转账
+                </el-button>
+                <el-button @click="handleTransferReset">重置</el-button>
+              </el-form-item>
+            </el-form>
+          </el-card>
+
+          <el-card class="mt-4">
+            <template #header>
+              <span>转账记录</span>
+            </template>
+            <div class="mb-4">
+              <el-form :inline="true" :model="transferSearchForm">
+                <el-form-item label="订单号">
+                  <el-input v-model="transferSearchForm.out_biz_no" placeholder="请输入订单号" clearable />
+                </el-form-item>
+                <el-form-item label="状态">
+                  <el-select v-model="transferSearchForm.status" placeholder="请选择状态" clearable>
+                    <el-option label="处理中" value="DEALING" />
+                    <el-option label="成功" value="SUCCESS" />
+                    <el-option label="失败" value="FAIL" />
+                    <el-option label="退票" value="REFUND" />
+                  </el-select>
+                </el-form-item>
+                <el-form-item>
+                  <el-button type="primary" @click="handleTransferSearch">查询</el-button>
+                  <el-button @click="handleTransferSearchReset">重置</el-button>
+                </el-form-item>
+              </el-form>
+            </div>
+
+            <el-table :data="transferList" border stripe v-loading="transferListLoading">
+              <template #empty>
+                <el-empty description="暂无数据" />
+              </template>
+              <el-table-column prop="out_biz_no" label="订单号" min-width="180" />
+              <el-table-column prop="amount" label="转账金额" min-width="100">
+                <template #default="{ row }">
+                  ¥{{ row.amount }}
+                </template>
+              </el-table-column>
+              <el-table-column prop="payee_info.name" label="收款方姓名" min-width="120" />
+              <el-table-column prop="payee_info.identity_type" label="收款方类型" min-width="100">
+                <template #default="{ row }">
+                  {{ getPayeeTypeLabel(row.payee_info?.identity_type) }}
+                </template>
+              </el-table-column>
+              <el-table-column prop="status" label="状态" min-width="100">
+                <template #default="{ row }">
+                  <el-tag :type="getTransferStatusType(row.status)">
+                    {{ row.status }}
+                  </el-tag>
+                </template>
+              </el-table-column>
+              <el-table-column prop="order_title" label="转账标题" min-width="150" />
+              <el-table-column prop="created_time" label="创建时间" min-width="160" />
+              <el-table-column label="操作" width="100" fixed="right">
+                <template #default="{ row }">
+                  <el-button type="primary" link @click="handleViewTransferDetail(row.out_biz_no)">
+                    详情
+                  </el-button>
+                </template>
+              </el-table-column>
+            </el-table>
+            <div class="mt-4 flex justify-end">
+              <el-pagination
+                v-model:current-page="transferPage.page_no"
+                v-model:page-size="transferPage.page_size"
+                :total="transferPage.total"
+                :page-sizes="[10, 20, 50, 100]"
+                layout="total, sizes, prev, pager, next, jumper"
+                @size-change="handleTransferListChange"
+                @current-change="handleTransferListChange"
+              />
+            </div>
+          </el-card>
+        </div>
+      </el-tab-pane>
+
+      <!-- <el-tab-pane label="账单查询" name="consume">
+        <div class="tab-content">
+          <el-card>
+            <template #header>
+              <span>账单详情查询</span>
+            </template>
+            <el-form ref="consumeFormRef" :model="consumeForm" :rules="consumeRules" label-width="140px">
+              <el-form-item label="支付宝账单号" prop="pay_no">
+                <el-input v-model="consumeForm.pay_no" placeholder="请输入支付宝账单号" />
+              </el-form-item>
+              <el-form-item label="企业ID" prop="enterprise_id">
+                <el-input
+                  v-model="consumeForm.enterprise_id"
+                  placeholder="请输入企业ID(2.0接口签约企业必填)"
+                  :disabled="!!currentEnterpriseId"
+                />
+              </el-form-item>
+              <el-form-item label="蚂蚁门店ID" prop="ant_shop_id">
+                <el-input v-model="consumeForm.ant_shop_id" placeholder="请输入蚂蚁门店ID(商户服务商必填)" />
+              </el-form-item>
+              <el-form-item label="查询选项">
+                <el-checkbox-group v-model="consumeForm.query_options">
+                  <el-checkbox label="Refund">退款信息</el-checkbox>
+                  <el-checkbox label="Order">订单信息</el-checkbox>
+                  <el-checkbox label="Ticket">票据信息</el-checkbox>
+                </el-checkbox-group>
+              </el-form-item>
+              <el-form-item>
+                <el-button
+                  v-hasPerm="['module_payment:account:consume:detail']"
+                  type="primary"
+                  :loading="consumeLoading"
+                  @click="handleConsumeQuery"
+                >
+                  查询
+                </el-button>
+                <el-button @click="handleConsumeReset">重置</el-button>
+              </el-form-item>
+            </el-form>
+          </el-card>
+
+          <el-card v-if="consumeDetail" class="mt-4">
+            <template #header>
+              <span>账单详情</span>
+            </template>
+            <ConsumeDetail :data="consumeDetail" />
+          </el-card>
+        </div>
+      </el-tab-pane> -->
+    </el-tabs>
+
+    <TransferDetail
+      v-model="transferDetailVisible"
+      :out-biz-no="currentTransferOutBizNo"
+      @refresh="handleTransferDetailRefresh"
+    />
+  </div>
+</template>
+
+<script setup lang="ts">
+defineOptions({
+  name: "Account",
+  inheritAttrs: false,
+});
+
+import { useEnterpriseStore } from "@/store/modules/enterprise.store";
+import AccountAPI from "@/api/module_payment/account";
+import AccountOverview from "./components/AccountOverview.vue";
+import TransferDetail from "./components/TransferDetail.vue";
+import ConsumeDetail from "./components/ConsumeDetail.vue";
+import { ref, reactive, computed, onMounted } from "vue";
+import { ElMessage } from "element-plus";
+import type { FormInstance, FormRules } from "element-plus";
+
+const enterpriseStore = useEnterpriseStore();
+
+const activeTab = ref("overview");
+const pageLoading = ref(false);
+const loadingText = ref("");
+
+const authorizeLoading = ref(false);
+const createLoading = ref(false);
+const depositLoading = ref(false);
+const transferLoading = ref(false);
+const consumeLoading = ref(false);
+const transferListLoading = ref(false);
+
+const authorizeFormRef = ref<FormInstance>();
+const createFormRef = ref<FormInstance>();
+const depositFormRef = ref<FormInstance>();
+const transferFormRef = ref<FormInstance>();
+const consumeFormRef = ref<FormInstance>();
+const overviewRef = ref<InstanceType<typeof AccountOverview>>();
+
+const currentEnterpriseId = computed(() => enterpriseStore.getCurrentEnterprise?.enterprise_id);
+
+const accountInfo = ref<{
+  account_book_id: string;
+  status: string;
+  balance: number;
+}>({
+  account_book_id: "",
+  status: "",
+  balance: 0,
+});
+
+const authorizeStatus = ref("PENDING");
+
+const authorizeForm = reactive({
+  enterprise_id: "",
+});
+
+const authorizeRules: FormRules = {
+  enterprise_id: [{ required: true, message: "请输入企业ID", trigger: "blur" }],
+};
+
+const authorizeResult = reactive({
+  sign_url: "",
+});
+
+const createForm = reactive({
+  enterprise_id: "",
+  account_type: "ALL",
+  scene: "B2B_TRANS",
+  remark: "",
+});
+
+const createRules: FormRules = {
+  enterprise_id: [{ required: true, message: "请输入企业ID", trigger: "blur" }],
+  account_type: [{ required: true, message: "请选择账户类型", trigger: "change" }],
+  scene: [{ required: true, message: "请选择场景类型", trigger: "change" }],
+};
+
+const createResult = reactive({
+  enterprise_id: "",
+  account_book_id: "",
+});
+
+const depositForm = reactive({
+  enterprise_id: "",
+  account_book_id: "",
+  amount: 0,
+  remark: "",
+});
+
+const depositRules: FormRules = {
+  enterprise_id: [{ required: true, message: "请输入企业ID", trigger: "blur" }],
+  account_book_id: [{ required: true, message: "请输入资金专户号", trigger: "blur" }],
+  amount: [{ required: true, message: "请输入充值金额", trigger: "blur" }],
+};
+
+const depositResult = reactive({
+  url: "",
+});
+
+const depositList = ref<any[]>([]);
+
+const transferForm = reactive({
+  enterprise_id: "",
+  account_book_id: "",
+  amount: 0,
+  order_title: "",
+  remark: "",
+  payee_info: {
+    identity_type: "alipay",
+    name: "",
+    identity: "",
+    bankcard_ext_info: {
+      account_type: "2",
+      inst_name: "",
+      inst_province: "",
+      inst_city: "",
+      inst_branch_name: "",
+      bank_code: "",
+    },
+  },
+});
+
+const transferRules: FormRules = {
+  enterprise_id: [{ required: true, message: "请输入企业ID", trigger: "blur" }],
+  account_book_id: [{ required: true, message: "请输入付款专户号", trigger: "blur" }],
+  amount: [{ required: true, message: "请输入转账金额", trigger: "blur" }],
+  "payee_info.identity_type": [{ required: true, message: "请选择收款方类型", trigger: "change" }],
+  "payee_info.name": [{ required: true, message: "请输入收款方姓名", trigger: "blur" }],
+  "payee_info.identity": [{ required: true, message: "请输入收款方账号", trigger: "blur" }],
+};
+
+const transferList = ref<any[]>([]);
+const transferPage = reactive({
+  page_no: 1,
+  page_size: 10,
+  total: 0,
+});
+
+const transferSearchForm = reactive({
+  out_biz_no: "",
+  status: "",
+});
+
+const transferDetailVisible = ref(false);
+const currentTransferOutBizNo = ref("");
+
+const consumeForm = reactive({
+  pay_no: "",
+  enterprise_id: "",
+  ant_shop_id: "",
+  query_options: [] as string[],
+});
+
+const consumeRules: FormRules = {
+  pay_no: [{ required: true, message: "请输入支付宝账单号", trigger: "blur" }],
+};
+
+const consumeDetail = ref<any>(null);
+
+function getDepositStatusType(status: string) {
+  const map: Record<string, any> = {
+    DEALING: "warning",
+    SUCCESS: "success",
+    FAIL: "danger",
+  };
+  return map[status] || "info";
+}
+
+function getTransferStatusType(status: string) {
+  const map: Record<string, any> = {
+    DEALING: "warning",
+    SUCCESS: "success",
+    FAIL: "danger",
+    REFUND: "warning",
+  };
+  return map[status] || "info";
+}
+
+function getPayeeTypeLabel(type: string) {
+  const map: Record<string, string> = {
+    ALIPAY_ACCOUNT: "支付宝",
+    BANK_CARD: "银行卡",
+    BOOK: "资金专户",
+  };
+  return map[type] || type;
+}
+
+async function handleAuthorize() {
+  if (!authorizeFormRef.value) return;
+  await authorizeFormRef.value.validate(async (valid) => {
+    if (valid) {
+      authorizeLoading.value = true;
+      try {
+        const res = await AccountAPI.authorizeApply({
+          enterprise_id: authorizeForm.enterprise_id || currentEnterpriseId.value!,
+        });
+        authorizeResult.sign_url = res.data.sign_url || "";
+      } finally {
+        authorizeLoading.value = false;
+      }
+    }
+  });
+}
+
+function handleAuthorizeReset() {
+  authorizeFormRef.value?.resetFields();
+  authorizeResult.sign_url = "";
+}
+
+async function handleCreate() {
+  if (!createFormRef.value) return;
+  await createFormRef.value.validate(async (valid) => {
+    if (valid) {
+      if (authorizeStatus.value !== "AUTHORIZED") {
+        ElMessage.warning("请先完成转账授权签约");
+        return;
+      }
+      createLoading.value = true;
+      try {
+        const res = await AccountAPI.create({
+          enterprise_id: createForm.enterprise_id || currentEnterpriseId.value!,
+          account_type: createForm.account_type,
+          scene: createForm.scene,
+          remark: createForm.remark,
+        });
+        createResult.enterprise_id = res.data.enterprise_id || "";
+        createResult.account_book_id = res.data.account_book_id || "";
+        accountInfo.value.account_book_id = createResult.account_book_id;
+        accountInfo.value.status = "ACTIVE";
+        overviewRef.value?.refresh();
+      } finally {
+        createLoading.value = false;
+      }
+    }
+  });
+}
+
+function handleCreateReset() {
+  createFormRef.value?.resetFields();
+  createResult.enterprise_id = "";
+  createResult.account_book_id = "";
+}
+
+async function handleDeposit() {
+  if (!depositFormRef.value) return;
+  await depositFormRef.value.validate(async (valid) => {
+    if (valid) {
+      if (!accountInfo.value.account_book_id) {
+        ElMessage.warning("请先开通资金专户");
+        return;
+      }
+      depositLoading.value = true;
+      try {
+        const res = await AccountAPI.deposit({
+          enterprise_id: depositForm.enterprise_id || currentEnterpriseId.value!,
+          account_book_id: depositForm.account_book_id || accountInfo.value.account_book_id,
+          amount: depositForm.amount,
+          remark: depositForm.remark,
+        });
+        depositResult.url = res.data.url || "";
+      } finally {
+        depositLoading.value = false;
+      }
+    }
+  });
+}
+
+function handleDepositReset() {
+  depositFormRef.value?.resetFields();
+  depositResult.url = "";
+}
+
+async function handleTransfer() {
+  if (!transferFormRef.value) return;
+  await transferFormRef.value.validate(async (valid) => {
+    if (valid) {
+      if (accountInfo.value.balance <= 0) {
+        ElMessage.warning("账户余额不足,请先充值");
+        return;
+      }
+      transferLoading.value = true;
+      try {
+        await AccountAPI.transfer({
+          enterprise_id: transferForm.enterprise_id || currentEnterpriseId.value!,
+          account_book_id: transferForm.account_book_id || accountInfo.value.account_book_id,
+          amount: transferForm.amount,
+          order_title: transferForm.order_title,
+          remark: transferForm.remark,
+          payee_info: {
+            identity_type: transferForm.payee_info.identity_type,
+            name: transferForm.payee_info.name,
+            identity: transferForm.payee_info.identity,
+            bankcard_ext_info:
+              transferForm.payee_info.identity_type === "bank"
+                ? transferForm.payee_info.bankcard_ext_info
+                : undefined,
+          },
+        });
+        ElMessage.success("转账申请已提交");
+        handleTransferListChange();
+        handleTransferReset();
+      } finally {
+        transferLoading.value = false;
+      }
+    }
+  });
+}
+
+function handleTransferReset() {
+  transferFormRef.value?.resetFields();
+  transferForm.payee_info = {
+    identity_type: "alipay",
+    name: "",
+    identity: "",
+    bankcard_ext_info: {
+      account_type: "2",
+      inst_name: "",
+      inst_province: "",
+      inst_city: "",
+      inst_branch_name: "",
+      bank_code: "",
+    },
+  };
+}
+
+async function handleTransferSearch() {
+  transferPage.page_no = 1;
+  await fetchTransferList();
+}
+
+function handleTransferSearchReset() {
+  transferSearchForm.out_biz_no = "";
+  transferSearchForm.status = "";
+  handleTransferSearch();
+}
+
+async function fetchTransferList() {
+  transferListLoading.value = true;
+  try {
+    const res = await AccountAPI.transferList({
+      page_no: transferPage.page_no,
+      page_size: transferPage.page_size,
+      out_biz_no: transferSearchForm.out_biz_no || undefined,
+      status: transferSearchForm.status || undefined,
+    });
+    transferList.value = res.data.data.items || [];
+    transferPage.total = res.data.data.total || 0;
+  } finally {
+    transferListLoading.value = false;
+  }
+}
+
+function handleTransferListChange() {
+  fetchTransferList();
+}
+
+function handleViewTransferDetail(outBizNo: string) {
+  currentTransferOutBizNo.value = outBizNo;
+  transferDetailVisible.value = true;
+}
+
+function handleTransferDetailRefresh() {
+  fetchTransferList();
+}
+
+async function handleConsumeQuery() {
+  if (!consumeFormRef.value) return;
+  await consumeFormRef.value.validate(async (valid) => {
+    if (valid) {
+      consumeLoading.value = true;
+      try {
+        const res = await AccountAPI.consumeDetail({
+          pay_no: consumeForm.pay_no,
+          enterprise_id: consumeForm.enterprise_id || currentEnterpriseId.value || undefined,
+          ant_shop_id: consumeForm.ant_shop_id || undefined,
+          query_options: consumeForm.query_options.length > 0 ? consumeForm.query_options : undefined,
+        });
+        consumeDetail.value = res.data;
+      } finally {
+        consumeLoading.value = false;
+      }
+    }
+  });
+}
+
+function handleConsumeReset() {
+  consumeFormRef.value?.resetFields();
+  consumeDetail.value = null;
+}
+
+function handleOverviewRefresh(data: any) {
+  if (data) {
+    accountInfo.value = {
+      account_book_id: data.account_book_id || "",
+      status: data.status || "",
+      balance: data.balance || 0,
+    };
+    authorizeStatus.value = data.authorize_status || "PENDING";
+  }
+}
+
+onMounted(() => {
+  if (currentEnterpriseId.value) {
+    authorizeForm.enterprise_id = currentEnterpriseId.value;
+    createForm.enterprise_id = currentEnterpriseId.value;
+    depositForm.enterprise_id = currentEnterpriseId.value;
+    transferForm.enterprise_id = currentEnterpriseId.value;
+    consumeForm.enterprise_id = currentEnterpriseId.value;
+  }
+});
+
+watch(activeTab, async (newValue) => { 
+  if (newValue === "transfer") {
+    await handleTransferSearch();
+  }
+})
+</script>
+
+<style lang="scss" scoped>
+.account-tabs {
+  height: 100%;
+
+  :deep(.el-tabs__content) {
+    height: calc(100% - 40px);
+    overflow-y: auto;
+  }
+}
+
+.tab-content {
+  padding: 0;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.mt-4 {
+  margin-top: 16px;
+}
+
+.ml-2 {
+  margin-left: 8px;
+}
+
+.mb-4 {
+  margin-bottom: 16px;
+}
+
+.flex {
+  display: flex;
+}
+
+.justify-end {
+  justify-content: flex-end;
+}
+
+.authorize-result,
+.create-result,
+.deposit-result {
+  margin-top: 20px;
+}
+</style>