Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
<title>ShopEase</title>
</head>
<body>
<div id="app"></div>
Expand Down
9 changes: 9 additions & 0 deletions src/frontend/public/Websitelogo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions src/frontend/src/api/address.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import axios from 'axios'

/** 单条地址 */
export interface Address {
AddressID: number
UserID: number
RecipientName: string
PhoneNumber: string
FullAddress_Text: string
IsDefault: boolean
}

/** 分页结果 */
export interface AddressList {
Addresses: Address[]
TotalCount: number
}

/* ---- CRUD ---- */

/** 获取当前用户所有地址 */
export const fetchAddresses = () =>
axios.get<AddressList>('/address')

/** 获取详情(很少用,通常列表带全量字段即可) */
export const fetchAddress = (id: number) =>
axios.get<Address>(`/address/${id}`)

/** 新增 */
export const addAddress = (payload: Omit<Address, 'AddressID' | 'UserID' | 'IsDefault'>) =>
axios.post<Address>('/address', payload)

/** 更新 */
export const updateAddress = (id: number, payload: Omit<Address, 'AddressID' | 'UserID' | 'IsDefault'>) =>
axios.put(`/address/${id}`, payload)

/** 删除 */
export const deleteAddress = (id: number) =>
axios.delete(`/address/${id}`)

/** 设为默认 */
export const setDefault = (id: number) =>
axios.post(`/address/${id}/set-default`)
9 changes: 9 additions & 0 deletions src/frontend/src/api/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import axios from 'axios'

/** Logout current session */
export const logout = () =>
axios.post('/auth/logout')

/** Logout all sessions for the current user */
export const logoutAll = () =>
axios.post('/auth/logout-all')
29 changes: 29 additions & 0 deletions src/frontend/src/api/cart.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import axios from 'axios'

export interface CartItem {
CartItemID: number
UserID: number
ProductID: number
Quantity: number
PriceAtAddition: number
AddedDate: string
ProductName: string
MainImageURL: string
Price: number
}

export interface CartResponse {
Items: CartItem[]
TotalItems: number
}

/** 获取购物车 */
export const fetchCart = () => axios.get<CartResponse>('/cart')

/** 更新购物车条目数量(Quantity 必须 >0) */
export const updateCartItem = (cartItemId: number, qty: number) =>
axios.put(`/cart/items/${cartItemId}`, { Quantity: qty })

/** 删除购物车条目 */
export const deleteCartItem = (cartItemId: number) =>
axios.delete(`/cart/items/${cartItemId}`)
18 changes: 18 additions & 0 deletions src/frontend/src/api/category.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import axios from 'axios'

/** 后端返回的分类结构 */
export interface Category {
CategoryID: number
CategoryName: string
CategoryDescription?: string
ParentCategoryID?: number | null
}

/**
* 获取分类列表
* @param parent_id 父分类 ID;不传则取所有一级分类
*/
export const fetchCategories = (parent_id?: number) =>
axios.get<Category[]>('/category', {
params: parent_id ? { parent_id } : {}
})
150 changes: 150 additions & 0 deletions src/frontend/src/api/order.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// src/frontend/src/api/order.ts
import axios from 'axios'

/** 单个订单内的商品条目 */
export interface OrderItem {
OrderItemID: number
OrderID: number
ProductID: number
StoreID: number
Quantity: number
PriceAtPurchase: string
ProductNameAtPurchase: string
ProductImageURLAtPurchase: string
Subtotal: string
}

/** 订单状态枚举 */
export type OrderStatusEnum =
| 'PENDING_PAYMENT'
| 'PAID_AND_PENDING_PROCESSING'
| 'PROCESSING_BY_MERCHANT'
| 'SHIPPED'
| 'DELIVERED'
| 'COMPLETED'
| 'CANCELLED_BY_USER'
| 'CANCELLED_BY_MERCHANT'
| 'CANCELLED_BY_SYSTEM'

export const statusValues: OrderStatusEnum[] = [
'PENDING_PAYMENT',
'PAID_AND_PENDING_PROCESSING',
'PROCESSING_BY_MERCHANT',
'SHIPPED',
'DELIVERED',
'COMPLETED',
'CANCELLED_BY_USER',
'CANCELLED_BY_MERCHANT',
'CANCELLED_BY_SYSTEM'
]

/** 后端返回的订单对象 */
export interface Order {
OrderID: number
UserID: number
StoreID: number
PaymentTransactionID: number
OrderStatus: OrderStatusEnum
OrderTotalAmount: string
DiscountAmount: string
ShippingFee: string
FinalAmountForThisOrder: string
ShippingAddress_RecipientName: string
ShippingAddress_PhoneNumber: string
ShippingAddress_Full: string
Notes_ByUser: string
Notes_ByMerchant: string
CreationTime: string
PaymentConfirmationTime?: string
ShippingTime?: string
DeliveryTime?: string
CompletionTime?: string
LastUpdatedDate: string
Items: OrderItem[]
PaymentStatus: string
}

/** 后端分页响应 */
export interface OrdersResponse {
Orders: Order[]
TotalCount: number
Offset: number
Limit: number
}

/**
* 获取当前用户订单列表(分页)
* @param offset 页偏移,默认 0
* @param limit 每页数量,默认 20
*/
export const fetchOrders = (offset = 0, limit = 20) =>
axios.get<OrdersResponse>('/order/', {
params: { offset, limit }
})

/**
* 获取单个订单详情
* @param orderId 订单ID
*/
export const fetchOrderDetail = (orderId: number) =>
axios.get<Order>(`/order/${orderId}`)

/**
* 更新订单状态
* @param orderId 订单ID
* @param data 状态更新数据
*/
export interface OrderUpdateStatusRequest {
NewStatus: OrderStatusEnum
TrackingNumber?: string
UserNotes?: string
AdminNotes?: string
}

export const updateOrderStatus = (orderId: number, data: OrderUpdateStatusRequest) =>
axios.put(`/order/${orderId}/status`, data)

/** 创建订单请求参数 */
export interface CreateOrderPayload {
ShippingAddressID: number // 选中的送货地址ID
Items: { CartItemID: number }[] // 购物车中选中的条目ID数组
Notes_ByUser: string // 用户备注(可选)
}

/** 创建订单响应中的订单项 */
export interface CreatedOrderItem {
OrderItemID: number
OrderID: number
ProductID: number
StoreID: number
Quantity: number
PriceAtPurchase: string
ProductNameAtPurchase: string
ProductImageURLAtPurchase: string
Subtotal: string
}

/** 创建订单响应中的订单 */
export interface CreatedOrder {
OrderID: number
StoreID: number
FinalAmountForThisOrder: string
OrderStatus: string
Items: CreatedOrderItem[]
}

/** 创建订单响应 */
export interface CreateOrderResponse {
PaymentTransactionID: number
ExternalPaymentURL: string
TotalAmountDue: string
Currency: string
OrdersCreated: CreatedOrder[]
Message?: string
}

/**
* 创建订单
*/
export const createOrder = (payload: CreateOrderPayload) =>
axios.post<CreateOrderResponse>('/order/create', payload)
15 changes: 15 additions & 0 deletions src/frontend/src/api/payment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import axios from 'axios'

/** 创建订单后模拟支付 */
export const simulatePay = (
paymentTransactionId: number,
method = 'MockPayment'
) =>
axios.post(`/payment/${paymentTransactionId}/simulate-pay`, {
SimulatedPaymentMethod: method,
ExternalGatewayTxID: `mock-${Date.now()}`
})

/** 查询支付状态 */
export const paymentStatus = (paymentTransactionId: number) =>
axios.get(`/payment/${paymentTransactionId}/status`)
Loading