feat: 支持发送匿名消息

This commit is contained in:
kuaifan 2023-03-05 18:18:57 +08:00
parent 5d5b1000fe
commit aa781a51df
8 changed files with 279 additions and 134 deletions

View File

@ -909,6 +909,59 @@ class DialogController extends AbstractController
}); });
} }
/**
* @api {post} api/dialog/msg/sendanon 16. 发送匿名消息
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup dialog
* @apiName msg__sendanon
*
* @apiParam {Number} userid 对方会员ID
* @apiParam {String} text 消息内容
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function msg__sendanon()
{
User::auth();
//
$userid = Base::getPostInt('userid');
$text = trim(Base::getPostValue('text'));
//
$anonMessage = Base::settingFind('system', 'anon_message', 'open');
if ($anonMessage != 'open') {
return Base::retError("匿名消息功能暂停使用");
}
//
$toUser = User::whereUserid($userid)->first();
if (empty($toUser) || $toUser->bot) {
return Base::retError("匿名消息仅允许发送给个人");
}
if ($toUser->isDisable()) {
return Base::retError("对方已离职");
}
$strlen = mb_strlen($text);
if ($strlen < 1) {
return Base::retError('消息内容不能为空');
}
if ($strlen > 2000) {
return Base::retError('消息内容最大不能超过2000字');
}
//
$botUser = User::botGetOrCreate('anon-msg');
if (empty($botUser)) {
return Base::retError('匿名机器人不存在');
}
$dialog = WebSocketDialog::checkUserDialog($botUser, $toUser->userid);
if (empty($dialog)) {
return Base::retError('匿名机器人会话不存在');
}
return WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => "<p>{$text}</p>"], $botUser->userid);
}
/** /**
* @api {get} api/dialog/msg/readlist 17. 获取消息阅读情况 * @api {get} api/dialog/msg/readlist 17. 获取消息阅读情况
* *

View File

@ -41,7 +41,7 @@ class SystemController extends AbstractController
* @apiParam {String} type * @apiParam {String} type
* - get: 获取(默认) * - get: 获取(默认)
* - all: 获取所有(需要管理员权限) * - all: 获取所有(需要管理员权限)
* - save: 保存设置(参数:['reg', 'reg_identity', 'reg_invite', 'login_code', 'password_policy', 'project_invite', 'chat_information', 'auto_archived', 'archived_day', 'all_group_mute', 'all_group_autoin', 'start_home', 'home_footer'] * - save: 保存设置(参数:['reg', 'reg_identity', 'reg_invite', 'login_code', 'password_policy', 'project_invite', 'chat_information', 'anon_message', 'auto_archived', 'archived_day', 'all_group_mute', 'all_group_autoin', 'start_home', 'home_footer']
* @apiSuccess {Number} ret 返回状态码1正确、0错误 * @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述) * @apiSuccess {String} msg 返回信息(错误描述)
@ -65,6 +65,7 @@ class SystemController extends AbstractController
'password_policy', 'password_policy',
'project_invite', 'project_invite',
'chat_information', 'chat_information',
'anon_message',
'auto_archived', 'auto_archived',
'archived_day', 'archived_day',
'all_group_mute', 'all_group_mute',
@ -101,6 +102,7 @@ class SystemController extends AbstractController
$setting['password_policy'] = $setting['password_policy'] ?: 'simple'; $setting['password_policy'] = $setting['password_policy'] ?: 'simple';
$setting['project_invite'] = $setting['project_invite'] ?: 'open'; $setting['project_invite'] = $setting['project_invite'] ?: 'open';
$setting['chat_information'] = $setting['chat_information'] ?: 'optional'; $setting['chat_information'] = $setting['chat_information'] ?: 'optional';
$setting['anon_message'] = $setting['anon_message'] ?: 'open';
$setting['auto_archived'] = $setting['auto_archived'] ?: 'close'; $setting['auto_archived'] = $setting['auto_archived'] ?: 'close';
$setting['archived_day'] = floatval($setting['archived_day']) ?: 7; $setting['archived_day'] = floatval($setting['archived_day']) ?: 7;
$setting['all_group_mute'] = $setting['all_group_mute'] ?: 'open'; $setting['all_group_mute'] = $setting['all_group_mute'] ?: 'open';

View File

@ -42,6 +42,9 @@ class VerifyCsrfToken extends Middleware
// 聊天发文件 // 聊天发文件
'api/dialog/msg/sendfile/', 'api/dialog/msg/sendfile/',
// 聊天发匿名消息
'api/dialog/msg/sendanon/',
// 保存文件内容 // 保存文件内容
'api/file/content/save/', 'api/file/content/save/',

View File

@ -179,6 +179,15 @@ class User extends AbstractModel
return in_array('temp', $this->identity); return in_array('temp', $this->identity);
} }
/**
* 返回是否禁用帐号(离职)
* @return bool
*/
public function isDisable()
{
return in_array('disable', $this->identity);
}
/** /**
* 返回是否管理员 * 返回是否管理员
* @return bool * @return bool
@ -575,13 +584,16 @@ class User extends AbstractModel
return Base::fillUrl($userimg); return Base::fillUrl($userimg);
} }
// 机器人头像 // 机器人头像
if ($email == 'system-msg@bot.system') { switch ($email) {
case 'system-msg@bot.system':
return url("images/avatar/default_system.png"); return url("images/avatar/default_system.png");
} elseif ($email == 'task-alert@bot.system') { case 'task-alert@bot.system':
return url("images/avatar/default_task.png"); return url("images/avatar/default_task.png");
} elseif ($email == 'check-in@bot.system') { case 'check-in@bot.system':
return url("images/avatar/default_checkin.png"); return url("images/avatar/default_checkin.png");
} elseif ($email == 'bot-manager@bot.system') { case 'anon-msg@bot.system':
return url("images/avatar/default_anon.png");
case 'bot-manager@bot.system':
return url("images/avatar/default_bot.png"); return url("images/avatar/default_bot.png");
} }
// 生成文字头像 // 生成文字头像
@ -652,14 +664,22 @@ class User extends AbstractModel
])->save(); ])->save();
} }
// //
if ($key === 'system-msg') { switch ($key) {
case 'system-msg':
$update['nickname'] = '系统消息'; $update['nickname'] = '系统消息';
} elseif ($key === 'task-alert') { break;
case 'task-alert':
$update['nickname'] = '任务提醒'; $update['nickname'] = '任务提醒';
} elseif ($key === 'check-in') { break;
case 'check-in':
$update['nickname'] = '签到打卡'; $update['nickname'] = '签到打卡';
} elseif ($key === 'bot-manager') { break;
case 'anon-msg':
$update['nickname'] = '匿名消息';
break;
case 'bot-manager':
$update['nickname'] = '机器人管理'; $update['nickname'] = '机器人管理';
break;
} }
} }
if ($update) { if ($update) {

View File

@ -80,10 +80,6 @@
<i class="taskfont">&#xe7c1;</i> <i class="taskfont">&#xe7c1;</i>
{{$L('新会议')}} {{$L('新会议')}}
</div> </div>
<div v-if="dialogData.type === 'user' && $isEEUiApp" class="chat-input-popover-item" @click="onToolbar('call')">
<i class="taskfont">&#xe7ba;</i>
{{$L('拨打电话')}}
</div>
<div class="chat-input-popover-item" @click="onToolbar('image')"> <div class="chat-input-popover-item" @click="onToolbar('image')">
<i class="taskfont">&#xe7bc;</i> <i class="taskfont">&#xe7bc;</i>
{{$L('发送图片')}} {{$L('发送图片')}}
@ -92,6 +88,16 @@
<i class="taskfont">&#xe7c0;</i> <i class="taskfont">&#xe7c0;</i>
{{$L('上传文件')}} {{$L('上传文件')}}
</div> </div>
<template v-if="dialogData.type === 'user' && !dialogData.bot">
<div v-if="$isEEUiApp" class="chat-input-popover-item" @click="onToolbar('call')">
<i class="taskfont">&#xe7ba;</i>
{{$L('拨打电话')}}
</div>
<div class="chat-input-popover-item" @click="onToolbar('anon')">
<i class="taskfont">&#xe690;</i>
{{$L('匿名消息')}}
</div>
</template>
</EPopover> </EPopover>
</li> </li>
@ -994,9 +1000,10 @@ export default {
}); });
break; break;
case 'call':
case 'image': case 'image':
case 'file': case 'file':
case 'call':
case 'anon':
this.$emit('on-more', action) this.$emit('on-more', action)
break; break;
} }

View File

@ -1434,14 +1434,17 @@ export default {
onEventMore(e) { onEventMore(e) {
switch (e) { switch (e) {
case 'call':
this.onCallTel()
break;
case 'image': case 'image':
case 'file': case 'file':
this.$refs.chatUpload.handleClick() this.$refs.chatUpload.handleClick()
break; break;
case 'call':
this.onCallTel()
break;
case 'anon':
this.onAnon()
break;
} }
}, },
@ -1469,6 +1472,43 @@ export default {
}); });
}, },
onAnon() {
if (this.dialogData.type !== 'user' || this.dialogData.bot) {
$A.modalWarning("匿名消息仅允许发送给个人");
return
}
$A.modalInput({
title: `发送匿名消息`,
placeholder: `匿名消息将通过匿名机器人发送给对方,绝对不会暴露你的身份`,
inputProps: {
type: 'textarea',
rows: 3,
autosize: { minRows: 3, maxRows: 6 },
maxlength: 2000,
},
okText: "匿名发送",
onOk: (value) => {
if (!value) {
return `请输入消息内容`
}
return new Promise((resolve, reject) => {
this.$store.dispatch("call", {
url: 'dialog/msg/sendanon',
data: {
userid: this.dialogData.dialog_user.userid,
text: value,
},
method: 'post',
}).then(({msg}) => {
resolve(msg)
}).catch(({msg}) => {
reject(msg)
});
})
}
});
},
onEventEmojiVisibleChange(val) { onEventEmojiVisibleChange(val) {
if (val && this.windowSmall) { if (val && this.windowSmall) {
this.onToBottom(); this.onToBottom();

View File

@ -1,6 +1,8 @@
<template> <template>
<div class="setting-component-item"> <div class="setting-component-item">
<Form ref="formDatum" :model="formDatum" label-width="auto" @submit.native.prevent> <Form ref="formDatum" :model="formDatum" label-width="auto" @submit.native.prevent>
<div class="block-setting-box">
<h3>{{ $L('帐号相关') }}</h3>
<FormItem :label="$L('允许注册')" prop="reg"> <FormItem :label="$L('允许注册')" prop="reg">
<RadioGroup v-model="formDatum.reg"> <RadioGroup v-model="formDatum.reg">
<Radio label="open">{{$L('允许')}}</Radio> <Radio label="open">{{$L('允许')}}</Radio>
@ -48,6 +50,9 @@
<div v-if="formDatum.password_policy == 'simple'" class="form-tip">{{$L('简单大于或等于6个字符')}}</div> <div v-if="formDatum.password_policy == 'simple'" class="form-tip">{{$L('简单大于或等于6个字符')}}</div>
<div v-else-if="formDatum.password_policy == 'complex'" class="form-tip">{{$L('复杂大于或等于6个字符包含数字、字母大小写或者特殊字符。')}}</div> <div v-else-if="formDatum.password_policy == 'complex'" class="form-tip">{{$L('复杂大于或等于6个字符包含数字、字母大小写或者特殊字符。')}}</div>
</FormItem> </FormItem>
</div>
<div class="block-setting-box">
<h3>{{ $L('项目相关') }}</h3>
<FormItem :label="$L('邀请项目')" prop="projectInvite"> <FormItem :label="$L('邀请项目')" prop="projectInvite">
<RadioGroup v-model="formDatum.project_invite"> <RadioGroup v-model="formDatum.project_invite">
<Radio label="open">{{$L('开启')}}</Radio> <Radio label="open">{{$L('开启')}}</Radio>
@ -55,14 +60,6 @@
</RadioGroup> </RadioGroup>
<div v-if="formDatum.project_invite == 'open'" class="form-tip">{{$L('开启项目管理员可生成链接邀请成员加入项目')}}</div> <div v-if="formDatum.project_invite == 'open'" class="form-tip">{{$L('开启项目管理员可生成链接邀请成员加入项目')}}</div>
</FormItem> </FormItem>
<FormItem :label="$L('聊天资料')" prop="chatInformation">
<RadioGroup v-model="formDatum.chat_information">
<Radio label="optional">{{$L('可选')}}</Radio>
<Radio label="required">{{$L('必填')}}</Radio>
</RadioGroup>
<div v-if="formDatum.chat_information == 'required'" class="form-tip">{{$L('必填发送聊天内容前必须设置昵称电话')}}</div>
<div v-else class="form-tip">{{$L('如果必填,发送聊天前必须设置昵称、电话。')}}</div>
</FormItem>
<FormItem :label="$L('自动归档任务')" prop="autoArchived"> <FormItem :label="$L('自动归档任务')" prop="autoArchived">
<RadioGroup :value="formDatum.auto_archived" @on-change="formArchived"> <RadioGroup :value="formDatum.auto_archived" @on-change="formArchived">
<Radio label="open">{{$L('开启')}}</Radio> <Radio label="open">{{$L('开启')}}</Radio>
@ -78,6 +75,9 @@
<div slot="content">{{$L('任务完成 (*) 天后自动归档。', formDatum.archived_day)}}</div> <div slot="content">{{$L('任务完成 (*) 天后自动归档。', formDatum.archived_day)}}</div>
</ETooltip> </ETooltip>
</FormItem> </FormItem>
</div>
<div class="block-setting-box">
<h3>{{ $L('消息相关') }}</h3>
<FormItem :label="$L('全员群组禁言')" prop="allGroupMute"> <FormItem :label="$L('全员群组禁言')" prop="allGroupMute">
<RadioGroup v-model="formDatum.all_group_mute"> <RadioGroup v-model="formDatum.all_group_mute">
<Radio label="open">{{$L('开放')}}</Radio> <Radio label="open">{{$L('开放')}}</Radio>
@ -96,6 +96,25 @@
<div v-if="formDatum.all_group_autoin == 'yes'" class="form-tip">{{$L('自动注册成功后自动进入全员群')}}</div> <div v-if="formDatum.all_group_autoin == 'yes'" class="form-tip">{{$L('自动注册成功后自动进入全员群')}}</div>
<div v-else-if="formDatum.all_group_autoin == 'no'" class="form-tip">{{$L('关闭:其他成员通过@邀请进入。')}}</div> <div v-else-if="formDatum.all_group_autoin == 'no'" class="form-tip">{{$L('关闭:其他成员通过@邀请进入。')}}</div>
</FormItem> </FormItem>
<FormItem :label="$L('聊天资料')" prop="chatInformation">
<RadioGroup v-model="formDatum.chat_information">
<Radio label="optional">{{$L('可选')}}</Radio>
<Radio label="required">{{$L('必填')}}</Radio>
</RadioGroup>
<div v-if="formDatum.chat_information == 'required'" class="form-tip">{{$L('必填发送聊天内容前必须设置昵称电话')}}</div>
<div v-else class="form-tip">{{$L('如果必填,发送聊天前必须设置昵称、电话。')}}</div>
</FormItem>
<FormItem :label="$L('匿名消息')" prop="anonMessage">
<RadioGroup v-model="formDatum.anon_message">
<Radio label="open">{{$L('开启')}}</Radio>
<Radio label="close">{{$L('关闭')}}</Radio>
</RadioGroup>
<div v-if="formDatum.anon_message == 'open'" class="form-tip">{{$L('允许匿名发送消息给其他成员')}}</div>
<div v-else class="form-tip">{{$L('禁止匿名发送消息。')}}</div>
</FormItem>
</div>
<div class="block-setting-box">
<h3>{{ $L('其他设置') }}</h3>
<FormItem :label="$L('是否启动首页')" prop="startHome"> <FormItem :label="$L('是否启动首页')" prop="startHome">
<RadioGroup v-model="formDatum.start_home"> <RadioGroup v-model="formDatum.start_home">
<Radio label="open">{{$L('开启')}}</Radio> <Radio label="open">{{$L('开启')}}</Radio>
@ -111,6 +130,7 @@
:autosize="{ minRows: 2, maxRows: 8 }" :autosize="{ minRows: 2, maxRows: 8 }"
:placeholder="$L('首页底部:首页底部网站备案号等信息')"/> :placeholder="$L('首页底部:首页底部网站备案号等信息')"/>
</FormItem> </FormItem>
</div>
</Form> </Form>
<div class="setting-footer"> <div class="setting-footer">
<Button :loading="loadIng > 0" type="primary" @click="submitForm">{{$L('提交')}}</Button> <Button :loading="loadIng > 0" type="primary" @click="submitForm">{{$L('提交')}}</Button>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB