瀏覽代碼

问题修改与优化

jiapu 3 月之前
父節點
當前提交
c55e8bfa0b
共有 2 個文件被更改,包括 121 次插入3 次删除
  1. 55 0
      code/frontend/src/utils/date.js
  2. 66 3
      code/frontend/src/views/plan/index.vue

+ 55 - 0
code/frontend/src/utils/date.js

@@ -0,0 +1,55 @@
+function pad(value) {
+  return String(value).padStart(2, '0')
+}
+
+function formatDateObject(date) {
+  return [
+    date.getFullYear(),
+    pad(date.getMonth() + 1),
+    pad(date.getDate())
+  ].join('-') + ' ' + [
+    pad(date.getHours()),
+    pad(date.getMinutes()),
+    pad(date.getSeconds())
+  ].join(':')
+}
+
+export function formatDateTime(value, emptyText = '-') {
+  if (value === null || value === undefined || value === '') {
+    return emptyText
+  }
+
+  if (value instanceof Date) {
+    return Number.isNaN(value.getTime()) ? emptyText : formatDateObject(value)
+  }
+
+  if (typeof value === 'number') {
+    const date = new Date(value)
+    return Number.isNaN(date.getTime()) ? emptyText : formatDateObject(date)
+  }
+
+  const text = String(value).trim()
+  if (!text) {
+    return emptyText
+  }
+
+  if (/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}/.test(text)) {
+    return text.slice(0, 19).replace('T', ' ')
+  }
+
+  if (/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}$/.test(text)) {
+    return `${text.slice(0, 16).replace('T', ' ')}:00`
+  }
+
+  if (/^\d{4}-\d{2}-\d{2}$/.test(text)) {
+    return `${text} 00:00:00`
+  }
+
+  const date = new Date(text)
+  return Number.isNaN(date.getTime()) ? text : formatDateObject(date)
+}
+
+export function dateTimeFormatter(row, column, cellValue) {
+  const value = cellValue ?? row?.[column?.property]
+  return formatDateTime(value)
+}

+ 66 - 3
code/frontend/src/views/plan/index.vue

@@ -194,9 +194,19 @@
           </el-col>
         </el-row>
         <el-form-item label="适用症状" prop="symptomsList">
-          <el-checkbox-group v-model="formData.symptomsList">
+          <el-checkbox-group v-model="formData.symptomsList" class="symptom-checkboxes">
             <el-checkbox v-for="s in symptomsOptions" :key="s" :label="s" />
           </el-checkbox-group>
+          <div v-if="dialogMode !== 'view'" class="symptom-add-row">
+            <el-input
+              v-model="customSymptom"
+              placeholder="输入症状名称"
+              maxlength="20"
+              clearable
+              @keyup.enter="addCustomSymptom"
+            />
+            <el-button type="primary" :icon="Plus" @click="addCustomSymptom">添加</el-button>
+          </div>
         </el-form-item>
         <el-form-item label="方案描述">
           <el-input v-model="formData.description" type="textarea" :rows="2" maxlength="200" show-word-limit />
@@ -365,7 +375,8 @@ import { useUserStore } from '@/store/user'
 import { formatDateTime } from '@/utils/date'
 // ============ 枚举常量 ============
 const effectOptions = ['驱寒', '祛湿', '祛风', '化瘀', '活血', '化痰', '养颜', '扶阳']
-const symptomsOptions = ['怕冷', '感冒', '咳嗽', '痰多', '疼痛', '腰酸', '失眠', '疲劳', '皮肤暗沉', '手脚冰凉', '其他']
+const defaultSymptomsOptions = ['怕冷', '感冒', '咳嗽', '痰多', '疼痛', '腰酸', '失眠', '疲劳', '皮肤暗沉', '手脚冰凉']
+const symptomsOptions = ref([...defaultSymptomsOptions])
 const userStore = useUserStore()
 
 // ============ 选项列表(用于选择框) ============
@@ -488,6 +499,7 @@ const dialogTitle = ref('')
 const dialogMode = ref('add')
 const submitLoading = ref(false)
 const formRef = ref(null)
+const customSymptom = ref('')
 
 const defaultStep = () => ({
   acupointId: null,
@@ -548,6 +560,39 @@ function onTechniqueChange(id, index) {
   formData.steps[index].techniqueName = found ? found.name : ''
 }
 
+function parseSymptoms(symptoms) {
+  return (symptoms || '')
+    .split(',')
+    .map(item => item.trim())
+    .filter(Boolean)
+    .filter((item, index, list) => list.indexOf(item) === index)
+}
+
+function syncSymptomOptions(symptoms) {
+  symptoms.forEach(item => {
+    if (!symptomsOptions.value.includes(item)) {
+      symptomsOptions.value.push(item)
+    }
+  })
+}
+
+function addCustomSymptom() {
+  const symptom = customSymptom.value.trim()
+  if (!symptom) {
+    ElMessage.warning('请输入症状名称')
+    return
+  }
+  if (/[,,]/.test(symptom)) {
+    ElMessage.warning('症状名称不能包含逗号')
+    return
+  }
+  syncSymptomOptions([symptom])
+  if (!formData.symptomsList.includes(symptom)) {
+    formData.symptomsList.push(symptom)
+  }
+  customSymptom.value = ''
+}
+
 function getCurrentAuthorId() {
   return userStore.userInfo?.userId || null
 }
@@ -588,6 +633,7 @@ function removeStep(index) {
 function handleAdd() {
   Object.assign(formData, defaultForm())
   formData.steps = [defaultStep()]
+  customSymptom.value = ''
   applyCurrentAuthor()
   dialogTitle.value = '新增方案'
   dialogMode.value = 'add'
@@ -600,11 +646,14 @@ function handleAdd() {
 async function handleEdit(row) {
   const res = await getPlanDetail(row.id)
   const detail = res.data
+  const symptomsList = parseSymptoms(detail.symptoms)
+  syncSymptomOptions(symptomsList)
   Object.assign(formData, defaultForm(), {
     ...detail,
-    symptomsList: detail.symptoms ? detail.symptoms.split(',') : [],
+    symptomsList,
     steps: detail.steps?.length > 0 ? detail.steps : [defaultStep()]
   })
+  customSymptom.value = ''
   applyCurrentAuthor()
   dialogTitle.value = '编辑方案'
   dialogMode.value = 'edit'
@@ -759,6 +808,20 @@ onMounted(() => {
   justify-content: flex-end;
 }
 
+.symptom-checkboxes {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 0 20px;
+}
+
+.symptom-add-row {
+  display: flex;
+  gap: 8px;
+  width: 360px;
+  max-width: 100%;
+  margin-top: 8px;
+}
+
 .step-row {
   border: 1px solid #ebeef5;
   border-radius: 6px;