JutarryWu преди 4 дни
родител
ревизия
4b7e2cb05f

BIN
src/assets/default-avatar.png


Файловите разлики са ограничени, защото са твърде много
+ 0 - 0
src/assets/icons/doctor.svg


+ 7 - 3
src/components/Chat/Avatar/index.vue

@@ -18,10 +18,14 @@ let props = defineProps({
   }
 })
 let url = computed(() => {
-  if (props.img?.indexOf('http') > -1) {
-    return props.img
+  if (props.img && props.img.length > 0) {
+    if (props.img?.indexOf('http') > -1) {
+      return props.img
+    } else {
+      return props.img
+    }
   } else {
-    return props.img
+    return '@/assets/default-avatar.png'
   }
 })
 </script>

+ 8 - 6
src/components/Chat/ChatComponent/index.vue

@@ -1,11 +1,7 @@
 <template>
   <section class="chat-container">
     <div class="h-[80px] flex-y-center flex-row top">
-      <avatar
-        :img="'https://gss0.baidu.com/-4o3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/dbb44aed2e738bd40f53cfe0ac8b87d6267ff9f5.jpgs'"
-        size="large"
-        class="ml-[32px]"
-      />
+      <avatar :img="userInfos.avatar" size="large" class="ml-[32px]" />
       <span class="ml-[32px] text-[26px] color-[#414D55]">{{ doctorInfo.name }}</span>
     </div>
     <div class="chat-main">
@@ -36,7 +32,7 @@
         </file-upload>
       </div>
       <div class="edit-div-area">
-        <EditDiv class="textarea" style="height: 100%" @change-text="changeText" />
+        <EditDiv class="textarea" @change-text="changeText" />
       </div>
       <el-button type="primary" class="send-btn" @click="mineSend()">发送 </el-button>
     </div>
@@ -398,6 +394,12 @@ defineExpose({
 
     .edit-div-area {
       height: calc(100% - 40px);
+
+      :deep(.el-scrollbar) {
+        .el-scrollbar__view {
+          height: 100%;
+        }
+      }
     }
   }
 }

+ 66 - 0
src/utils/index.ts

@@ -245,6 +245,30 @@ export function calculateAge(idCardNumber: string) {
   return age
 }
 
+/**
+ * 根据身份证号获取性别
+ * @param idCard
+ */
+export function getGenderFromIDCard(idCard: string): string | null {
+  // 首先校验身份证号是否有效
+  const reg15 = /^[1-9]\d{7}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))\d{3}$/
+  const reg18 = /^[1-9]\d{5}[1-9]\d{3}((0[1-9])|(1[0-12]))((0[1-9])|([1-2][0-9])|(3[0-1]))\d{3}(\d|X|x)$/
+
+  if (!reg15.test(idCard) && !reg18.test(idCard)) {
+    return null // 身份证号无效
+  }
+
+  // 获取第 17 位数字
+  const genderDigit = parseInt(idCard[idCard.length - 2], 10)
+
+  // 判断性别
+  if (genderDigit % 2 === 0) {
+    return '女'
+  } else {
+    return '男'
+  }
+}
+
 /**
  * 获取数据类型
  *
@@ -321,3 +345,45 @@ export function clearLocalStorageByPrefix(prefix: string): void {
     }
   })
 }
+
+/**
+ * 验证身份证号是否合法
+ * @param idCard
+ */
+export function validateIDCardStrict(idCard: string): boolean {
+  // 加权因子数组,用于计算校验码
+  const weightFactors: number[] = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
+  // 校验码对应表,用于比对计算出的校验码
+  const checkCodeMap: { [key: string]: string } = {
+    0: '1',
+    1: '0',
+    2: 'X',
+    3: '9',
+    4: '8',
+    5: '7',
+    6: '6',
+    7: '5',
+    8: '4',
+    9: '3',
+    10: '2'
+  }
+  // 先进行格式校验
+  const idCardRegex = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))\d{3}[0-9Xx]$/
+  if (!idCardRegex.test(idCard)) {
+    return false
+  }
+
+  // 提取前17位数字进行校验码计算
+  const idCard17 = idCard.substring(0, 17)
+  let sum: number = 0
+  for (let i = 0; i < 17; i++) {
+    sum += parseInt(idCard17[i]) * weightFactors[i]
+  }
+
+  // 计算校验码
+  const checkCodeIndex = sum % 11
+  const calculatedCheckCode = checkCodeMap[checkCodeIndex]
+
+  // 比对计算出的校验码和身份证号的最后一位
+  return calculatedCheckCode === idCard[17].toUpperCase()
+}

+ 0 - 1
src/views/gameCenter/components/Introduction/index.vue

@@ -156,7 +156,6 @@ const beginGame = () => {
       props.gameInfo.code?.indexOf('Cocos-') !== -1 ? <string>props.gameInfo.code?.split('-')[1] : props.gameInfo.code
     cocosUrl.value = `${window.location.origin}/${props.gameInfo.code?.indexOf('Cocos-') !== -1 ? 'cocos' : 'jquery'}/${cocosType.value}/?userID=${userStore.user.id}&planID=${tempPlanId}`
     console.log(cocosUrl.value)
-    debugger
     VoiceImpRef.value.pauseIntro()
     gameFlag.value.CocosDialog = true
   } else {

+ 11 - 1
src/views/gameCenter/components/games/CocosDialog/index.vue

@@ -2,7 +2,7 @@
   <my-full-screen-dialog ref="openDialogRef" close-color="#134FA4" :show-close="false" @close-dialog="handleClose">
     <div class="cocos-container w-full h-full flex flex-col items-center text-[#134FA4]">
       <iframe id="cocosDialog" :src="props.url" frameborder="0" allow="microphone *;camera *"></iframe>
-      <!--<iframe src="http://192.168.1.10:7456/web-mobile/ADL/index.html" frameborder="0"></iframe>-->
+      <!--      <iframe src="http://192.168.1.5:5588/jquery/CatchingBugs/" frameborder="0"></iframe>-->
     </div>
   </my-full-screen-dialog>
 </template>
@@ -15,6 +15,8 @@
  * 编写者: JutarryWu
  */
 import { onMounted } from 'vue'
+import { isJSON } from '@/utils'
+import AchievementAPI from '@/api/tester/rehabilitation/training/achievement'
 
 const props = defineProps({
   code: {
@@ -43,6 +45,14 @@ async function exec() {
   window.addEventListener('message', (e: MessageEvent) => {
     if (e.data === 'close') {
       handleClose(() => {})
+    } else if (e.data.includes('jquery-submitData-')) {
+      let tempData = e.data.split('-')[2]
+      if (isJSON(tempData)) {
+        AchievementAPI.add(JSON.parse(tempData)).then(() => {
+          ElMessage.success('本次训练已结束')
+          handleClose(() => {})
+        })
+      }
     }
   })
 }

+ 1 - 6
src/views/information/chatList/index.vue

@@ -16,11 +16,7 @@
           class="user-item bor-radius-8 p-[8px] flex flex-row flex-items-center h-[84px] hover:bg-[#F1F5F8] border-b-[1px] border-[#f1f5f8]"
           @click="handleClickUser(item)"
         >
-          <el-image
-            :src="'https://gss0.baidu.com/-4o3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/dbb44aed2e738bd40f53cfe0ac8b87d6267ff9f5.jpgs'"
-            fit="fill"
-            class="w-[52px] h-[52px] ml-[4px] bor-radius-8"
-          />
+          <el-image :src="item.avatar" fit="fill" class="w-[52px] h-[52px] ml-[4px] bor-radius-8" />
           <div class="flex-1 ml-[24px] h-[54px]">
             <div class="w-full h-full flex flex-row flex-items-center flex-justify-between">
               <div class="h-full flex flex-col">
@@ -182,7 +178,6 @@ async function exec() {
 }
 
 const handleClickUser = (item: UserType) => {
-  console.log(item)
   userInfos = item
   showRightChat.value = true
 

+ 43 - 2
src/views/login/components/login/index.vue

@@ -33,7 +33,7 @@
         </template>
       </el-input>
     </el-form-item>
-    <el-checkbox v-model="rememberPsw" label="记住密码" size="large" />
+    <el-checkbox v-model="rememberPsw" label="记住密码" size="large" @change="checkboxChange" />
 
     <!-- 登录按钮 -->
     <el-button
@@ -53,11 +53,17 @@
 import { useUserStore } from '@/store'
 import { LocationQuery, LocationQueryValue, useRoute } from 'vue-router'
 import router from '@/router'
-const $emits = defineEmits([])
+
+import { useSocket } from '@/utils/websoket'
+import { isJSON } from '@/utils'
+const { wsSend, wsOn } = useSocket()
 
 import openEyesUrl from '@/assets/images/icon-eyes-open.png'
 import closeEyesUrl from '@/assets/images/icon-eyes-close.png'
 import { LoginData } from '@/api/auth'
+import { checkboxEmits } from 'element-plus'
+
+const $emits = defineEmits([])
 
 // Stores
 const userStore = useUserStore()
@@ -141,6 +147,41 @@ function handleLogin() {
     }
   })
 }
+
+const checkboxChange = (val: boolean) => {
+  if (val) {
+    wsSend(
+      JSON.stringify({
+        dataSource: 'WebLogin',
+        msg: 'set-remember-flag-YES'
+      })
+    )
+  } else {
+    wsSend(
+      JSON.stringify({
+        dataSource: 'WebLogin',
+        msg: 'set-remember-flag-NO'
+      })
+    )
+  }
+}
+
+onMounted(() => {
+  wsSend(
+    JSON.stringify({
+      dataSource: 'WebLogin',
+      msg: 'check-remember-psw'
+    })
+  )
+
+  wsOn('message', (data: string) => {
+    if (data === 'check-remember-psw-YES') {
+      rememberPsw.value = true
+    } else if (data === 'check-remember-psw-NO') {
+      rememberPsw.value = false
+    }
+  })
+})
 </script>
 
 <style lang="scss" scoped>

+ 2 - 2
src/views/system/user/index.vue

@@ -101,7 +101,7 @@
         </el-form-item>
 
         <el-form-item label="手机号码" prop="phone">
-          <el-input v-model="formData.phone" :readonly="!!formData.id" placeholder="请输入手机号码" maxlength="11" />
+          <el-input v-model="formData.phone" placeholder="请输入手机号码" maxlength="11" />
         </el-form-item>
 
         <el-form-item label="用户姓名" prop="name">
@@ -249,8 +249,8 @@ function handleQuery() {
 
 /** 重置查询 */
 function resetQuery() {
-  queryFormRef.value.resetFields()
   queryParams.pageNum = 1
+  queryParams.username = ''
   handleQuery()
 }
 

+ 24 - 4
src/views/tester/components/AddTester/index.vue

@@ -97,6 +97,7 @@ import UserAPI, { UserForm } from '@/api/user'
 import { getCurrentInstance } from 'vue'
 import { CaseInfoVO } from '@/api/tester/case'
 import { FormInstance } from 'element-plus'
+import { getGenderFromIDCard, validateIDCardStrict } from '@/utils'
 
 const instance = getCurrentInstance()
 const loading = ref(false) //  加载状态
@@ -115,6 +116,23 @@ const caseAddShow = ref(false) // 病例页面是否展示
 const isAlreadyExists = ref(false) // 用户是否已经存在
 const showEmptyCaseLog = ref(false) // 若患者不存在数据库时,查询后显示空病例区域
 
+const validateIdCardPass = (rule: any, value: any, callback: any) => {
+  if (value === '') {
+    callback(new Error('请输入身份证号码'))
+  } else {
+    if (value.length === 15 || value.length === 18) {
+      if (!userFormRef.value) return
+      if (validateIDCardStrict(value)) {
+        callback()
+      } else {
+        callback(new Error('身份证号码不合法'))
+      }
+    } else {
+      callback(new Error('身份证号码长度应为 15 或者 18位'))
+    }
+  }
+}
+
 const rules = reactive({
   name: [
     { required: true, message: '请输入患者姓名', trigger: 'blur' },
@@ -126,10 +144,7 @@ const rules = reactive({
   ],
   sex: [{ required: true, message: '请选择性别', trigger: 'blue' }],
   code: [{ required: true, message: '请输入系统登录账号', trigger: 'blur' }],
-  cardNo: [
-    { required: true, message: '请输入身份证号码', trigger: 'blur' },
-    { min: 10, max: 50, message: '长度应为 15 到 18', trigger: 'blur' }
-  ],
+  cardNo: [{ required: true, validator: validateIdCardPass, trigger: 'blur' }],
   phone: [
     { required: true, message: '请输入系统登录账号(手机号)', trigger: 'blur' },
     {
@@ -204,6 +219,11 @@ const handleAutoCompleteChange = (val: string) => {
     instance?.proxy?.$Bus.emit('case-info-log', {
       show: false
     })
+  } else {
+    let tempSex = getGenderFromIDCard(val)
+    if (tempSex) {
+      userForm.sex = tempSex
+    }
   }
 }
 

+ 25 - 1
src/views/tester/components/CaseInformation/CaseAdd/index.vue

@@ -61,7 +61,11 @@
               <el-input v-model="caseForm.duration" placeholder="请输入持续时间" />
             </el-form-item>
             <el-form-item v-if="caseForm.epileptic === '1'" label="发作次数" prop="nbout">
-              <el-input v-model="caseForm.nbout" type="number" placeholder="请输入发作次数" />
+              <el-input-number v-model="caseForm.nbout" :min="1" :max="100" controls-position="right">
+                <template #suffix>
+                  <span>次</span>
+                </template>
+              </el-input-number>
             </el-form-item>
           </el-col>
         </el-row>
@@ -258,6 +262,26 @@ onUnmounted(() => {
       padding: 10px 16px;
     }
   }
+
+  :deep(.el-input-number) {
+    width: 100%;
+    height: 50px;
+    font-size: 15px;
+
+    .el-input-number__increase {
+      height: 50%;
+    }
+
+    .el-input-number__decrease {
+      height: 50%;
+    }
+
+    .el-input__wrapper {
+      background-color: #f1f5f8;
+      box-shadow: none;
+      padding: 10px 64px 10px 16px;
+    }
+  }
   :deep(.el-textarea) {
     font-size: 15px;
     .el-textarea__inner {

+ 44 - 24
src/views/tester/components/CaseInformation/CaseLog/index.vue

@@ -57,34 +57,54 @@
                 <span class="inline-block flex-1 text-[16px] line-height-[24px]">
                   {{ dayjs(item.tdate).format('YYYY年MM月DD日 HH:mm') }}
                 </span>
-                <span class="inline-block w-[98px] mr-[12px] text-right text-[16px] h-[24px] line-height-[24px]">
-                  是否昏迷:
-                </span>
-                <span class="inline-block flex-1 text-[16px] line-height-[24px]">
-                  {{ item.coma === '0' ? '否' : '是' }}
-                </span>
               </div>
               <div class="flex flex-row mt-[4px]">
-                <span class="inline-block w-[98px] mr-[12px] text-right text-[16px] h-[24px] line-height-[24px]">
-                  持续时间:
-                </span>
-                <span class="inline-block flex-1 text-[16px] line-height-[24px]">
-                  {{ item.duration }}
-                </span>
-                <span class="inline-block w-[98px] mr-[12px] text-right text-[16px] h-[24px] line-height-[24px]">
-                  发作次数:
-                </span>
-                <span class="inline-block flex-1 text-[16px] line-height-[24px]">
-                  {{ item.nbout }}
-                </span>
+                <div class="w-50% flex flex-row">
+                  <span class="inline-block w-[98px] mr-[12px] text-right text-[16px] h-[24px] line-height-[24px]">
+                    是否昏迷:
+                  </span>
+                  <span class="inline-block flex-1 text-[16px] line-height-[24px]">
+                    {{ item.coma === '0' ? '否' : '是' }}
+                  </span>
+                </div>
+                <div class="w-50% flex flex-row">
+                  <span class="inline-block w-[128px] mr-[12px] text-right text-[16px] h-[24px] line-height-[24px]">
+                    是否继发癫痫:
+                  </span>
+                  <span class="inline-block flex-1 text-[16px] line-height-[24px]">
+                    {{ item.epileptic === '0' ? '否' : '是' }}
+                  </span>
+                </div>
               </div>
               <div class="flex flex-row mt-[4px]">
-                <span class="inline-block w-[98px] mr-[12px] text-right text-[16px] h-[24px] line-height-[24px]">
-                  格斯拉评分:
-                </span>
-                <span class="inline-block flex-1 text-[16px] line-height-[24px]">
-                  {{ item.score }}
-                </span>
+                <div class="w-50% flex flex-row">
+                  <template v-if="item.coma === '1'">
+                    <span class="inline-block w-[98px] mr-[12px] text-right text-[16px] h-[24px] line-height-[24px]">
+                      格斯拉评分:
+                    </span>
+                    <span class="inline-block flex-1 text-[16px] line-height-[24px]">
+                      {{ item.score }}
+                    </span>
+                  </template>
+                </div>
+                <div class="w-50%">
+                  <template v-if="item.epileptic === '1'">
+                    <div class="w-full flex flex-row">
+                      <span class="inline-block w-[128px] mr-[12px] text-right text-[16px] h-[24px] line-height-[24px]">
+                        持续时间:
+                      </span>
+                      <span class="inline-block flex-1 text-[16px] line-height-[24px]">
+                        {{ item.duration }}
+                      </span>
+                    </div>
+                    <div class="w-full flex flex-row">
+                      <span class="inline-block w-[128px] mr-[12px] text-right text-[16px] h-[24px] line-height-[24px]">
+                        发作次数:
+                      </span>
+                      <span class="inline-block flex-1 text-[16px] line-height-[24px]"> {{ item.nbout }} 次 </span>
+                    </div>
+                  </template>
+                </div>
               </div>
               <div class="flex flex-row mt-[4px]">
                 <span class="inline-block w-[98px] mr-[12px] text-right text-[16px] h-[24px] line-height-[24px]">

+ 1 - 5
src/views/tester/components/RehabilitationEvaluation/RehabilitationEvaluationMgr/components/RehabilitationEvaluationMgrCognition/index.vue

@@ -8,7 +8,7 @@
         </el-form-item>
         <el-form-item label="认知任务分类:" prop="name">
           <el-select v-model="queryParams.typeId" placeholder="认知任务类别">
-            <el-option v-for="item in scaleTypeList" :key="item.id" :label="item.name" :value="item.id" />
+            <el-option v-for="item in scaleTypeList" :key="item.id" :label="item.name" :value="item.id!" />
           </el-select>
         </el-form-item>
 
@@ -76,10 +76,6 @@ import { useUserStore } from '@/store'
 import { UserPageVO } from '@/api/user'
 import { ElTable } from 'element-plus'
 import EvaluationCognitionSubjectAPI from '@/api/tester/evaluation/logCognition'
-import { useSocket } from '@/utils/websoket'
-import { isJSON } from '@/utils'
-
-const { socket, wsSend, wsOn, wsOff } = useSocket()
 
 defineOptions({
   name: 'EvaluationCognition',

+ 2 - 2
src/views/tester/components/RehabilitationEvaluation/RehabilitationEvaluationReportLog/index.vue

@@ -5,7 +5,7 @@
     <div class="search-container flex flex-row justify-between">
       <el-form ref="queryFormRef" :model="queryParams" :inline="true">
         <el-form-item label="评定记录:" prop="name">
-          <el-select v-model="queryParams.evaluateId" placeholder="评定记录" clearable @change="handleQuery">
+          <el-select v-model="queryParams.evaluateId" placeholder="评定记录" clearable>
             <el-option
               v-for="(item, index) in EvaluationLogData"
               :key="index"
@@ -447,7 +447,7 @@ function resetQuery() {
 }
 
 const handleDelete = (row: any) => {
-  ElMessageBox.confirm('确认删除记录?', '删除', {
+  ElMessageBox.confirm('确认删除记录?', '删除', {
     confirmButtonText: '确定',
     cancelButtonText: '取消',
     type: 'warning'

+ 4 - 3
src/views/tester/components/RehabilitationGoals/index.vue

@@ -4,7 +4,7 @@
       <simple-title title="康复目标" />
       <div class="w-full h-[110px] flex flex-row mt-[12px]">
         <el-image
-          :src="userInfo?.avatar || DefaultAvatar"
+          :src="userInfo?.avatar || 'static/image/user/default-avatar.png'"
           class="w-[100px] h-[100px] bor-radius-8 mr-[48px]"
           fit="fill"
         />
@@ -14,7 +14,9 @@
             <span class="ml-8">{{ userInfo?.sex }} / 22岁</span>
           </div>
           <div class="text-[#121A2D] text-[14px] mt-[20px]">入院时间:{{ userInfo?.ctime.slice(0, 16) }}</div>
-          <div v-if="false" class="text-[#121A2D] text-[14px] mt-[20px]">训练时间:{{ userInfo?.ctime.slice(0, 16) }}</div>
+          <div v-if="false" class="text-[#121A2D] text-[14px] mt-[20px]">
+            训练时间:{{ userInfo?.ctime.slice(0, 16) }}
+          </div>
         </div>
       </div>
       <div class="w-full mt-[12px] flex flex-row">
@@ -64,7 +66,6 @@
  */
 import { useUserStore } from '@/store'
 import UserAPI, { UserPageVO } from '@/api/user'
-import DefaultAvatar from '@/assets/default-avatar.png'
 
 const userStore = useUserStore()
 const userInfo = ref<UserPageVO>()

+ 1 - 2
src/views/tester/evaluation/infos/index.vue

@@ -38,7 +38,6 @@ import { computed, reactive, onMounted, type PropType, type ComponentPublicInsta
 import router from '@/router'
 import { useUserStore } from '@/store'
 import UserAPI, { UserPageQuery, UserPageVO } from '@/api/user'
-import DefaultAvatar from '@/assets/default-avatar.png'
 
 const loading = ref(false) //  加载状态
 const userStore = useUserStore()
@@ -66,7 +65,7 @@ function handleQuery() {
   UserAPI.getPage(queryParams)
     .then((data) => {
       pageData.value = data.records?.map((item) => {
-        item.avatar = item.avatar && item.avatar.length > 0 ? item.avatar : DefaultAvatar
+        item.avatar = item.avatar && item.avatar.length > 0 ? item.avatar : 'static/image/user/default-avatar.png'
         return item
       })
       total.value = data.total

Някои файлове не бяха показани, защото твърде много файлове са промени