community.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. // D2 커뮤니티(종목게시판·예측·트랙레코드) 도메인 타입
  2. // Backend Application/Features/Api/Forum/StockBoard/*/Response.cs + TrackRecord/*/Response.cs 대응.
  3. // ⚠️ D2 enum 은 숫자로 직렬화됨 (JsonStringEnumConverter 미적용 — 확인 완료).
  4. // 응답 DTO 는 숫자 코드(direction/status/tierCode)와 라벨 문자열(directionLabel/statusLabel/tier)을 함께 내려준다.
  5. // 색상은 숫자 코드로, 표시 텍스트는 라벨 문자열을 사용한다. 라벨/색 맵은 이 파일 하단에 한 곳으로 모은다.
  6. // ── 예측 방향 (Domain PredictionDirection: 1 Up / 2 Down) ──
  7. export const PredictionDirection = {
  8. Up: 1,
  9. Down: 2
  10. } as const;
  11. export type PredictionDirectionValue = (typeof PredictionDirection)[keyof typeof PredictionDirection];
  12. // ── 예측 상태 (Domain PredictionStatus: 0 Pending / 1 Hit / 2 Miss / 3 Void) ──
  13. export const PredictionStatus = {
  14. Pending: 0,
  15. Hit: 1,
  16. Miss: 2,
  17. Void: 3
  18. } as const;
  19. export type PredictionStatusValue = (typeof PredictionStatus)[keyof typeof PredictionStatus];
  20. // ── 트랙레코드 배지 등급 (Domain TrackRecordTier: 0 None / 1 Bronze / 2 Silver / 3 Gold / 4 GoldAnt) ──
  21. export const TrackRecordTier = {
  22. None: 0,
  23. Bronze: 1,
  24. Silver: 2,
  25. Gold: 3,
  26. GoldAnt: 4
  27. } as const;
  28. export type TrackRecordTierValue = (typeof TrackRecordTier)[keyof typeof TrackRecordTier];
  29. // ── 예측 기간 (5 또는 20 영업일만 허용, Backend CreatePost.AllowedHorizonDays) ──
  30. export const PredictionHorizon = {
  31. Short: 5,
  32. Long: 20
  33. } as const;
  34. export type PredictionHorizonValue = (typeof PredictionHorizon)[keyof typeof PredictionHorizon];
  35. // ── GET /api/stock-boards/{code}/posts ──
  36. export interface StockBoardStatsHeader {
  37. stockCode: string;
  38. stockName: string|null;
  39. posts: number;
  40. comments: number;
  41. lastPostAt: string|null;
  42. }
  43. export interface StockBoardPostRow {
  44. num: number;
  45. id: number;
  46. stockCode: string;
  47. subject: string;
  48. thumbnail: string|null;
  49. name: string|null;
  50. sid: string|null;
  51. hasPrediction: boolean;
  52. views: number;
  53. likes: number;
  54. comments: number;
  55. images: number;
  56. updatedAt: string|null;
  57. createdAt: string;
  58. }
  59. export interface StockBoardPostsResponse {
  60. total: number;
  61. stats: StockBoardStatsHeader;
  62. list: StockBoardPostRow[];
  63. }
  64. // ── GET /api/stock-boards/trending ──
  65. export interface TrendingStockRow {
  66. rank: number;
  67. stockCode: string;
  68. stockName: string|null;
  69. closePrice: number|null;
  70. changeRate: number|null;
  71. posts: number;
  72. score: number;
  73. }
  74. export interface TrendingStocksResponse {
  75. list: TrendingStockRow[];
  76. }
  77. // ── GET /api/posts/{id}/prediction ──
  78. export interface PostPredictionResponse {
  79. postID: number;
  80. memberID: number;
  81. stockCode: string;
  82. stockName: string|null;
  83. direction: PredictionDirectionValue;
  84. directionLabel: string;
  85. basePrice: number;
  86. targetPrice: number|null;
  87. horizonDays: number;
  88. dueDate: string;
  89. status: PredictionStatusValue;
  90. statusLabel: string;
  91. settledPrice: number|null;
  92. settledAt: string|null;
  93. createdAt: string;
  94. }
  95. // ── GET /api/members/{sid}/track-record ──
  96. export interface TrackRecordResponse {
  97. sid: string;
  98. hasRecord: boolean;
  99. tier: string;
  100. tierCode: TrackRecordTierValue;
  101. hitRate: number;
  102. predictions: number;
  103. hits: number;
  104. misses: number;
  105. voids: number;
  106. currentStreak: number;
  107. bestStreak: number;
  108. }
  109. // ── GET /api/track-records/leaderboard ──
  110. export interface LeaderboardRow {
  111. rank: number;
  112. sid: string;
  113. name: string;
  114. tier: string;
  115. tierCode: TrackRecordTierValue;
  116. hitRate: number;
  117. predictions: number;
  118. hits: number;
  119. misses: number;
  120. bestStreak: number;
  121. }
  122. export interface LeaderboardResponse {
  123. total: number;
  124. period: string;
  125. list: LeaderboardRow[];
  126. }
  127. // ── POST /api/boards/stock/posts (body) ──
  128. export interface CreateStockPostPrediction {
  129. direction: PredictionDirectionValue;
  130. horizonDays: PredictionHorizonValue;
  131. targetPrice?: number|null;
  132. }
  133. export interface CreateStockPostRequest {
  134. stockCode: string;
  135. subject: string;
  136. content: string;
  137. prediction?: CreateStockPostPrediction|null;
  138. }
  139. export interface CreateStockPostResponse {
  140. id: number;
  141. }
  142. // ── GET /api/members/equipped-items?ids= (작성자 지위 배지) ──
  143. export interface EquippedItem {
  144. slot: number;
  145. kind: number;
  146. productName: string;
  147. effectPayload: string|null;
  148. thumbnail: string|null;
  149. }
  150. export interface MemberEquip {
  151. memberID: number;
  152. items: EquippedItem[];
  153. }
  154. export interface EquippedItemsResponse {
  155. members: MemberEquip[];
  156. }
  157. // ── 라벨·색 맵 (한 곳 집중) ──
  158. // 예측 방향 — 라벨/기호/방향키(색 클래스)
  159. export const DIRECTION_META: Record<PredictionDirectionValue, { label: string; symbol: string; dir: 'up'|'down' }> = {
  160. [PredictionDirection.Up]: { label: '상승', symbol: '▲', dir: 'up' },
  161. [PredictionDirection.Down]: { label: '하락', symbol: '▼', dir: 'down' }
  162. };
  163. // 예측 상태 — 라벨 + 상태 색 클래스 modifier (prediction-badge--{tone})
  164. export const STATUS_META: Record<PredictionStatusValue, { label: string; tone: 'pending'|'hit'|'miss'|'void' }> = {
  165. [PredictionStatus.Pending]: { label: '진행중', tone: 'pending' },
  166. [PredictionStatus.Hit]: { label: '적중', tone: 'hit' },
  167. [PredictionStatus.Miss]: { label: '실패', tone: 'miss' },
  168. [PredictionStatus.Void]: { label: '무효', tone: 'void' }
  169. };
  170. // 트랙레코드 등급 — 라벨 + 색 클래스 modifier (tier-badge--{tone})
  171. export const TIER_META: Record<TrackRecordTierValue, { label: string; tone: 'none'|'bronze'|'silver'|'gold'|'goldant' }> = {
  172. [TrackRecordTier.None]: { label: '무등급', tone: 'none' },
  173. [TrackRecordTier.Bronze]: { label: '브론즈', tone: 'bronze' },
  174. [TrackRecordTier.Silver]: { label: '실버', tone: 'silver' },
  175. [TrackRecordTier.Gold]: { label: '골드', tone: 'gold' },
  176. [TrackRecordTier.GoldAnt]: { label: '황금개미', tone: 'goldant' }
  177. };
  178. // 예측 기간 라벨
  179. export const HORIZON_LABEL: Record<PredictionHorizonValue, string> = {
  180. [PredictionHorizon.Short]: '5영업일',
  181. [PredictionHorizon.Long]: '20영업일'
  182. };