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. 获取消息阅读情况
*

View File

@ -41,7 +41,7 @@ class SystemController extends AbstractController
* @apiParam {String} type
* - get: 获取(默认)
* - 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 {String} msg 返回信息(错误描述)
@ -65,6 +65,7 @@ class SystemController extends AbstractController
'password_policy',
'project_invite',
'chat_information',
'anon_message',
'auto_archived',
'archived_day',
'all_group_mute',
@ -101,6 +102,7 @@ class SystemController extends AbstractController
$setting['password_policy'] = $setting['password_policy'] ?: 'simple';
$setting['project_invite'] = $setting['project_invite'] ?: 'open';
$setting['chat_information'] = $setting['chat_information'] ?: 'optional';
$setting['anon_message'] = $setting['anon_message'] ?: 'open';
$setting['auto_archived'] = $setting['auto_archived'] ?: 'close';
$setting['archived_day'] = floatval($setting['archived_day']) ?: 7;
$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/sendanon/',
// 保存文件内容
'api/file/content/save/',

View File

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

View File

@ -80,10 +80,6 @@
<i class="taskfont">&#xe7c1;</i>
{{$L('新会议')}}
</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')">
<i class="taskfont">&#xe7bc;</i>
{{$L('发送图片')}}
@ -92,6 +88,16 @@
<i class="taskfont">&#xe7c0;</i>
{{$L('上传文件')}}
</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>
</li>
@ -994,9 +1000,10 @@ export default {
});
break;
case 'call':
case 'image':
case 'file':
case 'call':
case 'anon':
this.$emit('on-more', action)
break;
}

View File

@ -1434,14 +1434,17 @@ export default {
onEventMore(e) {
switch (e) {
case 'call':
this.onCallTel()
break;
case 'image':
case 'file':
this.$refs.chatUpload.handleClick()
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) {
if (val && this.windowSmall) {
this.onToBottom();

View File

@ -1,116 +1,136 @@
<template>
<div class="setting-component-item">
<Form ref="formDatum" :model="formDatum" label-width="auto" @submit.native.prevent>
<FormItem :label="$L('允许注册')" prop="reg">
<RadioGroup v-model="formDatum.reg">
<Radio label="open">{{$L('允许')}}</Radio>
<Radio label="invite">{{$L('邀请码')}}</Radio>
<Radio label="close">{{$L('禁止')}}</Radio>
</RadioGroup>
<div v-if="formDatum.reg == 'open'" class="form-tip">{{$L('允许开放注册功能')}}</div>
<template v-else-if="formDatum.reg == 'invite'">
<div class="form-tip">{{$L('邀请码:注册时需填写下方邀请码。')}}</div>
<Input v-model="formDatum.reg_invite" style="width:200px;margin-top:6px">
<span slot="prepend">{{$L('邀请码')}}</span>
</Input>
</template>
</FormItem>
<FormItem v-if="['open', 'invite'].includes(formDatum.reg)" :label="$L('注册身份')" prop="reg_identity">
<RadioGroup v-model="formDatum.reg_identity">
<Radio label="normal">{{$L('正常帐号')}}</Radio>
<Radio label="temp">{{$L('临时帐号')}}</Radio>
</RadioGroup>
<div class="form-tip form-list">
<p>{{$L('临时帐号')}}</p>
<ol>
<li>{{$L('禁止查看共享所有人的文件。')}}</li>
<li>{{$L('禁止发起会话。')}}</li>
<li>{{$L('禁止创建群聊。')}}</li>
<li>{{$L('禁止拨打电话。')}}</li>
</ol>
</div>
</FormItem>
<FormItem :label="$L('登录验证码')" prop="loginCode">
<RadioGroup v-model="formDatum.login_code">
<Radio label="auto">{{$L('自动')}}</Radio>
<Radio label="open">{{$L('开启')}}</Radio>
<Radio label="close">{{$L('关闭')}}</Radio>
</RadioGroup>
<div v-if="formDatum.login_code == 'auto'" class="form-tip">{{$L('自动密码输入错误后必须添加验证码')}}</div>
<div v-else-if="formDatum.login_code == 'open'" class="form-tip">{{$L('开启:每次登录都需要图形验证码。')}}</div>
<div v-else-if="formDatum.login_code == 'close'" class="form-tip">{{$L('关闭:不需要输入图形验证。')}}</div>
</FormItem>
<FormItem :label="$L('密码策略')" prop="passwordPolicy">
<RadioGroup v-model="formDatum.password_policy">
<Radio label="simple">{{$L('简单')}}</Radio>
<Radio label="complex">{{$L('复杂')}}</Radio>
</RadioGroup>
<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>
</FormItem>
<FormItem :label="$L('邀请项目')" prop="projectInvite">
<RadioGroup v-model="formDatum.project_invite">
<Radio label="open">{{$L('开启')}}</Radio>
<Radio label="close">{{$L('关闭')}}</Radio>
</RadioGroup>
<div v-if="formDatum.project_invite == 'open'" class="form-tip">{{$L('开启项目管理员可生成链接邀请成员加入项目')}}</div>
</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">
<RadioGroup :value="formDatum.auto_archived" @on-change="formArchived">
<Radio label="open">{{$L('开启')}}</Radio>
<Radio label="close">{{$L('关闭')}}</Radio>
</RadioGroup>
<div class="form-tip">{{$L('任务完成后自动归档。')}}</div>
<ETooltip v-if="formDatum.auto_archived=='open'" placement="right" :disabled="windowSmall || $isEEUiApp">
<div class="setting-auto-day">
<Input v-model="formDatum.archived_day" type="number">
<span slot="append">{{$L('天')}}</span>
<div class="block-setting-box">
<h3>{{ $L('帐号相关') }}</h3>
<FormItem :label="$L('允许注册')" prop="reg">
<RadioGroup v-model="formDatum.reg">
<Radio label="open">{{$L('允许')}}</Radio>
<Radio label="invite">{{$L('邀请码')}}</Radio>
<Radio label="close">{{$L('禁止')}}</Radio>
</RadioGroup>
<div v-if="formDatum.reg == 'open'" class="form-tip">{{$L('允许开放注册功能')}}</div>
<template v-else-if="formDatum.reg == 'invite'">
<div class="form-tip">{{$L('邀请码:注册时需填写下方邀请码。')}}</div>
<Input v-model="formDatum.reg_invite" style="width:200px;margin-top:6px">
<span slot="prepend">{{$L('邀请码')}}</span>
</Input>
</template>
</FormItem>
<FormItem v-if="['open', 'invite'].includes(formDatum.reg)" :label="$L('注册身份')" prop="reg_identity">
<RadioGroup v-model="formDatum.reg_identity">
<Radio label="normal">{{$L('正常帐号')}}</Radio>
<Radio label="temp">{{$L('临时帐号')}}</Radio>
</RadioGroup>
<div class="form-tip form-list">
<p>{{$L('临时帐号')}}</p>
<ol>
<li>{{$L('禁止查看共享所有人的文件。')}}</li>
<li>{{$L('禁止发起会话。')}}</li>
<li>{{$L('禁止创建群聊。')}}</li>
<li>{{$L('禁止拨打电话。')}}</li>
</ol>
</div>
<div slot="content">{{$L('任务完成 (*) 天后自动归档。', formDatum.archived_day)}}</div>
</ETooltip>
</FormItem>
<FormItem :label="$L('全员群组禁言')" prop="allGroupMute">
<RadioGroup v-model="formDatum.all_group_mute">
<Radio label="open">{{$L('开放')}}</Radio>
<Radio label="user">{{$L('成员禁言')}}</Radio>
<Radio label="all">{{$L('全部禁言')}}</Radio>
</RadioGroup>
<div v-if="formDatum.all_group_mute == 'open'" class="form-tip">{{$L('开放所有人都可以发言')}}</div>
<div v-else-if="formDatum.all_group_mute == 'user'" class="form-tip">{{$L('成员禁言:仅管理员可以发言。')}}</div>
<div v-else-if="formDatum.all_group_mute == 'all'" class="form-tip">{{$L('全部禁言:所有人都禁止发言。')}}</div>
</FormItem>
<FormItem :label="$L('自动进入全员群')" prop="allGroupAutoin">
<RadioGroup v-model="formDatum.all_group_autoin">
<Radio label="yes">{{$L('自动')}}</Radio>
<Radio label="no">{{$L('关闭')}}</Radio>
</RadioGroup>
<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>
</FormItem>
<FormItem :label="$L('是否启动首页')" prop="startHome">
<RadioGroup v-model="formDatum.start_home">
<Radio label="open">{{$L('开启')}}</Radio>
<Radio label="close">{{$L('关闭')}}</Radio>
</RadioGroup>
<div class="form-tip">{{$L('仅支持网页版。')}}</div>
<Input
v-if="formDatum.start_home == 'open'"
v-model="formDatum.home_footer"
type="textarea"
style="margin:8px 0 -8px"
:rows="2"
:autosize="{ minRows: 2, maxRows: 8 }"
:placeholder="$L('首页底部:首页底部网站备案号等信息')"/>
</FormItem>
</FormItem>
<FormItem :label="$L('登录验证码')" prop="loginCode">
<RadioGroup v-model="formDatum.login_code">
<Radio label="auto">{{$L('自动')}}</Radio>
<Radio label="open">{{$L('开启')}}</Radio>
<Radio label="close">{{$L('关闭')}}</Radio>
</RadioGroup>
<div v-if="formDatum.login_code == 'auto'" class="form-tip">{{$L('自动密码输入错误后必须添加验证码')}}</div>
<div v-else-if="formDatum.login_code == 'open'" class="form-tip">{{$L('开启:每次登录都需要图形验证码。')}}</div>
<div v-else-if="formDatum.login_code == 'close'" class="form-tip">{{$L('关闭:不需要输入图形验证。')}}</div>
</FormItem>
<FormItem :label="$L('密码策略')" prop="passwordPolicy">
<RadioGroup v-model="formDatum.password_policy">
<Radio label="simple">{{$L('简单')}}</Radio>
<Radio label="complex">{{$L('复杂')}}</Radio>
</RadioGroup>
<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>
</FormItem>
</div>
<div class="block-setting-box">
<h3>{{ $L('项目相关') }}</h3>
<FormItem :label="$L('邀请项目')" prop="projectInvite">
<RadioGroup v-model="formDatum.project_invite">
<Radio label="open">{{$L('开启')}}</Radio>
<Radio label="close">{{$L('关闭')}}</Radio>
</RadioGroup>
<div v-if="formDatum.project_invite == 'open'" class="form-tip">{{$L('开启项目管理员可生成链接邀请成员加入项目')}}</div>
</FormItem>
<FormItem :label="$L('自动归档任务')" prop="autoArchived">
<RadioGroup :value="formDatum.auto_archived" @on-change="formArchived">
<Radio label="open">{{$L('开启')}}</Radio>
<Radio label="close">{{$L('关闭')}}</Radio>
</RadioGroup>
<div class="form-tip">{{$L('任务完成后自动归档。')}}</div>
<ETooltip v-if="formDatum.auto_archived=='open'" placement="right" :disabled="windowSmall || $isEEUiApp">
<div class="setting-auto-day">
<Input v-model="formDatum.archived_day" type="number">
<span slot="append">{{$L('天')}}</span>
</Input>
</div>
<div slot="content">{{$L('任务完成 (*) 天后自动归档。', formDatum.archived_day)}}</div>
</ETooltip>
</FormItem>
</div>
<div class="block-setting-box">
<h3>{{ $L('消息相关') }}</h3>
<FormItem :label="$L('全员群组禁言')" prop="allGroupMute">
<RadioGroup v-model="formDatum.all_group_mute">
<Radio label="open">{{$L('开放')}}</Radio>
<Radio label="user">{{$L('成员禁言')}}</Radio>
<Radio label="all">{{$L('全部禁言')}}</Radio>
</RadioGroup>
<div v-if="formDatum.all_group_mute == 'open'" class="form-tip">{{$L('开放所有人都可以发言')}}</div>
<div v-else-if="formDatum.all_group_mute == 'user'" class="form-tip">{{$L('成员禁言:仅管理员可以发言。')}}</div>
<div v-else-if="formDatum.all_group_mute == 'all'" class="form-tip">{{$L('全部禁言:所有人都禁止发言。')}}</div>
</FormItem>
<FormItem :label="$L('自动进入全员群')" prop="allGroupAutoin">
<RadioGroup v-model="formDatum.all_group_autoin">
<Radio label="yes">{{$L('自动')}}</Radio>
<Radio label="no">{{$L('关闭')}}</Radio>
</RadioGroup>
<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>
</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">
<RadioGroup v-model="formDatum.start_home">
<Radio label="open">{{$L('开启')}}</Radio>
<Radio label="close">{{$L('关闭')}}</Radio>
</RadioGroup>
<div class="form-tip">{{$L('仅支持网页版。')}}</div>
<Input
v-if="formDatum.start_home == 'open'"
v-model="formDatum.home_footer"
type="textarea"
style="margin:8px 0 -8px"
:rows="2"
:autosize="{ minRows: 2, maxRows: 8 }"
:placeholder="$L('首页底部:首页底部网站备案号等信息')"/>
</FormItem>
</div>
</Form>
<div class="setting-footer">
<Button :loading="loadIng > 0" type="primary" @click="submitForm">{{$L('提交')}}</Button>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB