forked from gxwebsoft/mp-10550
新增:优惠券、积分明细
This commit is contained in:
113
src/api/shop/shopGoodsReview/model/index.ts
Normal file
113
src/api/shop/shopGoodsReview/model/index.ts
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
import type { PageParam } from '@/api/index';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品评价
|
||||||
|
*/
|
||||||
|
export interface ShopGoodsReview {
|
||||||
|
// 评价ID
|
||||||
|
reviewId?: number;
|
||||||
|
// 商品ID
|
||||||
|
goodsId?: number;
|
||||||
|
// 订单ID
|
||||||
|
orderId?: number;
|
||||||
|
// 用户ID
|
||||||
|
userId?: number;
|
||||||
|
// 用户昵称
|
||||||
|
nickname?: string;
|
||||||
|
// 用户头像
|
||||||
|
avatar?: string;
|
||||||
|
// 评价内容
|
||||||
|
content?: string;
|
||||||
|
// 评分 1-5星
|
||||||
|
rating?: number;
|
||||||
|
// 评价图片,JSON数组格式
|
||||||
|
images?: string;
|
||||||
|
// 是否匿名评价
|
||||||
|
isAnonymous?: boolean;
|
||||||
|
// 商家回复
|
||||||
|
reply?: string;
|
||||||
|
// 商家回复时间
|
||||||
|
replyTime?: string;
|
||||||
|
// 评价状态 0待审核 1已通过 2已拒绝
|
||||||
|
status?: number;
|
||||||
|
// 是否置顶
|
||||||
|
isTop?: boolean;
|
||||||
|
// 点赞数
|
||||||
|
likeCount?: number;
|
||||||
|
// 创建时间
|
||||||
|
createTime?: string;
|
||||||
|
// 更新时间
|
||||||
|
updateTime?: string;
|
||||||
|
// 商品信息
|
||||||
|
goodsName?: string;
|
||||||
|
goodsImage?: string;
|
||||||
|
goodsPrice?: string;
|
||||||
|
// SKU信息
|
||||||
|
skuId?: number;
|
||||||
|
specInfo?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评价统计
|
||||||
|
*/
|
||||||
|
export interface ReviewStats {
|
||||||
|
// 总评价数
|
||||||
|
totalCount: number;
|
||||||
|
// 好评数
|
||||||
|
goodCount: number;
|
||||||
|
// 中评数
|
||||||
|
mediumCount: number;
|
||||||
|
// 差评数
|
||||||
|
badCount: number;
|
||||||
|
// 好评率
|
||||||
|
goodRate: number;
|
||||||
|
// 平均评分
|
||||||
|
avgRating: number;
|
||||||
|
// 各星级统计
|
||||||
|
ratingStats: {
|
||||||
|
[key: number]: number; // 星级 -> 数量
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评价查询参数
|
||||||
|
*/
|
||||||
|
export interface ShopGoodsReviewParam extends PageParam {
|
||||||
|
// 商品ID
|
||||||
|
goodsId?: number;
|
||||||
|
// 用户ID
|
||||||
|
userId?: number;
|
||||||
|
// 订单ID
|
||||||
|
orderId?: number;
|
||||||
|
// 评分筛选
|
||||||
|
rating?: number;
|
||||||
|
// 状态筛选
|
||||||
|
status?: number;
|
||||||
|
// 是否有图片
|
||||||
|
hasImages?: boolean;
|
||||||
|
// 排序方式 time:时间 rating:评分 like:点赞数
|
||||||
|
sortBy?: string;
|
||||||
|
// 排序方向 asc:升序 desc:降序
|
||||||
|
sortOrder?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交评价请求
|
||||||
|
*/
|
||||||
|
export interface SubmitReviewRequest {
|
||||||
|
// 商品ID
|
||||||
|
goodsId: number;
|
||||||
|
// 订单ID
|
||||||
|
orderId: number;
|
||||||
|
// 评价内容
|
||||||
|
content: string;
|
||||||
|
// 评分
|
||||||
|
rating: number;
|
||||||
|
// 评价图片
|
||||||
|
images?: string[];
|
||||||
|
// 是否匿名
|
||||||
|
isAnonymous?: boolean;
|
||||||
|
// SKU信息
|
||||||
|
skuId?: number;
|
||||||
|
specInfo?: string;
|
||||||
|
}
|
||||||
102
src/api/user/balance-log/index.ts
Normal file
102
src/api/user/balance-log/index.ts
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
import type { ApiResult, PageResult } from '@/api/index';
|
||||||
|
import type { UserBalanceLog, UserBalanceLogParam } from './model';
|
||||||
|
import {SERVER_API_URL} from "@/utils/server";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询余额明细
|
||||||
|
*/
|
||||||
|
export async function pageUserBalanceLog(params: UserBalanceLogParam) {
|
||||||
|
const res = await request.get<ApiResult<PageResult<UserBalanceLog>>>(
|
||||||
|
SERVER_API_URL + '/sys/user-balance-log/page',
|
||||||
|
params
|
||||||
|
);
|
||||||
|
if (res.code === 0) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询余额明细列表
|
||||||
|
*/
|
||||||
|
export async function listUserBalanceLog(params?: UserBalanceLogParam) {
|
||||||
|
const res = await request.get<ApiResult<UserBalanceLog[]>>(
|
||||||
|
SERVER_API_URL + '/sys/user-balance-log',
|
||||||
|
params
|
||||||
|
);
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据id查询余额明细
|
||||||
|
*/
|
||||||
|
export async function getUserBalanceLog(id: number) {
|
||||||
|
const res = await request.get<ApiResult<UserBalanceLog>>(
|
||||||
|
SERVER_API_URL + '/sys/user-balance-log/' + id
|
||||||
|
);
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加余额明细
|
||||||
|
*/
|
||||||
|
export async function addUserBalanceLog(data: UserBalanceLog) {
|
||||||
|
const res = await request.post<ApiResult<unknown>>(
|
||||||
|
SERVER_API_URL + '/sys/user-balance-log',
|
||||||
|
data
|
||||||
|
);
|
||||||
|
if (res.code === 0) {
|
||||||
|
return res.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改余额明细
|
||||||
|
*/
|
||||||
|
export async function updateUserBalanceLog(data: UserBalanceLog) {
|
||||||
|
const res = await request.put<ApiResult<unknown>>(
|
||||||
|
SERVER_API_URL + '/sys/user-balance-log',
|
||||||
|
data
|
||||||
|
);
|
||||||
|
if (res.code === 0) {
|
||||||
|
return res.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除余额明细
|
||||||
|
*/
|
||||||
|
export async function removeUserBalanceLog(id?: number) {
|
||||||
|
const res = await request.del<ApiResult<unknown>>(
|
||||||
|
SERVER_API_URL + '/sys/user-balance-log/' + id
|
||||||
|
);
|
||||||
|
if (res.code === 0) {
|
||||||
|
return res.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除余额明细
|
||||||
|
*/
|
||||||
|
export async function removeUserBalanceLogs(data: (number | undefined)[]) {
|
||||||
|
const res = await request.del<ApiResult<unknown>>(
|
||||||
|
SERVER_API_URL + '/sys/user-balance-log/batch',
|
||||||
|
{
|
||||||
|
data
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (res.code === 0) {
|
||||||
|
return res.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.message));
|
||||||
|
}
|
||||||
31
src/api/user/balance-log/model/index.ts
Normal file
31
src/api/user/balance-log/model/index.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import type { PageParam } from '@/api/index';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 余额明细
|
||||||
|
*/
|
||||||
|
export interface UserBalanceLog {
|
||||||
|
logId?: number;
|
||||||
|
userId?: number;
|
||||||
|
scene?: number;
|
||||||
|
money?: string;
|
||||||
|
describe?: string;
|
||||||
|
remark?: string;
|
||||||
|
sortNumber?: number;
|
||||||
|
comments?: string;
|
||||||
|
status?: number;
|
||||||
|
deleted?: number;
|
||||||
|
tenantId?: number;
|
||||||
|
createTime?: string;
|
||||||
|
updateTime?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户搜索条件
|
||||||
|
*/
|
||||||
|
export interface UserBalanceLogParam extends PageParam {
|
||||||
|
logId?: number;
|
||||||
|
userId?: number;
|
||||||
|
scene?: number;
|
||||||
|
createTimeStart?: string;
|
||||||
|
createTimeEnd?: string;
|
||||||
|
}
|
||||||
78
src/api/user/coupon/index.ts
Normal file
78
src/api/user/coupon/index.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
import type { ApiResult, PageResult } from '@/api/index';
|
||||||
|
import type { UserCoupon, UserCouponParam } from './model';
|
||||||
|
import {SERVER_API_URL} from "@/utils/server";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询用户优惠券
|
||||||
|
*/
|
||||||
|
export async function pageUserCoupon(params: UserCouponParam) {
|
||||||
|
const res = await request.get<ApiResult<PageResult<UserCoupon>>>(
|
||||||
|
SERVER_API_URL + '/sys/user-coupon/page',
|
||||||
|
params
|
||||||
|
);
|
||||||
|
if (res.code === 0) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户优惠券列表
|
||||||
|
*/
|
||||||
|
export async function listUserCoupon(params?: UserCouponParam) {
|
||||||
|
const res = await request.get<ApiResult<UserCoupon[]>>(
|
||||||
|
SERVER_API_URL + '/sys/user-coupon',
|
||||||
|
params
|
||||||
|
);
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户优惠券统计
|
||||||
|
*/
|
||||||
|
export async function getUserCouponCount(userId: number) {
|
||||||
|
const res = await request.get<ApiResult<{
|
||||||
|
total: number;
|
||||||
|
unused: number;
|
||||||
|
used: number;
|
||||||
|
expired: number;
|
||||||
|
}>>(
|
||||||
|
SERVER_API_URL + '/sys/user-coupon/count',
|
||||||
|
{ userId }
|
||||||
|
);
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据id查询用户优惠券
|
||||||
|
*/
|
||||||
|
export async function getUserCoupon(id: number) {
|
||||||
|
const res = await request.get<ApiResult<UserCoupon>>(
|
||||||
|
SERVER_API_URL + '/sys/user-coupon/' + id
|
||||||
|
);
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用优惠券
|
||||||
|
*/
|
||||||
|
export async function useCoupon(couponId: number, orderId: number) {
|
||||||
|
const res = await request.put<ApiResult<unknown>>(
|
||||||
|
SERVER_API_URL + '/sys/user-coupon/use',
|
||||||
|
{ couponId, orderId }
|
||||||
|
);
|
||||||
|
if (res.code === 0) {
|
||||||
|
return res.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.message));
|
||||||
|
}
|
||||||
45
src/api/user/coupon/model/index.ts
Normal file
45
src/api/user/coupon/model/index.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import type { PageParam } from '@/api/index';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户优惠券
|
||||||
|
*/
|
||||||
|
export interface UserCoupon {
|
||||||
|
// 优惠券ID
|
||||||
|
couponId?: number;
|
||||||
|
// 用户ID
|
||||||
|
userId?: number;
|
||||||
|
// 优惠券名称
|
||||||
|
name?: string;
|
||||||
|
// 优惠券类型 1-满减券 2-折扣券 3-免费券
|
||||||
|
type?: number;
|
||||||
|
// 优惠券金额/折扣
|
||||||
|
value?: string;
|
||||||
|
// 使用门槛金额
|
||||||
|
minAmount?: string;
|
||||||
|
// 有效期开始时间
|
||||||
|
startTime?: string;
|
||||||
|
// 有效期结束时间
|
||||||
|
endTime?: string;
|
||||||
|
// 使用状态 0-未使用 1-已使用 2-已过期
|
||||||
|
status?: number;
|
||||||
|
// 使用时间
|
||||||
|
useTime?: string;
|
||||||
|
// 关联订单ID
|
||||||
|
orderId?: number;
|
||||||
|
// 备注
|
||||||
|
comments?: string;
|
||||||
|
// 创建时间
|
||||||
|
createTime?: string;
|
||||||
|
// 更新时间
|
||||||
|
updateTime?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户优惠券搜索条件
|
||||||
|
*/
|
||||||
|
export interface UserCouponParam extends PageParam {
|
||||||
|
userId?: number;
|
||||||
|
type?: number;
|
||||||
|
status?: number;
|
||||||
|
name?: string;
|
||||||
|
}
|
||||||
73
src/api/user/points/index.ts
Normal file
73
src/api/user/points/index.ts
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
import type { ApiResult, PageResult } from '@/api/index';
|
||||||
|
import type { UserPointsLog, UserPointsLogParam, UserPointsStats } from './model';
|
||||||
|
import {SERVER_API_URL} from "@/utils/server";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询用户积分记录
|
||||||
|
*/
|
||||||
|
export async function pageUserPointsLog(params: UserPointsLogParam) {
|
||||||
|
const res = await request.get<ApiResult<PageResult<UserPointsLog>>>(
|
||||||
|
SERVER_API_URL + '/sys/user-points-log/page',
|
||||||
|
params
|
||||||
|
);
|
||||||
|
if (res.code === 0) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户积分记录列表
|
||||||
|
*/
|
||||||
|
export async function listUserPointsLog(params?: UserPointsLogParam) {
|
||||||
|
const res = await request.get<ApiResult<UserPointsLog[]>>(
|
||||||
|
SERVER_API_URL + '/sys/user-points-log',
|
||||||
|
params
|
||||||
|
);
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户积分统计
|
||||||
|
*/
|
||||||
|
export async function getUserPointsStats(userId: number) {
|
||||||
|
const res = await request.get<ApiResult<UserPointsStats>>(
|
||||||
|
SERVER_API_URL + '/sys/user-points-log/stats',
|
||||||
|
{ userId }
|
||||||
|
);
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据id查询积分记录
|
||||||
|
*/
|
||||||
|
export async function getUserPointsLog(id: number) {
|
||||||
|
const res = await request.get<ApiResult<UserPointsLog>>(
|
||||||
|
SERVER_API_URL + '/sys/user-points-log/' + id
|
||||||
|
);
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用积分
|
||||||
|
*/
|
||||||
|
export async function usePoints(userId: number, points: number, reason: string, orderId?: number) {
|
||||||
|
const res = await request.post<ApiResult<unknown>>(
|
||||||
|
SERVER_API_URL + '/sys/user-points-log/use',
|
||||||
|
{ userId, points, reason, orderId }
|
||||||
|
);
|
||||||
|
if (res.code === 0) {
|
||||||
|
return res.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.message));
|
||||||
|
}
|
||||||
49
src/api/user/points/model/index.ts
Normal file
49
src/api/user/points/model/index.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import type { PageParam } from '@/api/index';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户积分记录
|
||||||
|
*/
|
||||||
|
export interface UserPointsLog {
|
||||||
|
// 积分记录ID
|
||||||
|
logId?: number;
|
||||||
|
// 用户ID
|
||||||
|
userId?: number;
|
||||||
|
// 积分变动类型 1-获得 2-消费 3-过期 4-管理员调整
|
||||||
|
type?: number;
|
||||||
|
// 积分变动数量
|
||||||
|
points?: number;
|
||||||
|
// 变动原因
|
||||||
|
reason?: string;
|
||||||
|
// 关联订单ID
|
||||||
|
orderId?: number;
|
||||||
|
// 备注
|
||||||
|
comments?: string;
|
||||||
|
// 创建时间
|
||||||
|
createTime?: string;
|
||||||
|
// 更新时间
|
||||||
|
updateTime?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户积分统计
|
||||||
|
*/
|
||||||
|
export interface UserPointsStats {
|
||||||
|
// 当前积分
|
||||||
|
currentPoints?: number;
|
||||||
|
// 累计获得积分
|
||||||
|
totalEarned?: number;
|
||||||
|
// 累计消费积分
|
||||||
|
totalUsed?: number;
|
||||||
|
// 即将过期积分
|
||||||
|
expiringSoon?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户积分搜索条件
|
||||||
|
*/
|
||||||
|
export interface UserPointsLogParam extends PageParam {
|
||||||
|
userId?: number;
|
||||||
|
type?: number;
|
||||||
|
startTime?: string;
|
||||||
|
endTime?: string;
|
||||||
|
}
|
||||||
@@ -36,7 +36,10 @@ export default defineAppConfig({
|
|||||||
"address/add",
|
"address/add",
|
||||||
"address/wxAddress",
|
"address/wxAddress",
|
||||||
"help/index",
|
"help/index",
|
||||||
"about/index"
|
"about/index",
|
||||||
|
"wallet/wallet",
|
||||||
|
"coupon/coupon",
|
||||||
|
"points/points"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,11 +6,15 @@ import {useEffect, useState} from "react";
|
|||||||
import {User} from "@/api/system/user/model";
|
import {User} from "@/api/system/user/model";
|
||||||
import navTo from "@/utils/common";
|
import navTo from "@/utils/common";
|
||||||
import {TenantId} from "@/config/app";
|
import {TenantId} from "@/config/app";
|
||||||
|
import {getUserCouponCount} from "@/api/user/coupon";
|
||||||
|
import {getUserPointsStats} from "@/api/user/points";
|
||||||
|
|
||||||
function UserCard() {
|
function UserCard() {
|
||||||
const [IsLogin, setIsLogin] = useState<boolean>(false)
|
const [IsLogin, setIsLogin] = useState<boolean>(false)
|
||||||
const [userInfo, setUserInfo] = useState<User>()
|
const [userInfo, setUserInfo] = useState<User>()
|
||||||
const [roleName, setRoleName] = useState<string>('注册用户')
|
const [roleName, setRoleName] = useState<string>('注册用户')
|
||||||
|
const [couponCount, setCouponCount] = useState(0)
|
||||||
|
const [pointsCount, setPointsCount] = useState(0)
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -30,6 +34,26 @@ function UserCard() {
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const loadUserStats = (userId: number) => {
|
||||||
|
// 加载优惠券数量
|
||||||
|
getUserCouponCount(userId)
|
||||||
|
.then((res: any) => {
|
||||||
|
setCouponCount(res.unused || 0)
|
||||||
|
})
|
||||||
|
.catch((error: any) => {
|
||||||
|
console.error('Coupon count error:', error)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 加载积分数量
|
||||||
|
getUserPointsStats(userId)
|
||||||
|
.then((res: any) => {
|
||||||
|
setPointsCount(res.currentPoints || 0)
|
||||||
|
})
|
||||||
|
.catch((error: any) => {
|
||||||
|
console.error('Points stats error:', error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const reload = () => {
|
const reload = () => {
|
||||||
Taro.getUserInfo({
|
Taro.getUserInfo({
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
@@ -44,6 +68,12 @@ function UserCard() {
|
|||||||
setUserInfo(data)
|
setUserInfo(data)
|
||||||
setIsLogin(true);
|
setIsLogin(true);
|
||||||
Taro.setStorageSync('UserId', data.userId)
|
Taro.setStorageSync('UserId', data.userId)
|
||||||
|
|
||||||
|
// 加载用户统计数据
|
||||||
|
if (data.userId) {
|
||||||
|
loadUserStats(data.userId)
|
||||||
|
}
|
||||||
|
|
||||||
// 获取openId
|
// 获取openId
|
||||||
if (!data.openid) {
|
if (!data.openid) {
|
||||||
Taro.login({
|
Taro.login({
|
||||||
@@ -186,17 +216,17 @@ function UserCard() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={'flex justify-around mt-5'}>
|
<div className={'flex justify-around mt-5'}>
|
||||||
<div className={'item flex justify-center flex-col items-center'}>
|
<div className={'item flex justify-center flex-col items-center'} onClick={() => navTo('/user/wallet/wallet', true)}>
|
||||||
<span className={'text-sm text-gray-500'}>余额</span>
|
<span className={'text-sm text-gray-500'}>余额</span>
|
||||||
<span className={'text-xl'}>¥ {userInfo?.balance}</span>
|
<span className={'text-xl'}>¥ {userInfo?.balance || '0.00'}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={'item flex justify-center flex-col items-center'}>
|
<div className={'item flex justify-center flex-col items-center'} onClick={() => navTo('/user/coupon/coupon', true)}>
|
||||||
<span className={'text-sm text-gray-500'}>优惠券</span>
|
<span className={'text-sm text-gray-500'}>优惠券</span>
|
||||||
<span className={'text-xl'}>0</span>
|
<span className={'text-xl'}>{couponCount}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={'item flex justify-center flex-col items-center'}>
|
<div className={'item flex justify-center flex-col items-center'} onClick={() => navTo('/user/points/points', true)}>
|
||||||
<span className={'text-sm text-gray-500'}>积分</span>
|
<span className={'text-sm text-gray-500'}>积分</span>
|
||||||
<span className={'text-xl'}>100</span>
|
<span className={'text-xl'}>{pointsCount}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
4
src/user/coupon/coupon.ts
Normal file
4
src/user/coupon/coupon.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export default definePageConfig({
|
||||||
|
navigationBarTitleText: '我的优惠券',
|
||||||
|
navigationBarTextStyle: 'black'
|
||||||
|
})
|
||||||
213
src/user/coupon/coupon.tsx
Normal file
213
src/user/coupon/coupon.tsx
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
import {useEffect, useState} from "react";
|
||||||
|
import Taro from '@tarojs/taro'
|
||||||
|
import {Button, Cell, Space, Empty, ConfigProvider, Tabs, TabPane, Tag} from '@nutui/nutui-react-taro'
|
||||||
|
import {View} from '@tarojs/components'
|
||||||
|
import {pageUserCoupon, getUserCouponCount} from "@/api/user/coupon";
|
||||||
|
import {UserCoupon as UserCouponType} from "@/api/user/coupon/model";
|
||||||
|
|
||||||
|
const UserCoupon = () => {
|
||||||
|
const [list, setList] = useState<UserCouponType[]>([])
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [activeTab, setActiveTab] = useState('0')
|
||||||
|
const [couponCount, setCouponCount] = useState({
|
||||||
|
total: 0,
|
||||||
|
unused: 0,
|
||||||
|
used: 0,
|
||||||
|
expired: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
const tabs = [
|
||||||
|
{ key: '0', title: '全部', status: undefined },
|
||||||
|
{ key: '1', title: '未使用', status: 0 },
|
||||||
|
{ key: '2', title: '已使用', status: 1 },
|
||||||
|
{ key: '3', title: '已过期', status: 2 }
|
||||||
|
]
|
||||||
|
|
||||||
|
const reload = (status?: number) => {
|
||||||
|
setLoading(true)
|
||||||
|
const userId = Taro.getStorageSync('UserId')
|
||||||
|
|
||||||
|
console.log('Loading coupons for userId:', userId, 'status:', status)
|
||||||
|
|
||||||
|
if (!userId) {
|
||||||
|
console.warn('No userId found in storage')
|
||||||
|
Taro.showToast({
|
||||||
|
title: '请先登录',
|
||||||
|
icon: 'error'
|
||||||
|
});
|
||||||
|
setLoading(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pageUserCoupon({
|
||||||
|
userId: parseInt(userId),
|
||||||
|
status: status,
|
||||||
|
page: 1,
|
||||||
|
limit: 20
|
||||||
|
})
|
||||||
|
.then((res: any) => {
|
||||||
|
console.log('Coupon response:', res)
|
||||||
|
setList(res?.list || [])
|
||||||
|
})
|
||||||
|
.catch((error: any) => {
|
||||||
|
console.error('Coupon error:', error)
|
||||||
|
Taro.showToast({
|
||||||
|
title: error?.message || '获取失败',
|
||||||
|
icon: 'error'
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setLoading(false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadCouponCount = () => {
|
||||||
|
const userId = Taro.getStorageSync('UserId')
|
||||||
|
if (!userId) return
|
||||||
|
|
||||||
|
getUserCouponCount(parseInt(userId))
|
||||||
|
.then((res: any) => {
|
||||||
|
setCouponCount(res)
|
||||||
|
})
|
||||||
|
.catch((error: any) => {
|
||||||
|
console.error('Coupon count error:', error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
reload()
|
||||||
|
loadCouponCount()
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onTabChange = (index: string) => {
|
||||||
|
setActiveTab(index)
|
||||||
|
const tab = tabs.find(t => t.key === index)
|
||||||
|
reload(tab?.status)
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCouponTypeText = (type?: number) => {
|
||||||
|
switch (type) {
|
||||||
|
case 1: return '满减券'
|
||||||
|
case 2: return '折扣券'
|
||||||
|
case 3: return '免费券'
|
||||||
|
default: return '优惠券'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCouponStatusText = (status?: number) => {
|
||||||
|
switch (status) {
|
||||||
|
case 0: return '未使用'
|
||||||
|
case 1: return '已使用'
|
||||||
|
case 2: return '已过期'
|
||||||
|
default: return '未知'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCouponStatusColor = (status?: number) => {
|
||||||
|
switch (status) {
|
||||||
|
case 0: return 'success'
|
||||||
|
case 1: return 'default'
|
||||||
|
case 2: return 'danger'
|
||||||
|
default: return 'default'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatCouponValue = (type?: number, value?: string) => {
|
||||||
|
if (!value) return '0'
|
||||||
|
switch (type) {
|
||||||
|
case 1: return `¥${value}`
|
||||||
|
case 2: return `${parseFloat(value) * 10}折`
|
||||||
|
case 3: return '免费'
|
||||||
|
default: return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<ConfigProvider>
|
||||||
|
<div className={'h-full flex flex-col justify-center items-center'} style={{
|
||||||
|
height: 'calc(100vh - 300px)',
|
||||||
|
}}>
|
||||||
|
<div>加载中...</div>
|
||||||
|
</div>
|
||||||
|
</ConfigProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list.length == 0) {
|
||||||
|
return (
|
||||||
|
<ConfigProvider>
|
||||||
|
<div className={'h-full flex flex-col justify-center items-center'} style={{
|
||||||
|
height: 'calc(100vh - 300px)',
|
||||||
|
}}>
|
||||||
|
<Empty
|
||||||
|
style={{
|
||||||
|
backgroundColor: 'transparent'
|
||||||
|
}}
|
||||||
|
description="您还没有优惠券"
|
||||||
|
/>
|
||||||
|
<Space>
|
||||||
|
<Button onClick={() => reload()}>刷新</Button>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
</ConfigProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConfigProvider>
|
||||||
|
<View>
|
||||||
|
<Tabs value={activeTab} onChange={onTabChange}>
|
||||||
|
{tabs.map(tab => (
|
||||||
|
<TabPane key={tab.key} title={tab.title}>
|
||||||
|
<View className="p-4">
|
||||||
|
{list.map((item, index) => (
|
||||||
|
<Cell.Group key={index} className="mb-4">
|
||||||
|
<Cell className="coupon-item p-4">
|
||||||
|
<View className="flex justify-between items-center">
|
||||||
|
<View className="flex-1">
|
||||||
|
<View className="flex items-center mb-2">
|
||||||
|
<View className="coupon-value text-2xl font-bold text-red-500 mr-3">
|
||||||
|
{formatCouponValue(item.type, item.value)}
|
||||||
|
</View>
|
||||||
|
<View className="flex flex-col">
|
||||||
|
<View className="text-base font-medium text-gray-800">
|
||||||
|
{item.name || getCouponTypeText(item.type)}
|
||||||
|
</View>
|
||||||
|
{item.minAmount && parseFloat(item.minAmount) > 0 && (
|
||||||
|
<View className="text-sm text-gray-500">
|
||||||
|
满¥{item.minAmount}可用
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View className="flex justify-between items-center text-xs text-gray-400">
|
||||||
|
<View>
|
||||||
|
有效期: {item.startTime ? new Date(item.startTime).toLocaleDateString() : ''} - {item.endTime ? new Date(item.endTime).toLocaleDateString() : ''}
|
||||||
|
</View>
|
||||||
|
<Tag type={getCouponStatusColor(item.status)} size="small">
|
||||||
|
{getCouponStatusText(item.status)}
|
||||||
|
</Tag>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{item.comments && (
|
||||||
|
<View className="text-xs text-gray-500 mt-2 p-2 bg-gray-50 rounded">
|
||||||
|
{item.comments}
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</Cell>
|
||||||
|
</Cell.Group>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
</TabPane>
|
||||||
|
))}
|
||||||
|
</Tabs>
|
||||||
|
</View>
|
||||||
|
</ConfigProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UserCoupon;
|
||||||
4
src/user/points/points.config.ts
Normal file
4
src/user/points/points.config.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export default definePageConfig({
|
||||||
|
navigationBarTitleText: '我的积分',
|
||||||
|
navigationBarTextStyle: 'black'
|
||||||
|
})
|
||||||
199
src/user/points/points.tsx
Normal file
199
src/user/points/points.tsx
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
import {useEffect, useState} from "react";
|
||||||
|
import Taro from '@tarojs/taro'
|
||||||
|
import {Button, Cell, Space, Empty, ConfigProvider, Card} from '@nutui/nutui-react-taro'
|
||||||
|
import {View} from '@tarojs/components'
|
||||||
|
import {pageUserPointsLog, getUserPointsStats} from "@/api/user/points";
|
||||||
|
import {UserPointsLog as UserPointsLogType, UserPointsStats} from "@/api/user/points/model";
|
||||||
|
|
||||||
|
const UserPoints = () => {
|
||||||
|
const [list, setList] = useState<UserPointsLogType[]>([])
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [stats, setStats] = useState<UserPointsStats>({})
|
||||||
|
|
||||||
|
const reload = () => {
|
||||||
|
setLoading(true)
|
||||||
|
const userId = Taro.getStorageSync('UserId')
|
||||||
|
|
||||||
|
console.log('Loading points log for userId:', userId)
|
||||||
|
|
||||||
|
if (!userId) {
|
||||||
|
console.warn('No userId found in storage')
|
||||||
|
Taro.showToast({
|
||||||
|
title: '请先登录',
|
||||||
|
icon: 'error'
|
||||||
|
});
|
||||||
|
setLoading(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pageUserPointsLog({
|
||||||
|
userId: parseInt(userId),
|
||||||
|
page: 1,
|
||||||
|
limit: 20
|
||||||
|
})
|
||||||
|
.then((res: any) => {
|
||||||
|
console.log('Points log response:', res)
|
||||||
|
setList(res?.list || [])
|
||||||
|
})
|
||||||
|
.catch((error: any) => {
|
||||||
|
console.error('Points log error:', error)
|
||||||
|
Taro.showToast({
|
||||||
|
title: error?.message || '获取失败',
|
||||||
|
icon: 'error'
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setLoading(false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadPointsStats = () => {
|
||||||
|
const userId = Taro.getStorageSync('UserId')
|
||||||
|
if (!userId) return
|
||||||
|
|
||||||
|
getUserPointsStats(parseInt(userId))
|
||||||
|
.then((res: any) => {
|
||||||
|
setStats(res)
|
||||||
|
})
|
||||||
|
.catch((error: any) => {
|
||||||
|
console.error('Points stats error:', error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
reload()
|
||||||
|
loadPointsStats()
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getPointsTypeText = (type?: number) => {
|
||||||
|
switch (type) {
|
||||||
|
case 1: return '获得积分'
|
||||||
|
case 2: return '消费积分'
|
||||||
|
case 3: return '积分过期'
|
||||||
|
case 4: return '管理员调整'
|
||||||
|
default: return '积分变动'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getPointsTypeColor = (type?: number) => {
|
||||||
|
switch (type) {
|
||||||
|
case 1: return 'text-green-500'
|
||||||
|
case 2: return 'text-red-500'
|
||||||
|
case 3: return 'text-gray-500'
|
||||||
|
case 4: return 'text-blue-500'
|
||||||
|
default: return 'text-gray-500'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<ConfigProvider>
|
||||||
|
<div className={'h-full flex flex-col justify-center items-center'} style={{
|
||||||
|
height: 'calc(100vh - 300px)',
|
||||||
|
}}>
|
||||||
|
<div>加载中...</div>
|
||||||
|
</div>
|
||||||
|
</ConfigProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConfigProvider>
|
||||||
|
<View className="bg-gray-50 min-h-screen">
|
||||||
|
{/* 积分统计卡片 */}
|
||||||
|
<View className="p-4">
|
||||||
|
<Card className="points-stats-card">
|
||||||
|
<View className="text-center py-4">
|
||||||
|
<View className="text-3xl font-bold text-orange-500 mb-2">
|
||||||
|
{stats.currentPoints || 0}
|
||||||
|
</View>
|
||||||
|
<View className="text-sm text-gray-500 mb-4">当前积分</View>
|
||||||
|
|
||||||
|
<View className="flex justify-around text-center">
|
||||||
|
<View>
|
||||||
|
<View className="text-lg font-medium text-gray-800">
|
||||||
|
{stats.totalEarned || 0}
|
||||||
|
</View>
|
||||||
|
<View className="text-xs text-gray-500">累计获得</View>
|
||||||
|
</View>
|
||||||
|
<View>
|
||||||
|
<View className="text-lg font-medium text-gray-800">
|
||||||
|
{stats.totalUsed || 0}
|
||||||
|
</View>
|
||||||
|
<View className="text-xs text-gray-500">累计消费</View>
|
||||||
|
</View>
|
||||||
|
<View>
|
||||||
|
<View className="text-lg font-medium text-gray-800">
|
||||||
|
{stats.expiringSoon || 0}
|
||||||
|
</View>
|
||||||
|
<View className="text-xs text-gray-500">即将过期</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</Card>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 积分记录 */}
|
||||||
|
<View className="px-4">
|
||||||
|
<View className="text-base font-medium text-gray-800 mb-3">积分明细</View>
|
||||||
|
|
||||||
|
{list.length === 0 ? (
|
||||||
|
<div className={'h-full flex flex-col justify-center items-center'} style={{
|
||||||
|
height: 'calc(100vh - 400px)',
|
||||||
|
}}>
|
||||||
|
<Empty
|
||||||
|
style={{
|
||||||
|
backgroundColor: 'transparent'
|
||||||
|
}}
|
||||||
|
description="您还没有积分记录"
|
||||||
|
/>
|
||||||
|
<Space>
|
||||||
|
<Button onClick={() => reload()}>刷新</Button>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
list.map((item, index) => (
|
||||||
|
<Cell.Group key={index} className="mb-3">
|
||||||
|
<Cell className="flex flex-col gap-2 p-4">
|
||||||
|
<View className="flex justify-between items-start">
|
||||||
|
<View className="flex-1">
|
||||||
|
<View className="font-medium text-base text-gray-800 mb-1">
|
||||||
|
{getPointsTypeText(item.type)}
|
||||||
|
</View>
|
||||||
|
<View className="text-sm text-gray-500">
|
||||||
|
{item.reason || '无备注'}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View className={`text-lg font-bold ${getPointsTypeColor(item.type)}`}>
|
||||||
|
{item.type === 1 ? '+' : item.type === 2 ? '-' : ''}
|
||||||
|
{item.points || 0}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View className="flex justify-between items-center text-xs text-gray-400 mt-2">
|
||||||
|
<View>
|
||||||
|
{item.createTime ? new Date(item.createTime).toLocaleString() : ''}
|
||||||
|
</View>
|
||||||
|
{item.orderId && (
|
||||||
|
<View>
|
||||||
|
订单: {item.orderId}
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{item.comments && (
|
||||||
|
<View className="text-xs text-gray-500 mt-1 p-2 bg-gray-50 rounded">
|
||||||
|
备注: {item.comments}
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</Cell>
|
||||||
|
</Cell.Group>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</ConfigProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UserPoints;
|
||||||
4
src/user/wallet/wallet.config.ts
Normal file
4
src/user/wallet/wallet.config.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export default definePageConfig({
|
||||||
|
navigationBarTitleText: '余额明细',
|
||||||
|
navigationBarTextStyle: 'black'
|
||||||
|
})
|
||||||
0
src/user/wallet/wallet.scss
Normal file
0
src/user/wallet/wallet.scss
Normal file
134
src/user/wallet/wallet.tsx
Normal file
134
src/user/wallet/wallet.tsx
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
import {useEffect, useState} from "react";
|
||||||
|
import Taro from '@tarojs/taro'
|
||||||
|
import {Button, Cell, Space, Empty, ConfigProvider, InfiniteLoading} from '@nutui/nutui-react-taro'
|
||||||
|
import {View, ScrollView} from '@tarojs/components'
|
||||||
|
import {pageUserBalanceLog} from "@/api/user/balance-log";
|
||||||
|
import {UserBalanceLog} from "@/api/user/balance-log/model";
|
||||||
|
import {formatCurrency} from "@/utils/common";
|
||||||
|
|
||||||
|
const Wallet = () => {
|
||||||
|
const [list, setList] = useState<UserBalanceLog[]>([])
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [loadingMore, setLoadingMore] = useState(false)
|
||||||
|
const [refreshing, setRefreshing] = useState(false)
|
||||||
|
const [hasMore, setHasMore] = useState(true)
|
||||||
|
const [currentPage, setCurrentPage] = useState(1)
|
||||||
|
const [total, setTotal] = useState(0)
|
||||||
|
const pageSize = 20
|
||||||
|
|
||||||
|
const reload = () => {
|
||||||
|
setLoading(true)
|
||||||
|
const userId = Taro.getStorageSync('UserId')
|
||||||
|
|
||||||
|
console.log('Loading balance log for userId:', userId)
|
||||||
|
|
||||||
|
if (!userId) {
|
||||||
|
console.warn('No userId found in storage')
|
||||||
|
Taro.showToast({
|
||||||
|
title: '请先登录',
|
||||||
|
icon: 'error'
|
||||||
|
});
|
||||||
|
setLoading(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pageUserBalanceLog({
|
||||||
|
userId: parseInt(userId),
|
||||||
|
page: 1,
|
||||||
|
limit: 20
|
||||||
|
})
|
||||||
|
.then((res: any) => {
|
||||||
|
console.log('Balance log response:', res)
|
||||||
|
setList(res?.list || [])
|
||||||
|
})
|
||||||
|
.catch((error: any) => {
|
||||||
|
console.error('Balance log error:', error)
|
||||||
|
Taro.showToast({
|
||||||
|
title: error?.message || '获取失败',
|
||||||
|
icon: 'error'
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setLoading(false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
reload()
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<ConfigProvider>
|
||||||
|
<div className={'h-full flex flex-col justify-center items-center'} style={{
|
||||||
|
height: 'calc(100vh - 300px)',
|
||||||
|
}}>
|
||||||
|
<div>加载中...</div>
|
||||||
|
</div>
|
||||||
|
</ConfigProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list.length == 0) {
|
||||||
|
return (
|
||||||
|
<ConfigProvider>
|
||||||
|
<div className={'h-full flex flex-col justify-center items-center'} style={{
|
||||||
|
height: 'calc(100vh - 300px)',
|
||||||
|
}}>
|
||||||
|
<Empty
|
||||||
|
style={{
|
||||||
|
backgroundColor: 'transparent'
|
||||||
|
}}
|
||||||
|
description="您还没有消费记录"
|
||||||
|
/>
|
||||||
|
<Space>
|
||||||
|
<Button onClick={() => reload()}>刷新</Button>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
</ConfigProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConfigProvider>
|
||||||
|
<View className="p-4">
|
||||||
|
{list.map((item, index) => (
|
||||||
|
<Cell.Group key={index} className="mb-4">
|
||||||
|
<Cell className="flex flex-col gap-2 p-4">
|
||||||
|
<View className="flex justify-between items-start w-full">
|
||||||
|
<View className="flex-1">
|
||||||
|
<View className="font-medium text-base text-gray-800 mb-1">
|
||||||
|
{item.scene === 10 ? '会员充值' : item.scene === 20 ? '用户消费' : item.scene === 30 ? '管理员操作' : '订单退款'}
|
||||||
|
</View>
|
||||||
|
<View className="text-sm text-gray-500">
|
||||||
|
{item.comments}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View className={`text-lg font-bold ${
|
||||||
|
item.scene === 10 ? 'text-green-500' : ''
|
||||||
|
}`}>
|
||||||
|
{item.scene === 10 ? '+' : '-'}
|
||||||
|
{formatCurrency(Number(item.money), 'CNY') || '0.00'}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View className="flex justify-between w-full items-center text-xs text-gray-400 mt-2">
|
||||||
|
<View>
|
||||||
|
{item.createTime}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{item.remark && (
|
||||||
|
<View className="text-xs text-gray-500 mt-1 p-2 bg-gray-50 rounded">
|
||||||
|
备注: {item.remark}
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</Cell>
|
||||||
|
</Cell.Group>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
</ConfigProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Wallet;
|
||||||
@@ -108,6 +108,20 @@ export function truncateText(text: string, maxLength: number = 30): string {
|
|||||||
return text.substring(0, maxLength);
|
return text.substring(0, maxLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化货币
|
||||||
|
* @param amount
|
||||||
|
* @param currency
|
||||||
|
*/
|
||||||
|
export function formatCurrency(amount: number, currency: string = 'CNY'): string {
|
||||||
|
return new Intl.NumberFormat('zh-CN', {
|
||||||
|
style: 'currency',
|
||||||
|
currency: currency,
|
||||||
|
minimumFractionDigits: 2,
|
||||||
|
maximumFractionDigits: 2
|
||||||
|
}).format(amount);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成订单标题
|
* 生成订单标题
|
||||||
* @param goodsNames 商品名称数组
|
* @param goodsNames 商品名称数组
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import {User} from "@/api/system/user/model";
|
|||||||
// 模版套餐ID - 请根据实际情况修改
|
// 模版套餐ID - 请根据实际情况修改
|
||||||
export const TEMPLATE_ID = '10550';
|
export const TEMPLATE_ID = '10550';
|
||||||
// 服务接口 - 请根据实际情况修改
|
// 服务接口 - 请根据实际情况修改
|
||||||
export const SERVER_API_URL = 'https://server.websoft.top/api';
|
// export const SERVER_API_URL = 'https://server.websoft.top/api';
|
||||||
// export const SERVER_API_URL = 'http://127.0.0.1:8000/api';
|
export const SERVER_API_URL = 'http://127.0.0.1:8000/api';
|
||||||
/**
|
/**
|
||||||
* 保存用户信息到本地存储
|
* 保存用户信息到本地存储
|
||||||
* @param token
|
* @param token
|
||||||
|
|||||||
Reference in New Issue
Block a user