- 新增家庭共享订阅管理 - 新增用户邀请统计 - 新增签名和订阅模式设置表单 - 更新 API 服务层和国际化文件 - UI 组件优化(enhanced-input、pro-table)
This commit is contained in:
@@ -30,7 +30,8 @@ export function EnhancedInput<T = string>({
|
||||
...props
|
||||
}: EnhancedInputProps<T>) {
|
||||
const getProcessedValue = (inputValue: unknown) => {
|
||||
if (inputValue === "" || inputValue === 0 || inputValue === "0") return "";
|
||||
if (inputValue === "" || inputValue === undefined || inputValue === null)
|
||||
return "";
|
||||
const newValue = String(inputValue ?? "");
|
||||
return formatInput ? formatInput(inputValue as T) : newValue;
|
||||
};
|
||||
@@ -69,13 +70,6 @@ export function EnhancedInput<T = string>({
|
||||
let inputValue = e.target.value;
|
||||
|
||||
if (props.type === "number") {
|
||||
if (inputValue === "0") {
|
||||
setValue("");
|
||||
setInternalValue(0);
|
||||
onValueChange?.(processValue(0));
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
/^-?\d*\.?\d*$/.test(inputValue) ||
|
||||
inputValue === "-" ||
|
||||
@@ -99,7 +93,7 @@ export function EnhancedInput<T = string>({
|
||||
} else {
|
||||
setInternalValue(inputValue);
|
||||
}
|
||||
setValue(inputValue === "0" ? "" : inputValue);
|
||||
setValue(inputValue);
|
||||
}
|
||||
} else {
|
||||
setValue(inputValue);
|
||||
@@ -111,19 +105,15 @@ export function EnhancedInput<T = string>({
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
if (props.type === "number" && value) {
|
||||
if (value === "-" || value === ".") {
|
||||
setValue("");
|
||||
setInternalValue("");
|
||||
onValueBlur?.("" as T);
|
||||
return;
|
||||
}
|
||||
|
||||
if (value === "0") {
|
||||
setValue("");
|
||||
onValueBlur?.(processValue(0));
|
||||
return;
|
||||
}
|
||||
if (
|
||||
props.type === "number" &&
|
||||
value !== "" &&
|
||||
(value === "-" || value === ".")
|
||||
) {
|
||||
setValue("");
|
||||
setInternalValue("");
|
||||
onValueBlur?.("" as T);
|
||||
return;
|
||||
}
|
||||
|
||||
const outputValue = processValue(value);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import type { Table } from "@tanstack/react-table";
|
||||
import { Input } from "@workspace/ui/components/input";
|
||||
import { Combobox } from "@workspace/ui/composed/combobox";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export interface IParams {
|
||||
key: string;
|
||||
@@ -81,15 +82,52 @@ export function ColumnFilter<TData>({
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Input
|
||||
className="min-w-32"
|
||||
<DebouncedInput
|
||||
externalValue={filters[param.key] || ""}
|
||||
key={param.key}
|
||||
onChange={(event) => updateFilter(param.key, event.target.value)}
|
||||
onSearch={(value) => updateFilter(param.key, value)}
|
||||
placeholder={param.placeholder || "Search..."}
|
||||
value={filters[param.key] || ""}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function DebouncedInput({
|
||||
externalValue,
|
||||
onSearch,
|
||||
placeholder,
|
||||
}: {
|
||||
externalValue: string;
|
||||
onSearch: (value: string) => void;
|
||||
placeholder: string;
|
||||
}) {
|
||||
const [localValue, setLocalValue] = useState(externalValue);
|
||||
|
||||
// Sync from external (e.g. reset)
|
||||
useEffect(() => {
|
||||
setLocalValue(externalValue);
|
||||
}, [externalValue]);
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setLocalValue(e.target.value);
|
||||
};
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
onSearch(localValue);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Input
|
||||
className="min-w-32"
|
||||
onChange={handleChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder={placeholder}
|
||||
value={localValue}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ export function ProTable<
|
||||
const [rowCount, setRowCount] = useState<number>(0);
|
||||
const [pagination, setPagination] = useState({
|
||||
pageIndex: 0,
|
||||
pageSize: 10,
|
||||
pageSize: 200,
|
||||
});
|
||||
const loading = useRef(false);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
// API 更新时间:
|
||||
// API 唯一标识:
|
||||
@@ -13,6 +13,7 @@ import * as log from "./log";
|
||||
import * as marketing from "./marketing";
|
||||
import * as order from "./order";
|
||||
import * as payment from "./payment";
|
||||
import * as redemption from "./redemption";
|
||||
import * as server from "./server";
|
||||
import * as subscribe from "./subscribe";
|
||||
import * as system from "./system";
|
||||
@@ -31,6 +32,7 @@ export default {
|
||||
marketing,
|
||||
order,
|
||||
payment,
|
||||
redemption,
|
||||
server,
|
||||
subscribe,
|
||||
system,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
@@ -56,9 +56,15 @@ export async function updateOrderStatus(
|
||||
);
|
||||
}
|
||||
|
||||
/** Manually activate order POST /v1/admin/order/activate */
|
||||
/**
|
||||
* 手动激活订单
|
||||
* POST /v1/admin/order/activate
|
||||
* @param body - 激活订单请求参数,包含 order_no
|
||||
* @param options - 可选的请求配置
|
||||
* @returns 激活结果
|
||||
*/
|
||||
export async function activateOrder(
|
||||
body: { order_no: string },
|
||||
body: API.ActivateOrderRequest,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data?: any }>(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,43 +1,14 @@
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
/** Toggle redemption code status PUT /v1/admin/redemption/code/status */
|
||||
export async function toggleRedemptionCodeStatus(
|
||||
body: API.ToggleRedemptionCodeStatusRequest,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data?: any }>(
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/redemption/code/status`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/** Update redemption code PUT /v1/admin/redemption/code */
|
||||
export async function updateRedemptionCode(
|
||||
body: API.UpdateRedemptionCodeRequest,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data?: any }>(
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/redemption/code`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/** Create redemption code POST /v1/admin/redemption/code */
|
||||
/**
|
||||
* 创建兑换码
|
||||
* POST /v1/admin/redemption/code
|
||||
* @param body - 创建兑换码请求参数
|
||||
* @param options - 可选的请求配置
|
||||
* @returns 创建结果
|
||||
*/
|
||||
export async function createRedemptionCode(
|
||||
body: API.CreateRedemptionCodeRequest,
|
||||
options?: { [key: string]: any }
|
||||
@@ -55,7 +26,37 @@ export async function createRedemptionCode(
|
||||
);
|
||||
}
|
||||
|
||||
/** Delete redemption code DELETE /v1/admin/redemption/code */
|
||||
/**
|
||||
* 更新兑换码
|
||||
* PUT /v1/admin/redemption/code
|
||||
* @param body - 更新兑换码请求参数
|
||||
* @param options - 可选的请求配置
|
||||
* @returns 更新结果
|
||||
*/
|
||||
export async function updateRedemptionCode(
|
||||
body: API.UpdateRedemptionCodeRequest,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data?: any }>(
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/redemption/code`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除兑换码
|
||||
* DELETE /v1/admin/redemption/code
|
||||
* @param body - 删除兑换码请求参数
|
||||
* @param options - 可选的请求配置
|
||||
* @returns 删除结果
|
||||
*/
|
||||
export async function deleteRedemptionCode(
|
||||
body: API.DeleteRedemptionCodeRequest,
|
||||
options?: { [key: string]: any }
|
||||
@@ -73,7 +74,13 @@ export async function deleteRedemptionCode(
|
||||
);
|
||||
}
|
||||
|
||||
/** Batch delete redemption code DELETE /v1/admin/redemption/code/batch */
|
||||
/**
|
||||
* 批量删除兑换码
|
||||
* DELETE /v1/admin/redemption/code/batch
|
||||
* @param body - 批量删除请求参数,包含 ids 数组
|
||||
* @param options - 可选的请求配置
|
||||
* @returns 批量删除结果
|
||||
*/
|
||||
export async function batchDeleteRedemptionCode(
|
||||
body: API.BatchDeleteRedemptionCodeRequest,
|
||||
options?: { [key: string]: any }
|
||||
@@ -91,9 +98,15 @@ export async function batchDeleteRedemptionCode(
|
||||
);
|
||||
}
|
||||
|
||||
/** Get redemption code list GET /v1/admin/redemption/code/list */
|
||||
/**
|
||||
* 获取兑换码列表
|
||||
* GET /v1/admin/redemption/code/list
|
||||
* @param params - 分页及筛选参数
|
||||
* @param options - 可选的请求配置
|
||||
* @returns 兑换码列表及总数
|
||||
*/
|
||||
export async function getRedemptionCodeList(
|
||||
params: API.GetRedemptionCodeListRequest,
|
||||
params: API.GetRedemptionCodeListParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data?: API.GetRedemptionCodeListResponse }>(
|
||||
@@ -108,9 +121,39 @@ export async function getRedemptionCodeList(
|
||||
);
|
||||
}
|
||||
|
||||
/** Get redemption record list GET /v1/admin/redemption/record/list */
|
||||
/**
|
||||
* 切换兑换码状态(启用/禁用)
|
||||
* PUT /v1/admin/redemption/code/status
|
||||
* @param body - 切换状态请求参数
|
||||
* @param options - 可选的请求配置
|
||||
* @returns 切换结果
|
||||
*/
|
||||
export async function toggleRedemptionCodeStatus(
|
||||
body: API.ToggleRedemptionCodeStatusRequest,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data?: any }>(
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/redemption/code/status`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取兑换记录列表
|
||||
* GET /v1/admin/redemption/record/list
|
||||
* @param params - 分页及筛选参数
|
||||
* @param options - 可选的请求配置
|
||||
* @returns 兑换记录列表及总数
|
||||
*/
|
||||
export async function getRedemptionRecordList(
|
||||
params: API.GetRedemptionRecordListRequest,
|
||||
params: API.GetRedemptionRecordListParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data?: API.GetRedemptionRecordListResponse }>(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
@@ -365,3 +365,43 @@ export async function updateVerifyConfig(
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取签名配置
|
||||
* GET /v1/admin/system/signature_config
|
||||
* @param options - 可选的请求配置
|
||||
* @returns 签名配置
|
||||
*/
|
||||
export async function getSignatureConfig(options?: { [key: string]: any }) {
|
||||
return request<API.Response & { data?: API.SignatureConfig }>(
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/system/signature_config`,
|
||||
{
|
||||
method: "GET",
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新签名配置
|
||||
* PUT /v1/admin/system/signature_config
|
||||
* @param body - 签名配置参数
|
||||
* @param options - 可选的请求配置
|
||||
* @returns 更新结果
|
||||
*/
|
||||
export async function updateSignatureConfig(
|
||||
body: API.SignatureConfig,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data?: any }>(
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/system/signature_config`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
+183
-80
@@ -250,85 +250,6 @@ declare namespace API {
|
||||
enable?: boolean;
|
||||
};
|
||||
|
||||
type CreateRedemptionCodeRequest = {
|
||||
total_count: number;
|
||||
subscribe_plan: number;
|
||||
unit_time: string;
|
||||
quantity: number;
|
||||
batch_count: number;
|
||||
};
|
||||
|
||||
type UpdateRedemptionCodeRequest = {
|
||||
id: number;
|
||||
total_count?: number;
|
||||
subscribe_plan?: number;
|
||||
unit_time?: string;
|
||||
quantity?: number;
|
||||
status?: number;
|
||||
};
|
||||
|
||||
type ToggleRedemptionCodeStatusRequest = {
|
||||
id: number;
|
||||
status: number;
|
||||
};
|
||||
|
||||
type DeleteRedemptionCodeRequest = {
|
||||
id: number;
|
||||
};
|
||||
|
||||
type BatchDeleteRedemptionCodeRequest = {
|
||||
ids: number[];
|
||||
};
|
||||
|
||||
type GetRedemptionCodeListRequest = {
|
||||
page: number;
|
||||
size: number;
|
||||
subscribe_plan?: number;
|
||||
unit_time?: string;
|
||||
code?: string;
|
||||
};
|
||||
|
||||
type GetRedemptionCodeListResponse = {
|
||||
total: number;
|
||||
list: RedemptionCode[];
|
||||
};
|
||||
|
||||
type GetRedemptionRecordListRequest = {
|
||||
page: number;
|
||||
size: number;
|
||||
user_id?: number;
|
||||
code_id?: number;
|
||||
};
|
||||
|
||||
type GetRedemptionRecordListResponse = {
|
||||
total: number;
|
||||
list: RedemptionRecord[];
|
||||
};
|
||||
|
||||
type RedemptionCode = {
|
||||
id: number;
|
||||
code: string;
|
||||
total_count: number;
|
||||
used_count: number;
|
||||
subscribe_plan: number;
|
||||
unit_time: string;
|
||||
quantity: number;
|
||||
status: number;
|
||||
created_at: number;
|
||||
updated_at: number;
|
||||
};
|
||||
|
||||
type RedemptionRecord = {
|
||||
id: number;
|
||||
redemption_code_id: number;
|
||||
user_id: number;
|
||||
subscribe_id: number;
|
||||
unit_time: string;
|
||||
quantity: number;
|
||||
redeemed_at: number;
|
||||
created_at: number;
|
||||
};
|
||||
|
||||
type CreateDocumentRequest = {
|
||||
title: string;
|
||||
content: string;
|
||||
@@ -1374,6 +1295,7 @@ declare namespace API {
|
||||
forced_invite: boolean;
|
||||
referral_percentage: number;
|
||||
only_first_purchase: boolean;
|
||||
gift_days?: number;
|
||||
};
|
||||
|
||||
type KickOfflineRequest = {
|
||||
@@ -1864,7 +1786,6 @@ declare namespace API {
|
||||
enable_ip_register_limit: boolean;
|
||||
ip_register_limit: number;
|
||||
ip_register_limit_duration: number;
|
||||
device_limit: number;
|
||||
};
|
||||
|
||||
type RegisterLog = {
|
||||
@@ -2659,4 +2580,186 @@ declare namespace API {
|
||||
security: string;
|
||||
security_config: SecurityConfig;
|
||||
};
|
||||
|
||||
type SignatureConfig = {
|
||||
enable_signature: boolean;
|
||||
};
|
||||
|
||||
type FamilyDetail = {
|
||||
summary: FamilySummary;
|
||||
members: FamilyMemberItem[];
|
||||
};
|
||||
|
||||
type FamilyMemberItem = {
|
||||
user_id: number;
|
||||
identifier: string;
|
||||
device_no: string;
|
||||
role: number;
|
||||
role_name: string;
|
||||
status: number;
|
||||
status_name: string;
|
||||
join_source: string;
|
||||
joined_at: number;
|
||||
left_at?: number;
|
||||
};
|
||||
|
||||
type FamilySummary = {
|
||||
family_id: number;
|
||||
owner_user_id: number;
|
||||
owner_identifier: string;
|
||||
status: string;
|
||||
active_member_count: number;
|
||||
max_members: number;
|
||||
created_at: number;
|
||||
updated_at: number;
|
||||
};
|
||||
|
||||
type GetFamilyDetailParams = {
|
||||
id: number;
|
||||
};
|
||||
|
||||
type GetFamilyListParams = {
|
||||
page: number;
|
||||
size: number;
|
||||
keyword?: string;
|
||||
status?: string;
|
||||
owner_user_id?: number;
|
||||
family_id?: number;
|
||||
user_id?: number;
|
||||
};
|
||||
|
||||
type GetFamilyListResponse = {
|
||||
list: FamilySummary[];
|
||||
total: number;
|
||||
};
|
||||
|
||||
type DissolveFamilyRequest = {
|
||||
family_id: number;
|
||||
reason?: string;
|
||||
};
|
||||
|
||||
type UpdateFamilyMaxMembersRequest = {
|
||||
family_id: number;
|
||||
max_members: number;
|
||||
};
|
||||
|
||||
type RemoveFamilyMemberRequest = {
|
||||
family_id: number;
|
||||
user_id: number;
|
||||
reason?: string;
|
||||
};
|
||||
|
||||
type GetAdminUserInviteStatsParams = {
|
||||
user_id: number;
|
||||
};
|
||||
|
||||
type GetAdminUserInviteStatsResponse = {
|
||||
invite_count: number;
|
||||
total_commission: number;
|
||||
current_commission: number;
|
||||
referral_percentage: number;
|
||||
only_first_purchase: boolean;
|
||||
};
|
||||
|
||||
type GetAdminUserInviteListParams = {
|
||||
user_id: number;
|
||||
page: number;
|
||||
size: number;
|
||||
};
|
||||
|
||||
type AdminInvitedUser = {
|
||||
id: number;
|
||||
avatar: string;
|
||||
identifier: string;
|
||||
enable: boolean;
|
||||
created_at: number;
|
||||
};
|
||||
|
||||
type GetAdminUserInviteListResponse = {
|
||||
total: number;
|
||||
list: AdminInvitedUser[];
|
||||
};
|
||||
|
||||
type ActivateOrderRequest = {
|
||||
order_no: string;
|
||||
};
|
||||
|
||||
type RedemptionCode = {
|
||||
id: number;
|
||||
code: string;
|
||||
total_count: number;
|
||||
used_count: number;
|
||||
subscribe_plan: number;
|
||||
unit_time: string;
|
||||
quantity: number;
|
||||
status: number;
|
||||
created_at: number;
|
||||
updated_at: number;
|
||||
};
|
||||
|
||||
type RedemptionRecord = {
|
||||
id: number;
|
||||
redemption_code_id: number;
|
||||
user_id: number;
|
||||
subscribe_id: number;
|
||||
unit_time: string;
|
||||
quantity: number;
|
||||
redeemed_at: number;
|
||||
created_at: number;
|
||||
};
|
||||
|
||||
type CreateRedemptionCodeRequest = {
|
||||
total_count: number;
|
||||
subscribe_plan: number;
|
||||
unit_time: string;
|
||||
quantity: number;
|
||||
batch_count: number;
|
||||
};
|
||||
|
||||
type UpdateRedemptionCodeRequest = {
|
||||
id: number;
|
||||
total_count?: number;
|
||||
subscribe_plan?: number;
|
||||
unit_time?: string;
|
||||
quantity?: number;
|
||||
status?: number;
|
||||
};
|
||||
|
||||
type DeleteRedemptionCodeRequest = {
|
||||
id: number;
|
||||
};
|
||||
|
||||
type BatchDeleteRedemptionCodeRequest = {
|
||||
ids: number[];
|
||||
};
|
||||
|
||||
type GetRedemptionCodeListParams = {
|
||||
page: number;
|
||||
size: number;
|
||||
subscribe_plan?: number;
|
||||
unit_time?: string;
|
||||
code?: string;
|
||||
};
|
||||
|
||||
type GetRedemptionCodeListResponse = {
|
||||
total: number;
|
||||
list: RedemptionCode[];
|
||||
};
|
||||
|
||||
type ToggleRedemptionCodeStatusRequest = {
|
||||
id: number;
|
||||
status: number;
|
||||
};
|
||||
|
||||
type GetRedemptionRecordListParams = {
|
||||
page: number;
|
||||
size: number;
|
||||
user_id?: number;
|
||||
code_id?: number;
|
||||
};
|
||||
|
||||
type GetRedemptionRecordListResponse = {
|
||||
total: number;
|
||||
list: RedemptionRecord[];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
@@ -291,32 +291,6 @@ export async function getUserSubscribe(
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
transformResponse: [
|
||||
(data) => {
|
||||
try {
|
||||
if (typeof data === "string") {
|
||||
// Convert large integers (int64) to strings BEFORE JSON.parse to prevent precision loss
|
||||
// JavaScript MAX_SAFE_INTEGER is 2^53 - 1 = 9007199254740991
|
||||
// This regex finds all numbers >= 10^16 (larger than MAX_SAFE_INTEGER)
|
||||
const processedData = data.replace(
|
||||
/"([^"]+)":\s*(\d{16,})/g,
|
||||
(match, key, value) => {
|
||||
// Check if number exceeds MAX_SAFE_INTEGER
|
||||
const num = parseInt(value, 10);
|
||||
if (!Number.isSafeInteger(num)) {
|
||||
return `"${key}": "${value}"`;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
);
|
||||
return JSON.parse(processedData);
|
||||
}
|
||||
return data;
|
||||
} catch {
|
||||
return data;
|
||||
}
|
||||
},
|
||||
],
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
@@ -531,3 +505,169 @@ export async function getUserSubscribeTrafficLogs(
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取家庭组详情
|
||||
* GET /v1/admin/user/family/detail
|
||||
* @param params - 家庭组 ID
|
||||
* @param options - 可选的请求配置
|
||||
* @returns 家庭组详情
|
||||
*/
|
||||
export async function getFamilyDetail(
|
||||
params: API.GetFamilyDetailParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data?: API.FamilyDetail }>(
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/user/family/detail`,
|
||||
{
|
||||
method: "GET",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取家庭组列表
|
||||
* GET /v1/admin/user/family/list
|
||||
* @param params - 分页及筛选参数
|
||||
* @param options - 可选的请求配置
|
||||
* @returns 家庭组列表
|
||||
*/
|
||||
export async function getFamilyList(
|
||||
params: API.GetFamilyListParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data?: API.GetFamilyListResponse }>(
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/user/family/list`,
|
||||
{
|
||||
method: "GET",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解散家庭组
|
||||
* PUT /v1/admin/user/family/dissolve
|
||||
* @param body - 解散请求参数
|
||||
* @param options - 可选的请求配置
|
||||
* @returns 解散结果
|
||||
*/
|
||||
export async function dissolveFamily(
|
||||
body: API.DissolveFamilyRequest,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data?: any }>(
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/user/family/dissolve`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新家庭组最大成员数
|
||||
* PUT /v1/admin/user/family/max_members
|
||||
* @param body - 更新参数
|
||||
* @param options - 可选的请求配置
|
||||
* @returns 更新结果
|
||||
*/
|
||||
export async function updateFamilyMaxMembers(
|
||||
body: API.UpdateFamilyMaxMembersRequest,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data?: any }>(
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/user/family/max_members`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除家庭组成员
|
||||
* PUT /v1/admin/user/family/member/remove
|
||||
* @param body - 移除成员请求参数
|
||||
* @param options - 可选的请求配置
|
||||
* @returns 移除结果
|
||||
*/
|
||||
export async function removeFamilyMember(
|
||||
body: API.RemoveFamilyMemberRequest,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data?: any }>(
|
||||
`${
|
||||
import.meta.env.VITE_API_PREFIX || ""
|
||||
}/v1/admin/user/family/member/remove`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取管理员用户邀请统计
|
||||
* GET /v1/admin/user/invite/stats
|
||||
* @param params - 用户 ID
|
||||
* @param options - 可选的请求配置
|
||||
* @returns 邀请统计数据
|
||||
*/
|
||||
export async function getAdminUserInviteStats(
|
||||
params: API.GetAdminUserInviteStatsParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data?: API.GetAdminUserInviteStatsResponse }>(
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/user/invite/stats`,
|
||||
{
|
||||
method: "GET",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取管理员用户邀请列表
|
||||
* GET /v1/admin/user/invite/list
|
||||
* @param params - 用户 ID 及分页参数
|
||||
* @param options - 可选的请求配置
|
||||
* @returns 邀请用户列表
|
||||
*/
|
||||
export async function getAdminUserInviteList(
|
||||
params: API.GetAdminUserInviteListParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data?: API.GetAdminUserInviteListResponse }>(
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/user/invite/list`,
|
||||
{
|
||||
method: "GET",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
// API 更新时间:
|
||||
// API 唯一标识:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
@@ -19,9 +19,7 @@ export async function appleLoginCallback(
|
||||
if (item !== undefined && item !== null) {
|
||||
if (typeof item === "object" && !(item instanceof File)) {
|
||||
if (Array.isArray(item)) {
|
||||
item.forEach((f) => {
|
||||
formData.append(ele, f || "");
|
||||
});
|
||||
for (const f of item) formData.append(ele, f || "");
|
||||
} else {
|
||||
formData.append(
|
||||
ele,
|
||||
|
||||
@@ -356,6 +356,7 @@ declare namespace API {
|
||||
forced_invite: boolean;
|
||||
referral_percentage: number;
|
||||
only_first_purchase: boolean;
|
||||
gift_days?: number;
|
||||
};
|
||||
|
||||
type LoginResponse = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
// API 更新时间:
|
||||
// API 唯一标识:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
// API 更新时间:
|
||||
// API 唯一标识:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
|
||||
+1
@@ -373,6 +373,7 @@ declare namespace API {
|
||||
forced_invite: boolean;
|
||||
referral_percentage: number;
|
||||
only_first_purchase: boolean;
|
||||
gift_days?: number;
|
||||
};
|
||||
|
||||
type MessageLog = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-nocheck
|
||||
// @ts-expect-error
|
||||
/* eslint-disable */
|
||||
import request from "@workspace/ui/lib/request";
|
||||
|
||||
@@ -269,24 +269,6 @@ export async function updateUserRules(
|
||||
);
|
||||
}
|
||||
|
||||
/** Redeem Code POST /v1/public/redemption/ */
|
||||
export async function redeemCode(
|
||||
body: { code: string },
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data: { message: string } }>(
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/public/redemption/`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/** Query User Subscribe GET /v1/public/user/subscribe */
|
||||
export async function queryUserSubscribe(options?: { [key: string]: any }) {
|
||||
return request<API.Response & { data?: API.QueryUserSubscribeListResponse }>(
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
const DEVICE_HASH_SALT = 0x5a_3c_7e_9b;
|
||||
|
||||
/**
|
||||
* Encode device id (user_device.id) to 8-char hex hash (bidirectional)
|
||||
* e.g. 1 → "5A3C7E9A", 42 → "5A3C7EA1"
|
||||
*/
|
||||
export function deviceIdToHash(id: number): string {
|
||||
// biome-ignore lint/suspicious/noBitwiseOperators: intentional XOR hash
|
||||
return ((id ^ DEVICE_HASH_SALT) >>> 0)
|
||||
.toString(16)
|
||||
.toUpperCase()
|
||||
.padStart(8, "0");
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode 8-char hex hash back to device id
|
||||
* e.g. "5A3C7E9A" → 1
|
||||
*/
|
||||
export function hashToDeviceId(hash: string): number {
|
||||
// biome-ignore lint/suspicious/noBitwiseOperators: intentional XOR hash
|
||||
return (Number.parseInt(hash, 16) ^ DEVICE_HASH_SALT) >>> 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shorten a long device identifier (e.g. "device68c71ab9f82d...") to 8-char display
|
||||
* Used when only the identifier string is available (no numeric device id)
|
||||
*/
|
||||
export function shortenDeviceIdentifier(identifier: string): string {
|
||||
return identifier
|
||||
.replace(/^device/i, "")
|
||||
.slice(0, 8)
|
||||
.toUpperCase();
|
||||
}
|
||||
Reference in New Issue
Block a user