문항관리 리디자인 - 유형/대상/언어 그룹 + 응답 통계
ID: fabf13f7-9bc6-48d7-abc7-8c47ed06d421
## 목표
기존 문항관리 페이지를 리디자인합니다. 문항 번호별 목록이 아닌, 검사 유형/대상/언어 그룹으로 목록을 보여주고, 선택하면 해당 문항들과 응답 통계가 표시됩니다.
## 변경 파일
### 1. 컨트롤러 수정: `app/controllers/admin/survey_questions_controller.rb`
#### index 액션 리디자인
- 기존 index: 문항 번호별 평면 목록 → 변경: 유형/대상/언어 그룹 목록
- 그룹 목록 데이터:
```ruby
def index
@groups = DiagnosisType.includes(:category, :target).where(active: true).order(:display_order)
@locales = %w[ko en zh vi]
end
```
- 각 그룹 = DiagnosisType × locale 조합 (예: "강점검사 - 성인 - 한국어")
#### show 액션 (그룹 선택 시)
- 라우트 변경 또는 새 액션 추가: `questions` 또는 기존 show 재활용
- 새 액션 `group_detail` 추가:
```ruby
def group_detail
@diagnosis_type = DiagnosisType.find(params[:diagnosis_type_id])
@locale = params[:locale] || "ko"
@target = @diagnosis_type.target
@questions = SurveyQuestion.includes(:translations, :category)
.where(category_id: @diagnosis_type.category_id)
.active
.order(:part, :display_order)
# 응답 통계 계산
# completed 세션의 response만 카운트
session_ids = DiagnosisSession.where(diagnosis_type: @diagnosis_type, status: "completed").pluck(:id)
@response_stats = calculate_response_stats(@questions, session_ids)
end
```
#### 응답 통계 계산 private 메서드
```ruby
def calculate_response_stats(questions, session_ids)
return {} if session_ids.empty?
stats = {}
responses = DiagnosisResponse.where(diagnosis_session_id: session_ids, survey_question_id: questions.pluck(:id))
.group(:survey_question_id, :response_value)
.count
questions.each do |q|
total = 0
distribution = {}
if q.part == 1
# Part1: 1점~5점 분포
(1..5).each do |val|
count = responses[[q.id, val.to_s]] || responses[[q.id, val]] || 0
distribution[val] = count
total += count
end
else
# Part2: A, B, C 선택지 분포 (response_value가 "A", "B", "C" 또는 1,2,3)
# DiagnosisResponse의 response_value 확인 필요
# selected_option_id 또는 response_value로 구분
%w[1 2 3].each do |val|
count = responses[[q.id, val]] || responses[[q.id, val.to_i]] || 0
distribution[val] = count
total += count
end
end
stats[q.id] = { distribution: distribution, total: total }
end
stats
end
```
### 2. 뷰 생성
#### `app/views/admin/survey_questions/index.html.erb` (리디자인)
- 그룹 목록을 카드/테이블로 표시:
- 진단 유형명 (category.name + target.name)
- 언어 선택 탭 또는 버튼 (ko, en, zh, vi)
- 문항 수 표시
- 클릭 시 → group_detail로 이동
#### `app/views/admin/survey_questions/group_detail.html.erb` (새 뷰)
- 상단: 뒤로 가기 + 그룹 정보 (유형, 대상, 언어)
- Part 1 섹션 (1~12번):
```
Q1. [문항 내용 - 해당 target/locale의 번역]
1점: 0 (0%) | 2점: 0 (0%) | 3점: 0 (0%) | 4점: 0 (0%) | 5점: 0 (0%)
```
- 각 점수의 count와 percentage 표시
- percentage = (count / total * 100).round(1)
- 바 차트(간단한 inline width %)로 시각화
- Part 2 섹션 (1~36번):
```
Q1. [문항 내용]
A선택지: [텍스트] 0 (0%) | B선택지: [텍스트] 0 (0%) | C선택지: [텍스트] 0 (0%)
```
- Part2 문항은 `SurveyQuestionTranslation`에서 해당 target, locale의 텍스트 가져오기
- 선택지 텍스트는 translation에 포함되어 있을 수 있음 - 확인 필요
### 3. 라우트 추가 (`config/routes.rb`)
```ruby
resources :survey_questions, except: :destroy do
collection { get :group_detail }
member do
patch :soft_delete
patch :restore
end
end
```
## 모델 관계 참고
- `SurveyQuestion`: category_id, part(1 or 2), dna_type, display_order
- `SurveyQuestionTranslation`: survey_question_id, target_id, locale, question_text
- `DiagnosisResponse`: diagnosis_session_id, survey_question_id, response_value, selected_option_id
- `DiagnosisType`: category_id, target_id, slug
- `DiagnosisCategory`: name (예: "강점검사")
- `DiagnosisTarget`: name, slug (예: "성인", "adult")
## 스타일 참고
- 기존 admin Tailwind 패턴 따르기
- 통계 바: `
- 테이블 스타일은 기존 admin 패턴
## 주의사항
- DiagnosisResponse의 response_value 형식을 실제 DB 데이터로 확인할 것 (docker compose exec web rails runner "DiagnosisResponse.limit(5).pluck(:response_value, :selected_option_id)")
- Part2 선택지가 어떻게 저장되는지 확인 필요
- 대량 데이터 쿼리 시 성능 고려 (group/count로 집계)
## 완료 기준
- /admin/survey_questions 에서 유형/대상별 그룹 목록 표시
- 그룹 선택 시 문항 + 응답 통계 표시
- Part1: 1~5점 분포 (count + percentage)
- Part2: A/B/C 선택지 분포 (count + percentage)
첨부 이미지
이미지 추가 (Ctrl+V로 붙여넣기 또는 클릭)
JPEG, PNG, GIF, WebP / 최대 10MB
활동 로그
-
팀팀리드 상태 변경: 리뷰 → 완료
2026년 02월 27일 15:23:55
-
팀팀리드 상태 변경: 할 일 → 리뷰
2026년 02월 27일 15:23:16