<template>
  <!--
    AI写病历：单根 u-popup（Vue2 不能双根）
    生成确认用抽屉内面板切换，避免第二个 popup 无反应
    模板禁止 ?? ?. ；:class 禁止方法调用
  -->
  <u-popup
    v-model="visible"
    mode="bottom"
    border-radius="24"
    :safe-area-inset-bottom="true"
    :mask-close-able="true"
    height="82%"
    z-index="10090"
    @close="onClose"
  >
    <view class="ai-mr-drawer">
      <view class="ai-mr-title-row">
        <text class="ai-mr-title">AI写病历</text>
        <text class="ai-mr-sub">{{ patientName || '—' }} · {{ sexLabel }} · {{ patientAge || 0 }}岁</text>
      </view>
      <!-- 醒目提示：记录与模态框顶部 -->
      <view v-if="disclaimerText && !consentVisible" class="ai-disclaimer">
        <text class="ai-disclaimer-title">重要提示</text>
        <text class="ai-disclaimer-body">{{ disclaimerText }}</text>
      </view>
      <!-- 首次知情同意（抽屉内覆盖层，按 VIP 功能签署一次） -->
      <view v-if="consentVisible" class="ai-consent-panel">
        <text class="fs-30 font-bold">AI 使用知情同意</text>
        <scroll-view scroll-y class="ai-consent-scroll">
          <text class="ai-consent-body">{{ consentText }}</text>
        </scroll-view>
      </view>
      <view v-else-if="!genModalVisible" class="ai-mr-body flex-row">
        <scroll-view scroll-y class="ai-mr-hist">
          <view class="ai-hist-hd">
            <text class="fs-24 font-bold">历史</text>
          </view>
          <view v-if="histLoading" class="p-24 color-sub fs-24">加载中…</view>
          <view v-else-if="historyEmpty" class="p-24 color-sub fs-22">暂无记录，可生成病历</view>
          <view
            v-for="row in historyView"
            :key="row.id"
            class="ai-hist-item"
            :class="{ 'ai-hist-item--active': activeId == row.id }"
            :data-id="row.id"
            @click="onSelectHistoryTap"
          >
            <text class="fs-26 font-bold ai-hist-name">{{ row.nameText }}</text>
            <text class="fs-22 color-sub">{{ row.timeText }}</text>
          </view>
        </scroll-view>
        <scroll-view scroll-y class="ai-mr-preview">
          <!-- AI 专属 Loading：仅生成中；历史详情用普通文案 -->
          <ai-generation-loading
            v-if="generating"
            type="medical_record"
            text="AI正在生成病历"
          />
          <view v-else-if="detailLoading" class="p-32 color-sub fs-24">加载历史病历…</view>
          <block v-else>
            <view v-if="!previewChief && !previewRows.length && !lastDurationMs" class="p-32 color-sub fs-24">
              请选择历史或生成病历
            </view>
            <view v-else-if="!previewChief && !previewRows.length && lastDurationMs" class="p-32 color-sub fs-24">
              本次生成未产出病历内容（耗时 {{ durationText }}）
            </view>
            <block v-else>
              <view v-if="previewChief" class="ai-chief-box">
                <text class="fs-20 color-sub">主诉</text>
                <text class="fs-24 m-t-4">{{ previewChief }}</text>
              </view>
              <view v-if="lastDurationMs" class="ai-chief-box">
                <text class="fs-20 color-sub">生成耗时</text>
                <text class="fs-24 m-t-4">{{ durationText }}</text>
              </view>
              <view v-if="previewRows.length" class="ai-preview-grid">
                <view
                  v-for="row in previewRows"
                  :key="row.key"
                  class="ai-preview-card"
                  :class="{
                    'ai-preview-card--full':
                      row.key == 'present_illness' ||
                      row.key == 'tcm_case' ||
                      row.key == 'treatment_advice' ||
                      row.key == 'auxiliary_exam',
                  }"
                >
                  <text class="fs-20 color-sub">{{ row.label }}</text>
                  <text class="fs-24 m-t-4">{{ row.value }}</text>
                </view>
              </view>
            </block>
          </block>
        </scroll-view>
      </view>
      <view v-else-if="genModalVisible" class="ai-gen-panel">
        <view class="ai-gen-hd flex-row flex-jus-sp flex-ali-center">
          <text class="fs-30 font-bold">生成病历</text>
          <text class="ai-mr-sub" @click="closeGenModal">返回</text>
        </view>
        <text class="ai-gen-tip">主诉必填；下方选填有内容会作为 AI 参考 · 点击文字可编辑</text>
        <scroll-view scroll-y class="ai-gen-scroll">
          <view class="ai-gen-patient">
            <text class="fs-20 color-sub">患者</text>
            <text class="fs-24 m-t-4">{{ patientName || '—' }} · {{ sexLabel }} · {{ patientAge || 0 }}岁</text>
          </view>
          <view class="ai-gen-grid">
            <view class="ai-gen-row ai-gen-row--full">
              <text class="ai-gen-label">主诉 *</text>
              <textarea
                v-if="editingKey == 'chief_complaint'"
                class="ai-gen-textarea"
                :value="aiChief"
                maxlength="500"
                auto-height
                placeholder="请确认或补充主诉"
                @input="onAiChiefInput"
                @blur="onGenFieldBlur"
              />
              <text
                v-else
                class="ai-gen-val"
                data-key="chief_complaint"
                @click="onStartEditTap"
              >{{ aiChief || '（空，点击填写）' }}</text>
            </view>
            <view
              v-for="(f, fi) in genOptionalFields"
              :key="fi"
              class="ai-gen-row"
            >
              <text class="ai-gen-label">{{ f.label }}</text>
              <textarea
                v-if="editingKey == f.key"
                class="ai-gen-textarea"
                :value="genContext[f.key] || ''"
                maxlength="1000"
                auto-height
                :data-key="f.key"
                :placeholder="'选填' + f.label"
                @input="onGenContextInput"
                @blur="onGenFieldBlur"
              />
              <text
                v-else
                class="ai-gen-val"
                :data-key="f.key"
                @click="onStartEditTap"
              >{{ genContext[f.key] || '（空，点击填写）' }}</text>
            </view>
          </view>
          <view class="ai-gen-scroll-pad" />
        </scroll-view>
      </view>
      <view class="ai-mr-footer safe-area-inset-bottom">
        <view v-if="consentVisible" class="ai-actions">
          <view class="ai-btn ai-btn--ghost" @click="onConsentCancel">取消</view>
          <view class="ai-btn ai-btn--primary" @click="onConsentAgree">
            {{ consentSubmitting ? '提交中…' : '我已知悉并同意' }}
          </view>
        </view>
        <view v-else-if="!genModalVisible" class="ai-actions">
          <view class="ai-btn ai-btn--ghost" @click="onClose">关闭</view>
          <view class="ai-btn ai-btn--ghost" @click="openGenModal">生成病历</view>
          <view class="ai-btn ai-btn--primary" @click="onConfirmImport">确认导入</view>
        </view>
        <view v-else class="ai-actions">
          <view class="ai-btn ai-btn--ghost" @click="closeGenModal">返回</view>
          <view class="ai-btn ai-btn--primary" @click="onGenerate">
            {{ generating ? '生成中…' : '开始生成' }}
          </view>
        </view>
      </view>
    </view>
  </u-popup>
</template>

<script>
import {
  aiAgreeConsentApi,
  aiFeatureGateApi,
  aiGenerateMedicalRecordApi,
  aiGenerationDetailApi,
  aiListGenerationsApi,
} from '@/api/reception.js'

const PREVIEW_DEFS = [
  { key: 'present_illness', label: '现病史' },
  { key: 'tongue', label: '舌象' },
  { key: 'pulse', label: '脉象' },
  { key: 'tcm_case', label: '中医病案' },
  { key: 'tcm_syndrome', label: '中医证候' },
  { key: 'tcm_disease', label: '中医疾病' },
  { key: 'tcm_method', label: '中医治法' },
  { key: 'diagnosis', label: '临床诊断' },
  { key: 'treatment_advice', label: '治疗意见' },
  { key: 'doctor_order', label: '医嘱' },
  { key: 'family_history', label: '家族史' },
  { key: 'epidemic_history', label: '流行病学史' },
  { key: 'past_history', label: '既往史' },
  { key: 'menstrual_history', label: '月经史' },
  { key: 'marital_history', label: '婚育史' },
  { key: 'personal_history', label: '个人史' },
  { key: 'allergy_history', label: '过敏史' },
  { key: 'physical_exam', label: '体征检查' },
  { key: 'auxiliary_exam', label: '辅助检查' },
]

/** 生成前可选填（非必填） */
const GEN_OPTIONAL_DEFS = [
  { key: 'present_illness', label: '现病史' },
  { key: 'past_history', label: '既往史' },
  { key: 'allergy_history', label: '过敏史' },
  { key: 'menstrual_history', label: '月经史' },
  { key: 'family_history', label: '家族史' },
  { key: 'marital_history', label: '婚育史' },
  { key: 'personal_history', label: '个人史' },
  { key: 'physical_exam', label: '体征检查' },
  { key: 'auxiliary_exam', label: '辅助检查' },
  { key: 'tongue', label: '舌象' },
  { key: 'pulse', label: '脉象' },
]

function emptyGenContext() {
  const o = {}
  for (let i = 0; i < GEN_OPTIONAL_DEFS.length; i++) {
    o[GEN_OPTIONAL_DEFS[i].key] = ''
  }
  return o
}

export default {
  name: 'AiMedicalRecordDrawer',
  props: {
    value: { type: Boolean, default: false },
    registerId: { type: [Number, String], default: 0 },
    storeId: { type: [Number, String], default: 0 },
    patientName: { type: String, default: '' },
    patientSex: { type: [Number, String], default: 0 },
    patientAge: { type: [Number, String], default: 0 },
    chiefComplaint: { type: String, default: '' },
    medicalRecord: { type: Object, default: () => ({}) },
  },
  data() {
    return {
      visible: false,
      genModalVisible: false,
      aiChief: '',
      genOptionalFields: GEN_OPTIONAL_DEFS,
      genContext: emptyGenContext(),
      /** 生成面板点击编辑的字段 key */
      editingKey: '',
      histLoading: false,
      generating: false,
      detailLoading: false,
      historyList: [],
      historyView: [],
      historyEmpty: true,
      activeId: 0,
      previewFields: {},
      previewChief: '',
      previewRows: [],
      lastDurationMs: 0,
      disclaimerText: '',
      consentText: '',
      consentVisible: false,
      consentSubmitting: false,
    }
  },
  computed: {
    sexLabel() {
      const s = Number(this.patientSex)
      if (s === 1) return '男'
      if (s === 2) return '女'
      return '未知'
    },
    durationText() {
      return this.formatDurationMs(this.lastDurationMs)
    },
  },
  watch: {
    value: {
      immediate: true,
      handler(v) {
        this.visible = !!v
        if (v) this.bootstrapOpen()
      },
    },
    visible(v) {
      this.$emit('input', v)
      this.$emit('overlay-change', !!v)
    },
  },
  methods: {
    bootstrapOpen() {
      this.aiChief = String(this.chiefComplaint || '').trim()
      const next = emptyGenContext()
      const snap = this.medicalRecord || {}
      for (let i = 0; i < GEN_OPTIONAL_DEFS.length; i++) {
        const k = GEN_OPTIONAL_DEFS[i].key
        next[k] = String(snap[k] || '').trim()
      }
      this.genContext = next
      this.genModalVisible = false
      this.editingKey = ''
      this.consentVisible = false
      this.consentSubmitting = false
      this.disclaimerText = ''
      this.consentText = ''
      this.resetPreview()
      this.ensureConsentThenBootstrap()
    },
    /**
     * 首次使用 AI 写病历：未签署则先展示知情同意，同意后再加载历史
     */
    async ensureConsentThenBootstrap() {
      try {
        const res = await aiFeatureGateApi({ feature_code: 'ai_medical_record' })
        const gate = this.unwrapBiz(res) || {}
        this.disclaimerText = String(gate.disclaimer_text || '')
        this.consentText = String(gate.consent_text || '')
        if (gate.consented) {
          this.afterConsentReady()
          return
        }
        this.consentVisible = true
      } catch (e) {
        const msg = (e && e.message) || (e && e.msg) || '无法校验 AI 使用规范'
        uni.showToast({ title: String(msg), icon: 'none' })
        this.onClose()
      }
    },
    afterConsentReady() {
      this.consentVisible = false
      this.loadHistory().then(() => {
        if (this.historyList.length) {
          this.selectHistoryById(Number(this.historyList[0].id))
        } else {
          this.openGenModal()
        }
      })
    },
    onConsentCancel() {
      this.onClose()
    },
    async onConsentAgree() {
      if (this.consentSubmitting) return
      this.consentSubmitting = true
      try {
        await aiAgreeConsentApi({
          feature_code: 'ai_medical_record',
          store_id: Number(this.storeId || 0),
        })
        uni.showToast({ title: '已记录知情同意', icon: 'none' })
        this.afterConsentReady()
      } catch (e) {
        const msg = (e && e.message) || (e && e.msg) || '签署失败'
        uni.showToast({ title: String(msg), icon: 'none' })
      } finally {
        this.consentSubmitting = false
      }
    },
    resetPreview() {
      this.activeId = 0
      this.previewFields = {}
      this.previewChief = ''
      this.previewRows = []
      this.lastDurationMs = 0
    },
    onClose() {
      this.visible = false
      this.genModalVisible = false
    },
    /**
     * Laravel jok 业务在 result；兼容 Yii data / 已解包对象
     */
    unwrapBiz(res) {
      if (res == null) return null
      if (res.result != null) return res.result
      if (res.data != null) return res.data
      return res
    },
    formatTime(ts) {
      if (typeof ts === 'string' && ts && Number.isNaN(Number(ts))) {
        return ts.length > 16 ? ts.slice(5, 16) : ts
      }
      const n = Number(ts || 0)
      if (!n) return '—'
      const d = new Date(n * 1000)
      const pad = (x) => (x < 10 ? '0' + x : '' + x)
      return pad(d.getMonth() + 1) + '-' + pad(d.getDate()) + ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes())
    },
    /** 毫秒转可读耗时（850ms / 1.2s） */
    formatDurationMs(ms) {
      const n = Number(ms || 0)
      if (!n) return ''
      if (n < 1000) return Math.round(n) + 'ms'
      const sec = n / 1000
      return sec >= 10 ? Math.round(sec) + 's' : sec.toFixed(1) + 's'
    },
    rebuildHistoryView() {
      const list = Array.isArray(this.historyList) ? this.historyList : []
      this.historyEmpty = list.length === 0
      this.historyView = list.map((row) => ({
        id: Number(row.id || 0),
        nameText: String(row.name || '').trim() || ('病历 #' + row.id),
        timeText: this.formatTime(row.created_at) + (row.duration_ms ? (' · ' + this.formatDurationMs(row.duration_ms)) : ''),
      }))
    },
    rebuildPreviewRows() {
      const fields = this.previewFields || {}
      const rows = []
      for (let i = 0; i < PREVIEW_DEFS.length; i++) {
        const d = PREVIEW_DEFS[i]
        const val = String(fields[d.key] || '').trim()
        if (val) rows.push({ key: d.key, label: d.label, value: val })
      }
      this.previewRows = rows
    },
    async loadHistory() {
      this.histLoading = true
      try {
        const res = await aiListGenerationsApi({
          register_id: Number(this.registerId),
          scene: 'medical_record',
          limit: 30,
        })
        const list = this.unwrapBiz(res)
        this.historyList = Array.isArray(list) ? list : []
        this.rebuildHistoryView()
      } catch (e) {
        this.historyList = []
        this.rebuildHistoryView()
        const msg = (e && e.message) || (e && e.msg) || ''
        if (msg) uni.showToast({ title: String(msg), icon: 'none' })
      } finally {
        this.histLoading = false
      }
    },
    openGenModal() {
      // 抽屉内切到生成面板，避免 Vue2 双根第二个 popup 无效
      this.$nextTick(() => {
        this.genModalVisible = true
      })
    },
    closeGenModal() {
      this.genModalVisible = false
      this.editingKey = ''
    },
    onAiChiefInput(e) {
      this.aiChief = (e && e.detail && e.detail.value) || ''
    },
    /** 点击字段进入编辑（对齐 PC / 出方生成面板交互） */
    onStartEditTap(e) {
      const key = e && e.currentTarget && e.currentTarget.dataset
        ? e.currentTarget.dataset.key
        : ''
      if (!key) return
      this.editingKey = key
    },
    onGenFieldBlur() {
      this.editingKey = ''
    },
    onGenContextInput(e) {
      const key = e && e.currentTarget && e.currentTarget.dataset
        ? e.currentTarget.dataset.key
        : ''
      const val = (e && e.detail && e.detail.value) || ''
      if (!key) return
      const next = Object.assign({}, this.genContext || {})
      next[key] = val
      this.genContext = next
    },
    async onGenerate() {
      if (this.generating) return
      const chief = String(this.aiChief || '').trim()
      if (!chief) {
        uni.showToast({ title: '请填写主诉后再生成', icon: 'none' })
        return
      }
      if (!Number(this.registerId)) {
        uni.showToast({ title: '挂号无效', icon: 'none' })
        return
      }
      this.closeGenModal()
      this.generating = true
      this.previewFields = {}
      this.previewChief = chief
      this.lastDurationMs = 0
      this.rebuildPreviewRows()
      try {
        const res = await aiGenerateMedicalRecordApi({
          register_id: Number(this.registerId),
          store_id: Number(this.storeId || 0) || undefined,
          chief_complaint: chief,
          medical_record: Object.assign({}, this.genContext || {}),
        })
        const data = this.unwrapBiz(res) || {}
        const durationText = this.formatDurationMs(data.duration_ms)
        this.lastDurationMs = Number(data.duration_ms || 0)
        // 业务软失败：HTTP 成功但 ok=false，toast 警告而非失败
        if (data.ok === false) {
          if (data.generation_id) {
            this.activeId = Number(data.generation_id)
            await this.loadHistory()
          }
          uni.showToast({ title: String(data.message || '生成未成功'), icon: 'none' })
          return
        }
        this.previewFields = data.fields || {}
        this.rebuildPreviewRows()
        await this.loadHistory()
        this.activeId = Number(data.generation_id || 0)
        uni.showToast({
          title: durationText ? ('已生成（耗时 ' + durationText + '）') : '已生成',
          icon: 'success',
        })
      } catch (e) {
        const msg = (e && e.message) || (e && e.msg) || '生成失败'
        uni.showToast({ title: String(msg), icon: 'none' })
      } finally {
        this.generating = false
      }
    },
    onSelectHistoryTap(e) {
      const raw = e && e.currentTarget && e.currentTarget.dataset
        ? e.currentTarget.dataset.id
        : 0
      const id = Number(raw || 0)
      if (!id) return
      this.selectHistoryById(id)
    },
    async selectHistoryById(id) {
      this.activeId = id
      this.detailLoading = true
      try {
        const res = await aiGenerationDetailApi({ id: id })
        const data = this.unwrapBiz(res) || {}
        this.previewFields = data.fields || {}
        const snap = data.input_snapshot || {}
        this.previewChief = String(snap.chief_complaint || this.aiChief || '').trim()
        this.lastDurationMs = 0
        for (let i = 0; i < this.historyList.length; i++) {
          if (Number(this.historyList[i].id) === id) {
            this.lastDurationMs = Number(this.historyList[i].duration_ms || 0)
            break
          }
        }
        this.rebuildPreviewRows()
      } catch (e) {
        this.previewFields = {}
        this.previewChief = ''
        this.rebuildPreviewRows()
        const msg = (e && e.message) || (e && e.msg) || '加载失败'
        uni.showToast({ title: String(msg), icon: 'none' })
      } finally {
        this.detailLoading = false
      }
    },
    onConfirmImport() {
      if (this.generating || this.detailLoading) return
      const hasFields = this.previewRows && this.previewRows.length
      const chief = String(this.previewChief || this.aiChief || '').trim()
      if (!hasFields && !chief) {
        uni.showToast({ title: '暂无可导入内容', icon: 'none' })
        return
      }
      this.$emit('import', {
        chief_complaint: chief,
        fields: Object.assign({}, this.previewFields || {}),
      })
      this.visible = false
    },
  },
}
</script>

<style scoped lang="scss">
.ai-mr-drawer {
  height: 100%;
  display: flex;
  flex-direction: column;
  background: #f7f8fa;
  position: relative;
  overflow: hidden;
}
.ai-gen-panel {
  flex: 1;
  height: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: #fff;
  overflow: hidden;
}
.ai-gen-scroll {
  flex: 1;
  height: 0;
  min-height: 0;
  padding: 0 24rpx 16rpx;
  box-sizing: border-box;
  background: #f7f8fa;
}
.ai-gen-scroll-pad {
  height: 32rpx;
}
.ai-mr-title-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 24rpx 32rpx;
  background: #fff;
}
.ai-mr-title {
  font-size: 32rpx;
  font-weight: bold;
  color: #333;
}
.ai-mr-sub {
  font-size: 24rpx;
  color: #6acdbb;
}
.ai-mr-body {
  flex: 1;
  height: 0;
  min-height: 0;
  overflow: hidden;
}
.ai-mr-hist {
  width: 220rpx;
  background: #fff;
  border-right: 1px solid #eee;
  height: 100%;
}
.ai-hist-hd {
  padding: 16rpx;
  border-bottom: 1px solid #f0f0f0;
}
.ai-hist-item {
  padding: 16rpx;
  border-bottom: 1px solid #f0f0f0;
  display: flex;
  flex-direction: column;
}
.ai-hist-item--active {
  background: #e8f8f4;
}
.ai-hist-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ai-mr-preview {
  flex: 1;
  height: 100%;
  padding: 16rpx 20rpx 24rpx;
  box-sizing: border-box;
}
.ai-chief-box {
  margin-bottom: 12rpx;
  padding: 12rpx 16rpx;
  background: #fff;
  border-radius: 10rpx;
  display: flex;
  flex-direction: column;
}
.ai-preview-grid {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  margin: 0 -6rpx;
}
.ai-preview-card {
  width: calc(50% - 12rpx);
  margin: 0 6rpx 12rpx;
  padding: 12rpx 16rpx;
  background: #fff;
  border-radius: 10rpx;
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
}
.ai-preview-card--full {
  width: calc(100% - 12rpx);
}
.m-t-4 {
  margin-top: 4rpx;
}
.ai-mr-footer {
  padding: 16rpx 24rpx 24rpx;
  background: #fff;
}
.ai-disclaimer {
  margin: 0 24rpx 12rpx;
  padding: 16rpx 20rpx;
  border-radius: 12rpx;
  border: 1px solid rgba(245, 158, 11, 0.45);
  background: rgba(245, 158, 11, 0.12);
}
.ai-disclaimer-title {
  display: block;
  font-size: 24rpx;
  font-weight: 600;
  color: #b45309;
  margin-bottom: 6rpx;
}
.ai-disclaimer-body {
  display: block;
  font-size: 22rpx;
  line-height: 1.55;
  color: #78716c;
  white-space: pre-wrap;
}
.ai-consent-panel {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: 16rpx 32rpx;
}
.ai-consent-scroll {
  flex: 1;
  height: 0;
  margin-top: 16rpx;
  padding: 16rpx;
  background: #f7f8fa;
  border-radius: 12rpx;
  box-sizing: border-box;
}
.ai-consent-body {
  font-size: 26rpx;
  line-height: 1.65;
  color: #2a2e35;
  white-space: pre-wrap;
}
.ai-actions {
  display: flex;
  flex-direction: row;
  justify-content: flex-end;
}
.ai-btn {
  padding: 16rpx 28rpx;
  border-radius: 40rpx;
  font-size: 26rpx;
  margin-left: 16rpx;
}
.ai-btn--ghost {
  background: #f5f5f5;
  color: #666;
}
.ai-btn--primary {
  background: #6acdbb;
  color: #fff;
}
.ai-btn--block {
  display: block;
  text-align: center;
  margin-left: 0;
}
.ai-gen-hd {
  padding: 16rpx 32rpx 8rpx;
}
.ai-gen-tip {
  display: block;
  padding: 0 32rpx 12rpx;
  font-size: 22rpx;
  color: #999;
}
.ai-gen-patient {
  margin: 0 6rpx 12rpx;
  padding: 12rpx 16rpx;
  background: #fff;
  border-radius: 10rpx;
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
}
.ai-gen-grid {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  margin: 0 -6rpx;
}
.ai-gen-row {
  width: calc(50% - 12rpx);
  margin: 0 6rpx 8rpx;
  padding: 12rpx 16rpx;
  background: #fff;
  border-radius: 10rpx;
  box-sizing: border-box;
}
.ai-gen-row--full {
  width: calc(100% - 12rpx);
}
.ai-gen-label {
  display: block;
  font-size: 20rpx;
  color: #999;
  margin-bottom: 4rpx;
}
.ai-gen-val {
  display: block;
  font-size: 24rpx;
  color: #2a2e35;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-all;
}
.ai-gen-textarea {
  width: 100%;
  min-height: 72rpx;
  margin-top: 4rpx;
  font-size: 24rpx;
  color: #2a2e35;
  background: #f7f8fa;
  padding: 8rpx;
  box-sizing: border-box;
  border-radius: 8rpx;
}
.color-sub {
  color: #999;
}
.p-24 {
  padding: 24rpx;
}
.p-32 {
  padding: 32rpx;
}
.m-t-8 {
  margin-top: 8rpx;
}
.fs-20 {
  font-size: 20rpx;
}
.fs-22 {
  font-size: 22rpx;
}
.fs-24 {
  font-size: 24rpx;
}
.fs-26 {
  font-size: 26rpx;
}
.fs-30 {
  font-size: 30rpx;
}
.font-bold {
  font-weight: bold;
}
.flex-row {
  display: flex;
  flex-direction: row;
}
.flex-ali-center {
  align-items: center;
}
.flex-jus-sp {
  justify-content: space-between;
}
</style>
