feat: scaffold monorepo with shared types and NestJS server
- pnpm workspace with packages/app, packages/server, packages/shared - @mp-pilates/shared: enums, constants, TypeScript interfaces for all 8 data models - @mp-pilates/server: NestJS bootstrap with health check, validation pipe, CORS - Base TypeScript config with strict mode
This commit is contained in:
13
packages/shared/package.json
Normal file
13
packages/shared/package.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "@mp-pilates/shared",
|
||||
"version": "0.1.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"dev": "tsc --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.4.0"
|
||||
}
|
||||
}
|
||||
21
packages/shared/src/constants.ts
Normal file
21
packages/shared/src/constants.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/** 默认免费取消截止小时数 */
|
||||
export const DEFAULT_CANCEL_HOURS_LIMIT = 2
|
||||
|
||||
/** 默认时段容量(私教 = 1) */
|
||||
export const DEFAULT_SLOT_CAPACITY = 1
|
||||
|
||||
/** 自动生成时段的天数范围 */
|
||||
export const SLOT_GENERATION_DAYS = 14
|
||||
|
||||
/** 时段筛选区间 */
|
||||
export const TIME_PERIODS = {
|
||||
MORNING: { label: '上午', start: '06:00', end: '12:00' },
|
||||
AFTERNOON: { label: '下午', start: '12:00', end: '18:00' },
|
||||
EVENING: { label: '晚上', start: '18:00', end: '22:00' },
|
||||
} as const
|
||||
|
||||
/** 日期选择器展示天数 */
|
||||
export const DATE_SELECTOR_DAYS = 7
|
||||
|
||||
/** 星期映射 */
|
||||
export const WEEKDAY_LABELS = ['', '周一', '周二', '周三', '周四', '周五', '周六', '周日'] as const
|
||||
46
packages/shared/src/enums.ts
Normal file
46
packages/shared/src/enums.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
// ===== User =====
|
||||
export enum UserRole {
|
||||
MEMBER = 'MEMBER',
|
||||
ADMIN = 'ADMIN',
|
||||
}
|
||||
|
||||
// ===== CardType =====
|
||||
export enum CardTypeCategory {
|
||||
TIMES = 'TIMES',
|
||||
DURATION = 'DURATION',
|
||||
TRIAL = 'TRIAL',
|
||||
}
|
||||
|
||||
// ===== Membership =====
|
||||
export enum MembershipStatus {
|
||||
ACTIVE = 'ACTIVE',
|
||||
EXPIRED = 'EXPIRED',
|
||||
USED_UP = 'USED_UP',
|
||||
}
|
||||
|
||||
// ===== TimeSlot =====
|
||||
export enum TimeSlotStatus {
|
||||
OPEN = 'OPEN',
|
||||
FULL = 'FULL',
|
||||
CLOSED = 'CLOSED',
|
||||
}
|
||||
|
||||
export enum TimeSlotSource {
|
||||
TEMPLATE = 'TEMPLATE',
|
||||
MANUAL = 'MANUAL',
|
||||
}
|
||||
|
||||
// ===== Booking =====
|
||||
export enum BookingStatus {
|
||||
CONFIRMED = 'CONFIRMED',
|
||||
CANCELLED = 'CANCELLED',
|
||||
COMPLETED = 'COMPLETED',
|
||||
NO_SHOW = 'NO_SHOW',
|
||||
}
|
||||
|
||||
// ===== Order =====
|
||||
export enum OrderStatus {
|
||||
PENDING = 'PENDING',
|
||||
PAID = 'PAID',
|
||||
REFUNDED = 'REFUNDED',
|
||||
}
|
||||
52
packages/shared/src/index.ts
Normal file
52
packages/shared/src/index.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
// Enums
|
||||
export {
|
||||
UserRole,
|
||||
CardTypeCategory,
|
||||
MembershipStatus,
|
||||
TimeSlotStatus,
|
||||
TimeSlotSource,
|
||||
BookingStatus,
|
||||
OrderStatus,
|
||||
} from './enums'
|
||||
|
||||
// Constants
|
||||
export {
|
||||
DEFAULT_CANCEL_HOURS_LIMIT,
|
||||
DEFAULT_SLOT_CAPACITY,
|
||||
SLOT_GENERATION_DAYS,
|
||||
TIME_PERIODS,
|
||||
DATE_SELECTOR_DAYS,
|
||||
WEEKDAY_LABELS,
|
||||
} from './constants'
|
||||
|
||||
// Types
|
||||
export type {
|
||||
User,
|
||||
UserProfileResponse,
|
||||
UpdateProfileDto,
|
||||
UserStatsResponse,
|
||||
CardType,
|
||||
CreateCardTypeDto,
|
||||
UpdateCardTypeDto,
|
||||
Membership,
|
||||
MembershipWithCardType,
|
||||
WeekTemplate,
|
||||
WeekTemplateInput,
|
||||
TimeSlot,
|
||||
TimeSlotWithBookingStatus,
|
||||
CreateManualSlotDto,
|
||||
Booking,
|
||||
BookingWithDetails,
|
||||
CreateBookingDto,
|
||||
Order,
|
||||
OrderWithDetails,
|
||||
CreateOrderDto,
|
||||
PaymentParams,
|
||||
CreateOrderResponse,
|
||||
StudioConfig,
|
||||
UpdateStudioConfigDto,
|
||||
ApiResponse,
|
||||
PaginatedData,
|
||||
PaginatedResponse,
|
||||
PaginationQuery,
|
||||
} from './types/index'
|
||||
19
packages/shared/src/types/api.ts
Normal file
19
packages/shared/src/types/api.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
export interface ApiResponse<T> {
|
||||
readonly success: boolean
|
||||
readonly data: T | null
|
||||
readonly message: string | null
|
||||
}
|
||||
|
||||
export interface PaginatedData<T> {
|
||||
readonly items: readonly T[]
|
||||
readonly total: number
|
||||
readonly page: number
|
||||
readonly limit: number
|
||||
}
|
||||
|
||||
export type PaginatedResponse<T> = ApiResponse<PaginatedData<T>>
|
||||
|
||||
export interface PaginationQuery {
|
||||
readonly page?: number
|
||||
readonly limit?: number
|
||||
}
|
||||
31
packages/shared/src/types/booking.ts
Normal file
31
packages/shared/src/types/booking.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { BookingStatus } from '../enums'
|
||||
|
||||
export interface Booking {
|
||||
readonly id: string
|
||||
readonly userId: string
|
||||
readonly timeSlotId: string
|
||||
readonly membershipId: string
|
||||
readonly status: BookingStatus
|
||||
readonly cancelledAt: string | null
|
||||
readonly createdAt: string
|
||||
readonly updatedAt: string
|
||||
}
|
||||
|
||||
export interface BookingWithDetails extends Booking {
|
||||
readonly timeSlot: {
|
||||
readonly date: string
|
||||
readonly startTime: string
|
||||
readonly endTime: string
|
||||
}
|
||||
readonly membership: {
|
||||
readonly id: string
|
||||
readonly cardType: {
|
||||
readonly name: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface CreateBookingDto {
|
||||
readonly timeSlotId: string
|
||||
readonly membershipId: string
|
||||
}
|
||||
38
packages/shared/src/types/card-type.ts
Normal file
38
packages/shared/src/types/card-type.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { CardTypeCategory } from '../enums'
|
||||
|
||||
export interface CardType {
|
||||
readonly id: string
|
||||
readonly name: string
|
||||
readonly type: CardTypeCategory
|
||||
readonly totalTimes: number | null
|
||||
readonly durationDays: number
|
||||
readonly price: number
|
||||
readonly originalPrice: number | null
|
||||
readonly description: string | null
|
||||
readonly isActive: boolean
|
||||
readonly sortOrder: number
|
||||
readonly createdAt: string
|
||||
readonly updatedAt: string
|
||||
}
|
||||
|
||||
export interface CreateCardTypeDto {
|
||||
readonly name: string
|
||||
readonly type: CardTypeCategory
|
||||
readonly totalTimes?: number
|
||||
readonly durationDays: number
|
||||
readonly price: number
|
||||
readonly originalPrice?: number
|
||||
readonly description?: string
|
||||
readonly sortOrder?: number
|
||||
}
|
||||
|
||||
export interface UpdateCardTypeDto {
|
||||
readonly name?: string
|
||||
readonly totalTimes?: number
|
||||
readonly durationDays?: number
|
||||
readonly price?: number
|
||||
readonly originalPrice?: number
|
||||
readonly description?: string
|
||||
readonly isActive?: boolean
|
||||
readonly sortOrder?: number
|
||||
}
|
||||
9
packages/shared/src/types/index.ts
Normal file
9
packages/shared/src/types/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export type { User, UserProfileResponse, UpdateProfileDto, UserStatsResponse } from './user'
|
||||
export type { CardType, CreateCardTypeDto, UpdateCardTypeDto } from './card-type'
|
||||
export type { Membership, MembershipWithCardType } from './membership'
|
||||
export type { WeekTemplate, WeekTemplateInput } from './week-template'
|
||||
export type { TimeSlot, TimeSlotWithBookingStatus, CreateManualSlotDto } from './time-slot'
|
||||
export type { Booking, BookingWithDetails, CreateBookingDto } from './booking'
|
||||
export type { Order, OrderWithDetails, CreateOrderDto, PaymentParams, CreateOrderResponse } from './order'
|
||||
export type { StudioConfig, UpdateStudioConfigDto } from './studio'
|
||||
export type { ApiResponse, PaginatedData, PaginatedResponse, PaginationQuery } from './api'
|
||||
18
packages/shared/src/types/membership.ts
Normal file
18
packages/shared/src/types/membership.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { MembershipStatus } from '../enums'
|
||||
import { CardType } from './card-type'
|
||||
|
||||
export interface Membership {
|
||||
readonly id: string
|
||||
readonly userId: string
|
||||
readonly cardTypeId: string
|
||||
readonly remainingTimes: number | null
|
||||
readonly startDate: string
|
||||
readonly expireDate: string
|
||||
readonly status: MembershipStatus
|
||||
readonly createdAt: string
|
||||
readonly updatedAt: string
|
||||
}
|
||||
|
||||
export interface MembershipWithCardType extends Membership {
|
||||
readonly cardType: CardType
|
||||
}
|
||||
42
packages/shared/src/types/order.ts
Normal file
42
packages/shared/src/types/order.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { OrderStatus } from '../enums'
|
||||
|
||||
export interface Order {
|
||||
readonly id: string
|
||||
readonly userId: string
|
||||
readonly cardTypeId: string
|
||||
readonly orderNo: string
|
||||
readonly amount: number
|
||||
readonly status: OrderStatus
|
||||
readonly wxTransactionId: string | null
|
||||
readonly paidAt: string | null
|
||||
readonly createdAt: string
|
||||
readonly updatedAt: string
|
||||
}
|
||||
|
||||
export interface OrderWithDetails extends Order {
|
||||
readonly cardType: {
|
||||
readonly name: string
|
||||
readonly type: string
|
||||
}
|
||||
readonly user?: {
|
||||
readonly nickname: string
|
||||
readonly phone: string | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface CreateOrderDto {
|
||||
readonly cardTypeId: string
|
||||
}
|
||||
|
||||
export interface PaymentParams {
|
||||
readonly timeStamp: string
|
||||
readonly nonceStr: string
|
||||
readonly package: string
|
||||
readonly signType: string
|
||||
readonly paySign: string
|
||||
}
|
||||
|
||||
export interface CreateOrderResponse {
|
||||
readonly order: Order
|
||||
readonly paymentParams: PaymentParams
|
||||
}
|
||||
25
packages/shared/src/types/studio.ts
Normal file
25
packages/shared/src/types/studio.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
export interface StudioConfig {
|
||||
readonly id: string
|
||||
readonly name: string
|
||||
readonly logo: string | null
|
||||
readonly bannerUrl: string | null
|
||||
readonly address: string
|
||||
readonly phone: string
|
||||
readonly latitude: number | null
|
||||
readonly longitude: number | null
|
||||
readonly cancelHoursLimit: number
|
||||
readonly photos: string[]
|
||||
readonly updatedAt: string
|
||||
}
|
||||
|
||||
export interface UpdateStudioConfigDto {
|
||||
readonly name?: string
|
||||
readonly logo?: string
|
||||
readonly bannerUrl?: string
|
||||
readonly address?: string
|
||||
readonly phone?: string
|
||||
readonly latitude?: number
|
||||
readonly longitude?: number
|
||||
readonly cancelHoursLimit?: number
|
||||
readonly photos?: string[]
|
||||
}
|
||||
29
packages/shared/src/types/time-slot.ts
Normal file
29
packages/shared/src/types/time-slot.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { TimeSlotStatus, TimeSlotSource } from '../enums'
|
||||
|
||||
export interface TimeSlot {
|
||||
readonly id: string
|
||||
readonly date: string
|
||||
readonly startTime: string
|
||||
readonly endTime: string
|
||||
readonly capacity: number
|
||||
readonly bookedCount: number
|
||||
readonly status: TimeSlotStatus
|
||||
readonly source: TimeSlotSource
|
||||
readonly templateId: string | null
|
||||
readonly createdAt: string
|
||||
readonly updatedAt: string
|
||||
}
|
||||
|
||||
export interface TimeSlotWithBookingStatus extends TimeSlot {
|
||||
/** 当前用户是否已预约此时段 */
|
||||
readonly isBookedByMe: boolean
|
||||
/** 当前用户在此时段的预约 ID(用于取消) */
|
||||
readonly myBookingId: string | null
|
||||
}
|
||||
|
||||
export interface CreateManualSlotDto {
|
||||
readonly date: string
|
||||
readonly startTime: string
|
||||
readonly endTime: string
|
||||
readonly capacity?: number
|
||||
}
|
||||
36
packages/shared/src/types/user.ts
Normal file
36
packages/shared/src/types/user.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { UserRole } from '../enums'
|
||||
|
||||
export interface User {
|
||||
readonly id: string
|
||||
readonly openid: string
|
||||
readonly unionid: string | null
|
||||
readonly phone: string | null
|
||||
readonly nickname: string
|
||||
readonly avatarUrl: string | null
|
||||
readonly role: UserRole
|
||||
readonly createdAt: string
|
||||
readonly updatedAt: string
|
||||
}
|
||||
|
||||
export interface UserProfileResponse {
|
||||
readonly id: string
|
||||
readonly phone: string | null
|
||||
readonly nickname: string
|
||||
readonly avatarUrl: string | null
|
||||
readonly role: UserRole
|
||||
readonly activeMembershipCount: number
|
||||
readonly createdAt: string
|
||||
}
|
||||
|
||||
export interface UpdateProfileDto {
|
||||
readonly nickname?: string
|
||||
readonly avatarUrl?: string
|
||||
}
|
||||
|
||||
export interface UserStatsResponse {
|
||||
readonly totalBookings: number
|
||||
readonly totalDays: number
|
||||
readonly monthBookings: number
|
||||
readonly monthDays: number
|
||||
readonly monthHours: number
|
||||
}
|
||||
18
packages/shared/src/types/week-template.ts
Normal file
18
packages/shared/src/types/week-template.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
export interface WeekTemplate {
|
||||
readonly id: string
|
||||
readonly dayOfWeek: number
|
||||
readonly startTime: string
|
||||
readonly endTime: string
|
||||
readonly capacity: number
|
||||
readonly isActive: boolean
|
||||
readonly createdAt: string
|
||||
readonly updatedAt: string
|
||||
}
|
||||
|
||||
export interface WeekTemplateInput {
|
||||
readonly dayOfWeek: number
|
||||
readonly startTime: string
|
||||
readonly endTime: string
|
||||
readonly capacity?: number
|
||||
readonly isActive?: boolean
|
||||
}
|
||||
10
packages/shared/tsconfig.json
Normal file
10
packages/shared/tsconfig.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"declaration": true,
|
||||
"declarationMap": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
Reference in New Issue
Block a user