feat: 新增个人身体画像评估与馆主经营助手
把 3 分钟身体状态评估做成独立获客链路,匿名测评后登录认领完整报告,并接入体验预约与今日待办。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -62,3 +62,171 @@ export enum SubscriptionMessageScene {
|
||||
CLASS_REMINDER = 'CLASS_REMINDER',
|
||||
ADMIN_BOOKING_CREATED = 'ADMIN_BOOKING_CREATED',
|
||||
}
|
||||
|
||||
// ===== Body portrait =====
|
||||
export enum BodyPortraitSource {
|
||||
XHS = 'xhs',
|
||||
WECHAT = 'wechat',
|
||||
DIANPING = 'dianping',
|
||||
MEMBER_SHARE = 'member_share',
|
||||
ORGANIC = 'organic',
|
||||
OTHER = 'other',
|
||||
}
|
||||
|
||||
export enum BodyPortraitAssessmentStatus {
|
||||
DRAFT = 'DRAFT',
|
||||
COMPLETED = 'COMPLETED',
|
||||
CLAIMED = 'CLAIMED',
|
||||
EXPIRED = 'EXPIRED',
|
||||
}
|
||||
|
||||
export enum BodyRegion {
|
||||
NECK = 'neck',
|
||||
SHOULDER = 'shoulder',
|
||||
UPPER_BACK = 'upperBack',
|
||||
LOW_BACK = 'lowBack',
|
||||
PELVIS = 'pelvis',
|
||||
HIP = 'hip',
|
||||
KNEE = 'knee',
|
||||
LEG = 'leg',
|
||||
}
|
||||
|
||||
export enum PortraitGoal {
|
||||
POSTURE = 'posture',
|
||||
NECK_RELIEF = 'neckRelief',
|
||||
BACK_COMFORT = 'backComfort',
|
||||
CORE = 'core',
|
||||
SHAPING = 'shaping',
|
||||
HIP_LEG = 'hipLeg',
|
||||
STABILITY = 'stability',
|
||||
OTHER = 'other',
|
||||
}
|
||||
|
||||
export enum SittingHours {
|
||||
LT4 = 'lt4',
|
||||
H4_TO_6 = 'h4to6',
|
||||
H6_TO_8 = 'h6to8',
|
||||
GT8 = 'gt8',
|
||||
}
|
||||
|
||||
export enum ExerciseFreq {
|
||||
NONE = 'none',
|
||||
W1_TO_2 = 'w1to2',
|
||||
W3_TO_4 = 'w3to4',
|
||||
W5_PLUS = 'w5plus',
|
||||
}
|
||||
|
||||
export enum WorkPosture {
|
||||
COMPUTER = 'computer',
|
||||
PHONE = 'phone',
|
||||
STANDING = 'standing',
|
||||
WALKING = 'walking',
|
||||
HOLDING_CHILD = 'holdingChild',
|
||||
OTHER = 'other',
|
||||
}
|
||||
|
||||
export enum AfterSitting {
|
||||
NECK_TIGHT = 'neckTight',
|
||||
LOW_BACK_ACHE = 'lowBackAche',
|
||||
BACK_STIFF = 'backStiff',
|
||||
HIP_TIGHT = 'hipTight',
|
||||
NONE = 'none',
|
||||
}
|
||||
|
||||
export enum StandingNotice {
|
||||
HEAD_FORWARD = 'headForward',
|
||||
ROUNDED_SHOULDERS = 'roundedShoulders',
|
||||
UNEVEN_SHOULDERS = 'unevenShoulders',
|
||||
BELLY_FORWARD = 'bellyForward',
|
||||
LOCKED_KNEES = 'lockedKnees',
|
||||
UNNOTICED = 'unnoticed',
|
||||
}
|
||||
|
||||
export enum SafetyFlag {
|
||||
PERSISTENT_PAIN = 'persistentPain',
|
||||
RECENT_INJURY = 'recentInjury',
|
||||
NUMBNESS = 'numbness',
|
||||
DOCTOR_LIMIT = 'doctorLimit',
|
||||
MEDICAL_RECOVERY = 'medicalRecovery',
|
||||
NONE = 'none',
|
||||
}
|
||||
|
||||
export enum BodyDimension {
|
||||
CERVICAL_SHOULDER = 'cervicalShoulder',
|
||||
SPINAL_MOBILITY = 'spinalMobility',
|
||||
CORE_CONTROL = 'coreControl',
|
||||
HIP_PELVIS = 'hipPelvis',
|
||||
LOWER_LIMB = 'lowerLimb',
|
||||
}
|
||||
|
||||
export enum ConcernLevel {
|
||||
LOW = 'low',
|
||||
MILD = 'mild',
|
||||
MODERATE = 'moderate',
|
||||
HIGH = 'high',
|
||||
PRIORITY = 'priority',
|
||||
}
|
||||
|
||||
export enum PortraitType {
|
||||
SEDENTARY_NECK_TENSION = 'sedentaryNeckTension',
|
||||
SEDENTARY_CORE_WEAK = 'sedentaryCoreWeak',
|
||||
NECK_COMPENSATION = 'neckCompensation',
|
||||
HIP_TIGHT = 'hipTight',
|
||||
UPPER_LOWER_CROSS = 'upperLowerCross',
|
||||
LOWER_LIMB_UNSTABLE = 'lowerLimbUnstable',
|
||||
MIXED_FATIGUE = 'mixedFatigue',
|
||||
LOW_OVERALL_CONCERN = 'lowOverallConcern',
|
||||
}
|
||||
|
||||
export enum PortraitMatchQuality {
|
||||
FULL = 'full',
|
||||
PARTIAL = 'partial',
|
||||
}
|
||||
|
||||
export enum GrowthLeadStage {
|
||||
VISIT = 'VISIT',
|
||||
STARTED = 'STARTED',
|
||||
COMPLETED = 'COMPLETED',
|
||||
CLAIMED = 'CLAIMED',
|
||||
PHONE_BOUND = 'PHONE_BOUND',
|
||||
TRIAL_PURCHASED = 'TRIAL_PURCHASED',
|
||||
TRIAL_BOOKED = 'TRIAL_BOOKED',
|
||||
TRIAL_ATTENDED = 'TRIAL_ATTENDED',
|
||||
PLAN_PURCHASED = 'PLAN_PURCHASED',
|
||||
TRAINING = 'TRAINING',
|
||||
RENEWAL_DUE = 'RENEWAL_DUE',
|
||||
RENEWED = 'RENEWED',
|
||||
}
|
||||
|
||||
export enum GrowthEventName {
|
||||
ASSESSMENT_STARTED = 'assessment_started',
|
||||
ASSESSMENT_COMPLETED = 'assessment_completed',
|
||||
ASSESSMENT_CLAIMED = 'assessment_claimed',
|
||||
REPORT_VIEWED = 'report_viewed',
|
||||
ADVICE_VIEWED = 'advice_viewed',
|
||||
PHONE_BOUND = 'phone_bound',
|
||||
TRIAL_CLICKED = 'trial_clicked',
|
||||
TRIAL_PURCHASED = 'trial_purchased',
|
||||
TRIAL_BOOKED = 'trial_booked',
|
||||
TRIAL_ATTENDED = 'trial_attended',
|
||||
PLAN_PURCHASED = 'plan_purchased',
|
||||
REPORT_SHARED = 'report_shared',
|
||||
}
|
||||
|
||||
export enum ProfessionalAssessmentKind {
|
||||
INITIAL = 'INITIAL',
|
||||
FOLLOW_UP = 'FOLLOW_UP',
|
||||
}
|
||||
|
||||
export enum TrainingPlanStatus {
|
||||
DRAFT = 'DRAFT',
|
||||
ACTIVE = 'ACTIVE',
|
||||
COMPLETED = 'COMPLETED',
|
||||
}
|
||||
|
||||
export enum ProgressPhotoAngle {
|
||||
FRONT = 'FRONT',
|
||||
SIDE = 'SIDE',
|
||||
BACK = 'BACK',
|
||||
DETAIL = 'DETAIL',
|
||||
}
|
||||
|
||||
@@ -9,6 +9,25 @@ export {
|
||||
OrderStatus,
|
||||
InviteReferralStatus,
|
||||
SubscriptionMessageScene,
|
||||
BodyPortraitSource,
|
||||
BodyPortraitAssessmentStatus,
|
||||
BodyRegion,
|
||||
PortraitGoal,
|
||||
SittingHours,
|
||||
ExerciseFreq,
|
||||
WorkPosture,
|
||||
AfterSitting,
|
||||
StandingNotice,
|
||||
SafetyFlag,
|
||||
BodyDimension,
|
||||
ConcernLevel,
|
||||
PortraitType,
|
||||
PortraitMatchQuality,
|
||||
GrowthLeadStage,
|
||||
GrowthEventName,
|
||||
ProfessionalAssessmentKind,
|
||||
TrainingPlanStatus,
|
||||
ProgressPhotoAngle,
|
||||
} from './enums'
|
||||
|
||||
// Constants
|
||||
@@ -116,3 +135,4 @@ export type {
|
||||
} from './types/index'
|
||||
|
||||
export * from './types/member-care'
|
||||
export * from './types/body-portrait'
|
||||
|
||||
427
packages/shared/src/types/body-portrait.ts
Normal file
427
packages/shared/src/types/body-portrait.ts
Normal file
@@ -0,0 +1,427 @@
|
||||
import {
|
||||
AfterSitting,
|
||||
BodyDimension,
|
||||
BodyPortraitAssessmentStatus,
|
||||
BodyPortraitSource,
|
||||
BodyRegion,
|
||||
ConcernLevel,
|
||||
ExerciseFreq,
|
||||
GrowthEventName,
|
||||
GrowthLeadStage,
|
||||
PortraitGoal,
|
||||
PortraitMatchQuality,
|
||||
PortraitType,
|
||||
ProfessionalAssessmentKind,
|
||||
ProgressPhotoAngle,
|
||||
SafetyFlag,
|
||||
SittingHours,
|
||||
StandingNotice,
|
||||
TrainingPlanStatus,
|
||||
WorkPosture,
|
||||
} from '../enums'
|
||||
|
||||
export const BODY_PORTRAIT_QUESTIONNAIRE_VERSION = 'portrait-q-v1'
|
||||
export const BODY_PORTRAIT_RULES_VERSION = 'portrait-r-v1'
|
||||
export const BODY_PORTRAIT_OFFLINE_PROTOCOL = 'offline-v1'
|
||||
export const BODY_PORTRAIT_DISCLAIMER =
|
||||
'本评估不是医疗诊断或体态疾病检测,仅用于运动训练参考。若你正处于明显疼痛、伤病或医生限制运动的阶段,请先由医生或相应专业人士确认运动条件。'
|
||||
|
||||
export const BODY_REGION_LABELS: Record<BodyRegion, string> = {
|
||||
[BodyRegion.NECK]: '头颈',
|
||||
[BodyRegion.SHOULDER]: '肩',
|
||||
[BodyRegion.UPPER_BACK]: '上背',
|
||||
[BodyRegion.LOW_BACK]: '腰',
|
||||
[BodyRegion.PELVIS]: '骨盆',
|
||||
[BodyRegion.HIP]: '髋',
|
||||
[BodyRegion.KNEE]: '膝',
|
||||
[BodyRegion.LEG]: '腿',
|
||||
}
|
||||
|
||||
export const PORTRAIT_GOAL_LABELS: Record<PortraitGoal, string> = {
|
||||
[PortraitGoal.POSTURE]: '看起来更挺拔',
|
||||
[PortraitGoal.NECK_RELIEF]: '肩颈没那么累',
|
||||
[PortraitGoal.BACK_COMFORT]: '久坐更舒服',
|
||||
[PortraitGoal.CORE]: '腹部更有力量',
|
||||
[PortraitGoal.SHAPING]: '身体线条更好',
|
||||
[PortraitGoal.HIP_LEG]: '腿型/髋部状态改善',
|
||||
[PortraitGoal.STABILITY]: '动作更稳定',
|
||||
[PortraitGoal.OTHER]: '我有自己的目标',
|
||||
}
|
||||
|
||||
export const SITTING_HOURS_LABELS: Record<SittingHours, string> = {
|
||||
[SittingHours.LT4]: '不到 4 小时',
|
||||
[SittingHours.H4_TO_6]: '4~6 小时',
|
||||
[SittingHours.H6_TO_8]: '6~8 小时',
|
||||
[SittingHours.GT8]: '超过 8 小时',
|
||||
}
|
||||
|
||||
export const EXERCISE_FREQ_LABELS: Record<ExerciseFreq, string> = {
|
||||
[ExerciseFreq.NONE]: '几乎不运动',
|
||||
[ExerciseFreq.W1_TO_2]: '1~2 次/周',
|
||||
[ExerciseFreq.W3_TO_4]: '3~4 次/周',
|
||||
[ExerciseFreq.W5_PLUS]: '5 次以上',
|
||||
}
|
||||
|
||||
export const WORK_POSTURE_LABELS: Record<WorkPosture, string> = {
|
||||
[WorkPosture.COMPUTER]: '电脑办公',
|
||||
[WorkPosture.PHONE]: '低头手机',
|
||||
[WorkPosture.STANDING]: '久站',
|
||||
[WorkPosture.WALKING]: '频繁走动',
|
||||
[WorkPosture.HOLDING_CHILD]: '抱娃',
|
||||
[WorkPosture.OTHER]: '其他',
|
||||
}
|
||||
|
||||
export const AFTER_SITTING_LABELS: Record<AfterSitting, string> = {
|
||||
[AfterSitting.NECK_TIGHT]: '肩颈紧',
|
||||
[AfterSitting.LOW_BACK_ACHE]: '腰酸',
|
||||
[AfterSitting.BACK_STIFF]: '背部僵硬',
|
||||
[AfterSitting.HIP_TIGHT]: '臀腿紧',
|
||||
[AfterSitting.NONE]: '没明显感觉',
|
||||
}
|
||||
|
||||
export const STANDING_NOTICE_LABELS: Record<StandingNotice, string> = {
|
||||
[StandingNotice.HEAD_FORWARD]: '头容易往前',
|
||||
[StandingNotice.ROUNDED_SHOULDERS]: '肩膀向内',
|
||||
[StandingNotice.UNEVEN_SHOULDERS]: '左右肩不一样高',
|
||||
[StandingNotice.BELLY_FORWARD]: '肚子容易往前顶',
|
||||
[StandingNotice.LOCKED_KNEES]: '膝盖容易锁死',
|
||||
[StandingNotice.UNNOTICED]: '没有注意过',
|
||||
}
|
||||
|
||||
export const SAFETY_FLAG_LABELS: Record<SafetyFlag, string> = {
|
||||
[SafetyFlag.PERSISTENT_PAIN]: '持续明显疼痛',
|
||||
[SafetyFlag.RECENT_INJURY]: '最近受伤',
|
||||
[SafetyFlag.NUMBNESS]: '手脚明显麻木',
|
||||
[SafetyFlag.DOCTOR_LIMIT]: '医生要求限制运动',
|
||||
[SafetyFlag.MEDICAL_RECOVERY]: '正处于需要专业医疗评估的恢复阶段',
|
||||
[SafetyFlag.NONE]: '以上都没有',
|
||||
}
|
||||
|
||||
export const BODY_DIMENSION_LABELS: Record<BodyDimension, string> = {
|
||||
[BodyDimension.CERVICAL_SHOULDER]: '肩颈状态',
|
||||
[BodyDimension.SPINAL_MOBILITY]: '脊柱活动',
|
||||
[BodyDimension.CORE_CONTROL]: '核心控制',
|
||||
[BodyDimension.HIP_PELVIS]: '髋骨盆状态',
|
||||
[BodyDimension.LOWER_LIMB]: '下肢稳定',
|
||||
}
|
||||
|
||||
export const CONCERN_LEVEL_LABELS: Record<ConcernLevel, string> = {
|
||||
[ConcernLevel.LOW]: '低关注',
|
||||
[ConcernLevel.MILD]: '轻度关注',
|
||||
[ConcernLevel.MODERATE]: '中度关注',
|
||||
[ConcernLevel.HIGH]: '高关注',
|
||||
[ConcernLevel.PRIORITY]: '重点关注',
|
||||
}
|
||||
|
||||
export const PORTRAIT_TYPE_LABELS: Record<PortraitType, string> = {
|
||||
[PortraitType.SEDENTARY_NECK_TENSION]: '久坐肩颈紧张型',
|
||||
[PortraitType.SEDENTARY_CORE_WEAK]: '久坐核心弱化型',
|
||||
[PortraitType.NECK_COMPENSATION]: '肩颈代偿型',
|
||||
[PortraitType.HIP_TIGHT]: '髋部紧张型',
|
||||
[PortraitType.UPPER_LOWER_CROSS]: '上下交叉混合型',
|
||||
[PortraitType.LOWER_LIMB_UNSTABLE]: '下肢稳定不足型',
|
||||
[PortraitType.MIXED_FATIGUE]: '全身疲劳累积型',
|
||||
[PortraitType.LOW_OVERALL_CONCERN]: '整体关注度较低型',
|
||||
}
|
||||
|
||||
export const GROWTH_LEAD_STAGE_LABELS: Record<GrowthLeadStage, string> = {
|
||||
[GrowthLeadStage.VISIT]: '访问',
|
||||
[GrowthLeadStage.STARTED]: '开始测评',
|
||||
[GrowthLeadStage.COMPLETED]: '完成报告',
|
||||
[GrowthLeadStage.CLAIMED]: '已认领',
|
||||
[GrowthLeadStage.PHONE_BOUND]: '已留联系方式',
|
||||
[GrowthLeadStage.TRIAL_PURCHASED]: '已购体验',
|
||||
[GrowthLeadStage.TRIAL_BOOKED]: '已预约',
|
||||
[GrowthLeadStage.TRIAL_ATTENDED]: '已到店',
|
||||
[GrowthLeadStage.PLAN_PURCHASED]: '已购买计划',
|
||||
[GrowthLeadStage.TRAINING]: '训练中',
|
||||
[GrowthLeadStage.RENEWAL_DUE]: '待续费',
|
||||
[GrowthLeadStage.RENEWED]: '已续费',
|
||||
}
|
||||
|
||||
export interface BodyPortraitAnswers {
|
||||
readonly concerns: readonly BodyRegion[]
|
||||
readonly goal: PortraitGoal | null
|
||||
readonly sittingHours: SittingHours | null
|
||||
readonly exerciseFreq: ExerciseFreq | null
|
||||
readonly workPosture: WorkPosture | null
|
||||
readonly endOfDayFatigue: readonly BodyRegion[]
|
||||
readonly afterSitting: readonly AfterSitting[]
|
||||
readonly standingNotice: readonly StandingNotice[]
|
||||
readonly safety: readonly SafetyFlag[]
|
||||
}
|
||||
|
||||
export interface BodyPortraitScores {
|
||||
readonly cervicalShoulder: number
|
||||
readonly spinalMobility: number
|
||||
readonly coreControl: number
|
||||
readonly hipPelvis: number
|
||||
readonly lowerLimb: number
|
||||
}
|
||||
|
||||
export interface BodyPortraitLevels {
|
||||
readonly cervicalShoulder: ConcernLevel
|
||||
readonly spinalMobility: ConcernLevel
|
||||
readonly coreControl: ConcernLevel
|
||||
readonly hipPelvis: ConcernLevel
|
||||
readonly lowerLimb: ConcernLevel
|
||||
}
|
||||
|
||||
export interface BodyPortraitEvidence {
|
||||
readonly dimension: BodyDimension
|
||||
readonly title: string
|
||||
readonly answers: readonly string[]
|
||||
readonly explanation: string
|
||||
}
|
||||
|
||||
export interface BodyPortraitAdviceItem {
|
||||
readonly title: string
|
||||
readonly detail: string
|
||||
readonly stopIf: string
|
||||
}
|
||||
|
||||
export interface BodyPortraitAdvice {
|
||||
readonly id: string
|
||||
readonly items: readonly BodyPortraitAdviceItem[]
|
||||
}
|
||||
|
||||
export interface BodyPortraitChain {
|
||||
readonly steps: readonly string[]
|
||||
readonly takeaway: string
|
||||
}
|
||||
|
||||
export interface BodyPortraitSafetyResult {
|
||||
readonly flagged: boolean
|
||||
readonly flags: readonly SafetyFlag[]
|
||||
readonly message: string | null
|
||||
}
|
||||
|
||||
export interface BodyPortraitReport {
|
||||
readonly questionnaireVersion: string
|
||||
readonly rulesVersion: string
|
||||
readonly scores: BodyPortraitScores
|
||||
readonly levels: BodyPortraitLevels
|
||||
readonly primaryType: PortraitType
|
||||
readonly secondaryType: PortraitType | null
|
||||
readonly headline: string
|
||||
readonly summary: string
|
||||
readonly evidence: readonly BodyPortraitEvidence[]
|
||||
readonly chain: BodyPortraitChain
|
||||
readonly advice: BodyPortraitAdvice | null
|
||||
readonly matchQuality: PortraitMatchQuality
|
||||
readonly safety: BodyPortraitSafetyResult
|
||||
readonly firstAssessmentHints: readonly string[]
|
||||
readonly goalLabel: string | null
|
||||
}
|
||||
|
||||
export interface BodyPortraitTeaser {
|
||||
readonly assessmentId: string
|
||||
readonly headline: string
|
||||
readonly primaryType: PortraitType
|
||||
readonly primaryTypeLabel: string
|
||||
readonly topDimension: BodyDimension | null
|
||||
readonly topDimensionLabel: string | null
|
||||
readonly matchQuality: PortraitMatchQuality
|
||||
readonly safetyFlagged: boolean
|
||||
readonly disclaimer: string
|
||||
}
|
||||
|
||||
export interface BodyPortraitVisitResponse {
|
||||
readonly visitId: string
|
||||
readonly visitToken: string
|
||||
readonly source: BodyPortraitSource
|
||||
}
|
||||
|
||||
export interface BodyPortraitSessionResponse {
|
||||
readonly assessmentId: string
|
||||
readonly accessToken: string
|
||||
readonly visitToken: string
|
||||
readonly questionnaireVersion: string
|
||||
readonly status: BodyPortraitAssessmentStatus
|
||||
readonly answers: BodyPortraitAnswers
|
||||
readonly teaser: BodyPortraitTeaser | null
|
||||
readonly report: BodyPortraitReport | null
|
||||
readonly claimed: boolean
|
||||
}
|
||||
|
||||
export interface BodyPortraitStats {
|
||||
readonly completedCount: number
|
||||
}
|
||||
|
||||
export interface CreateBodyPortraitVisitDto {
|
||||
readonly source?: BodyPortraitSource | string
|
||||
readonly campaignId?: string
|
||||
readonly referralCode?: string
|
||||
readonly landingPath?: string
|
||||
}
|
||||
|
||||
export interface SaveBodyPortraitAnswersDto {
|
||||
readonly accessToken: string
|
||||
readonly answers: Partial<BodyPortraitAnswers>
|
||||
}
|
||||
|
||||
export interface BodyPortraitAccessDto {
|
||||
readonly accessToken: string
|
||||
}
|
||||
|
||||
export interface TrackGrowthEventDto {
|
||||
readonly name: GrowthEventName
|
||||
readonly accessToken?: string
|
||||
readonly idempotencyKey?: string
|
||||
}
|
||||
|
||||
export interface GrowthEventRecord {
|
||||
readonly id: string
|
||||
readonly name: GrowthEventName
|
||||
readonly occurredAt: string
|
||||
}
|
||||
|
||||
export interface GrowthLeadSummary {
|
||||
readonly id: string
|
||||
readonly userId: string
|
||||
readonly nickname: string
|
||||
readonly phone: string | null
|
||||
readonly stage: GrowthLeadStage
|
||||
readonly source: BodyPortraitSource | null
|
||||
readonly campaignId: string | null
|
||||
readonly primaryType: PortraitType | null
|
||||
readonly topDimension: BodyDimension | null
|
||||
readonly safetyFlagged: boolean
|
||||
readonly lastActiveAt: string
|
||||
readonly completedAt: string | null
|
||||
readonly followUpDraft: string
|
||||
}
|
||||
|
||||
export interface GrowthLeadDetail extends GrowthLeadSummary {
|
||||
readonly goalLabel: string | null
|
||||
readonly scores: BodyPortraitScores | null
|
||||
readonly levels: BodyPortraitLevels | null
|
||||
readonly evidence: readonly BodyPortraitEvidence[]
|
||||
readonly answers: BodyPortraitAnswers | null
|
||||
readonly report: BodyPortraitReport | null
|
||||
readonly events: readonly GrowthEventRecord[]
|
||||
readonly coachNote: string
|
||||
readonly firstAssessmentHints: readonly string[]
|
||||
}
|
||||
|
||||
export interface GrowthTodayTask {
|
||||
readonly kind: 'completed_unbooked' | 'trial_unpurchased' | 'reassessment_due'
|
||||
readonly leadId: string
|
||||
readonly userId: string
|
||||
readonly nickname: string
|
||||
readonly title: string
|
||||
readonly detail: string
|
||||
readonly happenedAt: string
|
||||
readonly followUpDraft: string
|
||||
}
|
||||
|
||||
export interface GrowthFunnelRow {
|
||||
readonly source: BodyPortraitSource
|
||||
readonly started: number
|
||||
readonly completed: number
|
||||
readonly claimed: number
|
||||
readonly booked: number
|
||||
readonly attended: number
|
||||
readonly purchased: number
|
||||
}
|
||||
|
||||
export interface GrowthTodayDashboard {
|
||||
readonly tasks: readonly GrowthTodayTask[]
|
||||
readonly funnel: readonly GrowthFunnelRow[]
|
||||
}
|
||||
|
||||
export interface ProfessionalObservationScores {
|
||||
readonly headPosition: number
|
||||
readonly shoulderPosition: number
|
||||
readonly thoracicExtension: number
|
||||
readonly shoulderFlexion: number
|
||||
readonly breathing: number
|
||||
readonly pelvis: number
|
||||
readonly coreControl: number
|
||||
readonly hipMobility: number
|
||||
readonly singleLeg: number
|
||||
}
|
||||
|
||||
export interface ProfessionalAssessmentSessionRecord {
|
||||
readonly id: string
|
||||
readonly userId: string
|
||||
readonly kind: ProfessionalAssessmentKind
|
||||
readonly protocolVersion: string
|
||||
readonly recordedAt: string
|
||||
readonly bookingId: string | null
|
||||
readonly originAssessmentId: string | null
|
||||
readonly observations: ProfessionalObservationScores
|
||||
readonly subjectiveTension: number | null
|
||||
readonly coachSummary: string
|
||||
readonly trainingFocus: string
|
||||
readonly phaseGoal: string
|
||||
readonly photoAngle: ProgressPhotoAngle | null
|
||||
}
|
||||
|
||||
export interface CreateProfessionalAssessmentDto {
|
||||
readonly kind: ProfessionalAssessmentKind
|
||||
readonly recordedAt: string
|
||||
readonly bookingId?: string
|
||||
readonly originAssessmentId?: string
|
||||
readonly observations: ProfessionalObservationScores
|
||||
readonly subjectiveTension?: number | null
|
||||
readonly coachSummary: string
|
||||
readonly trainingFocus: string
|
||||
readonly phaseGoal: string
|
||||
readonly photoAngle?: ProgressPhotoAngle | null
|
||||
}
|
||||
|
||||
export interface TrainingPlanPhaseRecord {
|
||||
readonly id: string
|
||||
readonly name: string
|
||||
readonly lessonStart: number
|
||||
readonly lessonEnd: number
|
||||
readonly focus: readonly string[]
|
||||
readonly summary: string
|
||||
}
|
||||
|
||||
export interface TrainingPlanRecord {
|
||||
readonly id: string
|
||||
readonly userId: string
|
||||
readonly title: string
|
||||
readonly status: TrainingPlanStatus
|
||||
readonly weeks: number
|
||||
readonly sessionId: string | null
|
||||
readonly phases: readonly TrainingPlanPhaseRecord[]
|
||||
}
|
||||
|
||||
export interface CreateTrainingPlanDto {
|
||||
readonly sessionId?: string
|
||||
readonly title?: string
|
||||
readonly weeks?: number
|
||||
}
|
||||
|
||||
export interface ReassessmentTodoRecord {
|
||||
readonly id: string
|
||||
readonly userId: string
|
||||
readonly planId: string
|
||||
readonly lessonCheckpoint: number
|
||||
readonly dueAt: string
|
||||
readonly completedAt: string | null
|
||||
}
|
||||
|
||||
export interface GrowthComparisonRow {
|
||||
readonly label: string
|
||||
readonly first: string
|
||||
readonly latest: string
|
||||
}
|
||||
|
||||
export interface GrowthShareCardRecord {
|
||||
readonly id: string
|
||||
readonly shareCode: string
|
||||
readonly title: string
|
||||
readonly caption: string
|
||||
readonly completedCount: number
|
||||
readonly weeks: number
|
||||
readonly rows: readonly GrowthComparisonRow[]
|
||||
readonly includePhotos: boolean
|
||||
}
|
||||
|
||||
export interface CreateGrowthShareCardDto {
|
||||
readonly includePhotos?: boolean
|
||||
}
|
||||
@@ -10,6 +10,7 @@ export interface Booking {
|
||||
readonly confirmedAt: string | null
|
||||
readonly completedAt: string | null
|
||||
readonly operatorId: string | null
|
||||
readonly originAssessmentId?: string | null
|
||||
readonly createdAt: string
|
||||
readonly updatedAt: string
|
||||
}
|
||||
@@ -69,6 +70,7 @@ export interface BookingStatusHistory {
|
||||
export interface CreateBookingDto {
|
||||
readonly timeSlotId: string
|
||||
readonly membershipId: string
|
||||
readonly originAssessmentId?: string
|
||||
}
|
||||
|
||||
export interface AdminArrangeBookingDto {
|
||||
|
||||
@@ -53,3 +53,4 @@ export type {
|
||||
} from './invite'
|
||||
|
||||
export type { TeachingAnalytics, TeachingAnalyticsRecord, TeachingAnalyticsSummary } from './teaching-analytics'
|
||||
export * from './body-portrait'
|
||||
|
||||
@@ -16,7 +16,7 @@ export interface MemberNoteRecord {
|
||||
booking: { timeSlot: { date: string; startTime: string } } | null
|
||||
}
|
||||
export interface ProgressPhotoRecord {
|
||||
id: string; caption: string; recordedAt: string; consentedAt: string | null; revokedAt: string | null
|
||||
id: string; caption: string; recordedAt: string; consentedAt: string | null; revokedAt: string | null; angle?: string | null; sessionId?: string | null
|
||||
}
|
||||
export interface ProgressArchive {
|
||||
nickname: string; completedCount: number; milestones: number[]; metrics: BodyMetricRecord[]; notes: MemberNoteRecord[]; photos: ProgressPhotoRecord[]
|
||||
|
||||
Reference in New Issue
Block a user