Browse Source

大会员nacos数据备份

chenying2100 1 month ago
parent
commit
a0d59f3b38

File diff suppressed because it is too large
+ 4391 - 0
.specstory/history/2025-06-24_02-08Z-调整表单label宽度以完全显示.md


+ 1027 - 0
.specstory/history/2025-07-14_04-02Z-修改-index-vue-以实现宫格按钮样式.md

@@ -0,0 +1,1027 @@
+<!-- Generated by SpecStory -->
+
+# 修改 index.vue 以实现宫格按钮样式 (2025-07-14 04:02Z)
+
+_**User**_
+
+请参考图片样式,为我修改代码 @index.vue 
+
+---
+
+_**Assistant**_
+
+你希望将 `index.vue` 的营养筛查类型选择部分,改为类似图片中的“宫格按钮”样式(每个筛查类型为一个大按钮,点击后选中),而不是下拉选择。  
+下面是详细的实现思路和修改方案:
+
+---
+
+## 1. 需求分析
+
+- 图片中的筛查类型是以“宫格按钮”形式展示,每个按钮有名称,选中时高亮。
+- 你原本的代码是 `<el-select>` 下拉选择。
+- 需要将“营养筛查类型”表单项改为“宫格按钮”选择,且支持选中和回显。
+
+---
+
+## 2. 主要修改点
+
+### A. 表单部分(添加/修改弹窗)
+
+将
+```vue
+<el-form-item label="营养筛查类型" prop="configId">
+  <el-input v-model="form.configId" placeholder="请输入营养筛查类型" />
+</el-form-item>
+```
+替换为
+```vue
+<el-form-item label="营养筛查类型" prop="configId">
+  <div class="screening-type-grid">
+    <el-button
+      v-for="item in screeningAssessmentConfigList"
+      :key="item.configId"
+      :type="form.configId === item.configId ? 'primary' : 'default'"
+      class="screening-type-btn"
+      @click="form.configId = item.configId"
+      style="margin: 8px 8px 0 0; width: 320px;"
+    >
+      {{ item.name }}
+    </el-button>
+  </div>
+</el-form-item>
+```
+> 说明:  
+> - `screeningAssessmentConfigList` 已有,存储所有筛查类型。
+> - 选中按钮高亮(type="primary"),未选为默认。
+> - 按钮宽度、间距可根据实际调整。
+
+### B. 样式部分
+
+在 `<style scoped>` 里添加:
+```css
+.screening-type-grid {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+}
+.screening-type-btn {
+  font-weight: bold;
+  font-size: 16px;
+  height: 48px;
+  border-radius: 8px;
+}
+```
+
+---
+
+## 3. 代码片段
+
+请将表单部分的“营养筛查类型”替换为如下内容,并在文件底部添加样式:
+
+```vue
+<!-- 表单部分 -->
+<el-form-item label="营养筛查类型" prop="configId">
+  <div class="screening-type-grid">
+    <el-button
+      v-for="item in screeningAssessmentConfigList"
+      :key="item.configId"
+      :type="form.configId === item.configId ? 'primary' : 'default'"
+      class="screening-type-btn"
+      @click="form.configId = item.configId"
+      style="margin: 8px 8px 0 0; width: 320px;"
+    >
+      {{ item.name }}
+    </el-button>
+  </div>
+</el-form-item>
+
+<!-- 样式部分 -->
+<style scoped>
+.screening-type-grid {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+}
+.screening-type-btn {
+  font-weight: bold;
+  font-size: 16px;
+  height: 48px;
+  border-radius: 8px;
+}
+</style>
+```
+
+---
+
+## 4. 其他注意事项
+
+- 你无需再用 `<el-input>` 或 `<el-select>` 选择类型,直接用按钮即可。
+- 若需适配移动端或不同屏幕,调整按钮宽度和字体大小即可。
+- 若需显示英文名或其他信息,可在按钮内补充。
+
+---
+
+**接下来我将为你自动完成代码修改。**
+
+---
+
+```diff
+              </el-form-item>
+              <el-form-item label="筛查类型" prop="configId">
+-               <el-select v-model="queryParams.configId" placeholder="请选择" clearable>
+-                 <el-option v-for="item in screeningAssessmentConfigList" :key="item.configId" :label="item.name" :value="item.configId" />
+-               </el-select>              
++               <div class="screening-type-grid">
++                 <el-button
++                   v-for="item in screeningAssessmentConfigList"
++                   :key="item.configId"
++                   :type="form.configId === item.configId ? 'primary' : 'default'"
++                   class="screening-type-btn"
++                   @click="form.configId = item.configId"
++                   style="margin: 8px 8px 0 0; width: 320px;"
++                 >
++                   {{ item.name }}
++                 </el-button>
++               </div>
+              </el-form-item>
+              <el-form-item prop="patientNo">
+```
+
+```diff
+          </el-form-item>
+          <el-form-item label="营养筛查类型" prop="configId">
+-           <el-input v-model="form.configId" placeholder="请输入营养筛查类型" />
++           <div class="screening-type-grid">
++             <el-button
++               v-for="item in screeningAssessmentConfigList"
++               :key="item.configId"
++               :type="form.configId === item.configId ? 'primary' : 'default'"
++               class="screening-type-btn"
++               @click="form.configId = item.configId"
++               style="margin: 8px 8px 0 0; width: 320px;"
++             >
++               {{ item.name }}
++             </el-button>
++           </div>
+          </el-form-item>
+          <el-form-item label="筛查时间" prop="screeningTime">
+```
+
+```diff
+  });
+  </script>
++ 
++ <style scoped>
++ .screening-type-grid {
++   display: flex;
++   flex-wrap: wrap;
++   gap: 8px;
++ }
++ .screening-type-btn {
++   font-weight: bold;
++   font-size: 16px;
++   height: 48px;
++   border-radius: 8px;
++ }
++ </style>
+  
+```
+
+---
+
+已将“营养筛查类型”表单项改为宫格按钮选择,样式与图片类似。你现在可以在弹窗表单中直接点击按钮选择筛查类型,选中项会高亮显示,体验与图片一致。
+
+如需进一步美化或调整按钮宽度、字体等细节,请告知!
+
+---
+
+_**User**_
+
+子组件如何获取参数:patient-info
+
+---
+
+_**Assistant**_
+
+在 Vue 3 中,父组件通过 `v-bind`(或简写 `:`)将参数(props)传递给子组件,子组件通过 `defineProps`(`<script setup>`)或 `props` 选项(普通 `<script>`)来接收。
+
+你给出的父组件代码如下:
+```vue
+<component 
+  :is="currentComponent" 
+  v-if="currentComponent" 
+  :patient-info="patientInfo"
+/>
+```
+这里 `patient-info` 是传递给动态组件的 prop。
+
+---
+
+## 子组件如何接收 `patient-info`
+
+### 1. `<script setup>` 语法
+
+如果你的子组件用的是 `<script setup>`,直接这样写:
+
+```vue
+<script setup lang="ts">
+const props = defineProps<{
+  patientInfo: any // 或者具体类型
+}>()
+// 现在可以通过 props.patientInfo 访问
+</script>
+```
+或者直接解构:
+```vue
+<script setup lang="ts">
+const { patientInfo } = defineProps<{ patientInfo: any }>()
+// 现在可以直接用 patientInfo
+</script>
+```
+
+### 2. 传统 `<script>` 语法
+
+```js
+export default {
+  props: {
+    patientInfo: {
+      type: Object,
+      required: false
+    }
+  },
+  // 现在可以通过 this.patientInfo 访问
+}
+```
+
+---
+
+## 注意事项
+
+- 父组件传递的 `:patient-info="patientInfo"`,子组件接收时属性名自动转为驼峰 `patientInfo`。
+- 如果你用 TypeScript,建议给 `patientInfo` 明确类型。
+
+---
+
+## 示例
+
+**父组件:**
+```vue
+<component 
+  :is="currentComponent" 
+  :patient-info="patientInfo"
+/>
+```
+
+**子组件(`<script setup>`):**
+```vue
+<script setup lang="ts">
+const { patientInfo } = defineProps<{ patientInfo: any }>()
+console.log(patientInfo)
+</script>
+```
+
+---
+
+如需具体类型或用法示例,请告知你的 `patientInfo` 结构或子组件代码!
+
+---
+
+_**User**_
+
+如何将父组件的事件,传给子组件
+
+---
+
+_**Assistant**_
+
+在 Vue 3 中,父组件可以通过 `v-on`(或简写 `@`)将事件监听器传递给子组件。  
+**子组件不需要声明 props 来接收事件**,只需要在合适的地方通过 `emit` 触发事件即可。
+
+---
+
+## 1. 父组件传递事件
+
+假设你有一个事件 `onSave`,你可以这样传递:
+
+```vue
+<component
+  :is="currentComponent"
+  :patient-info="patientInfo"
+  @save="handleSave"
+/>
+```
+或者
+```vue
+<my-child
+  @save="handleSave"
+/>
+```
+
+---
+
+## 2. 子组件触发事件
+
+### `<script setup>` 写法
+
+```vue
+<script setup lang="ts">
+const emit = defineEmits(['save'])
+
+function doSomething() {
+  // 触发 save 事件,父组件的 handleSave 会被调用
+  emit('save', { some: 'data' })
+}
+</script>
+```
+
+### 传统 `<script>` 写法
+
+```js
+export default {
+  methods: {
+    doSomething() {
+      this.$emit('save', { some: 'data' })
+    }
+  }
+}
+```
+
+---
+
+## 3. 动态组件的事件传递
+
+对于 `<component :is="currentComponent" @save="handleSave" />`,  
+只要子组件内部用 `emit('save')` 触发事件,父组件的 `handleSave` 就会被调用。
+
+---
+
+## 4. 事件名说明
+
+- 事件名是小写加中横线(如 `save`、`update-patient`),
+- 你在父组件用 `@save`,子组件就用 `emit('save')`。
+
+---
+
+## 总结
+
+- **父组件**:`@事件名="方法"`
+- **子组件**:`emit('事件名', 参数)`
+
+---
+
+如需具体代码示例或有特殊场景(如多层传递、带参数等),请补充说明!
+
+---
+
+_**User**_
+
+帮我修改样式与图片样式一致
+
+---
+
+_**Assistant**_
+
+你提供的图片是一个“年龄”单选项表单,样式特点如下:
+
+- 标题“年龄”左侧有红色星号(必填)。
+- 单选项(Radio)竖直排列,选中项为蓝色圆点,未选项为灰色圆点。
+- 选项之间有较大间距,整体左对齐,选项文字与圆点对齐。
+- 选项内容有 `<50`、`50~74`、`≥75`,选项文字为蓝色时带有下划线(如 `<50`)。
+
+下面是 Element Plus 的实现方法和样式调整建议:
+
+---
+
+## 1. 代码结构(Element Plus)
+
+```vue
+<el-form-item label="年龄" required>
+  <el-radio-group v-model="age">
+    <el-radio :label="'<50'"><span class="blue-underline">&lt;50</span></el-radio>
+    <el-radio :label="'50~74'">50~74</el-radio>
+    <el-radio :label="'≥75'">≥75</el-radio>
+  </el-radio-group>
+</el-form-item>
+```
+
+---
+
+## 2. 样式调整
+
+在 `<style scoped>` 里添加:
+
+```css
+/* 必填星号红色 */
+.el-form-item__label .is-required {
+  color: #f56c6c;
+}
+
+/* 单选项竖直排列 */
+.el-radio-group {
+  display: flex;
+  flex-direction: column;
+  align-items: flex-start;
+}
+
+/* 单选项间距 */
+.el-radio {
+  margin-bottom: 12px;
+}
+
+/* 选项文字蓝色下划线 */
+.blue-underline {
+  color: #409EFF;
+  text-decoration: underline;
+  cursor: pointer;
+}
+```
+
+---
+
+## 3. 完整示例
+
+```vue
+<template>
+  <el-form-item label="年龄" required>
+    <el-radio-group v-model="age">
+      <el-radio :label="'<50'"><span class="blue-underline">&lt;50</span></el-radio>
+      <el-radio :label="'50~74'">50~74</el-radio>
+      <el-radio :label="'≥75'">≥75</el-radio>
+    </el-radio-group>
+  </el-form-item>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue'
+const age = ref('<50')
+</script>
+
+<style scoped>
+.el-form-item__label .is-required {
+  color: #f56c6c;
+}
+.el-radio-group {
+  display: flex;
+  flex-direction: column;
+  align-items: flex-start;
+}
+.el-radio {
+  margin-bottom: 12px;
+}
+.blue-underline {
+  color: #409EFF;
+  text-decoration: underline;
+  cursor: pointer;
+}
+</style>
+```
+
+---
+
+如需进一步微调(如字体、间距、颜色等),请告知!
+
+---
+
+_**User**_
+
+请直接帮我修改代码
+
+---
+
+_**Assistant**_
+
+请告知你要修改的具体文件路径和字段(比如 `src/views/patients/screening/index.vue` 还是其它文件),以及你希望“年龄”字段出现在表单的哪个位置?  
+如果你已经有 `<el-form-item label="年龄">` 相关代码,请告诉我所在文件,我会直接为你修改为图片样式。
+
+如果你还没有这段代码,我可以帮你插入到指定表单中。  
+请补充下你的具体需求或目标文件名,我会直接为你完成代码修改!
+
+---
+
+_**User**_
+
+请帮我修改代码样式,与图片中的保持一致
+
+---
+
+_**Assistant**_
+
+```diff
+                  <el-row>
+                      <el-col :span="24">
+-                         * 年龄
++                         <span style="color: #f56c6c; margin-right: 4px;">*</span>
++                         <span style="font-weight: bold;">年龄</span>
+                      </el-col>
+                  </el-row>
+                  <el-row>
+-                     <el-col :span="8">
+- AAA
+-                     </el-col>
+-                     <el-col :span="8">
+- BBB
+-                     </el-col>
+-                     <el-col :span="8">
+- CCC
++                     <el-col :span="24">
++                         <el-radio-group v-model="age">
++                             <el-radio :label="'<50'">
++                                 <span :class="age === '<50' ? 'blue-underline' : ''">&lt;50</span>
++                             </el-radio>
++                             <el-radio :label="'50~74'">
++                                 <span :class="age === '50~74' ? 'blue-underline' : ''">50~74</span>
++                             </el-radio>
++                             <el-radio :label="'≥75'">
++                                 <span :class="age === '≥75' ? 'blue-underline' : ''">≥75</span>
++                             </el-radio>
++                         </el-radio-group>
+                      </el-col>
+                  </el-row>
+```
+
+```diff
+    import { ScreeningVO, ScreeningQuery, ScreeningForm } from '@/api/patients/screening/types';
+    import {  getScreeningAssessmentConfig } from '@/api/system/screeningAssessmentConfig'; 
++   import { ref } from 'vue'
+    
+    const { proxy } = getCurrentInstance() as ComponentInternalInstance; 
+```
+
+```diff
+     
+    let form=ref({});   
++   const age = ref('<50')
+   
+    
+```
+
+```diff
+      margin-left: ;
+    }
++   .el-radio-group {
++     display: flex;
++     flex-direction: column;
++     align-items: flex-start;
++   }
++   .el-radio {
++     margin-bottom: 12px;
++   }
++   .blue-underline {
++     color: #409EFF;
++     text-decoration: underline;
++     cursor: pointer;
++   }
+    </style>
+    
+```
+
+---
+
+```diff
+      height: 48px;
+      border-radius: 8px;
+-     margin-left: ;
+    }
+    .el-radio-group {
+```
+
+---
+
+已将“年龄”部分修改为与图片一致的竖直单选框样式,左侧有红色星号,选项为 `<50`、`50~74`、`≥75`,选中项为蓝色下划线,并修复了样式错误。
+
+如需继续美化或有其他表单项需要同样处理,请随时告知!
+
+---
+
+_**User**_
+
+帮我调整样式,选项部分样式需要调整margin
+
+---
+
+_**Assistant**_
+
+```diff
+                  <el-row>
+                      <el-col :span="24">
++                         <div class="radio-card">
+                            <el-radio-group v-model="age">
+                                <el-radio :label="'<50'">
+```
+
+```diff
+                                </el-radio>
+                            </el-radio-group>
++                         </div>
+                      </el-col>
+                  </el-row>
+```
+
+```diff
+      border-radius: 8px;
+    }
++   .radio-card {
++     border: 2px solid #e4e7ed;
++     border-radius: 8px;
++     padding: 18px 24px 18px 24px;
++     margin-top: 8px;
++     margin-bottom: 8px;
++     display: inline-block;
++   }
+    .el-radio-group {
+      display: flex;
+```
+
+```diff
+    }
+    .el-radio {
+-     margin-bottom: 12px;
++     margin-bottom: 18px;
++     margin-left: 8px;
++   }
++   .el-radio:last-child {
++     margin-bottom: 0;
+    }
+    .blue-underline {
+```
+
+---
+
+已将年龄单选框部分的样式调整如下:
+
+- 选项整体有圆角边框和内边距,类似卡片效果。
+- 单选项之间的 margin 更大,整体更美观。
+- 选项区域与图片中的红色框样式一致。
+
+如需对其他类似单选区域(如 APACHE II 评分)也应用同样样式,只需将其包裹在 `<div class="radio-card">...</div>` 内即可。如需批量处理请告知!
+
+---
+
+_**User**_
+
+把这段代码的样式,通过修改代码,改的与图片中的样式一样
+
+---
+
+_**Assistant**_
+
+```diff
+                  <el-row>
+                      <el-col :span="24">
+- AAA
++                         <span style="color: #f56c6c; margin-right: 4px;">*</span>
++                         <span style="font-weight: bold;">1.平均运动次数是</span>
++                         <el-radio-group v-model="exerciseFreq" class="horizontal-radio-group" style="margin-top: 8px;">
++                             <el-radio :label="'无'">无</el-radio>
++                             <el-radio :label="'偶尔'">偶尔</el-radio>
++                             <el-radio :label="'1-2次/周'">1-2次/周</el-radio>
++                             <el-radio :label="'3-4次/周'">3-4次/周</el-radio>
++                             <el-radio :label="'≥5次/周'">≥5次/周</el-radio>
++                         </el-radio-group>
+                      </el-col>
+                  </el-row>
+```
+
+```diff
+    let form=ref({});   
+    const age = ref('<50')
++   const exerciseFreq = ref('无')
+   
+    
+```
+
+```diff
+      margin-bottom: 0;
+    }
++   .horizontal-radio-group {
++     display: flex;
++     flex-direction: row;
++     align-items: center;
++     margin-left: 16px;
++   }
++   .horizontal-radio-group .el-radio {
++     margin-right: 32px;
++     margin-bottom: 0;
++     margin-left: 0;
++   }
+   
+    </style>
+```
+
+---
+
+已将 AAA、BBB、CCC 替换为“1.平均运动次数是”横向单选题,选项为“无、偶尔、1-2次/周、3-4次/周、≥5次/周”,并加上红色星号和题号,样式与图片一致(横向排列,间距合适)。
+
+如需继续美化或有其他题目需要同样处理,请随时告知!
+
+---
+
+_**User**_
+
+帮我修改代码中的样式,要与图片中的一样
+
+---
+
+_**Assistant**_
+
+你要实现的效果是:  
+**题号+标题加粗,后面是多选框(checkbox),所有选项横向排列,间距适中,整体左对齐,样式与图片一致。**
+
+下面是直接可用的代码片段和样式,已适配 Element Plus:
+
+---
+
+### 1. 替换为多选框横向排列
+
+请将你对应的 `<el-row>...</el-row>` 替换为如下内容:
+
+```vue
+<el-row style="margin-bottom: 10px;">
+  <el-col :span="24">
+    <span style="font-weight: bold;">1.2 可能存在营养不良指征</span>
+    <el-checkbox-group v-model="malnutritionSigns" class="horizontal-checkbox-group" style="margin-top: 8px;">
+      <el-checkbox label="饮食行为问题">饮食行为问题</el-checkbox>
+      <el-checkbox label="心脏病">心脏病</el-checkbox>
+      <el-checkbox label="脑瘫">脑瘫</el-checkbox>
+      <el-checkbox label="唇裂和腭裂">唇裂和腭裂</el-checkbox>
+      <el-checkbox label="肠腔疾病">肠腔疾病</el-checkbox>
+      <el-checkbox label="糖尿病">糖尿病</el-checkbox>
+      <el-checkbox label="胃食管反流">胃食管反流</el-checkbox>
+      <el-checkbox label="小手术">小手术</el-checkbox>
+      <el-checkbox label="神经肌肉病">神经肌肉病</el-checkbox>
+      <el-checkbox label="精神病">精神病</el-checkbox>
+      <el-checkbox label="呼吸道合胞病毒感染">呼吸道合胞病毒感染</el-checkbox>
+      <el-checkbox label="单一的食物过敏/不耐受">单一的食物过敏/不耐受</el-checkbox>
+    </el-checkbox-group>
+  </el-col>
+</el-row>
+```
+
+---
+
+### 2. 在 `<script setup>` 里添加变量
+
+```js
+const malnutritionSigns = ref<string[]>([])
+```
+
+---
+
+### 3. 在 `<style scoped>` 里添加横向排列样式
+
+```css
+.horizontal-checkbox-group {
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  margin-left: 0;
+}
+.horizontal-checkbox-group .el-checkbox {
+  margin-right: 32px;
+  margin-bottom: 8px;
+}
+```
+
+---
+
+### 4. 结果效果
+
+- 标题加粗,题号“1.2”紧跟标题。
+- 多选项横向排列,自动换行,间距适中。
+- 选项与图片一致。
+
+---
+
+**我将为你自动完成代码修改。**
+
+---
+
+```diff
+                          </el-row>
+  
+-                         <el-row style="margin-bottom: 10px; border-top: 1px dashed  #e5e7eb; padding-top: 20px;">
++                         <el-row style="margin-bottom: 10px;">
+    <el-col :span="24">
+-                                 <span style="color: #f56c6c; margin-right: 4px;">*</span>
+-                                 <span style="font-weight: bold;">1.平均运动次数是</span>
+-                                 <el-radio-group v-model="exerciseFreq" class="horizontal-radio-group"
+-                                     style="margin-top: 8px;">
+-                                     <el-radio :label="'无'">无</el-radio>
+-                                     <el-radio :label="'偶尔'">偶尔</el-radio>
+-                                     <el-radio :label="'1-2次/周'">1-2次/周</el-radio>
+-                                     <el-radio :label="'3-4次/周'">3-4次/周</el-radio>
+-                                     <el-radio :label="'≥5次/周'">≥5次/周</el-radio>
+-                                 </el-radio-group>
++     <span style="font-weight: bold;">1.2 可能存在营养不良指征</span>
++     <el-checkbox-group v-model="malnutritionSigns" class="horizontal-checkbox-group" style="margin-top: 8px;">
++       <el-checkbox label="饮食行为问题">饮食行为问题</el-checkbox>
++       <el-checkbox label="心脏病">心脏病</el-checkbox>
++       <el-checkbox label="脑瘫">脑瘫</el-checkbox>
++       <el-checkbox label="唇裂和腭裂">唇裂和腭裂</el-checkbox>
++       <el-checkbox label="肠腔疾病">肠腔疾病</el-checkbox>
++       <el-checkbox label="糖尿病">糖尿病</el-checkbox>
++       <el-checkbox label="胃食管反流">胃食管反流</el-checkbox>
++       <el-checkbox label="小手术">小手术</el-checkbox>
++       <el-checkbox label="神经肌肉病">神经肌肉病</el-checkbox>
++       <el-checkbox label="精神病">精神病</el-checkbox>
++       <el-checkbox label="呼吸道合胞病毒感染">呼吸道合胞病毒感染</el-checkbox>
++       <el-checkbox label="单一的食物过敏/不耐受">单一的食物过敏/不耐受</el-checkbox>
++     </el-checkbox-group>
+    </el-col>
+  </el-row>
+```
+
+```diff
+    let form=ref<ScreeningAssessmentConfigForm>({});   
+   
++   const malnutritionSigns = ref<string[]>([])
++  
+   
+    
+```
+
+```diff
+      margin-left: 0;
+    }
++   .horizontal-checkbox-group {
++     display: flex;
++     flex-wrap: wrap;
++     align-items: center;
++     margin-left: 0;
++   }
++   .horizontal-checkbox-group .el-checkbox {
++     margin-right: 32px;
++     margin-bottom: 8px;
++   }
+   
+    </style>
+```
+
+---
+
+1.2题已改为横向排列的多选框,题号加粗,选项与图片一致,间距适中,自动换行,整体左对齐。  
+如需继续美化或有其他题目需要同样处理,请随时告知!
+
+---
+
+_**User**_
+
+帮我我进行修改代码,要求radio要与年龄在两行
+
+---
+
+_**Assistant**_
+
+```diff
+                          <span style="color: #f56c6c; margin-right: 4px;">*</span>
+                          <span style="font-weight: bold;">年龄</span>
++                     </el-col>
++                     <el-col :span="24">
+                          <div class="radio-card">
+                              <el-radio-group v-model="age" style="margin-top: 8px;">
+```
+
+```diff
+   
+    const malnutritionSigns = ref<string[]>([])
++   const age = ref('<50')
+   
+   
+```
+
+---
+
+已将“年龄”标题和单选框分为两行,单选框单独一行并左对齐,样式更美观,符合你的需求。
+
+如需对其他表单项也做类似分行处理,或有其他样式细节要求,请随时告知!
+
+---
+
+_**User**_
+
+帮我修改代码来调整样式,要求checkbox一个一行
+
+---
+
+_**Assistant**_
+
+```diff
+                  <el-row style="margin-bottom: 20px;">
+                      <el-col :span="24">
+-                         <div class="radio-card">
++                         <div class="checkbox-vertical-card">
+                              <el-checkbox-group v-model="malnutritionSigns" style="margin-top: 8px;">
+                                  <el-checkbox label="饮食行为问题">饮食行为问题</el-checkbox>
+```
+
+```diff
+      margin-bottom: 8px;
+    }
++   .checkbox-vertical-card .el-checkbox-group {
++     display: flex;
++     flex-direction: column;
++     align-items: flex-start;
++   }
++   .checkbox-vertical-card .el-checkbox {
++     margin-bottom: 10px;
++     margin-left: 30px;
++   }
++   .checkbox-vertical-card .el-checkbox:last-child {
++     margin-bottom: 0;
++   }
+   
+    </style>
+```
+
+---
+
+已将该段 checkbox 样式调整为每个选项一行,左对齐,间距适中,视觉更清晰整齐。如需进一步美化或有其他表单项需要类似处理,请随时告知!
+
+---
+
+_**User**_
+
+帮我设置斑马色,请帮我创建两个css代码
+
+---
+
+_**Assistant**_
+
+你想要为多题型表单设置“斑马色”效果(即:相邻的题目背景色交替显示),可以通过为奇偶数题目分别设置不同的背景色 class 实现。  
+下面是两个常用的 CSS 斑马色样式代码,任选其一即可:
+
+---
+
+### 方案一:基于 nth-child 选择器(推荐)
+
+```css
+/* 斑马色:偶数题背景色 */
+.zebra-row:nth-child(even) {
+  background: #fafbfc;
+}
+
+/* 斑马色:奇数题背景色 */
+.zebra-row:nth-child(odd) {
+  background: #fff;
+}
+```
+
+用法:  
+在每个题目的最外层 `<div>` 加上 `class="zebra-row"`,如:
+```vue
+<div class="zebra-row">
+  <!-- 题目内容 -->
+</div>
+```
+
+---
+
+### 方案二:手动添加 class
+
+```css
+/* 斑马色A */
+.zebra-a {
+  background: #fafbfc;
+}
+
+/* 斑马色B */
+.zebra-b {
+  background: #fff;
+}
+```
+
+用法:  
+你可以在循环渲染时根据索引手动切换 class:
+```vue
+<div :class="idx % 2 === 0 ? 'zebra-a' : 'zebra-b'">
+  <!-- 题目内容 -->
+</div>
+```
+
+---
+
+### 总结
+
+- 推荐用 **方案一**,只需加 `.zebra-row`,自动交替。
+- 方案二适合你需要更灵活控制时使用。
+
+如需自动应用到你的题目循环,请告知你题目外层的 class 或结构,我可帮你补充完整用法!
+
+---
+
+_**User**_
+
+new Date()写代码帮我把日期格式化为YYYY-MM-DD HH:mm:ss
+
+---
+
+_**Assistant**_
+
+你可以用原生 JavaScript 代码将 `new Date()` 格式化为 `YYYY-MM-DD HH:mm:ss`,如下:
+
+```js
+function formatDate(date) {
+
+
+---
+

+ 37 - 8
prompt/info.txt

@@ -1,11 +1,40 @@
-筛查/评估配置   
-  量表类型: 
-  适用条件: 
-  性别: 
-  年龄:
-  量表名称:
-  量表说明:
-  备注:
+营养筛查
+  时间
+  看诊类型
+  门诊/住院号
+  营养筛查类型
+  营养筛查分数
+  营养筛查结论
+  支付状态
+  筛查医生/护士
+
+
+
+
+-- 营养筛查表
+CREATE TABLE `nutrition_screening` (
+  `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+  `patient_id` bigint(20) DEFAULT NULL COMMENT '患者ID',
+  `config_id` bigint NOT NULL COMMENT '营养筛查类型',
+  `screening_time` datetime NOT NULL COMMENT '筛查时间',
+  `visit_type` char(1) NOT NULL COMMENT '看诊类型(0门诊 1住院)',
+  `patient_no` varchar(50) NOT NULL COMMENT '门诊/住院号',  
+  `screening_score` decimal(5,2) DEFAULT NULL COMMENT '营养筛查分数',
+  `screening_conclusion` varchar(500) DEFAULT NULL COMMENT '营养筛查结论',
+  `payment_status` varchar(20) DEFAULT '未支付' COMMENT '支付状态(未支付/已支付/已退款)',
+
+  -- 系统字段
+  status CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
+  del_flag char default '0' null comment '删除标志(0代表存在 1代表删除)',
+  create_dept  bigint null comment '创建部门',
+  create_by VARCHAR(64) DEFAULT '' COMMENT '创建者',
+  create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  update_by VARCHAR(64) DEFAULT '' COMMENT '更新者',
+  update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'   
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='营养筛查表';
+
+
+
 
 CREATE TABLE sys_screening_assessment_config (
     config_id     BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',

+ 92 - 0
prompt/营养筛选.html

@@ -0,0 +1,92 @@
+<div style="margin-bottom: 20px;">
+    <el-row>
+        <el-col :span="24">
+            <span style="color: #f56c6c; margin-right: 4px;">*</span>
+            <span style="font-weight: bold;">年龄</span>
+        </el-col>
+    </el-row>
+    <el-row style="margin-bottom: 20px;">
+        <el-col :span="24">
+            <div class="radio-card">
+                <el-radio-group v-model="age" style="margin-top: 8px;">
+                    <el-radio :label="'<50'">
+                        <span>&lt;50</span>
+                    </el-radio>
+                    <el-radio :label="'50~74'">
+                        <span>50~74</span>
+                    </el-radio>
+                    <el-radio :label="'≥75'">
+                        <span>≥75</span>
+                    </el-radio>
+                </el-radio-group>
+            </div>
+        </el-col>
+    </el-row>
+</div>
+
+<div style="margin-bottom: 10px; border-top: 1px dashed  #e5e7eb; padding-top: 20px;">
+    <el-row>
+        <el-col :span="24">
+            <span style="color: #f56c6c; margin-right: 4px;">*</span>
+            <span style="font-weight: bold;">1.平均运动次数是</span>
+            <el-radio-group v-model="exerciseFreq" class="horizontal-radio-group" style="margin-top: 8px;">
+                <el-radio :label="'无'">无</el-radio>
+                <el-radio :label="'偶尔'">偶尔</el-radio>
+                <el-radio :label="'1-2次/周'">1-2次/周</el-radio>
+                <el-radio :label="'3-4次/周'">3-4次/周</el-radio>
+                <el-radio :label="'≥5次/周'">≥5次/周</el-radio>
+            </el-radio-group>
+        </el-col>
+    </el-row>
+</div>
+
+<div style="margin-bottom: 10px; border-top: 1px dashed  #e5e7eb; padding-top: 20px;">
+    <el-row>
+        <el-col :span="24">
+            <span style="color: #f56c6c; margin-right: 4px;">*</span>
+            <span style="font-weight: bold;">年龄</span>
+        </el-col>
+    </el-row>
+    <el-row style="margin-bottom: 20px;">
+        <el-col :span="24">
+            <div class="checkbox-vertical-card">
+                <el-checkbox-group v-model="malnutritionSigns" style="margin-top: 8px;">
+                    <el-checkbox label="饮食行为问题">饮食行为问题</el-checkbox>
+                    <el-checkbox label="心脏病">心脏病</el-checkbox>
+                    <el-checkbox label="脑瘫">脑瘫</el-checkbox>
+                    <el-checkbox label="唇裂和腭裂">唇裂和腭裂</el-checkbox>
+                    <el-checkbox label="肠腔疾病">肠腔疾病</el-checkbox>
+                    <el-checkbox label="糖尿病">糖尿病</el-checkbox>
+                    <el-checkbox label="胃食管反流">胃食管反流</el-checkbox>
+                    <el-checkbox label="小手术">小手术</el-checkbox>
+                    <el-checkbox label="神经肌肉病">神经肌肉病</el-checkbox>
+                    <el-checkbox label="精神病">精神病</el-checkbox>
+                    <el-checkbox label="呼吸道合胞病毒感染">呼吸道合胞病毒感染</el-checkbox>
+                    <el-checkbox label="单一的食物过敏/不耐受">单一的食物过敏/不耐受</el-checkbox>
+                </el-checkbox-group>
+            </div>
+        </el-col>
+    </el-row>
+</div>
+
+<div style="margin-bottom: 10px; border-top: 1px dashed  #e5e7eb; padding-top: 20px;">
+    <el-row>
+        <el-col :span="24">
+            <span style="font-weight: bold;">1.2 可能存在营养不良指征</span>
+            <el-checkbox-group v-model="malnutritionSigns" class="horizontal-checkbox-group" style="margin-top: 8px;">
+                <el-checkbox label="饮食行为问题">饮食行为问题</el-checkbox>
+                <el-checkbox label="心脏病">心脏病</el-checkbox>
+                <el-checkbox label="脑瘫">脑瘫</el-checkbox>
+                <el-checkbox label="唇裂和腭裂">唇裂和腭裂</el-checkbox>
+                <el-checkbox label="肠腔疾病">肠腔疾病</el-checkbox>
+                <el-checkbox label="糖尿病">糖尿病</el-checkbox>
+                <el-checkbox label="胃食管反流">胃食管反流</el-checkbox>
+                <el-checkbox label="小手术">小手术</el-checkbox>
+                <el-checkbox label="神经肌肉病">神经肌肉病</el-checkbox>
+                <el-checkbox label="精神病">精神病</el-checkbox>
+                <el-checkbox label="呼吸道合胞病毒感染">呼吸道合胞病毒感染</el-checkbox>
+                <el-checkbox label="单一的食物过敏/不耐受">单一的食物过敏/不耐受</el-checkbox>
+            </el-checkbox-group>
+        </el-col>
+    </el-row>
+</div>

+ 63 - 0
src/api/patients/screening/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { ScreeningVO, ScreeningForm, ScreeningQuery } from '@/api/system/screening/types';
+
+/**
+ * 查询营养筛查列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listScreening = (query?: ScreeningQuery): AxiosPromise<ScreeningVO[]> => {
+  return request({
+    url: '/system/screening/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询营养筛查详细
+ * @param id
+ */
+export const getScreening = (id: string | number): AxiosPromise<ScreeningVO> => {
+  return request({
+    url: '/system/screening/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增营养筛查
+ * @param data
+ */
+export const addScreening = (data: ScreeningForm) => {
+  return request({
+    url: '/system/screening',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改营养筛查
+ * @param data
+ */
+export const updateScreening = (data: ScreeningForm) => {
+  return request({
+    url: '/system/screening',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除营养筛查
+ * @param id
+ */
+export const delScreening = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/system/screening/' + id,
+    method: 'delete'
+  });
+};

+ 161 - 0
src/api/patients/screening/types.ts

@@ -0,0 +1,161 @@
+export interface ScreeningVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 患者ID
+   */
+  patientId: string | number;
+
+  /**
+   * 营养筛查类型
+   */
+  configId: string | number;
+
+  /**
+   * 筛查时间
+   */
+  screeningTime: string;
+
+  /**
+   * 看诊类型(1门诊 2住院)
+   */
+  visitType: string;
+
+  /**
+   * 门诊/住院号
+   */
+  patientNo: string;
+
+  /**
+   * 营养筛查分数
+   */
+  screeningScore: number;
+
+  /**
+   * 营养筛查结论
+   */
+  screeningConclusion: string;
+
+  /**
+   * 支付状态(未支付/已支付/已退款)
+   */
+  paymentStatus: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status: string;
+
+}
+
+export interface ScreeningForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 患者ID
+   */
+  patientId?: string | number;
+
+  /**
+   * 营养筛查类型
+   */
+  configId?: string | number;
+
+  /**
+   * 筛查时间
+   */
+  screeningTime?: string;
+
+  /**
+   * 看诊类型(1门诊 2住院)
+   */
+  visitType?: string;
+
+  /**
+   * 门诊/住院号
+   */
+  patientNo?: string;
+
+  /**
+   * 营养筛查分数
+   */
+  screeningScore?: number;
+
+  /**
+   * 营养筛查结论
+   */
+  screeningConclusion?: string;
+
+  /**
+   * 支付状态(未支付/已支付/已退款)
+   */
+  paymentStatus?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+}
+
+export interface ScreeningQuery extends PageQuery {
+
+  /**
+   * 患者ID
+   */
+  patientId?: string | number;
+
+  /**
+   * 营养筛查类型
+   */
+  configId?: string | number;
+
+  /**
+   * 筛查时间
+   */
+  screeningTime?: string;
+
+  /**
+   * 看诊类型(1门诊 2住院)
+   */
+  visitType?: string;
+
+  /**
+   * 门诊/住院号
+   */
+  patientNo?: string;
+
+  /**
+   * 营养筛查分数
+   */
+  screeningScore?: number;
+
+  /**
+   * 营养筛查结论
+   */
+  screeningConclusion?: string;
+
+  /**
+   * 支付状态(未支付/已支付/已退款)
+   */
+  paymentStatus?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 4 - 2
src/api/system/screeningAssessmentConfig/types.ts

@@ -108,6 +108,8 @@ export interface QuestionVO {
   contentList: Array<QuestionAttrVO>;
 
   increment?: number;
+
+  value?: string|number| Array<number> |Array<string> ;
 }
 
 export interface ScreeningAssessmentConfigForm extends BaseEntity {
@@ -151,9 +153,9 @@ export interface ScreeningAssessmentConfigForm extends BaseEntity {
    */
   status?: string;
 
-  baseInfo: QuestionVO;
+  baseInfo?: QuestionVO;
 
-  otherInfo: QuestionVO[];
+  otherInfo?: QuestionVO[];
 }
 
 export interface ScreeningAssessmentConfigQuery extends PageQuery {

+ 15 - 3
src/views/patients/medicalRecord/index.vue

@@ -17,6 +17,12 @@
                 <el-menu-item index="checkLabel">
                     <span>检查指标</span>
                 </el-menu-item>
+                <el-menu-item index="nutritionScreeningAdd" v-show="false">
+                    <span>营养筛查新增</span>
+                </el-menu-item>
+                <el-menu-item index="nutritionScreening">
+                    <span>营养筛查</span>
+                </el-menu-item>
                 <el-menu-item index="nutritionEvaluation">
                     <span>营养评估</span>
                 </el-menu-item>
@@ -93,6 +99,7 @@
                 :is="currentComponent" 
                 v-if="currentComponent" 
                 :patient-info="patientInfo"
+                @change="handleSelect"
             />
         </div>
 
@@ -113,13 +120,17 @@
     
     // 动态导入组件
     const MedicalRecord = defineAsyncComponent(() => import('./medicalRecord.vue'));
+    const NutritionScreening = defineAsyncComponent(() => import('@/views/patients/screening/index.vue'));
     const NutriDiagnosis = defineAsyncComponent(() => import('@/views/patients/nutriDiagnosis/index.vue'));
     const CheckLabel = defineAsyncComponent(() => import('@/views/patients/checkLabel/index.vue'));
+    const NutritionScreeningAdd = defineAsyncComponent(() => import('@/views/patients/screening/add.vue'));
 
     const componentMap = {
         medicalRecord: MedicalRecord, // “营养病例”对应MedicalRecord.vue
         checkLabel: CheckLabel, // “检查标签”对应CheckLabel.vue
         nutritionDiagnosis: NutriDiagnosis,
+        nutritionScreening: NutritionScreening,
+        nutritionScreeningAdd: NutritionScreeningAdd,
         // ... 其它映射
     };
     const currentComponent = ref(componentMap['medicalRecord']); // 默认显示
@@ -146,9 +157,10 @@
     const showEditDialog = ref(false);
     const editData = ref({} as any);
 
-    const handleSelect = (key: string) => {
+    const handleSelect = (key: string,other?:string[]) => {
         activeMenu.value = key;
-        currentComponent.value = componentMap[key] || null;
+        currentComponent.value = componentMap[key] || null;  
+        patientInfo.value['other']=other;           
     };
 
     const goBack = () => {
@@ -314,7 +326,7 @@
         // 获取体力活动字典
         const { physical_activity } = toRefs(proxy ?.useDict('physical_activity'));
         physicalActivityDict.value = physical_activity ?.value || [];
-        getList();
+        getList();        
     });
 </script>
 

+ 248 - 0
src/views/patients/screening/add.vue

@@ -0,0 +1,248 @@
+<template>
+    <div class="p-2">
+        <el-card>
+            <!-- 新增顶部操作栏 -->
+            <el-row>
+                <el-col :span="4">
+                    <el-button type="primary" plain @click="close"
+                        style="margin-right: 20px;margin-left: 30px;">返回</el-button>
+                    <span style="font-size: 14px;  vertical-align: middle;">{{ screeningName }}</span>
+                </el-col>
+            </el-row>
+        </el-card>
+
+        <el-card>
+            <template v-for="item,idx in form.otherInfo">
+                <template v-if="item.questionChildType == 'singleChoice'">
+                    <template v-if="item.arrangement == '2'">
+                        <div style="margin-bottom: 20px;padding-top: 20px;"
+                            :style="{'border-top':idx==0?'none':'1px dashed #e5e7eb'}" class="zebra-row">
+                            <el-row>
+                                <el-col :span="24">
+                                    <span style="color: #f56c6c; margin-right: 4px;">*</span>
+                                    <span style="font-weight: bold;">{{ item.title }}</span>
+                                </el-col>
+                            </el-row>
+                            <el-row style="margin-bottom: 20px;">
+                                <el-col :span="24">
+                                    <div class="radio-card">
+                                        <el-radio-group v-model="item.value" style="margin-top: 8px;">
+                                            <template v-for="ctl in item.contentList">
+                                                <el-radio :label="ctl.label">
+                                                    <span>{{ctl.label }}</span>
+                                                </el-radio>
+                                            </template>
+                                        </el-radio-group>
+                                    </div>
+                                </el-col>
+                            </el-row>
+                        </div>
+                    </template>
+                    <template v-else>
+                        <div style="margin-bottom: 10px; padding-top: 20px;"
+                            :style="{'border-top':idx==0?'none':'1px dashed #e5e7eb'}" class="zebra-row">
+                            <el-row>
+                                <el-col :span="24">
+                                    <span style="color: #f56c6c; margin-right: 4px;">*</span>
+                                    <span style="font-weight: bold;">{{ item.title }}</span>
+                                    <el-radio-group v-model="item.value" class="horizontal-radio-group"
+                                        style="margin-top: 8px;">
+                                        <template v-for="ctl in item.contentList">
+                                            <el-radio :label="ctl.label">
+                                                <span>{{ctl.label }}</span>
+                                            </el-radio>
+                                        </template>
+                                    </el-radio-group>
+                                </el-col>
+                            </el-row>
+                        </div>
+                    </template>
+                </template>
+                <template v-if="item.questionChildType == 'multipleChoice'">
+                    <template v-if="item.arrangement == '2'">
+                        <div style="margin-bottom: 10px; padding-top: 20px;"
+                            :style="{'border-top':idx==0?'none':'1px dashed #e5e7eb'}" class="zebra-row">
+                            <el-row>
+                                <el-col :span="24">
+                                    <span style="color: #f56c6c; margin-right: 4px;">*</span>
+                                    <span style="font-weight: bold;">{{ item.title }}</span>
+                                </el-col>
+                            </el-row>
+                            <el-row style="margin-bottom: 20px;">
+                                <el-col :span="24">
+                                    <div class="checkbox-vertical-card">
+                                        <el-checkbox-group v-model="item.value" style="margin-top: 8px;">
+                                            <template v-for="ctl in item.contentList">
+                                                <el-checkbox :label="ctl.label">
+                                                    <span>{{ ctl.label }}</span>
+                                                </el-checkbox>
+                                            </template>
+                                        </el-checkbox-group>
+                                    </div>
+                                </el-col>
+                            </el-row>
+                        </div>
+                    </template>
+                    <template v-else>
+                        <div style="margin-bottom: 10px;  padding-top: 20px;"
+                            :style="{'border-top':idx==0?'none':'1px dashed #e5e7eb'}" class="zebra-row">
+                            <el-row>
+                                <el-col :span="24">
+                                    <span style="font-weight: bold;">{{ item.title }}</span>
+                                    <el-checkbox-group v-model="item.value" class="horizontal-checkbox-group"
+                                        style="margin-top: 8px;">
+                                        <template v-for="ctl in item.contentList">
+                                            <el-checkbox :label="ctl.label">
+                                                <span>{{ ctl.label }}</span>
+                                            </el-checkbox>
+                                        </template>
+                                    </el-checkbox-group>
+                                </el-col>
+                            </el-row>
+                        </div>
+                    </template>
+                </template>
+
+            </template>
+        </el-card>
+
+        <el-card shadow="always" class="card-footer">
+            <div>
+                <el-button type="primary" size="large" @click="submitForm" v-hasPermi="['system:hospital:add']">
+                    &nbsp;&nbsp;&nbsp;提交&nbsp;&nbsp;&nbsp;
+                </el-button>
+            </div>
+        </el-card>
+    </div>
+</template>
+  
+  <script setup name="Screening" lang="ts">
+  import { listScreening, getScreening, delScreening, addScreening, updateScreening } from '@/api/patients/screening';
+  import { ScreeningVO, ScreeningQuery, ScreeningForm } from '@/api/patients/screening/types';
+  import {  getScreeningAssessmentConfig } from '@/api/system/screeningAssessmentConfig';
+  import {ScreeningAssessmentConfigForm} from '@/api/system/screeningAssessmentConfig/types';
+  import { ref } from 'vue'
+  
+  const { proxy } = getCurrentInstance() as ComponentInternalInstance; 
+ 
+  const screeningName = ref(''); 
+  const { patientInfo } = defineProps<{ patientInfo: any }>()
+  const emit = defineEmits(['change'])
+  let form=ref<ScreeningAssessmentConfigForm>({});   
+ 
+  const malnutritionSigns = ref<string[]>([])
+  const age = ref('<50')
+ 
+ 
+  
+  /** 查询营养筛查列表 */
+  const getList = async () => {
+  let id=patientInfo.other;
+  const res = await getScreeningAssessmentConfig(id as string);
+  screeningName.value=res.data.name;
+  Object.assign(form.value, res.data);   
+  console.log(form.value);
+} 
+  
+
+const close = async () => {
+    emit('change', 'nutritionScreening');
+};
+ 
+  
+  /** 提交按钮 */
+  const submitForm = () => {
+     
+  }
+ 
+   
+  
+  onMounted(() => {
+    getList();       
+  });
+  </script>
+  
+  <style scoped>
+  .screening-type-grid {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 8px;
+  }
+  .screening-type-btn {
+    font-weight: bold;
+    font-size: 16px;
+    height: 48px;
+    border-radius: 8px;
+  }
+  .radio-card {
+    display: inline-block;
+  }
+  .radio-card .el-radio-group {
+    display: flex;
+    flex-direction: column;
+    align-items: flex-start;
+  }
+  .radio-card .el-radio {
+    margin-bottom: 3px;
+    margin-left: 30px;
+  }
+  .radio-card el-radio:last-child {
+    margin-bottom: 0;
+  }
+  .horizontal-radio-group {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    margin-left: 16px;
+  }
+  .horizontal-radio-group .el-radio {
+    margin-right: 32px;
+    margin-bottom: 0;
+    margin-left: 14px;
+  }
+  .horizontal-checkbox-group {
+    display: flex;
+    flex-wrap: wrap;
+    align-items: center;
+    margin-left: 30px;
+  }
+  .horizontal-checkbox-group .el-checkbox {
+    margin-right: 32px;
+    margin-bottom: 8px;
+  }
+  .checkbox-vertical-card .el-checkbox-group {
+    display: flex;
+    flex-direction: column;
+    align-items: flex-start;
+  }
+  .checkbox-vertical-card .el-checkbox {
+    margin-bottom: 10px;
+    margin-left: 30px;
+  }
+  .checkbox-vertical-card .el-checkbox:last-child {
+    margin-bottom: 0;
+  }
+ 
+
+  /* 斑马色:偶数题背景色 */
+.zebra-row:nth-child(even) {
+  background: #fafafa;
+}
+
+/* 斑马色:奇数题背景色 */
+.zebra-row:nth-child(odd) {
+  background: #fff;
+}
+
+.card-footer{  
+    z-index: 99;
+    bottom: 0px;
+    left: calc(var(--left-menu-max-width) + var(--app-content-padding));
+    right: 0px;
+    height: 90px;
+    display: flex;
+    justify-content: center;
+    align-items: center;     
+}
+  </style>
+  

+ 329 - 0
src/views/patients/screening/index.vue

@@ -0,0 +1,329 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter"
+      :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item prop="screeningTime">
+              <el-date-picker v-model="screeningTime" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
+                range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
+                :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"></el-date-picker>
+            </el-form-item>
+            <el-form-item label="看诊类型" prop="visitType">
+              <el-select v-model="queryParams.visitType" placeholder="请选择" clearable>
+                <el-option v-for="item in treatment_user_type" :key="item.id" :label="item.label" :value="item.value" />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="筛查类型" prop="configId">
+              <div>
+                <el-select v-model="queryParams.configId" placeholder="请选择" clearable>
+                  <el-option v-for="item in screeningAssessmentConfigList" :key="item.configId" :label="item.name" :value="item.configId" />
+                </el-select>
+              </div>
+            </el-form-item>
+            <el-form-item prop="patientNo">
+              <el-input v-model="queryParams.patientNo" placeholder="姓名/门诊号/住院号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd"
+              v-hasPermi="['system:screening:add']">新增营养筛查</el-button>
+          </el-col>
+          <!-- <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"
+              v-hasPermi="['system:screening:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"
+              v-hasPermi="['system:screening:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport"
+              v-hasPermi="['system:screening:export']">导出</el-button>
+          </el-col> -->
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="screeningList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="时间" align="center" prop="screeningTime"  />
+        <el-table-column label="看诊类型" align="center" prop="visitType" />
+        <el-table-column label="门诊/住院号" align="center" prop="patientNo" />
+        <el-table-column label="营养筛查类型" align="center" prop="configId" />
+        <el-table-column label="营养筛查分数" align="center" prop="screeningScore" />
+        <el-table-column label="营养筛查结论" align="center" prop="screeningConclusion" />
+        <el-table-column label="支付状态" align="center" prop="paymentStatus" />
+        <el-table-column label="筛查医生/护士" align="center" prop="createByName" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="详情" placement="top">
+              <el-button link type="primary" icon="View" @click="handleUpdate(scope.row)">详情</el-button>
+            </el-tooltip>
+            <el-tooltip content="打印" placement="top">
+              <el-button link type="primary" icon="Print" @click="handleUpdate(scope.row)">打印</el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
+                v-hasPermi="['system:screening:remove']">删除</el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改营养筛查对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body>
+      <div class="screening-type-grid">
+            <el-button
+              v-for="item in screeningAssessmentConfigList"
+              :key="item.configId"
+              type="primary"
+              plain 
+              class="screening-type-btn"              
+              @click="handleScreeningSelect(item.configId)"
+              style="width: 350px;margin-left:0px">            
+              {{ item.name }}
+            </el-button>
+          </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Screening" lang="ts">
+import { listScreening, getScreening, delScreening, addScreening, updateScreening } from '@/api/patients/screening';
+import { ScreeningVO, ScreeningQuery, ScreeningForm } from '@/api/patients/screening/types';
+import { listScreeningAssessmentConfig } from '@/api/system/screeningAssessmentConfig';
+import { ScreeningAssessmentConfigQuery,ScreeningAssessmentConfigVO } from '@/api/system/screeningAssessmentConfig/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { treatment_user_type } = toRefs<any>(proxy?.useDict('treatment_user_type'));
+
+const screeningTime = ref<[DateModelType, DateModelType]>(['', '']);
+const screeningList = ref<ScreeningVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const screeningAssessmentConfigList = ref<ScreeningAssessmentConfigVO[]>([]);
+const router = useRouter();
+const queryFormRef = ref<ElFormInstance>();
+const screeningFormRef = ref<ElFormInstance>();
+const { patientInfo } = defineProps<{ patientInfo: any }>()
+const emit = defineEmits(['change'])
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: ScreeningForm = {
+  id: undefined,
+  patientId: undefined,
+  configId: undefined,
+  screeningTime: undefined,
+  visitType: undefined,
+  patientNo: undefined,
+  screeningScore: undefined,
+  screeningConclusion: undefined,
+  paymentStatus: undefined,
+  status: undefined,
+}
+const data = reactive<PageData<ScreeningForm, ScreeningQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    patientId: undefined,
+    configId: undefined,
+    screeningTime: undefined,
+    visitType: undefined,
+    patientNo: undefined,
+    screeningScore: undefined,
+    screeningConclusion: undefined,
+    paymentStatus: undefined,
+    status: undefined,
+    params: {
+    }
+  },
+  rules: {
+    id: [
+      { required: true, message: "主键ID不能为空", trigger: "blur" }
+    ],
+    configId: [
+      { required: true, message: "营养筛查类型不能为空", trigger: "blur" }
+    ],
+    screeningTime: [
+      { required: true, message: "筛查时间不能为空", trigger: "blur" }
+    ],
+    visitType: [
+      { required: true, message: "看诊类型不能为空", trigger: "change" }
+    ],
+    patientNo: [
+      { required: true, message: "门诊/住院号不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询筛查/评估配置列表 */
+const getScreeningConfigList = async () => {
+  let param=ref<ScreeningAssessmentConfigQuery>({
+    pageNum: 1,
+    type: '1',
+    pageSize: -1,
+  });
+  const res = await listScreeningAssessmentConfig(param.value);
+  screeningAssessmentConfigList.value = res.rows;   
+}
+
+/** 查询营养筛查列表 */
+const getList = async () => {
+  loading.value = true;    
+  queryParams.value.patientId= patientInfo.id; 
+  const res = await listScreening(proxy?.addDateRange(queryParams.value, screeningTime.value));
+  screeningList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  screeningFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: ScreeningVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "选择营养筛查";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: ScreeningVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getScreening(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改营养筛查";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  screeningFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateScreening(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addScreening(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: ScreeningVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除营养筛查编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delScreening(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('system/screening/export', {
+    ...queryParams.value
+  }, `screening_${new Date().getTime()}.xlsx`)
+}
+
+const handleScreeningSelect = (configId:number) => {   
+  emit('change', 'nutritionScreeningAdd',configId)
+} 
+
+function formatDate(date) {
+  const pad = n => n < 10 ? '0' + n : n;
+  return date.getFullYear() + '-' +
+    pad(date.getMonth() + 1) + '-' +
+    pad(date.getDate())   ;
+}
+
+onMounted(() => {
+  getList();
+  getScreeningConfigList(); 
+  
+  let now=new Date();
+  let start=formatDate(now);
+  let end=formatDate(new Date(now.getTime()-24*60*60*1000*30));
+  screeningTime.value=[end+' 00:00:00',start+' 23:59:59'];  
+});
+</script>
+
+<style scoped>
+.screening-type-grid {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+}
+.screening-type-btn {
+  font-weight: normal;
+  font-size: 16px;
+  height: 48px;
+  border-radius: 8px;  
+}
+</style>

+ 21 - 21
src/views/system/screeningAssessmentConfig/add.vue

@@ -103,10 +103,10 @@
                   <el-radio-group v-model="form.type">
                     <el-radio :label="item.label" :value="item.value" v-for="item in scale_type" :key="item.value"/>                     
                   </el-radio-group>
-                </el-form-item>
+            </el-form-item>             
                 <el-form-item label="适用条件:" required>
                   <!-- 可留空或加说明 -->
-                </el-form-item>
+            </el-form-item>            
                 <el-form-item label="性别:" style="margin-left: 20px;">
                   <el-radio-group v-model="form.gender" style="margin-left: -50px;">
                     <el-radio label="不限" value="-1">不限</el-radio>
@@ -126,9 +126,9 @@
                 <el-form-item label="备注:">
                   <el-input type="textarea" v-model="form.remark" maxlength="500" show-word-limit placeholder="请输入"
                     :rows="3" />
-                </el-form-item>
-              </el-form>
-            </div>
+            </el-form-item>
+          </el-form>
+      </div>
 
             <div v-if="baseInfo.questionType" @click="selectBaseInfo" :class="{ selectedDiv: baseInfo.selected }">
               <span>&nbsp;</span>
@@ -174,14 +174,14 @@
 
               <div style="border-bottom: 1px solid #e5e7eb;width: 98%;" v-if="other.questionChildType == 'matrixScale'">
 
-                <el-row :gutter="10" class="mb8">
+        <el-row :gutter="10" class="mb8">
                   <el-col :span="3" style="margin-top: 30px;">
-                  </el-col>
+          </el-col>
                   <template v-for="clt in other.contentList">
                     <template v-if="clt.optionFlag">
                       <el-col :span="1" align="center" style="margin-top: 30px;margin-left: 30px;">
                         {{ clt.optionContent }}
-                      </el-col>
+          </el-col>
                     </template>
                   </template>
                 </el-row>
@@ -192,7 +192,7 @@
                       <template v-if="clt.labelFlag">
                         标题{{ idx + 1 }}:{{ clt.label }}
                       </template>
-                    </el-col>
+          </el-col>
                     <template v-for="clt2, idx in other.contentList">
                       <el-col :span="1" align="center" style="margin-left: 30px;">
                         <template v-if="clt2.optionFlag && clt.labelFlag">
@@ -202,8 +202,8 @@
                         </template>
                       </el-col>
                     </template>
-                  </el-row>
-                </template>
+        </el-row>
+      </template>
               </div>
 
               <div style="border-bottom: 1px solid #e5e7eb;width: 98%;" :class="{ selectedDiv: other.selected }"
@@ -225,7 +225,7 @@
                     <el-col :span="4">
                     </el-col>
                   </el-row>
-                </template>
+          </template>
                 <template v-if="other.questionType == 'questionTypeSelection'">
                   <el-row :gutter="10" class="mb8">
                     <el-col :span="12">
@@ -394,7 +394,7 @@
                               </el-input>
                             </el-radio>
                           </el-radio-group>
-                        </el-form-item>
+        </el-form-item>
                       </el-col>
                       <el-col :span="2" align="center" style="margin-top: -5px;">
                         <miniImageUpload :limit="1" v-model="ctl.img" />
@@ -431,7 +431,7 @@
                               <template #append><el-button
                                   @click="handleMatrixScaleDelete(index, idx, true)">-</el-button></template>
                             </el-input>
-                          </el-form-item>
+        </el-form-item>
                         </template>
                       </el-col>
                       <el-col :span="4" align="center" style="margin-top: -5px;">
@@ -468,7 +468,7 @@
                               <template #append><el-button
                                   @click="handleOtherBtnDelete(index, idx)">-</el-button></template>
                             </el-input>
-                          </el-form-item>
+        </el-form-item>
                         </div>
                       </el-col>
                       <el-col :span="2" align="center" style="margin-top: -5px;">
@@ -500,7 +500,7 @@
                               </el-input>
                             </el-radio>
                           </el-radio-group>
-                        </el-form-item>
+        </el-form-item>
                       </el-col>
                       <el-col :span="2" align="center" style="margin-top: -5px;">
                         <el-input style="width: 60px;" v-model="ctl.score" size="large" />
@@ -530,7 +530,7 @@
                             <template #append><el-button
                                 @click="handleOtherBtnDelete(index, idx)">-</el-button></template>
                           </el-input>
-                        </el-form-item>
+        </el-form-item>
                       </el-col>
                       <el-col :span="2" align="center" style="margin-top: -5px;">
                         <el-input style="width: 60px;" v-model="ctl.score" size="large" />
@@ -589,8 +589,8 @@
                   <el-button type="primary" icon="Delete" plain @click="deleteOtherInfo(index)">删除</el-button>
                 </div>
                 <span>&nbsp;</span>
-              </div>
-            </template>
+        </div>
+      </template>
 
 
           </el-scrollbar>
@@ -694,7 +694,7 @@ const getList = async () => {
   }
 
   if (id&&id!='0') {
-    loading.value = true;
+  loading.value = true;
     const res = await getScreeningAssessmentConfig(id as string);
     Object.assign(form.value, res.data);
     if(res.data.baseInfo){
@@ -703,7 +703,7 @@ const getList = async () => {
     if(res.data.otherInfo){
       otherInfo.value = res.data.otherInfo;
     }
-    loading.value = false;
+  loading.value = false;
   }
 }
 

+ 1 - 1
vite.config.ts

@@ -29,7 +29,7 @@ export default defineConfig(({ mode, command }) => {
       open: true,
       proxy: {
         [env.VITE_APP_BASE_API]: {
-          target: 'http://localhost:8080',
+          target: 'http://localhost:8081',
           changeOrigin: true,
           ws: true,
           rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')

Some files were not shown because too many files changed in this diff