Browse Source

feat: 更新转账场景判断

gatsby 3 weeks ago
parent
commit
07fbd21474

+ 1 - 1
backend/app/api/v1/module_system/user/schema.py

@@ -107,7 +107,7 @@ class UserRegisterSchema(BaseModel):
 
 
     name: str | None = Field(default=None, description="名称")
     name: str | None = Field(default=None, description="名称")
     template_name: Optional[str] = Field(default="verify", description="模版名称")
     template_name: Optional[str] = Field(default="verify", description="模版名称")
-    invite_code: str = Field(default=None, description="邀请码")
+    # invite_code: str = Field(default=None, description="邀请码")
     mobile: str = Field(default=None, description="手机号")
     mobile: str = Field(default=None, description="手机号")
     sms_code: Optional[str] = Field(default=None, description="验证码")
     sms_code: Optional[str] = Field(default=None, description="验证码")
     username: str = Field(..., description="账号")
     username: str = Field(..., description="账号")

+ 2 - 2
backend/app/api/v1/module_system/user/service.py

@@ -487,8 +487,8 @@ class UserService:
         返回:
         返回:
         - Dict: 注册后的用户详情字典
         - Dict: 注册后的用户详情字典
         """
         """
-        if not data.invite_code or data.invite_code != "8888":
-            raise CustomException("无效邀请码")
+        # if not data.invite_code or data.invite_code != "8888":
+        #     raise CustomException("无效邀请码")
 
 
         # 检查用户名是否存在
         # 检查用户名是否存在
         data.username = data.mobile
         data.username = data.mobile

+ 36 - 1
backend/app/plugin/module_payment/account/controller.py

@@ -1,7 +1,8 @@
+import io
 from typing import Annotated, Any, Optional, Dict
 from typing import Annotated, Any, Optional, Dict
 
 
 from fastapi import APIRouter, Body, Depends, Path, Query
 from fastapi import APIRouter, Body, Depends, Path, Query
-from fastapi.responses import JSONResponse
+from fastapi.responses import JSONResponse, StreamingResponse
 
 
 from app.api.v1.module_system.auth.schema import AuthSchema
 from app.api.v1.module_system.auth.schema import AuthSchema
 from app.common.response import ResponseSchema, SuccessResponse
 from app.common.response import ResponseSchema, SuccessResponse
@@ -211,6 +212,40 @@ async def consume_detail_query_controller(
     return SuccessResponse(data=result, msg="账单详情查询成功")
     return SuccessResponse(data=result, msg="账单详情查询成功")
 
 
 
 
+@AccountRouter.get(
+    "/transfer/export",
+    summary="导出转账记录报表",
+    description="导出指定时间范围内的转账记录为Excel文件",
+    responses={
+        200: {
+            "description": "Excel文件下载",
+            "content": {
+                "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": {}
+            }
+        }
+    },
+)
+async def transfer_export_controller(
+    auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:account:transfer:list"]))],
+    start_time: Annotated[str, Query(description="开始时间,格式:YYYY-MM-DD HH:MM:SS")],
+    end_time: Annotated[str, Query(description="结束时间,格式:YYYY-MM-DD HH:MM:SS")],
+    enterprise_id: Annotated[str | None, Query(description="企业ID(2.0接口签约企业必填)")] = None,
+) -> StreamingResponse:
+    """导出转账记录报表"""
+    result = await AccountService.transfer_export_service(
+        auth=auth, start_time=start_time, end_time=end_time, enterprise_id=enterprise_id
+    )
+    log.info(f"导出转账记录报表成功: {start_time} -> {end_time}")
+    
+    return StreamingResponse(
+        io.BytesIO(result),
+        media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+        headers={
+            "Content-Disposition": f"attachment; filename=transfer_report_{start_time}_{end_time}.xlsx"
+        }
+    )
+
+
 # @AccountRouter.post(
 # @AccountRouter.post(
 #     "/receipt/apply",
 #     "/receipt/apply",
 #     summary="申请资金回单",
 #     summary="申请资金回单",

+ 93 - 5
backend/app/plugin/module_payment/account/service.py

@@ -1,6 +1,6 @@
 from datetime import datetime
 from datetime import datetime
 from decimal import Decimal
 from decimal import Decimal
-from typing import Any
+from typing import Any, Optional
 
 
 from redis.asyncio import Redis
 from redis.asyncio import Redis
 
 
@@ -30,7 +30,7 @@ from .schema import (
     TenantTransferCreate,
     TenantTransferCreate,
     TenantTransferResponse,
     TenantTransferResponse,
 )
 )
-
+from ..openapi.crud import OpenTransferCRUD
 
 
 
 
 class AccountService:
 class AccountService:
@@ -103,8 +103,10 @@ class AccountService:
 
 
         model = AlipayCommerceEcTransAccountCreateModel()
         model = AlipayCommerceEcTransAccountCreateModel()
         model.enterprise_id = data.enterprise_id
         model.enterprise_id = data.enterprise_id
-        model.account_type = data.account_type or "ALL"  # 收支全能户
-        model.scene = data.scene or "B2B_TRANS"  # ToB转账场景
+        # model.account_type = data.account_type or "ALL"  # 收支全能户
+        # model.scene = data.scene or "B2B_TRANS"  # ToB转账场景
+        model.account_type = "ALL"
+        model.scene = "B2B_TRANS"
 
 
         request = AlipayCommerceEcTransAccountCreateRequest()
         request = AlipayCommerceEcTransAccountCreateRequest()
         request.biz_model = model
         request.biz_model = model
@@ -510,6 +512,11 @@ class AccountService:
 
 
         collect = []
         collect = []
         for v in list(result.account_list or []):
         for v in list(result.account_list or []):
+            if not hasattr(v, "account_book_id"):
+                continue
+            if not hasattr(v, "scene") and v['scene'] != "B2B_TRANS":
+                continue
+
             account = FundAccountApiDTO.to_alipay_dict(v)
             account = FundAccountApiDTO.to_alipay_dict(v)
             collect.append(account)
             collect.append(account)
         
         
@@ -530,7 +537,16 @@ class AccountService:
         if not transfer:
         if not transfer:
             raise CustomException(msg="转账记录不存在")
             raise CustomException(msg="转账记录不存在")
 
 
-        return TransferOutSchema.model_validate(transfer)
+        transfer_result = TransferOutSchema.model_validate(transfer)
+
+        # 查询三方订单号
+        open_transfer_crud = OpenTransferCRUD(auth)
+        open_transfer_data = await open_transfer_crud.get(out_biz_no=transfer.out_biz_no)
+
+        if open_transfer_data:
+            transfer_result.third_biz_no = open_transfer_data.third_biz_no
+
+        return transfer_result
 
 
     @classmethod
     @classmethod
     async def transfer_list_service(
     async def transfer_list_service(
@@ -554,6 +570,78 @@ class AccountService:
             out_schema=TransferListOutSchema,
             out_schema=TransferListOutSchema,
         )
         )
 
 
+    @classmethod
+    async def transfer_export_service(
+        cls,
+        auth: AuthSchema,
+        start_time: str,
+        end_time: str,
+        enterprise_id: Optional[str] = None,
+    ) -> bytes:
+        """
+        导出转账记录报表为Excel文件
+        """
+        log.info(f"导出转账记录报表: {start_time} -> {end_time}")
+        
+        crud = TransferCRUD(auth)
+        
+        search = {
+            "created_time__gte": start_time,
+            "created_time__lte": end_time,
+        }
+        
+        if enterprise_id:
+            search["enterprise_id"] = enterprise_id
+        
+        records = await crud.list(
+            search=search,
+            order_by=[{"id": "desc"}],
+        )
+        
+        from app.utils.excel_util import ExcelUtil
+        
+        status_map = {
+            "DEALING": "处理中",
+            "SUCCESS": "成功",
+            "FAIL": "失败",
+            "REFUND": "退票",
+        }
+        
+        payee_type_map = {
+            "ALIPAY_ACCOUNT": "支付宝账户",
+            "BANK_CARD": "银行卡",
+        }
+        
+        list_data = []
+        for i, record in enumerate(records, start=1):
+            payee_info = record.payee_info or {}
+            list_data.append({
+                "序号": i,
+                "订单号": record.out_biz_no or "",
+                "商户订单号": record.order_no or "",
+                "金额(元)": str(record.amount or 0),
+                "收款方姓名": payee_info.get("name", ""),
+                "收款方类型": payee_type_map.get(payee_info.get("identity_type", ""), ""),
+                "状态": status_map.get(record.status, record.status),
+                "转账标题": record.order_title or "",
+                "创建时间": record.created_time.strftime("%Y-%m-%d %H:%M:%S") if record.created_time else "",
+            })
+        
+        mapping_dict = {
+            "序号": "序号",
+            "订单号": "订单号",
+            "商户订单号": "商户订单号",
+            "金额(元)": "金额(元)",
+            "收款方姓名": "收款方姓名",
+            "收款方类型": "收款方类型",
+            "状态": "状态",
+            "转账标题": "转账标题",
+            "创建时间": "创建时间",
+        }
+        
+        return ExcelUtil.export_list2excel(list_data, mapping_dict)
+
+
     @classmethod
     @classmethod
     async def update_transfer_status_service(
     async def update_transfer_status_service(
         cls,
         cls,

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

@@ -109,6 +109,19 @@ export const AccountAPI = {
       params,
       params,
     });
     });
   },
   },
+
+  exportTransferReport(params: {
+    start_time: string;
+    end_time: string;
+    enterprise_id?: string;
+  }) {
+    return request({
+      url: `${API_PATH}/transfer/export`,
+      method: "get",
+      params,
+      responseType: "blob",
+    });
+  },
 };
 };
 
 
 export interface TransferOutSchema {
 export interface TransferOutSchema {

+ 1 - 1
frontend/src/api/module_system/user.ts

@@ -150,7 +150,7 @@ export interface ForgetPasswordForm {
 export interface RegisterForm {
 export interface RegisterForm {
   sms_code: string;
   sms_code: string;
   mobile: string;
   mobile: string;
-  invite_code: string;
+  // invite_code: string;
   username: string;
   username: string;
   password: string;
   password: string;
   confirmPassword: string;
   confirmPassword: string;

+ 4 - 1
frontend/src/views/module_payment/account/components/TransferDetail.vue

@@ -8,12 +8,15 @@
   >
   >
     <div v-loading="loading" class="transfer-detail">
     <div v-loading="loading" class="transfer-detail">
       <el-descriptions :column="1" border>
       <el-descriptions :column="1" border>
-        <el-descriptions-item label="商家订单号">
+        <el-descriptions-item label="订单号">
           {{ detailData.out_biz_no || '-' }}
           {{ detailData.out_biz_no || '-' }}
         </el-descriptions-item>
         </el-descriptions-item>
         <el-descriptions-item label="支付宝转账单号">
         <el-descriptions-item label="支付宝转账单号">
           {{ detailData.order_no || '-' }}
           {{ detailData.order_no || '-' }}
         </el-descriptions-item>
         </el-descriptions-item>
+        <el-descriptions-item label="三方订单号">
+          {{ detailData.third_biz_no || '-' }}
+        </el-descriptions-item>
         <el-descriptions-item label="企业ID">
         <el-descriptions-item label="企业ID">
           {{ detailData.enterprise_id || '-' }}
           {{ detailData.enterprise_id || '-' }}
         </el-descriptions-item>
         </el-descriptions-item>

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

@@ -266,6 +266,14 @@
             <template #header>
             <template #header>
               <div class="card-header">
               <div class="card-header">
                 <span>转账记录</span>
                 <span>转账记录</span>
+                <!-- <el-button
+                  type="primary"
+                  icon="Download"
+                  class="ml-auto"
+                  @click="showDownloadMenu = true"
+                >
+                  下载报表
+                </el-button> -->
               </div>
               </div>
             </template>
             </template>
             <div class="mb-4">
             <div class="mb-4">
@@ -508,6 +516,43 @@
         </span>
         </span>
       </template>
       </template>
     </el-dialog>
     </el-dialog>
+
+    <!-- 下载报表弹窗 -->
+    <el-dialog title="下载转账报表" v-model="showDownloadMenu" width="500px" :close-on-click-modal="false">
+      <div class="download-options">
+        <div class="option-group">
+          <p class="option-title">快捷时间范围</p>
+          <div class="option-buttons">
+            <el-button
+              v-for="option in quickOptions"
+              :key="option.value"
+              :type="selectedQuickOption === option.value ? 'primary' : ''"
+              @click="selectedQuickOption = option.value"
+            >
+              {{ option.label }}
+            </el-button>
+          </div>
+        </div>
+        <div class="option-group mt-4">
+          <p class="option-title">自定义时间范围</p>
+          <el-date-picker
+            v-model="customDateRange"
+            type="daterange"
+            range-separator="至"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            class="w-full"
+            @change="handleCustomDateChange"
+          />
+        </div>
+      </div>
+      <template #footer>
+        <el-button @click="showDownloadMenu = false">取消</el-button>
+        <el-button type="primary" @click="handleDownload" :loading="downloadLoading">
+          下载报表
+        </el-button>
+      </template>
+    </el-dialog>
   </div>
   </div>
 </template>
 </template>
 
 
@@ -540,6 +585,18 @@ const depositLoading = ref(false);
 const transferLoading = ref(false);
 const transferLoading = ref(false);
 const consumeLoading = ref(false);
 const consumeLoading = ref(false);
 const transferListLoading = ref(false);
 const transferListLoading = ref(false);
+const downloadLoading = ref(false);
+
+const showDownloadMenu = ref(false);
+const selectedQuickOption = ref("today");
+const customDateRange = ref<Date[] | null>(null);
+
+const quickOptions = [
+  { label: "当天", value: "today" },
+  { label: "近3天", value: "3days" },
+  { label: "近15天", value: "15days" },
+  { label: "近30天", value: "30days" },
+];
 
 
 const authorizeFormRef = ref<FormInstance>();
 const authorizeFormRef = ref<FormInstance>();
 const createFormRef = ref<FormInstance>();
 const createFormRef = ref<FormInstance>();
@@ -1294,6 +1351,104 @@ onMounted(async() => {
   }
   }
 });
 });
 
 
+async function handleDownload() {
+  downloadLoading.value = true;
+  try {
+    let start_time: string;
+    let end_time: string;
+
+    if (selectedQuickOption.value !== "custom") {
+      const range = calculateTimeRange(selectedQuickOption.value);
+      start_time = range.start_time;
+      end_time = range.end_time;
+    } else {
+      if (!customDateRange.value || customDateRange.value.length !== 2) {
+        ElMessage.warning("请选择时间范围");
+        return;
+      }
+      const [start, end] = customDateRange.value;
+      start_time = formatDateTime(start, "start");
+      end_time = formatDateTime(end, "end");
+    }
+
+    const res = await AccountAPI.exportTransferReport({
+      start_time,
+      end_time,
+      enterprise_id: currentEnterpriseId.value || undefined,
+    });
+
+    const blob = new Blob([res.data], {
+      type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+    });
+    const url = window.URL.createObjectURL(blob);
+    const a = document.createElement("a");
+    a.href = url;
+    a.download = `转账报表_${start_time}_${end_time}.xlsx`;
+    document.body.appendChild(a);
+    a.click();
+    document.body.removeChild(a);
+    window.URL.revokeObjectURL(url);
+
+    ElMessage.success("报表下载成功");
+    showDownloadMenu.value = false;
+    selectedQuickOption.value = "today";
+    customDateRange.value = null;
+  } catch (error) {
+    ElMessage.error("下载失败,请稍后重试");
+  } finally {
+    downloadLoading.value = false;
+  }
+}
+
+function calculateTimeRange(type: string): { start_time: string; end_time: string } {
+  const now = new Date();
+  const start = new Date();
+
+  switch (type) {
+    case "today":
+      start.setHours(0, 0, 0, 0);
+      break;
+    case "3days":
+      start.setDate(now.getDate() - 3);
+      start.setHours(0, 0, 0, 0);
+      break;
+    case "15days":
+      start.setDate(now.getDate() - 15);
+      start.setHours(0, 0, 0, 0);
+      break;
+    case "30days":
+      start.setDate(now.getDate() - 30);
+      start.setHours(0, 0, 0, 0);
+      break;
+  }
+
+  const end = new Date(now);
+  end.setHours(23, 59, 59, 999);
+
+  return {
+    start_time: formatDateTime(start),
+    end_time: formatDateTime(end),
+  };
+}
+
+function formatDateTime(date: Date, type: string = "start"): string {
+  const year = date.getFullYear();
+  const month = String(date.getMonth() + 1).padStart(2, "0");
+  const day = String(date.getDate()).padStart(2, "0");
+  
+  if (type === "start") {
+    return `${year}-${month}-${day} 00:00:00`;
+  } else {
+    return `${year}-${month}-${day} 23:59:59`;
+  }
+}
+
+function handleCustomDateChange() {
+  if (customDateRange.value && customDateRange.value.length === 2) {
+    selectedQuickOption.value = "custom";
+  }
+}
+
 </script>
 </script>
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>
@@ -1385,4 +1540,21 @@ onMounted(async() => {
     }
     }
   }
   }
 }
 }
+
+.download-options {
+  .option-group {
+    .option-title {
+      font-size: 14px;
+      font-weight: 500;
+      color: #606266;
+      margin-bottom: 12px;
+    }
+
+    .option-buttons {
+      display: flex;
+      flex-wrap: wrap;
+      gap: 8px;
+    }
+  }
+}
 </style>
 </style>

+ 30 - 36
frontend/src/views/module_payment/employee/components/DepartmentDetail.vue

@@ -9,16 +9,16 @@
 
 
       <el-descriptions :column="1" border>
       <el-descriptions :column="1" border>
         <el-descriptions-item label="部门名称">
         <el-descriptions-item label="部门名称">
-          {{ departmentData.name || '-' }}
+          {{ departmentData.name || "-" }}
         </el-descriptions-item>
         </el-descriptions-item>
         <el-descriptions-item label="部门编码">
         <el-descriptions-item label="部门编码">
-          {{ departmentData.code || '-' }}
+          {{ departmentData.code || "-" }}
         </el-descriptions-item>
         </el-descriptions-item>
         <el-descriptions-item label="上级部门">
         <el-descriptions-item label="上级部门">
-          {{ departmentData.parent_name || '-' }}
+          {{ departmentData.parent_name || "-" }}
         </el-descriptions-item>
         </el-descriptions-item>
         <el-descriptions-item label="部门负责人">
         <el-descriptions-item label="部门负责人">
-          {{ departmentData.leader_employee_name || '-' }}
+          {{ departmentData.leader_employee_name || "-" }}
         </el-descriptions-item>
         </el-descriptions-item>
         <el-descriptions-item label="排序值">
         <el-descriptions-item label="排序值">
           {{ departmentData.sort_order || 0 }}
           {{ departmentData.sort_order || 0 }}
@@ -29,10 +29,10 @@
           </el-tag>
           </el-tag>
         </el-descriptions-item>
         </el-descriptions-item>
         <el-descriptions-item label="创建时间">
         <el-descriptions-item label="创建时间">
-          {{ departmentData.created_time || '-' }}
+          {{ departmentData.created_time || "-" }}
         </el-descriptions-item>
         </el-descriptions-item>
         <el-descriptions-item label="更新时间">
         <el-descriptions-item label="更新时间">
-          {{ departmentData.updated_time || '-' }}
+          {{ departmentData.updated_time || "-" }}
         </el-descriptions-item>
         </el-descriptions-item>
       </el-descriptions>
       </el-descriptions>
 
 
@@ -56,13 +56,17 @@
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
-import { ref, onMounted } from 'vue';
-import { ElMessage } from 'element-plus';
-import { useRoute } from 'vue-router';
-import DepartmentAPI, { DEPARTMENT_STATUS_LABEL, DEPARTMENT_STATUS_TAG_TYPE } from '@/api/module_payment/department';
-import EmployeeAPI, { STATUS_LABEL, STATUS_TAG_TYPE } from '@/api/module_payment/employee';
+import { ref, onMounted } from "vue";
+import { ElMessage } from "element-plus";
+import { useRoute } from "vue-router";
+import DepartmentAPI, {
+  DEPARTMENT_STATUS_LABEL,
+  DEPARTMENT_STATUS_TAG_TYPE,
+} from "@/api/module_payment/department";
+import EmployeeAPI, { STATUS_LABEL, STATUS_TAG_TYPE } from "@/api/module_payment/employee";
 
 
 const props = defineProps<{
 const props = defineProps<{
+  enterpriseId: string;
   departmentId?: string;
   departmentId?: string;
 }>();
 }>();
 
 
@@ -77,37 +81,30 @@ const EMPLOYEE_STATUS_LABEL = STATUS_LABEL;
 // 加载部门详情
 // 加载部门详情
 const loadDepartmentDetail = async () => {
 const loadDepartmentDetail = async () => {
   if (!props.departmentId) return;
   if (!props.departmentId) return;
-  
+
   loading.value = true;
   loading.value = true;
   try {
   try {
     // 从路由参数获取企业ID
     // 从路由参数获取企业ID
     const route = useRoute();
     const route = useRoute();
-    const enterpriseId = route.query.enterprise_id as string;
-    
-    if (!enterpriseId) {
-      ElMessage.warning('请先选择企业');
-      return;
-    }
-    
-    const res = await DepartmentAPI.getDepartmentDetail(props.departmentId, enterpriseId);
+    const res = await DepartmentAPI.getDepartmentDetail(props.departmentId, props.enterpriseId);
     if (res.data.code === 200) {
     if (res.data.code === 200) {
       const data = res.data.data;
       const data = res.data.data;
       departmentData.value = {
       departmentData.value = {
         name: data.department.department_name,
         name: data.department.department_name,
         code: data.department.department_code,
         code: data.department.department_code,
-        parent_name: '', // 可以根据parent_department_id查询上级部门名称
+        parent_name: "", // 可以根据parent_department_id查询上级部门名称
         leader_employee_name: data.department.leader_employee_name,
         leader_employee_name: data.department.leader_employee_name,
         sort_order: data.department.sort_order,
         sort_order: data.department.sort_order,
         status: data.department.status,
         status: data.department.status,
         created_time: data.department.created_time,
         created_time: data.department.created_time,
-        updated_time: data.department.updated_time
+        updated_time: data.department.updated_time,
       };
       };
     } else {
     } else {
-      ElMessage.error(res.data.message || '加载部门详情失败');
+      ElMessage.error(res.data.message || "加载部门详情失败");
     }
     }
   } catch (error) {
   } catch (error) {
-    console.error('加载部门详情失败:', error);
-    ElMessage.error('加载部门详情失败');
+    console.error("加载部门详情失败:", error);
+    ElMessage.error("加载部门详情失败");
   } finally {
   } finally {
     loading.value = false;
     loading.value = false;
   }
   }
@@ -116,27 +113,24 @@ const loadDepartmentDetail = async () => {
 // 加载部门员工
 // 加载部门员工
 const loadRelatedEmployees = async () => {
 const loadRelatedEmployees = async () => {
   if (!props.departmentId) return;
   if (!props.departmentId) return;
-  
+
   try {
   try {
     const res = await EmployeeAPI.listEmployee({
     const res = await EmployeeAPI.listEmployee({
       department_id: props.departmentId,
       department_id: props.departmentId,
       page_no: 1,
       page_no: 1,
-      page_size: 100
+      page_size: 100,
     });
     });
     if (res.data.code === 200) {
     if (res.data.code === 200) {
       relatedEmployees.value = res.data.data?.items || [];
       relatedEmployees.value = res.data.data?.items || [];
     }
     }
   } catch (error) {
   } catch (error) {
-    console.error('加载部门员工失败:', error);
+    console.error("加载部门员工失败:", error);
   }
   }
 };
 };
 
 
 onMounted(async () => {
 onMounted(async () => {
   if (props.departmentId) {
   if (props.departmentId) {
-    await Promise.all([
-      loadDepartmentDetail(),
-      loadRelatedEmployees()
-    ]);
+    await Promise.all([loadDepartmentDetail(), loadRelatedEmployees()]);
   }
   }
 });
 });
 </script>
 </script>
@@ -144,20 +138,20 @@ onMounted(async () => {
 <style scoped lang="scss">
 <style scoped lang="scss">
 .department-detail {
 .department-detail {
   padding: 20px 0;
   padding: 20px 0;
-  
+
   .detail-card {
   .detail-card {
     margin-bottom: 20px;
     margin-bottom: 20px;
   }
   }
-  
+
   .card-header {
   .card-header {
     display: flex;
     display: flex;
     justify-content: space-between;
     justify-content: space-between;
     align-items: center;
     align-items: center;
   }
   }
-  
+
   .related-employees {
   .related-employees {
     margin-top: 30px;
     margin-top: 30px;
-    
+
     .section-title {
     .section-title {
       font-size: 16px;
       font-size: 16px;
       font-weight: 600;
       font-weight: 600;

+ 30 - 40
frontend/src/views/module_payment/employee/index.vue

@@ -21,8 +21,7 @@
 
 
           <template #table="{ data, loading, tableRef, onSelectionChange }">
           <template #table="{ data, loading, tableRef, onSelectionChange }">
             <div class="data-table__content">
             <div class="data-table__content">
-              <el-table :ref="tableRef as any" v-loading="loading" :data="data" height="100%" border
-                @selection-change="onSelectionChange">
+              <el-table :ref="tableRef as any" v-loading="loading" :data="data" height="100%" border @selection-change="onSelectionChange">
                 <template #empty>
                 <template #empty>
                   <el-empty :image-size="80" description="暂无数据" />
                   <el-empty :image-size="80" description="暂无数据" />
                 </template>
                 </template>
@@ -30,14 +29,14 @@
                   min-width="55" align="center" />
                   min-width="55" align="center" />
                 <!-- <el-table-column v-if="contentCols.find((col) => col.prop === 'employee_id')?.show" key="employee_id"
                 <!-- <el-table-column v-if="contentCols.find((col) => col.prop === 'employee_id')?.show" key="employee_id"
                   label="员工ID" prop="employee_id" min-width="150" show-overflow-tooltip /> -->
                   label="员工ID" prop="employee_id" min-width="150" show-overflow-tooltip /> -->
-                <el-table-column v-if="contentCols.find((col) => col.prop === 'employee_name')?.show" key="employee_name" label="员工姓名"
-                  prop="employee_name" min-width="120" show-overflow-tooltip />
+                <el-table-column v-if="contentCols.find((col) => col.prop === 'employee_name')?.show"
+                  key="employee_name" label="员工姓名" prop="employee_name" min-width="120" show-overflow-tooltip />
                 <el-table-column v-if="contentCols.find((col) => col.prop === 'employee_no')?.show" key="employee_no"
                 <el-table-column v-if="contentCols.find((col) => col.prop === 'employee_no')?.show" key="employee_no"
                   label="员工工号" prop="employee_no" min-width="120" show-overflow-tooltip />
                   label="员工工号" prop="employee_no" min-width="120" show-overflow-tooltip />
-                <el-table-column v-if="contentCols.find((col) => col.prop === 'employee_mobile')?.show" key="employee_mobile" label="手机号"
-                  prop="employee_mobile" min-width="120" />
-                <el-table-column v-if="contentCols.find((col) => col.prop === 'employee_email')?.show" key="employee_email" label="邮箱"
-                  prop="employee_email" min-width="150" show-overflow-tooltip />
+                <el-table-column v-if="contentCols.find((col) => col.prop === 'employee_mobile')?.show"
+                  key="employee_mobile" label="手机号" prop="employee_mobile" min-width="120" />
+                <el-table-column v-if="contentCols.find((col) => col.prop === 'employee_email')?.show"
+                  key="employee_email" label="邮箱" prop="employee_email" min-width="150" show-overflow-tooltip />
                 <el-table-column v-if="contentCols.find((col) => col.prop === 'status')?.show" key="status" label="激活状态"
                 <el-table-column v-if="contentCols.find((col) => col.prop === 'status')?.show" key="status" label="激活状态"
                   prop="status" min-width="100">
                   prop="status" min-width="100">
                   <template #default="scope">
                   <template #default="scope">
@@ -101,13 +100,13 @@
                   prop="name" min-width="150" show-overflow-tooltip />
                   prop="name" min-width="150" show-overflow-tooltip />
                 <el-table-column v-if="deptContentCols.find((col) => col.prop === 'code')?.show" key="code" label="部门编码"
                 <el-table-column v-if="deptContentCols.find((col) => col.prop === 'code')?.show" key="code" label="部门编码"
                   prop="code" min-width="120" show-overflow-tooltip />
                   prop="code" min-width="120" show-overflow-tooltip />
-                <el-table-column v-if="deptContentCols.find((col) => col.prop === 'created_time')?.show" key="created_time"
-                  label="创建时间" prop="created_time" min-width="160" sortable />
+                <el-table-column v-if="deptContentCols.find((col) => col.prop === 'created_time')?.show"
+                  key="created_time" label="创建时间" prop="created_time" min-width="160" sortable />
                 <el-table-column v-if="deptContentCols.find((col) => col.prop === 'operation')?.show" fixed="right"
                 <el-table-column v-if="deptContentCols.find((col) => col.prop === 'operation')?.show" fixed="right"
                   label="操作" align="center" min-width="160">
                   label="操作" align="center" min-width="160">
                   <template #default="scope">
                   <template #default="scope">
-                    <el-button v-hasPerm="['module_payment:department:detail']" type="info" size="small" link :icon="View"
-                      @click="handleOpenDeptDialog('detail', scope.row.department_id)">
+                    <el-button v-hasPerm="['module_payment:department:detail']" type="info" size="small" link
+                      :icon="View" @click="handleOpenDeptDialog('detail', scope.row.department_id)">
                       详情
                       详情
                     </el-button>
                     </el-button>
                     <el-button v-hasPerm="['module_payment:department:update']" type="primary" size="small" link
                     <el-button v-hasPerm="['module_payment:department:update']" type="primary" size="small" link
@@ -133,10 +132,10 @@
           <EmployeeDetail :employee-id="currentEmployeeId" :enterprise-id="currentEnterpriseId" />
           <EmployeeDetail :employee-id="currentEmployeeId" :enterprise-id="currentEnterpriseId" />
         </template>
         </template>
         <template v-else-if="dialogVisible.entity === 'department'">
         <template v-else-if="dialogVisible.entity === 'department'">
-          <DepartmentDetail :department-id="currentDepartmentId" />
+          <DepartmentDetail :department-id="currentDepartmentId" :enterprise-id="currentEnterpriseId" />
         </template>
         </template>
       </template>
       </template>
-      
+
       <template v-else>
       <template v-else>
         <template v-if="dialogVisible.entity === 'employee'">
         <template v-if="dialogVisible.entity === 'employee'">
           <EmployeeForm ref="formRef" :type="dialogVisible.type" :employee-id="currentEmployeeId"
           <EmployeeForm ref="formRef" :type="dialogVisible.type" :employee-id="currentEmployeeId"
@@ -154,7 +153,8 @@
             <el-button v-if="dialogVisible.type !== 'detail'" @click="handleResetForm">
             <el-button v-if="dialogVisible.type !== 'detail'" @click="handleResetForm">
               重置
               重置
             </el-button>
             </el-button>
-            <el-button v-if="dialogVisible.type !== 'detail' && dialogVisible.type === 'create'" type="primary" @click="handleSaveAndAddNext">
+            <el-button v-if="dialogVisible.type !== 'detail' && dialogVisible.type === 'create'" type="primary"
+              @click="handleSaveAndAddNext">
               保存并添加下一个
               保存并添加下一个
             </el-button>
             </el-button>
             <el-button v-if="dialogVisible.type !== 'detail'" type="primary" @click="handleSubmit">
             <el-button v-if="dialogVisible.type !== 'detail'" type="primary" @click="handleSubmit">
@@ -171,19 +171,15 @@
               保存并添加下一个
               保存并添加下一个
             </el-button>
             </el-button>
             <el-button v-else type="primary" @click="handleCloseDialog">确定</el-button>
             <el-button v-else type="primary" @click="handleCloseDialog">确定</el-button>
-          </template>   
+          </template>
           <!-- <el-button @click="handleCloseDialog">取消</el-button> -->
           <!-- <el-button @click="handleCloseDialog">取消</el-button> -->
         </div>
         </div>
       </template>
       </template>
     </EnhancedDialog>
     </EnhancedDialog>
 
 
     <!-- 签约链接对话框 -->
     <!-- 签约链接对话框 -->
-    <el-dialog
-      v-model="inviteDialogVisible.visible"
-      :title="inviteDialogVisible.title"
-      width="600px"
-      @close="inviteDialogVisible.data = null"
-    >
+    <el-dialog v-model="inviteDialogVisible.visible" :title="inviteDialogVisible.title" width="600px"
+      @close="inviteDialogVisible.data = null">
       <div v-if="inviteDialogVisible.data" class="invite-link-container">
       <div v-if="inviteDialogVisible.data" class="invite-link-container">
         <el-descriptions :column="1" border>
         <el-descriptions :column="1" border>
           <el-descriptions-item label="邀请链接">
           <el-descriptions-item label="邀请链接">
@@ -196,7 +192,7 @@
               </el-button>
               </el-button>
             </div>
             </div>
           </el-descriptions-item>
           </el-descriptions-item>
-          
+
           <!-- <el-descriptions-item label="小程序签约二维码">
           <!-- <el-descriptions-item label="小程序签约二维码">
             <div class="qrcode-item">
             <div class="qrcode-item">
               <div v-if="miniAppQrCode" class="qrcode-container">
               <div v-if="miniAppQrCode" class="qrcode-container">
@@ -259,7 +255,6 @@ import { useRoute } from "vue-router";
 import { ref, reactive, computed } from "vue";
 import { ref, reactive, computed } from "vue";
 import { ElMessage, ElMessageBox } from "element-plus";
 import { ElMessage, ElMessageBox } from "element-plus";
 import { useEnterpriseStore } from "@/store/modules/enterprise.store";
 import { useEnterpriseStore } from "@/store/modules/enterprise.store";
-import QRCode from "qrcode";
 
 
 const route = useRoute();
 const route = useRoute();
 
 
@@ -316,15 +311,10 @@ const inviteDialogVisible = reactive({
 
 
 const useEnterprise = useEnterpriseStore();
 const useEnterprise = useEnterpriseStore();
 
 
-const currentEmployeeId = ref<string>('');
-const currentDepartmentId = ref<string>('');
+const currentEmployeeId = ref<string>("");
+const currentDepartmentId = ref<string>("");
 const currentEnterpriseId = computed(() => useEnterprise.getCurrentEnterprise?.enterprise_id || "");
 const currentEnterpriseId = computed(() => useEnterprise.getCurrentEnterprise?.enterprise_id || "");
 
 
-// 小程序链接二维码
-const miniAppQrCode = computed(() => {
-  return '';
-});
-
 // 部门搜索配置
 // 部门搜索配置
 const deptSearchConfig = reactive<ISearchConfig>({
 const deptSearchConfig = reactive<ISearchConfig>({
   permPrefix: "module_payment:department",
   permPrefix: "module_payment:department",
@@ -339,12 +329,12 @@ const deptSearchConfig = reactive<ISearchConfig>({
       type: "input",
       type: "input",
       attrs: { placeholder: "请输入部门名称", clearable: true },
       attrs: { placeholder: "请输入部门名称", clearable: true },
     },
     },
-    {
-      prop: "code",
-      label: "部门编码",
-      type: "input",
-      attrs: { placeholder: "请输入部门编码", clearable: true },
-    },
+    // {
+    //   prop: "code",
+    //   label: "部门编码",
+    //   type: "input",
+    //   attrs: { placeholder: "请输入部门编码", clearable: true },
+    // },
     // {
     // {
     //   prop: "status",
     //   prop: "status",
     //   label: "状态",
     //   label: "状态",
@@ -536,7 +526,7 @@ async function handleDeleteDepartment(departmentId: string, departmentName: stri
       ElMessage.warning("请先选择企业");
       ElMessage.warning("请先选择企业");
       return;
       return;
     }
     }
-    
+
     await ElMessageBox.confirm(
     await ElMessageBox.confirm(
       `确定要删除部门「${departmentName}」吗?`,
       `确定要删除部门「${departmentName}」吗?`,
       "删除部门",
       "删除部门",
@@ -546,7 +536,7 @@ async function handleDeleteDepartment(departmentId: string, departmentName: stri
         type: "warning"
         type: "warning"
       }
       }
     );
     );
-    
+
     const res = await DepartmentAPI.deleteDepartment(departmentId, enterpriseId);
     const res = await DepartmentAPI.deleteDepartment(departmentId, enterpriseId);
     if (res.data.code === 200) {
     if (res.data.code === 200) {
       ElMessage.success("删除部门成功");
       ElMessage.success("删除部门成功");
@@ -616,7 +606,7 @@ async function copyInviteLink(text: string) {
     display: flex;
     display: flex;
     align-items: center;
     align-items: center;
     gap: 8px;
     gap: 8px;
-    
+
     .el-link {
     .el-link {
       flex: 1;
       flex: 1;
       word-break: break-all;
       word-break: break-all;

+ 2 - 2
frontend/src/views/module_payment/institution/index.vue

@@ -234,11 +234,11 @@ const categoryTabs = [
   // { key: "gas", label: "加油", icon: "Fuel", scenes: [{ label: "公务车加油", value: "official_gas" }, { label: "私家车补贴", value: "private_gas" }] },
   // { key: "gas", label: "加油", icon: "Fuel", scenes: [{ label: "公务车加油", value: "official_gas" }, { label: "私家车补贴", value: "private_gas" }] },
   // { key: "medical", label: "医疗", icon: "Stethoscope", scenes: [{ label: "体检", value: "medical_checkup" }, { label: "门诊报销", value: "outpatient" }, { label: "住院报销", value: "hospitalization" }] },
   // { key: "medical", label: "医疗", icon: "Stethoscope", scenes: [{ label: "体检", value: "medical_checkup" }, { label: "门诊报销", value: "outpatient" }, { label: "住院报销", value: "hospitalization" }] },
   // { key: "advertising", label: "电商广告充值", icon: "Monitor", scenes: [{ label: "平台推广", value: "platform_promo" }, { label: "品牌广告", value: "brand_ad" }, { label: "促销活动", value: "promotion" }] },
   // { key: "advertising", label: "电商广告充值", icon: "Monitor", scenes: [{ label: "平台推广", value: "platform_promo" }, { label: "品牌广告", value: "brand_ad" }, { label: "促销活动", value: "promotion" }] },
-  { key: "default", label: "默认", icon: "Box", scenes: [{ label: "通用", value: "common" }] },
+  { key: "DEFAULT", label: "默认", icon: "Box", scenes: [{ label: "通用", value: "common" }] },
 ];
 ];
 
 
 // 当前激活的分类
 // 当前激活的分类
-const activeCategory = ref("default");
+const activeCategory = ref("DEFAULT");
 
 
 // 当前分类对应的场景列表
 // 当前分类对应的场景列表
 const currentScenes = computed(() => {
 const currentScenes = computed(() => {

+ 9 - 10
frontend/src/views/module_system/auth/components/Register.vue

@@ -3,13 +3,13 @@
     <h3 text-center m-0 mb-20px>{{ t("login.reg") }}</h3>
     <h3 text-center m-0 mb-20px>{{ t("login.reg") }}</h3>
     <el-form ref="formRef" :model="model" :rules="rules" size="large" label-suffix=":">
     <el-form ref="formRef" :model="model" :rules="rules" size="large" label-suffix=":">
       <!-- 邀请码 -->
       <!-- 邀请码 -->
-      <el-form-item prop="invite_code">
+      <!-- <el-form-item prop="invite_code">
         <el-input v-model.trim="model.invite_code" placeholder="请输入邀请码" clearable>
         <el-input v-model.trim="model.invite_code" placeholder="请输入邀请码" clearable>
           <template #prefix>
           <template #prefix>
             <el-icon><SetUp /></el-icon>
             <el-icon><SetUp /></el-icon>
           </template>
           </template>
         </el-input>
         </el-input>
-      </el-form-item>
+      </el-form-item> -->
 
 
       <el-form-item prop="mobile">
       <el-form-item prop="mobile">
         <el-input v-model.trim="model.mobile" placeholder="请输入手机号" clearable>
         <el-input v-model.trim="model.mobile" placeholder="请输入手机号" clearable>
@@ -130,7 +130,6 @@ const smsCountdown = ref(0);
 
 
 
 
 const model = ref<RegisterForm>({
 const model = ref<RegisterForm>({
-  invite_code: "",
   mobile: "",
   mobile: "",
   sms_code: "",
   sms_code: "",
   username: "",
   username: "",
@@ -140,13 +139,13 @@ const model = ref<RegisterForm>({
 
 
 const rules = computed(() => {
 const rules = computed(() => {
   return {
   return {
-    invite_code: [
-      {
-        required: true,
-        trigger: "blur",
-        message: "请输入邀请码",
-      },
-    ],
+    // invite_code: [
+    //   {
+    //     required: true,
+    //     trigger: "blur",
+    //     message: "请输入邀请码",
+    //   },
+    // ],
     // 验证国内手机号格式
     // 验证国内手机号格式
     mobile: [
     mobile: [
       {
       {