9 changed files with 36 additions and 491 deletions
@ -1,361 +0,0 @@
@@ -1,361 +0,0 @@
|
||||
<template> |
||||
<div> |
||||
<PageWrapper dense |
||||
fixedHeight |
||||
contentFullHeight |
||||
contentClass="flex" |
||||
> |
||||
<ACard class="base-info w-2/5 xl:w-2/5"> |
||||
<template #title> |
||||
<UserOutlined/> 基本信息 |
||||
</template> |
||||
<div class="user-info-top"> |
||||
<AAvatar draggable |
||||
width="32px" |
||||
:src="getAvatarUrl" |
||||
:size="80" |
||||
/> |
||||
<h2>{{ getUserInfo.nickName }}</h2> |
||||
<p>{{ getUserInfo.remarks }}</p> |
||||
<a-button preIcon="fa6-solid:id-badge" |
||||
type="primary" |
||||
shape="round" |
||||
>{{ getUserInfo.userName }}</a-button> |
||||
</div> |
||||
<ADivider/> |
||||
<div class="user-info-main"> |
||||
<ADescriptions :labelStyle="getLabelStyle" |
||||
:contentStyle="getDescriptionsStyle" |
||||
:colon="false" |
||||
> |
||||
<ADescriptionsItem span="24"> |
||||
<template #label> |
||||
<Icon icon="fa6-solid:building"/> |
||||
</template> |
||||
{{ getUserInfo.deptName }} |
||||
</ADescriptionsItem> |
||||
<ADescriptionsItem span="24"> |
||||
<template #label> |
||||
<Icon icon="fa6-solid:envelope"/> |
||||
</template> |
||||
{{ getUserInfo.email }} |
||||
</ADescriptionsItem> |
||||
<ADescriptionsItem span="24"> |
||||
<template #label> |
||||
<Icon icon="fa6-solid:mobile"/> |
||||
</template> |
||||
{{ getUserInfo.phone }} |
||||
</ADescriptionsItem> |
||||
<ADescriptionsItem span="24"> |
||||
<template #label> |
||||
<Icon icon="fa6-solid:venus-double"/> |
||||
</template> |
||||
{{ ~~getUserInfo.sex === 0 ? '男' : '女' }} |
||||
</ADescriptionsItem> |
||||
<ADescriptionsItem span="24"> |
||||
<template #label> |
||||
<Icon icon="fa6-solid:city"/> |
||||
</template> |
||||
长沙康来公司多租户 |
||||
</ADescriptionsItem> |
||||
<ADescriptionsItem span="24"> |
||||
<template #label> |
||||
<Icon icon="fa6-solid:robot"/> |
||||
</template> |
||||
<h1 style="margin-right: 5px">企业认证:</h1> |
||||
<a v-if="getPushThirdParty.status == '0'">申请中</a> |
||||
<a v-else-if="getPushThirdParty.status == '1'">已认证</a> |
||||
<a v-else @click="handleCertification">申请</a> |
||||
</ADescriptionsItem> |
||||
</ADescriptions> |
||||
</div> |
||||
</ACard> |
||||
<ACard class="info-modify w-3/5 xl:w-3/5"> |
||||
<template #title> |
||||
<CreditCardOutlined/> 资料修改 |
||||
</template> |
||||
<ACard :bordered="false" |
||||
:tab-list="state.tabList" |
||||
:active-tab-key="state.currentCardKey" |
||||
@tabChange="key => state.currentCardKey = key" |
||||
> |
||||
<BasicForm v-show="state.currentCardKey === 'baseInfo'" @register="registerForm"/> |
||||
<AForm v-show="state.currentCardKey === 'uploadAvatar'" |
||||
ref="formElRef" |
||||
class="upload-avatar-form" |
||||
:scrollToFirstError="true" |
||||
@keypress.enter="handleSubmit" |
||||
> |
||||
<AFormItem> |
||||
<AUpload list-type="picture-card" |
||||
class="avatar-uploader" |
||||
accept="image/*" |
||||
:multiple="false" |
||||
:show-upload-list="false" |
||||
:customRequest="handleUploadAvatar" |
||||
:before-upload="handleBeforeUpload" |
||||
> |
||||
<img v-if="getImageUrl" :src="getImageUrl"> |
||||
<div v-else> |
||||
<LoadingOutlined v-if="state.uploadAvatarLoading"/> |
||||
<PlusOutlined v-else/> |
||||
<div class="ant-upload-text">上传头像</div> |
||||
</div> |
||||
</AUpload> |
||||
</AFormItem> |
||||
<AFormItem :wrapperCol="{ style: { 'text-align': 'left' }, class: 'avatar-submit-form-item' }"> |
||||
<a-button preIcon="fa-regular:save" |
||||
:loading="state.uploadAvatarBtnLoading" |
||||
type="primary" |
||||
@click="handleAvatarSubmit" |
||||
>保存</a-button> |
||||
<a-button preIcon="ant-design:delete-twotone" |
||||
danger |
||||
type="primary" |
||||
:disabled="!state.imageUrl" |
||||
@click="state.imageUrl = ''" |
||||
>删除</a-button> |
||||
</AFormItem> |
||||
</AForm> |
||||
</ACard> |
||||
</ACard> |
||||
</PageWrapper> |
||||
<ThirdPartyModal @register="registerModal" @success="handleRefreshPushThirdParty"/> |
||||
</div> |
||||
</template> |
||||
|
||||
<script lang="ts" setup> |
||||
import {Avatar, Card, Descriptions, Divider, Form, Upload} from 'ant-design-vue'; |
||||
import {PageWrapper} from '/@/components/Page'; |
||||
import {CreditCardOutlined, LoadingOutlined, PlusOutlined, UserOutlined} from '@ant-design/icons-vue'; |
||||
import type {CSSProperties} from 'vue'; |
||||
import {computed, reactive, unref} from 'vue'; |
||||
import {Icon} from '/@/components/Icon'; |
||||
import {BasicForm, useForm} from '/@/components/Form/index'; |
||||
import {userFormSchema} from './userInfo.data'; |
||||
import {useMessage} from '/@/hooks/web/useMessage'; |
||||
import {editUser, getUser} from '/@/api/platform/system/controller/user'; |
||||
import type {User} from '/@/api/platform/core/entity/user'; |
||||
import type {PushThirdParty} from '/@/api/platform/common/entity/pushThirdParty'; |
||||
import {useUserStore} from '/@/store/modules/user'; |
||||
import {commonUpload} from '/@/api/platform/core/controller/upload'; |
||||
import {useGlobSetting} from '/@/hooks/setting'; |
||||
import {isUrl} from '/@/utils/is'; |
||||
import {getPushThirdPartyByUserId} from '/@/api/platform/common/controller/pushThirdParty'; |
||||
import {useModal} from '/@/components/Modal'; |
||||
import ThirdPartyModal from '/@/views/common/push/pushThirdParty/ThirdPartyModal.vue'; |
||||
|
||||
interface InfoState { |
||||
currentCardKey: string; |
||||
baseInfoBtnLoading: boolean; |
||||
uploadAvatarBtnLoading: boolean; |
||||
uploadAvatarLoading: boolean; |
||||
userInfo: User | any; |
||||
pushThirdParty: PushThirdParty | any; |
||||
imageUrl: string; |
||||
tabList: Recordable[]; |
||||
} |
||||
|
||||
const ACard = Card; |
||||
const AAvatar = Avatar; |
||||
const ADescriptions = Descriptions; |
||||
const ADescriptionsItem = Descriptions.Item; |
||||
const ADivider = Divider; |
||||
const AForm = Form; |
||||
const AFormItem = Form.Item; |
||||
const AUpload = Upload; |
||||
const { createMessage } = useMessage(); |
||||
const userStore = useUserStore(); |
||||
const userInfo = userStore.getUserInfo; |
||||
const { apiUrl } = useGlobSetting(); |
||||
const state = reactive<InfoState>({ |
||||
currentCardKey: 'baseInfo', |
||||
baseInfoBtnLoading: false, |
||||
uploadAvatarLoading: false, |
||||
uploadAvatarBtnLoading: false, |
||||
userInfo: undefined, |
||||
pushThirdParty: undefined, |
||||
imageUrl: '', |
||||
tabList: [ |
||||
{ |
||||
key: 'baseInfo', |
||||
tab: '基本信息', |
||||
}, |
||||
{ |
||||
key: 'uploadAvatar', |
||||
tab: '上传头像', |
||||
} |
||||
] |
||||
}); |
||||
|
||||
const [registerModal, { openModal }] = useModal(); |
||||
const defaultAvatarUrl = 'https://godolphinx.org/dolphin1024x1024.png'; |
||||
const [registerForm, { resetFields, setFieldsValue, updateSchema, validate, clearValidate }] = useForm({ |
||||
labelWidth: 100, |
||||
schemas: userFormSchema, |
||||
showSubmitButton: true, |
||||
showResetButton: false, |
||||
showAdvancedButton: false, |
||||
submitButtonOptions: { |
||||
text: '保存', |
||||
preIcon: 'fa-regular:save', |
||||
loading: state.baseInfoBtnLoading, |
||||
onClick: handleSubmit |
||||
}, |
||||
actionColOptions: { span: 24 } |
||||
}); |
||||
getUser(userInfo.id).then(result => { |
||||
state.userInfo = result.result; |
||||
setFieldsValue(result.result); |
||||
handleRefreshPushThirdParty(); |
||||
}); |
||||
|
||||
function handleRefreshPushThirdParty() { |
||||
getPushThirdPartyByUserId(userInfo.id).then(pushThirdParty => state.pushThirdParty = pushThirdParty); |
||||
} |
||||
|
||||
async function handleSubmit() { |
||||
try { |
||||
const formData = await validate(); |
||||
state.baseInfoBtnLoading = true; |
||||
await editUser(formData); |
||||
createMessage.success('保存成功!'); |
||||
const result = await getUser(userInfo.id); |
||||
state.userInfo = result.result; |
||||
await setFieldsValue(result.result); |
||||
} finally { |
||||
state.baseInfoBtnLoading = false; |
||||
} |
||||
} |
||||
|
||||
async function handleAvatarSubmit() { |
||||
try { |
||||
state.uploadAvatarBtnLoading = true; |
||||
await editUser({ |
||||
id: userInfo.id, |
||||
avatar: state.imageUrl |
||||
}); |
||||
createMessage.success('保存成功!'); |
||||
const result = await getUser(userInfo.id); |
||||
state.userInfo = result.result; |
||||
await setFieldsValue(result.result); |
||||
} finally { |
||||
state.uploadAvatarBtnLoading = false; |
||||
} |
||||
} |
||||
|
||||
function handleCertification() { |
||||
openModal(true,{ _tag: 'add' }); |
||||
} |
||||
|
||||
const getUserInfo = computed((): User & any => { |
||||
let userInfo = state.userInfo || {}; |
||||
userInfo.avatar || (userInfo.avatar = defaultAvatarUrl); |
||||
state!.imageUrl = userInfo.avatar; |
||||
return userInfo; |
||||
}); |
||||
|
||||
const getPushThirdParty = computed((): PushThirdParty & any => state.pushThirdParty || {}); |
||||
|
||||
const getAvatarUrl = computed((): string => isUrl(unref(getUserInfo).avatar) ? unref(getUserInfo).avatar : apiUrl + unref(getUserInfo).avatar); |
||||
|
||||
const getImageUrl = computed((): string => (!state.imageUrl || isUrl(state.imageUrl)) ? state.imageUrl : apiUrl + state.imageUrl); |
||||
|
||||
const getLabelStyle = computed((): CSSProperties => ({ |
||||
fontSize: '14px', |
||||
display: 'inline', |
||||
width: '40px' |
||||
})); |
||||
|
||||
const getDescriptionsStyle = computed((): CSSProperties => ({ |
||||
fontSize: '20px', |
||||
color: '#606266', |
||||
'text-align': 'left', |
||||
'font-weight': 400, |
||||
'line-height': '23px', |
||||
'font-size': '14px' |
||||
})); |
||||
|
||||
function handleBeforeUpload (file: File) { |
||||
const isJpgOrPng = file.type?.includes('image/'), |
||||
isLt2M = file.size / 1024 / 1024 < 10; |
||||
|
||||
!isJpgOrPng && createMessage.error('您只能上传 image/* 格式的文件!'); |
||||
!isLt2M && createMessage.error('图片必须小于 10MB!'); |
||||
return isJpgOrPng && isLt2M; |
||||
} |
||||
|
||||
async function handleUploadAvatar(file) { |
||||
try { |
||||
state.uploadAvatarLoading = true; |
||||
const { data } = await commonUpload({ |
||||
file: file.file, |
||||
name: 'file', |
||||
}, () => {}); |
||||
state.imageUrl = data.url; |
||||
} finally { |
||||
state.uploadAvatarLoading = false; |
||||
} |
||||
} |
||||
|
||||
</script> |
||||
|
||||
<style lang="less" scoped> |
||||
|
||||
.base-info { |
||||
overflow-y: scroll; |
||||
overflow-x: hidden; |
||||
margin: 10px 15px 10px 10px; |
||||
scrollbar-width: none; |
||||
|
||||
.user-info-top { |
||||
padding: 20px 0px; |
||||
text-align: center; |
||||
|
||||
h2 { |
||||
color: #515a6e; |
||||
margin-top: 10px; |
||||
font-size: 24px; |
||||
} |
||||
|
||||
p { |
||||
color: #999; |
||||
margin-top: 5px; |
||||
font-size: 12px; |
||||
font-weight: 0; |
||||
} |
||||
} |
||||
|
||||
.user-info-main { |
||||
padding: 20px 100px; |
||||
} |
||||
} |
||||
|
||||
.base-info::-webkit-scrollbar { |
||||
display: none; |
||||
} |
||||
|
||||
.info-modify { |
||||
margin: 10px 10px 10px 0px; |
||||
|
||||
::v-deep(.avatar-uploader) > .ant-upload { |
||||
width: 180px; |
||||
height: 180px; |
||||
} |
||||
|
||||
::v-deep(.ant-upload-select-picture-card .ant-upload-text) { |
||||
margin-top: 8px; |
||||
color: #666; |
||||
} |
||||
|
||||
::v-deep(.upload-avatar-form) > .ant-row { |
||||
margin-bottom: 0px; |
||||
} |
||||
|
||||
::v-deep(.avatar-submit-form-item) button { |
||||
margin-left: 6px; |
||||
} |
||||
|
||||
} |
||||
|
||||
</style> |
@ -1,96 +0,0 @@
@@ -1,96 +0,0 @@
|
||||
import { FormSchema } from '/@/components/Table'; |
||||
|
||||
export const userFormSchema: FormSchema[] = [ |
||||
{ |
||||
field: 'id', |
||||
label: 'ID', |
||||
component: 'Input', |
||||
show: false |
||||
}, |
||||
{ |
||||
field: 'nickName', |
||||
label: '用户昵称', |
||||
component: 'Input', |
||||
required: true, |
||||
colProps: { |
||||
span: 12 |
||||
} |
||||
}, |
||||
{ |
||||
field: 'deptName', |
||||
label: '归属机构', |
||||
component: 'Input', |
||||
required: true, |
||||
componentProps: { |
||||
disabled: true |
||||
}, |
||||
colProps: { |
||||
span: 12 |
||||
} |
||||
}, |
||||
{ |
||||
field: 'phone', |
||||
label: '手机号', |
||||
component: 'Input', |
||||
rules: [ |
||||
{ |
||||
required: true, |
||||
message: '请输入手机号!', |
||||
}, |
||||
{ |
||||
pattern: new RegExp('^1[3|4|5|6|7|8|9][0-9]\\d{8}$'), |
||||
message: '请输入正确的手机号码!', |
||||
validateTrigger: 'blur' |
||||
} |
||||
], |
||||
colProps: { |
||||
span: 12 |
||||
} |
||||
}, |
||||
{ |
||||
field: 'email', |
||||
label: '邮箱', |
||||
component: 'Input', |
||||
rules: [ |
||||
{ |
||||
required: true, |
||||
message: '请输入邮箱!', |
||||
}, |
||||
{ |
||||
type: 'email', |
||||
message: '请输入正确的邮箱地址!', |
||||
validateTrigger: ['blur', 'change'] |
||||
} |
||||
], |
||||
colProps: { |
||||
span: 12 |
||||
} |
||||
}, |
||||
{ |
||||
field: 'sex', |
||||
label: '性别', |
||||
component: 'RadioGroup', |
||||
defaultValue: '0', |
||||
required: true, |
||||
componentProps: { |
||||
options: [ |
||||
{ label: '男', value: '0' }, |
||||
{ label: '女', value: '1' } |
||||
] |
||||
}, |
||||
colProps: { |
||||
span: 12 |
||||
} |
||||
}, |
||||
{ |
||||
label: '备注', |
||||
field: 'remarks', |
||||
component: 'InputTextArea', |
||||
componentProps: { |
||||
rows: 6 |
||||
}, |
||||
colProps: { |
||||
span: 24 |
||||
} |
||||
} |
||||
]; |
Loading…
Reference in new issue