mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-30 15:50:26 +00:00
feat: 扩展收藏功能,支持消息类型的收藏
- 在 UserFavorite 模型中添加消息类型常量 - 更新 UsersController,支持消息的收藏、切换和状态检查 - 修改前端 Vue 组件以实现消息的收藏操作和状态显示 - 优化收藏管理界面,支持消息类型的展示与处理
This commit is contained in:
parent
18a922b5cd
commit
73ca4b1ea5
@ -2835,7 +2835,7 @@ class UsersController extends AbstractController
|
||||
* @apiGroup users
|
||||
* @apiName favorites
|
||||
*
|
||||
* @apiParam {String} [type] 收藏类型过滤 (task/project/file)
|
||||
* @apiParam {String} [type] 收藏类型过滤 (task/project/file/message)
|
||||
* @apiParam {Number} [page=1] 页码
|
||||
* @apiParam {Number} [pagesize=20] 每页数量
|
||||
*
|
||||
@ -2852,7 +2852,7 @@ class UsersController extends AbstractController
|
||||
$pageSize = min(intval(Request::input('pagesize', 20)), 100);
|
||||
//
|
||||
// 验证收藏类型
|
||||
$allowedTypes = [UserFavorite::TYPE_TASK, UserFavorite::TYPE_PROJECT, UserFavorite::TYPE_FILE];
|
||||
$allowedTypes = [UserFavorite::TYPE_TASK, UserFavorite::TYPE_PROJECT, UserFavorite::TYPE_FILE, UserFavorite::TYPE_MESSAGE];
|
||||
if ($type && !in_array($type, $allowedTypes)) {
|
||||
return Base::retError('无效的收藏类型');
|
||||
}
|
||||
@ -2870,7 +2870,7 @@ class UsersController extends AbstractController
|
||||
* @apiGroup users
|
||||
* @apiName favorite__toggle
|
||||
*
|
||||
* @apiParam {String} type 收藏类型 (task/project/file)
|
||||
* @apiParam {String} type 收藏类型 (task/project/file/message)
|
||||
* @apiParam {Number} id 收藏对象ID
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
@ -2889,7 +2889,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
//
|
||||
// 验证收藏类型
|
||||
$allowedTypes = [UserFavorite::TYPE_TASK, UserFavorite::TYPE_PROJECT, UserFavorite::TYPE_FILE];
|
||||
$allowedTypes = [UserFavorite::TYPE_TASK, UserFavorite::TYPE_PROJECT, UserFavorite::TYPE_FILE, UserFavorite::TYPE_MESSAGE];
|
||||
if (!in_array($type, $allowedTypes)) {
|
||||
return Base::retError('无效的收藏类型');
|
||||
}
|
||||
@ -2914,6 +2914,12 @@ class UsersController extends AbstractController
|
||||
return Base::retError('文件不存在');
|
||||
}
|
||||
break;
|
||||
case UserFavorite::TYPE_MESSAGE:
|
||||
$object = WebSocketDialogMsg::whereId($id)->first();
|
||||
if (!$object) {
|
||||
return Base::retError('消息不存在');
|
||||
}
|
||||
break;
|
||||
}
|
||||
//
|
||||
$result = UserFavorite::toggleFavorite($user->userid, $type, $id);
|
||||
@ -2930,7 +2936,7 @@ class UsersController extends AbstractController
|
||||
* @apiGroup users
|
||||
* @apiName favorites__clean
|
||||
*
|
||||
* @apiParam {String} [type] 收藏类型 (task/project/file),不传则清理全部
|
||||
* @apiParam {String} [type] 收藏类型 (task/project/file/message),不传则清理全部
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
@ -2944,7 +2950,7 @@ class UsersController extends AbstractController
|
||||
//
|
||||
// 验证收藏类型
|
||||
if ($type) {
|
||||
$allowedTypes = [UserFavorite::TYPE_TASK, UserFavorite::TYPE_PROJECT, UserFavorite::TYPE_FILE];
|
||||
$allowedTypes = [UserFavorite::TYPE_TASK, UserFavorite::TYPE_PROJECT, UserFavorite::TYPE_FILE, UserFavorite::TYPE_MESSAGE];
|
||||
if (!in_array($type, $allowedTypes)) {
|
||||
return Base::retError('无效的收藏类型');
|
||||
}
|
||||
@ -2964,7 +2970,7 @@ class UsersController extends AbstractController
|
||||
* @apiGroup users
|
||||
* @apiName favorite__check
|
||||
*
|
||||
* @apiParam {String} type 收藏类型 (task/project/file)
|
||||
* @apiParam {String} type 收藏类型 (task/project/file/message)
|
||||
* @apiParam {Number} id 收藏对象ID
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
@ -2983,7 +2989,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
//
|
||||
// 验证收藏类型
|
||||
$allowedTypes = [UserFavorite::TYPE_TASK, UserFavorite::TYPE_PROJECT, UserFavorite::TYPE_FILE];
|
||||
$allowedTypes = [UserFavorite::TYPE_TASK, UserFavorite::TYPE_PROJECT, UserFavorite::TYPE_FILE, UserFavorite::TYPE_MESSAGE];
|
||||
if (!in_array($type, $allowedTypes)) {
|
||||
return Base::retError('无效的收藏类型');
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@ class UserFavorite extends AbstractModel
|
||||
const TYPE_TASK = 'task';
|
||||
const TYPE_PROJECT = 'project';
|
||||
const TYPE_FILE = 'file';
|
||||
const TYPE_MESSAGE = 'message';
|
||||
|
||||
protected $fillable = [
|
||||
'userid',
|
||||
@ -126,13 +127,15 @@ class UserFavorite extends AbstractModel
|
||||
$data = [
|
||||
'tasks' => [],
|
||||
'projects' => [],
|
||||
'files' => []
|
||||
'files' => [],
|
||||
'messages' => []
|
||||
];
|
||||
|
||||
// 分组收集ID
|
||||
$taskIds = [];
|
||||
$projectIds = [];
|
||||
$fileIds = [];
|
||||
$messageIds = [];
|
||||
|
||||
foreach ($favorites->items() as $favorite) {
|
||||
switch ($favorite->favoritable_type) {
|
||||
@ -145,6 +148,9 @@ class UserFavorite extends AbstractModel
|
||||
case self::TYPE_FILE:
|
||||
$fileIds[] = $favorite->favoritable_id;
|
||||
break;
|
||||
case self::TYPE_MESSAGE:
|
||||
$messageIds[] = $favorite->favoritable_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,6 +236,38 @@ class UserFavorite extends AbstractModel
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($messageIds)) {
|
||||
$messages = WebSocketDialogMsg::select([
|
||||
'id', 'dialog_id', 'userid', 'type', 'msg', 'created_at'
|
||||
])->whereIn('id', $messageIds)->get()->keyBy('id');
|
||||
|
||||
foreach ($favorites->items() as $favorite) {
|
||||
if ($favorite->favoritable_type === self::TYPE_MESSAGE && isset($messages[$favorite->favoritable_id])) {
|
||||
$message = $messages[$favorite->favoritable_id];
|
||||
|
||||
// 使用 previewTextMsg 获取消息预览文本
|
||||
$previewText = '';
|
||||
if ($message->msg && is_array($message->msg)) {
|
||||
$previewText = WebSocketDialogMsg::previewTextMsg($message->msg);
|
||||
}
|
||||
|
||||
// 如果没有预览文本,使用消息类型作为标题
|
||||
if (empty($previewText)) {
|
||||
$previewText = '[' . ucfirst($message->type) . ']';
|
||||
}
|
||||
|
||||
$data['messages'][] = [
|
||||
'id' => $message->id,
|
||||
'name' => $previewText,
|
||||
'dialog_id' => $message->dialog_id,
|
||||
'userid' => $message->userid,
|
||||
'type' => $message->type,
|
||||
'favorited_at' => Carbon::parse($favorite->created_at)->format('Y-m-d H:i:s'),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'data' => $data,
|
||||
'total' => $favorites->total(),
|
||||
|
||||
@ -376,6 +376,10 @@
|
||||
<i class="taskfont"></i>
|
||||
<span>{{ $L(operateItem.tag ? '取消标注' : '标注') }}</span>
|
||||
</li>
|
||||
<li @click="onOperate('favorite')">
|
||||
<i class="taskfont">{{ operateItem.favorited ? '' : '' }}</i>
|
||||
<span>{{ $L(operateItem.favorited ? '取消收藏' : '收藏') }}</span>
|
||||
</li>
|
||||
<li v-if="actionPermission(operateItem, 'newTask')" @click="onOperate('newTask')">
|
||||
<i class="taskfont"></i>
|
||||
<span>{{ $L('新任务') }}</span>
|
||||
@ -3135,6 +3139,9 @@ export default {
|
||||
})
|
||||
}
|
||||
}
|
||||
if (this.operateVisible) {
|
||||
this.checkMessageFavoriteStatus(this.operateItem);
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
this.operateItem.clientX = event.clientX
|
||||
this.operateItem.clientY = event.clientY
|
||||
@ -3286,6 +3293,10 @@ export default {
|
||||
this.onTag()
|
||||
break;
|
||||
|
||||
case "favorite":
|
||||
this.onFavorite()
|
||||
break;
|
||||
|
||||
case "newTask":
|
||||
let content = $A.formatMsgBasic(this.operateItem.msg.text)
|
||||
content = content.replace(/<img[^>]*?src=(["'])([^"']+?)(_thumb\.(png|jpg|jpeg))?\1[^>]*?>/g, `<img src="$2">`)
|
||||
@ -4064,6 +4075,47 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
onFavorite() {
|
||||
if (this.operateVisible) {
|
||||
return
|
||||
}
|
||||
|
||||
this.$store.dispatch("toggleFavorite", {
|
||||
type: 'message',
|
||||
id: this.operateItem.id
|
||||
}).then(({data, msg}) => {
|
||||
this.$set(this.operateItem, 'favorited', data.favorited);
|
||||
const message = this.dialogMsgs.find(msg => msg.id === this.operateItem.id);
|
||||
if (message) {
|
||||
this.$set(message, 'favorited', data.favorited);
|
||||
}
|
||||
this.$Message.success(msg);
|
||||
}).catch(({msg}) => {
|
||||
$A.messageError(msg);
|
||||
});
|
||||
},
|
||||
|
||||
checkMessageFavoriteStatus(message) {
|
||||
if (!message.id) return;
|
||||
|
||||
this.$store.dispatch("checkFavoriteStatus", {
|
||||
type: 'message',
|
||||
id: message.id
|
||||
}).then(({data}) => {
|
||||
this.$set(this.operateItem, 'favorited', data.favorited || false);
|
||||
const msgInList = this.dialogMsgs.find(msg => msg.id === message.id);
|
||||
if (msgInList) {
|
||||
this.$set(msgInList, 'favorited', data.favorited || false);
|
||||
}
|
||||
}).catch(() => {
|
||||
this.$set(this.operateItem, 'favorited', false);
|
||||
const msgInList = this.dialogMsgs.find(msg => msg.id === message.id);
|
||||
if (msgInList) {
|
||||
this.$set(msgInList, 'favorited', false);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onTypeChange(val) {
|
||||
if (val === 'user') {
|
||||
if (this.todoSettingData.userids.length === 0 && this.todoSettingData.quick_value.length > 0) {
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
<Option value="task">{{$L('任务')}}</Option>
|
||||
<Option value="project">{{$L('项目')}}</Option>
|
||||
<Option value="file">{{$L('文件')}}</Option>
|
||||
<Option value="message">{{$L('消息')}}</Option>
|
||||
</Select>
|
||||
</div>
|
||||
</li>
|
||||
@ -85,16 +86,19 @@ export default {
|
||||
const typeMap = {
|
||||
'task': this.$L('任务'),
|
||||
'project': this.$L('项目'),
|
||||
'file': this.$L('文件')
|
||||
'file': this.$L('文件'),
|
||||
'message': this.$L('消息')
|
||||
};
|
||||
const color = {
|
||||
'task': 'primary',
|
||||
'project': 'success',
|
||||
'file': 'warning'
|
||||
'task': 'success',
|
||||
'project': '#f87cbd',
|
||||
'file': 'warning',
|
||||
'message': 'primary'
|
||||
};
|
||||
return h('Tag', {
|
||||
class: 'favorite-type-tag',
|
||||
props: {
|
||||
color: color[row.type] || 'default'
|
||||
color: color[row.type] || 'primary'
|
||||
}
|
||||
}, typeMap[row.type] || row.type);
|
||||
}
|
||||
@ -288,6 +292,21 @@ export default {
|
||||
});
|
||||
}
|
||||
|
||||
// 处理消息收藏
|
||||
if (data.data.messages) {
|
||||
data.data.messages.forEach(message => {
|
||||
this.allData.push({
|
||||
id: message.id,
|
||||
type: 'message',
|
||||
name: message.name,
|
||||
dialog_id: message.dialog_id,
|
||||
userid: message.userid,
|
||||
msg_type: message.type,
|
||||
favorited_at: message.favorited_at,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.total = data.total || this.allData.length;
|
||||
this.filterData();
|
||||
this.noText = '没有相关的收藏';
|
||||
@ -349,6 +368,16 @@ export default {
|
||||
}, 600);
|
||||
this.$emit('on-close');
|
||||
break;
|
||||
case 'message':
|
||||
this.$store.dispatch("openDialog", item.dialog_id).then(() => {
|
||||
this.$store.state.dialogSearchMsgId = item.id;
|
||||
if (this.$route.name === 'manage-messenger') {
|
||||
this.$emit('on-close');
|
||||
}
|
||||
}).catch(({msg}) => {
|
||||
$A.modalError(msg || this.$L('打开会话失败'));
|
||||
});
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
6
resources/assets/js/store/actions.js
vendored
6
resources/assets/js/store/actions.js
vendored
@ -2851,7 +2851,7 @@ export default {
|
||||
/**
|
||||
* 检查收藏状态
|
||||
* @param dispatch
|
||||
* @param {object} params {type: 'task|project|file', id: number}
|
||||
* @param {object} params {type: 'task|project|file|message', id: number}
|
||||
*/
|
||||
checkFavoriteStatus({dispatch}, {type, id}) {
|
||||
return dispatch('call', {
|
||||
@ -2868,7 +2868,7 @@ export default {
|
||||
/**
|
||||
* 切换收藏状态
|
||||
* @param dispatch
|
||||
* @param {object} params {type: 'task|project|file', id: number}
|
||||
* @param {object} params {type: 'task|project|file|message', id: number}
|
||||
*/
|
||||
toggleFavorite({dispatch}, {type, id}) {
|
||||
return dispatch('call', {
|
||||
@ -2884,7 +2884,7 @@ export default {
|
||||
/**
|
||||
* 批量检查收藏状态
|
||||
* @param dispatch
|
||||
* @param {object} params {type: 'task|project|file', items: array}
|
||||
* @param {object} params {type: 'task|project|file|message', items: array}
|
||||
*/
|
||||
checkFavoritesStatus({dispatch}, {type, items}) {
|
||||
if (!Array.isArray(items) || items.length === 0) {
|
||||
|
||||
7
resources/assets/sass/dark.scss
vendored
7
resources/assets/sass/dark.scss
vendored
@ -758,4 +758,11 @@ body.dark-mode-reverse {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.favorite-type-tag {
|
||||
.ivu-tag-text {
|
||||
-webkit-filter: invert(100%);
|
||||
filter: invert(100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user