16 changed files with 931 additions and 10 deletions
@ -0,0 +1,92 @@
@@ -0,0 +1,92 @@
|
||||
<template> |
||||
<List :class="prefixCls"> |
||||
<a-row :gutter="16"> |
||||
<template v-for="item in list" :key="item.title"> |
||||
<a-col :span="6"> |
||||
<ListItem> |
||||
<Card :hoverable="true" :class="`${prefixCls}__card`"> |
||||
<div :class="`${prefixCls}__card-title`"> |
||||
<Icon class="icon" v-if="item.icon" :icon="item.icon" :color="item.color" /> |
||||
{{ item.title }} |
||||
</div> |
||||
<div :class="`${prefixCls}__card-num`"> |
||||
活跃用户:<span>{{ item.active }}</span> 万 |
||||
</div> |
||||
<div :class="`${prefixCls}__card-num`"> |
||||
新增用户:<span>{{ item.new }}</span> |
||||
</div> |
||||
<Icon |
||||
:class="`${prefixCls}__card-download`" |
||||
v-if="item.download" |
||||
:icon="item.download" |
||||
/> |
||||
</Card> |
||||
</ListItem> |
||||
</a-col> |
||||
</template> |
||||
</a-row> |
||||
</List> |
||||
</template> |
||||
<script lang="ts"> |
||||
import { defineComponent } from 'vue'; |
||||
import { List, Card, Row, Col } from 'ant-design-vue'; |
||||
import Icon from '/@/components/Icon/index'; |
||||
import { applicationList } from './data'; |
||||
|
||||
export default defineComponent({ |
||||
components: { |
||||
List, |
||||
ListItem: List.Item, |
||||
Card, |
||||
Icon, |
||||
[Row.name]: Row, |
||||
[Col.name]: Col, |
||||
}, |
||||
setup() { |
||||
return { |
||||
prefixCls: 'account-center-application', |
||||
list: applicationList, |
||||
}; |
||||
}, |
||||
}); |
||||
</script> |
||||
<style lang="less"> |
||||
.account-center-application { |
||||
&__card { |
||||
width: 100%; |
||||
margin-bottom: -12px; |
||||
|
||||
.ant-card-body { |
||||
padding: 16px; |
||||
} |
||||
|
||||
&-title { |
||||
margin-bottom: 5px; |
||||
font-size: 16px; |
||||
font-weight: 500; |
||||
|
||||
.icon { |
||||
margin-top: -5px; |
||||
font-size: 22px; |
||||
} |
||||
} |
||||
|
||||
&-num { |
||||
margin-left: 24px; |
||||
line-height: 36px; |
||||
color: @text-color-secondary; |
||||
|
||||
span { |
||||
margin-left: 5px; |
||||
font-size: 18px; |
||||
} |
||||
} |
||||
|
||||
&-download { |
||||
float: right; |
||||
font-size: 20px !important; |
||||
color: @primary-color; |
||||
} |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,97 @@
@@ -0,0 +1,97 @@
|
||||
<template> |
||||
<List item-layout="vertical" :class="prefixCls"> |
||||
<template v-for="item in list" :key="item.title"> |
||||
<ListItem> |
||||
<ListItemMeta> |
||||
<template #description> |
||||
<div :class="`${prefixCls}__content`"> |
||||
{{ item.content }} |
||||
</div> |
||||
</template> |
||||
<template #title> |
||||
<p :class="`${prefixCls}__title`"> |
||||
{{ item.title }} |
||||
</p> |
||||
<div> |
||||
<template v-for="tag in item.description" :key="tag"> |
||||
<Tag class="mb-2"> |
||||
{{ tag }} |
||||
</Tag> |
||||
</template> |
||||
</div> |
||||
</template> |
||||
</ListItemMeta> |
||||
<div> |
||||
<template v-for="action in actions" :key="action.text"> |
||||
<div :class="`${prefixCls}__action`"> |
||||
<Icon |
||||
v-if="action.icon" |
||||
:class="`${prefixCls}__action-icon`" |
||||
:icon="action.icon" |
||||
:color="action.color" |
||||
/> |
||||
{{ action.text }} |
||||
</div> |
||||
</template> |
||||
<span :class="`${prefixCls}__time`">{{ item.time }}</span> |
||||
</div> |
||||
</ListItem> |
||||
</template> |
||||
</List> |
||||
</template> |
||||
<script lang="ts"> |
||||
import { defineComponent } from 'vue'; |
||||
import { List, Tag } from 'ant-design-vue'; |
||||
import Icon from '/@/components/Icon/index'; |
||||
import { actions, articleList } from './data'; |
||||
|
||||
export default defineComponent({ |
||||
components: { |
||||
List, |
||||
ListItem: List.Item, |
||||
ListItemMeta: List.Item.Meta, |
||||
Tag, |
||||
Icon, |
||||
}, |
||||
setup() { |
||||
return { |
||||
prefixCls: 'account-center-article', |
||||
list: articleList, |
||||
actions, |
||||
}; |
||||
}, |
||||
}); |
||||
</script> |
||||
<style lang="less" scoped> |
||||
.account-center-article { |
||||
&__title { |
||||
margin-bottom: 12px; |
||||
font-size: 18px; |
||||
} |
||||
|
||||
&__content { |
||||
color: rgb(0 0 0 / 65%); |
||||
} |
||||
|
||||
&__action { |
||||
display: inline-block; |
||||
padding: 0 16px; |
||||
color: rgb(0 0 0 / 45%); |
||||
|
||||
&:nth-child(1), |
||||
&:nth-child(2) { |
||||
border-right: 1px solid rgb(206 206 206 / 40%); |
||||
} |
||||
|
||||
&-icon { |
||||
margin-right: 3px; |
||||
} |
||||
} |
||||
|
||||
&__time { |
||||
position: absolute; |
||||
right: 20px; |
||||
color: rgb(0 0 0 / 45%); |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,71 @@
@@ -0,0 +1,71 @@
|
||||
<template> |
||||
<List :class="prefixCls"> |
||||
<a-row :gutter="16"> |
||||
<template v-for="item in list" :key="item.title"> |
||||
<a-col :span="6"> |
||||
<ListItem> |
||||
<Card :hoverable="true" :class="`${prefixCls}__card`"> |
||||
<img :src="demoImg" /> |
||||
<div :class="`${prefixCls}__card-title`"> |
||||
{{ item.title }} |
||||
</div> |
||||
<div :class="`${prefixCls}__card-content`"> |
||||
{{ item.content }} |
||||
</div> |
||||
</Card> |
||||
</ListItem> |
||||
</a-col> |
||||
</template> |
||||
</a-row> |
||||
</List> |
||||
</template> |
||||
<script lang="ts"> |
||||
import { defineComponent } from 'vue'; |
||||
import { List, Card, Row, Col } from 'ant-design-vue'; |
||||
import demoImg from '/@/assets/images/demo.png'; |
||||
import { projectList } from './data'; |
||||
|
||||
export default defineComponent({ |
||||
components: { |
||||
List, |
||||
ListItem: List.Item, |
||||
Card, |
||||
[Row.name]: Row, |
||||
[Col.name]: Col, |
||||
}, |
||||
setup() { |
||||
return { |
||||
prefixCls: 'account-center-project', |
||||
list: projectList, |
||||
demoImg, |
||||
}; |
||||
}, |
||||
}); |
||||
</script> |
||||
<style lang="less"> |
||||
.account-center-project { |
||||
&__card { |
||||
width: 100%; |
||||
|
||||
.ant-card-body { |
||||
padding: 0 0 24px; |
||||
} |
||||
|
||||
img { |
||||
width: 100%; |
||||
height: 130px; |
||||
} |
||||
|
||||
&-title { |
||||
margin: 5px 10px; |
||||
font-size: 16px; |
||||
font-weight: 500; |
||||
color: rgb(0 0 0 / 85%); |
||||
} |
||||
|
||||
&-content { |
||||
margin: 5px 10px; |
||||
} |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,132 @@
@@ -0,0 +1,132 @@
|
||||
export interface ListItem { |
||||
title: string; |
||||
icon: string; |
||||
color?: string; |
||||
} |
||||
|
||||
export interface TabItem { |
||||
key: string; |
||||
name: string; |
||||
component: string; |
||||
} |
||||
|
||||
export const tags: string[] = [ |
||||
'很有想法的', |
||||
'专注设计', |
||||
'川妹子', |
||||
'大长腿', |
||||
'海纳百川', |
||||
'前端开发', |
||||
'vue3', |
||||
]; |
||||
|
||||
export const teams: ListItem[] = [ |
||||
{ |
||||
icon: 'ri:alipay-fill', |
||||
title: '科学搬砖组', |
||||
color: '#ff4000', |
||||
}, |
||||
{ |
||||
icon: 'emojione-monotone:letter-a', |
||||
title: '中二少年团', |
||||
color: '#7c51b8', |
||||
}, |
||||
{ |
||||
icon: 'ri:alipay-fill', |
||||
title: '高逼格设计', |
||||
color: '#00adf7', |
||||
}, |
||||
{ |
||||
icon: 'jam:codepen-circle', |
||||
title: '程序员日常', |
||||
color: '#00adf7', |
||||
}, |
||||
{ |
||||
icon: 'fa:behance-square', |
||||
title: '科学搬砖组', |
||||
color: '#7c51b8', |
||||
}, |
||||
{ |
||||
icon: 'jam:codepen-circle', |
||||
title: '程序员日常', |
||||
color: '#ff4000', |
||||
}, |
||||
]; |
||||
|
||||
export const details: ListItem[] = [ |
||||
{ |
||||
icon: 'ic:outline-contacts', |
||||
title: '交互专家', |
||||
}, |
||||
{ |
||||
icon: 'grommet-icons:cluster', |
||||
title: '某某某事业群', |
||||
}, |
||||
{ |
||||
icon: 'bx:bx-home-circle', |
||||
title: '福建省厦门市', |
||||
}, |
||||
]; |
||||
|
||||
export const achieveList: TabItem[] = [ |
||||
{ |
||||
key: '1', |
||||
name: '文章', |
||||
component: 'Article', |
||||
}, |
||||
{ |
||||
key: '2', |
||||
name: '应用', |
||||
component: 'Application', |
||||
}, |
||||
{ |
||||
key: '3', |
||||
name: '项目', |
||||
component: 'Project', |
||||
}, |
||||
]; |
||||
|
||||
export const actions: any[] = [ |
||||
{ icon: 'clarity:star-line', text: '156', color: '#018ffb' }, |
||||
{ icon: 'bx:bxs-like', text: '156', color: '#459ae8' }, |
||||
{ icon: 'bx:bxs-message-dots', text: '2', color: '#42d27d' }, |
||||
]; |
||||
|
||||
export const articleList = (() => { |
||||
const result: any[] = []; |
||||
for (let i = 0; i < 4; i++) { |
||||
result.push({ |
||||
title: 'Vben Admin', |
||||
description: ['Vben', '设计语言', 'Typescript'], |
||||
content: '基于Vue Next, TypeScript, Ant Design实现的一套完整的企业级后台管理系统。', |
||||
time: '2020-11-14 11:20', |
||||
}); |
||||
} |
||||
return result; |
||||
})(); |
||||
|
||||
export const applicationList = (() => { |
||||
const result: any[] = []; |
||||
for (let i = 0; i < 8; i++) { |
||||
result.push({ |
||||
title: 'Vben Admin', |
||||
icon: 'emojione-monotone:letter-a', |
||||
color: '#1890ff', |
||||
active: '100', |
||||
new: '1,799', |
||||
download: 'bx:bx-download', |
||||
}); |
||||
} |
||||
return result; |
||||
})(); |
||||
|
||||
export const projectList = (() => { |
||||
const result: any[] = []; |
||||
for (let i = 0; i < 8; i++) { |
||||
result.push({ |
||||
title: 'Vben Admin', |
||||
content: '基于Vue Next, TypeScript, Ant Design实现的一套完整的企业级后台管理系统。', |
||||
}); |
||||
} |
||||
return result; |
||||
})(); |
@ -0,0 +1,155 @@
@@ -0,0 +1,155 @@
|
||||
<template> |
||||
<div :class="prefixCls"> |
||||
<a-row :class="`${prefixCls}-top`"> |
||||
<a-col :span="9" :class="`${prefixCls}-col`"> |
||||
<a-row> |
||||
<a-col :span="8"> |
||||
<div :class="`${prefixCls}-top__avatar`"> |
||||
<img width="70" :src="avatar" /> |
||||
<span>Vben</span> |
||||
<div>海纳百川,有容乃大</div> |
||||
</div> |
||||
</a-col> |
||||
<a-col :span="16"> |
||||
<div :class="`${prefixCls}-top__detail`"> |
||||
<template v-for="detail in details" :key="detail.title"> |
||||
<p> |
||||
<Icon :icon="detail.icon" /> |
||||
{{ detail.title }} |
||||
</p> |
||||
</template> |
||||
</div> |
||||
</a-col> |
||||
</a-row> |
||||
</a-col> |
||||
<a-col :span="7" :class="`${prefixCls}-col`"> |
||||
<CollapseContainer title="标签" :canExpan="false"> |
||||
<template v-for="tag in tags" :key="tag"> |
||||
<Tag class="mb-2"> |
||||
{{ tag }} |
||||
</Tag> |
||||
</template> |
||||
</CollapseContainer> |
||||
</a-col> |
||||
<a-col :span="8" :class="`${prefixCls}-col`"> |
||||
<CollapseContainer :class="`${prefixCls}-top__team`" title="团队" :canExpan="false"> |
||||
<div v-for="(team, index) in teams" :key="index" :class="`${prefixCls}-top__team-item`"> |
||||
<Icon :icon="team.icon" :color="team.color" /> |
||||
<span>{{ team.title }}</span> |
||||
</div> |
||||
</CollapseContainer> |
||||
</a-col> |
||||
</a-row> |
||||
<div :class="`${prefixCls}-bottom`"> |
||||
<Tabs> |
||||
<template v-for="item in achieveList" :key="item.key"> |
||||
<TabPane :tab="item.name"> |
||||
<component :is="item.component" /> |
||||
</TabPane> |
||||
</template> |
||||
</Tabs> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script lang="ts"> |
||||
import { Tag, Tabs, Row, Col } from 'ant-design-vue'; |
||||
import { defineComponent, computed } from 'vue'; |
||||
import { CollapseContainer } from '/@/components/Container/index'; |
||||
import Icon from '/@/components/Icon/index'; |
||||
import Article from './Article.vue'; |
||||
import Application from './Application.vue'; |
||||
import Project from './Project.vue'; |
||||
|
||||
import headerImg from '/@/assets/images/header.jpg'; |
||||
import { tags, teams, details, achieveList } from './data'; |
||||
import { useUserStore } from '/@/store/modules/user'; |
||||
|
||||
export default defineComponent({ |
||||
components: { |
||||
CollapseContainer, |
||||
Icon, |
||||
Tag, |
||||
Tabs, |
||||
TabPane: Tabs.TabPane, |
||||
Article, |
||||
Application, |
||||
Project, |
||||
[Row.name]: Row, |
||||
[Col.name]: Col, |
||||
}, |
||||
setup() { |
||||
const userStore = useUserStore(); |
||||
const avatar = computed(() => userStore.getUserInfo.avatar || headerImg); |
||||
return { |
||||
prefixCls: 'account-center', |
||||
avatar, |
||||
tags, |
||||
teams, |
||||
details, |
||||
achieveList, |
||||
}; |
||||
}, |
||||
}); |
||||
</script> |
||||
<style lang="less" scoped> |
||||
.account-center { |
||||
&-col:not(:last-child) { |
||||
padding: 0 10px; |
||||
|
||||
&:not(:last-child) { |
||||
border-right: 1px dashed rgb(206 206 206 / 50%); |
||||
} |
||||
} |
||||
|
||||
&-top { |
||||
padding: 10px; |
||||
margin: 16px 16px 12px; |
||||
background-color: @component-background; |
||||
border-radius: 3px; |
||||
|
||||
&__avatar { |
||||
text-align: center; |
||||
|
||||
img { |
||||
margin: auto; |
||||
border-radius: 50%; |
||||
} |
||||
|
||||
span { |
||||
display: block; |
||||
font-size: 20px; |
||||
font-weight: 500; |
||||
} |
||||
|
||||
div { |
||||
margin-top: 3px; |
||||
font-size: 12px; |
||||
} |
||||
} |
||||
|
||||
&__detail { |
||||
padding-left: 20px; |
||||
margin-top: 15px; |
||||
} |
||||
|
||||
&__team { |
||||
&-item { |
||||
display: inline-block; |
||||
padding: 4px 24px; |
||||
} |
||||
|
||||
span { |
||||
margin-left: 3px; |
||||
} |
||||
} |
||||
} |
||||
|
||||
&-bottom { |
||||
padding: 10px; |
||||
margin: 0 16px 16px; |
||||
background-color: @component-background; |
||||
border-radius: 3px; |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,34 @@
@@ -0,0 +1,34 @@
|
||||
<template> |
||||
<CollapseContainer title="企业认证" :canExpan="false"> |
||||
|
||||
</CollapseContainer> |
||||
</template> |
||||
<script lang="ts"> |
||||
import { List } from 'ant-design-vue'; |
||||
import { defineComponent } from 'vue'; |
||||
import { CollapseContainer } from '/@/components/Container/index'; |
||||
import Icon from '/@/components/Icon/index'; |
||||
|
||||
export default defineComponent({ |
||||
components: { |
||||
CollapseContainer |
||||
}, |
||||
setup() { |
||||
return { |
||||
|
||||
}; |
||||
}, |
||||
}); |
||||
</script> |
||||
<style lang="less" scoped> |
||||
.avatar { |
||||
font-size: 40px !important; |
||||
} |
||||
|
||||
.extra { |
||||
float: right; |
||||
margin-top: 10px; |
||||
margin-right: 30px; |
||||
cursor: pointer; |
||||
} |
||||
</style> |
@ -0,0 +1,152 @@
@@ -0,0 +1,152 @@
|
||||
<template> |
||||
<div ref="wrapperRef" |
||||
class="user-info" |
||||
:style="getContentStyle" |
||||
> |
||||
<ARow :gutter="24"> |
||||
<ACol :span="14"> |
||||
<BasicForm @register="register"/> |
||||
</ACol> |
||||
<ACol :span="10"> |
||||
<div class="change-avatar"> |
||||
<CropperAvatar |
||||
:uploadApi="commonUpload" |
||||
:value="getAvatarUrl" |
||||
btnText="更换头像" |
||||
:btnProps="{ preIcon: 'ant-design:cloud-upload-outlined' }" |
||||
:width="150" |
||||
@change="handleAvatarChange" |
||||
/> |
||||
</div> |
||||
</ACol> |
||||
</ARow> |
||||
</div> |
||||
</template> |
||||
<script lang="ts"> |
||||
import { Row, Col } from 'ant-design-vue'; |
||||
import { defineComponent, onMounted, computed, ref, CSSProperties, unref, reactive } from 'vue'; |
||||
import { BasicForm, useForm } from '/@/components/Form/index'; |
||||
import { CropperAvatar } from '/@/components/Cropper'; |
||||
import { useMessage } from '/@/hooks/web/useMessage'; |
||||
import { editUser, getUser } from '/@/api/platform/system/controller/user'; |
||||
import { userFormSchema } from './data'; |
||||
import { useUserStore } from '/@/store/modules/user'; |
||||
import { commonUpload } from '/@/api/platform/core/controller/upload'; |
||||
import { useContentHeight } from '/@/hooks/web/useContentHeight'; |
||||
import { User } from '/@/api/platform/core/entity/user'; |
||||
import { isEmpty, isUrl } from '/@/utils/is'; |
||||
import { assignWith } from 'lodash-es'; |
||||
import { useGlobSetting } from '/@/hooks/setting'; |
||||
const { apiUrl } = useGlobSetting(); |
||||
|
||||
interface State { |
||||
baseInfoBtnLoading: boolean; |
||||
userInfo: User | any; |
||||
} |
||||
export default defineComponent({ |
||||
components: { |
||||
BasicForm, |
||||
ARow: Row, |
||||
ACol: Col, |
||||
CropperAvatar, |
||||
}, |
||||
setup() { |
||||
const wrapperRef = ref(null); |
||||
const { createMessage } = useMessage(); |
||||
const userStore = useUserStore(); |
||||
const userInfoStore = userStore.getUserInfo; |
||||
const state = reactive<State>({ |
||||
baseInfoBtnLoading: false, |
||||
userInfo: undefined |
||||
}); |
||||
const [register, { setFieldsValue, validate }] = useForm({ |
||||
labelWidth: 120, |
||||
schemas: userFormSchema, |
||||
showSubmitButton: true, |
||||
showResetButton: false, |
||||
showAdvancedButton: false, |
||||
submitButtonOptions: { |
||||
text: '保存', |
||||
preIcon: 'fa-regular:save', |
||||
loading: state.baseInfoBtnLoading, |
||||
onClick: handleSubmit |
||||
}, |
||||
actionColOptions: { span: 24 } |
||||
}); |
||||
|
||||
onMounted(async () => { |
||||
const result = await getUser(userInfoStore.id); |
||||
state.userInfo = result.result; |
||||
await setFieldsValue(result.result); |
||||
}); |
||||
|
||||
// 动态计算元素高度 |
||||
const { redoHeight, contentHeight } = useContentHeight( |
||||
computed(() => true), |
||||
wrapperRef, |
||||
[], |
||||
[], |
||||
ref(30)); |
||||
|
||||
const getContentStyle = computed((): CSSProperties => ({ minHeight: `${unref(contentHeight)}px` })); |
||||
|
||||
async function handleSubmit() { |
||||
try { |
||||
const formData = await validate(); |
||||
formData.avatar = state.userInfo.avatar; |
||||
state.baseInfoBtnLoading = true; |
||||
await editUser(formData); |
||||
createMessage.success('保存成功!'); |
||||
const result = await getUser(userInfoStore.id); |
||||
state.userInfo = result.result; |
||||
// 更新用户状态管理与用户信息数据 |
||||
const userinfo = userStore.getUserInfo; |
||||
assignWith(userinfo, state.userInfo, (objValue, srcValue)=> !isEmpty(srcValue) ? srcValue : objValue); |
||||
userStore.setUserInfo(userinfo); |
||||
await setFieldsValue(result.result); |
||||
} finally { |
||||
state.baseInfoBtnLoading = false; |
||||
} |
||||
} |
||||
|
||||
const getUserInfo = computed((): User & any => state.userInfo || {}); |
||||
|
||||
const getAvatarUrl = computed((): string => { |
||||
if (!unref(getUserInfo).avatar) return userInfoStore.avatar; |
||||
return isUrl(unref(getUserInfo).avatar) ? unref(getUserInfo).avatar : apiUrl + unref(getUserInfo).avatar; |
||||
}); |
||||
|
||||
function handleAvatarChange({ src, data }) { |
||||
state.userInfo.avatar = data.url; |
||||
} |
||||
|
||||
return { |
||||
register, |
||||
wrapperRef, |
||||
getUserInfo, |
||||
commonUpload, |
||||
handleAvatarChange, |
||||
getContentStyle, |
||||
getAvatarUrl, |
||||
handleSubmit |
||||
}; |
||||
} |
||||
}); |
||||
</script> |
||||
|
||||
<style lang="less" scoped> |
||||
.user-info { |
||||
background: @component-background; |
||||
|
||||
> .ant-row:first-child { |
||||
.ant-col { |
||||
margin-top: 45px; |
||||
} |
||||
} |
||||
|
||||
.change-avatar { |
||||
margin-top: 35px; |
||||
text-align: center; |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,93 @@
@@ -0,0 +1,93 @@
|
||||
import { FormSchema } from '/@/components/Form/index'; |
||||
|
||||
export const settingList = [ |
||||
{ |
||||
key: '1', |
||||
name: '个人信息', |
||||
component: 'UserInfo', |
||||
prefixIcon: 'fa:user' |
||||
}, |
||||
{ |
||||
key: '2', |
||||
name: '企业认证', |
||||
component: 'EntCertification', |
||||
prefixIcon: 'fa6-solid:city' |
||||
} |
||||
]; |
||||
|
||||
export const userFormSchema: FormSchema[] = [ |
||||
{ |
||||
field: 'id', |
||||
label: 'ID', |
||||
component: 'Input', |
||||
show: false |
||||
}, |
||||
{ |
||||
field: 'nickName', |
||||
label: '用户昵称', |
||||
component: 'Input', |
||||
required: true |
||||
}, |
||||
{ |
||||
field: 'deptName', |
||||
label: '归属机构', |
||||
component: 'Input', |
||||
required: true, |
||||
componentProps: { |
||||
disabled: true |
||||
} |
||||
}, |
||||
{ |
||||
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' |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
field: 'email', |
||||
label: '邮箱', |
||||
component: 'Input', |
||||
rules: [ |
||||
{ |
||||
required: true, |
||||
message: '请输入邮箱!', |
||||
}, |
||||
{ |
||||
type: 'email', |
||||
message: '请输入正确的邮箱地址!', |
||||
validateTrigger: ['blur', 'change'] |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
field: 'sex', |
||||
label: '性别', |
||||
component: 'RadioGroup', |
||||
defaultValue: '0', |
||||
required: true, |
||||
componentProps: { |
||||
options: [ |
||||
{ label: '男', value: '0' }, |
||||
{ label: '女', value: '1' } |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
label: '备注', |
||||
field: 'remarks', |
||||
component: 'InputTextArea', |
||||
componentProps: { |
||||
rows: 6 |
||||
} |
||||
} |
||||
]; |
@ -0,0 +1,88 @@
@@ -0,0 +1,88 @@
|
||||
<template> |
||||
<ScrollContainer> |
||||
<div class="account-setting"> |
||||
<Tabs tab-position="left" |
||||
:animated="false" |
||||
:tabBarStyle="tabBarStyle" |
||||
> |
||||
<template v-for="item in settingList" :key="item.key"> |
||||
<TabPane> |
||||
<template #tab> |
||||
<span> |
||||
<Icon :icon="item.prefixIcon"/> |
||||
{{ item.name }} |
||||
</span> |
||||
</template> |
||||
<component :is="item.component"/> |
||||
</TabPane> |
||||
</template> |
||||
</Tabs> |
||||
</div> |
||||
</ScrollContainer> |
||||
</template> |
||||
|
||||
<script lang="ts"> |
||||
import { defineComponent } from 'vue'; |
||||
import { Tabs } from 'ant-design-vue'; |
||||
import { ScrollContainer } from '/@/components/Container/index'; |
||||
import { settingList } from './data'; |
||||
import UserInfo from './UserInfo.vue'; |
||||
import EntCertification from './EntCertification.vue'; |
||||
import { Icon } from '/@/components/Icon'; |
||||
|
||||
export default defineComponent({ |
||||
components: { |
||||
ScrollContainer, |
||||
Tabs, |
||||
TabPane: Tabs.TabPane, |
||||
UserInfo, |
||||
EntCertification, |
||||
Icon |
||||
}, |
||||
setup() { |
||||
return { |
||||
settingList, |
||||
tabBarStyle: { |
||||
width: '220px', |
||||
'margin-bottom': '200px' |
||||
}, |
||||
}; |
||||
}, |
||||
}); |
||||
</script> |
||||
<style lang="less" scoped> |
||||
.account-setting { |
||||
margin: 12px; |
||||
|
||||
::v-deep(.ant-tabs-left) > .ant-tabs-left-bar { |
||||
background-color: @component-background; |
||||
height: 260px; |
||||
|
||||
.ant-tabs-tab { |
||||
padding: 8px 24px; |
||||
text-align: left; |
||||
} |
||||
|
||||
.ant-tabs-tab-active { |
||||
border-radius: 0 20px 20px 0; |
||||
background-color: @primary-color !important; |
||||
color: #fff!important; |
||||
} |
||||
|
||||
.ant-tabs-nav { |
||||
padding-top: 14px; |
||||
padding-right: 14px; |
||||
padding-bottom: 14px; |
||||
} |
||||
|
||||
.ant-tabs-ink-bar { |
||||
height: 0px !important; |
||||
} |
||||
} |
||||
|
||||
::v-deep(.ant-tabs) > .ant-tabs-left-content { |
||||
padding-left: 10px; |
||||
} |
||||
|
||||
} |
||||
</style> |
Loading…
Reference in new issue