Prechádzať zdrojové kódy

完善客户信息表+患者信息表逻辑

cgp 2 dní pred
rodič
commit
f2aa0afdcf

+ 18 - 0
src/api/patientInfo.js

@@ -60,3 +60,21 @@ export function exportPatientInfo(query) {
     responseType: 'blob'
   })
 }
+
+// 根据手机号分页查询处方列表
+export function getPrescribeListByPhone(data) {
+  return request({
+    url: '/app/patientInfo/getPrescribeListByPhone',
+    method: 'post',
+    data: data
+  })
+}
+
+// 根据手机号分页查询信息采集列表
+export function getCollectionInfoListByPhone(data) {
+  return request({
+    url: '/app/patientInfo/getCollectionInfoListByPhone',
+    method: 'post',
+    data: data
+  })
+}

+ 223 - 0
src/views/patientInfo/CollectionInfoDialog.vue

@@ -0,0 +1,223 @@
+<template>
+  <el-dialog
+    title="信息采集表"
+    :visible.sync="dialogVisible"
+    width="1100px"
+    append-to-body
+    :close-on-click-modal="false"
+    @close="handleClose"
+  >
+    <el-table v-loading="loading" :data="collectionList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="用户姓名" align="center" prop="userName" />
+      <el-table-column label="性别" align="center" prop="sex">
+        <template slot-scope="scope">
+          <span>{{ formatSex(scope.row.sex) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="电话尾号" align="center" prop="userPhoneFour" />
+      <el-table-column label="是否过敏" align="center" prop="allergy">
+        <template slot-scope="scope">
+          <span>{{ scope.row.allergy || '无' }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="医生" align="center" prop="doctorName" />
+      <el-table-column label="销售" align="center" prop="companyUserName" />
+      <el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="100">
+        <template slot-scope="scope">
+          <el-button size="mini" type="text" icon="el-icon-view" @click="handleView(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-dialog title="采集详情" :visible.sync="detailOpen" width="800px" append-to-body>
+      <el-form ref="detailForm" :model="detailForm" label-width="120px" size="small">
+        <el-row>
+          <el-col :span="8">
+            <el-form-item label="用户姓名">{{ detailForm.userName }}</el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="性别">{{ formatSex(detailForm.sex) }}</el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="年龄">{{ detailForm.age }}</el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="电话尾号">{{ detailForm.userPhoneFour }}</el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="是否过敏">{{ detailForm.allergy || '无' }}</el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="备注">{{ detailForm.remark }}</el-form-item>
+          </el-col>
+        </el-row>
+        <el-divider content-position="left">采集详情</el-divider>
+        <div v-if="parsedQuestions && parsedQuestions.length > 0">
+          <div v-for="(question, index) in parsedQuestions" :key="index" class="question-item">
+            <h4 class="question-title">{{ index + 1 }}. {{ question.title }}</h4>
+            <div class="options-container">
+              <el-tag
+                v-for="(option, optionIndex) in question.options"
+                :key="optionIndex"
+                :type="isOptionSelected(question, option.value) ? 'primary' : 'info'"
+                :effect="isOptionSelected(question, option.value) ? 'dark' : 'plain'"
+                class="option-tag"
+              >
+                {{ option.name }}
+              </el-tag>
+            </div>
+          </div>
+        </div>
+        <div v-else class="no-data">暂无采集信息详情</div>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="detailOpen = false">关 闭</el-button>
+      </div>
+    </el-dialog>
+  </el-dialog>
+</template>
+
+<script>
+import { getCollectionInfoListByPhone } from '@/api/patientInfo'
+import { parseTime } from '@/utils/common'
+
+export default {
+  name: 'CollectionInfoDialog',
+  props: {
+    visible: { type: Boolean, default: false },
+    phone: { type: String, default: '' }
+  },
+  data() {
+    return {
+      loading: false,
+      collectionList: [],
+      total: 0,
+      ids: [],
+      single: true,
+      multiple: true,
+      queryParams: { pageNum: 1, pageSize: 10 },
+      detailForm: {},
+      detailOpen: false,
+      parsedQuestions: []
+    }
+  },
+  computed: {
+    dialogVisible: {
+      get() { return this.visible },
+      set(val) { this.$emit('update:visible', val) }
+    }
+  },
+  watch: {
+    visible(newVal) {
+      if (newVal && this.phone) {
+        this.queryParams.pageNum = 1
+        this.getList()
+      }
+    }
+  },
+  methods: {
+    parseTime,
+    formatSex(sex) {
+      if (sex === 0 || sex === '0') return '女'
+      if (sex === 1 || sex === '1') return '男'
+      return '未知'
+    },
+    /** 请求列表数据 */
+    getList() {
+      this.loading = true
+      getCollectionInfoListByPhone({
+        phone: this.phone,
+        pageNum: this.queryParams.pageNum,
+        pageSize: this.queryParams.pageSize
+      }).then(res => {
+        // 兼容多种返回结构:res 可能是完整的后端 JSON,也可能进一步被若依拦截器包裹
+        const inner = res.data || res
+        // 数据可能在 list 或 rows 中
+        const list = inner.list || inner.rows || []
+        this.collectionList = list
+        this.total = inner.total || 0
+        this.loading = false
+      }).catch(err => {
+        console.error('获取信息采集列表失败:', err)
+        this.collectionList = []
+        this.total = 0
+        this.loading = false
+      })
+    },
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+    handleView(row) {
+      this.detailForm = { ...row }
+      this.parsedQuestions = this.parseJsonInfo(row.jsonInfo)
+      this.detailOpen = true
+    },
+    parseJsonInfo(jsonInfoStr) {
+      try {
+        if (!jsonInfoStr) return []
+        const parsed = JSON.parse(jsonInfoStr)
+        return Array.isArray(parsed) ? parsed.sort((a, b) => a.sort - b.sort) : []
+      } catch (e) {
+        console.error('解析jsonInfo失败:', e)
+        return []
+      }
+    },
+    isOptionSelected(question, optionValue) {
+      return question.value && question.value.includes(optionValue)
+    },
+    handleClose() {
+      this.collectionList = []
+      this.total = 0
+      this.queryParams.pageNum = 1
+      this.$emit('update:visible', false)
+    }
+  }
+}
+</script>
+
+<style scoped>
+.question-item {
+  margin-bottom: 20px;
+  padding: 10px;
+  border: 1px solid #ebeef5;
+  border-radius: 4px;
+  background-color: #fafafa;
+}
+.question-title {
+  margin: 0 0 10px 0;
+  font-size: 16px;
+  font-weight: bold;
+  color: #303133;
+}
+.options-container {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+}
+.option-tag {
+  margin-bottom: 5px;
+}
+.no-data {
+  text-align: center;
+  color: #909399;
+  padding: 20px;
+}
+</style>

+ 110 - 4
src/views/patientInfo/index.vue

@@ -64,6 +64,8 @@
         <template slot-scope="scope">
           <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">修改</el-button>
           <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
+          <el-button size="mini" type="text" icon="el-icon-view" @click="handlePrescribe(scope.row)">查看处方</el-button>
+          <el-button size="mini" type="text" icon="el-icon-document" @click="handleCollection(scope.row)">查看信息采集</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -196,6 +198,53 @@
         <el-button @click="cancel">取 消</el-button>
       </div>
     </el-dialog>
+
+
+    <!-- 处方列表弹窗 -->
+    <el-dialog title="处方信息" :visible.sync="prescribeOpen" width="1100px" append-to-body :close-on-click-modal="false">
+      <el-table v-loading="prescribeLoading" :data="prescribeList">
+        <el-table-column label="处方ID" align="center" prop="prescribeId" />
+        <el-table-column label="处方单号" align="center" prop="prescribeCode" />
+        <el-table-column label="处方类型" align="center" prop="prescribeType">
+          <template slot-scope="scope">
+            <dict-tag :options="prescribeTypeOptions" :value="scope.row.prescribeType" />
+          </template>
+        </el-table-column>
+        <el-table-column label="患者姓名" align="center" prop="patientName" />
+        <el-table-column label="医生姓名" align="center" prop="doctorName" />
+        <el-table-column label="是否确认" align="center" prop="doctorConfirm">
+          <template slot-scope="scope">
+            <dict-tag :options="doctorConfirmOptions" :value="scope.row.doctorConfirm" />
+          </template>
+        </el-table-column>
+        <el-table-column label="审核时间" align="center" prop="auditTime" width="180">
+          <template slot-scope="scope">
+            <span>{{ parseTime(scope.row.auditTime, '{y}-{m}-{d}') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="处方图片" align="center" prop="prescribeImgUrl">
+          <template slot-scope="scope">
+            <el-image
+              v-if="scope.row.doctorConfirm == 1 && scope.row.prescribeImgUrl"
+              style="width: 60px; height: 60px"
+              :src="scope.row.prescribeImgUrl"
+              :preview-src-list="[scope.row.prescribeImgUrl]"
+            />
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination
+        v-show="prescribeTotal > 0"
+        :total="prescribeTotal"
+        :page.sync="prescribeQueryParams.pageNum"
+        :limit.sync="prescribeQueryParams.pageSize"
+        @pagination="getPrescribeList"
+      />
+    </el-dialog>
+
+    <!-- 信息采集弹窗 -->
+    <collection-info-dialog :visible.sync="collectionVisible" :phone="currentPhone" />
   </div>
 </template>
 
@@ -207,12 +256,14 @@ import {
   updatePatientInfo,
   delPatientInfo,
   exportPatientInfo,
-  getDoctorBaseInfo
+  getDoctorBaseInfo,
+  getPrescribeListByPhone
 } from '@/api/patientInfo'
 import { parseTime } from "../../utils/common";
-
+import CollectionInfoDialog from './CollectionInfoDialog.vue'  // 引入信息采集表组件
 export default {
   name: "Patient",
+  components: { CollectionInfoDialog },   // 注册信息采集表组件
   data() {
     // 自定义年龄验证器(备用,el-input-number 已设 min,此规则确保即使组件异常也能拦截)
     const validateAge = (rule, value, callback) => {
@@ -309,7 +360,28 @@ export default {
         practiseCode: '',
         certificateCode: '',
         signUrl: ''
-      }
+      },
+      // 处方相关
+      prescribeOpen: false,
+      prescribeLoading: false,
+      prescribeList: [],
+      prescribeTotal: 0,
+      currentPhone: '',
+      prescribeQueryParams: {
+        pageNum: 1,
+        pageSize: 10
+      },
+      doctorConfirmOptions: [
+        { dictValue: '0', dictLabel: "未确认" },
+        { dictValue: '1', dictLabel: "已确认" }
+      ],
+      prescribeTypeOptions: [
+        { dictValue: '1', dictLabel: "西药" },
+        { dictValue: '2', dictLabel: "中药" },
+        { dictValue: '3', dictLabel: "OTC" }
+      ],
+      //控制信息采集弹窗的变量
+      collectionVisible: false,
     }
   },
 
@@ -492,7 +564,41 @@ export default {
         params.endTime = dateRange[1];
       }
       return params;
-    }
+    },
+    /** 打开处方弹窗 */
+    handlePrescribe(row) {
+      this.currentPhone = row.phone;
+      this.prescribeQueryParams.pageNum = 1;
+      this.prescribeOpen = true;
+      this.getPrescribeList();
+    },
+
+    /** 查询处方列表 */
+    getPrescribeList() {
+      this.prescribeLoading = true;
+      const params = {
+        phone: this.currentPhone,
+        pageNum: this.prescribeQueryParams.pageNum,
+        pageSize: this.prescribeQueryParams.pageSize
+      };
+      getPrescribeListByPhone(params).then(response => {
+        const data = response.data;   // 后端返回 PageInfo,data 中包含 list 和 total
+        this.prescribeList = data.list || [];
+        this.prescribeTotal = data.total || 0;
+        this.prescribeLoading = false;
+      }).catch(() => {
+        this.prescribeLoading = false;
+      });
+    },
+    /** 打开信息采集弹窗 */
+    handleCollection(row) {
+      if (!row.phone) {
+        this.$message.warning('该客户未登记手机号,无法查看信息采集表')
+        return
+      }
+      this.currentPhone = row.phone
+      this.collectionVisible = true
+    },
   }
 }
 </script>