WXL
3 天以前 4c9fdc87987140e8b2c3f0dfc2f6608cdb6be774
src/views/business/affirm/affirmInfo.vue
@@ -9,28 +9,6 @@
      </div>
      <el-form :model="form" ref="form" label-width="120px" class="paper-form">
        <div class="form-row">
          <el-form-item
            label="协调员1"
            prop="coordinatedusernameo"
            class="col-1-3"
          >
            <el-input v-model="form.coordinatedusernameo" />
          </el-form-item>
          <el-form-item
            label="协调员2"
            prop="coordinatedusernamet"
            class="col-1-3"
          >
            <el-input v-model="form.coordinatedusernamet" />
          </el-form-item>
          <!-- <el-col :span="8">
            <el-form-item label="业务人员" prop="responsibleusername">
              <el-input v-model="form.responsibleusername" />
            </el-form-item>
          </el-col> -->
        </div>
        <!-- <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="确认时间" prop="signdate">
@@ -46,86 +24,155 @@
        <!-- 亲属信息 -->
        <el-divider content-position="left">亲属确认信息</el-divider>
        <el-alert
          title="第一条数据为主要亲属,需填写完整的姓名、关系、身份证和电话信息"
          type="info"
          show-icon
          :closable="false"
          style="margin-bottom: 15px;"
        <!-- 主要亲属表单 -->
        <div class="form-row">
          <el-form-item label="亲属姓名" class="col-1-3">
            <el-input
              v-model="familyMemberList[0].name"
              :disabled="isReadOnly"
              placeholder="请输入亲属姓名"
            />
          </el-form-item>
          <el-form-item label="关系" class="col-1-3">
            <el-select
              v-model="familyMemberList[0].relation"
              :disabled="isReadOnly"
              placeholder="请选择关系"
        >
        </el-alert>
        <div style="margin-top: 15px;">
          <el-button
            style="float: right; margin-bottom: 5px;"
            type="primary"
            size="mini"
            icon="el-icon-plus"
            @click="openFamilyDialog(false)"
          >
            添加其他家属
          </el-button>
              <el-option
                v-for="dict in dict.type.sys_FamilyRelation"
                :key="dict.value"
                :label="dict.label"
                :value="dict.value"
              />
            </el-select>
          </el-form-item>
          <el-form-item label="身份证号" class="col-1-3">
            <el-input
              v-model="familyMemberList[0].idcard"
              :disabled="isReadOnly"
              placeholder="请输入身份证号"
              maxlength="18"
            />
          </el-form-item>
        </div>
        <el-table :data="familyMemberList" size="small" border>
        <div class="form-row">
          <el-form-item label="住址" class="col-full">
            <template v-if="!isReadOnly">
              <div class="area-select-box">
                <li_area_select v-model="familyMemberList[0].address" />
              </div>
              <el-input
                v-model="familyMemberList[0].address.detail"
                placeholder="请输入详细地址"
                class="address-detail"
              />
            </template>
            <span v-else>{{ formatAddress(familyMemberList[0].address) }}</span>
          </el-form-item>
        </div>
        <div class="form-row">
          <el-form-item label="现居住地" class="col-full">
            <template v-if="!isReadOnly">
              <div class="area-select-box">
                <li_area_select
                  v-model="familyMemberList[0].currentResidence"
                />
              </div>
              <el-input
                v-model="familyMemberList[0].currentResidence.detail"
                placeholder="请输入详细地址"
                class="address-detail"
              />
            </template>
            <span v-else>{{
              formatAddress(familyMemberList[0].currentResidence)
            }}</span>
          </el-form-item>
        </div>
        <div class="form-row">
          <el-form-item label="手机" class="col-1-3">
            <el-input
              v-model="familyMemberList[0].phone"
              :disabled="isReadOnly"
              placeholder="请输入手机号"
              maxlength="11"
            />
          </el-form-item>
        </div>
        <!-- 亲属关系确认 -->
        <div class="form-row">
          <el-form-item label="亲属关系确认" class="col-full">
            <el-checkbox-group
              v-model="form.kinship"
              :disabled="isReadOnly"
              @change="syncKinshipRelatives"
            >
              <el-checkbox
                v-for="dict in kinshipCheckboxOptions"
                :key="dict.value"
                :label="String(dict.value)"
              >
                {{
                  isChildLabel(dict.label) ? dict.label + "(人)" : dict.label
                }}
              </el-checkbox>
            </el-checkbox-group>
          </el-form-item>
        </div>
        <div class="form-row" v-if="adultChildSelected">
          <el-form-item label="子女数量" class="col-1-3">
            <el-input
              v-model="form.kinshipChildrennum"
              :disabled="isReadOnly"
              placeholder="请输入子女数量"
              @input="syncKinshipRelatives"
            />
          </el-form-item>
        </div>
        <!-- 亲属表(由亲属关系勾选自动生成,姓名可编辑) -->
        <el-table
          :data="otherFamilyMemberList"
          size="small"
          border
          style="margin-top: 15px;"
        >
          <el-table-column label="序号" width="60" align="center">
            <template slot-scope="scope">
              {{ scope.$index + 1 }}
            </template>
          </el-table-column>
          <el-table-column label="姓名" prop="name" min-width="120">
          <el-table-column label="与捐赠者关系" width="160" align="center">
            <template slot-scope="scope">
              <span :class="{ 'main-family': scope.$index === 0 }">{{
                scope.row.name
              }}</span>
              {{ getKinshipLabel(scope.row.relation) }}
            </template>
          </el-table-column>
          <el-table-column label="与捐赠者关系" prop="relation" min-width="140">
          <el-table-column label="姓名" min-width="200">
            <template slot-scope="scope">
              <dict-tag
                :options="dict.type.sys_FamilyRelation"
                :value="scope.row.relation"
              <el-input
                style="width: 160px"
                v-model="scope.row.name"
                :disabled="isReadOnly"
                placeholder="请输入姓名"
                size="small"
              />
            </template>
          </el-table-column>
          <el-table-column label="身份证号" prop="idcard" min-width="180">
            <template slot-scope="scope">
              <span v-if="scope.$index === 0">{{ scope.row.idcard }}</span>
              <span v-else style="color: #909399;">-</span>
            </template>
          </el-table-column>
          <el-table-column label="联系电话" prop="phone" min-width="130">
            <template slot-scope="scope">
              <span v-if="scope.$index === 0">{{ scope.row.phone }}</span>
              <span v-else style="color: #909399;">-</span>
            </template>
          </el-table-column>
          <el-table-column label="类型" width="70" align="center">
            <template slot-scope="scope">
              <el-tag v-if="scope.$index === 0" type="warning" size="small"
                >主要</el-tag
          <el-table-column
            v-if="!isReadOnly"
            label="操作"
            width="80"
            align="center"
              >
              <el-tag v-else type="info" size="small">其他</el-tag>
            </template>
          </el-table-column>
          <el-table-column label="操作" width="150" align="center">
            <template slot-scope="scope">
              <el-button
                size="mini"
                type="text"
                @click="editFamilyMember(scope.$index)"
              >
                编辑
              </el-button>
              <el-button
                v-if="scope.$index > 0"
                size="mini"
                type="text"
                style="color:red"
                @click="deleteFamilyMember(scope.$index)"
              >
                删除
              </el-button>
              <span v-else style="color: #909399; font-size: 12px;"
                >不可删除</span
                size="small"
                style="color: #f56c6c"
                @click="handleDeleteFamilyRow(scope.$index)"
                >删除</el-button
              >
            </template>
          </el-table-column>
@@ -133,6 +180,10 @@
        <div class="form-row">
          <el-form-item label-width="100px" label="捐献决定" class="col-full">
            <div class="decision-statement">
              我(们)已知悉捐献的相关法律法规及规定,同意并代表捐献者做出逝世后自愿、无偿捐献决定:
            </div>
            <template v-if="!isReadOnly">
            <el-checkbox-group v-model="organdecision">
              <el-checkbox
                v-for="item in organselection"
@@ -145,12 +196,19 @@
              v-if="organdecision.includes('其他')"
              v-model="organdecisionOther"
              placeholder="请输入其他捐献决定的具体内容"
              style="margin-top: 10px; width: 300px;"
                class="decision-other"
            ></el-input>
            </template>
            <span v-else class="decision-selected">{{
              displayOrganDecision
            }}</span>
            <div class="decision-statement">
              同意上述所捐用于临床医疗、医学教学和科学研究。
            </div>
          </el-form-item>
        </div>
        <div class="form-row">
        <!-- <div class="form-row">
          <el-form-item
            label="家属意见备注"
            prop="relativeRemark"
@@ -161,6 +219,65 @@
              :rows="3"
              v-model="form.relativeRemark"
              placeholder="记录家属的意见和沟通情况"
              :disabled="isReadOnly"
            />
          </el-form-item>
        </div> -->
        <!-- 人体器官获取组织与负责人签字 -->
        <div class="form-row">
          <el-form-item label="人体器官获取组织" class="col-half">
            <el-input
              v-model="form.acquisitiontissuename"
              :disabled="isReadOnly"
              placeholder="请输入人体器官获取组织"
            />
          </el-form-item>
          <el-form-item
            label="负责人签字"
            prop="responsibleusername"
            class="col-half"
          >
            <el-input
              v-model="form.responsibleusername"
              :disabled="isReadOnly"
              placeholder="请输入负责人签字"
            />
          </el-form-item>
        </div>
        <!-- 协调员与签署日期 -->
        <div class="form-row">
          <el-form-item
            label="协调员1"
            prop="coordinatedusernameo"
            class="col-1-3"
          >
            <el-input
              v-model="form.coordinatedusernameo"
              :disabled="isReadOnly"
              placeholder="请输入协调员1"
            />
          </el-form-item>
          <el-form-item
            label="协调员2"
            prop="coordinatedusernamet"
            class="col-1-3"
          >
            <el-input
              v-model="form.coordinatedusernamet"
              :disabled="isReadOnly"
              placeholder="请输入协调员2"
            />
          </el-form-item>
          <el-form-item label="签署日期" prop="signdate" class="col-1-3">
            <el-date-picker
              clearable
              v-model="form.signdate"
              type="date"
              value-format="yyyy-MM-dd"
              placeholder="选择签署日期"
              :disabled="isReadOnly"
            />
          </el-form-item>
        </div>
@@ -169,15 +286,15 @@
    <!-- 添加这里:底部居中按钮 -->
    <!-- 附件信息 - 按类型分类 -->
    <!-- 捐献确认阶段附件(可编辑) -->
    <el-card class="attachment-card">
      <div slot="header" class="clearfix">
        <span class="detail-title">相关附件上传</span>
        <span class="detail-title">捐献确认阶段附件</span>
      </div>
      <el-tabs v-model="activeAttachmentType" type="card">
        <el-tab-pane
          v-for="type in attachmentTypes"
          v-for="type in confirmAttachmentTypes"
          :key="type.value"
          :label="type.label"
          :name="type.value"
@@ -187,6 +304,7 @@
              <span class="upload-title">{{ type.label }}</span>
              <el-tooltip content="点击上传该类型附件" placement="top">
                <el-button
                  v-if="!isReadOnly"
                  size="mini"
                  type="primary"
                  icon="el-icon-plus"
@@ -199,7 +317,7 @@
            <div class="attachment-list">
              <el-table
                :data="getAttachmentsByType(type.value)"
                :data="getConfirmAttachments(type.value)"
                size="small"
                v-loading="attachmentLoading"
                style="width: 100%;"
@@ -244,6 +362,7 @@
                      预览
                    </el-button>
                    <el-button
                      v-if="!isReadOnly"
                      size="mini"
                      type="danger"
                      @click="handleRemoveAttachment(type.value, scope.$index)"
@@ -255,7 +374,94 @@
              </el-table>
              <div
                v-if="getAttachmentsByType(type.value).length === 0"
                v-if="getConfirmAttachments(type.value).length === 0"
                class="empty-attachment"
              >
                <el-empty
                  :description="`暂无${type.label}附件`"
                  :image-size="80"
                ></el-empty>
              </div>
            </div>
          </div>
        </el-tab-pane>
      </el-tabs>
    </el-card>
    <!-- 捐献者登记阶段附件(仅查看) -->
    <el-card class="attachment-card">
      <div slot="header" class="clearfix">
        <span class="detail-title">捐献者登记阶段附件(仅查看)</span>
      </div>
      <el-tabs v-model="activeRegisterType" type="card">
        <el-tab-pane
          v-for="type in registerAttachmentTypes"
          :key="type.value"
          :label="type.label"
          :name="type.value"
        >
          <div class="attachment-section">
            <div class="attachment-header">
              <span class="upload-title">{{ type.label }}</span>
            </div>
            <div class="attachment-list">
              <el-table
                :data="getRegisterAttachments(type.value)"
                size="small"
                v-loading="attachmentLoading"
                style="width: 100%;"
              >
                <el-table-column label="文件名" min-width="200">
                  <template slot-scope="scope">
                    <i
                      class="el-icon-document"
                      style="color: #409EFF; margin-right: 8px;"
                    ></i>
                    <span class="file-name">{{ scope.row.fileName }}</span>
                  </template>
                </el-table-column>
                <el-table-column label="文件类型" width="90" align="center">
                  <template slot-scope="scope">
                    <el-tag size="small">{{
                      getFileType(scope.row.fileName)
                    }}</el-tag>
                  </template>
                </el-table-column>
                <el-table-column label="文件大小" width="90" align="center">
                  <template slot-scope="scope">
                    <span>{{ formatFileSize(scope.row.fileSize) }}</span>
                  </template>
                </el-table-column>
                <el-table-column label="上传时间" width="155" align="center">
                  <template slot-scope="scope">
                    <span>{{
                      formatDateTime(
                        scope.row.uploadTime || scope.row.createTime
                      )
                    }}</span>
                  </template>
                </el-table-column>
                <el-table-column label="操作" width="90" align="center">
                  <template slot-scope="scope">
                    <el-button
                      size="mini"
                      type="primary"
                      @click="handlePreview(scope.row)"
                    >
                      预览
                    </el-button>
                  </template>
                </el-table-column>
              </el-table>
              <div
                v-if="getRegisterAttachments(type.value).length === 0"
                class="empty-attachment"
              >
                <el-empty
@@ -271,6 +477,7 @@
    <!-- 底部操作按钮 -->
    <div style="text-align: center; margin: 30px 0;">
      <el-button
        v-if="!isReadOnly"
        type="primary"
        @click="handleSave"
        :loading="saveLoading"
@@ -279,6 +486,7 @@
        保存确认信息
      </el-button>
      <el-button
        v-if="!isReadOnly"
        type="success"
        @click="accomplish"
        :loading="saveLoading"
@@ -287,60 +495,6 @@
        确认完成
      </el-button>
    </div>
    <!-- 家属弹窗 -->
    <el-dialog
      :title="familyDialogTitle"
      :visible.sync="familyDialogVisible"
      width="420px"
      :close-on-click-modal="false"
    >
      <el-form :model="currentFamilyMember" label-width="110px">
        <el-form-item label="姓名" prop="name">
          <el-input
            v-model="currentFamilyMember.name"
            placeholder="请输入姓名"
          />
        </el-form-item>
        <el-form-item label="与捐赠者关系" prop="relation">
          <el-select
            v-model="currentFamilyMember.relation"
            style="width:100%"
            placeholder="请选择关系"
          >
            <el-option
              v-for="dict in dict.type.sys_FamilyRelation"
              :key="dict.value"
              :label="dict.label"
              :value="dict.value"
            />
          </el-select>
        </el-form-item>
        <template v-if="currentFamilyMember.isMain">
          <el-form-item label="身份证号" prop="idcard">
            <el-input
              v-model="currentFamilyMember.idcard"
              placeholder="请输入身份证号"
              maxlength="18"
            />
          </el-form-item>
          <el-form-item label="联系电话" prop="phone">
            <el-input
              v-model="currentFamilyMember.phone"
              placeholder="请输入联系电话"
              maxlength="11"
            />
          </el-form-item>
        </template>
      </el-form>
      <span slot="footer">
        <el-button @click="familyDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="saveFamilyMember">确定</el-button>
      </span>
    </el-dialog>
    <!-- 上传对话框 -->
    <el-dialog
@@ -394,18 +548,32 @@
</template>
<script>
import { relativesList, relativesEdit, relativesAdd } from "@/api/businessApi";
import {
  relativesList,
  relativesEdit,
  relativesAdd
} from "@/api/businessApi";
import {
  listRelativesconfirmation,
  getRelativesconfirmation
} from "@/api/project/relativesconfirmation";
import {
  getDonatebaseinfo,
  updateDonatebaseinfo
} from "@/api/project/donatebaseinfo";
import FilePreviewDialog from "@/components/FilePreviewDialog";
import CaseBasicInfo from "@/components/CaseBasicInfo";
import Li_area_select from "@/components/Address";
import { getToken } from "@/utils/auth";
export default {
  name: "ConfirmationDetail",
  components: {
    FilePreviewDialog,
    CaseBasicInfo
    CaseBasicInfo,
    Li_area_select
  },
  dicts: ["sys_FamilyRelation"],
  dicts: ["sys_FamilyRelation", "sys_KinshipConfirm", "sys_Kinship"],
  data() {
    return {
      caseId: null,
@@ -422,30 +590,34 @@
        coordinatedusernameo: "",
        coordinatedusernamet: "",
        responsibleusername: "",
        acquisitiontissuename: "",
        relativeconfirmationsign: "0",
        signdate: "",
        relativeconfirmationsignname: "",
        signfamilyrelations: "",
        relativeidcardno: "",
        relativephone: "",
        phone: "",
        kinship: [],
        kinshipChildrennum: null,
        relativeRemark: "",
        assessannex: "",
        otherFamilyMembers: ""
      },
      // 统一亲属列表(第一条为主要亲属,其余为其他亲属)
      familyMemberList: [],
      // 当前编辑的家属(弹窗用)
      currentFamilyMember: {
      familyMemberList: [
        {
        name: "",
        relation: "",
        phone: "",
        idcard: "",
        isMain: false
      },
      isEditFamilyMember: false,
      editFamilyMemberIndex: -1,
      familyDialogVisible: false,
      familyDialogTitle: "添加家属",
          address: { sheng: "", shi: "", qu: "", detail: "" },
          currentResidence: { sheng: "", shi: "", qu: "", detail: "" },
          isMain: true
        }
      ],
      // 标记本次 syncKinshipRelatives 属于"回显填充"(此时允许用已有子女行数兜底数量)
      kinshipHydrated: false,
      uploadAction: process.env.VUE_APP_BASE_API + "/common/upload",
      headers: {
@@ -466,7 +638,9 @@
      loading: false,
      saveLoading: false,
      infoid: null,
      activeAttachmentType: "1",
      archiveData: null,
      activeAttachmentType: "2",
      activeRegisterType: "1",
      attachmentLoading: false,
      uploadDialogVisible: false,
      uploadLoading: false,
@@ -474,30 +648,117 @@
      currentUploadType: "",
      previewVisible: false,
      currentPreviewFile: null,
      attachmentTypes: [
        { value: "1", label: "人体器官潜在捐献者登记表" },
      // 捐献确认阶段附件(可编辑,存储于亲属确认表 assessannex)
      confirmAttachmentTypes: [
        { value: "2", label: "人体器官捐献亲属确认登记表" },
        { value: "3", label: "捐献者及直系亲属身份证、户口簿相关证明" },
        { value: "4", label: "公民身故后人体器官(角膜)遗体捐献告知书" },
        { value: "5", label: "脑死亡判定知情同意书" },
        { value: "6", label: "心死亡判定知情同意书" }
        { value: "7", label: "授权委托资料" }
      ],
      attachmentData: {
        "1": [],
      confirmAttachmentData: {
        "2": [],
        "3": [],
        "4": [],
        "7": []
      },
      // 捐献者登记阶段附件(仅查看,存储于亲属确认表 assessannex)
      registerAttachmentTypes: [
        { value: "1", label: "人体器官潜在捐献者登记表附件" },
        { value: "5", label: "证件照" },
        { value: "6", label: "疾病诊断治疗" }
      ],
      registerAttachmentData: {
        "1": [],
        "5": [],
        "6": []
      }
    };
  },
  computed: {
    // 查看模式:只读,禁用表单并隐藏保存按钮
    isReadOnly() {
      return this.$route.query.mode === "view";
    },
    // 是否选中"成年子女"
    adultChildSelected() {
      const value = this.findAdultChildValue();
      return value != null && (this.form.kinship || []).includes(value);
    },
    // 亲属关系确认字典(优先 sys_KinshipConfirm,其次 sys_Kinship)
    kinshipDictOptions() {
      const a = this.dict.type.sys_KinshipConfirm || [];
      const b = this.dict.type.sys_Kinship || [];
      return a.length ? a : b;
    },
    // 重排亲属关系选项:子女/成年子女排倒数第二,受托人排最后
    orderedKinshipOptions() {
      const list = this.kinshipDictOptions;
      const children = list.filter(d => this.isChildLabel(d.label));
      const trustee = list.filter(d => d.label === "受托人");
      const others = list.filter(
        d => !this.isChildLabel(d.label) && d.label !== "受托人"
      );
      return [...others, ...children, ...trustee];
    },
    // 渲染勾选框实际使用的选项 = 当前字典 + 历史脏数据中映射不到的值
    // 脏值如果不在选项里,el-checkbox-group 根本没有对应复选框,视觉上就是"勾不上";
    // 补成带"(历史数据)"标记的项后既能显示勾选,也允许用户手动取消。
    // 独立成计算属性(不并入 orderedKinshipOptions),避免与 watch 互相触发形成循环。
    kinshipCheckboxOptions() {
      const options = (this.orderedKinshipOptions || []).map(d => ({
        value: String(d.value),
        label: d.label
      }));
      const extra = [];
      (this.form.kinship || []).forEach(v => {
        const raw = String(v);
        if (!raw) return;
        if (options.some(o => o.value === raw)) return;
        if (extra.some(o => o.value === raw)) return;
        const label = this.getKinshipLabel(raw);
        extra.push({
          value: raw,
          label: label === raw ? `历史数据(${raw})` : `${label}(历史数据)`
        });
      });
      return [...options, ...extra];
    },
    // 其他亲属列表(排除第一条主要亲属)
    otherFamilyMemberList() {
      return this.familyMemberList.slice(1);
    },
    // 捐献决定(查看模式只展示已勾选项)
    displayOrganDecision() {
      return (this.organdecision || [])
        .map(item => {
          if (item === "其他" && this.organdecisionOther) {
            return `其他(${this.organdecisionOther})`;
          }
          return item;
        })
        .join("、");
    },
    getCurrentTypeLabel() {
      const type = this.attachmentTypes.find(
      const type =
        this.confirmAttachmentTypes.find(
          t => t.value === this.currentUploadType
        ) ||
        this.registerAttachmentTypes.find(
        t => t.value === this.currentUploadType
      );
      return type ? type.label : "";
    }
  },
  watch: {
    // 字典是异步加载的,加载完成后重新校准已保存的勾选值并重算亲属表
    orderedKinshipOptions(val) {
      if (!val || !val.length) return;
      const normalized = this.normalizeKinshipValues(this.form.kinship || []);
      if (normalized.join(",") !== (this.form.kinship || []).join(",")) {
        this.form.kinship = normalized;
      }
      this.kinshipHydrated = true;
      this.syncKinshipRelatives();
    }
  },
  created() {
@@ -512,9 +773,39 @@
    async getDetail(infoid) {
      this.loading = true;
      try {
        const response = await relativesList({ infoid });
        const response = await relativesList({
          infoid,
          pageNum: 1,
          pageSize: 10
        });
        // 亲属确认完整记录(含 kinship 多选字段),用于保证勾选回显
        let fullRecord = null;
        try {
          const fullRes = await listRelativesconfirmation({
            infoid,
            pageNum: 1,
            pageSize: 10
          });
          if (
            fullRes.code === 200 &&
            Array.isArray(fullRes.rows) &&
            fullRes.rows.length
          ) {
            // 必须校验 infoid 一致,否则可能拿到全表第一条记录
            const matched = fullRes.rows.find(
              r => String(r.infoid) === String(infoid)
            );
            fullRecord = matched || fullRes.rows[0];
          }
        } catch (e) {
          console.warn("获取亲属确认完整记录失败:", e);
        }
        if (response.code === 200) {
          this.handleDetailData(response);
          this.handleDetailData(response, fullRecord);
          await this.loadArchiveInfo();
          // 再用主键精确拉一次完整记录,确保 kinship 一定能拿到
          await this.loadFullKinship();
        } else {
          this.$message.error("获取详情失败:" + (response.msg || "未知错误"));
        }
@@ -526,7 +817,7 @@
      }
    },
    handleDetailData(response) {
    handleDetailData(response, fullRecord) {
      let detailData = null;
      if (response.data) {
        if (Array.isArray(response.data)) {
@@ -538,8 +829,60 @@
        } else {
          detailData = response.data;
        }
      } else if (response.rows && Array.isArray(response.rows)) {
        detailData = response.rows[0] || {};
      } else {
        detailData = response;
      }
      // 先解析亲属大字段:勾选值可能需要从它反推
      this.familyMemberList = [];
      let parsedMembers = [];
      const rawMembers =
        detailData.otherFamilyMembers ||
        (fullRecord && fullRecord.otherFamilyMembers) ||
        "";
      if (rawMembers) {
        try {
          parsedMembers =
            typeof rawMembers === "string"
              ? JSON.parse(rawMembers)
              : rawMembers || [];
          if (!Array.isArray(parsedMembers)) parsedMembers = [];
        } catch (e) {
          console.warn("解析其他家属数据失败:", e);
          parsedMembers = [];
        }
      }
      // 亲属关系确认勾选值:完整记录 → 详情 → 从亲属表反推(三重兜底)
      let kinshipRaw = null;
      if (
        fullRecord &&
        fullRecord.kinship != null &&
        fullRecord.kinship !== ""
      ) {
        kinshipRaw = fullRecord.kinship;
      } else if (detailData.kinship != null && detailData.kinship !== "") {
        kinshipRaw = detailData.kinship;
      }
      let kinshipValues = this.parseKinship(kinshipRaw);
      if (!kinshipValues.length) {
        // 兜底:亲属表能复现,说明它存的 relation 就是当时勾选的值
        kinshipValues = Array.from(
          new Set(
            parsedMembers
              .filter(
                m =>
                  m &&
                  m.isMain !== true &&
                  m.relation != null &&
                  m.relation !== ""
              )
              .map(m => String(m.relation).trim())
              .filter(v => v !== "")
          )
        );
      }
      this.form = {
@@ -555,81 +898,252 @@
        coordinatedusernameo: detailData.coordinatedusernameo || "",
        coordinatedusernamet: detailData.coordinatedusernamet || "",
        responsibleusername: detailData.responsibleusername || "",
        acquisitiontissuename: "",
        relativeconfirmationsign: detailData.relativeconfirmationsign || "0",
        signdate: detailData.signdate,
        signdate: this.normalizeSigndate(detailData.signdate),
        relativeconfirmationsignname:
          detailData.relativeconfirmationsignname || "",
        signfamilyrelations: detailData.signfamilyrelations || "",
        relativeidcardno: detailData.relativeidcardno || "",
        relativephone: detailData.relativephone || "",
        phone: detailData.phone || detailData.relativephone || "",
        kinship: kinshipValues,
        kinshipChildrennum:
          detailData.kinshipChildrennum != null &&
          detailData.kinshipChildrennum !== ""
            ? detailData.kinshipChildrennum
            : fullRecord && fullRecord.kinshipChildrennum != null
            ? fullRecord.kinshipChildrennum
            : null,
        relativeRemark: detailData.relativeRemark || "",
        assessannex: detailData.assessannex || ""
      };
      // 初始化家属列表
      this.familyMemberList = [];
      if (detailData.relativeconfirmationsignname) {
        this.familyMemberList.push({
          name: detailData.relativeconfirmationsignname,
      // 主要亲属:优先取 JSON 中标记 isMain 的项(新格式,含住址/现居住地)
      let mainMember = (parsedMembers || []).find(m => m && m.isMain === true);
      // 命中项在解析数组中的位置;-1 表示主亲属不来自 otherFamilyMembers
      let mainIndex = mainMember ? parsedMembers.indexOf(mainMember) : -1;
      if (!mainMember) {
        const hasMain =
          detailData.relativeconfirmationsignname ||
          detailData.signfamilyrelations ||
          detailData.relativeidcardno;
        if (hasMain) {
          // 老格式:主亲属存在专用字段里,otherFamilyMembers 只存"其他亲属"
          mainMember = {
            name: detailData.relativeconfirmationsignname || "",
          relation: detailData.signfamilyrelations || "",
          phone: detailData.relativephone || "",
          idcard: detailData.relativeidcardno || ""
        });
            idcard: detailData.relativeidcardno || "",
            phone: detailData.phone || detailData.relativephone || "",
            address: "",
            currentResidence: "",
            isMain: true
          };
        } else if (parsedMembers.length) {
          // 脏数据兜底:主亲属专用字段全空、JSON 里也没有 isMain 标记时,
          // 把第一条当作主亲属,其余作为其他亲属,避免主亲属整块空白
          mainMember = parsedMembers[0];
          mainIndex = 0;
      }
      if (detailData.otherFamilyMembers) {
        try {
          const otherMembers =
            typeof detailData.otherFamilyMembers === "string"
              ? JSON.parse(detailData.otherFamilyMembers)
              : detailData.otherFamilyMembers || [];
          otherMembers.forEach(member => {
      }
            this.familyMemberList.push({
              name: member.name,
              relation: member.relation,
        name: (mainMember && mainMember.name) || "",
        relation: (mainMember && mainMember.relation) || "",
        idcard: (mainMember && mainMember.idcard) || "",
        phone: (mainMember && mainMember.phone) || "",
        address: this.normalizeAddress(mainMember && mainMember.address),
        currentResidence: this.normalizeAddress(
          mainMember && mainMember.currentResidence
        ),
        isMain: true
      });
      // 其他亲属(姓名来自 JSON,关系按 kinship 勾选生成)
      // 历史脏数据的行没有 isMain / seq / 住址字段,这里统一补齐默认值
      (parsedMembers || []).forEach((member, idx) => {
        if (!member) return;
        if (idx === mainIndex) return;
        if (member.isMain === true) return;
        this.familyMemberList.push({
          relation: member.relation != null ? String(member.relation) : "",
          seq: member.seq != null ? member.seq : 0,
          name: member.name || "",
              phone: member.phone || "",
              idcard: member.idcard || ""
          idcard: member.idcard || "",
          address: this.normalizeAddress(member.address),
          currentResidence: this.normalizeAddress(member.currentResidence),
          isMain: false
            });
          });
        } catch (e) {
          console.warn("解析其他家属数据失败:", e);
        }
      }
      // 字典若已缓存,watch 不会触发,这里主动把勾选值归一化一次
      this.form.kinship = this.normalizeKinshipValues(this.form.kinship || []);
      // 根据 kinship 勾选自动生成亲属表行(保留已有姓名)
      this.kinshipHydrated = true;
      this.syncKinshipRelatives();
      if (detailData.organdecision) {
        this.organdecision = Array.isArray(detailData.organdecision)
          ? detailData.organdecision
          : detailData.organdecision.split(",");
      }
      this.organdecisionOther = detailData.organdecisionOther || "";
      this.processAssessannexData();
      // 调试用:确认 kinship / 子女数量 / 亲属大字段 是否都回来了
      console.log("[affirmInfo] 亲属关系回显", {
        kinship: this.form.kinship,
        kinshipChildrennum: this.form.kinshipChildrennum,
        otherFamilyMembers: this.form.otherFamilyMembers
      });
    },
    // 加载档案表信息(人体器官获取组织等字段属于档案表,不在亲属确认表)
    async loadArchiveInfo() {
      if (!this.caseId) return;
      try {
        const caseRes = await getDonatebaseinfo(this.caseId);
        if (caseRes.code === 200 && caseRes.data) {
          this.archiveData = caseRes.data;
          this.form.acquisitiontissuename =
            caseRes.data.acquisitiontissuename || "";
        }
      } catch (e) {
        console.warn("获取档案表信息失败:", e);
      }
    },
    // 用主键精确拉取完整记录,补齐列表接口可能缺失的 kinship 字段
    async loadFullKinship() {
      const rid = this.form.id || this.$route.query.id;
      if (!rid) return;
      try {
        const res = await getRelativesconfirmation(rid);
        const data = res && res.data;
        if (!data) return;
        let changed = false;
        if (data.kinship != null && data.kinship !== "") {
          const values = this.parseKinship(data.kinship);
          // 接口返回的真实值优先于从 otherFamilyMembers 反推的兜底值
          // (反推值只用于字段缺失的情况,属于降级真相源)
          if (
            values.length &&
            values.join(",") !== (this.form.kinship || []).join(",")
          ) {
            this.form.kinship = values;
            changed = true;
          }
        }
        if (
          (this.form.kinshipChildrennum == null ||
            this.form.kinshipChildrennum === "") &&
          data.kinshipChildrennum != null
        ) {
          this.form.kinshipChildrennum = data.kinshipChildrennum;
          changed = true;
        }
        if (changed) {
          this.kinshipHydrated = true;
          this.syncKinshipRelatives();
        }
      } catch (e) {
        console.warn("获取亲属确认完整记录失败(getInfo):", e);
      }
    },
    // 把已保存的勾选值映射到当前字典的 value(兼容两套字典编码不一致)
    // 注意:映射不到的历史脏值(如 relation="4"/"6")必须原样保留,不能丢弃;
    // 字典是异步加载的,若在此处过滤,字典一到位就会把反推出来的勾选清空。
    normalizeKinshipValues(values) {
      const options = this.orderedKinshipOptions || [];
      if (!options.length) return values;
      const result = [];
      (values || []).forEach(v => {
        const mapped = this.toCurrentKinshipValue(v);
        if (mapped !== "" && !result.includes(mapped)) result.push(mapped);
      });
      return result;
    },
    // 单个关系值 → 当前字典体系下的值
    // 命中顺序:当前字典 value → 当前字典同名 label → 子女类归一化(子女 ⇄ 成年子女)
    // 全都命中不了说明是历史脏数据,原样返回,保证表格行不丢、勾选不被抹掉
    toCurrentKinshipValue(v) {
      if (v == null || v === "") return "";
      const options = this.orderedKinshipOptions || [];
      if (!options.length) return String(v);
      const raw = String(v);
      if (options.some(o => String(o.value) === raw)) return raw;
      const label = this.getKinshipLabel(raw);
      if (!label || label === raw) return raw; // 三个字典都查不到 → 脏值原样保留
      const sameLabel = options.find(o => o.label === label);
      if (sameLabel) return String(sameLabel.value);
      // 子女类关系在不同字典里叫法不同("子女"/"成年子女"),视为同一关系
      if (this.isChildLabel(label)) {
        const exact = options.find(o => o.label === "成年子女");
        if (exact) return String(exact.value);
        const any = options.find(o => this.isChildLabel(o.label));
        if (any) return String(any.value);
      }
      return raw;
    },
    // 解析亲属关系确认(多选,; 或 , 分隔,统一转为字符串数组)
    parseKinship(val) {
      if (!val) return [];
      const arr = Array.isArray(val) ? val : String(val).split(/[;,]/);
      return arr
        .map(v => (v == null ? "" : String(v).trim()))
        .filter(v => v !== "");
    },
    // 签署日期统一转成 yyyy-MM-dd,兼容后端返回的多种日期格式
    normalizeSigndate(val) {
      if (!val) return null;
      const m = String(val).match(/^(\d{4}-\d{2}-\d{2})/);
      return m ? m[1] : null;
    },
    processAssessannexData() {
      if (this.form.assessannex) {
      Object.keys(this.confirmAttachmentData).forEach(key => {
        this.confirmAttachmentData[key] = [];
      });
      Object.keys(this.registerAttachmentData).forEach(key => {
        this.registerAttachmentData[key] = [];
      });
      if (!this.form.assessannex) return;
        try {
          const annexData =
            typeof this.form.assessannex === "string"
              ? JSON.parse(this.form.assessannex)
              : this.form.assessannex;
          Object.keys(this.attachmentData).forEach(key => {
            this.attachmentData[key] = [];
          });
          if (Array.isArray(annexData)) {
            annexData.forEach(attachment => {
              const type = attachment.type || "1";
              if (this.attachmentData[type]) {
                this.attachmentData[type].push(attachment);
            const type = String(attachment.type || "");
            // 确认阶段(2/3/4)与登记阶段(1/5/6)均维护在 assessannex
            if (this.confirmAttachmentData[type]) {
              this.confirmAttachmentData[type].push(attachment);
            } else if (this.registerAttachmentData[type]) {
              this.registerAttachmentData[type].push(attachment);
              }
            });
          }
        } catch (error) {
          console.warn("assessannex数据解析失败:", error);
        }
      }
    },
    getAttachmentsByType(type) {
      return this.attachmentData[type] || [];
    getConfirmAttachments(type) {
      return this.confirmAttachmentData[type] || [];
    },
    getRegisterAttachments(type) {
      return this.registerAttachmentData[type] || [];
    },
    openUploadDialog(type) {
@@ -696,7 +1210,11 @@
        uploadTime: this.getCurrentTime(),
        uploader: "当前用户"
      };
      this.attachmentData[this.currentUploadType].push(newAttachment);
      if (this.confirmAttachmentData[this.currentUploadType]) {
        this.confirmAttachmentData[this.currentUploadType].push(newAttachment);
      } else if (this.registerAttachmentData[this.currentUploadType]) {
        this.registerAttachmentData[this.currentUploadType].push(newAttachment);
      }
      this.updateAssessannexField();
      this.$message.success("上传成功");
@@ -721,8 +1239,10 @@
        type: "warning"
      })
        .then(() => {
          if (this.attachmentData[type] && this.attachmentData[type][index]) {
            this.attachmentData[type].splice(index, 1);
          const container =
            this.confirmAttachmentData[type] || this.registerAttachmentData[type];
          if (container && container[index]) {
            container.splice(index, 1);
            this.$message.success("附件删除成功");
            this.updateAssessannexField();
          }
@@ -730,146 +1250,276 @@
        .catch(() => {});
    },
    // 家属操作方法
    openFamilyDialog(isMain) {
      this.isEditFamilyMember = false;
      this.editFamilyMemberIndex = -1;
      this.familyDialogTitle = "添加其他家属";
      // 如果还没有任何家属,则添加主要亲属
      if (this.familyMemberList.length === 0) {
        this.currentFamilyMember = {
          name: "",
          relation: "",
          phone: "",
          idcard: "",
          isMain: true
        };
        this.familyDialogTitle = "添加主要亲属";
      } else {
        this.currentFamilyMember = {
          name: "",
          relation: "",
          phone: "",
          idcard: "",
          isMain: false
        };
      }
      this.familyDialogVisible = true;
    },
    editFamilyMember(index) {
      this.isEditFamilyMember = true;
      this.editFamilyMemberIndex = index;
      const member = this.familyMemberList[index];
      this.currentFamilyMember = {
        name: member.name,
        relation: member.relation,
        phone: member.phone || "",
        idcard: member.idcard || "",
        isMain: index === 0
      };
      this.familyDialogTitle = index === 0 ? "编辑主要亲属" : "编辑其他家属";
      this.familyDialogVisible = true;
    },
    deleteFamilyMember(index) {
      if (index === 0) {
        this.$message.warning("主要亲属不可删除");
        return;
      }
      this.$confirm("确认删除该家属?", "提示", { type: "warning" })
        .then(() => {
          this.familyMemberList.splice(index, 1);
          this.updateFamilyMemberField();
        })
        .catch(() => {});
    },
    saveFamilyMember() {
      if (!this.currentFamilyMember.name) {
        this.$message.warning("请输入姓名");
        return;
      }
      if (!this.currentFamilyMember.relation) {
        this.$message.warning("请选择与捐赠者关系");
        return;
      }
      // 如果是主要亲属,验证身份证和电话
      if (this.currentFamilyMember.isMain) {
        if (!this.currentFamilyMember.idcard) {
          this.$message.warning("请输入主要亲属的身份证号");
          return;
        }
        if (
          !/^(\d{15}|\d{18}|\d{17}(\d|X|x))$/.test(
            this.currentFamilyMember.idcard
    // 根据 kinship 勾选自动生成亲属表行,同时保留已有亲属数据(合并,避免丢失)
    syncKinshipRelatives() {
      // 勾选值统一映射到当前字典体系,保证与表格行的 relation 处在同一值域。
      // 必须去重:历史脏数据里多个不同编码(如 "4"、"6")可能映射成同一个 value,
      // 不去重的话每个重复值都会再生成一遍行,表现就是"行数成倍变多"。
      const kinship = Array.from(
        new Set(
          (this.form.kinship || [])
            .map(v => this.toCurrentKinshipValue(v))
            .filter(v => v !== "")
          )
        ) {
          this.$message.warning("请输入正确的身份证号");
          return;
      );
      const adultChildValue = this.findAdultChildValue();
      // 已有亲属(非主要亲属),保留姓名与关系;关系值统一映射到当前字典体系
      const existing = this.familyMemberList
        .slice(1)
        .filter(m => m && !m.isMain)
        .map(m => ({ ...m, relation: this.toCurrentKinshipValue(m.relation) }));
      // 子女数量:接口可能不返回该字段
      // 回显时用已有子女行数兜底;用户主动清空("")则不兜底,行照常清掉
      const existingChildCount = adultChildValue
        ? existing.filter(e => e.relation === adultChildValue).length
        : 0;
      const rawCountStr = this.form.kinshipChildrennum;
      // null / "" / 数字 0 都视为"没填数量"(真要 0 个,取消勾选即可)
      const rawMissing =
        rawCountStr == null || rawCountStr === "" || rawCountStr === 0;
      let childCount;
      if (rawMissing) {
        childCount = this.kinshipHydrated ? existingChildCount : 0;
        // 回显兜底:把推算出的数量写回表单,否则数量框空白、保存时又丢
        // (程序赋值不会触发 el-input 的 @input,不会形成循环)
        if (this.kinshipHydrated && existingChildCount > 0) {
          this.form.kinshipChildrennum = String(existingChildCount);
        }
        if (!this.currentFamilyMember.phone) {
          this.$message.warning("请输入主要亲属的联系电话");
          return;
        }
        if (!/^1[3-9]\d{9}$/.test(this.currentFamilyMember.phone)) {
          this.$message.warning("请输入正确的手机号");
          return;
        }
      } else {
        const n = parseInt(rawCountStr, 10);
        childCount = isNaN(n) || n < 0 ? 0 : n;
      }
      const memberData = {
        name: this.currentFamilyMember.name,
        relation: this.currentFamilyMember.relation,
        phone: this.currentFamilyMember.isMain
          ? this.currentFamilyMember.phone
          : "",
        idcard: this.currentFamilyMember.isMain
          ? this.currentFamilyMember.idcard
          : ""
      // 取一行已有数据复用姓名:先按 关系+序号 精确匹配,再退化为同关系顺序取
      const used = new Set();
      const takeExisting = (relation, seq) => {
        let idx = existing.findIndex(
          (e, i) =>
            !used.has(i) && e.relation === relation && (e.seq || 0) === seq
        );
        if (idx === -1) {
          idx = existing.findIndex(
            (e, i) => !used.has(i) && e.relation === relation
          );
        }
        if (idx === -1) return null;
        used.add(idx);
        return existing[idx];
      };
      if (this.isEditFamilyMember) {
        this.familyMemberList.splice(this.editFamilyMemberIndex, 1, memberData);
      // 生成一行:命中已有行时整行复用(含 phone/idcard/住址等),
      // 历史脏数据里这些字段可能有值,重建时不能只保留 relation/name 把其余抹掉
      const buildRow = (relation, seq, hit) => ({
        relation: relation,
        seq: seq,
        name: (hit && hit.name) || "",
        phone: (hit && hit.phone) || "",
        idcard: (hit && hit.idcard) || "",
        address: this.normalizeAddress(hit && hit.address),
        currentResidence: this.normalizeAddress(hit && hit.currentResidence),
        isMain: false
      });
      const merged = [];
      kinship.forEach(rel => {
        if (adultChildValue && rel === adultChildValue) {
          // 成年子女:子女数量决定行数
          for (let i = 0; i < childCount; i++) {
            const hit = takeExisting(rel, i);
            merged.push(buildRow(rel, i, hit));
          }
      } else {
        this.familyMemberList.push(memberData);
          const hit = takeExisting(rel, 0);
          merged.push(buildRow(rel, 0, hit));
        }
      });
      // 未被勾选命中的已有亲属一律保留。
      // 不能按关系去重:历史数据里"两个兄弟姐妹"这类同关系多行是合法的,
      // 去重会静默丢人。之前出现"同关系重复行"的根因是 takeExisting 没命中,
      // 现在 used 保证每个已有行最多被消耗一次,不会重复生成。
      existing.forEach((e, idx) => {
        if (used.has(idx)) return;
        // 子女行数由子女数量决定,多余的子女行不保留
        if (adultChildValue && e.relation === adultChildValue) return;
        merged.push(buildRow(e.relation || "", e.seq != null ? e.seq : 0, e));
      });
      this.familyMemberList = [this.familyMemberList[0], ...merged];
      this.updateFamilyMemberField();
      // 兜底只在回显那一次生效
      this.kinshipHydrated = false;
    },
    // 删除亲属表某一行,并同步取消上方对应的关系勾选
    handleDeleteFamilyRow(index) {
      const rowIndex = index + 1; // otherFamilyMemberList = familyMemberList.slice(1)
      const row = this.familyMemberList[rowIndex];
      if (!row) return;
      if (row.isMain) return;
      const relation = row.relation
        ? this.toCurrentKinshipValue(row.relation)
        : "";
      const adultChildValue = this.findAdultChildValue();
      const isChild = !!adultChildValue && relation === adultChildValue;
      // 勾选里存的可能是历史编码(如 "4")而不是映射后的值(如 "2"),
      // 取消勾选时两种都要比对,否则会出现"行删了但勾选还在"
      const removeKinship = target => {
        const mapped = this.toCurrentKinshipValue(target);
        this.form.kinship = (this.form.kinship || []).filter(
          v =>
            String(v) !== String(target) &&
            this.toCurrentKinshipValue(v) !== mapped
        );
      };
      console.log("[affirmInfo] 删除亲属行", {
        index,
        relation,
        adultChildValue,
        isChild,
        before: this.familyMemberList.slice(1).map(m => m.relation),
        kinship: this.form.kinship
      });
      if (isChild) {
        // 成年子女:直接删这一行,数量按剩余子女行数重算,归零才取消勾选
        this.familyMemberList.splice(rowIndex, 1);
        const rest = this.familyMemberList.filter(
          (m, i) =>
            i > 0 &&
            !m.isMain &&
            this.toCurrentKinshipValue(m.relation) === adultChildValue
        ).length;
        if (rest > 0) {
          this.form.kinshipChildrennum = String(rest);
        } else {
          this.form.kinshipChildrennum = "";
          removeKinship(adultChildValue);
        }
      } else if (relation) {
        // 其余关系:一行对应一个勾选,取消勾选并整组清掉
        removeKinship(relation);
        this.familyMemberList = this.familyMemberList.filter(
          (m, i) =>
            i === 0 ||
            m.isMain ||
            this.toCurrentKinshipValue(m.relation) !== relation
        );
      } else {
        // 关系为空的历史遗留行,只删这一行
        this.familyMemberList.splice(rowIndex, 1);
      }
      // 直接回写大字段。不调用 syncKinshipRelatives,避免行被按勾选重新生成回来
      this.updateFamilyMemberField();
      this.familyDialogVisible = false;
      this.$message.success(this.isEditFamilyMember ? "编辑成功" : "添加成功");
      if (relation) {
        this.$message.success(
          `已移除「${this.getKinshipLabel(relation)}」并同步取消勾选`
        );
      }
    },
    getKinshipLabel(value) {
      if (value == null || value === "") return "";
      const dictLists = [
        this.dict.type.sys_KinshipConfirm,
        this.dict.type.sys_Kinship,
        this.dict.type.sys_FamilyRelation
      ];
      for (const list of dictLists) {
        const dict = (list || []).find(d => String(d.value) === String(value));
        if (dict) return dict.label;
      }
      // 三个字典都查不到 → 老编码/脏数据,按原值展示,并记录一次便于排查
      if (!this._warnedKinshipValues) this._warnedKinshipValues = new Set();
      const key = String(value);
      if (!this._warnedKinshipValues.has(key)) {
        this._warnedKinshipValues.add(key);
        console.warn(
          `[affirmInfo] 亲属关系编码「${key}」在 sys_KinshipConfirm / sys_Kinship / sys_FamilyRelation 中均不存在,按原值展示`
        );
      }
      return value;
    },
    isChildLabel(label) {
      return label === "子女" || label === "成年子女";
    },
    findAdultChildValue() {
      const list = this.kinshipDictOptions || [];
      // 优先精确匹配"成年子女",避免把"子女"当成成年子女处理
      const exact = list.find(d => d.label === "成年子女");
      if (exact) return String(exact.value);
      const any = list.find(d => this.isChildLabel(d.label));
      return any ? String(any.value) : null;
    },
    formatAddress(addr) {
      if (!addr) return "";
      if (typeof addr === "string") return addr;
      return [addr.sheng, addr.shi, addr.qu, addr.detail]
        .filter(p => p)
        .join("");
    },
    normalizeAddress(addr) {
      if (!addr) {
        return { sheng: "", shi: "", qu: "", detail: "" };
      }
      if (typeof addr === "string") {
        return { sheng: "", shi: "", qu: "", detail: addr };
      }
      return {
        sheng: (addr && addr.sheng) || "",
        shi: (addr && addr.shi) || "",
        qu: (addr && addr.qu) || "",
        detail: (addr && addr.detail) || ""
      };
    },
    updateFamilyMemberField() {
      if (this.familyMemberList.length > 0) {
        const mainMember = this.familyMemberList[0];
        this.form.relativeconfirmationsignname = mainMember.name;
        this.form.signfamilyrelations = mainMember.relation;
      if (mainMember) {
        this.form.relativeconfirmationsignname = mainMember.name || "";
        this.form.signfamilyrelations = mainMember.relation || "";
        this.form.relativeidcardno = mainMember.idcard || "";
        this.form.phone = mainMember.phone || "";
        this.form.relativephone = mainMember.phone || "";
        const otherMembers = this.familyMemberList.slice(1).map(member => ({
          name: member.name,
          relation: member.relation,
          phone: member.phone || "",
          idcard: member.idcard || ""
        }));
        this.form.otherFamilyMembers = JSON.stringify(otherMembers);
      } else {
        this.form.relativeconfirmationsignname = "";
        this.form.signfamilyrelations = "";
        this.form.relativeidcardno = "";
        this.form.phone = "";
        this.form.relativephone = "";
        this.form.otherFamilyMembers = "[]";
      }
      // 所有亲属(含主要亲属)统一存入一个 JSON 大字段,住址/现居住地也存这里
      const allMembers = this.familyMemberList.map((member, index) => ({
        name: member.name || "",
        relation: member.relation || "",
        idcard: member.idcard || "",
        phone: member.phone || "",
        address: member.address || "",
        currentResidence: member.currentResidence || "",
        seq: member.seq != null ? member.seq : 0,
        isMain: index === 0
      }));
      this.form.otherFamilyMembers = JSON.stringify(allMembers);
    },
    updateAssessannexField() {
      const allAttachments = [];
      Object.values(this.attachmentData).forEach(attachments => {
      [
        ...Object.values(this.confirmAttachmentData),
        ...Object.values(this.registerAttachmentData)
      ].forEach(attachments => {
        allAttachments.push(...attachments);
      });
      this.form.assessannex = JSON.stringify(allAttachments);
@@ -977,6 +1627,7 @@
    },
    async handleSave() {
      if (this.saveLoading) return;
      try {
        await this.$refs.form.validate();
        this.saveLoading = true;
@@ -988,10 +1639,26 @@
          ...this.form,
          infoid: this.infoid,
          organdecision: this.organdecision.join(","),
          organdecisionOther: this.organdecisionOther
          organdecisionOther: this.organdecisionOther,
          kinship: (this.form.kinship || []).join(",")
        };
        // 人体器官获取组织属于档案表字段,不随亲属确认表保存
        delete saveData.acquisitiontissuename;
        // 签署日期为空时不提交,避免后端 Date 反序列化报错
        if (!saveData.signdate) {
          delete saveData.signdate;
        }
        if (saveData.state == 1 || !saveData.state) {
          saveData.state = 2;
        }
        // 新增时校验是否已有相同患者
        if (!saveData.id) {
          const exists = await this.checkPatientExists();
          if (exists) {
            this.$message.warning("该患者已存在,请勿重复添加");
            return;
          }
        }
        let response = null;
@@ -1002,6 +1669,8 @@
        }
        if (response.code === 200) {
          // 人体器官获取组织单独保存到档案表
          await this.saveArchiveAcquisitionTissue();
          this.$message.success("保存成功");
          this.$router.push("/case/affirm");
        } else {
@@ -1014,6 +1683,45 @@
        }
      } finally {
        this.saveLoading = false;
      }
    },
    // 保存档案表的人体器官获取组织字段
    async saveArchiveAcquisitionTissue() {
      if (!this.caseId) return;
      try {
        const payload = {
          ...(this.archiveData || {}),
          id: this.caseId,
          acquisitiontissuename: this.form.acquisitiontissuename
        };
        await updateDonatebaseinfo(payload);
      } catch (e) {
        console.warn("保存档案表人体器官获取组织失败:", e);
      }
    },
    // 新增时校验是否已有相同患者(按住院号)
    async checkPatientExists() {
      let inpatientno = this.form.inpatientno;
      if (!inpatientno && this.caseId) {
        try {
          const caseRes = await getDonatebaseinfo(this.caseId);
          inpatientno = (caseRes.data && caseRes.data.inpatientno) || "";
        } catch (e) {
          inpatientno = "";
        }
      }
      if (!inpatientno) return false;
      try {
        const res = await relativesList({
          inpatientno,
          pageNum: 1,
          pageSize: 1
        });
        const list = res.data || [];
        return list.some(item => item && item.id != null && item.id !== "");
      } catch (e) {
        return false;
      }
    }
  }
@@ -1171,19 +1879,53 @@
  line-height: 1.4;
}
/* 控件宽度适中,不铺满整格(内容短时输入框不再拉得很长) */
/* 控件宽度适中,不铺满整格(内容短时输入框不再拉得很长);窄屏时自动收缩避免溢出 */
.paper-form >>> .el-form-item__content .el-input,
.paper-form >>> .el-form-item__content .el-select,
.paper-form >>> .el-form-item__content .el-cascader {
  width: 220px;
  max-width: 100%;
  width: 100%;
  max-width: 220px;
}
.paper-form >>> .el-form-item__content .el-date-editor {
  width: 240px;
  max-width: 100%;
  width: 100%;
  max-width: 240px;
}
.paper-form >>> .el-form-item__content .el-range-editor {
  width: 360px;
  max-width: 100%;
}
/* 地址选择器(省市区三级联动 + 详细地址,详细地址分行显示) */
.paper-form >>> .area-select-box {
  flex: 0 0 auto;
  width: 480px;
  max-width: 100%;
}
.paper-form >>> .address-detail {
  flex: 0 0 100%;
  width: 100% !important;
  margin: 6px 0 0 0;
}
/* 捐献决定语句排版 */
.paper-form >>> .decision-statement {
  flex: 0 0 100%;
  width: 100%;
  line-height: 1.8;
  font-size: 13px;
  color: #303133;
  padding: 2px 0;
}
.paper-form >>> .decision-other {
  width: 320px !important;
  margin-left: 8px;
}
.paper-form >>> .decision-selected {
  flex: 0 0 100%;
  width: 100%;
  line-height: 1.8;
  font-size: 13px;
  color: #303133;
  padding: 2px 0;
}
</style>