瀏覽代碼

feature:调整图片剪切,修改注册提示

liuzhenlin 1 周之前
父節點
當前提交
eaf734b6cd
共有 5 個文件被更改,包括 281 次插入258 次删除
  1. 3 0
      src/constants/pageConstants.ts
  2. 0 1
      src/view/instr/appointList/inProgress/index.vue
  3. 30 20
      src/view/login/index.vue
  4. 1 1
      src/view/todo/detail.vue
  5. 247 236
      src/view/user/edit.vue

+ 3 - 0
src/constants/pageConstants.ts

@@ -217,3 +217,6 @@ const PATH = 'pages/appointList/user'
 export const scanCodeWxUrl = (query: string) => {
   return `weixin://dl/business/?appid=${APPID}&path=${PATH}&query=scene=${query}`
 }
+
+// 用户 头像大小 / M
+export const userImgSize = 3

+ 0 - 1
src/view/instr/appointList/inProgress/index.vue

@@ -176,7 +176,6 @@ export default {
             message: `本次上机时长共计${useTime}分钟,确定要下机吗?`
           })
             .then((e) => {
-              console.log(e)
               this.getOff()
             })
             .catch(() => {

+ 30 - 20
src/view/login/index.vue

@@ -40,13 +40,8 @@
     <footer>
       <img width="124" src="../../assets/img/slogan.png" />
     </footer>
-    <van-dialog
-      v-model:show="noticeDialogVisible"
-      title="注册须知"
-      :show-confirm-button="false"
-      :show-cancel-button="false"
-      class="notice-dialog"
-    >
+    <van-dialog v-model:show="noticeDialogVisible" title="注册须知" :show-confirm-button="false" :show-cancel-button="false"
+      class="notice-dialog">
       <div class="notice-content">
         <div class="notice-list">
           <div class="notice-item" v-for="(item, index) in noticeContent" :key="index">
@@ -55,7 +50,7 @@
           </div>
         </div>
         <van-checkbox v-model="noticeChecked" icon-size="18px" class="agreement-checkbox">
-          我已阅读并同意注册须知
+          我已阅读并同意注册注意事项
         </van-checkbox>
         <div class="notice-buttons">
           <van-button block plain hairline class="notice-btn" @click="noticeDialogVisible = false">
@@ -92,26 +87,32 @@ const showPassword = ref(false)
 const noticeDialogVisible = ref(false)
 const noticeChecked = ref(false)
 const noticeContent = ref([
+  // 注册须知内容
   {
-    title: '校内课题组负责人',
-    content:
-      '点击统一身份登录,会自动建立同名课题组,完善课题组信息。(组织机构选择默认的远程组织机构,完善邮箱电话等信息,客户端密码暂与信息门户密码一致)提示注册成功后即可登录。',
+    title: '院内人员',
+    content: '遵义医科大学附属医院的职工和学生 '
   },
   {
-    title: '校内普通用户',
-    content:
-      '点击统一身份登录,完善个人信息,选择对应老师的课题组(如搜索不到请联系导师先注册课题组),注册之后等待课题组负责人审核激活。',
+    title: '校内人员:',
+    content: '遵义医科大学、二附院、三附院、附属口腔医院、珠海校区的职工和学生'
   },
   {
-    title: '校外用户加入已有课题组',
-    content:
-      '设置账户密码后点击下一步,完善个人信息后选择需要加入的对应课题组,提交后等待课题组负责人审核激活。',
+    title: '院外人员:',
+    content: '除以上两类人员,均属于院外人员'
   },
   {
-    title: '校外用户注册新课题组',
-    content:
-      '设置账号密码后点击下一步,点击新建课题组,完善基本信息(单位名称填写公司名称或学校名称,组织机构选择企业或其他高校,注册课题组的同时该课题组的负责人信息会一并注册,无需重复注册个人用户),注册成功后联系管理员激活。',
+    title: '课题组负责人注册',
+    content: '若您是导师或经费自主者,请勾选课题组负责人进行注册,账号可以是工号或其他数字,填写完整的课题信息和个人信息,提交后请联系我中心管理员审核。'
   },
+  {
+    title: '课题组成员注册',
+    content: '若您是学生,请勾选课题组成员进行注册,关联到导师课题组(若导师还未注册账号,请联系导师先注册课题组负责人后,您再注册),账号可以是工号、学号或其他数字,填写完整的个人信息提交后,请联系导师审核通过。'
+  },
+  {
+    title: '头像上传要求',
+    content: '小于3MB的颈部以上头像即可(头像须上传,便于申请平台入室后关联门禁扫脸)'
+  },
+
 ])
 const state = reactive({
   captchaImage: '',
@@ -297,6 +298,7 @@ onMounted(async () => {
     margin-left: 16px;
   }
 }
+
 .notice-dialog {
   :deep(.van-dialog__header) {
     font-size: 18px;
@@ -308,6 +310,7 @@ onMounted(async () => {
     overflow-y: auto;
     padding: 20px;
   }
+
   .notice-title {
     text-align: center;
     color: #333;
@@ -315,30 +318,37 @@ onMounted(async () => {
     font-size: 14px;
     font-weight: 600;
   }
+
   .notice-list {
     margin-bottom: 14px;
   }
+
   .notice-item {
     margin-bottom: 12px;
   }
+
   .notice-item-title {
     font-weight: 600;
     color: #333;
     margin-bottom: 4px;
     font-size: 14px;
   }
+
   .notice-item-content {
     color: #666;
     line-height: 1.5;
     font-size: 14px;
   }
+
   .agreement-checkbox {
     margin: 16px 0;
     color: #666;
   }
+
   .notice-buttons {
     display: flex;
     gap: 12px;
+
     .notice-btn {
       flex: 1;
     }

+ 1 - 1
src/view/todo/detail.vue

@@ -22,7 +22,7 @@
     </van-cell-group>
     <h4>附件信息</h4>
     <InstrumentAppointment v-if="state.form.defCode === 'instrument_appointment'" :code="state.form.businessCode" />
-    
+
     <h4>审批记录</h4>
     <FlowTable :id="state.form.id" :businessCode="state.form.businessCode" :defCode="state.form.defCode" />
     <h4 v-if="state.type === 'approval'">审批意见</h4>

+ 247 - 236
src/view/user/edit.vue

@@ -22,13 +22,15 @@
             <van-image width="30px" height="30px" :src="userInfos.avatar" />
           </template>
         </van-cell>
-        <van-field v-model="state.form.nickName" label="用户昵称" placeholder="用户昵称" :rules="[{ required: true, message: '请输入用户昵称' }]" />
+        <van-field v-model="state.form.nickName" label="用户昵称" placeholder="用户昵称"
+          :rules="[{ required: true, message: '请输入用户昵称' }]" />
         <van-field v-model="state.form.phone" label="手机号" placeholder="手机号"> </van-field>
         <van-field v-model="state.form.email" label="电子邮箱" placeholder="电子邮箱" />
         <van-field v-model="state.form.sex" label="性别" placeholder="性别">
           <template #input>
             <van-radio-group v-model="state.form.sex" direction="horizontal">
-              <van-radio v-for="item in userSexList" :key="item.id" :name="item.dictValue">{{ item.dictLabel }}</van-radio>
+              <van-radio v-for="item in userSexList" :key="item.id" :name="item.dictValue">{{ item.dictLabel
+              }}</van-radio>
             </van-radio-group>
           </template>
         </van-field>
@@ -39,10 +41,12 @@
       </div>
     </van-form>
     <!-- 剪裁图片组件 -->
-    <van-popup class="bg-tran" v-model:show="cropperState.isShowDialog" closeable @close="closeDialog" position="bottom" :style="{ padding: '10px' }">
+    <van-popup class="bg-tran" v-model:show="cropperState.isShowDialog" closeable @close="closeDialog" position="bottom"
+      :style="{ padding: '10px' }">
       <div class="cropper-warp">
         <div class="cropper-warp-left">
-          <img :src="typeof cropperState.cropperImg === 'string' ? cropperState.cropperImg : ''" class="cropper-warp-left-img" />
+          <img :src="typeof cropperState.cropperImg === 'string' ? cropperState.cropperImg : ''"
+            class="cropper-warp-left-img" />
         </div>
         <!-- <div class="cropper-warp-right">
           <div class="cropper-warp-right-title">预览</div>
@@ -65,262 +69,269 @@
 </template>
 
 <script lang="ts" setup>
-  import { storeToRefs } from 'pinia'
-  import { useUserInfo } from '/@/stores/userInfo'
-  import { Local } from '/@/utils/storage'
-  import { showConfirmDialog, showDialog, showNotify } from 'vant'
-  import { useRouter } from 'vue-router'
-  import { nextTick, onMounted, reactive, ref } from 'vue'
-  import { useUserApi } from '/@/api/system/user'
-  import to from 'await-to-js'
-  import { useDictApi } from '/@/api/system/dict'
-  import Cropper from 'cropperjs'
-  import 'cropperjs/dist/cropper.css'
-  import axios from 'axios'
+import { storeToRefs } from 'pinia'
+import { useUserInfo } from '/@/stores/userInfo'
+import { showNotify } from 'vant'
+import { useRouter } from 'vue-router'
+import { nextTick, onMounted, reactive, ref } from 'vue'
+import { useUserApi } from '/@/api/system/user'
+import to from 'await-to-js'
+import { useDictApi } from '/@/api/system/dict'
+import Cropper from 'cropperjs'
+import 'cropperjs/dist/cropper.css'
+import axios from 'axios'
+import { userImgSize } from '/@/constants/pageConstants'
 
-  const router = useRouter()
-  const storesUseUserInfo = useUserInfo()
-  const { userInfos } = storeToRefs(storesUseUserInfo)
-  const userApi = useUserApi()
-  const formRef = ref()
-  const dictApi = useDictApi()
-  const userSexList = ref(<RowDicDataType[]>[])
-  const state = reactive({
-    form: {
-      id: 0,
-      userId: 0, // 用户账号
-      nickName: '', // 用户昵称
-      phone: '', // 手机号
-      email: '', // 电子邮件
-      sex: '', // 性别
-      avatar: '', // 头像图片地址
-      pgName: ''
-    },
-    dialog: {
-      isShowDialog: false,
-      type: '',
-      title: '',
-      submitTxt: ''
-    }
-  })
-  // 定义变量内容
-  const cropperState = reactive({
+const router = useRouter()
+const storesUseUserInfo = useUserInfo()
+const { userInfos } = storeToRefs(storesUseUserInfo)
+const userApi = useUserApi()
+const formRef = ref()
+const dictApi = useDictApi()
+const userSexList = ref(<RowDicDataType[]>[])
+const state = reactive({
+  form: {
+    id: 0,
+    userId: 0, // 用户账号
+    nickName: '', // 用户昵称
+    phone: '', // 手机号
+    email: '', // 电子邮件
+    sex: '', // 性别
+    avatar: '', // 头像图片地址
+    pgName: ''
+  },
+  dialog: {
     isShowDialog: false,
-    cropperImg: '' as ArrayBuffer | string,
-    cropperImgBase64: '',
-    cropper: '' as RefType
+    type: '',
+    title: '',
+    submitTxt: ''
+  }
+})
+// 定义变量内容
+const cropperState = reactive({
+  isShowDialog: false,
+  cropperImg: '' as ArrayBuffer | string,
+  cropperImgBase64: '',
+  cropper: '' as RefType
+})
+const cropper = ref()
+const getDicts = () => {
+  Promise.all([dictApi.getDictDataByType('sys_com_sex')]).then(([sex]) => {
+    userSexList.value = sex.data.values || []
   })
-  const cropper = ref()
-  const getDicts = () => {
-    Promise.all([dictApi.getDictDataByType('sys_com_sex')]).then(([sex]) => {
-      userSexList.value = sex.data.values || []
+}
+const afterRead = (res: any) => {
+  const rawFile = res.file
+  if (
+    rawFile.type !== 'image/jpeg' &&
+    rawFile.type !== 'image/jpg' &&
+    rawFile.type !== 'image/png' &&
+    rawFile.type !== 'image/bmp' &&
+    rawFile.type !== 'image/gif'
+  ) {
+    showNotify({
+      message: '上传图片必须是JPG/PNG/BMP/GIF类型!',
+      type: 'warning'
     })
-  }
-  const afterRead = (res: any) => {
-    const rawFile = res.file
-    if (
-      rawFile.type !== 'image/jpeg' &&
-      rawFile.type !== 'image/jpg' &&
-      rawFile.type !== 'image/png' &&
-      rawFile.type !== 'image/bmp' &&
-      rawFile.type !== 'image/gif'
-    ) {
-      showNotify({
-        message: '上传图片必须是JPG/PNG/BMP/GIF类型!',
-        type: 'warning'
-      })
-      return false
-    } else if (rawFile.size / 1024 / 1024 > 2) {
-      showNotify({
-        message: '图片大小不能超过2MB!',
-        type: 'warning'
-      })
-      return false
-    }
-    const reader = new FileReader()
-    reader.readAsDataURL(rawFile)
-    reader.onload = () => {
-      cropperState.cropperImg = reader.result
-      cropperState.cropper.destroy()
-      setTimeout(() => {
-        initCropper()
-      })
-    }
     return false
-  }
-  // 打开弹窗
-  const openDialog = (imgs: string) => {
-    cropperState.cropperImg = imgs
-    cropperState.isShowDialog = true
-    nextTick(() => {
-      initCropper()
+  } else if (rawFile.size / 1024 / 1024 > userImgSize) {
+    showNotify({
+      message: `图片大小不能超过${userImgSize}MB!`,
+      type: 'warning'
     })
+    return false
   }
-  // 初始化cropperjs图片裁剪
-  const initCropper = () => {
-    const letImg = <HTMLImageElement>document.querySelector('.cropper-warp-left-img')
-    cropperState.cropper = new Cropper(letImg, {
-      viewMode: 1,
-      dragMode: 'move',
-      initialAspectRatio: 1,
-      aspectRatio: 1,
-      preview: '.before',
-      background: false,
-      autoCropArea: 1,
-      cropBoxMovable: true, // 是否允许剪裁框拖动
-      cropBoxResizable: false, // 是否允许剪裁框缩放
-      zoomable: true,
-      ready() {
-        cropperState.cropper.setCropBoxData({
-          width: 500, // 宽度
-          height: 500 // 高度
-        })
-      },
-      crop: () => {
-        cropperState.cropperImgBase64 = cropperState.cropper
-          .getCroppedCanvas({ width: 500, height: 500 })
-          .toDataURL('image/jpeg')
-      }
+  const reader = new FileReader()
+  reader.readAsDataURL(rawFile)
+  reader.onload = () => {
+    cropperState.cropperImg = reader.result
+    cropperState.cropper.destroy()
+    setTimeout(() => {
+      initCropper()
     })
   }
-  const editAvatar = () => {
-    openDialog(state.form.avatar)
-  }
-  const onAvatarSubmit = () => {
-    const base64Url = cropperState.cropper.getCroppedCanvas({ width: 500, height: 500 }).toDataURL('image/jpeg')
-    let file = dataURLtoFile(base64Url, 'avatar.png')
-    uploadBaseFunc(file)
-  }
-  // base64转file
-  const dataURLtoFile = (dataurl, filename) => {
-    // 获取到base64编码
-    const arr = dataurl.split(',')
-    // 将base64编码转为字符串
-    const bstr = window.atob(arr[1])
-    let n = bstr.length
-    const u8arr = new Uint8Array(n) // 创建初始化为0的,包含length个元素的无符号整型数组
-    while (n--) {
-      u8arr[n] = bstr.charCodeAt(n)
+  return false
+}
+// 打开弹窗
+const openDialog = (imgs: string) => {
+  cropperState.cropperImg = imgs
+  cropperState.isShowDialog = true
+  nextTick(() => {
+    initCropper()
+  })
+}
+// 初始化cropperjs图片裁剪
+const initCropper = () => {
+  const letImg = <HTMLImageElement>document.querySelector('.cropper-warp-left-img')
+  cropperState.cropper = new Cropper(letImg, {
+    viewMode: 1,
+    dragMode: 'move',
+    initialAspectRatio: 1,
+    aspectRatio: 1,
+    preview: '.before',
+    background: false,
+    autoCropArea: 1,
+    cropBoxMovable: true, // 是否允许剪裁框拖动
+    cropBoxResizable: false, // 是否允许剪裁框缩放
+    zoomable: true,
+    ready() {
+      cropperState.cropper.setCropBoxData({
+        width: 500, // 宽度
+        height: 500 // 高度
+      })
+    },
+    crop: () => {
+      cropperState.cropperImgBase64 = cropperState.cropper
+        .getCroppedCanvas({ width: 500, height: 500 })
+        .toDataURL('image/jpeg')
     }
-    return new File([u8arr], filename, {
-      type: 'image/png'
-    })
+  })
+}
+const editAvatar = () => {
+  openDialog(state.form.avatar)
+}
+const onAvatarSubmit = () => {
+  const base64Url = cropperState.cropper.getCroppedCanvas({ width: 500, height: 500 }).toDataURL('image/jpeg')
+  let file = dataURLtoFile(base64Url, 'avatar.png')
+  uploadBaseFunc(file)
+}
+// base64转file
+const dataURLtoFile = (dataurl, filename) => {
+  // 获取到base64编码
+  const arr = dataurl.split(',')
+  // 将base64编码转为字符串
+  const bstr = window.atob(arr[1])
+  let n = bstr.length
+  const u8arr = new Uint8Array(n) // 创建初始化为0的,包含length个元素的无符号整型数组
+  while (n--) {
+    u8arr[n] = bstr.charCodeAt(n)
   }
-  // 上传图片获取地址
-  const uploadBaseFunc = (file) => {
-    const formData = new FormData()
-    formData.append('file', file)
-    const uploadUrl = import.meta.env.VITE_UPLOAD // 上传的图片服务器地址
-    axios
-      .post(uploadUrl, formData, {
-        headers: {
-          'Content-Type': 'multipart/form-data'
-        }
-      })
-      .then(async (res) => {
-        if (res) {
-          if (res.data.Code == 200) {
-            // 图片上传成功,直接修改
-            const [err]: ToResponse = await to(userApi.setAvatar({ fileUrl: res?.data.Data || '' }))
-            if (err) return
-            showNotify({
-              type: 'success',
-              message: '修改成功'
-            })
-            storesUseUserInfo.setUserInfos()
-            closeDialog()
-          }
+  return new File([u8arr], filename, {
+    type: 'image/png'
+  })
+}
+// 上传图片获取地址
+const uploadBaseFunc = (file) => {
+  const formData = new FormData()
+  formData.append('file', file)
+  const uploadUrl = import.meta.env.VITE_UPLOAD // 上传的图片服务器地址
+  axios
+    .post(uploadUrl, formData, {
+      headers: {
+        'Content-Type': 'multipart/form-data'
+      }
+    })
+    .then(async (res) => {
+      if (res) {
+        if (res.data.Code == 200) {
+          // 图片上传成功,直接修改
+          const [err]: ToResponse = await to(userApi.setAvatar({ fileUrl: res?.data.Data || '' }))
+          if (err) return
+          showNotify({
+            type: 'success',
+            message: '修改成功'
+          })
+          storesUseUserInfo.setUserInfos()
+          closeDialog()
         }
+      }
+    })
+    .catch(() => {
+      showNotify({
+        type: 'warning',
+        message: '上传失败'
       })
-      .catch(() => {
-        showNotify({
-          type: 'warning',
-          message: '上传失败'
-        })
-      })
-  }
-  // 关闭弹窗
-  const closeDialog = () => {
-    if (cropperState.cropper) {
-      cropperState.cropper.destroy()
-      cropperState.isShowDialog = false
-      cropperState.cropperImg = ''
-      cropperState.cropperImgBase64 = ''
-      cropperState.cropper = ''
-      cropperState.isShowDialog = false
-    }
-  }
-  const initForm = async () => {
-    const [err, res]: ToResponse = await to(userApi.getProfile())
-    if (err) return
-    state.form = res?.data
-  }
-  const onSubmit = async () => {
-    const [errValid] = await to(formRef.value.validate())
-    if (errValid) return
-    state.form.userId = state.form.id
-    const params = JSON.parse(JSON.stringify(state.form))
-    const [err]: ToResponse = await to(userApi.updateProfile(params))
-    if (err) return
-    showNotify({
-      type: 'success',
-      message: '修改成功'
     })
-    storesUseUserInfo.setUserInfos()
-    router.push('/user')
+}
+// 关闭弹窗
+const closeDialog = () => {
+  if (cropperState.cropper) {
+    cropperState.cropper.destroy()
+    cropperState.isShowDialog = false
+    cropperState.cropperImg = ''
+    cropperState.cropperImgBase64 = ''
+    cropperState.cropper = ''
+    cropperState.isShowDialog = false
   }
-  onMounted(() => {
-    getDicts()
-    initForm()
+}
+const initForm = async () => {
+  const [err, res]: ToResponse = await to(userApi.getProfile())
+  if (err) return
+  state.form = res?.data
+}
+const onSubmit = async () => {
+  const [errValid] = await to(formRef.value.validate())
+  if (errValid) return
+  state.form.userId = state.form.id
+  const params = JSON.parse(JSON.stringify(state.form))
+  const [err]: ToResponse = await to(userApi.updateProfile(params))
+  if (err) return
+  showNotify({
+    type: 'success',
+    message: '修改成功'
   })
+  storesUseUserInfo.setUserInfos()
+  router.push('/user')
+}
+onMounted(() => {
+  getDicts()
+  initForm()
+})
 </script>
 
 <style lang="scss" scoped>
-  .app-container {
-    header {
-      background-color: #1c9bfd;
-      color: #fff;
-      padding: 10px;
-      border-radius: 8px;
-      margin-top: 10px;
+.app-container {
+  header {
+    background-color: #1c9bfd;
+    color: #fff;
+    padding: 10px;
+    border-radius: 8px;
+    margin-top: 10px;
+    display: flex;
+
+    img {
+      width: 100px;
+      height: 100px;
+      border-radius: 50%;
+      margin-right: 10px;
+    }
+
+    .content {
+      flex: 1;
       display: flex;
-      img {
-        width: 100px;
-        height: 100px;
-        border-radius: 50%;
-        margin-right: 10px;
-      }
-      .content {
-        flex: 1;
+      flex-direction: column;
+      justify-content: space-around;
+      overflow: hidden;
+
+      .bold {
         display: flex;
-        flex-direction: column;
-        justify-content: space-around;
-        overflow: hidden;
-        .bold {
-          display: flex;
-          align-items: center;
-          font-weight: bold;
-          // flex-wrap: nowrap;
-          white-space: nowrap;
-          .van-text-ellipsis {
-            flex: 1;
-          }
+        align-items: center;
+        font-weight: bold;
+        // flex-wrap: nowrap;
+        white-space: nowrap;
+
+        .van-text-ellipsis {
+          flex: 1;
         }
       }
     }
-    .avatar {
-      vertical-align: middle;
-    }
   }
-  .cropper-warp {
-    width: 100%;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    background-color: #eee;
-    .cropper-warp-left {
-      height: 500px;
-      width: 500px;
-    }
+
+  .avatar {
+    vertical-align: middle;
+  }
+}
+
+.cropper-warp {
+  width: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background-color: #eee;
+
+  .cropper-warp-left {
+    height: 500px;
+    width: 500px;
   }
+}
 </style>