WXL (wul)
5 天以前 39c8b288ec8294e026459dfb1955f0bbc49ebb52
src/views/patient/archives/childHealth/detail.vue
@@ -60,9 +60,20 @@
        </div>
        <el-form :model="archive" label-width="110px" size="small" :disabled="!editing">
          <el-row :gutter="20">
            <el-col :span="8"><el-form-item label="身份证号"><el-input v-model="archive.idcardno" class="w-md" placeholder="输入合法身份证号后自动带出出生日期与年龄" /></el-form-item></el-col>
          </el-row>
          <el-row :gutter="20">
            <el-col :span="8"><el-form-item label="出生日期"><el-date-picker v-model="archive.birthday" value-format="yyyy-MM-dd" class="w-md" /></el-form-item></el-col>
            <el-col :span="8"><el-form-item label="出生体重"><el-input v-model="archive.birthWeight" class="w-xs" /></el-form-item></el-col>
            <el-col :span="8"><el-form-item label="出生孕周"><el-input v-model="archive.gestationalWeek" class="w-xs" /></el-form-item></el-col>
            <el-col :span="8"><el-form-item label="出生体重">
              <el-input v-model="archive.birthWeight" class="w-xs">
                <template slot="append">kg</template>
              </el-input>
            </el-form-item></el-col>
            <el-col :span="8"><el-form-item label="出生孕周">
              <el-input v-model="archive.gestationalWeek" class="w-xs">
                <template slot="append">周</template>
              </el-input>
            </el-form-item></el-col>
          </el-row>
          <el-row :gutter="20">
            <el-col :span="8"><el-form-item label="诊断日期"><el-date-picker v-model="archive.diagnosisDate" value-format="yyyy-MM-dd" class="w-md" /></el-form-item></el-col>
@@ -76,11 +87,11 @@
      </el-card>
      <!-- 高危儿专案 → 可编辑表格 -->
      <el-card v-if="archive.subType === 'highRisk'" class="info-card" shadow="never" style="margin-top:14px">
      <el-card v-if="archive.subType === 'highrisk'" class="info-card" shadow="never" style="margin-top:14px">
        <div slot="header" class="card-header"><span>高危儿专案管理</span></div>
        <el-form :model="archive" label-width="110px" size="small" :disabled="!editing" inline>
          <el-form-item label="高危儿分类"><el-input v-model="archive.highRiskCategory" class="w-md" /></el-form-item>
          <el-form-item label="高危儿名称"><el-input v-model="archive.highRiskName" class="w-lg" /></el-form-item>
          <el-form-item label="高危儿分类"><el-input v-model="archive.highriskCategory" class="w-md" /></el-form-item>
          <el-form-item label="高危儿名称"><el-input v-model="archive.highriskName" class="w-lg" /></el-form-item>
          <el-form-item label="拟随访日期"><el-date-picker v-model="archive.followupDate" value-format="yyyy-MM-dd" class="w-md" /></el-form-item>
        </el-form>
        <el-tabs v-model="activeTab" type="border-card">
@@ -177,7 +188,7 @@
import EditableTable from "../components/EditableTable.vue";
import InfoField from "./InfoField.vue";
import ServiceRecords from "../components/ServiceRecords.vue";
import { loadArchives, saveArchives } from "../types";
import { getArchive, saveArchive, closeArchive, calcAge } from "../apiAdapter";
export default {
  name: "ChildHealthArchiveDetail",
@@ -195,37 +206,37 @@
      growthData: [], neuroData: [], interventionData: [],
      measureData: [], dietData: [], planData: [],
      growthColumns: [
        { prop:"checkDate", label:"检查日期", width:120, type:"date" },{ prop:"monthAge", label:"月龄", width:80 },
        { prop:"checkDate", label:"检查日期", width:180, type:"date" },{ prop:"monthAge", label:"月龄", width:80 },
        { prop:"weight", label:"体重(kg)", width:100, type:"number" },{ prop:"height", label:"身高(cm)", width:100, type:"number" },
        { prop:"headCircum", label:"头围(cm)", width:100, type:"number" },{ prop:"weightPercentile", label:"体重百分位", width:110 },
        { prop:"heightPercentile", label:"身高百分位", width:110 },{ prop:"evaluation", label:"评估结果", type:"select", options:["正常","偏瘦","偏胖","发育迟缓"] },
        { prop:"doctor", label:"检查医生", width:100 },
      ],
      neuroColumns: [
        { prop:"checkDate", label:"评估日期", width:120, type:"date" },{ prop:"monthAge", label:"月龄", width:70 },
        { prop:"checkDate", label:"评估日期", width:180, type:"date" },{ prop:"monthAge", label:"月龄", width:70 },
        { prop:"muscleTone", label:"肌张力", width:100 },{ prop:"reflex", label:"原始反射", width:100 },
        { prop:"gms", label:"GMs评估", width:120 },{ prop:"nbnaScore", label:"NBNA评分", width:100, type:"number" },
        { prop:"evaluation", label:"综合评估", type:"select", options:["正常","异常","可疑"] },{ prop:"doctor", label:"评估医生", width:100 },
      ],
      interventionColumns: [
        { prop:"date", label:"日期", width:120, type:"date" },{ prop:"type", label:"干预类型", width:140 },
        { prop:"date", label:"日期", width:180, type:"date" },{ prop:"type", label:"干预类型", width:140 },
        { prop:"content", label:"干预内容", minWidth:200 },{ prop:"frequency", label:"频率", width:120 },
        { prop:"effect", label:"效果评价", width:100 },{ prop:"executor", label:"执行人", width:100 },
      ],
      measureColumns: [
        { prop:"checkDate", label:"检查日期", width:120, type:"date" },{ prop:"weight", label:"体重(kg)", width:100, type:"number" },
        { prop:"checkDate", label:"检查日期", width:180, type:"date" },{ prop:"weight", label:"体重(kg)", width:100, type:"number" },
        { prop:"height", label:"身高(cm)", width:100, type:"number" },{ prop:"bmi", label:"BMI", width:80, type:"number" },
        { prop:"bmiPercentile", label:"BMI百分位", width:110 },{ prop:"waistHip", label:"腰围/臀围", width:120 },
        { prop:"evaluation", label:"营养评价", type:"select", options:["正常","超重","肥胖","营养不良"] },
      ],
      dietColumns: [
        { prop:"date", label:"评估日期", width:120, type:"date" },{ prop:"energy", label:"能量(kcal/d)", width:120, type:"number" },
        { prop:"date", label:"评估日期", width:180, type:"date" },{ prop:"energy", label:"能量(kcal/d)", width:120, type:"number" },
        { prop:"protein", label:"蛋白质(g/d)", width:120, type:"number" },{ prop:"fat", label:"脂肪(g/d)", width:100, type:"number" },
        { prop:"carbs", label:"碳水(g/d)", width:100, type:"number" },{ prop:"dietScore", label:"膳食评分", width:100 },
        { prop:"problem", label:"存在问题", minWidth:160 },
      ],
      planColumns: [
        { prop:"date", label:"制定日期", width:120, type:"date" },{ prop:"target", label:"干预目标", minWidth:200 },
        { prop:"date", label:"制定日期", width:180, type:"date" },{ prop:"target", label:"干预目标", minWidth:200 },
        { prop:"energyTarget", label:"能量目标(kcal)", width:130, type:"number" },{ prop:"foodGuide", label:"膳食指导", minWidth:200 },
        { prop:"exercise", label:"运动建议", minWidth:180 },{ prop:"reviewDate", label:"复查日期", width:120 },
      ],
@@ -238,17 +249,55 @@
      return map[this.archive?.sourcePage] || this.archive?.sourcePage || "-";
    },
  },
  watch: {
    // 身份证号填完整后,自动把出生日期与年龄补上(只补空字段)
    "archive.idcardno"(val) { this.fillBirthdayFromIdcard(val); },
  },
  created() {
    const id = this.$route.query.id;
    if (id) this.loadArchive(id, this.$route.query.edit == 1);
    const typeKey = this.$route.query.type;
    if (id) this.loadArchive(id, typeKey, this.$route.query.edit == 1, this.$route.query.detailId);
  },
  methods: {
    loadArchive(id, autoEdit) {
    /**
     * 从身份证号解析出生日期 yyyy-MM-dd
     * 18 位:第 7-14 位是 yyyyMMdd;15 位老身份证:第 7-12 位是 yyMMdd,前面补 19
     * 格式不对或日期不存在(如 20260231)返回空
     */
    parseIdcardBirth(id) {
      if (!id) return "";
      const s = String(id).trim().toUpperCase();
      let y, m, d;
      if (/^\d{17}[\dX]$/.test(s)) {
        y = s.substring(6, 10); m = s.substring(10, 12); d = s.substring(12, 14);
      } else if (/^\d{15}$/.test(s)) {
        y = "19" + s.substring(6, 8); m = s.substring(8, 10); d = s.substring(10, 12);
      } else {
        return "";
      }
      const pad = (n) => String(n).padStart(2, "0");
      const dt = new Date(Number(y), Number(m) - 1, Number(d));
      if (isNaN(dt.getTime())) return "";
      // 拒绝 2 月 31 日这类不存在的日期
      if (dt.getFullYear() !== Number(y) || pad(dt.getMonth() + 1) !== m || pad(dt.getDate()) !== d) return "";
      return y + "-" + m + "-" + d;
    },
    /** 身份证合法时补齐出生日期与年龄,已经有值的字段不动 */
    fillBirthdayFromIdcard(id) {
      if (!this.archive) return;
      const birth = this.parseIdcardBirth(id);
      if (!birth) return;
      if (!this.archive.birthday) this.archive.birthday = birth;
      if (!this.archive.age) this.archive.age = calcAge(birth);
    },
    loadArchive(id, typeKey, autoEdit, detailId) {
      this.loading = true;
      this.archive = loadArchives().find((item) => item.id === id) || null;
      getArchive(typeKey, id, detailId)
        .then((archive) => {
          this.archive = archive || null;
      if (this.archive) {
        if (!this.archive.parentInfo) this.archive.parentInfo = {};
        if (this.archive.subType === 'highRisk') {
            if (this.archive.subType === 'highrisk') {
          this.activeTab = "growth";
          this.growthData = this.archive.growthData || getDefaultGrowthData();
          this.neuroData = this.archive.neuroData || getDefaultNeuroData();
@@ -258,20 +307,23 @@
          this.measureData = this.archive.measureData || getDefaultMeasureData();
          this.dietData = this.archive.dietData || getDefaultDietData();
          this.planData = this.archive.planData || getDefaultPlanData();
        } else if (this.archive.subType === 'learning' && this.archive.archiveForm?.learningData) {
            } else if (this.archive.subType === 'learning' && this.archive.archiveForm && this.archive.archiveForm.learningData) {
          Object.assign(this.form, this.archive.archiveForm.learningData);
        }
      }
      if (autoEdit) this.editing = true;
      this.loading = false;
        })
        .catch(() => { this.archive = null; })
        .finally(() => { this.loading = false; });
    },
    toggleEdit() {
      if (this.editing) {
        // 先把页面表单回填到档案对象,再整体提交
        if (this.archive.subType === 'learning') {
          if (!this.archive.archiveForm) this.archive.archiveForm = {};
          this.archive.archiveForm.learningData = JSON.parse(JSON.stringify(this.form));
        }
        if (this.archive.subType === 'highRisk') {
        if (this.archive.subType === 'highrisk') {
          this.archive.growthData = JSON.parse(JSON.stringify(this.growthData));
          this.archive.neuroData = JSON.parse(JSON.stringify(this.neuroData));
          this.archive.interventionData = JSON.parse(JSON.stringify(this.interventionData));
@@ -281,27 +333,31 @@
          this.archive.dietData = JSON.parse(JSON.stringify(this.dietData));
          this.archive.planData = JSON.parse(JSON.stringify(this.planData));
        }
        this.archive.updateTime = new Date().toISOString().replace("T"," ").substring(0,19);
        const all = loadArchives();
        const idx = all.findIndex(item => item.id === this.archive.id);
        if (idx >= 0) all[idx] = JSON.parse(JSON.stringify(this.archive));
        saveArchives(all);
        this.loading = true;
        saveArchive(this.archive)
          .then(() => {
        this.$message.success("保存成功");
            this.editing = false;
          })
          .catch(() => {})
          .finally(() => { this.loading = false; });
        return;
      }
      this.editing = !this.editing;
      this.editing = true;
    },
    handleCloseCase() {
      this.$modal.confirm("确认将该档案结案?").then(() => {
        this.loading = true;
        return closeArchive(this.archive)
          .then(() => {
        this.archive.closeStatus = 1;
        this.archive.updateTime = new Date().toISOString().replace("T"," ").substring(0,19);
        const all = loadArchives();
        const idx = all.findIndex(item => item.id === this.archive.id);
        if (idx >= 0) all[idx] = JSON.parse(JSON.stringify(this.archive));
        saveArchives(all);
        this.$message.success("已结案");
          })
          .catch(() => {})
          .finally(() => { this.loading = false; });
      }).catch(() => {});
    },
    subTypeTag(type) { const m={highRisk:"danger",nutrition:"warning",learning:"info"}; return m[type]||""; },
    subTypeTag(type) { const m={highrisk:"danger",nutrition:"warning",learning:"info"}; return m[type]||""; },
  },
};
@@ -340,7 +396,7 @@
<style lang="scss" scoped>
// 输入框宽度(按字段长短区分)
.w-xs { width: 90px; }
.w-xs { width: 120px; }
.w-sm { width: 150px; }
.w-md { width: 200px; }
.w-lg { width: 280px; }