|
|
@@ -0,0 +1,253 @@
|
|
|
+# encoding:utf-8
|
|
|
+class TcmExam < ActiveRecord::Base
|
|
|
+ has_paper_trail
|
|
|
+ self.table_name = "tcm_exams"
|
|
|
+ belongs_to :wx_user
|
|
|
+ belongs_to :scale_user, :foreign_key => :scale_user_id
|
|
|
+
|
|
|
+ STATUS_ENUM = [["待处理", "pending"], ["处理中", "processing"], ["已完成", "completed"], ["失败", "failed"]]
|
|
|
+
|
|
|
+ def wx_user_contact
|
|
|
+ return "-" if wx_user.blank?
|
|
|
+ user = wx_user.user
|
|
|
+ return "-" if user.blank?
|
|
|
+ contact = user.tel
|
|
|
+ contact = user.email if contact.blank?
|
|
|
+ contact.blank? ? "-" : contact
|
|
|
+ end
|
|
|
+
|
|
|
+ def scale_user_name
|
|
|
+ return "-" if scale_user.blank?
|
|
|
+ scale_user.nick_name || "-"
|
|
|
+ end
|
|
|
+
|
|
|
+ # 解析 AI 报告内容
|
|
|
+ def parsed_ai_summary
|
|
|
+ return {} if ai_summary.blank?
|
|
|
+ begin
|
|
|
+ JSON.parse(ai_summary)
|
|
|
+ rescue
|
|
|
+ {}
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ # 解析观察图片
|
|
|
+ def parsed_observation_images
|
|
|
+ return {} if observation_images.blank?
|
|
|
+ begin
|
|
|
+ JSON.parse(observation_images)
|
|
|
+ rescue
|
|
|
+ {}
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ # 解析问诊答案
|
|
|
+ def parsed_question_answers
|
|
|
+ return {} if question_answers.blank?
|
|
|
+ begin
|
|
|
+ JSON.parse(question_answers)
|
|
|
+ rescue
|
|
|
+ {}
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ # 解析最新体脂秤结果
|
|
|
+ def parsed_latest_scale_result
|
|
|
+ return {} if latest_scale_result.blank?
|
|
|
+ begin
|
|
|
+ JSON.parse(latest_scale_result)
|
|
|
+ rescue
|
|
|
+ {}
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ # 状态标签
|
|
|
+ def status_label
|
|
|
+ case status
|
|
|
+ when "pending" then "待处理"
|
|
|
+ when "processing" then "处理中"
|
|
|
+ when "completed" then "已完成"
|
|
|
+ when "failed" then "失败"
|
|
|
+ else status || "-"
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ rails_admin do
|
|
|
+ navigation_label '中医诊疗记录'
|
|
|
+ parent ScaleDevice
|
|
|
+ weight 3
|
|
|
+
|
|
|
+ list do
|
|
|
+ filters [:wx_user, :scale_user, :status, :created_at]
|
|
|
+ field :id do
|
|
|
+ label 'ID'
|
|
|
+ end
|
|
|
+ field :wx_user_id do
|
|
|
+ label '微信用户ID'
|
|
|
+ end
|
|
|
+ field :wx_user do
|
|
|
+ label '微信用户'
|
|
|
+ pretty_value do
|
|
|
+ bindings[:object].wx_user_contact
|
|
|
+ end
|
|
|
+ end
|
|
|
+ field :scale_user_id do
|
|
|
+ label '称用户ID'
|
|
|
+ end
|
|
|
+ field :scale_user do
|
|
|
+ label '称用户名'
|
|
|
+ pretty_value do
|
|
|
+ bindings[:object].scale_user_name
|
|
|
+ end
|
|
|
+ end
|
|
|
+ field :status do
|
|
|
+ label '状态'
|
|
|
+ pretty_value do
|
|
|
+ bindings[:object].status_label
|
|
|
+ end
|
|
|
+ end
|
|
|
+ field :ai_summary do
|
|
|
+ label '报告详情'
|
|
|
+ formatted_value do
|
|
|
+ exam = bindings[:object]
|
|
|
+ bindings[:view].link_to('查看报告', bindings[:view].rails_admin.show_path(model_name: 'tcm_exam', id: exam.id), class: 'btn btn-info btn-sm')
|
|
|
+ end
|
|
|
+ end
|
|
|
+ field :created_at do
|
|
|
+ label '创建时间'
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ show do
|
|
|
+ field :id
|
|
|
+ field :wx_user_id do
|
|
|
+ label '微信用户ID'
|
|
|
+ end
|
|
|
+ field :wx_user do
|
|
|
+ label '微信用户'
|
|
|
+ pretty_value do
|
|
|
+ bindings[:object].wx_user_contact
|
|
|
+ end
|
|
|
+ end
|
|
|
+ field :scale_user_id do
|
|
|
+ label '称用户ID'
|
|
|
+ end
|
|
|
+ field :scale_user do
|
|
|
+ label '称用户名'
|
|
|
+ pretty_value do
|
|
|
+ bindings[:object].scale_user_name
|
|
|
+ end
|
|
|
+ end
|
|
|
+ field :status do
|
|
|
+ label '状态'
|
|
|
+ pretty_value do
|
|
|
+ bindings[:object].status_label
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ # 望诊图片
|
|
|
+ field :observation_images do
|
|
|
+ label '望诊图片'
|
|
|
+ pretty_value do
|
|
|
+ exam = bindings[:object]
|
|
|
+ images = exam.parsed_observation_images
|
|
|
+ return "-" if images.empty?
|
|
|
+
|
|
|
+ image_labels = {
|
|
|
+ 'tongue' => '舌面照',
|
|
|
+ 'tongueBottom' => '舌底照',
|
|
|
+ 'face' => '面部照',
|
|
|
+ 'body' => '全身照'
|
|
|
+ }
|
|
|
+
|
|
|
+ html = '<div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin: 10px 0;">'
|
|
|
+ ['tongue', 'tongueBottom', 'face', 'body'].each do |key|
|
|
|
+ urls = images[key]
|
|
|
+ next if urls.blank? || urls.empty?
|
|
|
+ url = urls.first
|
|
|
+ next if url.blank?
|
|
|
+ html += %Q{
|
|
|
+ <div style="text-align: center;">
|
|
|
+ <img src="#{url}" style="width: 100%; max-width: 200px; height: 150px; object-fit: cover; border-radius: 8px; border: 1px solid #e5e7eb; cursor: pointer;" onclick="window.open('#{url}')" />
|
|
|
+ <div style="margin-top: 6px; font-size: 12px; color: #5d4037; font-weight: 600;">#{image_labels[key] || key}</div>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ end
|
|
|
+ html += '</div>'
|
|
|
+ html.html_safe
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ # AI 报告内容 - 一般情况
|
|
|
+ field :ai_summary do
|
|
|
+ label '壹 · 一般情况'
|
|
|
+ pretty_value do
|
|
|
+ exam = bindings[:object]
|
|
|
+ summary = exam.parsed_ai_summary
|
|
|
+ content = summary['general'] || summary['summary'] || '-'
|
|
|
+ %Q{<div style="background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 10px; padding: 14px; margin: 10px 0; line-height: 1.7;">#{content.to_s.gsub("\n", "<br>")}</div>}.html_safe
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ # 问诊
|
|
|
+ field :question_answers do
|
|
|
+ label '贰 · 问诊 (十问歌)'
|
|
|
+ pretty_value do
|
|
|
+ exam = bindings[:object]
|
|
|
+ summary = exam.parsed_ai_summary
|
|
|
+ content = summary['inquiry'] || '-'
|
|
|
+ %Q{<div style="background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 10px; padding: 14px; margin: 10px 0; line-height: 1.7;">#{content.to_s.gsub("\n", "<br>")}</div>}.html_safe
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ # 望诊与闻诊
|
|
|
+ field :extra_note do
|
|
|
+ label '叁 · 望诊与闻诊'
|
|
|
+ pretty_value do
|
|
|
+ exam = bindings[:object]
|
|
|
+ summary = exam.parsed_ai_summary
|
|
|
+ content = summary['observation'] || '-'
|
|
|
+ %Q{<div style="background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 10px; padding: 14px; margin: 10px 0; line-height: 1.7;">#{content.to_s.gsub("\n", "<br>")}</div>}.html_safe
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ # 总体评估与体质辨识
|
|
|
+ field :latest_scale_result do
|
|
|
+ label '肆 · 总体评估与体质辨识'
|
|
|
+ pretty_value do
|
|
|
+ exam = bindings[:object]
|
|
|
+ summary = exam.parsed_ai_summary
|
|
|
+ content = summary['constitution'] || '-'
|
|
|
+ %Q{<div style="background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 10px; padding: 14px; margin: 10px 0; line-height: 1.7;">#{content.to_s.gsub("\n", "<br>")}</div>}.html_safe
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ # 调养与建议
|
|
|
+ field :report_html do
|
|
|
+ label '伍 · 调养与建议'
|
|
|
+ pretty_value do
|
|
|
+ exam = bindings[:object]
|
|
|
+ summary = exam.parsed_ai_summary
|
|
|
+ content = summary['advice'] || '-'
|
|
|
+ %Q{<div style="background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 10px; padding: 14px; margin: 10px 0; line-height: 1.7;">#{content.to_s.gsub("\n", "<br>")}</div>}.html_safe
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ field :created_at do
|
|
|
+ label '创建时间'
|
|
|
+ end
|
|
|
+ field :updated_at do
|
|
|
+ label '更新时间'
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ # 禁用编辑和删除,只允许查看
|
|
|
+ edit do
|
|
|
+ field :status, :enum do
|
|
|
+ enum do
|
|
|
+ STATUS_ENUM
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end
|
|
|
+end
|