mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-10 18:02:55 +00:00
feat: 优化个人资料卡片
This commit is contained in:
parent
6d97bf1e88
commit
ab76185434
@ -5,120 +5,82 @@
|
||||
:fullscreen="isFullscreen"
|
||||
:mask-closable="false"
|
||||
:footer-hide="true"
|
||||
width="600">
|
||||
width="420">
|
||||
<div class="user-detail-body">
|
||||
<UserAvatar
|
||||
:userid="userData.userid"
|
||||
:size="120"
|
||||
:show-state-dot="false"
|
||||
@on-click="onOpenAvatar"/>
|
||||
<ul class="user-select-auto">
|
||||
<li class="user-name">
|
||||
<h1>{{userData.nickname}}</h1>
|
||||
<em v-if="userData.delete_at" class="deleted no-dark-content">{{$L('已删除')}}</em>
|
||||
<em v-else-if="userData.disable_at" class="disabled no-dark-content">{{$L('已离职')}}</em>
|
||||
</li>
|
||||
<li v-if="userData.userid != userId && commonDialog.total !== null">
|
||||
<span>{{$L('共同群聊')}}: </span>
|
||||
<a href="javascript:void(0)" @click="commonDialogShow=true">{{ $L('(*)个', commonDialog.total) }}</a>
|
||||
</li>
|
||||
<template v-if="!userData.bot">
|
||||
<li>
|
||||
<span>{{$L('部门')}}: </span>
|
||||
{{userData.department_name || '-'}}
|
||||
</li>
|
||||
<li>
|
||||
<span>{{$L('职位/职称')}}: </span>
|
||||
{{userData.profession || '-'}}
|
||||
</li>
|
||||
<li>
|
||||
<span>{{$L('生日')}}: </span>
|
||||
{{userData.birthday ? ($A.newDateString(userData.birthday, 'YYYY-MM-DD') || userData.birthday) : '-'}}
|
||||
</li>
|
||||
<li>
|
||||
<span>{{$L('地址')}}: </span>
|
||||
{{userData.address || '-'}}
|
||||
</li>
|
||||
<li>
|
||||
<span>{{$L('个人简介')}}: </span>
|
||||
{{userData.introduction || '-'}}
|
||||
</li>
|
||||
<li class="user-tags-line">
|
||||
<span>{{$L('个性标签')}}: </span>
|
||||
<div class="tags-content" @click="onOpenTagsModal">
|
||||
<div v-if="displayTags.length" class="tags-list">
|
||||
<Tag
|
||||
v-for="tag in displayTags"
|
||||
:key="tag.id"
|
||||
:color="tag.recognized ? 'primary' : 'default'"
|
||||
class="tag-pill">{{tag.name}}</Tag>
|
||||
</div>
|
||||
<span v-else class="tags-empty">{{$L('暂无个性标签')}}</span>
|
||||
<div class="tags-extra">
|
||||
<span v-if="personalTagTotal > displayTags.length" class="tags-total">{{$L('共(*)个', personalTagTotal)}}</span>
|
||||
<Button type="text" size="small" class="manage-button" @click.stop="onOpenTagsModal">{{$L('管理')}}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<span>{{$L('最后在线')}}: </span>
|
||||
{{$A.newDateString(userData.line_at, 'YYYY-MM-DD HH:mm') || '-'}}
|
||||
</li>
|
||||
<li v-if="userData.delete_at">
|
||||
<strong><span>{{$L('删除时间')}}: </span>{{$A.newDateString(userData.delete_at, 'YYYY-MM-DD HH:mm')}}</strong>
|
||||
</li>
|
||||
<li v-else-if="userData.disable_at">
|
||||
<strong><span>{{$L('离职时间')}}: </span>{{$A.newDateString(userData.disable_at, 'YYYY-MM-DD HH:mm')}}</strong>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
<div class="user-detail-actions">
|
||||
<Button icon="md-chatbubbles" :disabled="!!userData.delete_at" @click="onOpenDialog">{{ $L('开始聊天') }}</Button>
|
||||
<Button icon="md-people" :disabled="!!userData.delete_at" @click="onOpenCreateGroup">{{ $L('创建群组') }}</Button>
|
||||
<div class="profile-header">
|
||||
<div class="cover-photo"></div>
|
||||
<div class="profile-avatar">
|
||||
<UserAvatar
|
||||
:userid="userData.userid"
|
||||
:size="80"
|
||||
:show-state-dot="false"
|
||||
@on-click="onOpenAvatar"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="profile-content">
|
||||
<div class="user-info-top">
|
||||
<span class="username">@{{userData.nickname || 'Arnoldy'}}</span>
|
||||
<h1 class="fullname">{{userData.nickname || 'Arnoldy Chafe'}}</h1>
|
||||
<div class="meta">
|
||||
<span>{{userData.address || 'Bandung'}}</span>
|
||||
<span class="separator">|</span>
|
||||
<span>Joined {{$A.newDateString(userData.line_at, 'MMM YYYY')}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="profile-actions">
|
||||
<Button type="primary" icon="ios-person-add-outline">{{$L('Follow')}}</Button>
|
||||
<Button icon="ios-chatbubble-outline">{{$L('Message')}}</Button>
|
||||
<Button icon="ios-more"></Button>
|
||||
</div>
|
||||
|
||||
<div class="profile-bio">
|
||||
<p>{{userData.introduction || 'CEO System D, Because your satisfaction is everything & Standing out from the rest, and that\'s what we want you to be as well.'}}</p>
|
||||
</div>
|
||||
|
||||
<div class="profile-information">
|
||||
<h2>{{$L('Information')}}</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<Icon type="ios-globe-outline" />
|
||||
<span class="label">{{$L('Website')}}</span>
|
||||
<span class="value">www.Arnoldy.com</span>
|
||||
</li>
|
||||
<li>
|
||||
<Icon type="ios-mail-outline" />
|
||||
<span class="label">{{$L('Email')}}</span>
|
||||
<span class="value">Hello@adalahreza.com</span>
|
||||
</li>
|
||||
<li>
|
||||
<Icon type="ios-call-outline" />
|
||||
<span class="label">{{$L('Phone')}}</span>
|
||||
<span class="value">+62 517 218 92 00</span>
|
||||
</li>
|
||||
<li>
|
||||
<Icon type="ios-calendar-outline" />
|
||||
<span class="label">{{$L('Joined')}}</span>
|
||||
<span class="value">{{$A.newDateString(userData.line_at, 'DD MMMM, YYYY')}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="profile-tags" @click="onOpenTagsModal">
|
||||
<div v-if="displayTags.length" class="tags-list">
|
||||
<Tag
|
||||
v-for="tag in displayTags"
|
||||
:key="tag.id"
|
||||
:color="tag.recognized ? 'primary' : 'default'"
|
||||
class="tag-pill">{{tag.name}}</Tag>
|
||||
<Tag v-if="!displayTags.length" class="tag-pill">UI Designer</Tag>
|
||||
<Tag v-if="!displayTags.length" class="tag-pill">UX Designer</Tag>
|
||||
<Tag v-if="!displayTags.length" class="tag-pill">Design System</Tag>
|
||||
<Tag v-if="!displayTags.length" class="tag-pill">Product</Tag>
|
||||
<Tag v-if="!displayTags.length" class="tag-pill">Succesfull</Tag>
|
||||
</div>
|
||||
<span v-else class="tags-empty">{{$L('暂无个性标签')}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 共同群组 -->
|
||||
<Modal v-model="commonDialogShow" :title="$L('共同群组') + ' (' + $L('(*)个', commonDialog.total) + ')'" :footer-hide="true" width="500">
|
||||
<div class="common-dialog-content">
|
||||
<div v-if="commonDialogLoading > 0 && commonDialog.list.length === 0" class="loading-wrapper">
|
||||
<Loading/>
|
||||
</div>
|
||||
<div v-else-if="commonDialogList.length === 0" class="empty-wrapper">
|
||||
<div class="empty-content">
|
||||
<Icon type="ios-people-outline" size="48"/>
|
||||
<p>{{$L('暂无共同群组')}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="dialog-list">
|
||||
<div
|
||||
v-for="dialog in commonDialogList"
|
||||
:key="dialog.id"
|
||||
class="dialog-item"
|
||||
@click="onOpenCommonDialogChat(dialog)">
|
||||
<div class="dialog-avatar">
|
||||
<EAvatar v-if="dialog.avatar" :src="dialog.avatar" :size="42"></EAvatar>
|
||||
<i v-else-if="dialog.group_type=='department'" class="taskfont icon-avatar department"></i>
|
||||
<i v-else-if="dialog.group_type=='project'" class="taskfont icon-avatar project"></i>
|
||||
<i v-else-if="dialog.group_type=='task'" class="taskfont icon-avatar task"></i>
|
||||
<i v-else-if="dialog.group_type=='okr'" class="taskfont icon-avatar task"></i>
|
||||
<Icon v-else class="icon-avatar" type="ios-people" />
|
||||
</div>
|
||||
<div class="dialog-info">
|
||||
<div class="dialog-name" v-html="transformEmojiToHtml(dialog.name)"></div>
|
||||
<div class="dialog-meta">
|
||||
<span class="member-count">{{$L('(*)人', dialog.people || 0)}}</span>
|
||||
<span v-if="dialog.last_at" class="last-time">{{$A.timeFormat(dialog.last_at)}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<Icon class="enter-icon" type="ios-arrow-forward" />
|
||||
</div>
|
||||
<div v-if="commonDialog.has_more" class="load-more-wrapper">
|
||||
<Button type="primary" @click="loadCommonDialogList(true)" :loading="commonDialogLoading > 0">{{$L('加载更多')}}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
<UserTagsModal
|
||||
v-if="userData.userid"
|
||||
v-model="tagModalVisible"
|
||||
@ -129,7 +91,6 @@
|
||||
|
||||
<script>
|
||||
import emitter from "../../../store/events";
|
||||
import transformEmojiToHtml from "../../../utils/emoji";
|
||||
import {mapState} from "vuex";
|
||||
import UserTagsModal from "./UserTagsModal.vue";
|
||||
|
||||
@ -143,20 +104,8 @@ export default {
|
||||
userData: {
|
||||
userid: 0
|
||||
},
|
||||
|
||||
showModal: false,
|
||||
|
||||
tagModalVisible: false,
|
||||
|
||||
commonDialog: {
|
||||
userid: null,
|
||||
total: null,
|
||||
list: [],
|
||||
page: 1,
|
||||
has_more: false,
|
||||
},
|
||||
commonDialogShow: false,
|
||||
commonDialogLoading: 0,
|
||||
}
|
||||
},
|
||||
|
||||
@ -170,13 +119,6 @@ export default {
|
||||
|
||||
watch: {
|
||||
...mapState(['cacheUserBasic']),
|
||||
|
||||
commonDialogShow() {
|
||||
if (!this.commonDialogShow || this.commonDialog.list.length > 0) {
|
||||
return;
|
||||
}
|
||||
this.loadCommonDialogList(false);
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
@ -184,10 +126,6 @@ export default {
|
||||
return windowWidth < 576
|
||||
},
|
||||
|
||||
commonDialogList() {
|
||||
return this.commonDialog.list || [];
|
||||
},
|
||||
|
||||
displayTags() {
|
||||
return Array.isArray(this.userData.personal_tags) ? this.userData.personal_tags : [];
|
||||
},
|
||||
@ -201,8 +139,6 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
transformEmojiToHtml,
|
||||
|
||||
onShow(userid) {
|
||||
if (!/^\d+$/.test(userid)) {
|
||||
return
|
||||
@ -212,14 +148,12 @@ export default {
|
||||
this.userData = user;
|
||||
this.ensureTagDefaults();
|
||||
this.showModal = true;
|
||||
this.loadCommonDialogCount()
|
||||
}).finally(_ => {
|
||||
this.$store.dispatch("hiddenSpinner")
|
||||
});
|
||||
},
|
||||
|
||||
onHide() {
|
||||
this.commonDialogShow = false;
|
||||
this.showModal = false;
|
||||
this.tagModalVisible = false;
|
||||
},
|
||||
@ -236,20 +170,6 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
onOpenCreateGroup() {
|
||||
const userids = [];
|
||||
if (this.userId) {
|
||||
userids.push(this.userId);
|
||||
}
|
||||
if (this.userData.userid && this.userData.userid !== this.userId) {
|
||||
userids.push(this.userData.userid);
|
||||
}
|
||||
if (userids.length === 0 && this.userData.userid) {
|
||||
userids.push(this.userData.userid);
|
||||
}
|
||||
emitter.emit('createGroup', userids);
|
||||
},
|
||||
|
||||
ensureTagDefaults() {
|
||||
if (!Array.isArray(this.userData.personal_tags)) {
|
||||
this.$set(this.userData, 'personal_tags', []);
|
||||
@ -270,152 +190,11 @@ export default {
|
||||
this.$set(this.userData, 'personal_tags', Array.isArray(top) ? top : []);
|
||||
this.$set(this.userData, 'personal_tags_total', typeof total === 'number' ? total : this.userData.personal_tags.length);
|
||||
},
|
||||
|
||||
loadCommonDialogCount() {
|
||||
const target_userid = this.userData.userid;
|
||||
const previousUserId = this.commonDialog.userid;
|
||||
if (!target_userid) {
|
||||
this.commonDialog = {
|
||||
...this.commonDialog,
|
||||
userid: target_userid || null,
|
||||
total: null,
|
||||
list: [],
|
||||
page: 1,
|
||||
has_more: false,
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
if (previousUserId !== target_userid) {
|
||||
this.commonDialog = {
|
||||
...this.commonDialog,
|
||||
userid: target_userid,
|
||||
total: null,
|
||||
list: [],
|
||||
page: 1,
|
||||
has_more: false,
|
||||
};
|
||||
}
|
||||
|
||||
const cacheMap = this.$store.state.dialogCommonCountCache || {};
|
||||
const cached = cacheMap[String(target_userid)];
|
||||
if (cached && typeof cached.total !== 'undefined') {
|
||||
this.commonDialog = {
|
||||
...this.commonDialog,
|
||||
total: cached.total,
|
||||
};
|
||||
}
|
||||
|
||||
this.$store.dispatch('call', {
|
||||
url: 'dialog/common/list',
|
||||
data: {
|
||||
target_userid,
|
||||
only_count: 'yes'
|
||||
}
|
||||
}).then(({data}) => {
|
||||
if (target_userid !== this.userData.userid) {
|
||||
return
|
||||
}
|
||||
const parsedTotal = Number(data.total);
|
||||
const total = Number.isNaN(parsedTotal) ? 0 : parsedTotal;
|
||||
this.commonDialog = {
|
||||
...this.commonDialog,
|
||||
userid: target_userid,
|
||||
total,
|
||||
list: [],
|
||||
page: 1,
|
||||
has_more: false,
|
||||
};
|
||||
this.$store.commit('common/dialog/count/save', {
|
||||
userid: target_userid,
|
||||
total,
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
loadCommonDialogList(loadMore = false) {
|
||||
this.commonDialogLoading++;
|
||||
const target_userid = this.userData.userid;
|
||||
this.$store.dispatch('call', {
|
||||
url: 'dialog/common/list',
|
||||
data: {
|
||||
target_userid,
|
||||
page: loadMore ? this.commonDialog.page + 1 : 1
|
||||
}
|
||||
}).then(({data}) => {
|
||||
if (target_userid !== this.userData.userid) {
|
||||
return;
|
||||
}
|
||||
this.commonDialog = {
|
||||
...this.commonDialog,
|
||||
list: loadMore ? [...this.commonDialog.list, ...data.data] : data.data,
|
||||
total: data.total,
|
||||
page: data.current_page,
|
||||
has_more: !!data.next_page_url
|
||||
}
|
||||
}).catch(({msg}) => {
|
||||
$A.modalError(msg || this.$L('加载失败'));
|
||||
}).finally(() => {
|
||||
this.commonDialogLoading--;
|
||||
});
|
||||
},
|
||||
|
||||
onOpenCommonDialogChat(dialog) {
|
||||
this.$store.dispatch("openDialog", dialog.id).then(() => {
|
||||
this.onHide();
|
||||
}).catch(({msg}) => {
|
||||
$A.modalError(msg);
|
||||
});
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.user-tags-line {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
|
||||
span:first-child {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.tags-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tags-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
|
||||
.tag-pill {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.tags-empty {
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.tags-extra {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.tags-total {
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.manage-button {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
// The styles will be moved to the SCSS file as requested.
|
||||
// This scoped style block can be removed if not needed for specific overrides.
|
||||
</style>
|
||||
|
||||
@ -1,89 +1,125 @@
|
||||
.common-user-detail-modal {
|
||||
.ivu-modal {
|
||||
max-width: 90%;
|
||||
|
||||
&.ivu-modal-fullscreen {
|
||||
max-width: none;
|
||||
|
||||
.ivu-modal-content {
|
||||
margin-top: calc(var(--status-bar-height) + 46px);
|
||||
margin-bottom: 0;
|
||||
border-top-left-radius: 18px !important;
|
||||
border-top-right-radius: 18px !important;
|
||||
|
||||
.ivu-modal-body {
|
||||
.user-detail-body {
|
||||
padding-bottom: var(--navigation-bar-height);
|
||||
}
|
||||
.ivu-modal-content {
|
||||
border-radius: 16px;
|
||||
}
|
||||
.ivu-modal-body {
|
||||
padding: 0 !important;
|
||||
}
|
||||
.user-detail-body {
|
||||
.profile-header {
|
||||
position: relative;
|
||||
height: 120px;
|
||||
.cover-photo {
|
||||
background: #1a2c47;
|
||||
height: 80px;
|
||||
border-top-left-radius: 16px;
|
||||
border-top-right-radius: 16px;
|
||||
}
|
||||
.profile-avatar {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
border: 4px solid #fff;
|
||||
border-radius: 50%;
|
||||
.user-avatar {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
.profile-content {
|
||||
padding: 16px 24px 24px;
|
||||
text-align: center;
|
||||
|
||||
.user-detail-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.ivu-modal-content {
|
||||
overflow: hidden;
|
||||
|
||||
.ivu-modal-body {
|
||||
padding: 0 !important;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.user-detail-body {
|
||||
.user-info-top {
|
||||
.username {
|
||||
color: #808695;
|
||||
font-size: 14px;
|
||||
}
|
||||
.fullname {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
margin: 4px 0;
|
||||
}
|
||||
.meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 84px 24px;
|
||||
|
||||
.avatar-wrapper {
|
||||
cursor: pointer;
|
||||
color: #808695;
|
||||
font-size: 12px;
|
||||
.separator {
|
||||
margin: 0 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> ul {
|
||||
width: 80%;
|
||||
.profile-actions {
|
||||
margin: 16px 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
> li {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 12px auto;
|
||||
.profile-bio {
|
||||
color: #515a6e;
|
||||
line-height: 1.5;
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
&.user-name {
|
||||
align-items: center;
|
||||
}
|
||||
.profile-information {
|
||||
text-align: left;
|
||||
background-color: #f8f8f9;
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
|
||||
> em {
|
||||
font-style: normal;
|
||||
&.disabled,
|
||||
&.deleted {
|
||||
display: inline-block;
|
||||
margin-left: 2px;
|
||||
white-space: nowrap;
|
||||
font-size: 12px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
padding: 0 6px;
|
||||
border-radius: 3px;
|
||||
transform: scale(0.9);
|
||||
transform-origin: right center;
|
||||
color: #ffffff;
|
||||
background-color: #ED4014;
|
||||
}
|
||||
}
|
||||
h2 {
|
||||
font-size: 16px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
> span {
|
||||
flex-shrink: 0;
|
||||
opacity: 0.8;
|
||||
padding-right: 4px;
|
||||
}
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 0;
|
||||
font-size: 14px;
|
||||
|
||||
.ivu-icon {
|
||||
font-size: 20px;
|
||||
margin-right: 12px;
|
||||
color: #808695;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: #515a6e;
|
||||
}
|
||||
|
||||
.value {
|
||||
margin-left: auto;
|
||||
color: #17233d;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.profile-tags {
|
||||
margin-top: 24px;
|
||||
cursor: pointer;
|
||||
.tags-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
justify-content: center;
|
||||
}
|
||||
.ivu-tag {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user