WXL
10 小时以前 9d408b549b899631db29af772ee4e96f4c49a91c
相关推送
已修改10个文件
已添加11个文件
4902 ■■■■ 文件已修改
package.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/079.jpg!list1x.v2 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/yisn.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/yisna.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/logo/OPO_Logo.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/logo/OPO_Logo1.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/logo/logo.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/logo/logo1.png 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Navbar.vue 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/user.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/affirm/affirmInfo.vue 727 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/affirm/index.vue 428 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/affirm/mockConfirmationApi.js 174 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/assess/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/maintain/index.vue 484 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/maintain/maintainInfo.vue 878 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/maintain/mockMaintenanceApi.js 575 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/indexstatistics/index.vue 1582 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/register.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
vue.config.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json
@@ -1,7 +1,7 @@
{
  "name": "ruoyi",
  "version": "3.7.0",
  "description": "浙江省OPO数字化管理平台",
  "description": "青岛大学附属医院opo",
  "author": "浙江亥尔时信息科技有限公司",
  "license": "MIT",
  "scripts": {
src/assets/images/079.jpg!list1x.v2
Binary files differ
src/assets/images/yisn.jpg
src/assets/images/yisna.jpg
src/assets/logo/OPO_Logo.png

src/assets/logo/OPO_Logo1.png
src/assets/logo/logo.png

src/assets/logo/logo1.png
src/layout/components/Navbar.vue
@@ -45,7 +45,14 @@
        trigger="click"
      >
        <div class="avatar-wrapper">
          <img :src="avatar" class="user-avatar" />
          <img
            :src="
              sex == 1
                ? require('@/assets/images/yisn.jpg')
                : require('@/assets/images/yisna.jpg')
            "
            class="user-avatar"
          />
          <i class="el-icon-caret-bottom" />
        </div>
        <el-dropdown-menu slot="dropdown">
@@ -85,7 +92,7 @@
    SizeSelect,
    Search,
    RuoYiGit,
    RuoYiDoc,
    RuoYiDoc
  },
  computed: {
    ...mapGetters(["sidebar", "avatar", "device"]),
@@ -96,20 +103,21 @@
      set(val) {
        this.$store.dispatch("settings/changeSetting", {
          key: "showSettings",
          value: val,
          value: val
        });
      },
      }
    },
    topNav: {
      get() {
        return this.$store.state.settings.topNav;
      },
    },
      }
    }
  },
  data() {
    return {
      isBadgeHidden: true,
      badgeVal: 0,
      sex: this.$store.state.user.sex
    };
  },
  mounted() {
@@ -129,8 +137,7 @@
//     },
    clickMessage() {
      this.$router.push({
        path: "/message",
        path: "/message"
      });
    },
    toggleSideBar() {
@@ -140,7 +147,7 @@
      this.$confirm("确定注销并退出系统吗?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
        type: "warning"
      })
        .then(() => {
          this.$store.dispatch("LogOut").then(() => {
@@ -148,7 +155,7 @@
          });
        })
        .catch(() => {});
    },
    }
  },
  watch: {
    badgeVal: function () {
@@ -157,9 +164,9 @@
      },5000);
      this.$once("hook:beforeDestroy",()=>{
        clearInterval(timer);
      })
    },
  },
      });
    }
  }
};
</script>
<style lang="scss" >
src/store/modules/user.js
@@ -9,6 +9,7 @@
  state: {
    token: getToken(),
    name: '',
    sex:'',
    avatar: '',
    code: '',
    msg: '',
@@ -31,6 +32,9 @@
    },
    SET_NAME: (state, name) => {
      state.name = name
    },
    SET_SEX: (state, sex) => {
      state.sex = sex
    },
    SET_AVATAR: (state, avatar) => {
      state.avatar = avatar
@@ -93,6 +97,7 @@
            commit('SET_ROLES', ['ROLE_DEFAULT'])
          }
          commit('SET_NAME', user.userName)
          commit('SET_SEX', user.sex)
          commit('SET_ROLESor', user.roles)
          commit('SET_AVATAR', avatar)
          resolve(res)
src/views/business/affirm/affirmInfo.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,727 @@
<template>
  <div class="confirmation-detail">
    <el-card class="detail-card">
      <!-- åŸºç¡€ä¿¡æ¯ -->
      <div slot="header" class="clearfix">
        <span class="detail-title">捐献确认基本信息</span>
        <el-button
          v-if="$route.query.confirm"
          type="primary"
          style="float: right; padding: 3px 0"
          @click="handleSave"
        >
          ä¿å­˜ç¡®è®¤ä¿¡æ¯
        </el-button>
      </div>
      <el-form :model="form" ref="form" label-width="120px">
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="案例编号" prop="caseNo">
              <el-input v-model="form.caseNo" :readonly="!isEdit" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="捐献者姓名" prop="donorName">
              <el-input v-model="form.donorName" :readonly="!isEdit" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="性别" prop="gender">
              <el-select
                v-model="form.gender"
                :disabled="!isEdit"
                style="width: 100%"
              >
                <el-option label="男" value="0" />
                <el-option label="女" value="1" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="年龄" prop="age">
              <el-input v-model="form.age" :readonly="!isEdit" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="疾病诊断" prop="diagnosis">
              <el-input v-model="form.diagnosis" :readonly="!isEdit" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="所在医疗机构" prop="hospitalName">
              <el-input v-model="form.hospitalName" :readonly="!isEdit" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="协调员1" prop="coordinator1">
              <el-input v-model="form.coordinator1" :readonly="!isEdit" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="协调员2" prop="coordinator2">
              <el-input v-model="form.coordinator2" :readonly="!isEdit" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="业务人员" prop="assignee">
              <el-input v-model="form.assignee" :readonly="!isEdit" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="确认状态" prop="confirmationStatus">
              <el-select
                v-model="form.confirmationStatus"
                :disabled="!isEdit"
                style="width: 100%"
              >
                <el-option label="未确认" value="0" />
                <el-option label="家属确认" value="1" />
                <el-option label="不同意捐献" value="2" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="确认时间" prop="confirmationTime">
              <el-date-picker
                v-model="form.confirmationTime"
                type="datetime"
                value-format="yyyy-MM-dd HH:mm:ss"
                style="width: 100%"
                :disabled="!isEdit"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-form-item label="家属意见备注" prop="familyRemark">
          <el-input
            type="textarea"
            :rows="3"
            v-model="form.familyRemark"
            :readonly="!isEdit"
            placeholder="记录家属的意见和沟通情况"
          />
        </el-form-item>
      </el-form>
    </el-card>
    <!-- é™„件列表 -->
    <el-card class="attachment-card">
      <div slot="header" class="clearfix">
        <span class="detail-title">相关附件上传</span>
        <el-button
          v-if="isEdit"
          type="primary"
          size="mini"
          @click="handleSaveAll"
          :loading="saveLoading"
        >
          ä¿å­˜æ‰€æœ‰é™„ä»¶
        </el-button>
      </div>
      <!-- é™„件类型选项卡 -->
      <el-tabs v-model="activeAttachmentType" type="card">
        <el-tab-pane
          v-for="type in attachmentTypes"
          :key="type.value"
          :label="type.label"
          :name="type.value"
        >
          <div class="attachment-upload-section">
            <div class="upload-header">
              <span class="upload-title">{{ type.label }}</span>
              <el-tooltip content="点击上传该类型附件" placement="top">
                <el-button
                  size="mini"
                  type="primary"
                  icon="el-icon-plus"
                  @click="openUploadDialog(type.value)"
                  :disabled="!isEdit"
                >
                  æ·»åР附件
                </el-button>
              </el-tooltip>
            </div>
            <!-- é™„件列表 -->
            <el-table
              :data="getAttachmentsByType(type.value)"
              v-loading="attachmentLoading"
              style="width: 100%; margin-top: 15px;"
            >
              <el-table-column label="文件名称" min-width="200">
                <template slot-scope="scope">
                  <div class="file-info">
                    <i
                      class="el-icon-document"
                      style="margin-right: 8px; color: #409EFF;"
                    ></i>
                    <span>{{ scope.row.fileName }}</span>
                  </div>
                </template>
              </el-table-column>
              <el-table-column label="文件大小" width="100" align="center">
                <template slot-scope="scope">
                  <span>{{ formatFileSize(scope.row.fileSize) }}</span>
                </template>
              </el-table-column>
              <el-table-column label="上传时间" width="160" align="center">
                <template slot-scope="scope">
                  <span>{{ parseTime(scope.row.uploadTime) }}</span>
                </template>
              </el-table-column>
              <el-table-column label="上传人" width="100" align="center">
                <template slot-scope="scope">
                  <span>{{ scope.row.uploader }}</span>
                </template>
              </el-table-column>
              <el-table-column
                label="操作"
                width="120"
                align="center"
                v-if="isEdit"
              >
                <template slot-scope="scope">
                  <el-button
                    size="mini"
                    type="text"
                    icon="el-icon-view"
                    @click="handlePreview(scope.row)"
                    >预览</el-button
                  >
                  <el-button
                    size="mini"
                    type="text"
                    icon="el-icon-delete"
                    style="color: #F56C6C;"
                    @click="handleRemoveAttachment(scope.row, type.value)"
                    >删除</el-button
                  >
                </template>
              </el-table-column>
              <el-table-column label="操作" width="80" align="center" v-else>
                <template slot-scope="scope">
                  <el-button
                    size="mini"
                    type="text"
                    icon="el-icon-view"
                    @click="handlePreview(scope.row)"
                    >预览</el-button
                  >
                </template>
              </el-table-column>
            </el-table>
            <div
              v-if="getAttachmentsByType(type.value).length === 0"
              class="empty-attachment"
            >
              <el-empty description="暂无附件" :image-size="80"></el-empty>
            </div>
          </div>
        </el-tab-pane>
      </el-tabs>
    </el-card>
    <el-dialog
      :title="`上传${getCurrentTypeLabel}附件`"
      :visible.sync="uploadDialogVisible"
      width="500px"
      :close-on-click-modal="false"
    >
      <el-upload
        ref="uploadRef"
        class="upload-demo"
        drag
        action="#"
        multiple
        :file-list="tempFileList"
        :before-upload="beforeUpload"
        :on-change="handleFileChange"
        :on-remove="handleTempRemove"
        :auto-upload="false"
        :http-request="handleHttpRequest"
      >
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
        <div class="el-upload__tip" slot="tip">
          æ”¯æŒä¸Šä¼ pdf、jpg、png、doc、docx格式文件,单个文件不超过10MB
        </div>
      </el-upload>
      <span slot="footer" class="dialog-footer">
        <el-button @click="uploadDialogVisible = false">取消</el-button>
        <el-button
          type="primary"
          @click="submitUpload"
          :loading="uploadLoading"
          :disabled="tempFileList.length === 0"
        >
          ç¡®è®¤ä¸Šä¼ 
        </el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
import {
  getConfirmationDetail,
  updateConfirmation
} from "./mockConfirmationApi";
export default {
  name: "ConfirmationDetail",
  data() {
    return {
      // æ˜¯å¦ç¼–辑模式
      isEdit: false,
      // è¡¨å•数据
      form: {
        id: undefined,
        caseNo: "",
        donorName: "",
        gender: "",
        age: "",
        diagnosis: "",
        hospitalName: "",
        coordinator1: "",
        coordinator2: "",
        assignee: "",
        confirmationStatus: "0",
        confirmationTime: "",
        familyRemark: ""
      },
      // é™„件列表
      // é™„件相关数据
      activeAttachmentType: "1",
      attachmentLoading: false,
      uploadDialogVisible: false,
      uploadLoading: false,
      saveLoading: false,
      tempFileList: [],
      currentUploadType: "",
      // é™„件类型定义
      attachmentTypes: [
        { value: "1", label: "人体器官潜在捐献者登记表" },
        { value: "2", label: "人体器官捐献亲属确认登记表" },
        { value: "3", label: "捐献者及直系亲属身份证、户口簿相关证明" },
        { value: "4", label: "公民身故后人体器官(角膜)遗体捐献告知书" },
        { value: "5", label: "脑死亡判定知情同意书" },
        { value: "6", label: "心死亡判定知情同意书" }
      ],
      // é™„件列表数据
      attachmentList: [
        // æ¨¡æ‹Ÿæ•°æ® - å®žé™…项目中从接口获取
        {
          id: 1,
          type: "1",
          typeName: "人体器官潜在捐献者登记表",
          fileName: "潜在捐献者登记表_202312001.pdf",
          fileSize: 2548321,
          uploadTime: "2023-12-01 10:30:00",
          uploader: "张三",
          fileUrl: "/attachments/1.pdf"
        },
        {
          id: 2,
          type: "1",
          typeName: "人体器官潜在捐献者登记表",
          fileName: "补充说明.docx",
          fileSize: 512345,
          uploadTime: "2023-12-01 14:20:00",
          uploader: "李四",
          fileUrl: "/attachments/2.docx"
        }
      ]
    };
  },
  computed: {
    isEdit() {
      return this.$route.query.confirm === "true";
    },
    getCurrentTypeLabel() {
      const type = this.attachmentTypes.find(
        t => t.value === this.currentUploadType
      );
      return type ? type.label : "";
    }
  },
  created() {
    const id = this.$route.query.id;
    this.isEdit = this.$route.query.confirm === "true";
    if (id) {
      this.getDetail(id);
    }
    this.getAttachmentList();
  },
  methods: {
    // èŽ·å–è¯¦æƒ…
    getDetail(id) {
      getConfirmationDetail(id).then(response => {
        if (response.code === 200) {
          this.form = response.data;
        }
      });
    },
    // èŽ·å–é™„ä»¶åˆ—è¡¨
    getAttachmentList() {
      this.attachmentLoading = true;
      // æ¨¡æ‹Ÿé™„件数据
      this.attachmentList = [
        {
          id: 1,
          type: "1",
          typeName: "人体器官潜在捐献者登记表",
          fileName: "潜在捐献者登记表_202312001.pdf",
          uploadTime: "2023-12-01 10:30:00",
          uploader: "张三",
          fileSize: "2.5MB",
          fileUrl: "/attachments/1.pdf"
        },
        {
          id: 2,
          type: "2",
          typeName: "人体器官捐献亲属确认登记表",
          fileName: "亲属确认登记表_202312001.pdf",
          uploadTime: "2023-12-01 14:20:00",
          uploader: "李四",
          fileSize: "1.8MB",
          fileUrl: "/attachments/2.pdf"
        },
        {
          id: 3,
          type: "3",
          typeName: "捐献者及直系亲属身份证、户口簿相关证明",
          fileName: "身份证明_202312001.zip",
          uploadTime: "2023-12-01 16:45:00",
          uploader: "王五",
          fileSize: "5.2MB",
          fileUrl: "/attachments/3.zip"
        },
        {
          id: 4,
          type: "4",
          typeName: "公民身故后人体器官(角膜)遗体捐献告知书",
          fileName: "捐献告知书_202312001.pdf",
          uploadTime: "2023-12-02 09:15:00",
          uploader: "张三",
          fileSize: "1.2MB",
          fileUrl: "/attachments/4.pdf"
        },
        {
          id: 5,
          type: "5",
          typeName: "脑死亡判定知情同意书",
          fileName: "脑死亡判定同意书_202312001.pdf",
          uploadTime: "2023-12-02 11:30:00",
          uploader: "李四",
          fileSize: "0.8MB",
          fileUrl: "/attachments/5.pdf"
        },
        {
          id: 6,
          type: "6",
          typeName: "心死亡判定知情同意书",
          fileName: "心死亡判定同意书_202312001.pdf",
          uploadTime: "2023-12-02 13:20:00",
          uploader: "王五",
          fileSize: "0.9MB",
          fileUrl: "/attachments/6.pdf"
        }
      ];
      this.attachmentLoading = false;
    },
    // ä¸‹è½½é™„ä»¶
    handleDownload(row) {
      // å®žé™…项目中这里调用文件下载接口
      this.$message.success(`下载文件: ${row.fileName}`);
      console.log("下载文件:", row.fileUrl);
    },
    // ä¿å­˜ç¡®è®¤ä¿¡æ¯
    handleSave() {
      this.$refs.form.validate(valid => {
        if (valid) {
          updateConfirmation(this.form).then(response => {
            if (response.code === 200) {
              this.$message.success("保存成功");
              this.isEdit = false;
              this.$router.push("/case/confirmation");
            }
          });
        }
      });
    },
 // æ ¹æ®ç±»åž‹èŽ·å–é™„ä»¶
    getAttachmentsByType(type) {
      return this.attachmentList.filter(item => item.type === type);
    },
    // æ‰“开上传对话框
    openUploadDialog(type) {
      this.currentUploadType = type;
      this.tempFileList = [];
      this.uploadDialogVisible = true;
      this.$nextTick(() => {
        if (this.$refs.uploadRef) {
          this.$refs.uploadRef.clearFiles();
        }
      });
    },
    // ä¸Šä¼ å‰æ ¡éªŒ
    beforeUpload(file) {
      const allowedTypes = [
        'application/pdf',
        'image/jpeg',
        'image/png',
        'application/msword',
        'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
      ];
      const maxSize = 10 * 1024 * 1024; // 10MB
      // æ ¡éªŒæ–‡ä»¶ç±»åž‹
      const isTypeOk = allowedTypes.includes(file.type) ||
                      file.name.endsWith('.pdf') ||
                      file.name.endsWith('.jpg') ||
                      file.name.endsWith('.jpeg') ||
                      file.name.endsWith('.png') ||
                      file.name.endsWith('.doc') ||
                      file.name.endsWith('.docx');
      if (!isTypeOk) {
        this.$message.error('文件格式不支持,请上传pdf、jpg、png、doc或docx格式文件');
        return false;
      }
      // æ ¡éªŒæ–‡ä»¶å¤§å°
      if (file.size > maxSize) {
        this.$message.error('文件大小不能超过10MB');
        return false;
      }
      return true;
    },
    // æ–‡ä»¶é€‰æ‹©å˜åŒ–
    handleFileChange(file, fileList) {
      this.tempFileList = fileList;
    },
    // ç§»é™¤ä¸´æ—¶æ–‡ä»¶
    handleTempRemove(file, fileList) {
      this.tempFileList = fileList;
    },
    // è‡ªå®šä¹‰ä¸Šä¼ è¯·æ±‚
    handleHttpRequest(options) {
      // æ¨¡æ‹Ÿä¸Šä¼ è¿‡ç¨‹
      return new Promise((resolve, reject) => {
        this.uploadLoading = true;
        // æ¨¡æ‹Ÿä¸Šä¼ å»¶è¿Ÿ
        setTimeout(() => {
          const newAttachment = {
            id: Date.now(),
            type: this.currentUploadType,
            typeName: this.getCurrentTypeLabel,
            fileName: options.file.name,
            fileSize: options.file.size,
            uploadTime: new Date().toISOString(),
            uploader: '当前用户', // å®žé™…项目中从用户信息获取
            fileUrl: URL.createObjectURL(options.file) // ä¸´æ—¶URL,实际项目中为服务器返回的URL
          };
          this.attachmentList.push(newAttachment);
          this.uploadLoading = false;
          resolve({ code: 200, data: newAttachment });
        }, 1500);
      });
    },
    // æäº¤ä¸Šä¼ 
    async submitUpload() {
      if (this.tempFileList.length === 0) {
        this.$message.warning('请先选择要上传的文件');
        return;
      }
      try {
        // ä¾æ¬¡ä¸Šä¼ æ‰€æœ‰æ–‡ä»¶
        for (const file of this.tempFileList) {
          await this.$refs.uploadRef.submit();
        }
        this.$message.success('文件上传成功');
        this.uploadDialogVisible = false;
        this.tempFileList = [];
      } catch (error) {
        this.$message.error('文件上传失败');
        console.error('上传失败:', error);
      }
    },
    // åˆ é™¤é™„ä»¶
    handleRemoveAttachment(attachment, type) {
      this.$confirm('确定要删除这个附件吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        const index = this.attachmentList.findIndex(item => item.id === attachment.id);
        if (index !== -1) {
          this.attachmentList.splice(index, 1);
          this.$message.success('附件删除成功');
          // å®žé™…项目中调用删除接口
          // this.deleteAttachment(attachment.id);
        }
      }).catch(() => {});
    },
    // é¢„览附件
    handlePreview(attachment) {
      // å®žé™…项目中根据文件类型调用不同的预览方式
      if (attachment.fileName.endsWith('.pdf')) {
        // PDF预览
        window.open(attachment.fileUrl, '_blank');
      } else if (attachment.fileName.match(/\.(jpg|jpeg|png)$/i)) {
        // å›¾ç‰‡é¢„览
        this.$alert(`<img src="${attachment.fileUrl}" style="max-width: 100%;" alt="${attachment.fileName}">`,
          '图片预览', {
            dangerouslyUseHTMLString: true,
            customClass: 'image-preview-dialog'
          });
      } else {
        // å…¶ä»–文件类型提示下载
        this.$message.info('该文件类型暂不支持在线预览,请下载后查看');
      }
    },
    // ä¿å­˜æ‰€æœ‰é™„件信息
    handleSaveAll() {
      this.saveLoading = true;
      // æ¨¡æ‹Ÿä¿å­˜è¿‡ç¨‹
      setTimeout(() => {
        this.$message.success('附件信息保存成功');
        this.saveLoading = false;
        // å®žé™…项目中调用保存接口
        // this.saveAttachments();
      }, 1000);
    },
    // æ–‡ä»¶å¤§å°æ ¼å¼åŒ–
    formatFileSize(size) {
      if (size === 0) return '0 B';
      const k = 1024;
      const sizes = ['B', 'KB', 'MB', 'GB'];
      const i = Math.floor(Math.log(size) / Math.log(k));
      return parseFloat((size / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
    },
    // æ—¶é—´æ ¼å¼åŒ–
    parseTime(time) {
      if (!time) return '';
      const date = new Date(time);
      return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
    }
  }
};
</script>
<style scoped>
.confirmation-detail {
  padding: 20px;
}
.detail-card {
  margin-bottom: 20px;
}
.attachment-card {
  margin-bottom: 20px;
}
.detail-title {
  font-size: 16px;
  font-weight: bold;
}
.fixed-width .el-button {
  margin: 0 5px;
}
.confirmation-detail {
  padding: 20px;
}
.detail-card {
  margin-bottom: 20px;
}
.attachment-card {
  margin-bottom: 20px;
}
.detail-title {
  font-size: 16px;
  font-weight: bold;
}
.attachment-upload-section {
  padding: 10px;
}
.upload-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 15px;
}
.upload-title {
  font-size: 14px;
  font-weight: 600;
  color: #303133;
}
.file-info {
  display: flex;
  align-items: center;
}
.empty-attachment {
  text-align: center;
  padding: 40px 0;
  color: #909399;
}
/* å›¾ç‰‡é¢„览对话框样式 */
:deep(.image-preview-dialog) {
  width: auto;
  max-width: 90vw;
}
:deep(.image-preview-dialog .el-message-box__content) {
  text-align: center;
}
</style>
src/views/business/affirm/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,428 @@
<template>
  <div class="confirmation-list">
    <!-- æŸ¥è¯¢æ¡ä»¶ -->
    <el-card class="search-card">
      <el-form
        :model="queryParams"
        ref="queryForm"
        :inline="true"
        label-width="100px"
      >
        <el-form-item label="捐献者姓名" prop="donorName">
          <el-input
            v-model="queryParams.donorName"
            placeholder="请输入捐献者姓名"
            clearable
            style="width: 200px"
            @keyup.enter.native="handleQuery"
          />
        </el-form-item>
        <el-form-item label="所在医疗机构" prop="hospitalName">
          <el-input
            v-model="queryParams.hospitalName"
            placeholder="请输入医疗机构"
            clearable
            style="width: 200px"
            @keyup.enter.native="handleQuery"
          />
        </el-form-item>
        <el-form-item label="业务人员" prop="assignee">
          <el-input
            v-model="queryParams.assignee"
            placeholder="请输入业务人员"
            clearable
            style="width: 200px"
            @keyup.enter.native="handleQuery"
          />
        </el-form-item>
        <el-form-item label="确认状态" prop="confirmationStatus">
          <el-select
            v-model="queryParams.confirmationStatus"
            placeholder="请选择确认状态"
            clearable
            style="width: 200px"
          >
            <el-option label="未确认" value="0" />
            <el-option label="家属确认" value="1" />
            <el-option label="不同意捐献" value="2" />
          </el-select>
        </el-form-item>
        <el-form-item label="确认时间" prop="confirmationTimeRange">
          <el-date-picker
            v-model="queryParams.confirmationTimeRange"
            type="daterange"
            range-separator="至"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            value-format="yyyy-MM-dd"
            style="width: 240px"
          />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" icon="el-icon-search" @click="handleQuery"
            >搜索</el-button
          >
          <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
        </el-form-item>
      </el-form>
    </el-card>
    <!-- æ“ä½œæŒ‰é’® -->
    <el-card class="tool-card">
      <el-row :gutter="10">
        <el-col :span="16">
          <el-button type="primary" icon="el-icon-plus" @click="handleCreate"
            >新增确认</el-button
          >
          <el-button
            type="success"
            icon="el-icon-edit"
            :disabled="single"
            @click="handleUpdate"
            >修改</el-button
          >
          <el-button
            type="danger"
            icon="el-icon-delete"
            :disabled="multiple"
            @click="handleDelete"
            >删除</el-button
          >
          <el-button
            type="warning"
            icon="el-icon-download"
            @click="handleExport"
            >导出</el-button
          >
        </el-col>
        <el-col :span="8" style="text-align: right">
          <el-tooltip content="刷新" placement="top">
            <el-button icon="el-icon-refresh" circle @click="getList" />
          </el-tooltip>
        </el-col>
      </el-row>
    </el-card>
    <!-- æ•°æ®è¡¨æ ¼ -->
    <el-card>
      <el-table
        v-loading="loading"
        :data="confirmationList"
        @selection-change="handleSelectionChange"
        @row-click="handleRowClick"
      >
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column
          label="案例编号"
          align="center"
          prop="caseNo"
          width="120"
        />
        <el-table-column
          label="潜在捐献者姓名"
          align="center"
          prop="donorName"
          width="120"
        />
        <el-table-column label="性别" align="center" prop="gender" width="80">
          <template slot-scope="scope">
            <dict-tag
              :options="dict.type.sys_user_sex"
              :value="parseInt(scope.row.gender)"
            />
          </template>
        </el-table-column>
        <el-table-column label="年龄" align="center" prop="age" width="80" />
        <el-table-column
          label="疾病诊断"
          align="center"
          prop="diagnosis"
          min-width="180"
          show-overflow-tooltip
        />
        <el-table-column
          label="所在医疗机构"
          align="center"
          prop="hospitalName"
          width="150"
          show-overflow-tooltip
        />
        <el-table-column
          label="确认状态"
          align="center"
          prop="confirmationStatus"
          width="120"
        >
          <template slot-scope="scope">
            <el-tag :type="statusFilter(scope.row.confirmationStatus)">
              {{ statusTextFilter(scope.row.confirmationStatus) }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column
          label="确认时间"
          align="center"
          prop="confirmationTime"
          width="120"
        >
          <template slot-scope="scope">
            <span>{{
              scope.row.confirmationTime
                ? parseTime(scope.row.confirmationTime, "{y}-{m}-{d}")
                : "-"
            }}</span>
          </template>
        </el-table-column>
        <el-table-column
          label="业务人员"
          align="center"
          prop="assignee"
          width="100"
        />
        <el-table-column
          label="协调员1"
          align="center"
          prop="coordinator1"
          width="100"
        />
        <el-table-column
          label="协调员2"
          align="center"
          prop="coordinator2"
          width="100"
        />
        <el-table-column
          label="操作"
          align="center"
          width="120"
          class-name="small-padding fixed-width"
        >
          <template slot-scope="scope">
            <el-button
              size="mini"
              type="text"
              icon="el-icon-view"
              @click.stop="handleView(scope.row)"
              >详情</el-button
            >
            <el-button
              v-if="scope.row.confirmationStatus === '0'"
              size="mini"
              type="text"
              icon="el-icon-edit"
              @click.stop="handleConfirm(scope.row)"
              >确认</el-button
            >
          </template>
        </el-table-column>
      </el-table>
      <!-- åˆ†é¡µç»„ä»¶ -->
      <pagination
        v-show="total > 0"
        :total="total"
        :page.sync="queryParams.pageNum"
        :limit.sync="queryParams.pageSize"
        @pagination="getList"
      />
    </el-card>
  </div>
</template>
<script>
import { listConfirmation, delConfirmation, exportConfirmation } from "./mockConfirmationApi";
import Pagination from "@/components/Pagination";
export default {
  name: "ConfirmationList",
  components: { Pagination },
  dicts: ["sys_user_sex"],
  data() {
    return {
      // é®ç½©å±‚
      loading: true,
      // é€‰ä¸­æ•°ç»„
      ids: [],
      // éžå•个禁用
      single: true,
      // éžå¤šä¸ªç¦ç”¨
      multiple: true,
      // æ€»æ¡æ•°
      total: 0,
      // æçŒ®ç¡®è®¤è¡¨æ ¼æ•°æ®
      confirmationList: [],
      // æŸ¥è¯¢å‚æ•°
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        donorName: undefined,
        hospitalName: undefined,
        assignee: undefined,
        confirmationStatus: undefined,
        confirmationTimeRange: []
      }
    };
  },
  created() {
    this.getList();
  },
  methods: {
    // çŠ¶æ€è¿‡æ»¤å™¨
    statusFilter(status) {
      const statusMap = {
        "0": "warning", // æœªç¡®è®¤
        "1": "success", // å®¶å±žç¡®è®¤
        "2": "danger" // ä¸åŒæ„æçŒ®
      };
      return statusMap[status] || "info";
    },
    statusTextFilter(status) {
      const statusMap = {
        "0": "未确认",
        "1": "家属确认",
        "2": "不同意捐献"
      };
      return statusMap[status] || "未知";
    },
    // æŸ¥è¯¢æçŒ®ç¡®è®¤åˆ—表
    getList() {
      this.loading = true;
      listConfirmation(this.queryParams)
        .then(response => {
          if (response.code === 200) {
            this.confirmationList = response.data.rows;
            this.total = response.data.total;
          } else {
            this.$message.error("获取数据失败");
          }
          this.loading = false;
        })
        .catch(error => {
          console.error("获取捐献确认列表失败:", error);
          this.loading = false;
          this.$message.error("获取数据失败");
        });
    },
    // æœç´¢æŒ‰é’®æ“ä½œ
    handleQuery() {
      this.queryParams.pageNum = 1;
      this.getList();
    },
    // é‡ç½®æŒ‰é’®æ“ä½œ
    resetQuery() {
      this.$refs.queryForm.resetFields();
      this.handleQuery();
    },
    // å¤šé€‰æ¡†é€‰ä¸­æ•°æ®
    handleSelectionChange(selection) {
      this.ids = selection.map(item => item.id);
      this.single = selection.length !== 1;
      this.multiple = !selection.length;
    },
    // è¡Œç‚¹å‡»äº‹ä»¶
    handleRowClick(row) {
      this.$router.push({
        path: "/case/affirmInfo",
        query: { id: row.id }
      });
    },
    // æŸ¥çœ‹è¯¦æƒ…
    handleView(row) {
      this.$router.push({
        path: "/case/affirmInfo",
        query: { id: row.id }
      });
    },
    // ç¡®è®¤æ“ä½œ
    handleConfirm(row) {
      this.$router.push({
        path: "/case/affirmInfo",
        query: { id: row.id, confirm: true }
      });
    },
    // æ–°å¢žæŒ‰é’®æ“ä½œ
    handleCreate() {
      this.$router.push("/case/confirmation/add");
    },
    // ä¿®æ”¹æŒ‰é’®æ“ä½œ
    handleUpdate() {
      const id = this.ids[0];
      this.$router.push({
        path: "/case/confirmation/edit",
        query: { id: id }
      });
    },
    // åˆ é™¤æŒ‰é’®æ“ä½œ
    handleDelete() {
      const ids = this.ids;
      this.$confirm("是否确认删除选中的数据项?", "警告", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      })
        .then(() => {
          return delConfirmation(ids);
        })
        .then(response => {
          if (response.code === 200) {
            this.$message.success("删除成功");
            this.getList();
          }
        })
        .catch(() => {});
    },
    // å¯¼å‡ºæŒ‰é’®æ“ä½œ
    handleExport() {
      const queryParams = this.queryParams;
      this.$confirm("是否确认导出所有确认数据?", "警告", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      })
        .then(() => {
          this.loading = true;
          return exportConfirmation(queryParams);
        })
        .then(response => {
          if (response.code === 200) {
            this.$message.success("导出成功");
            // å®žé™…项目中这里处理文件下载
          }
          this.loading = false;
        })
        .catch(() => {
          this.loading = false;
        });
    },
    // æ—¶é—´æ ¼å¼åŒ–
    parseTime(time, pattern) {
      if (!time) return "";
      const date = new Date(time);
      return `${date.getFullYear()}-${(date.getMonth() + 1)
        .toString()
        .padStart(2, "0")}-${date
        .getDate()
        .toString()
        .padStart(2, "0")}`;
    }
  }
};
</script>
<style scoped>
.confirmation-list {
  padding: 20px;
}
.search-card {
  margin-bottom: 20px;
}
.tool-card {
  margin-bottom: 20px;
}
.fixed-width .el-button {
  margin: 0 5px;
}
</style>
src/views/business/affirm/mockConfirmationApi.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,174 @@
// æ¨¡æ‹ŸæçŒ®ç¡®è®¤API
const confirmationData = {
  rows: [
    {
      id: 1,
      caseNo: 'QJ202312001',
      donorName: '张某某',
      gender: '0',
      age: '45',
      diagnosis: '重型颅脑损伤',
      hospitalName: '北京市第一人民医院',
      confirmationStatus: '0',
      confirmationTime: '',
      assignee: '王医生',
      coordinator1: '协调员A',
      coordinator2: '协调员B',
      familyRemark: ''
    },
    {
      id: 2,
      caseNo: 'QJ202312002',
      donorName: '李某某',
      gender: '1',
      age: '32',
      diagnosis: '脑出血',
      hospitalName: '上海市中心医院',
      confirmationStatus: '1',
      confirmationTime: '2023-12-01 14:30:00',
      assignee: '李医生',
      coordinator1: '协调员C',
      coordinator2: '协调员D',
      familyRemark: '家属同意捐献,已签署相关文件'
    },
    {
      id: 3,
      caseNo: 'QJ202312003',
      donorName: '王某某',
      gender: '0',
      age: '58',
      diagnosis: '心脏骤停后脑损伤',
      hospitalName: '广州市人民医院',
      confirmationStatus: '2',
      confirmationTime: '2023-12-02 10:15:00',
      assignee: '张医生',
      coordinator1: '协调员E',
      coordinator2: '协调员F',
      familyRemark: '家属经考虑后决定不同意捐献'
    }
  ],
  total: 3
};
// èŽ·å–æçŒ®ç¡®è®¤åˆ—è¡¨
export function listConfirmation(params) {
  return new Promise((resolve) => {
    setTimeout(() => {
      const { pageNum, pageSize, donorName, hospitalName, confirmationStatus } = params;
      let filteredData = confirmationData.rows;
      // æ¨¡æ‹Ÿç­›é€‰
      if (donorName) {
        filteredData = filteredData.filter(item =>
          item.donorName.includes(donorName)
        );
      }
      if (hospitalName) {
        filteredData = filteredData.filter(item =>
          item.hospitalName.includes(hospitalName)
        );
      }
      if (confirmationStatus) {
        filteredData = filteredData.filter(item =>
          item.confirmationStatus === confirmationStatus
        );
      }
      const start = (pageNum - 1) * pageSize;
      const end = start + pageSize;
      const pageData = filteredData.slice(start, end);
      resolve({
        code: 200,
        data: {
          rows: pageData,
          total: filteredData.length
        }
      });
    }, 500);
  });
}
// èŽ·å–æçŒ®ç¡®è®¤è¯¦æƒ…
export function getConfirmationDetail(id) {
  return new Promise((resolve) => {
    setTimeout(() => {
      const detail = confirmationData.rows.find(item => item.id == id);
      resolve({
        code: 200,
        data: detail || {}
      });
    }, 300);
  });
}
// æ›´æ–°æçŒ®ç¡®è®¤ä¿¡æ¯
export function updateConfirmation(data) {
  return new Promise((resolve) => {
    setTimeout(() => {
      const index = confirmationData.rows.findIndex(item => item.id === data.id);
      if (index !== -1) {
        confirmationData.rows[index] = { ...confirmationData.rows[index], ...data };
      }
      resolve({ code: 200, message: '更新成功' });
    }, 300);
  });
}
// åˆ é™¤æçŒ®ç¡®è®¤
export function delConfirmation(ids) {
  return new Promise((resolve) => {
    setTimeout(() => {
      confirmationData.rows = confirmationData.rows.filter(
        item => !ids.includes(item.id)
      );
      confirmationData.total = confirmationData.rows.length;
      resolve({ code: 200, message: '删除成功' });
    }, 300);
  });
}
// å¯¼å‡ºæçŒ®ç¡®è®¤æ•°æ®
export function exportConfirmation(params) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        code: 200,
        data: {
          downloadUrl: '/download/confirmation_export.xlsx'
        },
        message: '导出成功'
      });
    }, 1000);
  });
}
// é™„件相关API接口
export const attachmentApi = {
  // èŽ·å–æ¡ˆä¾‹é™„ä»¶åˆ—è¡¨
  getAttachments(caseId) {
    return request.get(`/api/attachments/case/${caseId}`);
  },
  // ä¸Šä¼ é™„ä»¶
  uploadAttachment(data) {
    const formData = new FormData();
    formData.append('file', data.file);
    formData.append('caseId', data.caseId);
    formData.append('type', data.type);
    return request.post('/api/attachments/upload', formData, {
      headers: { 'Content-Type': 'multipart/form-data' }
    });
  },
  // åˆ é™¤é™„ä»¶
  deleteAttachment(attachmentId) {
    return request.delete(`/api/attachments/${attachmentId}`);
  },
  // æ‰¹é‡ä¿å­˜é™„件信息
  saveAttachments(attachments) {
    return request.post('/api/attachments/batch-save', attachments);
  }
};
src/views/business/assess/index.vue
@@ -376,18 +376,18 @@
    // è¡Œç‚¹å‡»äº‹ä»¶
    handleRowClick(row) {
      this.$router.push({
        path: "/case/assessment/detail",
        path: "/case/assessInfo",
        query: { id: row.id }
      });
    },
    // æŸ¥çœ‹è¯¦æƒ…
    handleView(row) {
      this.$router.push({ path: "/organ/assessInfo", query: { id: row.id } });
      this.$router.push({ path: "/case/assessInfo", query: { id: row.id } });
    },
    // è¿›è¡Œè¯„ä¼°
    handleAssess(row) {
      this.$router.push({
        path: "/case/assessment/detail",
        path: "/case/assessInfo",
        query: { id: row.id, assess: true }
      });
    },
src/views/business/maintain/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,484 @@
<template>
  <div class="maintenance-list">
    <!-- æŸ¥è¯¢æ¡ä»¶ -->
    <el-card class="search-card">
      <el-form
        :model="queryParams"
        ref="queryForm"
        :inline="true"
        label-width="100px"
      >
        <el-form-item label="捐献者姓名" prop="donorName">
          <el-input
            v-model="queryParams.donorName"
            placeholder="请输入捐献者姓名"
            clearable
            style="width: 200px"
            @keyup.enter.native="handleQuery"
          />
        </el-form-item>
        <el-form-item label="所在医疗机构" prop="hospitalName">
          <el-input
            v-model="queryParams.hospitalName"
            placeholder="请输入医疗机构"
            clearable
            style="width: 200px"
            @keyup.enter.native="handleQuery"
          />
        </el-form-item>
        <el-form-item label="医疗组人员" prop="medicalStaff">
          <el-input
            v-model="queryParams.medicalStaff"
            placeholder="请输入医疗组人员"
            clearable
            style="width: 200px"
            @keyup.enter.native="handleQuery"
          />
        </el-form-item>
        <el-form-item label="患者状态" prop="patientStatus">
          <el-select
            v-model="queryParams.patientStatus"
            placeholder="请选择患者状态"
            clearable
            style="width: 200px"
          >
            <el-option label="DCD" value="1" />
            <el-option label="DBD" value="2" />
            <el-option label="DBCD" value="3" />
            <el-option label="已完成捐献" value="4" />
            <el-option label="未完成捐献" value="5" />
          </el-select>
        </el-form-item>
        <el-form-item label="录入时间" prop="recordTimeRange">
          <el-date-picker
            v-model="queryParams.recordTimeRange"
            type="daterange"
            range-separator="至"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            value-format="yyyy-MM-dd"
            style="width: 240px"
          />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" icon="el-icon-search" @click="handleQuery"
            >搜索</el-button
          >
          <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
        </el-form-item>
      </el-form>
    </el-card>
    <!-- æ“ä½œæŒ‰é’® -->
    <el-card class="tool-card">
      <el-row :gutter="10">
        <el-col :span="16">
          <!-- <el-button type="primary" icon="el-icon-plus" @click="handleCreate"
            >新增维护</el-button
          > -->
          <el-button
            type="success"
            icon="el-icon-edit"
            :disabled="single"
            @click="handleUpdate"
            >修改</el-button
          >
          <el-button
            type="danger"
            icon="el-icon-delete"
            :disabled="multiple"
            @click="handleDelete"
            >删除</el-button
          >
          <el-button
            type="warning"
            icon="el-icon-download"
            @click="handleExport"
            >导出</el-button
          >
        </el-col>
        <el-col :span="8" style="text-align: right">
          <el-tooltip content="刷新" placement="top">
            <el-button icon="el-icon-refresh" circle @click="getList" />
          </el-tooltip>
        </el-col>
      </el-row>
    </el-card>
    <!-- æ•°æ®è¡¨æ ¼ -->
    <el-card>
      <el-table
        v-loading="loading"
        :data="maintenanceList"
        @selection-change="handleSelectionChange"
        @row-click="handleRowClick"
      >
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column
          label="案例编号"
          align="center"
          prop="caseNo"
          width="120"
        />
        <el-table-column
          label="潜在捐献者姓名"
          align="center"
          prop="donorName"
          width="120"
        />
        <el-table-column label="性别" align="center" prop="gender" width="80">
          <template slot-scope="scope">
            <dict-tag
              :options="dict.type.sys_user_sex"
              :value="parseInt(scope.row.gender)"
            />
          </template>
        </el-table-column>
        <el-table-column label="年龄" align="center" prop="age" width="80" />
        <el-table-column
          label="疾病诊断"
          align="center"
          prop="diagnosis"
          min-width="180"
          show-overflow-tooltip
        />
        <el-table-column
          label="所在医疗机构"
          align="center"
          prop="hospitalName"
          width="150"
          show-overflow-tooltip
        />
        <el-table-column
          label="患者状态"
          align="center"
          prop="patientStatus"
          width="120"
        >
          <template slot-scope="scope">
            <el-tag :type="statusFilter(scope.row.patientStatus)">
              {{ statusTextFilter(scope.row.patientStatus) }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column
          label="入院时间"
          align="center"
          prop="admissionTime"
          width="120"
        >
          <template slot-scope="scope">
            <span>{{
              scope.row.admissionTime
                ? parseTime(scope.row.admissionTime, "{y}-{m}-{d}")
                : "-"
            }}</span>
          </template>
        </el-table-column>
        <el-table-column
          label="出院时间"
          align="center"
          prop="dischargeTime"
          width="120"
        >
          <template slot-scope="scope">
            <span>{{
              scope.row.dischargeTime
                ? parseTime(scope.row.dischargeTime, "{y}-{m}-{d}")
                : "-"
            }}</span>
          </template>
        </el-table-column>
        <el-table-column
          label="最新培养结果"
          align="center"
          prop="latestCultureResult"
          width="120"
        >
          <template slot-scope="scope">
            <el-tag
              :type="scope.row.latestCultureResult === '阴性' ? 'success' : 'danger'"
              effect="plain"
            >
              {{ scope.row.latestCultureResult || '未检测' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column
          label="护理核查表录入时间"
          align="center"
          prop="lastRecordTime"
          width="140"
        >
          <template slot-scope="scope">
            <span>{{
              scope.row.lastRecordTime
                ? parseTime(scope.row.lastRecordTime, "{y}-{m}-{d} {h}:{i}")
                : "-"
            }}</span>
          </template>
        </el-table-column>
        <el-table-column
          label="协调员"
          align="center"
          prop="coordinator"
          width="100"
        />
        <el-table-column
          label="操作"
          align="center"
          width="180"
          class-name="small-padding fixed-width"
        >
          <template slot-scope="scope">
            <el-button
              size="mini"
              type="text"
              icon="el-icon-view"
              @click.stop="handleView(scope.row)"
              >详情</el-button
            >
            <!-- <el-button
              size="mini"
              type="text"
              icon="el-icon-edit"
              @click.stop="handleRecord(scope.row)"
              >录入核查</el-button
            >
            <el-button
              size="mini"
              type="text"
              icon="el-icon-document"
              @click.stop="handleRecordList(scope.row)"
              >记录查询</el-button
            > -->
          </template>
        </el-table-column>
      </el-table>
      <!-- åˆ†é¡µç»„ä»¶ -->
      <pagination
        v-show="total > 0"
        :total="total"
        :page.sync="queryParams.pageNum"
        :limit.sync="queryParams.pageSize"
        @pagination="getList"
      />
    </el-card>
  </div>
</template>
<script>
import { listMaintenance, delMaintenance, exportMaintenance } from "./mockMaintenanceApi";
import Pagination from "@/components/Pagination";
export default {
  name: "MaintenanceList",
  components: { Pagination },
  dicts: ["sys_user_sex"],
  data() {
    return {
      // é®ç½©å±‚
      loading: true,
      // é€‰ä¸­æ•°ç»„
      ids: [],
      // éžå•个禁用
      single: true,
      // éžå¤šä¸ªç¦ç”¨
      multiple: true,
      // æ€»æ¡æ•°
      total: 0,
      // ä¾›è€…维护表格数据
      maintenanceList: [],
      // æŸ¥è¯¢å‚æ•°
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        donorName: undefined,
        hospitalName: undefined,
        medicalStaff: undefined,
        patientStatus: undefined,
        recordTimeRange: []
      }
    };
  },
  created() {
    this.getList();
  },
  methods: {
    // çŠ¶æ€è¿‡æ»¤å™¨
    statusFilter(status) {
      const statusMap = {
        "1": "primary",   // DCD
        "2": "warning",   // DBD
        "3": "info",       // DBCD
        "4": "success",    // å·²å®ŒæˆæçŒ®
        "5": "danger"      // æœªå®ŒæˆæçŒ®
      };
      return statusMap[status] || "info";
    },
    statusTextFilter(status) {
      const statusMap = {
        "1": "DCD",
        "2": "DBD",
        "3": "DBCD",
        "4": "已完成捐献",
        "5": "未完成捐献"
      };
      return statusMap[status] || "未知";
    },
    // æŸ¥è¯¢ä¾›è€…维护列表
    getList() {
      this.loading = true;
      listMaintenance(this.queryParams)
        .then(response => {
          if (response.code === 200) {
            this.maintenanceList = response.data.rows;
            this.total = response.data.total;
          } else {
            this.$message.error("获取数据失败");
          }
          this.loading = false;
        })
        .catch(error => {
          console.error("获取供者维护列表失败:", error);
          this.loading = false;
          this.$message.error("获取数据失败");
        });
    },
    // æœç´¢æŒ‰é’®æ“ä½œ
    handleQuery() {
      this.queryParams.pageNum = 1;
      this.getList();
    },
    // é‡ç½®æŒ‰é’®æ“ä½œ
    resetQuery() {
      this.$refs.queryForm.resetFields();
      this.handleQuery();
    },
    // å¤šé€‰æ¡†é€‰ä¸­æ•°æ®
    handleSelectionChange(selection) {
      this.ids = selection.map(item => item.id);
      this.single = selection.length !== 1;
      this.multiple = !selection.length;
    },
    // è¡Œç‚¹å‡»äº‹ä»¶
    handleRowClick(row) {
      this.$router.push({
        path: "/case/maintainInfo",
        query: { id: row.id }
      });
    },
    // æŸ¥çœ‹è¯¦æƒ…
    handleView(row) {
      this.$router.push({
        path: "/case/maintainInfo",
        query: { id: row.id }
      });
    },
    // å½•入护理核查
    handleRecord(row) {
      this.$router.push({
        path: "/case/maintenance/record",
        query: { id: row.id, maintenanceId: row.maintenanceId }
      });
    },
    // æŸ¥çœ‹è®°å½•列表
    handleRecordList(row) {
      this.$router.push({
        path: "/case/maintenance/records",
        query: { id: row.id, maintenanceId: row.maintenanceId }
      });
    },
    // æ–°å¢žæŒ‰é’®æ“ä½œ
    handleCreate() {
      this.$router.push("/case/maintenance/add");
    },
    // ä¿®æ”¹æŒ‰é’®æ“ä½œ
    handleUpdate() {
      const id = this.ids[0];
      this.$router.push({
        path: "/case/maintenance/edit",
        query: { id: id }
      });
    },
    // åˆ é™¤æŒ‰é’®æ“ä½œ
    handleDelete() {
      const ids = this.ids;
      this.$confirm("是否确认删除选中的数据项?", "警告", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      })
        .then(() => {
          return delMaintenance(ids);
        })
        .then(response => {
          if (response.code === 200) {
            this.$message.success("删除成功");
            this.getList();
          }
        })
        .catch(() => {});
    },
    // å¯¼å‡ºæŒ‰é’®æ“ä½œ
    handleExport() {
      const queryParams = this.queryParams;
      this.$confirm("是否确认导出所有维护数据?", "警告", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      })
        .then(() => {
          this.loading = true;
          return exportMaintenance(queryParams);
        })
        .then(response => {
          if (response.code === 200) {
            this.$message.success("导出成功");
          }
          this.loading = false;
        })
        .catch(() => {
          this.loading = false;
        });
    },
    // æ—¶é—´æ ¼å¼åŒ–
    parseTime(time, pattern) {
      if (!time) return "";
      const date = new Date(time);
      if (pattern) {
        return pattern.replace(/{(\w+)}/g, (match, p) => {
          switch(p) {
            case 'y': return date.getFullYear();
            case 'm': return (date.getMonth() + 1).toString().padStart(2, '0');
            case 'd': return date.getDate().toString().padStart(2, '0');
            case 'h': return date.getHours().toString().padStart(2, '0');
            case 'i': return date.getMinutes().toString().padStart(2, '0');
            default: return match;
          }
        });
      }
      return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, "0")}-${date.getDate().toString().padStart(2, "0")}`;
    }
  }
};
</script>
<style scoped>
.maintenance-list {
  padding: 20px;
}
.search-card {
  margin-bottom: 20px;
}
.tool-card {
  margin-bottom: 20px;
}
.fixed-width .el-button {
  margin: 0 5px;
}
</style>
src/views/business/maintain/maintainInfo.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,878 @@
<template>
  <div class="maintenance-detail">
    <!-- åŸºç¡€ä¿¡æ¯ -->
    <el-card class="detail-card">
      <div slot="header" class="clearfix">
        <span class="detail-title">供者基本信息</span>
        <el-button
          v-if="isEdit"
          type="primary"
          style="float: right; padding: 3px 0"
          @click="handleSave"
        >
          ä¿å­˜ä¿¡æ¯
        </el-button>
      </div>
      <el-form :model="form" ref="form" label-width="120px">
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="案例编号" prop="caseNo">
              <el-input v-model="form.caseNo" :readonly="!isEdit" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="捐献者姓名" prop="donorName">
              <el-input v-model="form.donorName" :readonly="!isEdit" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="性别" prop="gender">
              <el-select v-model="form.gender" :disabled="!isEdit" style="width: 100%">
                <el-option label="男" value="0" />
                <el-option label="女" value="1" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="年龄" prop="age">
              <el-input v-model="form.age" :readonly="!isEdit" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="疾病诊断" prop="diagnosis">
              <el-input v-model="form.diagnosis" :readonly="!isEdit" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="所在医疗机构" prop="hospitalName">
              <el-input v-model="form.hospitalName" :readonly="!isEdit" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="患者状态" prop="patientStatus">
              <el-select v-model="form.patientStatus" :disabled="!isEdit" style="width: 100%">
                <el-option label="DCD" value="1" />
                <el-option label="DBD" value="2" />
                <el-option label="DBCD" value="3" />
                <el-option label="已完成捐献" value="4" />
                <el-option label="未完成捐献" value="5" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="未完成原因" prop="incompleteReason" v-if="form.patientStatus === '5'">
              <el-input
                v-model="form.incompleteReason"
                :readonly="!isEdit"
                placeholder="请输入未完成捐献的原因"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="入院时间" prop="admissionTime">
              <el-date-picker
                v-model="form.admissionTime"
                type="datetime"
                value-format="yyyy-MM-dd HH:mm:ss"
                style="width: 100%"
                :disabled="!isEdit"
              />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="出院时间" prop="dischargeTime">
              <el-date-picker
                v-model="form.dischargeTime"
                type="datetime"
                value-format="yyyy-MM-dd HH:mm:ss"
                style="width: 100%"
                :disabled="!isEdit"
              />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="协调员" prop="coordinator">
              <el-input v-model="form.coordinator" :readonly="!isEdit" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="血型" prop="bloodType">
              <el-select v-model="form.bloodType" :disabled="!isEdit" style="width: 100%">
                <el-option label="A型" value="A" />
                <el-option label="B型" value="B" />
                <el-option label="O型" value="O" />
                <el-option label="AB型" value="AB" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="RH因子" prop="rhFactor">
              <el-select v-model="form.rhFactor" :disabled="!isEdit" style="width: 100%">
                <el-option label="阳性" value="positive" />
                <el-option label="阴性" value="negative" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-form-item label="特殊病史" prop="specialMedicalHistory">
          <el-input
            type="textarea"
            :rows="3"
            v-model="form.specialMedicalHistory"
            :readonly="!isEdit"
            placeholder="记录特殊病史信息"
          />
        </el-form-item>
      </el-form>
    </el-card>
    <!-- åŸ¹å…»ç»“果记录 -->
 <!-- åŸ¹å…»ç»“果记录 -->
    <el-card class="culture-card">
      <div slot="header" class="clearfix">
        <span class="detail-title">培养结果记录</span>
        <el-button
          type="primary"
          size="mini"
          icon="el-icon-plus"
          @click="handleAddCulture"
        >
          æ–°å¢žåŸ¹å…»è®°å½•
        </el-button>
      </div>
      <el-table :data="cultureList" v-loading="cultureLoading">
        <el-table-column label="培养类型" align="center" prop="cultureType" width="120">
          <template slot-scope="scope">
            <dict-tag :options="cultureTypeOptions" :value="scope.row.cultureType" />
          </template>
        </el-table-column>
        <el-table-column label="采样时间" align="center" prop="sampleTime" width="160" />
        <el-table-column label="培养结果" align="center" prop="result" width="100">
          <template slot-scope="scope">
            <el-tag :type="scope.row.result === '阴性' ? 'success' : 'danger'" effect="plain">
              {{ scope.row.result }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="菌种" align="center" prop="bacteria" width="120" />
        <el-table-column label="药敏结果" align="center" prop="drugSensitivity" min-width="150" show-overflow-tooltip />
        <el-table-column label="检测机构" align="center" prop="testingInstitution" width="120" />
        <el-table-column label="操作" align="center" width="180" class-name="small-padding fixed-width">
          <template slot-scope="scope">
            <el-button
              size="mini"
              type="text"
              icon="el-icon-edit"
              @click="handleEditCulture(scope.row)"
            >编辑</el-button>
            <el-button
              size="mini"
              type="text"
              icon="el-icon-delete"
              style="color: #F56C6C;"
              @click="handleDeleteCulture(scope.row)"
            >删除</el-button>
            <el-button
              size="mini"
              type="text"
              icon="el-icon-view"
              @click="handleViewCulture(scope.row)"
            >详情</el-button>
          </template>
        </el-table-column>
      </el-table>
      <!-- åˆ†é¡µç»„ä»¶ -->
      <pagination
        v-show="cultureTotal > 0"
        :total="cultureTotal"
        :page.sync="cultureQueryParams.pageNum"
        :limit.sync="cultureQueryParams.pageSize"
        @pagination="getCultureList"
      />
    </el-card>
    <!-- æŠ¤ç†æ ¸æŸ¥è®°å½• -->
    <el-card class="record-card">
      <div slot="header" class="clearfix">
        <span class="detail-title">护理核查记录</span>
        <el-button
          type="primary"
          size="mini"
          icon="el-icon-plus"
          @click="handleAddRecord"
        >
          æ–°å¢žæ ¸æŸ¥è®°å½•
        </el-button>
      </div>
      <el-table :data="recordList" v-loading="recordLoading">
        <el-table-column label="核查时间" align="center" prop="recordTime" width="160" />
        <el-table-column label="核查人" align="center" prop="recorder" width="100" />
        <el-table-column label="体温(℃)" align="center" prop="temperature"  />
        <el-table-column label="心率(次/分)" align="center" prop="heartRate"  />
        <el-table-column label="血压(mmHg)" align="center" prop="bloodPressure" width="160" />
        <el-table-column label="呼吸(次/分)" align="center" prop="respirationRate"  />
        <el-table-column label="血氧饱和度(%)" align="center" prop="oxygenSaturation" width="160" />
        <el-table-column label="尿量(ml/h)" align="center" prop="urineOutput"  />
        <el-table-column label="操作" align="center" width="200" class-name="small-padding fixed-width">
          <template slot-scope="scope">
            <el-button
              size="mini"
              type="text"
              icon="el-icon-edit"
              @click="handleEditRecord(scope.row)"
            >编辑</el-button>
            <el-button
              size="mini"
              type="text"
              icon="el-icon-delete"
              style="color: #F56C6C;"
              @click="handleDeleteRecord(scope.row)"
            >删除</el-button>
            <el-button
              size="mini"
              type="text"
              icon="el-icon-view"
              @click="handleViewRecord(scope.row)"
            >详情</el-button>
          </template>
        </el-table-column>
      </el-table>
      <!-- åˆ†é¡µç»„ä»¶ -->
      <pagination
        v-show="recordTotal > 0"
        :total="recordTotal"
        :page.sync="recordQueryParams.pageNum"
        :limit.sync="recordQueryParams.pageSize"
        @pagination="getRecordList"
      />
    </el-card>
    <!-- åŸ¹å…»è®°å½•编辑对话框 -->
    <el-dialog
      :title="cultureDialogTitle"
      :visible.sync="cultureDialogVisible"
      width="700px"
      :close-on-click-modal="false"
    >
      <el-form :model="cultureForm" ref="cultureForm" :rules="cultureRules" label-width="120px">
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="培养类型" prop="cultureType">
              <el-select v-model="cultureForm.cultureType" placeholder="请选择培养类型" style="width: 100%">
                <el-option
                  v-for="item in cultureTypeOptions"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="采样时间" prop="sampleTime">
              <el-date-picker
                v-model="cultureForm.sampleTime"
                type="datetime"
                value-format="yyyy-MM-dd HH:mm:ss"
                placeholder="选择采样时间"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="培养结果" prop="result">
              <el-select v-model="cultureForm.result" placeholder="请选择培养结果" style="width: 100%">
                <el-option label="阴性" value="阴性" />
                <el-option label="阳性" value="阳性" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="菌种" prop="bacteria">
              <el-input v-model="cultureForm.bacteria" placeholder="请输入检测到的菌种" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-form-item label="药敏结果" prop="drugSensitivity">
          <el-input
            type="textarea"
            :rows="3"
            v-model="cultureForm.drugSensitivity"
            placeholder="请输入药敏试验结果"
          />
        </el-form-item>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="检测机构" prop="testingInstitution">
              <el-input v-model="cultureForm.testingInstitution" placeholder="请输入检测机构" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="标本类型" prop="specimenType">
              <el-input v-model="cultureForm.specimenType" placeholder="请输入标本类型" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-form-item label="备注" prop="remarks">
          <el-input
            type="textarea"
            :rows="2"
            v-model="cultureForm.remarks"
            placeholder="请输入备注信息"
          />
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="cultureDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleSaveCulture" :loading="cultureSaveLoading">保存</el-button>
      </span>
    </el-dialog>
    <!-- æŠ¤ç†æ ¸æŸ¥è®°å½•编辑对话框 -->
    <el-dialog
      :title="recordDialogTitle"
      :visible.sync="recordDialogVisible"
      width="800px"
      :close-on-click-modal="false"
    >
      <el-form :model="recordForm" ref="recordForm" :rules="recordRules" label-width="120px">
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="核查时间" prop="recordTime">
              <el-date-picker
                v-model="recordForm.recordTime"
                type="datetime"
                value-format="yyyy-MM-dd HH:mm:ss"
                placeholder="选择核查时间"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="核查人" prop="recorder">
              <el-input v-model="recordForm.recorder" placeholder="请输入核查人姓名" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="体温(℃)" prop="temperature">
              <el-input-number
                v-model="recordForm.temperature"
                :min="30" :max="45" :step="0.1"
                controls-position="right"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="心率(次/分)" prop="heartRate">
              <el-input-number
                v-model="recordForm.heartRate"
                :min="0" :max="200"
                controls-position="right"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="呼吸(次/分)" prop="respirationRate">
              <el-input-number
                v-model="recordForm.respirationRate"
                :min="0" :max="60"
                controls-position="right"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="血压(mmHg)" prop="bloodPressure">
              <el-input v-model="recordForm.bloodPressure" placeholder="格式:收缩压/舒张压" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="血氧饱和度(%)" prop="oxygenSaturation">
              <el-input-number
                v-model="recordForm.oxygenSaturation"
                :min="0" :max="100"
                controls-position="right"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="尿量(ml/h)" prop="urineOutput">
              <el-input-number
                v-model="recordForm.urineOutput"
                :min="0" :max="1000"
                controls-position="right"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="中心静脉压" prop="cvp">
              <el-input-number
                v-model="recordForm.cvp"
                :min="0" :max="20" :step="0.1"
                controls-position="right"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-form-item label="备注" prop="remarks">
          <el-input
            type="textarea"
            :rows="3"
            v-model="recordForm.remarks"
            placeholder="请输入核查备注信息"
          />
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="recordDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleSaveRecord" :loading="recordSaveLoading">保存</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
import { getMaintenanceDetail, updateMaintenance } from "./mockMaintenanceApi";
import { listCultureResults, addCultureResult, updateCultureResult, deleteCultureResult } from "./mockMaintenanceApi";
import { listNursingRecords, addNursingRecord, updateNursingRecord, deleteNursingRecord } from "./mockMaintenanceApi";
import Pagination from "@/components/Pagination";
export default {
 name: "MaintenanceDetail",
  components: { Pagination },
  data() {
    return {
      isEdit: false,
      form: {
        id: undefined,
        caseNo: '',
        donorName: '',
        gender: '',
        age: '',
        diagnosis: '',
        hospitalName: '',
        patientStatus: '1',
        admissionTime: '',
        dischargeTime: '',
        coordinator: '',
        bloodType: '',
        rhFactor: '',
        specialMedicalHistory: '',
        incompleteReason: ''
      },
      // åŸ¹å…»ç»“果相关数据
      cultureList: [],
      cultureLoading: false,
      cultureTotal: 0,
      cultureQueryParams: {
        pageNum: 1,
        pageSize: 10
      },
      cultureDialogVisible: false,
      cultureDialogTitle: '',
      cultureSaveLoading: false,
      cultureForm: {
        id: undefined,
        cultureType: '',
        sampleTime: '',
        result: '阴性',
        bacteria: '',
        drugSensitivity: '',
        testingInstitution: '',
        specimenType: '',
        remarks: ''
      },
      cultureRules: {
        cultureType: [{ required: true, message: '请选择培养类型', trigger: 'change' }],
        sampleTime: [{ required: true, message: '请选择采样时间', trigger: 'change' }],
        result: [{ required: true, message: '请选择培养结果', trigger: 'change' }]
      },
      cultureTypeOptions: [
        { value: '1', label: '血培养' },
        { value: '2', label: '痰培养' },
        { value: '3', label: '尿培养' },
        { value: '4', label: '伤口分泌物' },
        { value: '5', label: '脑脊液培养' },
        { value: '6', label: '其他' }
      ],
      // æŠ¤ç†æ ¸æŸ¥è®°å½•相关数据
      recordList: [],
      recordLoading: false,
      recordTotal: 0,
      recordQueryParams: {
        pageNum: 1,
        pageSize: 10
      },
      recordDialogVisible: false,
      recordDialogTitle: '',
      recordSaveLoading: false,
      recordForm: {
        id: undefined,
        recordTime: '',
        recorder: '',
        temperature: 36.5,
        heartRate: 80,
        bloodPressure: '120/80',
        respirationRate: 18,
        oxygenSaturation: 98,
        urineOutput: 50,
        cvp: 8,
        remarks: ''
      },
      recordRules: {
        recordTime: [{ required: true, message: '请选择核查时间', trigger: 'change' }],
        recorder: [{ required: true, message: '请输入核查人', trigger: 'blur' }],
        temperature: [{ required: true, message: '请输入体温', trigger: 'blur' }]
      }
    };
  },
 created() {
    const id = this.$route.query.id;
    this.isEdit = this.$route.query.edit === 'true';
    if (id) {
      this.getDetail(id);
      this.getCultureList();
      this.getRecordList();
    }
  },
  methods: {
     // èŽ·å–è¯¦æƒ…
    getDetail(id) {
      getMaintenanceDetail(id).then(response => {
        if (response.code === 200) {
          this.form = response.data;
        }
      });
    },
    // åŸ¹å…»è®°å½•相关方法
    getCultureList() {
      this.cultureLoading = true;
      listCultureResults(this.form.id, this.cultureQueryParams).then(response => {
        if (response.code === 200) {
          this.cultureList = response.data.rows;
          this.cultureTotal = response.data.total;
        }
        this.cultureLoading = false;
      }).catch(() => {
        this.cultureLoading = false;
      });
    },
    handleAddCulture() {
      this.cultureDialogTitle = '新增培养记录';
      this.cultureForm = {
        id: undefined,
        cultureType: '',
        sampleTime: '',
        result: '阴性',
        bacteria: '',
        drugSensitivity: '',
        testingInstitution: '',
        specimenType: '',
        remarks: ''
      };
      this.cultureDialogVisible = true;
      this.$nextTick(() => {
        this.$refs.cultureForm && this.$refs.cultureForm.clearValidate();
      });
    },
    handleEditCulture(row) {
      this.cultureDialogTitle = '编辑培养记录';
      this.cultureForm = { ...row };
      this.cultureDialogVisible = true;
      this.$nextTick(() => {
        this.$refs.cultureForm && this.$refs.cultureForm.clearValidate();
      });
    },
    handleViewCulture(row) {
      this.$alert(`
        <div>
          <p><strong>培养类型:</strong>${this.getCultureTypeLabel(row.cultureType)}</p>
          <p><strong>采样时间:</strong>${row.sampleTime}</p>
          <p><strong>培养结果:</strong>${row.result}</p>
          <p><strong>菌种:</strong>${row.bacteria || '无'}</p>
          <p><strong>药敏结果:</strong>${row.drugSensitivity || '无'}</p>
          <p><strong>检测机构:</strong>${row.testingInstitution}</p>
        </div>
      `, '培养记录详情', {
        dangerouslyUseHTMLString: true,
        customClass: 'detail-dialog'
      });
    },
    handleSaveCulture() {
      this.$refs.cultureForm.validate(valid => {
        if (valid) {
          this.cultureSaveLoading = true;
          const api = this.cultureForm.id ? updateCultureResult : addCultureResult;
          const requestData = {
            ...this.cultureForm,
            maintenanceId: this.form.id
          };
          api(requestData).then(response => {
            if (response.code === 200) {
              this.$message.success(this.cultureForm.id ? '修改成功' : '新增成功');
              this.cultureDialogVisible = false;
              this.getCultureList();
            }
            this.cultureSaveLoading = false;
          }).catch(() => {
            this.cultureSaveLoading = false;
          });
        }
      });
    },
    handleDeleteCulture(row) {
      this.$confirm('确定要删除这条培养记录吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        deleteCultureResult(row.id).then(response => {
          if (response.code === 200) {
            this.$message.success('删除成功');
            this.getCultureList();
          }
        });
      }).catch(() => {});
    },
    getCultureTypeLabel(value) {
      const type = this.cultureTypeOptions.find(item => item.value === value);
      return type ? type.label : '未知';
    },
    // æŠ¤ç†æ ¸æŸ¥è®°å½•相关方法
    getRecordList() {
      this.recordLoading = true;
      listNursingRecords(this.form.id, this.recordQueryParams).then(response => {
        if (response.code === 200) {
          this.recordList = response.data.rows;
          this.recordTotal = response.data.total;
        }
        this.recordLoading = false;
      }).catch(() => {
        this.recordLoading = false;
      });
    },
    handleAddRecord() {
      this.recordDialogTitle = '新增护理核查记录';
      this.recordForm = {
        id: undefined,
        recordTime: new Date().toISOString().replace('T', ' ').substring(0, 19),
        recorder: '当前用户', // å®žé™…项目中从用户信息获取
        temperature: 36.5,
        heartRate: 80,
        bloodPressure: '120/80',
        respirationRate: 18,
        oxygenSaturation: 98,
        urineOutput: 50,
        cvp: 8,
        remarks: ''
      };
      this.recordDialogVisible = true;
      this.$nextTick(() => {
        this.$refs.recordForm && this.$refs.recordForm.clearValidate();
      });
    },
    handleEditRecord(row) {
      this.recordDialogTitle = '编辑护理核查记录';
      this.recordForm = { ...row };
      this.recordDialogVisible = true;
      this.$nextTick(() => {
        this.$refs.recordForm && this.$refs.recordForm.clearValidate();
      });
    },
    handleViewRecord(row) {
      this.$alert(`
        <div>
          <p><strong>核查时间:</strong>${row.recordTime}</p>
          <p><strong>核查人:</strong>${row.recorder}</p>
          <p><strong>生命体征:</strong></p>
          <ul>
            <li>体温:${row.temperature}℃</li>
            <li>心率:${row.heartRate}次/分</li>
            <li>血压:${row.bloodPressure}mmHg</li>
            <li>呼吸:${row.respirationRate}次/分</li>
            <li>血氧饱和度:${row.oxygenSaturation}%</li>
            <li>尿量:${row.urineOutput}ml/h</li>
          </ul>
          <p><strong>备注:</strong>${row.remarks || '无'}</p>
        </div>
      `, '护理核查记录详情', {
        dangerouslyUseHTMLString: true,
        customClass: 'detail-dialog'
      });
    },
    handleSaveRecord() {
      this.$refs.recordForm.validate(valid => {
        if (valid) {
          this.recordSaveLoading = true;
          const api = this.recordForm.id ? updateNursingRecord : addNursingRecord;
          const requestData = {
            ...this.recordForm,
            maintenanceId: this.form.id
          };
          api(requestData).then(response => {
            if (response.code === 200) {
              this.$message.success(this.recordForm.id ? '修改成功' : '新增成功');
              this.recordDialogVisible = false;
              this.getRecordList();
            }
            this.recordSaveLoading = false;
          }).catch(() => {
            this.recordSaveLoading = false;
          });
        }
      });
    },
    handleDeleteRecord(row) {
      this.$confirm('确定要删除这条护理核查记录吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        deleteNursingRecord(row.id).then(response => {
          if (response.code === 200) {
            this.$message.success('删除成功');
            this.getRecordList();
          }
        });
      }).catch(() => {});
    },
    // ä¿å­˜åŸºæœ¬ä¿¡æ¯
    handleSave() {
      this.$refs.form.validate(valid => {
        if (valid) {
          updateMaintenance(this.form).then(response => {
            if (response.code === 200) {
              this.$message.success("保存成功");
              this.isEdit = false;
            }
          });
        }
      });
    }
  }
};
</script>
<style scoped>
.maintenance-detail {
  padding: 20px;
}
.detail-card {
  margin-bottom: 20px;
}
.culture-card {
  margin-bottom: 20px;
}
.record-card {
  margin-bottom: 20px;
}
.detail-title {
  font-size: 16px;
  font-weight: bold;
}
.maintenance-detail {
  padding: 20px;
}
.detail-card {
  margin-bottom: 20px;
}
.culture-card {
  margin-bottom: 20px;
}
.record-card {
  margin-bottom: 20px;
}
.detail-title {
  font-size: 16px;
  font-weight: bold;
}
.fixed-width .el-button {
  margin: 0 2px;
}
/* è¯¦æƒ…对话框样式 */
:deep(.detail-dialog) {
  width: 500px;
}
:deep(.detail-dialog .el-message-box__content) {
  line-height: 1.8;
}
:deep(.detail-dialog ul) {
  margin: 10px 0;
  padding-left: 20px;
}
:deep(.detail-dialog li) {
  margin-bottom: 5px;
}
</style>
src/views/business/maintain/mockMaintenanceApi.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,575 @@
// æ¨¡æ‹Ÿä¾›è€…维护API
const maintenanceData = {
  rows: [
    {
      id: 1,
      maintenanceId: 'WH202312001',
      caseNo: 'QJ202312001',
      donorName: '张某某',
      gender: '0',
      age: '45',
      diagnosis: '重型颅脑损伤',
      hospitalName: '北京市第一人民医院',
      patientStatus: '1',
      admissionTime: '2023-12-01 08:00:00',
      dischargeTime: '',
      coordinator: '协调员A',
      latestCultureResult: '阴性',
      lastRecordTime: '2023-12-03 14:30:00',
      bloodType: 'A',
      rhFactor: 'positive',
      specialMedicalHistory: '无特殊病史',
      incompleteReason: ''
    },
    {
      id: 2,
      maintenanceId: 'WH202312002',
      caseNo: 'QJ202312002',
      donorName: '李某某',
      gender: '1',
      age: '32',
      diagnosis: '脑出血',
      hospitalName: '上海市中心医院',
      patientStatus: '2',
      admissionTime: '2023-11-28 10:30:00',
      dischargeTime: '',
      coordinator: '协调员B',
      latestCultureResult: '阳性',
      lastRecordTime: '2023-12-03 16:20:00',
      bloodType: 'B',
      rhFactor: 'positive',
      specialMedicalHistory: '高血压病史5å¹´',
      incompleteReason: ''
    },
    {
      id: 3,
      maintenanceId: 'WH202312003',
      caseNo: 'QJ202312003',
      donorName: '王某某',
      gender: '0',
      age: '58',
      diagnosis: '心脏骤停后脑损伤',
      hospitalName: '广州市人民医院',
      patientStatus: '4',
      admissionTime: '2023-11-25 09:15:00',
      dischargeTime: '2023-12-02 14:00:00',
      coordinator: '协调员C',
      latestCultureResult: '阴性',
      lastRecordTime: '2023-12-02 10:00:00',
      bloodType: 'O',
      rhFactor: 'negative',
      specialMedicalHistory: '糖尿病史10å¹´',
      incompleteReason: ''
    },
    {
      id: 4,
      maintenanceId: 'WH202312004',
      caseNo: 'QJ202312004',
      donorName: '赵某某',
      gender: '1',
      age: '29',
      diagnosis: '交通事故颅脑损伤',
      hospitalName: '深圳市中心医院',
      patientStatus: '5',
      admissionTime: '2023-12-01 15:45:00',
      dischargeTime: '2023-12-04 11:20:00',
      coordinator: '协调员D',
      latestCultureResult: '阴性',
      lastRecordTime: '2023-12-03 09:15:00',
      bloodType: 'AB',
      rhFactor: 'positive',
      specialMedicalHistory: '无',
      incompleteReason: '家属临时改变决定'
    }
  ],
  total: 4
};
// æŠ¤ç†æ ¸æŸ¥è®°å½•数据
const nursingRecordsData = {
  rows: [
    {
      id: 1,
      maintenanceId: 'WH202312001',
      recordTime: '2023-12-03 08:00:00',
      recorder: '张护士',
      temperature: '36.5',
      heartRate: '78',
      bloodPressure: '120/80',
      respirationRate: '18',
      oxygenSaturation: '98',
      urineOutput: '50',
      consciousness: '清醒',
      pupilLeft: '2.5mm',
      pupilRight: '2.5mm',
      lightReflexLeft: '灵敏',
      lightReflexRight: '灵敏',
      ventilatorMode: 'SIMV',
      fio2: '40%',
      peep: '5cmH2O',
      cvp: '8mmHg',
      bloodSugar: '5.6',
      remarks: '生命体征平稳'
    },
    {
      id: 2,
      maintenanceId: 'WH202312001',
      recordTime: '2023-12-03 12:00:00',
      recorder: '李护士',
      temperature: '36.8',
      heartRate: '82',
      bloodPressure: '118/76',
      respirationRate: '16',
      oxygenSaturation: '99',
      urineOutput: '45',
      consciousness: '清醒',
      pupilLeft: '2.5mm',
      pupilRight: '2.5mm',
      lightReflexLeft: '灵敏',
      lightReflexRight: '灵敏',
      ventilatorMode: 'SIMV',
      fio2: '40%',
      peep: '5cmH2O',
      cvp: '9mmHg',
      bloodSugar: '5.8',
      remarks: '情况稳定'
    }
  ],
  total: 2
};
// åŸ¹å…»ç»“果数据
const cultureResultsData = {
  rows: [
    {
      id: 1,
      maintenanceId: 'WH202312001',
      cultureType: '1',
      sampleTime: '2023-12-01 10:00:00',
      result: '阴性',
      bacteria: '',
      drugSensitivity: '',
      testingInstitution: '检验科',
      specimenType: '血液',
      collectionMethod: '静脉采血'
    },
    {
      id: 2,
      maintenanceId: 'WH202312001',
      cultureType: '2',
      sampleTime: '2023-12-02 14:30:00',
      result: '阳性',
      bacteria: '肺炎克雷伯菌',
      drugSensitivity: '对头孢类敏感,对青霉素耐药',
      testingInstitution: '微生物室',
      specimenType: '痰液',
      collectionMethod: '深部咳痰'
    },
    {
      id: 3,
      maintenanceId: 'WH202312002',
      cultureType: '1',
      sampleTime: '2023-12-03 09:15:00',
      result: '阳性',
      bacteria: '金黄色葡萄球菌',
      drugSensitivity: '对万古霉素敏感',
      testingInstitution: '检验科',
      specimenType: '血液',
      collectionMethod: '中心静脉采血'
    }
  ],
  total: 3
};
// èŽ·å–ä¾›è€…ç»´æŠ¤åˆ—è¡¨
export function listMaintenance(params) {
  return new Promise((resolve) => {
    setTimeout(() => {
      const { pageNum = 1, pageSize = 10, donorName, hospitalName, patientStatus, medicalStaff } = params;
      // æ·±æ‹·è´æ•°æ®é¿å…æ±¡æŸ“
      let filteredData = JSON.parse(JSON.stringify(maintenanceData.rows));
      // æ¨¡æ‹Ÿç­›é€‰é€»è¾‘
      if (donorName) {
        filteredData = filteredData.filter(item =>
          item.donorName && item.donorName.includes(donorName)
        );
      }
      if (hospitalName) {
        filteredData = filteredData.filter(item =>
          item.hospitalName && item.hospitalName.includes(hospitalName)
        );
      }
      if (patientStatus) {
        filteredData = filteredData.filter(item => item.patientStatus === patientStatus);
      }
      if (medicalStaff) {
        filteredData = filteredData.filter(item =>
          item.coordinator && item.coordinator.includes(medicalStaff)
        );
      }
      // åˆ†é¡µå¤„理
      const start = (pageNum - 1) * pageSize;
      const end = start + pageSize;
      const pageData = filteredData.slice(start, end);
      resolve({
        code: 200,
        data: {
          rows: pageData,
          total: filteredData.length,
          pageNum: parseInt(pageNum),
          pageSize: parseInt(pageSize)
        },
        message: '获取成功'
      });
    }, 500);
  });
}
// èŽ·å–ä¾›è€…ç»´æŠ¤è¯¦æƒ…
export function getMaintenanceDetail(id) {
  return new Promise((resolve) => {
    setTimeout(() => {
      const detail = maintenanceData.rows.find(item => item.id == id);
      if (detail) {
        resolve({
          code: 200,
          data: detail,
          message: '获取成功'
        });
      } else {
        resolve({
          code: 404,
          data: null,
          message: '数据不存在'
        });
      }
    }, 300);
  });
}
// æ›´æ–°ä¾›è€…维护信息
export function updateMaintenance(data) {
  return new Promise((resolve) => {
    setTimeout(() => {
      const index = maintenanceData.rows.findIndex(item => item.id === data.id);
      if (index !== -1) {
        maintenanceData.rows[index] = { ...maintenanceData.rows[index], ...data };
        resolve({
          code: 200,
          message: '更新成功',
          data: maintenanceData.rows[index]
        });
      } else {
        resolve({
          code: 404,
          message: '数据不存在',
          data: null
        });
      }
    }, 300);
  });
}
// åˆ é™¤ä¾›è€…维护
export function delMaintenance(ids) {
  return new Promise((resolve) => {
    setTimeout(() => {
      const originalLength = maintenanceData.rows.length;
      maintenanceData.rows = maintenanceData.rows.filter(
        item => !ids.includes(item.id)
      );
      maintenanceData.total = maintenanceData.rows.length;
      if (maintenanceData.rows.length < originalLength) {
        resolve({
          code: 200,
          message: '删除成功',
          data: { deletedCount: originalLength - maintenanceData.rows.length }
        });
      } else {
        resolve({
          code: 404,
          message: '未找到要删除的数据',
          data: null
        });
      }
    }, 300);
  });
}
// å¯¼å‡ºä¾›è€…维护数据
export function exportMaintenance(params) {
  return new Promise((resolve) => {
    setTimeout(() => {
      // æ¨¡æ‹Ÿå¯¼å‡ºæ•°æ®å¤„理
      const exportData = maintenanceData.rows.map(item => ({
        '案例编号': item.caseNo,
        '捐献者姓名': item.donorName,
        '性别': item.gender === '0' ? '男' : '女',
        '年龄': item.age,
        '疾病诊断': item.diagnosis,
        '医疗机构': item.hospitalName,
        '患者状态': getPatientStatusText(item.patientStatus),
        '入院时间': item.admissionTime,
        '出院时间': item.dischargeTime || '',
        '最新培养结果': item.latestCultureResult,
        '协调员': item.coordinator
      }));
      resolve({
        code: 200,
        data: {
          downloadUrl: '/download/maintenance_export.xlsx',
          fileName: `供者维护数据_${new Date().toISOString().split('T')[0]}.xlsx`,
          recordCount: exportData.length
        },
        message: '导出成功'
      });
    }, 1000);
  });
}
// å·¥å…·å‡½æ•°
function getPatientStatusText(status) {
  const statusMap = {
    '1': 'DCD',
    '2': 'DBD',
    '3': 'DBCD',
    '4': '已完成捐献',
    '5': '未完成捐献'
  };
  return statusMap[status] || '未知';
}
// æ‰¹é‡æ“ä½œ
export function batchUpdateMaintenance(updateData) {
  return new Promise((resolve) => {
    setTimeout(() => {
      const { ids, updateFields } = updateData;
      let successCount = 0;
      maintenanceData.rows.forEach(item => {
        if (ids.includes(item.id)) {
          Object.assign(item, updateFields);
          successCount++;
        }
      });
      resolve({
        code: 200,
        data: { successCount, totalCount: ids.length },
        message: `成功更新${successCount}条记录`
      });
    }, 500);
  });
}
// åŸ¹å…»ç»“果相关API
export function listCultureResults(maintenanceId, params = {}) {
  return new Promise((resolve) => {
    setTimeout(() => {
      const { pageNum = 1, pageSize = 10 } = params;
      let filteredData = cultureResultsData.rows.filter(item =>
        item.maintenanceId === maintenanceId
      );
      // æŒ‰é‡‡æ ·æ—¶é—´å€’序排列
      filteredData.sort((a, b) => new Date(b.sampleTime) - new Date(a.sampleTime));
      const start = (pageNum - 1) * pageSize;
      const end = start + pageSize;
      const pageData = filteredData.slice(start, end);
      resolve({
        code: 200,
        data: {
          rows: pageData,
          total: filteredData.length,
          pageNum: parseInt(pageNum),
          pageSize: parseInt(pageSize)
        },
        message: '获取成功'
      });
    }, 300);
  });
}
export function addCultureResult(cultureData) {
  return new Promise((resolve) => {
    setTimeout(() => {
      const newCulture = {
        id: Date.now(),
        ...cultureData,
        createTime: new Date().toISOString()
      };
      cultureResultsData.rows.unshift(newCulture);
      cultureResultsData.total = cultureResultsData.rows.length;
      resolve({
        code: 200,
        data: newCulture,
        message: '新增成功'
      });
    }, 300);
  });
}
export function updateCultureResult(cultureData) {
  return new Promise((resolve) => {
    setTimeout(() => {
      const index = cultureResultsData.rows.findIndex(item => item.id === cultureData.id);
      if (index !== -1) {
        cultureResultsData.rows[index] = {
          ...cultureResultsData.rows[index],
          ...cultureData,
          updateTime: new Date().toISOString()
        };
        resolve({
          code: 200,
          data: cultureResultsData.rows[index],
          message: '更新成功'
        });
      } else {
        resolve({
          code: 404,
          data: null,
          message: '数据不存在'
        });
      }
    }, 300);
  });
}
export function deleteCultureResult(id) {
  return new Promise((resolve) => {
    setTimeout(() => {
      const index = cultureResultsData.rows.findIndex(item => item.id === id);
      if (index !== -1) {
        cultureResultsData.rows.splice(index, 1);
        cultureResultsData.total = cultureResultsData.rows.length;
        resolve({
          code: 200,
          message: '删除成功'
        });
      } else {
        resolve({
          code: 404,
          message: '数据不存在'
        });
      }
    }, 300);
  });
}
// æŠ¤ç†æ ¸æŸ¥è®°å½•相关API
export function listNursingRecords(maintenanceId, params = {}) {
  return new Promise((resolve) => {
    setTimeout(() => {
      const { pageNum = 1, pageSize = 10 } = params;
      let filteredData = nursingRecordsData.rows.filter(item =>
        item.maintenanceId === maintenanceId
      );
      // æŒ‰è®°å½•时间倒序排列
      filteredData.sort((a, b) => new Date(b.recordTime) - new Date(a.recordTime));
      const start = (pageNum - 1) * pageSize;
      const end = start + pageSize;
      const pageData = filteredData.slice(start, end);
      resolve({
        code: 200,
        data: {
          rows: pageData,
          total: filteredData.length,
          pageNum: parseInt(pageNum),
          pageSize: parseInt(pageSize)
        },
        message: '获取成功'
      });
    }, 300);
  });
}
export function addNursingRecord(recordData) {
  return new Promise((resolve) => {
    setTimeout(() => {
      const newRecord = {
        id: Date.now(),
        ...recordData,
        createTime: new Date().toISOString()
      };
      nursingRecordsData.rows.unshift(newRecord);
      nursingRecordsData.total = nursingRecordsData.rows.length;
      resolve({
        code: 200,
        data: newRecord,
        message: '新增成功'
      });
    }, 300);
  });
}
export function updateNursingRecord(recordData) {
  return new Promise((resolve) => {
    setTimeout(() => {
      const index = nursingRecordsData.rows.findIndex(item => item.id === recordData.id);
      if (index !== -1) {
        nursingRecordsData.rows[index] = {
          ...nursingRecordsData.rows[index],
          ...recordData,
          updateTime: new Date().toISOString()
        };
        resolve({
          code: 200,
          data: nursingRecordsData.rows[index],
          message: '更新成功'
        });
      } else {
        resolve({
          code: 404,
          data: null,
          message: '数据不存在'
        });
      }
    }, 300);
  });
}
export function deleteNursingRecord(id) {
  return new Promise((resolve) => {
    setTimeout(() => {
      const index = nursingRecordsData.rows.findIndex(item => item.id === id);
      if (index !== -1) {
        nursingRecordsData.rows.splice(index, 1);
        nursingRecordsData.total = nursingRecordsData.rows.length;
        resolve({
          code: 200,
          message: '删除成功'
        });
      } else {
        resolve({
          code: 404,
          message: '数据不存在'
        });
      }
    }, 300);
  });
}
src/views/login.vue
@@ -6,7 +6,7 @@
      :rules="loginRules"
      class="login-form"
    >
      <h3 class="title">浙江省OPO数字化管理平台</h3>
      <h3 class="title">青岛大学附属医院opo</h3>
      <el-form-item prop="username">
        <el-input
          v-model="loginForm.username"
src/views/project/indexstatistics/index.vue
@@ -1,40 +1,38 @@
<template>
  <div class="app-container" style="background-color: #f2f2f2; color: #fff">
    <el-card shadow="always" style="color: #566f94">
      <el-row :gutter="8">
        <el-col :span="8">
  <div class="app-container">
    <!-- ç­›é€‰æ¡ä»¶å¡ç‰‡ -->
    <el-card class="filter-card">
      <el-row :gutter="16">
        <el-col :xs="24" :sm="8" :md="6">
          <el-date-picker
            v-model="selecttime"
            type="monthrange"
            range-separator="至"
            start-placeholder="开始月份(默认本年度)"
            start-placeholder="开始月份"
            end-placeholder="结束月份"
            style="width: 100%"
            value-format="yyyy-MM-dd"
            @change="getTimeList"
            style="width: 100%"
          >
          </el-date-picker>
          />
        </el-col>
        <el-col :span="6">
        <el-col :xs="24" :sm="8" :md="6">
          <el-select
            style="width: 100%"
            v-model="reportervalue"
            placeholder="请选择报告人"
            style="width: 100%"
          >
            <el-option
              v-for="item in reportlist"
              :key="item.index"
              :label="item.reportername"
              :value="item.reporterno"
            >
            </el-option>
            />
          </el-select>
        </el-col>
        <el-col :span="6">
        <el-col :xs="24" :sm="8" :md="6">
          <el-select
            v-model="city"
            placeholder="请选择所属地市"
            @change="getprovincedata"
            style="width: 100%"
          >
            <el-option
@@ -42,581 +40,382 @@
              :key="item.value"
              :label="item.label"
              :value="item.value"
            >
            </el-option>
            />
          </el-select>
        </el-col>
        <el-col :span="2">
        <el-col :xs="24" :sm="24" :md="6">
          <div class="action-buttons">
          <el-button
            type="primary"
            @click="selectdatas"
            icon="el-icon-search"
            style="margin-left: 10px"
            >搜索</el-button
              @click="selectdatas"
          >
              æœç´¢
            </el-button>
            <el-button icon="el-icon-refresh" @click="resetFilters">
              é‡ç½®
            </el-button>
          </div>
        </el-col>
      </el-row>
    </el-card>
    <div style="display: flex;">
      <div style="width: 76%;">
        <el-row
          :gutter="10"
          style="font-size: 18px; font-weight: bold;  margin-top: 10px"
        >
          <el-col :span="6">
    <!-- æ•°æ®æ¦‚览区域 -->
    <el-card class="overview-card">
      <template #header>
        <div class="card-header">
          <span class="header-title">数据概览</span>
          <span class="header-subtitle">实时统计指标</span>
        </div>
      </template>
      <el-row :gutter="16">
        <!-- ç¬¬ä¸€è¡Œç»Ÿè®¡å¡ç‰‡ -->
        <el-col :xs="12" :sm="6" :md="3">
            <router-link
              :to="{
                name: 'Donatebaseinfo',
                params: {
                  starttime: starttime,
                  endtime: endtime,
                  tempRecordState: '',
                  reporterno: reportervalue,
                  shen: searchAddress.shen,
                  shi: searchAddress.shi,
                  qu: searchAddress.qu,
                  city: city
                }
              params: { ...routeParams }
              }"
            class="stat-card-link"
            >
              <!-- params: {
              tempRecordState: 0,
            }, -->
              <!-- @click="tobaseinfo0" -->
              <el-card shadow="always" style="color: #566f94">
                <svg-icon icon-class="user" />&nbsp;&nbsp; æ½œåœ¨æçŒ®ç´¯è®¡ï¼š{{
                  donateNumData.numberOfDonate
                }}&nbsp; ä¾‹
            <el-card class="stat-card" shadow="hover">
              <div class="stat-content">
                <div class="stat-icon" style="background-color: #409EFF;">
                  <svg-icon icon-class="user" />
                </div>
                <div class="stat-info">
                  <div class="stat-value">
                    {{ donateNumData.numberOfDonate }}
                  </div>
                  <div class="stat-title">上报案例累计</div>
                </div>
              </div>
              </el-card>
            </router-link>
          </el-col>
          <el-col :span="6">
        <el-col :xs="12" :sm="6" :md="3">
            <router-link
              :to="{
                name: 'Medicalevaluation',
                params: {
                  starttime: starttime,
                  endtime: endtime,
                  tempRecordState: '',
                  reporterno: reportervalue,
                  shen: searchAddress.shen,
                  shi: searchAddress.shi,
                  qu: searchAddress.qu,
                  city: city
                }
              params: { ...routeParams }
              }"
            class="stat-card-link"
            >
              <el-card
                shadow="always"
                style="color: #566f94"
                @click="Tomedicalevalua"
              >
                <svg-icon icon-class="tool" />&nbsp;&nbsp; å®ŒæˆåŒ»å­¦è¯„估累计:{{
                  donateNumData.numberOfMedicalEvaluation
                }}&nbsp; ä¾‹
            <el-card class="stat-card" shadow="hover">
              <div class="stat-content">
                <div class="stat-icon" style="background-color: #67C23A;">
                  <svg-icon icon-class="tool" />
                </div>
                <div class="stat-info">
                  <div class="stat-value">
                    {{ donateNumData.numberOfMedicalEvaluation }}
                  </div>
                  <div class="stat-title">捐献案例累计</div>
                </div>
              </div>
              </el-card>
            </router-link>
          </el-col>
          <el-col :span="6">
        <el-col :xs="12" :sm="6" :md="3">
            <router-link
              :to="{
                name: 'Relativesconfirmation',
                params: {
                  starttime: starttime,
                  endtime: endtime,
                  tempRecordState: '',
                  reporterno: reportervalue,
                  shen: searchAddress.shen,
                  shi: searchAddress.shi,
                  qu: searchAddress.qu,
                  city: city
                }
              params: { ...routeParams }
              }"
            class="stat-card-link"
            >
              <el-card shadow="always" style="color: #566f94">
                <svg-icon icon-class="checkbox" />&nbsp;&nbsp;
                å®Œæˆäº²å±žç¡®è®¤ç´¯è®¡ï¼š{{
                  donateNumData.numberOfRelativeConfirmation
                }}&nbsp; ä¾‹
            <el-card class="stat-card" shadow="hover">
              <div class="stat-content">
                <div class="stat-icon" style="background-color: #E6A23C;">
                  <svg-icon icon-class="checkbox" />
                </div>
                <div class="stat-info">
                  <div class="stat-value">
                    {{ donateNumData.numberOfRelativeConfirmation }}
                  </div>
                  <div class="stat-title">供体转运累计</div>
                </div>
              </div>
              </el-card>
            </router-link>
          </el-col>
          <el-col :span="6">
        <el-col :xs="12" :sm="6" :md="3">
            <router-link
              :to="{
                name: 'EthicalReview',
                params: {
                  starttime: starttime,
                  endtime: endtime,
                  tempRecordState: '',
                  reporterno: reportervalue,
                  shen: searchAddress.shen,
                  shi: searchAddress.shi,
                  qu: searchAddress.qu,
                  city: city
                }
              params: { ...routeParams }
              }"
            class="stat-card-link"
            >
              <el-card shadow="always" style="color: #566f94">
                <svg-icon icon-class="education" />&nbsp;&nbsp;
                å®Œæˆä¼¦ç†å®¡æŸ¥ç´¯è®¡ï¼š{{
                  donateNumData.numberOfEthicalReview
                }}&nbsp; ä¾‹
            <el-card class="stat-card" shadow="hover">
              <div class="stat-content">
                <div class="stat-icon" style="background-color: #F56C6C;">
                  <svg-icon icon-class="education" />
                </div>
                <div class="stat-info">
                  <div class="stat-value">
                    {{ donateNumData.numberOfEthicalReview }}
                  </div>
                  <div class="stat-title">亲属确认累计</div>
                </div>
              </div>
              </el-card>
            </router-link>
          </el-col>
        </el-row>
        <el-row
          :gutter="10"
          style="margin-top: 10px; font-size: 18px;  font-weight: bold"
        >
          <el-col :span="6">
            <el-card shadow="always" style="color: #566f94">
              <svg-icon icon-class="druid" />&nbsp;&nbsp; å®Œæˆå™¨å®˜åˆ†é…ç´¯è®¡ï¼š{{
                donateNumData.numberOfDonatePeople
              }}&nbsp; ä¸ª
              <!-- donateNumData.numberOfOrgans -->
        <!-- ç¬¬äºŒè¡Œç»Ÿè®¡å¡ç‰‡ -->
        <el-col :xs="12" :sm="6" :md="3">
          <el-card class="stat-card" shadow="hover">
            <div class="stat-content">
              <div class="stat-icon" style="background-color: #909399;">
                <svg-icon icon-class="druid" />
              </div>
              <div class="stat-info">
                <div class="stat-value">
                  {{ donateNumData.numberOfDonatePeople }}
                </div>
                <div class="stat-title">完成伦理审查累计</div>
              </div>
            </div>
            </el-card>
          </el-col>
          <el-col :span="6">
        <el-col :xs="12" :sm="6" :md="3">
            <router-link
              :to="{
                name: 'Donationwitness',
                params: {
                  starttime: starttime,
                  endtime: endtime,
                  tempRecordState: '',
                  reporterno: reportervalue,
                  shen: searchAddress.shen,
                  shi: searchAddress.shi,
                  qu: searchAddress.qu,
                  city: city
                }
              params: { ...routeParams }
              }"
            class="stat-card-link"
            >
              <el-card shadow="always" style="color: #566f94">
                <svg-icon icon-class="job" />&nbsp;&nbsp; å®ŒæˆèŽ·å–è§è¯ç´¯è®¡ï¼š{{
                  donateNumData.numberOfWitness
                }}&nbsp; ä¾‹
            <el-card class="stat-card" shadow="hover">
              <div class="stat-content">
                <div class="stat-icon" style="background-color: #B37FEB;">
                  <svg-icon icon-class="job" />
                </div>
                <div class="stat-info">
                  <div class="stat-value">
                    {{ donateNumData.numberOfWitness }}
                  </div>
                  <div class="stat-title">完成器官分配累计</div>
                </div>
              </div>
              </el-card>
            </router-link>
          </el-col>
          <el-col :span="6">
        <el-col :xs="12" :sm="6" :md="3">
            <router-link
              :to="{
                name: 'Donatefinish',
                params: {
                  starttime: starttime,
                  endtime: endtime,
                  tempRecordState: '',
                  reporterno: reportervalue,
                  shen: searchAddress.shen,
                  shi: searchAddress.shi,
                  qu: searchAddress.qu,
                  city: city
                }
              params: { ...routeParams }
              }"
            class="stat-card-link"
            >
              <el-card shadow="always" style="color: #566f94">
                <svg-icon icon-class="lock" />&nbsp;&nbsp; æçŒ®å®Œæˆç´¯è®¡ï¼š{{
                  donateNumData.numberOfCompletion
                }}&nbsp; ä¾‹
            <el-card class="stat-card" shadow="hover">
              <div class="stat-content">
                <div class="stat-icon" style="background-color: #FF85C0;">
                  <svg-icon icon-class="lock" />
                </div>
                <div class="stat-info">
                  <div class="stat-value">
                    {{ donateNumData.numberOfCompletion }}
                  </div>
                  <div class="stat-title">完成获取累计</div>
                </div>
              </div>
              </el-card>
            </router-link>
          </el-col>
          <el-col :span="6">
        <el-col :xs="12" :sm="6" :md="3">
            <router-link
              @click.native="closeBaseInfoTab"
              :to="{
                name: 'Donatebaseinfo',
                params: {
                  starttime: starttime,
                  endtime: endtime,
                  terminationcase: 1,
                  reporterno: reportervalue,
                  shen: searchAddress.shen,
                  shi: searchAddress.shi,
                  qu: searchAddress.qu,
                  city: city
                }
              params: { ...routeParams, terminationcase: 1 }
              }"
            class="stat-card-link"
            >
              <el-card shadow="always" style="color: #566f94">
                <svg-icon icon-class="lock" />&nbsp;&nbsp; æçŒ®ç»ˆæ­¢ç´¯è®¡ï¼š{{
                  donateNumData.numberOfTerminated
                }}&nbsp; ä¾‹
            <el-card class="stat-card" shadow="hover">
              <div class="stat-content">
                <div class="stat-icon" style="background-color: #5DC8EF;">
                  <svg-icon icon-class="lock" />
                </div>
                <div class="stat-info">
                  <div class="stat-value">
                    {{ donateNumData.numberOfTerminated }}
                  </div>
                  <div class="stat-title">捐献终止累计</div>
                </div>
              </div>
              </el-card>
            </router-link>
          </el-col>
        </el-row>
        <el-row style="margin-top: 10px; " :gutter="5">
          <el-col :span="12">
            <el-card
              shadow="always"
              style="padding: 0; font-weight: bold; height: 640px"
              ref="statisticsCard"
            >
              <el-row style="margin-bottom: 20px">
                <span style="font-size: 18px; color: #566f94; font-weight: bold"
                  >指标数据分析</span
                >
                <span style="margin-left: 30px;">
    </el-card>
    <!-- æŒ‡æ ‡åˆ†æžåŒºåŸŸ -->
    <el-row :gutter="16" class="analysis-section">
      <el-col :xs="24" :lg="12">
        <el-card class="chart-card">
          <template #header>
            <div class="card-header">
              <span>指标数据分析</span>
                  <router-link
                    :to="{
                      name: 'DonationProcess',
                      params: {
                        starttime: starttime,
                        endtime: endtime,
                        terminationcase: 1,
                        reporterno: reportervalue,
                        shen: searchAddress.shen,
                        shi: searchAddress.shi,
                        qu: searchAddress.qu,
                        city: city
                      }
                  params: { ...routeParams, terminationcase: 1 }
                    }"
                  >
                    <el-button type="primary" round>捐献进程</el-button>
                <el-button type="primary" size="small" round
                  >捐献进程</el-button
                >
                  </router-link>
                </span>
              </el-row>
              <el-row :gutter="3">
                <el-col :span="8" style="text-align: center">
                  <el-card
                    shadow="always"
                    style="padding: 0; margin: 0; width: 100%; color: #566f94"
                  >
                    å™¨å®˜æçŒ®è½¬åŒ–率<br />
            </div>
          </template>
<div class="metrics-wrapper">
  <div class="metrics-grid">
    <div class="metric-item">
      <div class="metric-title">器官捐献转化率</div>
      <div class="metric-value">
                    {{ (qualirtData.donateTransferRate * 100).toFixed(2) }}%
                  </el-card>
                </el-col>
                <el-col :span="8" style="text-align: center">
                  <el-card
                    shadow="always"
                    style="padding: 0; margin: 0; width: 100%; color: #566f94"
                  >
                    å¹³å‡å™¨å®˜äº§å‡ºçއ<br />
      </div>
    </div>
    <div class="metric-item">
      <div class="metric-title">平均器官产出率</div>
      <div class="metric-value">
                    {{ (qualirtData.organProductionRate * 100).toFixed(2) }}%
                  </el-card>
                </el-col>
                <el-col :span="8" style="text-align: center">
                  <el-card
                    shadow="always"
                    style="padding: 0; margin: 0; width: 100%; color: #566f94"
                  >
                    èŽ·å–å™¨å®˜åˆ©ç”¨çŽ‡<br />
      </div>
    </div>
    <div class="metric-item">
      <div class="metric-title">获取器官利用率</div>
      <div class="metric-value">
                    {{ (qualirtData.organUsedRate * 100).toFixed(2) }}%
                  </el-card>
                </el-col>
              </el-row>
              <el-row :gutter="3" style="margin-top: 5px">
                <el-col :span="24" style="text-align: center">
                  <el-card shadow="always" style="padding: 0; color: #566f94">
                    <el-row> å™¨å®˜æçŒ®åˆ†ç±»å æ¯” </el-row>
                    <el-row :gutter="10" style="margin-top: 10px">
                      <el-col :span="8" style="text-align: center"
      </div>
    </div>
    <div class="metric-item full-width">
      <div class="metric-title">器官捐献分类占比</div>
      <div class="metric-breakdown">
        <span
                        >DBD:
                        {{ (qualirtData.dbddonateRate * 100).toFixed(2) }}%
                      </el-col>
                      <el-col :span="8" style="text-align: center">
                        DCD:
                        {{ (qualirtData.dcddonateRate * 100).toFixed(2) }}%
                      </el-col>
                      <el-col :span="8" style="text-align: center">
                        DBCD:
                        {{ (qualirtData.dbcddonateRate * 100).toFixed(2) }}%
                      </el-col>
                    </el-row>
                  </el-card>
                </el-col>
              </el-row>
              <el-row :gutter="3" style="margin-top: 5px">
                <el-col :span="12" style="text-align: center; color: #566f94">
                  <el-card
                    shadow="always"
                    style="padding: 0; margin: 0; width: 100%; color: #566f94"
          {{ (qualirtData.dbddonateRate * 100).toFixed(2) }}%</span
                  >
                    <el-row>
                      <span style="font-size: 14px"> èŽ·å–å‰æ´»æ£€çŽ‡</span>
                    </el-row>
                    {{
                      (qualirtData.organBeforeGetCheckRate * 100).toFixed(2)
                    }}%
                  </el-card>
                </el-col>
                <el-col :span="12" style="text-align: center">
                  <el-card
                    shadow="always"
                    style="padding: 0; margin: 0; width: 100%; color: #566f94"
        <span
          >DCD:
          {{ (qualirtData.dcddonateRate * 100).toFixed(2) }}%</span
                  >
                    <el-row>
                      <span style="font-size: 14px">获取后活检率</span>
                    </el-row>
        <span
          >DBCD:
          {{ (qualirtData.dbcddonateRate * 100).toFixed(2) }}%</span
        >
      </div>
    </div>
    <div class="metric-item">
      <div class="metric-title">获取前活检率</div>
      <div class="metric-value">
        {{ (qualirtData.organBeforeGetCheckRate * 100).toFixed(2) }}%
      </div>
    </div>
    <div class="metric-item">
      <div class="metric-title">获取后活检率</div>
      <div class="metric-value">
                    {{ (qualirtData.organAfterGetCheckRate * 100).toFixed(2) }}%
                  </el-card>
                </el-col>
              </el-row>
              <el-row :gutter="3" style="margin-top: 5px">
                <el-col :span="12" style="text-align: center">
                  <el-card
                    shadow="always"
                    style="padding: 0; margin: 0; width: 100%; color: #566f94"
                  >
                    <span style="font-size: 14px">边缘供器官比率</span><br />
      </div>
    </div>
    <div class="metric-item">
      <div class="metric-title">边缘供器官比率</div>
      <div class="metric-value">
                    {{ (qualirtData.marginOrganRate * 100).toFixed(2) }}%
                  </el-card>
                </el-col>
                <el-col :span="12" style="text-align: center">
                  <el-card
                    shadow="always"
                    style="padding: 0; margin: 0; width: 100%; color: #566f94"
                  >
                    <span style="font-size: 14px"
                      >器官保存液病原菌培养阳性率</span
                    ><br />
      </div>
    </div>
    <div class="metric-item">
      <div class="metric-title">器官保存液病原菌培养阳性率</div>
      <div class="metric-value">
                    {{ (qualirtData.germPositiveRate * 100).toFixed(2) }}%
      </div>
    </div>
    <div class="metric-item full-width">
      <div class="metric-title">移植器官原发性无功能发生率</div>
      <div class="metric-breakdown">
        <span
          >总: {{ (qualirtData.totalPNFRate * 100).toFixed(2) }}%</span
        >
        <span
          >DBD: {{ (qualirtData.dbdpnfrate * 100).toFixed(2) }}%</span
        >
        <span
          >DCD: {{ (qualirtData.dcdpnfrate * 100).toFixed(2) }}%</span
        >
        <span
          >DBCD: {{ (qualirtData.dbcdpnfrate * 100).toFixed(2) }}%</span
        >
      </div>
    </div>
    <div class="metric-item full-width">
      <div class="metric-title">移植器官术后功能延迟性恢复发生率</div>
      <div class="metric-breakdown">
        <span
          >总: {{ (qualirtData.totalDGFRate * 100).toFixed(2) }}%</span
        >
        <span
          >DBD: {{ (qualirtData.dbddgfrate * 100).toFixed(2) }}%</span
        >
        <span
          >DCD: {{ (qualirtData.dcddgfrate * 100).toFixed(2) }}%</span
        >
        <span
          >DBCD: {{ (qualirtData.dbcddgfrate * 100).toFixed(2) }}%</span
        >
      </div>
    </div>
  </div>
</div>
                  </el-card>
                </el-col>
              </el-row>
              <el-row :gutter="3" style="margin-top: 5px">
                <el-col :span="24" style="text-align: center">
                  <el-card shadow="always" style="padding: 0; color: #566f94">
                    <el-row> ç§»æ¤å™¨å®˜åŽŸå‘æ€§æ— åŠŸèƒ½å‘ç”ŸçŽ‡ </el-row>
                    <el-row :gutter="10" style="margin-top: 10px">
                      <el-row>
                        <el-col :span="6" style="text-align: center">
                          æ€»å‘生率<br />
                          {{ (qualirtData.totalPNFRate * 100).toFixed(2) }}%
                        </el-col>
                        <el-col :span="6" style="text-align: center">
                          DBD<br />
                          {{ (qualirtData.dbdpnfrate * 100).toFixed(2) }}%
                        </el-col>
                        <el-col :span="6" style="text-align: center">
                          DCD<br />
                          {{ (qualirtData.dcdpnfrate * 100).toFixed(2) }}%
                        </el-col>
                        <el-col :span="6" style="text-align: center">
                          DBCD<br />
                          {{ (qualirtData.dbcdpnfrate * 100).toFixed(2) }}%
                        </el-col>
                      </el-row>
                    </el-row>
                  </el-card>
                </el-col>
              </el-row>
              <el-row :gutter="3" style="margin-top: 5px">
                <el-col :span="24" style="text-align: center">
                  <el-card shadow="always" style="padding: 0; color: #566f94">
                    <el-row> ç§»æ¤å™¨å®˜æœ¯åŽåŠŸèƒ½å»¶è¿Ÿæ€§æ¢å¤å‘ç”ŸçŽ‡ </el-row>
                    <el-row :gutter="10" style="margin-top: 10px">
                      <el-row>
                        <el-col :span="6" style="text-align: center">
                          æ€»å‘生率<br />{{
                            (qualirtData.totalDGFRate * 100).toFixed(2)
                          }}%
                        </el-col>
                        <el-col :span="6" style="text-align: center">
                          DBD<br />{{
                            (qualirtData.dbddgfrate * 100).toFixed(2)
                          }}%
                        </el-col>
                        <el-col :span="6" style="text-align: center">
                          DCD<br />{{
                            (qualirtData.dcddgfrate * 100).toFixed(2)
                          }}%
                        </el-col>
                        <el-col :span="6" style="text-align: center">
                          DBCD<br />{{
                            (qualirtData.dbcddgfrate * 100).toFixed(2)
                          }}%
                        </el-col>
                      </el-row>
                    </el-row>
                  </el-card>
                </el-col>
              </el-row>
            </el-card>
          </el-col>
          <el-col :span="12">
            <el-card shadow="always" style="height: 640px" ref="organChartCard">
      <el-col :xs="24" :lg="12">
        <el-card class="chart-card">
          <template #header>
            <div class="card-header">
              <span>器官数量统计</span>
            </div>
          </template>
              <OrganNumChart :cdata="organData" :CommonOrgan="CommonOrgan" />
            </el-card>
            <!-- <el-col :span="7">
        <el-card shadow="always" style="height: 640px" ref="orgNumberCard">
          <el-row style="margin-bottom: 20px">
            <el-col :span="14">
              <span style="font-size: 18px; color: #566f94; font-weight: bold"
                >各地区医院案例数据</span
              >
            </el-col>
          </el-row>
          <el-row>
          </el-row>
          <dv-scroll-board
            :config="config"
            style="width: 100%; height: 540px"
          />
        </el-card>
      </el-col> -->
          </el-col>
        </el-row>
      </div>
      <div style="width: 24%; margin-top: 10px; padding-left: 10px; ">
        <el-card
          class="box-card"
          style="padding: 0; font-weight: bold; height: 780px; "
        >
          <div slot="header" class="clearfix">
            <span style="font-size: 18px; color: #566f94; font-weight: bold"
              >消息列表</span
            >
            <el-button
              v-if="ReadState == 1"
              style="float: right; padding: 6px "
              type="danger"
              plain
              @click="FnReadState"
              >查看未读消息</el-button
            >
            <el-button
              v-else
              style="float: right; padding: 6px "
              type="info"
              plain
              @click="FnReadState"
              >查看已读消息</el-button
            >
          </div>
          <div style="height: 606px;overflow: auto;">
            <el-table :data="tableData" v-loading="loading" style="width: 100%">
              <el-table-column label="通知日期">
                <template slot-scope="scope">
                  <i class="el-icon-time"></i>
                  <span style="margin-left: 10px">{{
                    scope.row.createTime
                  }}</span>
                </template>
              </el-table-column>
              <el-table-column label="概要">
                <template slot-scope="scope">
                  <el-popover trigger="hover" placement="top">
                    <div class="dialog-class" style="margin: 20px;">
                      <div>{{ scope.row.messagecontent }}</div>
                      <div style=" height: 100px;margin-top: 40px;">
                        <span>{{ "处理人:" + scope.row.sendusername }}</span>
                        <div>{{ "处理时间:" + scope.row.updateTime }}</div>
                      </div>
                      <div style="text-align: right; ; margin: 0">
                        <el-button
                          type="primary"
                          size="mini"
                          @click="clickMessageDetailed(scope.row)"
                          >确定</el-button
                        >
                      </div>
                    </div>
                    <div slot="reference" class="name-wrapper">
                      <el-tag size="medium">{{
                        scope.row.messagetitle
                      }}</el-tag>
                    </div>
                  </el-popover>
                </template>
              </el-table-column>
              <el-table-column label="状态" align="center" prop="paystatus">
                <template slot-scope="scope">
                  <dict-tag
                    :options="dict.type.sys_messagestatus"
                    :value="scope.row.isread"
                  />
                </template>
              </el-table-column>
            </el-table>
          </div>
          <pagination
            v-show="total > 0"
            :total="total"
            :page.sync="searchData.pageNum"
            :limit.sync="searchData.pageSize"
            @pagination="GetMessageList"
          />
        </el-card>
      </div>
    </div>
  </div>
</template>
<script>
import {
  listMedicalevaluation,
  listnewMedicalevaluation, //通过VO获取
  getMedicalevaluation,
  delMedicalevaluation,
  addMedicalevaluation,
  updateMedicalevaluation,
  exportMedicalevaluation
} from "@/api/project/medicalevaluation";
import {
  listRelativesconfirmation,
  getRelativesconfirmation,
  delRelativesconfirmation,
  addRelativesconfirmation,
  updateRelativesconfirmation,
  listnewRelativesconfirmation,
  // exportRelativesconfirmation,
  updatedonatorno,
  updateDonateNumber,
  downloadconfirmationinfo
} from "@/api/project/relativesconfirmation";
import {
  listEthicalreviewopinions,
  getEthicalreviewopinions,
  delEthicalreviewopinions,
  addEthicalreviewopinions,
  updateEthicalreviewopinions,
  listnewEthicalreviewopinions
} from "@/api/project/ethicalreviewopinions";
import {
  getByInfoId,
  listDonationwitness,
  getDonationwitness,
  delDonationwitness,
  addDonationwitness,
  updateDonationwitness,
  listnewDonationwitness,
  downloadwitnessinfo
} from "@/api/project/donationwitness";
import {
  getDonatecompletioninfo,
  listnewDonatecompletioninfo,
  addDonatecompletioninfo,
  updateDonatecompletioninfo,
  listDonatecompletioninfo,
  downloadcompletioninfo
} from "@/api/project/donatecompletioninfo";
import { listOrganallocation } from "@/api/project/organallocation";
import RankChart from "./components/rankbarchart";
import request from '@/utils/request'
import OrganNumChart from "./components/organnumchart";
import { listDonatebaseinfo } from "@/api/project/donatebaseinfo";
import dayjs from "dayjs";
import {
  getOrgansQuality,
  getAllOrganInfo,
  getDonateNumber,
  getcountByRecordState,
  getOrgansOfHospital,
  getNumberOfOrgan,
  getOrgansOfHospitalByMonth,
  getDonateorganSum
} from "@/api/project/donateorgan";
import { getUserProfile } from "@/api/system/user";
import { listDonatebaseinfo } from "@/api/project/donatebaseinfo";
import { listnewMedicalevaluation } from "@/api/project/medicalevaluation";
import { listnewRelativesconfirmation } from "@/api/project/relativesconfirmation";
import { listnewEthicalreviewopinions } from "@/api/project/ethicalreviewopinions";
import { listOrganallocation } from "@/api/project/organallocation";
import { listnewDonationwitness } from "@/api/project/donationwitness";
import { listnewDonatecompletioninfo } from "@/api/project/donatecompletioninfo";
import {
  getDonateorganSum,
  getOrgansOfHospitalByMonth,
  getOrgansQuality
} from "@/api/project/donateorgan";
import OrganNumChart from "./components/organnumchart";
import dayjs from "dayjs";
import {
  listSystemmessageList,
  listSystemmessageCount,
@@ -637,7 +436,6 @@
  name: "home",
  dicts: ["sys_messagestatus"],
  components: {
    RankChart,
    OrganNumChart,
    Li_area_select
  },
@@ -645,13 +443,11 @@
  data() {
    return {
      city: "",
      reportno: "",
      reportervalue: "",
      selecttime: [new Date(new Date().getFullYear(), 0), new Date()],
      year: "选择年份",
      isloading: false,
      maxHeight: 0,
      areaJson: "/project/dict/treeselect", // æå‰å­˜å‚¨åœ°å€æ•°æ®æŽ¥å£
      CommonOrgan: null,
      starttime: dayjs().format("YYYY-01-01 00:00:00"),
      endtime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
      provinceData: [
        { label: "全部地市", value: "" },
        { label: "杭州市", value: "1" },
@@ -666,24 +462,8 @@
        { label: "台州市", value: "A" },
        { label: "丽水市", value: "B" }
      ],
      ReadState: 1,
      searchData: {
        del_flag: 0,
        receiveuserno: "",
        isread: null,
        pageNum: 1,
        pageSize: 10
      },
      total: 0,
      loading: false,
      value: "",
      userID: "",
      //时间选项
      timeoption: "",
      //起始时间
      starttime: this.$moment().format("YYYY-01-01 00:00:00"),
      //结束时间
      endtime: this.$moment().format("YYYY-MM-DD HH:mm:ss"),
      reportlist: [],
      organData: [
        {
@@ -842,54 +622,42 @@
          address: "上海市普陀区金沙江路 1516 å¼„"
        }
      ],
      //统计指标数据
      qualirtData: {
        dbcddgfrate: 0,
        //dbcd捐献分类占比
        dbcddonateRate: 0,
        dbcdpnfrate: 0,
        dbddgfrate: 0,
        //dbd捐献分类占比
        dbddonateRate: 0,
        dbdpnfrate: 0,
        dcddgfrate: 0,
        //dcd捐献分类占比
        dcddonateRate: 0,
        dcddonateRate: 0,
        dcdpnfrate: 0,
        //捐献转化率
        donateTransferRate: 0,
        //病原菌阳性率
        germPositiveRate: 0,
        //边缘器官比率
        marginOrganRate: 0,
        organAfterGetCheckRate: 0,
        organBeforeGetCheckRate: 0,
        //器官产出率
        organProductionRate: 0,
        //器官利用率
        organUsedRate: 0,
        totalDGFRate: 0,
        totalPNFRate: 0
      },
      //捐献累计数量
      donateNumData: {
        //捐献完成数量
        numberOfCompletion: 0,
        //潜在捐献登记数量
        numberOfDonate: 0,
        //伦理审查数量
        numberOfEthicalReview: 0,
        //医学评估数量
        numberOfMedicalEvaluation: 0,
        //器官分配数量
        numberOfOrgans: 0,
        //家属确认数量
        numberOfRelativeConfirmation: 0,
        //获取见证数量
        numberOfWitness: 0,
        //终止数量
        numberOfTerminated: 0
        numberOfTerminated: 0,
        numberOfDonatePeople: 0
      },
      CommonOrgan: {
        countSum: 1,
        abandonCountSum: 0
      },
      config: {
        ...DEF_TABLE_CONFIG
@@ -912,361 +680,181 @@
    this.$nextTick(() => {
      this.GetDonateOrganNum();
      this.GetDonateOrganQuality();
      //  this.GetDonateNum();
      this.value = "杭州市";
      this.GetOrgDonateNumNew();
      this.GetOrgDonateNum();
      this.getAddressData();
    });
  },
  methods: {
    getprovincedata() {},
    // èŽ·å–ç”¨æˆ·ä¿¡æ¯
    GetUser() {
      this.loading = true;
      getUserProfile()
        .then(res => {
          this.searchData.receiveuserno = res.data.userName;
          this.GetMessageList();
          this.userInfo = res.data;
        })
        .catch(error => {
          this.$message.error(error);
          console.error("获取用户信息失败:", error);
        });
    },
    GetMessageList() {
      listSystemmessageList(this.searchData).then(res => {
        if (res.code == 200) {
          this.tableData = res.rows;
          this.loading = false;
          this.total = res.total;
        }
      });
    },
    // æå‰ç¼“存数据
    getAddressData() {
      var that = this;
      request({
        url: that.areaJson,
        method: "get",
      }).then(function (response) {
        if (response.code === 200) {
          //获取地址
          let addressArray = response.data;
          this.$store.commit('updateMyData', addressArray);
        }
      });
    },
    // ç¡®å®šå·²è¯»
    clickMessageDetailed(item) {
      let data = item;
      if (data.isread == 0) {
        item.isread = 1;
        updateSystemmessage(item)
          .then(res => {
            this.$message.success("已读");
            this.GetMessageList();
          })
          .catch(error => {});
      } else {
        this.$message.info("此消息已读");
      }
    },
    // åˆ‡æ¢è¯»å–状态
    FnReadState() {
      if (this.ReadState == 1) {
        this.searchData.isread = 0;
        this.ReadState = 0;
        this.GetMessageList();
      } else {
        this.searchData.isread = 1;
        this.ReadState = 1;
        this.GetMessageList();
      }
    },
    get_unix_time(dateStr) {
      var newstr = dateStr.replace(/-/g, "/");
      var date = new Date(newstr);
      var time_str = date.getTime().toString();
      return time_str.substr(0, 10);
    },
    resetArr(Arr) {
      var hash = {};
      Arr = Arr.reduce(function(arr, current) {
        hash[current.reporterno]
          ? ""
          : (hash[current.reporterno] = true && arr.push(current));
        return arr;
      }, []);
      return Arr;
    // é‡ç½®ç­›é€‰æ¡ä»¶
    resetFilters() {
      this.selecttime = [new Date(new Date().getFullYear(), 0), new Date()];
      this.reportervalue = "";
      this.city = "";
      this.getTimeList();
      this.selectdatas();
    },
    // tobaseinfo0(){
    //   this.$router.push({path:'/Donatebaseinfo', query: {userid: 0 }})
    // },
    // æ—¶é—´é€‰æ‹©å¤„理
    getTimeList(e) {
      if (this.selecttime && this.selecttime.length === 2) {
        this.starttime = this.selecttime[0] + " 00:00:00";
        let endDate = new Date(this.selecttime[1]);
        endDate.setMonth(endDate.getMonth() + 1);
        endDate.setDate(0);
        this.endtime = dayjs(endDate).format("YYYY-MM-DD 23:59:59");
      } else {
        this.starttime = dayjs().format("YYYY-01-01 00:00:00");
        this.endtime = dayjs().format("YYYY-MM-DD HH:mm:ss");
      }
    },
    // æœç´¢æ•°æ®
    selectdatas() {
      this.GetDonateOrganNum();
      this.GetDonateOrganQuality();
      //  this.GetDonateNum();
      this.GetOrgDonateNumNew();
      this.GetOrgDonateNum();
    },
    getTimeList(e) {
      if (this.selecttime != 0) {
        this.endtime = this.selecttime[1];
        this.starttime = this.selecttime[0];
        // if (this.endtime == this.starttime) {
        let num = Number(this.endtime.slice(5, 7));
        if (num < 9) {
          let mon = Number(this.endtime.slice(6, 7));
          this.endtime =
            this.endtime.slice(0, 5) +
            "0" +
            (mon + 1) +
            "-" +
            "01" +
            " " +
            "00" +
            ":" +
            "00" +
            ":" +
            "00";
        }
        // this.endtime=this.endtime.slice(0,5)å¹´
        else if (num >= 10) {
          this.endtime =
            this.endtime.slice(0, 5) +
            (num + 1) +
            "-" +
            "01" +
            " " +
            "00" +
            ":" +
            "00" +
            ":" +
            "00";
        } else {
          this.endtime =
            this.endtime.slice(0, 5) +
            "10" +
            "-" +
            "01" +
            " " +
            "00" +
            ":" +
            "00" +
            ":" +
            "00";
        }
        this.starttime = this.starttime + " " + "00" + ":" + "00" + ":" + "00";
        // }
      } else {
        this.starttime = "1998-01-01 00:00:00";
        this.endtime = "2998-01-01 00:00:00";
      }
    },
    Tobaseinfo() {
      this.$router.push("../../donatebaseinfo/index.vue");
    },
    Tomedicalevalua() {
      this.$router.push("../../medicalevaluation/index.vue");
    },
    getyearvalue() {
      console.log("year de  value:", this.year);
    },
    handlerInput(e) {
      console.log("全省导览当前所选年份:", e);
    },
    //获取器官捐献数量
    // èŽ·å–å™¨å®˜æ•°é‡ç»Ÿè®¡
    GetDonateOrganNum() {
      let param = {
        starttime: this.starttime,
        endtime: this.endtime,
        city: this.city
        // repoterno:'015'
      };
      if (this.reportervalue != "") {
      if (this.reportervalue) {
        param.reporterno = this.reportervalue;
      }
      console.log(param, "param");
      getDonateorganSum(param).then(response => {
        /*
        let list = this.organData.map((item) => item);
        for (let i = 0; i < list.length; i++) {
          let k = list[i].key;
        }
        this.organData = list;
      */
        let list = response.data.organInfoVOList;
        this.CommonOrgan = response.data;
        for (let i = 0; i < this.organData.length; i++) {
          let ii = list.findIndex(
            item => item.organNo == this.organData[i].code
          );
          if (ii > -1) {
            this.organData[i].value = list[ii].count;
            this.organData[i].value1 = list[ii].abandonCount;
          }
        }
      });
    },
    //获取指标监控数据
    GetDonateOrganQuality() {
      let starttime = this.selecttime.length > 0 ? this.selecttime[0] : "";
      let endtime =
        this.selecttime.length > 0
          ? this.$moment(this.selecttime[1])
              .add(1, "month")
              .add(-1, "days")
              .format("YYYY-MM-DD")
          : "";
      let param = {
        starttime: this.starttime,
        endtime: this.endtime,
        city: this.city
        // repoterno:'015'
      };
      getOrgansQuality(param).then(response => {
        if (response.code == 200) {
          this.qualirtData = response.data;
        } else {
          console.log("获取指标监控数据失败!");
        }
      });
    },
    //获取累计捐献信息数据
    GetDonateNum() {
      let param = {
        pageNum: 1,
        pageSize: 10,
        starttime: this.starttime,
        endtime: this.endtime,
        reportno: this.reportervalue,
        city: this.city
        // residenceprovince: this.$refs.areaSelect.getSheng(),
        // residencecity: this.$refs.areaSelect.getShi(),
        // residencetown: this.$refs.areaSelect.getQu(),
      };
      // getcountByRecordState(param).then(res=>{
      //   console.log('dawdwadwadwad',res);
      //    if (res.code == 200) {
      //     this.donateNumData = res.data;
      //     this.donateNumData.numberOfDonatePeople =
      //       res.data.numberOfDonatePeople;
      //     console.log("this.donateNumData", this.donateNumData);
      //   } else {
      //   }
      // })
      // getDonateNumber;
      // getDonateNumber(param).then((response) => {
      //   console.log("获取累计捐献信息数据", response.code, response.data);
      //   if (response.code == 200) {
      //     //先注销的数据
      //     // this.donateNumData = response.data;
      //     this.donateNumData.numberOfDonate = response.data.numberOfDonate;
      //     this.donateNumData.numberOfMedicalEvaluation=response.data.numberOfMedicalEvaluation;
      //     this.donateNumData.numberOfRelativeConfirmation=response.data.numberOfRelativeConfirmation;
      //     this.donateNumData.numberOfEthicalReview=response.data.numberOfEthicalReview;
      //     this.donateNumData.numberOfWitness=response.data.numberOfWitness;
      //     this.donateNumData.numberOfCompletion=response.data.numberOfCompletion;
      //     this.donateNumData.numberOfTerminated =
      //       response.data.numberOfTerminated;
      //     this.donateNumData.numberOfDonatePeople =
      //       response.data.numberOfDonatePeople;
      //     console.log("this.donateNumData", this.donateNumData);
      //   } else {
        if (response.code === 200) {
          // this.CommonOrgan = response.data || {
          //   countSum: 1,
          //   abandonCountSum: 0
          // };
          // let list = response.data.organInfoVOList || [];
          // this.organData.forEach(item => {
          //   const found = list.find(organ => organ.organNo === item.code);
          //   if (found) {
          //     item.value = found.count || 0;
          //     item.value1 = found.abandonCount || 0;
      //   }
      // });
        }
      });
    },
    GetOrgDonateNumNew() {
      // let starttime = this.selecttime.length > 0 ? this.$moment(this.selecttime[0]).format("YYYY-MM-DD 00:00:01") : "";
      // let endtime =
      //   this.selecttime.length > 0
      //     ? this.$moment(this.selecttime[1])
      //         .add(1, "month")
      //         .add(-1, "days")
      //         .format("YYYY-MM-DD")
      //     : "";
      let info = {
    // èŽ·å–è´¨é‡æŒ‡æ ‡æ•°æ®
    GetDonateOrganQuality() {
      let param = {
        starttime: this.starttime,
        endtime: this.endtime,
        city: this.city
      };
      getOrgansQuality(param).then(response => {
        if (response.code === 200) {
          this.qualirtData = response.data;
        }
      });
    },
    // èŽ·å–ç»Ÿè®¡æ•°æ®
    GetOrgDonateNumNew() {
      const info = {
        starttime: this.starttime,
        endtime: this.endtime
        // residenceprovince: this.$refs.areaSelect.getSheng(),
        // residencecity: this.$refs.areaSelect.getShi(),
        // residencetown: this.$refs.areaSelect.getQu(),
      };
      if (this.reportervalue != "") {
      if (this.reportervalue) {
        info.reporterno = this.reportervalue;
      }
      if (this.city != "") {
      if (this.city) {
        info.city = this.city;
      }
      //潜在捐献
      // å¹¶è¡ŒèŽ·å–æ‰€æœ‰ç»Ÿè®¡æ•°æ®
      Promise.all([
      listDonatebaseinfo(info).then(res => {
        this.donateNumData.numberOfDonate = res.total;
      });
          this.donateNumData.numberOfDonate = res.total || 0;
        }),
      //医学评估
      listnewMedicalevaluation(info).then(res => {
        this.donateNumData.numberOfMedicalEvaluation = res.total;
          this.donateNumData.numberOfMedicalEvaluation = res.total || 0;
      }),
        //亲属确认
        listnewRelativesconfirmation(info).then(res => {
          this.donateNumData.numberOfRelativeConfirmation = res.total;
        });
      //伦理审查
      listnewEthicalreviewopinions(info).then(res => {
        this.donateNumData.numberOfEthicalReview = res.total;
      }),
        //器官捐献
        listOrganallocation(info).then(res => {
          this.donateNumData.numberOfDonatePeople = res.total;
        });
      //获取见证
        listnewRelativesconfirmation(info).then(res => {
          this.donateNumData.numberOfRelativeConfirmation = res.total || 0;
        }),
        listnewEthicalreviewopinions(info).then(res => {
          this.donateNumData.numberOfEthicalReview = res.total || 0;
        }),
        listOrganallocation(info).then(res => {
          this.donateNumData.numberOfDonatePeople = res.total || 0;
        }),
      listnewDonationwitness(info).then(res => {
        this.donateNumData.numberOfWitness = res.total;
      });
          this.donateNumData.numberOfWitness = res.total || 0;
        }),
      listnewDonatecompletioninfo(info).then(res => {
        this.donateNumData.numberOfCompletion = res.total;
      });
          this.donateNumData.numberOfCompletion = res.total || 0;
        }),
      //终止
      info.terminationCase = 1;
      listDonatebaseinfo(info).then(res => {
        this.donateNumData.numberOfTerminated = res.total;
        listDonatebaseinfo({ ...info, terminationCase: 1 }).then(res => {
          this.donateNumData.numberOfTerminated = res.total || 0;
        })
      ]).then(() => {
        this.loadReportList();
      });
    },
    // åŠ è½½æŠ¥å‘Šäººåˆ—è¡¨
    loadReportList() {
      listDonatebaseinfo({}).then(res => {
        let list = res.rows;
        let reportlist = [];
        reportlist.push({ reporterno: "", reportername: "全部人员" });
        let list = res.rows || [];
        let reportlist = [{ reporterno: "", reportername: "全部人员" }];
        list.forEach(element => {
          if (element.reporterno && element.reportername) {
          reportlist.push({
            reporterno: element.reporterno,
            reportername: element.reportername
          });
        });
        if (reportlist != 0) {
          reportlist = this.resetArr(reportlist);
          this.reportlist = reportlist;
        }
      });
        this.reportlist = this.resetArr(reportlist);
      });
    },
    // æ•°ç»„去重
    resetArr(Arr) {
      const hash = {};
      return Arr.reduce((arr, current) => {
        if (!hash[current.reporterno]) {
          hash[current.reporterno] = true;
          arr.push(current);
        }
        return arr;
      }, []);
    },
    //获取医院机构捐献数量
    GetOrgDonateNum() {
      // let time1 =  new Date(this.starttime).getTime()
@@ -1343,83 +931,299 @@
      // this.$tab.closePage(obj);
    }
  },
  computed: {},
  computed: {
    routeParams() {
      return {
        starttime: this.starttime,
        endtime: this.endtime,
        tempRecordState: "",
        reporterno: this.reportervalue,
        shen: this.searchAddress?.shen || "",
        shi: this.searchAddress?.shi || "",
        qu: this.searchAddress?.qu || "",
        city: this.city
      };
    }
  },
  watch: {}
};
</script>
<style lang="scss" scoped>
.c-home {
  .box-title {
    width: 100%;
    span {
      display: block;
      width: 130px;
      height: 25px;
      -webkit-transform: skew(20deg);
      -moz-transform: skew(20deg);
      -o-transform: skew(20deg);
      background: #0a459f;
      line-height: 25px;
      align-self: center;
      border: 1px transparent solid;
      border-image: linear-gradient(#070a17, #7be6fc) 10 10;
      border-image: linear-gradient(#070a17, #7be6fc) 10 10;
      border-image: linear-gradient(#070a17, #7be6fc) 10 10;
      margin: 0 auto;
.app-container {
  padding: 20px;
  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
  min-height: 100vh;
    }
    b {
      display: block;
      color: #fff;
      text-align: center;
      transform: skewY(-20deg);
      transform: skewX(-20deg);
.filter-card {
  margin-bottom: 24px;
  border-radius: 12px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
  border: none;
  background: rgba(255, 255, 255, 0.95);
  :deep(.el-card__body) {
    padding: 20px;
    }
  }
  .box-num {
    position: relative;
    .box-num-main {
      text-align: right;
      padding-right: 70px;
      .box-num-main-n {
        color: #409eff;
        font-size: 25px;
.overview-card {
  margin-bottom: 24px;
  border-radius: 12px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
  border: none;
  background: rgba(255, 255, 255, 0.95);
  .card-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    .header-title {
      font-size: 18px;
      font-weight: 600;
      color: #303133;
    }
    .header-subtitle {
      font-size: 14px;
      color: #909399;
      }
    }
    .box-num-ex {
      position: absolute;
      bottom: 5px;
      right: 10px;
      width: 45px;
  :deep(.el-card__body) {
    padding: 20px;
  }
}
.metrics-wrapper {     // å·¦ä¾§å†…容区域固定 320px,溢出自动滚动
  height: 590px;       // å’Œå³ä¾§å›¾è¡¨é»˜è®¤é«˜ä¸€æ ·ï¼Œä¹Ÿå¯ä»¥æ”¹æˆ 350 / 400 â€¦
  overflow-y: auto;
  padding-right: 4px;  // ç•™ä¸€ç‚¹æ»šåŠ¨æ¡ä½ç½®ï¼Œé¿å…æ–‡å­—è´´è¾¹
}
.chart-card {
  border-radius: 12px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
  border: none;
  background: rgba(255, 255, 255, 0.95);
  height: 100%;
  .card-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
      span {
        color: #409eff;
      font-size: 16px;
      font-weight: 600;
      color: #303133;
    }
  }
  :deep(.el-card__body) {
    padding: 20px;
  }
}
.stat-card-link {
  text-decoration: none;
  display: block;
  &:hover {
    text-decoration: none;
  }
}
.stat-card {
  border-radius: 8px;
  transition: all 0.3s ease;
  border: none;
  margin-bottom: 16px;
  background: linear-gradient(135deg, #fff 60%, #f8f9fa 100%);
  &:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1);
  }
  .stat-content {
    display: flex;
    align-items: center;
    padding: 16px;
  }
  .stat-icon {
    width: 48px;
    height: 48px;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-right: 12px;
    .svg-icon {
      font-size: 24px;
      color: white;
    }
  }
  .stat-info {
    flex: 1;
    .stat-value {
      font-size: 24px;
      font-weight: bold;
      color: #303133;
      margin-bottom: 4px;
    }
    .stat-title {
      font-size: 14px;
      color: #606266;
      line-height: 1.4;
    }
  }
}
.metrics-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
  margin-top: 16px;
}
.metric-item {
  background: linear-gradient(135deg, #fafdff 0%, #e3f0ff 100%);
  border-radius: 8px;
  padding: 16px;
  text-align: center;
  transition: all 0.3s ease;
  &:hover {
    transform: translateY(-1px);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  }
  &.full-width {
    grid-column: 1 / -1;
  }
  .metric-title {
    font-size: 12px;
    color: #606266;
    margin-bottom: 8px;
    font-weight: 500;
  }
  .metric-value {
    font-size: 18px;
    font-weight: bold;
    color: #303133;
  }
  .metric-breakdown {
    display: flex;
    justify-content: space-around;
    flex-wrap: wrap;
    gap: 8px;
    span {
      font-size: 12px;
      color: #606266;
      background: rgba(255, 255, 255, 0.7);
      padding: 4px 8px;
      border-radius: 4px;
    }
  }
}
.action-buttons {
  display: flex;
  gap: 12px;
  justify-content: flex-end;
  @media (max-width: 768px) {
    justify-content: stretch;
    .el-button {
      flex: 1;
    }
  }
}
.analysis-section {
  margin-top: 24px;
}
// å“åº”式调整
@media (max-width: 1200px) {
  .metrics-grid {
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  }
}
@media (max-width: 768px) {
  .app-container {
    padding: 12px;
  }
  .filter-card,
  .overview-card,
  .chart-card {
    margin-bottom: 16px;
    :deep(.el-card__body) {
      padding: 16px;
    }
  }
  .stat-card .stat-content {
    padding: 12px;
    .stat-icon {
      width: 40px;
      height: 40px;
      margin-right: 8px;
      .svg-icon {
        font-size: 20px;
      }
    }
    .stat-info {
      .stat-value {
        font-size: 20px;
      }
      .stat-title {
        font-size: 12px;
      }
    }
  }
  .metrics-grid {
    grid-template-columns: 1fr;
    gap: 12px;
}
::v-deep .c-table-title {
  .el-divider.el-divider--horizontal {
    background-color: #95a1ec;
    .el-divider__text.is-left {
      color: #303133;
      background: #fafafa;
    }
  }
  .active {
    .el-divider.el-divider--horizontal {
      .el-divider__text.is-left {
        color: #409eff;
  .metric-item {
    padding: 12px;
    .metric-value {
      font-size: 16px;
      }
    }
  }
// åŠ¨ç”»æ•ˆæžœ
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s ease;
}
.border-box-contaier {
  height: 90px;
  padding: 10px;
  overflow: hidden;
  box-sizing: border-box;
  // background-color: #282c34;
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
</style>
src/views/register.vue
@@ -1,7 +1,7 @@
<template>
  <div class="register">
    <el-form ref="registerForm" :model="registerForm" :rules="registerRules" class="register-form">
      <h3 class="title">浙江省OPO数字化管理平台</h3>
      <h3 class="title">青岛大学附属医院opo</h3>
      <el-form-item prop="username">
        <el-input v-model="registerForm.username" type="text" auto-complete="off" placeholder="账号">
          <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
vue.config.js
@@ -33,8 +33,8 @@
    proxy: {
      // detail: https://cli.vuejs.org/config/#devserver-proxy
      [process.env.VUE_APP_BASE_API]: {
        // target:`http://localhost:8080`,
        target:`http://192.168.100.10:8080`,
        target:`http://localhost:8080`,
        // target:`http://192.168.100.10:8080`,
        // target:`http://192.168.100.137:8080`,
        // target: `https://slb.hospitalstar.com:9093`,
        changeOrigin: true,