mirror of
				https://github.com/continew-org/continew-admin-ui.git
				synced 2025-10-31 22:57:15 +08:00 
			
		
		
		
	feat: 新增上传个人头像
This commit is contained in:
		| @@ -3,6 +3,11 @@ import type * as System from '@/apis/system/type' | |||||||
|  |  | ||||||
| const BASE_URL = '/system/user' | const BASE_URL = '/system/user' | ||||||
|  |  | ||||||
|  | /** @desc 上传头像 */ | ||||||
|  | export function uploadAvatar(data: FormData) { | ||||||
|  |   return http.post(`${BASE_URL}/avatar`, data) | ||||||
|  | } | ||||||
|  |  | ||||||
| /** @desc 修改用户基本信息 */ | /** @desc 修改用户基本信息 */ | ||||||
| export function updateUserBaseInfo(data: { nickname: string; gender: number }) { | export function updateUserBaseInfo(data: { nickname: string; gender: number }) { | ||||||
|   return http.patch(`${BASE_URL}/basic/info`, data) |   return http.patch(`${BASE_URL}/basic/info`, data) | ||||||
|   | |||||||
| @@ -3,14 +3,11 @@ | |||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script lang="ts" setup> | <script lang="ts" setup> | ||||||
| import Dayjs from 'dayjs' |  | ||||||
| import { useAppStore } from '@/stores' | import { useAppStore } from '@/stores' | ||||||
|  |  | ||||||
| const appStore = useAppStore() | const appStore = useAppStore() | ||||||
|  |  | ||||||
| defineOptions({ name: 'GiFooter' }) | defineOptions({ name: 'GiFooter' }) | ||||||
|  |  | ||||||
| const year = Dayjs(new Date()).format('YYYY') |  | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <style lang="scss" scoped> | <style lang="scss" scoped> | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| import router from '@/router' | import router from '@/router' | ||||||
| import { useUserStore, useRouteStore, useAppStore } from '@/stores' | import { useUserStore, useRouteStore } from '@/stores' | ||||||
| import { getToken } from '@/utils/auth' | import { getToken } from '@/utils/auth' | ||||||
| import { isHttp } from '@/utils/validate' | import { isHttp } from '@/utils/validate' | ||||||
|  |  | ||||||
|   | |||||||
| @@ -26,7 +26,7 @@ export function downloadByUrl({ | |||||||
| }): Promise<boolean> { | }): Promise<boolean> { | ||||||
|   // 是否同源 |   // 是否同源 | ||||||
|   const isSameHost = new URL(url).host == location.host |   const isSameHost = new URL(url).host == location.host | ||||||
|   return new Promise<boolean>((resolve, reject) => { |   return new Promise<boolean>((resolve) => { | ||||||
|     if (isSameHost) { |     if (isSameHost) { | ||||||
|       const link = document.createElement('a') |       const link = document.createElement('a') | ||||||
|       link.href = url |       link.href = url | ||||||
|   | |||||||
| @@ -177,7 +177,7 @@ const del = <T = any>(url: string, params?: object, config?: AxiosRequestConfig) | |||||||
|     ...config |     ...config | ||||||
|   }) |   }) | ||||||
| } | } | ||||||
| const download = <T = any>(url: string, params?: object, config?: AxiosRequestConfig): Promise<AxiosResponse> => { | const download = (url: string, params?: object, config?: AxiosRequestConfig): Promise<AxiosResponse> => { | ||||||
|   return requestNative({ |   return requestNative({ | ||||||
|     method: 'get', |     method: 'get', | ||||||
|     url, |     url, | ||||||
|   | |||||||
| @@ -37,7 +37,6 @@ import { getImageCaptcha } from '@/apis' | |||||||
| import { Message, type FormInstance } from '@arco-design/web-vue' | import { Message, type FormInstance } from '@arco-design/web-vue' | ||||||
| import { useUserStore } from '@/stores' | import { useUserStore } from '@/stores' | ||||||
| import { useStorage } from '@vueuse/core' | import { useStorage } from '@vueuse/core' | ||||||
| import { useLoading } from '@/hooks' |  | ||||||
| import { encryptByRsa } from '@/utils/encrypt' | import { encryptByRsa } from '@/utils/encrypt' | ||||||
|  |  | ||||||
| const loginConfig = useStorage('login-config', { | const loginConfig = useStorage('login-config', { | ||||||
|   | |||||||
| @@ -1,54 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <a-model v-model:visible="visible"> |  | ||||||
|     <div class="cropper"> |  | ||||||
|       // 裁剪左侧内容 |  | ||||||
|       <div class="cropper_left"> |  | ||||||
|         <vueCropper |  | ||||||
|           :tyle="{ width: '400px' }" |  | ||||||
|           ref="cropperRef" |  | ||||||
|           :img="options.img" |  | ||||||
|           :info="true" |  | ||||||
|           :info-true="options.infoTrue" |  | ||||||
|           :auto-crop="options.autoCrop" |  | ||||||
|           :fixed-box="options.fixedBox" |  | ||||||
|           :can-move="options.canMoveBox" |  | ||||||
|           :can-scale="options.canScale" |  | ||||||
|           :fixed-number="fixedNumber" |  | ||||||
|           :fixed="options.fixed" |  | ||||||
|           :full="options.full" |  | ||||||
|           :center-box="options.centerBox" |  | ||||||
|           @real-time="previewHandle" |  | ||||||
|         /> |  | ||||||
|         <div class="reupload_box"> |  | ||||||
|           <div class="reupload_text" @click="uploadFile('reload')">重新上传</div> |  | ||||||
|           <div> |  | ||||||
|             <el-icon class="rotate_right" @click="changeScale(1)"> |  | ||||||
|               <CirclePlus /> |  | ||||||
|             </el-icon> |  | ||||||
|             <el-icon class="rotate_right" @click="changeScale(-1)"> |  | ||||||
|               <Remove /> |  | ||||||
|             </el-icon> |  | ||||||
|             <el-icon class="rotate_right" @click="rotateRight"> |  | ||||||
|               <RefreshRight /> |  | ||||||
|             </el-icon> |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|       </div> |  | ||||||
|       <div class="cropper_right"> |  | ||||||
|         <div class="preview_text">预览</div> |  | ||||||
|         <div :style="getStyle" class="previewImg"> |  | ||||||
|           <div :style="previewFileStyle"> |  | ||||||
|             <img :style="previews.img" :src="previews.url" alt="" /> |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|       </div> |  | ||||||
|     </div> |  | ||||||
|   </a-model> |  | ||||||
| </template> |  | ||||||
| <script setup lang="ts"> |  | ||||||
| import 'vue-cropper/dist/index.css' |  | ||||||
| import VueCropper from 'vue-cropper' |  | ||||||
| import { ref } from 'vue' |  | ||||||
|  |  | ||||||
| const visible = ref(true) |  | ||||||
| </script> |  | ||||||
							
								
								
									
										77
									
								
								src/views/setting/profile/BasicInfoUpdateModal.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/views/setting/profile/BasicInfoUpdateModal.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | |||||||
|  | <template> | ||||||
|  |   <a-modal v-model:visible="visible" title="修改基本信息" @before-ok="save" @close="reset"> | ||||||
|  |     <GiForm ref="formRef" v-model="form" :options="options" :columns="columns" /> | ||||||
|  |   </a-modal> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script setup lang="ts"> | ||||||
|  | import { updateUserBaseInfo } from '@/apis' | ||||||
|  | import { Message } from '@arco-design/web-vue' | ||||||
|  | import { GiForm, type Columns } from '@/components/GiForm' | ||||||
|  | import { useForm } from '@/hooks' | ||||||
|  | import { useUserStore } from '@/stores' | ||||||
|  |  | ||||||
|  | const options: Options = { | ||||||
|  |   form: {}, | ||||||
|  |   col: { xs: 24, sm: 24, md: 24, lg: 24, xl: 24, xxl: 24 }, | ||||||
|  |   btns: { hide: true } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const columns: Columns = [ | ||||||
|  |   { | ||||||
|  |     label: '昵称', | ||||||
|  |     field: 'nickname', | ||||||
|  |     type: 'input', | ||||||
|  |     rules: [{ required: true, message: '请输入昵称' }] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     label: '性别', | ||||||
|  |     field: 'gender', | ||||||
|  |     type: 'radio-group', | ||||||
|  |     options: [ | ||||||
|  |       { label: '男', value: 1 }, | ||||||
|  |       { label: '女', value: 2 }, | ||||||
|  |       { label: '未知', value: 0, disabled: true } | ||||||
|  |     ], | ||||||
|  |     rules: [{ required: true, message: '请选择性别' }] | ||||||
|  |   } | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | const userStore = useUserStore() | ||||||
|  | const userInfo = computed(() => userStore.userInfo) | ||||||
|  | const { form, resetForm } = useForm({ | ||||||
|  |   nickname: userInfo.value.nickname, | ||||||
|  |   gender: userInfo.value.gender | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | const formRef = ref<InstanceType<typeof GiForm>>() | ||||||
|  | // 重置 | ||||||
|  | const reset = () => { | ||||||
|  |   formRef.value?.formRef?.resetFields() | ||||||
|  |   resetForm() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const visible = ref(false) | ||||||
|  | // 修改 | ||||||
|  | const onUpdate = async () => { | ||||||
|  |   reset() | ||||||
|  |   visible.value = true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 保存 | ||||||
|  | const save = async () => { | ||||||
|  |   const isInvalid = await formRef.value?.formRef?.validate() | ||||||
|  |   if (isInvalid) return false | ||||||
|  |   try { | ||||||
|  |     await updateUserBaseInfo(form) | ||||||
|  |     Message.success('修改成功') | ||||||
|  |     // 修改成功后,重新获取用户信息 | ||||||
|  |     await userStore.getInfo() | ||||||
|  |     return true | ||||||
|  |   } catch (error) { | ||||||
|  |     return false | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | defineExpose({ onUpdate }) | ||||||
|  | </script> | ||||||
| @@ -2,9 +2,21 @@ | |||||||
|   <a-card title="基本信息" bordered class="gradient-card"> |   <a-card title="基本信息" bordered class="gradient-card"> | ||||||
|     <div class="body"> |     <div class="body"> | ||||||
|       <section> |       <section> | ||||||
|         <div class="avatar"> |         <a-upload | ||||||
|           <img :src="userStore.avatar" alt="avatar" /> |           :file-list="avatarList" | ||||||
|         </div> |           accept="image/*" | ||||||
|  |           :show-file-list="false" | ||||||
|  |           list-type="picture-card" | ||||||
|  |           :show-upload-button="true" | ||||||
|  |           :on-before-upload="onBeforeUpload" | ||||||
|  |         > | ||||||
|  |           <template #upload-button> | ||||||
|  |             <a-avatar :size="100"> | ||||||
|  |               <template #trigger-icon><icon-camera /></template> | ||||||
|  |               <img v-if="avatarList.length" :src="avatarList[0].url" alt="avatar" /> | ||||||
|  |             </a-avatar> | ||||||
|  |           </template> | ||||||
|  |         </a-upload> | ||||||
|         <div class="name"> |         <div class="name"> | ||||||
|           <span style="margin-right: 10px">{{ userInfo.nickname }}</span> |           <span style="margin-right: 10px">{{ userInfo.nickname }}</span> | ||||||
|           <icon-edit :size="16" class="btn" @click="onUpdate" /> |           <icon-edit :size="16" class="btn" @click="onUpdate" /> | ||||||
| @@ -44,84 +56,146 @@ | |||||||
|     <div class="footer">注册于 {{ userInfo.registrationDate }}</div> |     <div class="footer">注册于 {{ userInfo.registrationDate }}</div> | ||||||
|   </a-card> |   </a-card> | ||||||
|  |  | ||||||
|   <a-modal v-model:visible="visible" title="修改基本信息" @before-ok="save" @close="reset"> |   <a-modal v-model:visible="visible" title="上传头像" :width="400" :footer="false" @close="reset"> | ||||||
|     <GiForm ref="formRef" v-model="form" :options="options" :columns="columns" /> |     <a-row> | ||||||
|  |       <a-col :span="14" style="width: 200px; height: 200px"> | ||||||
|  |         <vue-cropper | ||||||
|  |           ref="cropperRef" | ||||||
|  |           :img="options.img" | ||||||
|  |           :info="true" | ||||||
|  |           :auto-crop="options.autoCrop" | ||||||
|  |           :auto-crop-width="options.autoCropWidth" | ||||||
|  |           :auto-crop-height="options.autoCropHeight" | ||||||
|  |           :fixed-box="options.fixedBox" | ||||||
|  |           :fixed="options.fixed" | ||||||
|  |           :full="options.full" | ||||||
|  |           :center-box="options.centerBox" | ||||||
|  |           :can-move="options.canMove" | ||||||
|  |           :output-type="options.outputType" | ||||||
|  |           :output-size="options.outputSize" | ||||||
|  |           @real-time="handleRealTime" | ||||||
|  |         /> | ||||||
|  |       </a-col> | ||||||
|  |       <a-col :span="10" style="display: flex; justify-content: center"> | ||||||
|  |         <div :style="previewStyle"> | ||||||
|  |           <div :style="previews.div"> | ||||||
|  |             <img :src="previews.url" :style="previews.img" alt="" /> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </a-col> | ||||||
|  |     </a-row> | ||||||
|  |     <div style="text-align: center; padding-top: 30px"> | ||||||
|  |       <a-space> | ||||||
|  |         <a-button type="primary" @click="handleUpload">确定</a-button> | ||||||
|  |         <a-button @click="reset">取消</a-button> | ||||||
|  |       </a-space> | ||||||
|  |     </div> | ||||||
|   </a-modal> |   </a-modal> | ||||||
|  |   <BasicInfoUpdateModal ref="BasicInfoUpdateModalRef" /> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
| import { updateUserBaseInfo, updateUserPassword } from '@/apis' | import { uploadAvatar } from '@/apis' | ||||||
| import { Message } from '@arco-design/web-vue' | import BasicInfoUpdateModal from './BasicInfoUpdateModal.vue' | ||||||
| import { type Columns, GiForm } from '@/components/GiForm' | import { Message, type FileItem } from '@arco-design/web-vue' | ||||||
| import { useForm } from '@/hooks' | import { VueCropper } from 'vue-cropper' | ||||||
|  | import 'vue-cropper/dist/index.css' | ||||||
| import { useUserStore } from '@/stores' | import { useUserStore } from '@/stores' | ||||||
| import { encryptByRsa } from '@/utils/encrypt' | import getAvatar from '@/utils/avatar' | ||||||
|  |  | ||||||
| const userStore = useUserStore() | const userStore = useUserStore() | ||||||
| const userInfo = computed(() => userStore.userInfo) | const userInfo = computed(() => userStore.userInfo) | ||||||
| const formRef = ref<InstanceType<typeof GiForm>>() |  | ||||||
|  |  | ||||||
| const options: Options = { | const avatar = { | ||||||
|   form: {}, |   uid: '-2', | ||||||
|   col: { xs: 24, sm: 24, md: 24, lg: 24, xl: 24, xxl: 24 }, |   name: 'avatar.png', | ||||||
|   btns: { hide: true } |   url: userInfo.value.avatar | ||||||
| } | } | ||||||
|  | const avatarList = ref<FileItem[]>([avatar]) | ||||||
| const columns: Columns = [ | const fileRef = ref(reactive({ name: 'avatar.png' })) | ||||||
|   { | const options: cropperOptions = reactive({ | ||||||
|     label: '昵称', |   img: '', | ||||||
|     field: 'nickname', |   autoCrop: true, | ||||||
|     type: 'input', |   autoCropWidth: 160, | ||||||
|     rules: [{ required: true, message: '请输入昵称' }] |   autoCropHeight: 160, | ||||||
|   }, |   fixedBox: true, | ||||||
|   { |   fixed: true, | ||||||
|     label: '性别', |   full: false, | ||||||
|     field: 'gender', |   centerBox: true, | ||||||
|     type: 'radio-group', |   canMove: true, | ||||||
|     options: [ |   outputSize: 1, | ||||||
|       { label: '男', value: 1 }, |   outputType: 'png' | ||||||
|       { label: '女', value: 2 }, |  | ||||||
|       { label: '未知', value: 0, disabled: true } |  | ||||||
|     ], |  | ||||||
|     rules: [{ required: true, message: '请选择性别' }] |  | ||||||
|   } |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| const { form, resetForm } = useForm({ |  | ||||||
|   nickname: userInfo.value.nickname, |  | ||||||
|   gender: userInfo.value.gender |  | ||||||
| }) | }) | ||||||
|  | const visible = ref(false) | ||||||
|  | // 打开裁剪框 | ||||||
|  | const onBeforeUpload = (file: File): boolean => { | ||||||
|  |   fileRef.value = file | ||||||
|  |   const reader = new FileReader() | ||||||
|  |   reader.readAsDataURL(file) | ||||||
|  |   reader.onload = () => { | ||||||
|  |     options.img = reader.result | ||||||
|  |   } | ||||||
|  |   visible.value = true | ||||||
|  |   return false | ||||||
|  | } | ||||||
|  |  | ||||||
| // 重置 | // 重置 | ||||||
| const reset = () => { | const reset = () => { | ||||||
|   formRef.value?.formRef?.resetFields() |   fileRef.value = { name: '' } | ||||||
|   resetForm() |   options.img = '' | ||||||
|  |   visible.value = false | ||||||
| } | } | ||||||
|  |  | ||||||
| const visible = ref(false) | const previews: any = ref({}) | ||||||
| // 修改 | const previewStyle: any = ref({}) | ||||||
| const onUpdate = async () => { | // 实时预览 | ||||||
|   reset() | const handleRealTime = (data: any) => { | ||||||
|   visible.value = true |   previewStyle.value = { | ||||||
| } |     width: `${data.w}px`, | ||||||
|  |     height: `${data.h}px`, | ||||||
| // 保存 |     overflow: 'hidden', | ||||||
| const save = async () => { |     margin: '0', | ||||||
|   const isInvalid = await formRef.value?.formRef?.validate() |     zoom: 100 / data.h, | ||||||
|   if (isInvalid) return false |     borderRadius: '50%' | ||||||
|   try { |  | ||||||
|     await updateUserBaseInfo(form) |  | ||||||
|     Message.success('修改成功') |  | ||||||
|     // 修改成功后,重新获取用户信息 |  | ||||||
|     await userStore.getInfo() |  | ||||||
|     return true |  | ||||||
|   } catch (error) { |  | ||||||
|     return false |  | ||||||
|   } |   } | ||||||
|  |   previews.value = data | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const cropperRef = ref() | ||||||
|  | // 上传头像 | ||||||
|  | const handleUpload = async () => { | ||||||
|  |   cropperRef.value.getCropBlob((data: any) => { | ||||||
|  |     const formData = new FormData() | ||||||
|  |     formData.append('avatarFile', data, fileRef.value?.name) | ||||||
|  |     uploadAvatar(formData).then((res) => { | ||||||
|  |       userInfo.value.avatar = res.data.avatar | ||||||
|  |       avatarList.value[0].url = getAvatar(res.data.avatar, undefined) | ||||||
|  |       reset() | ||||||
|  |       Message.success('更新成功') | ||||||
|  |     }) | ||||||
|  |   }) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const BasicInfoUpdateModalRef = ref<InstanceType<typeof BasicInfoUpdateModal>>() | ||||||
|  | // 修改基本信息 | ||||||
|  | const onUpdate = async () => { | ||||||
|  |   BasicInfoUpdateModalRef.value?.onUpdate() | ||||||
| } | } | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <style scoped lang="scss"> | <style scoped lang="scss"> | ||||||
|  | :deep(.arco-avatar-trigger-icon-button) { | ||||||
|  |   width: 32px; | ||||||
|  |   height: 32px; | ||||||
|  |   line-height: 32px; | ||||||
|  |   background-color: #e8f3ff; | ||||||
|  |   .arco-icon-camera { | ||||||
|  |     margin-top: 8px; | ||||||
|  |     color: rgb(var(--arcoblue-6)); | ||||||
|  |     font-size: 14px; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| .body { | .body { | ||||||
|   display: flex; |   display: flex; | ||||||
|   flex-direction: column; |   flex-direction: column; | ||||||
| @@ -137,11 +211,6 @@ const save = async () => { | |||||||
|     justify-content: center; |     justify-content: center; | ||||||
|     align-items: center; |     align-items: center; | ||||||
|     padding: 32px 0 50px; |     padding: 32px 0 50px; | ||||||
|     .avatar > img { |  | ||||||
|       width: 80px; |  | ||||||
|       height: 80px; |  | ||||||
|       border-radius: 50%; |  | ||||||
|     } |  | ||||||
|     .name { |     .name { | ||||||
|       font-size: 20px; |       font-size: 20px; | ||||||
|       margin: 20px 0; |       margin: 20px 0; | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ | |||||||
|       <div class="sub-text-wrapper"> |       <div class="sub-text-wrapper"> | ||||||
|         <div class="sub-text">无操作登录会话保持<span class="sub-text-value">30</span>分钟,超时登录会话将失效</div> |         <div class="sub-text">无操作登录会话保持<span class="sub-text-value">30</span>分钟,超时登录会话将失效</div> | ||||||
|         <div class="sub-text">登录会话最大保持<span class="sub-text-value">0</span>天,超时登录会话将失效</div> |         <div class="sub-text">登录会话最大保持<span class="sub-text-value">0</span>天,超时登录会话将失效</div> | ||||||
|         <a-link class="link">修改规则(未开放)</a-link class="link"> |         <a-link class="link">修改规则(未开放)</a-link> | ||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
|   </a-card> |   </a-card> | ||||||
|   | |||||||
| @@ -20,16 +20,12 @@ | |||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
| import { Message } from '@arco-design/web-vue' |  | ||||||
| import BasicsSetting from './BasicsSetting.vue' | import BasicsSetting from './BasicsSetting.vue' | ||||||
| import SessionSetting from './SessionSetting.vue' | import SessionSetting from './SessionSetting.vue' | ||||||
| import PasswordPolicy from './PasswordPolicy.vue' | import PasswordPolicy from './PasswordPolicy.vue' | ||||||
| import AccountProtection from './AccountProtection.vue' | import AccountProtection from './AccountProtection.vue' | ||||||
|  |  | ||||||
| defineOptions({ name: 'SettingSecurity' }) | defineOptions({ name: 'SettingSecurity' }) | ||||||
|  |  | ||||||
| const route = useRoute() |  | ||||||
| const form = reactive({ name: '' }) |  | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <style lang="scss" scoped> | <style lang="scss" scoped> | ||||||
|   | |||||||
| @@ -179,6 +179,7 @@ const getMenuAllCheckedKeys = () => { | |||||||
|   // 获取半选中的菜单 |   // 获取半选中的菜单 | ||||||
|   const halfCheckedNodes = menuTreeRef.value?.getHalfCheckedNodes() |   const halfCheckedNodes = menuTreeRef.value?.getHalfCheckedNodes() | ||||||
|   const halfCheckedKeys = halfCheckedNodes.map((item: TreeNodeData) => item.key) |   const halfCheckedKeys = halfCheckedNodes.map((item: TreeNodeData) => item.key) | ||||||
|  |   // eslint-disable-next-line prefer-spread | ||||||
|   checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys) |   checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys) | ||||||
|   return checkedKeys |   return checkedKeys | ||||||
| } | } | ||||||
| @@ -194,6 +195,7 @@ const getDeptAllCheckedKeys = () => { | |||||||
|   // 获取半选中的部门 |   // 获取半选中的部门 | ||||||
|   const halfCheckedNodes = deptTreeRef.value?.getHalfCheckedNodes() |   const halfCheckedNodes = deptTreeRef.value?.getHalfCheckedNodes() | ||||||
|   const halfCheckedKeys = halfCheckedNodes.map((item: TreeNodeData) => item.key) |   const halfCheckedKeys = halfCheckedNodes.map((item: TreeNodeData) => item.key) | ||||||
|  |   // eslint-disable-next-line prefer-spread | ||||||
|   checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys) |   checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys) | ||||||
|   return checkedKeys |   return checkedKeys | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user