WXL (wul)
4 小时以前 01d3b0dd65574a8b6ff6ff66b0474f2de82daa6a
测试完成
已修改6个文件
1305 ■■■■ 文件已修改
src/views/Satisfaction/configurationmyd/batch.vue 337 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/Satisfaction/configurationmyd/components/DetailsAnomaly.vue 923 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/Satisfaction/sfstatistics/components/SatisfactionStatistics.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/record/detailpage/index.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/satisfaction/index.vue 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vue.config.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/Satisfaction/configurationmyd/batch.vue
@@ -14,11 +14,7 @@
          >
            批量提交处理
          </el-button>
          <el-button
            type="warning"
            icon="el-icon-back"
            @click="handleGoBack"
          >
          <el-button type="warning" icon="el-icon-back" @click="handleGoBack">
            返回异常列表
          </el-button>
        </div>
@@ -70,10 +66,7 @@
              >
                筛选
              </el-button>
              <el-button
                icon="el-icon-refresh"
                @click="handleResetFilter"
              >
              <el-button icon="el-icon-refresh" @click="handleResetFilter">
                重置
              </el-button>
            </el-form-item>
@@ -88,11 +81,7 @@
          @selection-change="handleSelectionChange"
          class="exception-table"
        >
          <el-table-column
            type="selection"
            width="55"
            align="center"
          />
          <el-table-column type="selection" width="55" align="center" />
          <el-table-column
            label="序号"
@@ -125,11 +114,7 @@
            </template>
          </el-table-column>
          <el-table-column
            label="患者信息"
            width="300"
            align="center"
          >
          <el-table-column label="患者信息" width="300" align="center">
            <template slot-scope="{ row }">
              <div class="patient-info">
                <div class="patient-item">
@@ -138,7 +123,9 @@
                </div>
                <div class="patient-item">
                  <span class="label">性别:</span>
                  <span class="value">{{ row.gender === 1 ? '男' : '女' }}</span>
                  <span class="value">{{
                    row.gender === 1 ? "男" : "女"
                  }}</span>
                </div>
                <div class="patient-item">
                  <span class="label">年龄:</span>
@@ -152,11 +139,7 @@
            </template>
          </el-table-column>
          <el-table-column
            label="出院信息"
            width="250"
            align="center"
          >
          <el-table-column label="出院信息" width="250" align="center">
            <template slot-scope="{ row }">
              <div class="discharge-info">
                <div class="info-item">
@@ -182,10 +165,7 @@
            align="center"
          >
            <template slot-scope="{ row }">
              <el-tag
                :type="getStatusTagType(row.processStatus)"
                effect="dark"
              >
              <el-tag :type="getStatusTagType(row.processStatus)" effect="dark">
                {{ getStatusText(row.processStatus) }}
              </el-tag>
            </template>
@@ -193,7 +173,7 @@
          <el-table-column
            label="操作"
            width="180"
            width="210"
            align="center"
            fixed="right"
          >
@@ -302,17 +282,15 @@
            :file-list="fileList"
          >
            <el-button size="small" type="primary">点击上传</el-button>
            <div slot="tip" class="el-upload__tip">支持上传图片、文档等附件,单个文件不超过10MB</div>
            <div slot="tip" class="el-upload__tip">
              支持上传图片、文档等附件,单个文件不超过10MB
            </div>
          </el-upload>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="processDialogVisible = false">取消</el-button>
        <el-button
          type="primary"
          @click="submitProcess"
          :loading="processing"
        >
        <el-button type="primary" @click="submitProcess" :loading="processing">
          提交处理
        </el-button>
      </span>
@@ -384,14 +362,31 @@
        </el-button>
      </span>
    </el-dialog>
    <!-- 异常详情弹框 -->
    <Details-anomaly
      :visible="detailDialogVisible"
      :record-id="selectedRecordId"
      :title="detailDialogTitle"
      @update:visible="handleDetailDialogClose"
      @processed="handleProcessed"
      @close="handleDetailDialogClose"
    />
  </div>
</template>
<script>
import DetailsAnomaly from "./components/DetailsAnomaly.vue";
export default {
  name: 'BatchProcess',
  name: "BatchProcess",
  components: {
    DetailsAnomaly,
  },
  data() {
    return {
      // 添加以下数据
      detailDialogVisible: false,
      selectedRecordId: null,
      detailDialogTitle: "异常反馈详情",
      // 当前处理的异常ID
      currentExceptionId: null,
@@ -400,10 +395,10 @@
      // 过滤参数
      filterParams: {
        deptId: '',
        status: '',
        deptId: "",
        status: "",
        pageNum: 1,
        pageSize: 10
        pageSize: 10,
      },
      // 加载状态
@@ -413,16 +408,16 @@
      // 科室列表
      deptList: [
        { id: 1, name: '心血管内科' },
        { id: 2, name: '神经内科' },
        { id: 3, name: '普外科' },
        { id: 4, name: '骨科' },
        { id: 5, name: '妇产科' },
        { id: 6, name: '儿科' },
        { id: 7, name: '急诊科' },
        { id: 8, name: '呼吸内科' },
        { id: 9, name: '消化内科' },
        { id: 10, name: '内分泌科' }
        { id: 1, name: "心血管内科" },
        { id: 2, name: "神经内科" },
        { id: 3, name: "普外科" },
        { id: 4, name: "骨科" },
        { id: 5, name: "妇产科" },
        { id: 6, name: "儿科" },
        { id: 7, name: "急诊科" },
        { id: 8, name: "呼吸内科" },
        { id: 9, name: "消化内科" },
        { id: 10, name: "内分泌科" },
      ],
      // 异常列表数据
@@ -432,28 +427,33 @@
      // 处理对话框
      processDialogVisible: false,
      processForm: {
        status: '',
        status: "",
        reportDepts: [],
        remark: ''
        remark: "",
      },
      processRules: {
        status: [
          { required: true, message: '请选择处理状态', trigger: 'change' }
          { required: true, message: "请选择处理状态", trigger: "change" },
        ],
        remark: [
          { required: true, message: '请输入处理备注', trigger: 'blur' },
          { min: 5, max: 500, message: '备注长度在 5 到 500 个字符', trigger: 'blur' }
        ]
          { required: true, message: "请输入处理备注", trigger: "blur" },
          {
            min: 5,
            max: 500,
            message: "备注长度在 5 到 500 个字符",
            trigger: "blur",
          },
        ],
      },
      fileList: [],
      // 批量处理对话框
      batchDialogVisible: false,
      batchProcessForm: {
        status: '',
        status: "",
        reportDepts: [],
        remark: ''
      }
        remark: "",
      },
    };
  },
@@ -467,121 +467,125 @@
      this.loading = true;
      try {
        // Mock 数据
        await new Promise(resolve => {
        await new Promise((resolve) => {
          setTimeout(() => {
            this.exceptionList = [
              {
                id: 1,
                responsibilityDept: '心血管内科',
                unsatisfactoryDetail: '医生查房时间太短,沟通不够充分,对病情解释不够详细',
                patientName: '张先生',
                responsibilityDept: "心血管内科",
                unsatisfactoryDetail:
                  "医生查房时间太短,沟通不够充分,对病情解释不够详细",
                patientName: "张先生",
                gender: 1,
                age: 45,
                phone: '138****1234',
                dischargeDept: '心血管内科',
                dischargeWard: '内科一病区',
                fillTime: '2024-01-15 10:30:25',
                phone: "138****1234",
                dischargeDept: "心血管内科",
                dischargeWard: "内科一病区",
                fillTime: "2024-01-15 10:30:25",
                processStatus: 0,
                questionnaireId: 1001
                questionnaireId: 1001,
              },
              {
                id: 2,
                responsibilityDept: '神经内科',
                unsatisfactoryDetail: '护士打针技术不佳,扎了三次才成功,且态度不够耐心',
                patientName: '李女士',
                responsibilityDept: "神经内科",
                unsatisfactoryDetail:
                  "护士打针技术不佳,扎了三次才成功,且态度不够耐心",
                patientName: "李女士",
                gender: 0,
                age: 38,
                phone: '139****5678',
                dischargeDept: '神经内科',
                dischargeWard: '内科二病区',
                fillTime: '2024-01-14 16:20:10',
                phone: "139****5678",
                dischargeDept: "神经内科",
                dischargeWard: "内科二病区",
                fillTime: "2024-01-14 16:20:10",
                processStatus: 0,
                questionnaireId: 1002
                questionnaireId: 1002,
              },
              {
                id: 3,
                responsibilityDept: '普外科',
                unsatisfactoryDetail: '术后换药不及时,伤口疼痛时没有及时处理',
                patientName: '王先生',
                responsibilityDept: "普外科",
                unsatisfactoryDetail: "术后换药不及时,伤口疼痛时没有及时处理",
                patientName: "王先生",
                gender: 1,
                age: 52,
                phone: '137****9012',
                dischargeDept: '普外科',
                dischargeWard: '外科一病区',
                fillTime: '2024-01-13 09:15:45',
                phone: "137****9012",
                dischargeDept: "普外科",
                dischargeWard: "外科一病区",
                fillTime: "2024-01-13 09:15:45",
                processStatus: 1,
                questionnaireId: 1003
                questionnaireId: 1003,
              },
              {
                id: 4,
                responsibilityDept: '骨科',
                unsatisfactoryDetail: '康复指导不够专业,对恢复过程描述不清楚',
                patientName: '刘女士',
                responsibilityDept: "骨科",
                unsatisfactoryDetail: "康复指导不够专业,对恢复过程描述不清楚",
                patientName: "刘女士",
                gender: 0,
                age: 65,
                phone: '136****3456',
                dischargeDept: '骨科',
                dischargeWard: '外科二病区',
                fillTime: '2024-01-12 14:40:30',
                phone: "136****3456",
                dischargeDept: "骨科",
                dischargeWard: "外科二病区",
                fillTime: "2024-01-12 14:40:30",
                processStatus: 0,
                questionnaireId: 1004
                questionnaireId: 1004,
              },
              {
                id: 5,
                responsibilityDept: '妇产科',
                unsatisfactoryDetail: '产前检查排队时间过长,等待期间没有休息座位',
                patientName: '陈女士',
                responsibilityDept: "妇产科",
                unsatisfactoryDetail:
                  "产前检查排队时间过长,等待期间没有休息座位",
                patientName: "陈女士",
                gender: 0,
                age: 28,
                phone: '135****7890',
                dischargeDept: '妇产科',
                dischargeWard: '妇产科病区',
                fillTime: '2024-01-11 11:25:15',
                phone: "135****7890",
                dischargeDept: "妇产科",
                dischargeWard: "妇产科病区",
                fillTime: "2024-01-11 11:25:15",
                processStatus: 2,
                questionnaireId: 1005
                questionnaireId: 1005,
              },
              {
                id: 6,
                responsibilityDept: '儿科',
                unsatisfactoryDetail: '儿童用药剂量交代不清晰,用药注意事项没有说明',
                patientName: '赵宝宝',
                responsibilityDept: "儿科",
                unsatisfactoryDetail:
                  "儿童用药剂量交代不清晰,用药注意事项没有说明",
                patientName: "赵宝宝",
                gender: 1,
                age: 5,
                phone: '134****1234',
                dischargeDept: '儿科',
                dischargeWard: '儿科病区',
                fillTime: '2024-01-10 15:50:20',
                phone: "134****1234",
                dischargeDept: "儿科",
                dischargeWard: "儿科病区",
                fillTime: "2024-01-10 15:50:20",
                processStatus: 0,
                questionnaireId: 1006
                questionnaireId: 1006,
              },
              {
                id: 7,
                responsibilityDept: '急诊科',
                unsatisfactoryDetail: '急诊等待时间过长,病情没有得到及时评估',
                patientName: '孙先生',
                responsibilityDept: "急诊科",
                unsatisfactoryDetail: "急诊等待时间过长,病情没有得到及时评估",
                patientName: "孙先生",
                gender: 1,
                age: 40,
                phone: '133****5678',
                dischargeDept: '急诊科',
                dischargeWard: '急诊病区',
                fillTime: '2024-01-09 10:15:40',
                phone: "133****5678",
                dischargeDept: "急诊科",
                dischargeWard: "急诊病区",
                fillTime: "2024-01-09 10:15:40",
                processStatus: 0,
                questionnaireId: 1007
                questionnaireId: 1007,
              },
              {
                id: 8,
                responsibilityDept: '呼吸内科',
                unsatisfactoryDetail: '医生开药较多,费用较高,没有说明必要性',
                patientName: '周女士',
                responsibilityDept: "呼吸内科",
                unsatisfactoryDetail: "医生开药较多,费用较高,没有说明必要性",
                patientName: "周女士",
                gender: 0,
                age: 55,
                phone: '132****9012',
                dischargeDept: '呼吸内科',
                dischargeWard: '内科一病区',
                fillTime: '2024-01-08 13:30:55',
                phone: "132****9012",
                dischargeDept: "呼吸内科",
                dischargeWard: "内科一病区",
                fillTime: "2024-01-08 13:30:55",
                processStatus: 1,
                questionnaireId: 1008
              }
                questionnaireId: 1008,
              },
            ];
            this.total = this.exceptionList.length;
            resolve();
@@ -595,20 +599,28 @@
    // 获取状态标签类型
    getStatusTagType(status) {
      switch (status) {
        case 0: return 'warning'; // 待处理
        case 1: return 'primary'; // 处理中
        case 2: return 'success'; // 已处理
        default: return 'info';
        case 0:
          return "warning"; // 待处理
        case 1:
          return "primary"; // 处理中
        case 2:
          return "success"; // 已处理
        default:
          return "info";
      }
    },
    // 获取状态文本
    getStatusText(status) {
      switch (status) {
        case 0: return '待处理';
        case 1: return '处理中';
        case 2: return '已处理';
        default: return '未知';
        case 0:
          return "待处理";
        case 1:
          return "处理中";
        case 2:
          return "已处理";
        default:
          return "未知";
      }
    },
@@ -621,23 +633,23 @@
    // 重置筛选
    handleResetFilter() {
      this.filterParams = {
        deptId: '',
        status: '',
        deptId: "",
        status: "",
        pageNum: 1,
        pageSize: 10
        pageSize: 10,
      };
      this.loadExceptionList();
    },
    // 处理选择变化
    handleSelectionChange(selection) {
      this.selectedExceptionIds = selection.map(item => item.id);
      this.selectedExceptionIds = selection.map((item) => item.id);
    },
    // 处理批量提交
    handleBatchSubmit() {
      if (this.selectedExceptionIds.length === 0) {
        this.$message.warning('请先选择要处理的异常反馈');
        this.$message.warning("请先选择要处理的异常反馈");
        return;
      }
      this.batchDialogVisible = true;
@@ -645,26 +657,31 @@
    // 返回异常列表
    handleGoBack() {
      this.$router.push('/satisfaction/exception/list');
      this.$router.push("/satisfaction/exception/list");
    },
    // 查看详情
    handleViewDetail(row) {
      this.$router.push({
        path: '/satisfaction/exception/detail',
        query: {
          id: row.questionnaireId
        }
      });
      this.selectedRecordId = row.id;
      this.detailDialogTitle = `${row.patientName} - 异常反馈详情`;
      this.detailDialogVisible = true;
    },
    // 处理详情弹框关闭
    handleDetailDialogClose() {
      this.detailDialogVisible = false;
      this.selectedRecordId = null;
    }, // 处理完成后的回调
    handleProcessed() {
      // 重新加载数据
      this.loadExceptionList();
    },
    // 处理单个异常
    handleProcess(row) {
      this.currentExceptionId = row.id;
      this.processForm = {
        status: row.processStatus === 0 ? 1 : row.processStatus,
        reportDepts: [],
        remark: ''
        remark: "",
      };
      this.processDialogVisible = true;
    },
@@ -676,9 +693,9 @@
          this.processing = true;
          try {
            // Mock API调用
            await new Promise(resolve => setTimeout(resolve, 1000));
            await new Promise((resolve) => setTimeout(resolve, 1000));
            this.$message.success('处理提交成功');
            this.$message.success("处理提交成功");
            this.processDialogVisible = false;
            this.loadExceptionList();
          } finally {
@@ -695,9 +712,11 @@
          this.batchProcessing = true;
          try {
            // Mock API调用
            await new Promise(resolve => setTimeout(resolve, 1500));
            await new Promise((resolve) => setTimeout(resolve, 1500));
            this.$message.success(`已批量处理 ${this.selectedExceptionIds.length} 条异常反馈`);
            this.$message.success(
              `已批量处理 ${this.selectedExceptionIds.length} 条异常反馈`
            );
            this.batchDialogVisible = false;
            this.selectedExceptionIds = [];
            this.loadExceptionList();
@@ -723,11 +742,11 @@
    // 文件上传相关方法
    handlePreview(file) {
      console.log('预览文件:', file);
      console.log("预览文件:", file);
    },
    handleRemove(file, fileList) {
      console.log('移除文件:', file, fileList);
      console.log("移除文件:", file, fileList);
    },
    beforeRemove(file) {
@@ -735,9 +754,13 @@
    },
    handleExceed(files, fileList) {
      this.$message.warning(`当前限制选择 3 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`);
    }
  }
      this.$message.warning(
        `当前限制选择 3 个文件,本次选择了 ${files.length} 个文件,共选择了 ${
          files.length + fileList.length
        } 个文件`
      );
    },
  },
};
</script>
@@ -750,7 +773,7 @@
  .page-header {
    margin-bottom: 20px;
    padding: 20px;
    background: linear-gradient(135deg, #5788FE 0%, #66b1ff 100%);
    background: linear-gradient(135deg, #5788fe 0%, #66b1ff 100%);
    border-radius: 8px;
    color: white;
src/views/Satisfaction/configurationmyd/components/DetailsAnomaly.vue
@@ -0,0 +1,923 @@
<template>
  <el-dialog
    :title="title"
    :visible.sync="dialogVisible"
    width="900px"
    top="5vh"
    class="exception-detail-dialog"
    @close="handleClose"
  >
    <!-- 基本信息 -->
    <div class="info-section">
      <div class="section-title">基本信息</div>
      <el-row :gutter="20">
        <el-col :span="8">
          <div class="info-item">
            <span class="label">患者姓名:</span>
            <span class="value">{{ currentRecord.patientName }}</span>
          </div>
        </el-col>
        <el-col :span="8">
          <div class="info-item">
            <span class="label">性别:</span>
            <span class="value">{{ currentRecord.gender === 1 ? '男' : '女' }}</span>
          </div>
        </el-col>
        <el-col :span="8">
          <div class="info-item">
            <span class="label">年龄:</span>
            <span class="value">{{ currentRecord.age }}岁</span>
          </div>
        </el-col>
        <el-col :span="8">
          <div class="info-item">
            <span class="label">联系方式:</span>
            <span class="value">{{ currentRecord.phone }}</span>
          </div>
        </el-col>
        <el-col :span="8">
          <div class="info-item">
            <span class="label">出院科室:</span>
            <span class="value">{{ currentRecord.dischargeDept }}</span>
          </div>
        </el-col>
        <el-col :span="8">
          <div class="info-item">
            <span class="label">出院病区:</span>
            <span class="value">{{ currentRecord.dischargeWard }}</span>
          </div>
        </el-col>
        <el-col :span="8">
          <div class="info-item">
            <span class="label">填写时间:</span>
            <span class="value">{{ currentRecord.fillTime }}</span>
          </div>
        </el-col>
        <el-col :span="8">
          <div class="info-item">
            <span class="label">负责科室:</span>
            <el-tag type="primary">{{ currentRecord.responsibilityDept }}</el-tag>
          </div>
        </el-col>
        <el-col :span="8">
          <div class="info-item">
            <span class="label">处理状态:</span>
            <el-tag
              :type="getStatusTagType(currentRecord.processStatus)"
              effect="dark"
            >
              {{ getStatusText(currentRecord.processStatus) }}
            </el-tag>
          </div>
        </el-col>
      </el-row>
    </div>
    <!-- 问卷详情 -->
    <div class="questionnaire-section">
      <div class="section-title">问卷填写详情</div>
      <div class="questionnaire-content">
        <div class="question-item" v-for="(question, index) in questionnaireData" :key="index">
          <div class="question-header">
            <span class="question-index">{{ index + 1 }}.</span>
            <span class="question-text">{{ question.question }}</span>
            <el-tag
              size="mini"
              :type="question.type === 1 ? 'primary' : 'success'"
              class="question-type"
            >
              {{ question.type === 1 ? '单选题' : '多选题' }}
            </el-tag>
          </div>
          <div class="question-options">
            <el-radio-group
              v-model="question.answer"
              v-if="question.type === 1"
              disabled
            >
              <el-radio
                v-for="option in question.options"
                :key="option.value"
                :label="option.value"
                :class="{ 'unsatisfactory-option': isUnsatisfactoryOption(option.value) }"
              >
                {{ option.text }}
              </el-radio>
            </el-radio-group>
            <el-checkbox-group
              v-model="question.answer"
              v-else
              disabled
            >
              <el-checkbox
                v-for="option in question.options"
                :key="option.value"
                :label="option.value"
                :class="{ 'unsatisfactory-option': isUnsatisfactoryOption(option.value) }"
              >
                {{ option.text }}
              </el-checkbox>
            </el-checkbox-group>
          </div>
          <div v-if="question.additional" class="additional-remark">
            <div class="remark-label">补充说明:</div>
            <div class="remark-content">{{ question.additional }}</div>
          </div>
        </div>
      </div>
    </div>
    <!-- 处理记录 -->
    <div class="process-section">
      <div class="section-title">处理记录</div>
      <div class="process-timeline" v-if="processRecords.length > 0">
        <el-timeline>
          <el-timeline-item
            v-for="(record, index) in processRecords"
            :key="index"
            :timestamp="record.time"
            placement="top"
          >
            <el-card>
              <div class="process-item">
                <div class="process-header">
                  <span class="process-user">{{ record.user }}</span>
                  <el-tag
                    size="small"
                    :type="getStatusTagType(record.status)"
                  >
                    {{ getStatusText(record.status) }}
                  </el-tag>
                </div>
                <div class="process-content">
                  <div v-if="record.reportDepts && record.reportDepts.length > 0" class="process-depts">
                    <span class="label">报备科室:</span>
                    <el-tag
                      v-for="dept in record.reportDepts"
                      :key="dept"
                      size="small"
                      type="info"
                      class="dept-tag"
                    >
                      {{ dept }}
                    </el-tag>
                  </div>
                  <div v-if="record.remark" class="process-remark">
                    <span class="label">处理备注:</span>
                    <span class="content">{{ record.remark }}</span>
                  </div>
                  <div v-if="record.attachments && record.attachments.length > 0" class="process-attachments">
                    <span class="label">附件:</span>
                    <el-button
                      v-for="file in record.attachments"
                      :key="file.id"
                      type="text"
                      size="small"
                      icon="el-icon-document"
                      @click="handlePreviewFile(file)"
                    >
                      {{ file.name }}
                    </el-button>
                  </div>
                </div>
              </div>
            </el-card>
          </el-timeline-item>
        </el-timeline>
      </div>
      <div v-else class="no-record">
        暂无处理记录
      </div>
    </div>
    <span slot="footer" class="dialog-footer">
      <el-button
        type="primary"
        icon="el-icon-edit"
        @click="handleProcess"
        v-if="currentRecord.processStatus !== 2"
      >
        处理异常
      </el-button>
      <el-button @click="dialogVisible = false">关闭</el-button>
    </span>
    <!-- 处理对话框 -->
    <el-dialog
      title="处理异常反馈"
      :visible.sync="processDialogVisible"
      width="600px"
      center
      append-to-body
    >
      <el-form
        :model="processForm"
        :rules="processRules"
        ref="processForm"
        label-width="100px"
        size="medium"
      >
        <el-form-item label="处理状态" prop="status">
          <el-select
            v-model="processForm.status"
            placeholder="请选择处理状态"
            style="width: 100%"
          >
            <el-option label="处理中" :value="1" />
            <el-option label="已处理" :value="2" />
            <el-option label="已驳回" :value="3" />
          </el-select>
        </el-form-item>
        <el-form-item label="报备科室" prop="reportDepts">
          <el-select
            v-model="processForm.reportDepts"
            placeholder="请选择报备科室"
            multiple
            filterable
            collapse-tags
            style="width: 100%"
          >
            <el-option
              v-for="dept in deptList"
              :key="dept.id"
              :label="dept.name"
              :value="dept.id"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="处理备注" prop="remark">
          <el-input
            v-model="processForm.remark"
            type="textarea"
            :rows="4"
            placeholder="请输入处理备注(最多500字)"
            maxlength="500"
            show-word-limit
          />
        </el-form-item>
        <el-form-item label="附件上传">
          <el-upload
            class="upload-demo"
            action="#"
            :on-preview="handleFilePreview"
            :on-remove="handleFileRemove"
            :before-remove="beforeFileRemove"
            :limit="3"
            :on-exceed="handleFileExceed"
            :file-list="fileList"
          >
            <el-button size="small" type="primary">点击上传</el-button>
            <div slot="tip" class="el-upload__tip">支持上传图片、文档等附件,单个文件不超过10MB</div>
          </el-upload>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="processDialogVisible = false">取消</el-button>
        <el-button
          type="primary"
          @click="submitProcess"
          :loading="processing"
        >
          提交处理
        </el-button>
      </span>
    </el-dialog>
  </el-dialog>
</template>
<script>
export default {
  name: 'ExceptionDetailDialog',
  props: {
    // 是否显示对话框
    visible: {
      type: Boolean,
      default: false
    },
    // 记录ID
    recordId: {
      type: [Number, String],
      default: null
    },
    // 对话框标题
    title: {
      type: String,
      default: '异常反馈详情'
    }
  },
  data() {
    return {
      // 当前记录
      currentRecord: {},
      // 问卷数据
      questionnaireData: [],
      // 处理记录
      processRecords: [],
      // 科室列表
      deptList: [
        { id: 1, name: '心血管内科' },
        { id: 2, name: '神经内科' },
        { id: 3, name: '普外科' },
        { id: 4, name: '骨科' },
        { id: 5, name: '妇产科' },
        { id: 6, name: '儿科' },
        { id: 7, name: '急诊科' },
        { id: 8, name: '呼吸内科' }
      ],
      // 处理对话框
      processDialogVisible: false,
      processing: false,
      processForm: {
        status: '',
        reportDepts: [],
        remark: ''
      },
      processRules: {
        status: [
          { required: true, message: '请选择处理状态', trigger: 'change' }
        ],
        remark: [
          { required: true, message: '请输入处理备注', trigger: 'blur' },
          { min: 5, max: 500, message: '备注长度在 5 到 500 个字符', trigger: 'blur' }
        ]
      },
      fileList: [],
      // 加载状态
      loading: false
    };
  },
  computed: {
    dialogVisible: {
      get() {
        return this.visible;
      },
      set(val) {
        this.$emit('update:visible', val);
      }
    }
  },
  watch: {
    visible: {
      immediate: true,
      handler(val) {
        if (val && this.recordId) {
          this.loadData();
        }
      }
    }
  },
  methods: {
    // 加载数据
    async loadData() {
      this.loading = true;
      try {
        await Promise.all([
          this.loadRecordDetail(),
          this.loadQuestionnaireData(),
          this.loadProcessRecords()
        ]);
      } finally {
        this.loading = false;
      }
    },
    // 加载记录详情
    async loadRecordDetail() {
      return new Promise(resolve => {
        setTimeout(() => {
          // 根据不同的recordId返回不同的mock数据
          const mockRecords = {
            1: {
              id: 1,
              patientName: '张先生',
              gender: 1,
              age: 45,
              phone: '13800138000',
              dischargeDept: '心血管内科',
              dischargeWard: '内科一病区',
              fillTime: '2024-01-15 10:30:25',
              responsibilityDept: '心血管内科',
              processStatus: 0
            },
            2: {
              id: 2,
              patientName: '李女士',
              gender: 0,
              age: 38,
              phone: '13900139000',
              dischargeDept: '神经内科',
              dischargeWard: '内科二病区',
              fillTime: '2024-01-14 16:20:10',
              responsibilityDept: '神经内科',
              processStatus: 0
            },
            3: {
              id: 3,
              patientName: '王先生',
              gender: 1,
              age: 52,
              phone: '13700137000',
              dischargeDept: '普外科',
              dischargeWard: '外科一病区',
              fillTime: '2024-01-13 09:15:45',
              responsibilityDept: '普外科',
              processStatus: 1
            }
          };
          this.currentRecord = mockRecords[this.recordId] || {
            id: 1,
            patientName: '张先生',
            gender: 1,
            age: 45,
            phone: '13800138000',
            dischargeDept: '心血管内科',
            dischargeWard: '内科一病区',
            fillTime: '2024-01-15 10:30:25',
            responsibilityDept: '心血管内科',
            processStatus: 0
          };
          resolve();
        }, 300);
      });
    },
    // 加载问卷数据
    async loadQuestionnaireData() {
      return new Promise(resolve => {
        setTimeout(() => {
          this.questionnaireData = [
            {
              question: '您对医护人员的服务态度是否满意?',
              type: 1,
              options: [
                { value: '非常满意', text: '非常满意' },
                { value: '满意', text: '满意' },
                { value: '一般', text: '一般' },
                { value: '不满意', text: '不满意' },
                { value: '非常不满意', text: '非常不满意' }
              ],
              answer: '不满意',
              additional: '医生查房时间太短,沟通不够充分,对病情解释不够详细'
            },
            {
              question: '您对医生的诊疗水平和技术能力评价如何?',
              type: 1,
              options: [
                { value: '非常专业', text: '非常专业' },
                { value: '比较专业', text: '比较专业' },
                { value: '一般', text: '一般' },
                { value: '不够专业', text: '不够专业' },
                { value: '非常不专业', text: '非常不专业' }
              ],
              answer: '比较专业',
              additional: ''
            },
            {
              question: '您对医院的环境和卫生状况是否满意?',
              type: 1,
              options: [
                { value: '非常满意', text: '非常满意' },
                { value: '满意', text: '满意' },
                { value: '一般', text: '一般' },
                { value: '不满意', text: '不满意' },
                { value: '非常不满意', text: '非常不满意' }
              ],
              answer: '一般',
              additional: ''
            },
            {
              question: '您认为医护人员与您的沟通是否充分?',
              type: 1,
              options: [
                { value: '非常充分', text: '非常充分' },
                { value: '比较充分', text: '比较充分' },
                { value: '一般', text: '一般' },
                { value: '不够充分', text: '不够充分' },
                { value: '非常不充分', text: '非常不充分' }
              ],
              answer: '不够充分',
              additional: '医生讲解病情时语速太快,没有给足够的时间提问'
            },
            {
              question: '您对等待就诊和治疗的时间是否满意?',
              type: 1,
              options: [
                { value: '非常满意', text: '非常满意' },
                { value: '满意', text: '满意' },
                { value: '一般', text: '一般' },
                { value: '不满意', text: '不满意' },
                { value: '非常不满意', text: '非常不满意' }
              ],
              answer: '不满意',
              additional: '预约的9点,实际10点才见到医生'
            }
          ];
          resolve();
        }, 300);
      });
    },
    // 加载处理记录
    async loadProcessRecords() {
      return new Promise(resolve => {
        setTimeout(() => {
          this.processRecords = [
            {
              id: 1,
              time: '2024-01-15 14:20:30',
              user: '张医生',
              status: 1, // 处理中
              reportDepts: ['医务科', '护理部'],
              remark: '已收到反馈,正在安排相关人员核查情况',
              attachments: [
                { id: 1, name: '初步调查记录.docx' },
                { id: 2, name: '患者沟通记录.jpg' }
              ]
            },
            {
              id: 2,
              time: '2024-01-15 10:45:12',
              user: '系统',
              status: 0, // 待处理
              remark: '系统自动识别为异常反馈,已分配到责任科室',
              attachments: []
            }
          ];
          resolve();
        }, 300);
      });
    },
    // 判断是否为不满意选项
    isUnsatisfactoryOption(value) {
      const unsatisfactoryValues = [
        '不满意',
        '非常不满意',
        '不够专业',
        '非常不专业',
        '不够充分',
        '非常不充分'
      ];
      return unsatisfactoryValues.includes(value);
    },
    // 获取状态标签类型
    getStatusTagType(status) {
      switch (status) {
        case 0: return 'warning'; // 待处理
        case 1: return 'primary'; // 处理中
        case 2: return 'success'; // 已处理
        case 3: return 'danger';  // 已驳回
        default: return 'info';
      }
    },
    // 获取状态文本
    getStatusText(status) {
      switch (status) {
        case 0: return '待处理';
        case 1: return '处理中';
        case 2: return '已处理';
        case 3: return '已驳回';
        default: return '未知';
      }
    },
    // 处理异常
    handleProcess() {
      this.processForm = {
        status: this.currentRecord.processStatus === 0 ? 1 : this.currentRecord.processStatus,
        reportDepts: [],
        remark: ''
      };
      this.processDialogVisible = true;
    },
    // 提交处理
    async submitProcess() {
      this.$refs.processForm.validate(async (valid) => {
        if (valid) {
          this.processing = true;
          try {
            // Mock API调用
            await new Promise(resolve => setTimeout(resolve, 1000));
            this.$message.success('处理提交成功');
            this.processDialogVisible = false;
            // 重新加载数据
            await this.loadData();
            // 触发父组件刷新
            this.$emit('processed');
          } finally {
            this.processing = false;
          }
        }
      });
    },
    // 预览文件
    handlePreviewFile(file) {
      this.$message.info(`预览文件: ${file.name}`);
    },
    // 处理对话框关闭
    handleClose() {
      this.$emit('close');
    },
    // 文件上传相关方法
    handleFilePreview(file) {
      console.log('预览文件:', file);
    },
    handleFileRemove(file, fileList) {
      console.log('移除文件:', file, fileList);
    },
    beforeFileRemove(file) {
      return this.$confirm(`确定移除 ${file.name}?`);
    },
    handleFileExceed(files, fileList) {
      this.$message.warning(`当前限制选择 3 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`);
    }
  }
};
</script>
<style lang="scss" scoped>
.exception-detail-dialog {
  ::v-deep .el-dialog {
    max-height: 85vh;
    display: flex;
    flex-direction: column;
    .el-dialog__body {
      flex: 1;
      overflow-y: auto;
      padding: 20px;
    }
  }
  .info-section {
    margin-bottom: 20px;
    padding: 20px;
    background: #f8f9fa;
    border-radius: 8px;
    border: 1px solid #ebeef5;
    .section-title {
      font-size: 16px;
      font-weight: 600;
      color: #303133;
      margin-bottom: 15px;
      padding-bottom: 10px;
      border-bottom: 2px solid #409EFF;
    }
    .info-item {
      margin-bottom: 12px;
      display: flex;
      align-items: center;
      .label {
        font-size: 14px;
        color: #606266;
        min-width: 80px;
        font-weight: 500;
      }
      .value {
        font-size: 14px;
        color: #303133;
        font-weight: 500;
      }
    }
  }
  .questionnaire-section {
    margin-bottom: 20px;
    padding: 20px;
    background: #fff;
    border-radius: 8px;
    border: 1px solid #ebeef5;
    .section-title {
      font-size: 16px;
      font-weight: 600;
      color: #303133;
      margin-bottom: 15px;
      padding-bottom: 10px;
      border-bottom: 2px solid #409EFF;
    }
    .questionnaire-content {
      .question-item {
        margin-bottom: 20px;
        padding: 15px;
        border-radius: 6px;
        border: 1px solid #ebeef5;
        transition: all 0.3s;
        &:hover {
          border-color: #409EFF;
          box-shadow: 0 2px 12px 0 rgba(64, 158, 255, 0.1);
        }
        .question-header {
          display: flex;
          align-items: center;
          margin-bottom: 15px;
          padding-bottom: 10px;
          border-bottom: 1px dashed #dcdfe6;
          .question-index {
            font-weight: 600;
            color: #409EFF;
            margin-right: 8px;
            font-size: 15px;
          }
          .question-text {
            flex: 1;
            font-size: 15px;
            color: #303133;
            font-weight: 500;
            line-height: 1.5;
          }
          .question-type {
            margin-left: 10px;
          }
        }
        .question-options {
          ::v-deep .el-radio-group {
            display: flex;
            flex-direction: column;
            gap: 10px;
          }
          ::v-deep .el-checkbox-group {
            display: flex;
            flex-wrap: wrap;
            gap: 15px;
          }
          ::v-deep .el-radio,
          ::v-deep .el-checkbox {
            margin: 0;
            padding: 8px 12px;
            border-radius: 4px;
            border: 1px solid #ebeef5;
            transition: all 0.3s;
            &:hover {
              background: #f5f7fa;
            }
            &.unsatisfactory-option {
              border-color: #e6a23c;
              background: #fdf6ec;
            }
          }
        }
        .additional-remark {
          margin-top: 15px;
          padding: 12px;
          background: #f0f9ff;
          border-radius: 6px;
          border-left: 4px solid #409EFF;
          .remark-label {
            font-size: 13px;
            color: #606266;
            font-weight: 500;
            margin-bottom: 5px;
          }
          .remark-content {
            font-size: 14px;
            color: #303133;
            line-height: 1.6;
          }
        }
      }
    }
  }
  .process-section {
    .section-title {
      font-size: 16px;
      font-weight: 600;
      color: #303133;
      margin-bottom: 15px;
      padding-bottom: 10px;
      border-bottom: 2px solid #409EFF;
    }
    .process-timeline {
      ::v-deep .el-timeline-item {
        padding-bottom: 20px;
        .el-timeline-item__timestamp {
          font-size: 13px;
          color: #909399;
        }
      }
      .process-item {
        .process-header {
          display: flex;
          justify-content: space-between;
          align-items: center;
          margin-bottom: 10px;
          .process-user {
            font-size: 14px;
            font-weight: 600;
            color: #409EFF;
          }
        }
        .process-content {
          .process-depts {
            margin-bottom: 8px;
            .label {
              font-size: 13px;
              color: #606266;
              margin-right: 5px;
            }
            .dept-tag {
              margin-right: 5px;
              margin-bottom: 5px;
            }
          }
          .process-remark {
            margin-bottom: 8px;
            .label {
              font-size: 13px;
              color: #606266;
              margin-right: 5px;
            }
            .content {
              font-size: 13px;
              color: #303133;
              line-height: 1.5;
            }
          }
          .process-attachments {
            .label {
              font-size: 13px;
              color: #606266;
              margin-right: 5px;
            }
            ::v-deep .el-button {
              margin-right: 8px;
              margin-bottom: 5px;
            }
          }
        }
      }
    }
    .no-record {
      text-align: center;
      padding: 40px 0;
      color: #909399;
      font-style: italic;
      background: #f8f9fa;
      border-radius: 6px;
    }
  }
  .dialog-footer {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: 10px;
  }
}
</style>
src/views/Satisfaction/sfstatistics/components/SatisfactionStatistics.vue
@@ -273,10 +273,10 @@
              <!-- 综合得分行 -->
              <div class="summary-row">
                <div class="summary-content">
                  <div class="summary-item">
                  <!-- <div class="summary-item">
                    <span class="label">综合得分:</span>
                    <span class="value">{{ totalScore.toFixed(1) }}</span>
                  </div>
                  </div> -->
                  <div class="summary-item">
                    <span class="label">总答题人数:</span>
                    <span class="value">{{ totalAnswerCount }}</span>
src/views/followvisit/record/detailpage/index.vue
@@ -655,6 +655,20 @@
                    </el-input>
                  </el-form-item>
                </el-col>
                 <el-col :span="10">
                  <el-form-item label="短号电话">
                    <el-input
                      placeholder="联系电话缺失"
                      v-model="userform.telshortcode"
                    >
                      <el-button
                        slot="append"
                        icon="el-icon-phone"
                        @click="handleCall(userform.telshortcode, 'tel')"
                      ></el-button>
                    </el-input>
                  </el-form-item>
                </el-col>
              </el-row>
              <!-- 联系人信息行 -->
src/views/followvisit/satisfaction/index.vue
@@ -29,6 +29,17 @@
            v-model="topqueryParams.patName"
          ></el-input>
        </el-form-item>
        <el-form-item label="时间范围">
          <el-date-picker
            v-model="dateRangefs"
            style="width: 240px"
            value-format="yyyy-MM-dd HH:MM:SS"
            type="datetimerange"
            range-separator="-"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
          ></el-date-picker>
        </el-form-item>
        <el-form-item>
          <el-button
            type="primary"
@@ -279,8 +290,8 @@
          fixed="right"
          width="150"
          align="center"
          key="createTime"
          prop="createTime"
          key="updateTime"
          prop="updateTime"
          sortable
        >
        </el-table-column>
@@ -366,6 +377,8 @@
      total: 0,
      // 用户表格数据
      userList: null,
      dateRangefs: [],
      // 弹出层标题
      title: "新增影像随访",
      // 是否显示修改、添加弹出层
@@ -594,14 +607,14 @@
    /** 搜索按钮操作 */
    handleQuery() {
      this.topqueryParams.pageNum = 1;
      this.topqueryParams.startTime = this.dateRangefs[0] || null;
      this.topqueryParams.endTime = this.dateRangefs[1] || null;
      this.getList();
    },
    /** 重置按钮操作 */
    resetQuery() {
      this.dateRange = [];
      this.resetForm("queryForm");
      this.topqueryParams.deptId = undefined;
      this.$refs.tree.setCurrentKey(null);
      this.topqueryParams = {};
      this.handleQuery();
    },
    // 多选框选中数据
vue.config.js
@@ -36,8 +36,8 @@
      // detail: https://cli.vuejs.org/config/#devserver-proxy
      [process.env.VUE_APP_BASE_API]: {
        // target: `https://www.health-y.cn/lssf`,
        // target: `http://192.168.100.10:8096`,
        target: `http://192.168.100.10:8094`,//省立同德
        target: `http://192.168.100.10:8096`,
        // target: `http://192.168.100.10:8094`,//省立同德
        // target: `http://192.168.100.10:8095`,//新华
        // target:`http://localhost:8095`,
        // target:`http://35z1t16164.qicp.vip`,