diff --git a/src/api/payments/index.ts b/src/api/payments/index.ts index e5daba7..95d3bb1 100644 --- a/src/api/payments/index.ts +++ b/src/api/payments/index.ts @@ -5,16 +5,27 @@ import { get } from '@/utils/request'; import { USE_MOCK, MOCK_DELAY } from '@/config/mock'; import { buildMockPaymentFlowPage } from '@/config/mock/paymentFlow'; -import type { PaymentFlowQueryParams, PaymentFlowVO, PageData, ApiResult } from './types'; +import type { + PaymentFlowQueryParams, + PaymentFlowVO, + PaymentFlowPageData, + ApiResult, +} from './types'; -export type { PaymentFlowVO, PaymentFlowQueryParams, PageData, ApiResult } from './types'; +export type { + PaymentFlowVO, + PaymentFlowQueryParams, + PaymentFlowPageData, + PaymentFlowExData, + ApiResult, +} from './types'; const delay = (ms: number) => new Promise((r) => setTimeout(r, ms)); /** GET /admin/finance/paymentFlow/page — 支付流水分页 */ export async function getPaymentFlowList( params: PaymentFlowQueryParams, -): Promise>> { +): Promise> { if (USE_MOCK) { await delay(MOCK_DELAY); const page = Number(params.page) || 1; diff --git a/src/api/payments/types.ts b/src/api/payments/types.ts index 4b52998..48b433f 100644 --- a/src/api/payments/types.ts +++ b/src/api/payments/types.ts @@ -41,6 +41,22 @@ export interface PageData { total: number; list: T[]; } + +/** 支付流水分页扩展汇总(与 total 同级) */ +export interface PaymentFlowExData { + /** 总支付金额 */ + totalAmount: string; + /** 总退款金额 */ + totalRefundAmount: string; +} + +/** 支付流水分页响应 */ +export interface PaymentFlowPageData { + total: number; + list: PaymentFlowVO[]; + exData: PaymentFlowExData; +} + export interface ApiResult { code: number; msg: string; diff --git a/src/api/roles/types.ts b/src/api/roles/types.ts index 7dc35f7..b4b6219 100644 --- a/src/api/roles/types.ts +++ b/src/api/roles/types.ts @@ -41,6 +41,19 @@ export interface RoleUsageUserQueryParams { roleId?: string; } +/** 保存角色 — POST /admin/sys/role/save */ +export interface RoleSaveParams { + name: string; + menuIds: string[]; +} + +/** 更新角色 — POST /admin/sys/role/update */ +export interface RoleUpdateParams { + id: string; + name: string; + menuIds: string[]; +} + export interface PageData { total: number; list: T[]; diff --git a/src/api/users/index.ts b/src/api/users/index.ts index d76ac08..1ab6212 100644 --- a/src/api/users/index.ts +++ b/src/api/users/index.ts @@ -28,7 +28,7 @@ export type { const delay = (ms: number) => new Promise((r) => setTimeout(r, ms)); -/** GET /sys/user/page — 用户分页 */ +/** GET /admin/sys/user/page — 用户分页 */ export async function getUserList( params: UserListQueryParams, ): Promise>> { @@ -38,7 +38,7 @@ export async function getUserList( const limit = Number(params.limit) || 10; return { code: 200, msg: 'success', data: buildMockUserListPage(page, limit) }; } - return get('/sys/user/page', params as Record); + return get('/admin/sys/user/page', params as Record); } /** POST /sys/user/save — 新增用户 */ diff --git a/src/config/mock/paymentFlow.ts b/src/config/mock/paymentFlow.ts index 1ddc00e..e48463d 100644 --- a/src/config/mock/paymentFlow.ts +++ b/src/config/mock/paymentFlow.ts @@ -2,7 +2,7 @@ * 支付流水假数据 * 对应接口:GET /admin/finance/paymentFlow/page */ -import type { PaymentFlowVO, PaymentFlowQueryParams, PageData } from '@/api/payments'; +import type { PaymentFlowVO, PaymentFlowQueryParams, PaymentFlowPageData } from '@/api/payments'; const MOCK_LIST: PaymentFlowVO[] = [ { @@ -127,7 +127,7 @@ export function buildMockPaymentFlowPage( page: number, limit: number, params: PaymentFlowQueryParams, -): PageData { +): PaymentFlowPageData { let filtered = [...MOCK_LIST]; if (params.nickname) { @@ -143,7 +143,22 @@ export function buildMockPaymentFlowPage( inDateRange(item.createDate, params.createDateBegin, params.createDateEnd), ); + let totalAmount = 0; + let totalRefundAmount = 0; + for (const item of filtered) { + const amt = Number(item.amount) || 0; + if (item.type === 1) totalAmount += amt; + else if (item.type === 2) totalRefundAmount += amt; + } + const total = filtered.length; const start = (page - 1) * limit; - return { total, list: filtered.slice(start, start + limit) }; + return { + total, + list: filtered.slice(start, start + limit), + exData: { + totalAmount: totalAmount.toFixed(2), + totalRefundAmount: totalRefundAmount.toFixed(2), + }, + }; } diff --git a/src/pages/finance/payments/index.tsx b/src/pages/finance/payments/index.tsx index f3d2162..dfe6a4f 100644 --- a/src/pages/finance/payments/index.tsx +++ b/src/pages/finance/payments/index.tsx @@ -83,11 +83,11 @@ export default defineComponent({
总支付金额: - {summary.value.totalPay}元 + {summary.value.totalAmount}元 总退款金额: - {summary.value.totalRefund}元 + {summary.value.totalRefundAmount}元
diff --git a/src/pages/finance/payments/model/services.ts b/src/pages/finance/payments/model/services.ts index 7b1ced6..905aae6 100644 --- a/src/pages/finance/payments/model/services.ts +++ b/src/pages/finance/payments/model/services.ts @@ -8,21 +8,22 @@ import { buildMockPaymentFlowPage } from '@/config/mock/paymentFlow'; import type { PaymentFlowQueryParams, PaymentFlowVO, - PageData, + PaymentFlowPageData, ApiResult, } from '@/api/payments/types'; export type { PaymentFlowVO, PaymentFlowQueryParams, - PageData, + PaymentFlowPageData, + PaymentFlowExData, ApiResult, } from '@/api/payments/types'; // ============================================================ // URL 常量 // ============================================================ -const paymentFlowList = '/finance/paymentFlow/page'; +const paymentFlowList = '/admin/finance/paymentFlow/page'; const delay = (ms: number) => new Promise((r) => setTimeout(r, ms)); @@ -33,7 +34,7 @@ const delay = (ms: number) => new Promise((r) => setTimeout(r, ms)); /** 支付流水分页 */ export async function getPaymentFlowList( params: PaymentFlowQueryParams, -): Promise>> { +): Promise> { if (USE_MOCK) { await delay(MOCK_DELAY); const page = Number(params.page) || 1; diff --git a/src/pages/finance/payments/model/usePaymentsModel.ts b/src/pages/finance/payments/model/usePaymentsModel.ts index 45ed3ed..71d08f6 100644 --- a/src/pages/finance/payments/model/usePaymentsModel.ts +++ b/src/pages/finance/payments/model/usePaymentsModel.ts @@ -41,7 +41,7 @@ export function usePaymentsModel() { ); // ===== 汇总 ===== - const [summary, setSummary] = useState({ totalPay: '0.00', totalRefund: '0.00' }); + const [summary, setSummary] = useState({ totalAmount: '0.00', totalRefundAmount: '0.00' }); // ===== 表格状态 ===== const [loading, setLoading] = useState(false); @@ -104,21 +104,14 @@ export function usePaymentsModel() { setLoading(true); try { const queryParams = buildQueryParams(); - console.log('支付流水查询参数:', queryParams); const res = await getPaymentFlowList(queryParams); if (res.code == 200) { - console.log('支付流水查询结果:', { total: res.data.total, count: res.data.list.length }); setDataSource(res.data.list); setPagination({ ...pagination.value, total: res.data.total }); - // 汇总:type=1 金额为收入,type=2 金额为退款 - let totalPay = 0; - let totalRefund = 0; - for (const item of res.data.list) { - const amt = Number(item.amount) || 0; - if (item.type === 1) totalPay += amt; - else if (item.type === 2) totalRefund += amt; - } - setSummary({ totalPay: totalPay.toFixed(2), totalRefund: totalRefund.toFixed(2) }); + setSummary({ + totalAmount: res.data.exData?.totalAmount ?? '0.00', + totalRefundAmount: res.data.exData?.totalRefundAmount ?? '0.00', + }); } } catch { // 网络层已统一提示 @@ -134,7 +127,7 @@ export function usePaymentsModel() { filterForm.type = ''; setPagination({ current: 1, pageSize: 10, total: 0 }); setDataSource([]); - setSummary({ totalPay: '0.00', totalRefund: '0.00' }); + setSummary({ totalAmount: '0.00', totalRefundAmount: '0.00' }); setTimeout(() => handleSearch(), 350); }, 500); diff --git a/src/pages/finance/withdraw/components/WithdrawDetailModal.tsx b/src/pages/finance/withdraw/components/WithdrawDetailModal.tsx index 9e83023..8cd54f8 100644 --- a/src/pages/finance/withdraw/components/WithdrawDetailModal.tsx +++ b/src/pages/finance/withdraw/components/WithdrawDetailModal.tsx @@ -2,7 +2,7 @@ import { defineComponent, reactive, ref, watch } from 'vue'; import { Modal, Radio, Input, Button, Upload, Image, Spin, message } from 'ant-design-vue'; import { PlusOutlined } from '@ant-design/icons-vue'; import { getWithdrawInfo, postWithdrawAudit, type WithdrawInfoVO } from '../model/services'; -import { AUDIT_STATUS_MAP, PAY_STATUS_MAP } from '../model/useWithdrawModel'; +import { getAuditStatusText, getPayStatusText } from '../model/useWithdrawModel'; import styles from './WithdrawDetailModal.module.less'; const { TextArea } = Input; @@ -135,8 +135,8 @@ export default defineComponent({ {renderItem('费率:', `${(Number(d.feeRate) * 100).toFixed(2)}%`)} {renderItem('手续费:', `¥${d.feeAmount}`)} {renderItem('到账金额:', `¥${d.receivedAmount}`, true)} - {renderItem('审核状态:', AUDIT_STATUS_MAP[d.auditStatus] ?? '-', true)} - {renderItem('列账状态:', PAY_STATUS_MAP[d.payStatus] ?? '-')} + {renderItem('审核状态:', getAuditStatusText(d.auditStatus), true)} + {renderItem('列账状态:', getPayStatusText(d.payStatus))}
diff --git a/src/pages/finance/withdraw/index.tsx b/src/pages/finance/withdraw/index.tsx index 715c713..233fa1b 100644 --- a/src/pages/finance/withdraw/index.tsx +++ b/src/pages/finance/withdraw/index.tsx @@ -1,6 +1,6 @@ import { defineComponent, onMounted } from 'vue'; import { Button, Input, Table, Form, Space, Pagination, Select } from 'ant-design-vue'; -import { useWithdrawModel, AUDIT_STATUS_MAP, PAY_STATUS_MAP } from './model/useWithdrawModel'; +import { useWithdrawModel, renderAuditStatus, renderPayStatus } from './model/useWithdrawModel'; import { useContainerSize } from '@/hooks'; import WithdrawDetailModal from './components/WithdrawDetailModal'; import pageStyles from '@/assets/styles/pageLayout.module.less'; @@ -21,10 +21,10 @@ function renderBodyCell({ onView: (record: any) => void; }) { if (column.key === 'auditStatus') { - return {AUDIT_STATUS_MAP[record.auditStatus] || record.auditStatus || '-'}; + return renderAuditStatus(record.auditStatus); } if (column.key === 'payStatus') { - return {PAY_STATUS_MAP[record.payStatus] ?? '-'}; + return renderPayStatus(record.payStatus); } if (column.key === 'action') { // auditStatus=0(待审核)→ 显示「审核」,其他 → 显示「查看」 diff --git a/src/pages/finance/withdraw/model/useWithdrawModel.ts b/src/pages/finance/withdraw/model/useWithdrawModel.ts index 43410f7..a68e784 100644 --- a/src/pages/finance/withdraw/model/useWithdrawModel.ts +++ b/src/pages/finance/withdraw/model/useWithdrawModel.ts @@ -1,4 +1,5 @@ -import { computed, reactive, toRef, Ref } from 'vue'; +import { computed, reactive, toRef, Ref, h } from 'vue'; +import { StatusTag, type StatusTagTone } from '@/components'; import { useState, useDebounce, useThrottleFn } from '@/hooks'; import { getWithdrawList, type WithdrawVO, type WithdrawQueryParams } from './services'; @@ -22,20 +23,45 @@ export const PAY_STATUS_OPTIONS = [ { value: '2', label: '支付失败' }, ] as const; -/** 审核状态文案映射 */ -export const AUDIT_STATUS_MAP: Record = { - 0: '待审核', - 1: '审核通过', - 2: '审核驳回', +/** 审核状态文案 + 色调映射 */ +const AUDIT_STATUS_MAP: Record = { + 0: { label: '待审核', tone: 'warning' }, + 1: { label: '审核通过', tone: 'success' }, + 2: { label: '审核驳回', tone: 'danger' }, }; -/** 到账状态文案映射 */ -export const PAY_STATUS_MAP: Record = { - 0: '未支付', - 1: '支付成功', - 2: '支付失败', +/** 到账状态文案 + 色调映射 */ +const PAY_STATUS_MAP: Record = { + 0: { label: '未支付', tone: 'default' }, + 1: { label: '支付成功', tone: 'success' }, + 2: { label: '支付失败', tone: 'danger' }, }; +/** 渲染审核状态 StatusTag */ +export function renderAuditStatus(status: number) { + const info = AUDIT_STATUS_MAP[status] || { + label: String(status ?? '-'), + tone: 'default' as const, + }; + return h(StatusTag, { label: info.label, tone: info.tone }); +} + +/** 渲染到账状态 StatusTag */ +export function renderPayStatus(status: number) { + const info = PAY_STATUS_MAP[status] || { label: String(status ?? '-'), tone: 'default' as const }; + return h(StatusTag, { label: info.label, tone: info.tone }); +} + +/** 获取审核状态纯文本(详情弹窗用) */ +export function getAuditStatusText(status: number): string { + return AUDIT_STATUS_MAP[status]?.label ?? String(status ?? '-'); +} + +/** 获取到账状态纯文本(详情弹窗用) */ +export function getPayStatusText(status: number): string { + return PAY_STATUS_MAP[status]?.label ?? String(status ?? '-'); +} + // ============================================================ // Model // ============================================================ diff --git a/src/pages/system/roles/model/services.ts b/src/pages/system/roles/model/services.ts index 8fe963e..6a28944 100644 --- a/src/pages/system/roles/model/services.ts +++ b/src/pages/system/roles/model/services.ts @@ -3,13 +3,11 @@ * 该页面使用的所有接口集中管理 */ import { get, post } from '@/utils/request'; -import { USE_MOCK, MOCK_DELAY } from '@/config/mock'; -import { buildMockRoleListPage } from '@/config/mock/roleList'; -import { buildMockRoleUsageUserPage } from '@/config/mock/roleUsageUser'; -import { buildMockPermissionTree } from '@/config/mock/permissionTree'; import type { RoleListQueryParams, RoleUsageUserQueryParams, + RoleSaveParams, + RoleUpdateParams, TournamentAdminRolePageVO, RoleUsageUserVO, PermissionTreeNode, @@ -22,6 +20,8 @@ export type { RoleUsageUserVO, RoleListQueryParams, RoleUsageUserQueryParams, + RoleSaveParams, + RoleUpdateParams, PermissionTreeNode, PageData, ApiResult, @@ -30,56 +30,49 @@ export type { // ============================================================ // URL 常量 // ============================================================ -const roleList = '/sys/role/page'; -const roleUsageUserList = '/sys/role/usageUserPage'; -const rolePermissionList = '/sys/role/permissionList'; -const roleDelete = '/sys/role/del'; - -const delay = (ms: number) => new Promise((r) => setTimeout(r, ms)); +const roleList = '/admin/sys/role/page'; +const roleSave = '/admin/sys/role/save'; +const roleUpdate = '/admin/sys/role/update'; +const roleUsageUserList = '/admin/sys/role/usageUserPage'; +const rolePermissionList = '/admin/sys/role/permissionList'; +const roleDelete = '/admin/sys/role/del'; // ============================================================ // API 函数 // ============================================================ -/** 角色列表分页 */ -export async function getRoleList( +/** 角色列表分页 — GET /admin/sys/role/page */ +export function getRoleList( params: RoleListQueryParams, ): Promise>> { - if (USE_MOCK) { - await delay(MOCK_DELAY); - const page = Number(params.page) || 1; - const limit = Number(params.limit) || 10; - return { code: 200, msg: 'success', data: buildMockRoleListPage(page, limit) }; - } return get(roleList, params as Record); } -/** 角色下用户列表分页 */ -export async function getRoleUsageUserList( +/** 新增角色 — POST /admin/sys/role/save */ +export function saveRole(params: RoleSaveParams): Promise>> { + return post(roleSave, params); +} + +/** 更新角色 — POST /admin/sys/role/update */ +export function updateRole(params: RoleUpdateParams): Promise>> { + return post(roleUpdate, params); +} + +/** 角色下用户列表分页 — GET /admin/sys/role/usageUserPage */ +export function getRoleUsageUserList( params: RoleUsageUserQueryParams, ): Promise>> { - if (USE_MOCK) { - await delay(MOCK_DELAY); - const page = Number(params.page) || 1; - const limit = Number(params.limit) || 10; - return { code: 200, msg: 'success', data: buildMockRoleUsageUserPage(page, limit) }; - } return get(roleUsageUserList, params as Record); } -/** 角色权限树 */ -export async function getPermissionTree( +/** 角色权限树 — GET /admin/sys/role/permissionList */ +export function getPermissionTree( roleId: number | string, ): Promise> { - if (USE_MOCK) { - await delay(MOCK_DELAY); - const id = Number(roleId) || 0; - return { code: 200, msg: 'success', data: buildMockPermissionTree(id) }; - } return get(rolePermissionList, { roleId: String(roleId) }); } -/** 删除角色 */ +/** 删除角色 — POST /admin/sys/role/del */ export function deleteRole(id: number): Promise> { return post(roleDelete, { id }); } diff --git a/src/pages/system/roles/model/useRoleModel.ts b/src/pages/system/roles/model/useRoleModel.ts index 7355ebe..65f2452 100644 --- a/src/pages/system/roles/model/useRoleModel.ts +++ b/src/pages/system/roles/model/useRoleModel.ts @@ -3,6 +3,8 @@ import { message } from 'ant-design-vue'; import { useState, useDebounce, useThrottleFn } from '@/hooks'; import { getRoleList, + saveRole, + updateRole, deleteRole, type TournamentAdminRolePageVO, type RoleListQueryParams, @@ -125,11 +127,31 @@ export function useRoleModel() { if (formSubmitting.value) return; setFormSubmitting(true); try { - console.log(isEdit.value ? '编辑角色' : '新增角色', formPayload); - // TODO: 替换为真实 API 调用(/sys/role/save、/sys/role/update) - message.success(isEdit.value ? '编辑成功' : '新增成功'); - handleCloseForm(); - handleSearch(); + // 从叶节点权限中提取选中的 menuIds + const menuIds: string[] = (formPayload.leafPermissions || []) + .filter((item: any) => item.selected === true) + .map((item: any) => String(item.id)); + + let res: any; + if (isEdit.value) { + res = await updateRole({ + id: String(formPayload.roleId), + name: formPayload.roleName, + menuIds, + }); + } else { + res = await saveRole({ + name: formPayload.roleName, + menuIds, + }); + } + if (res.code == 200) { + message.success(isEdit.value ? '编辑成功' : '新增成功'); + handleCloseForm(); + handleSearch(); + } else { + message.error(res.msg || '操作失败'); + } } catch { // 网络层已统一提示,不再重复 message.error } finally { diff --git a/src/pages/system/users/model/services.ts b/src/pages/system/users/model/services.ts index d850d85..bd3362a 100644 --- a/src/pages/system/users/model/services.ts +++ b/src/pages/system/users/model/services.ts @@ -3,7 +3,6 @@ * 该页面使用的所有接口集中管理 */ import { get, post } from '@/utils/request'; -import { fetchPermissions } from '@/api/menu'; import type { UserListQueryParams, UserSaveParams, @@ -29,6 +28,7 @@ export type { // ============================================================ // URL 常量 // ============================================================ +const userPage = '/admin/sys/user/page'; const userSave = '/sys/user/save'; const userUpdate = '/sys/user/update'; const userActive = '/sys/user/active'; @@ -39,47 +39,14 @@ const userUpdatePwd = '/sys/user/updatepwd'; // ============================================================ /** - * 用户列表 - 通过 fetchPermissions 接口获取用户权限列表 - * 接口: GET /admin/sys/role/permissionList - * 返回权限编码列表,前端做分页处理 + * 用户列表分页 + * 接口: GET /admin/sys/user/page + * 参数: page, limit, text(姓名/手机号), roleId(角色ID), status(0=停用,1=正常) */ -export async function getUserList( - _params: UserListQueryParams, +export function getUserList( + params: UserListQueryParams, ): Promise>> { - // 调用 fetchPermissions 获取用户权限数据 - const list = await fetchPermissions(); - - // 将权限编码字符串转为类用户列表格式,支持分页 - const page = Number(_params.page) || 1; - const limit = Number(_params.limit) || 10; - const start = (page - 1) * limit; - const end = start + limit; - const pagedList = list.slice(start, end); - - // 将权限编码映射为用户 VO 格式(后端返回的权限码可能包含用户信息) - const userListData: TournamentAdminUserVO[] = pagedList.map((item, index) => { - // 如果 item 是对象则直接使用,如果是字符串则构造基本结构 - if (typeof item === 'object' && item !== null) { - return item as unknown as TournamentAdminUserVO; - } - return { - id: String(start + index + 1), - realName: String(item), - phone: '', - roleName: '', - status: '1', - createTime: '', - } as TournamentAdminUserVO; - }); - - return { - code: 200, - msg: 'success', - data: { - total: list.length, - list: userListData, - }, - }; + return get(userPage, params as Record); } /** 新增用户 */