mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-11 02:12:53 +00:00
feat: 添加会员扩展信息接口,优化用户详情和个人设置页面
This commit is contained in:
parent
e4cfa4b405
commit
ab4640382d
@ -388,9 +388,6 @@ class UsersController extends AbstractController
|
||||
$data['nickname_original'] = $user->getRawOriginal('nickname');
|
||||
$data['department_name'] = $user->getDepartmentName();
|
||||
$data['department_owner'] = UserDepartment::where('parent_id',0)->where('owner_userid', $user->userid)->exists(); // 适用默认部门下第1级负责人才能添加部门OKR
|
||||
$tagMeta = UserTag::listWithMeta($user->userid, $user);
|
||||
$data['personal_tags'] = $tagMeta['top'];
|
||||
$data['personal_tags_total'] = $tagMeta['total'];
|
||||
return Base::retSuccess('success', $data);
|
||||
}
|
||||
|
||||
@ -809,12 +806,8 @@ class UsersController extends AbstractController
|
||||
public function basic()
|
||||
{
|
||||
$sharekey = Request::header('sharekey');
|
||||
$shareInfo = $sharekey ? Meeting::getShareInfo($sharekey) : null;
|
||||
$viewer = null;
|
||||
if (empty($shareInfo)) {
|
||||
$viewer = User::auth();
|
||||
} elseif (Doo::userId() > 0) {
|
||||
$viewer = User::whereUserid(Doo::userId())->first();
|
||||
if (empty($sharekey) || !Meeting::getShareInfo($sharekey)) {
|
||||
User::auth();
|
||||
}
|
||||
//
|
||||
$userid = Request::input('userid');
|
||||
@ -832,16 +825,75 @@ class UsersController extends AbstractController
|
||||
$basic = UserDelete::userid2basic($id);
|
||||
}
|
||||
if ($basic) {
|
||||
$tagMeta = UserTag::listWithMeta($basic->userid, $viewer);
|
||||
$basic->personal_tags = $tagMeta['top'];
|
||||
$basic->personal_tags_total = $tagMeta['total'];
|
||||
//
|
||||
$retArray[] = $basic;
|
||||
}
|
||||
}
|
||||
return Base::retSuccess('success', $retArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/extra 获取会员扩展信息
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup users
|
||||
* @apiName extra
|
||||
*
|
||||
* @apiParam {Number} [userid] 会员ID(不传默认为当前用户)
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function extra()
|
||||
{
|
||||
$user = User::auth();
|
||||
//
|
||||
$userid = intval(Request::input('userid'));
|
||||
if ($userid <= 0) {
|
||||
$userid = $user->userid;
|
||||
}
|
||||
if ($userid <= 0) {
|
||||
return Base::retError('会员不存在');
|
||||
}
|
||||
|
||||
$user = User::query()
|
||||
->select(['userid', 'birthday', 'address', 'introduction'])
|
||||
->whereUserid($userid)
|
||||
->first();
|
||||
|
||||
$birthday = null;
|
||||
$address = null;
|
||||
$introduction = null;
|
||||
|
||||
if ($user) {
|
||||
$birthday = $user->birthday;
|
||||
$address = $user->address;
|
||||
$introduction = $user->introduction;
|
||||
} else {
|
||||
$deleted = UserDelete::whereUserid($userid)->first();
|
||||
if (empty($deleted) || empty($deleted->cache)) {
|
||||
return Base::retError('会员不存在');
|
||||
}
|
||||
$birthday = $deleted->cache['birthday'] ?? null;
|
||||
$address = $deleted->cache['address'] ?? null;
|
||||
$introduction = $deleted->cache['introduction'] ?? null;
|
||||
}
|
||||
|
||||
$tagMeta = UserTag::listWithMeta($userid, $user);
|
||||
|
||||
$data = [
|
||||
'userid' => $userid,
|
||||
'birthday' => $birthday,
|
||||
'address' => $address,
|
||||
'introduction' => $introduction,
|
||||
'personal_tags' => $tagMeta['top'],
|
||||
'personal_tags_total' => $tagMeta['total'],
|
||||
];
|
||||
|
||||
return Base::retSuccess('success', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/lists 会员列表(限管理员)
|
||||
*
|
||||
|
||||
@ -92,7 +92,7 @@ class User extends AbstractModel
|
||||
public static $defaultAvatarMode = 'auto';
|
||||
|
||||
// 基本信息的字段
|
||||
public static $basicField = ['userid', 'email', 'nickname', 'profession', 'birthday', 'address', 'introduction', 'department', 'userimg', 'bot', 'az', 'pinyin', 'line_at', 'disable_at'];
|
||||
public static $basicField = ['userid', 'email', 'nickname', 'profession', 'department', 'userimg', 'bot', 'az', 'pinyin', 'line_at', 'disable_at'];
|
||||
|
||||
/**
|
||||
* 昵称
|
||||
|
||||
@ -198,10 +198,14 @@ export default {
|
||||
return;
|
||||
}
|
||||
this.$store.dispatch("showSpinner", 600);
|
||||
this.$store
|
||||
.dispatch("getUserData", userid)
|
||||
.then((user) => {
|
||||
this.userData = user;
|
||||
Promise.all([
|
||||
this.$store.dispatch("getUserData", userid).catch(() => null),
|
||||
this.$store.dispatch("getUserExtra", userid).catch(() => null),
|
||||
])
|
||||
.then(([user, extra]) => {
|
||||
const baseData = $A.isJson(user) ? user : {};
|
||||
const extraData = $A.isJson(extra) ? extra : {};
|
||||
this.userData = Object.assign({}, baseData, extraData);
|
||||
this.ensureTagDefaults();
|
||||
this.showModal = true;
|
||||
this.loadCommonDialogCount();
|
||||
|
||||
@ -93,7 +93,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
<div v-if="total > 0" class="tag-modal-footer">
|
||||
<span>{{$L('当前共(*)个标签', total)}}</span>
|
||||
<span>{{$L('当前共 (*) 个标签', total)}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</ModalAlive>
|
||||
@ -213,17 +213,14 @@ export default {
|
||||
},
|
||||
emitUpdated(payload) {
|
||||
this.$emit('updated', payload);
|
||||
if (this.userid === this.$store.state.userInfo.userid) {
|
||||
const info = Object.assign({}, this.$store.state.userInfo, {
|
||||
personal_tags: payload.top,
|
||||
personal_tags_total: payload.total
|
||||
});
|
||||
this.$store.dispatch('saveUserInfoBase', info);
|
||||
}
|
||||
this.$store.dispatch('saveUserBasic', {
|
||||
this.$store.dispatch('saveUserExtra', {
|
||||
userid: this.userid,
|
||||
personal_tags: payload.top,
|
||||
personal_tags_total: payload.total
|
||||
data: {
|
||||
personal_tags: Array.isArray(payload?.top) ? payload.top : [],
|
||||
personal_tags_total: typeof payload?.total === 'number'
|
||||
? payload.total
|
||||
: (Array.isArray(payload?.top) ? payload.top.length : 0)
|
||||
}
|
||||
});
|
||||
},
|
||||
handleAdd() {
|
||||
@ -418,10 +415,15 @@ export default {
|
||||
padding: 6px 12px;
|
||||
border-radius: 12px;
|
||||
font-size: 13px;
|
||||
line-height: 1;
|
||||
user-select: none;
|
||||
background-color: #f5f5f5;
|
||||
color: #606266;
|
||||
line-height: 14px;
|
||||
height: 26px;
|
||||
max-width: 160px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
&.is-recognized {
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
@ -89,16 +89,20 @@ export default {
|
||||
loadIng: 0,
|
||||
|
||||
formData: {
|
||||
// 基本信息
|
||||
userimg: '',
|
||||
email: '',
|
||||
tel: '',
|
||||
nickname: '',
|
||||
profession: '',
|
||||
// 拓展信息 生日、地址、个人简介
|
||||
birthday: '',
|
||||
address: '',
|
||||
introduction: ''
|
||||
},
|
||||
|
||||
extraInfo: {},
|
||||
|
||||
ruleData: {
|
||||
email: [
|
||||
{required: true, message: this.$L('请输入邮箱地址!'), trigger: 'change'},
|
||||
@ -120,6 +124,7 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
this.initData();
|
||||
this.loadUserExtra();
|
||||
},
|
||||
computed: {
|
||||
...mapState(['userInfo', 'formOptions']),
|
||||
@ -131,27 +136,60 @@ export default {
|
||||
watch: {
|
||||
userInfo() {
|
||||
this.initData();
|
||||
this.loadUserExtra();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initData() {
|
||||
const extra = this.extraInfo || {};
|
||||
this.$set(this.formData, 'userimg', $A.strExists(this.userInfo.userimg, '/avatar') ? '' : this.userInfo.userimg);
|
||||
this.$set(this.formData, 'email', this.userInfo.email);
|
||||
this.$set(this.formData, 'tel', this.userInfo.tel);
|
||||
this.$set(this.formData, 'nickname', typeof this.userInfo.nickname_original !== "undefined" ? this.userInfo.nickname_original : this.userInfo.nickname);
|
||||
this.$set(this.formData, 'profession', this.userInfo.profession);
|
||||
this.$set(this.formData, 'birthday', this.userInfo.birthday || '');
|
||||
this.$set(this.formData, 'address', this.userInfo.address || '');
|
||||
this.$set(this.formData, 'introduction', this.userInfo.introduction || '');
|
||||
this.$set(this.formData, 'birthday', extra.birthday || '');
|
||||
this.$set(this.formData, 'address', extra.address || '');
|
||||
this.$set(this.formData, 'introduction', extra.introduction || '');
|
||||
this.formData_bak = $A.cloneJSON(this.formData);
|
||||
this.syncPersonalTags();
|
||||
},
|
||||
|
||||
loadUserExtra(force = false) {
|
||||
const userid = this.userInfo?.userid;
|
||||
if (!userid) {
|
||||
this.applyExtraInfo({});
|
||||
return;
|
||||
}
|
||||
const payload = force ? {userid, force: true} : userid;
|
||||
this.$store.dispatch("getUserExtra", payload)
|
||||
.then((data) => {
|
||||
if ($A.isJson(data)) {
|
||||
this.applyExtraInfo(data);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
if (!this.extraInfo || Object.keys(this.extraInfo).length === 0) {
|
||||
this.applyExtraInfo({});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
applyExtraInfo(extra) {
|
||||
const info = $A.isJson(extra) ? extra : {};
|
||||
this.extraInfo = info;
|
||||
this.$set(this.formData, 'birthday', info.birthday || '');
|
||||
this.$set(this.formData, 'address', info.address || '');
|
||||
this.$set(this.formData, 'introduction', info.introduction || '');
|
||||
this.syncPersonalTags();
|
||||
this.formData_bak = $A.cloneJSON(this.formData);
|
||||
},
|
||||
|
||||
syncPersonalTags() {
|
||||
const tags = Array.isArray(this.userInfo.personal_tags) ? this.userInfo.personal_tags : [];
|
||||
const extra = this.extraInfo || {};
|
||||
const tags = Array.isArray(extra.personal_tags) ? extra.personal_tags : [];
|
||||
this.personalTags = tags.slice(0, 10);
|
||||
this.personalTagTotal = typeof this.userInfo.personal_tags_total === 'number'
|
||||
? this.userInfo.personal_tags_total
|
||||
this.personalTagTotal = typeof extra.personal_tags_total === 'number'
|
||||
? extra.personal_tags_total
|
||||
: this.personalTags.length;
|
||||
},
|
||||
|
||||
@ -166,7 +204,24 @@ export default {
|
||||
data,
|
||||
}).then(() => {
|
||||
$A.messageSuccess('修改成功');
|
||||
this.$store.dispatch('getUserInfo').catch(() => {});
|
||||
const userid = this.userInfo?.userid;
|
||||
const extraPayload = {
|
||||
birthday: data.birthday || '',
|
||||
address: data.address || '',
|
||||
introduction: data.introduction || ''
|
||||
};
|
||||
if (userid) {
|
||||
this.$store.dispatch('saveUserExtra', {
|
||||
userid,
|
||||
data: extraPayload
|
||||
});
|
||||
}
|
||||
this.applyExtraInfo(Object.assign({}, this.extraInfo, extraPayload));
|
||||
this.$store.dispatch('getUserInfo')
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
this.loadUserExtra(true);
|
||||
});
|
||||
}).catch(({msg}) => {
|
||||
$A.modalError(msg);
|
||||
}).finally(_ => {
|
||||
@ -190,6 +245,10 @@ export default {
|
||||
onTagsUpdated({top, total}) {
|
||||
this.personalTags = Array.isArray(top) ? top : [];
|
||||
this.personalTagTotal = typeof total === 'number' ? total : this.personalTags.length;
|
||||
this.extraInfo = Object.assign({}, this.extraInfo, {
|
||||
personal_tags: this.personalTags,
|
||||
personal_tags_total: this.personalTagTotal
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -205,13 +264,18 @@ export default {
|
||||
|
||||
.tag-pill {
|
||||
cursor: pointer;
|
||||
padding: 5px 12px;
|
||||
padding: 6px 12px;
|
||||
border-radius: 12px;
|
||||
font-size: 13px;
|
||||
line-height: 1;
|
||||
user-select: none;
|
||||
background-color: #f5f5f5;
|
||||
color: #606266;
|
||||
line-height: 14px;
|
||||
height: 26px;
|
||||
max-width: 160px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
&.is-recognized {
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
60
resources/assets/js/store/actions.js
vendored
60
resources/assets/js/store/actions.js
vendored
@ -714,6 +714,64 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取会员扩展信息
|
||||
* @param state
|
||||
* @param dispatch
|
||||
* @param userid
|
||||
* @returns {Promise<unknown>}
|
||||
*/
|
||||
getUserExtra({state, dispatch}, userid) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
if (!userid) {
|
||||
reject({msg: "userid missing"});
|
||||
return;
|
||||
}
|
||||
const cacheMap = state.cacheUserExtra || {};
|
||||
const cacheItem = cacheMap[`${userid}`];
|
||||
const now = Date.now();
|
||||
if (cacheItem && cacheItem.data && (now - cacheItem.updatedAt) < 30000) {
|
||||
resolve(cacheItem.data);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const {data} = await dispatch("call", {
|
||||
url: 'users/extra',
|
||||
data: {userid},
|
||||
});
|
||||
state.cacheUserExtra = Object.assign({}, cacheMap, {
|
||||
[`${userid}`]: {
|
||||
data,
|
||||
updatedAt: Date.now()
|
||||
}
|
||||
});
|
||||
resolve(data);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 缓存会员扩展信息
|
||||
* @param state
|
||||
* @param payload {userid, data}
|
||||
*/
|
||||
saveUserExtra({state}, payload) {
|
||||
const userid = $A.runNum(payload?.userid);
|
||||
if (!userid || !$A.isJson(payload?.data)) {
|
||||
return;
|
||||
}
|
||||
const cacheMap = state.cacheUserExtra || {};
|
||||
const current = cacheMap[`${userid}`]?.data || {};
|
||||
state.cacheUserExtra = Object.assign({}, cacheMap, {
|
||||
[`${userid}`]: {
|
||||
data: Object.assign({}, current, payload.data),
|
||||
updatedAt: Date.now()
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 更新会员信息
|
||||
* @param state
|
||||
@ -856,7 +914,7 @@ export default {
|
||||
} catch (_) {}
|
||||
}
|
||||
if (tempUser) {
|
||||
resolve(tempUser);
|
||||
resolve($A.cloneJSON(tempUser));
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
|
||||
1
resources/assets/js/store/state.js
vendored
1
resources/assets/js/store/state.js
vendored
@ -90,6 +90,7 @@ export default {
|
||||
// User
|
||||
cacheUserWait: [],
|
||||
cacheUserBasic: [],
|
||||
cacheUserExtra: {},
|
||||
|
||||
// 日历
|
||||
cacheCalendarView: null,
|
||||
|
||||
@ -163,7 +163,6 @@
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
.recognition-total {
|
||||
padding-left: 8px;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user