perf: 优化消息组件

This commit is contained in:
kuaifan 2024-10-16 14:27:30 +08:00
parent ae587950b9
commit e0a108eb2e
36 changed files with 777 additions and 338 deletions

View File

@ -262,7 +262,7 @@ class ApproveController extends AbstractController
$this->approveMsg('approve_reviewer', $dialog, $botUser, $val, $process, $pass);
}
// 发起人
if ($process['is_finished'] == true) {
if ($process['is_finished']) {
$dialog = WebSocketDialog::checkUserDialog($botUser, $process['start_user_id']);
if (!empty($dialog)) {
$this->approveMsg('approve_submitter', $dialog, $botUser, ['userid' => $data['userid']], $process, $pass);
@ -284,7 +284,7 @@ class ApproveController extends AbstractController
}
// 抄送人
$notifier = $this->handleProcessNode($process, $task['step']);
$notifier = $this->handleProcessNode($process);
if ($notifier && $pass == 'pass') {
foreach ($notifier as $val) {
$dialog = WebSocketDialog::checkUserDialog($botUser, $val['target_id']);
@ -899,7 +899,7 @@ class ApproveController extends AbstractController
3 => '拒绝',
4 => '撤回'
);
return isset($state_map[$state]) ? $state_map[$state] : '';
return $state_map[$state] ?? '';
}
/**
@ -986,21 +986,24 @@ class ApproveController extends AbstractController
'comment_content' => $process['comment_contents']['content'] ?? '',
'comment_pictures' => $process['comment_contents']['pictures'] ?? []
];
$text = view('push.bot', ['type' => $type, 'action' => $action, 'is_finished' => $process['is_finished'], 'data' => (object)$data])->render();
$text = preg_replace("/^\x20+/", "", $text);
$text = preg_replace("/\n\x20+/", "\n", $text);
$msg_action = null;
$msg_data = [
'type' => $type,
'action' => $action,
'is_finished' => $process['is_finished'],
'data' => $data
];
if ($action == 'withdraw' || $action == 'pass' || $action == 'refuse') {
// 任务完成,给发起人发送消息
if ($type == 'approve_submitter' && $action != 'withdraw') {
return WebSocketDialogMsg::sendMsg($msg_action, $dialog->id, 'text', ['text' => $text, 'approve_type' => $type], $botUser->userid, false, false, true);
return WebSocketDialogMsg::sendMsg($msg_action, $dialog->id, 'template', $msg_data, $botUser->userid, false, false, true);
}
// 查找最后一条消息msg_id
$msg_action = 'change-' . $toUser['msg_id'];
}
//
try {
$msg = WebSocketDialogMsg::sendMsg($msg_action, $dialog->id, 'text', ['text' => $text, 'approve_type' => $type], $process['start_user_id'], false, false, true);
$msg = WebSocketDialogMsg::sendMsg($msg_action, $dialog->id, 'template', $msg_data, $process['start_user_id'], false, false, true);
// 关联信息
if ($action == 'start') {
$proc_msg = new ApproveProcMsg();
@ -1022,7 +1025,7 @@ class ApproveController extends AbstractController
Task::deliver(new PushTask($params, false));
}
} catch (\Throwable $th) {
//throw $th;
info($th->getMessage());
}
return true;
}
@ -1126,7 +1129,7 @@ class ApproveController extends AbstractController
$ret = Ihttp::ihttp_get($this->flow_url . '/api/v1/workflow/process/getUserApprovalStatus?' . http_build_query($data));
$procdef = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
if (isset($procdef['status']) && $procdef['status'] == 200) {
return Base::retSuccess('success', isset($procdef['data']["proc_def_name"]) ? $procdef['data']["proc_def_name"] : '');
return Base::retSuccess('success', $procdef['data']["proc_def_name"] ?? '');
}
return Base::retSuccess('success', '');
}

View File

@ -578,7 +578,7 @@ class User extends AbstractModel
case 'ai-gemini@bot.system':
return url("images/avatar/default_gemini.png");
case 'ai-zhipu@bot.system':
return url("images/avatar/default_zhipu.png");
return url("images/avatar/default_zhipu.png");
case 'bot-manager@bot.system':
return url("images/avatar/default_bot.png");
case 'meeting-alert@bot.system':
@ -651,7 +651,9 @@ class User extends AbstractModel
])->save();
}
//
$update['nickname'] = UserBot::systemBotName($email);
if (empty($update['nickname'])) {
$update['nickname'] = UserBot::systemBotName($email);
}
}
if ($update) {
$botUser->updateInstance($update);

View File

@ -949,7 +949,7 @@ class WebSocketDialogMsg extends AbstractModel
];
}
} else {
if ($dialogMsg->type !== 'text') {
if (!in_array($dialogMsg->type, ['text', 'template'])) {
throw new ApiException('此消息不支持此操作');
}
if ($dialogMsg->userid != $sender) {

View File

@ -340,19 +340,13 @@ class BotReceiveMsgTask extends AbstractTask
break;
}
//
$text = view('push.bot', [
WebSocketDialogMsg::sendMsg(null, $msg->dialog_id, 'template', [
'type' => $type,
'data' => $data,
'notice' => $notice,
'manager' => $isManager,
'version' => Base::getVersion()
])->render();
if (!$isManager) {
$text = preg_replace("/\s*\{机器人ID\}/", "", $text);
}
$text = preg_replace("/^\x20+/", "", $text);
$text = preg_replace("/\n\x20+/", "\n", $text);
WebSocketDialogMsg::sendMsg(null, $msg->dialog_id, 'text', ['text' => $text], $botUser->userid, false, false, true); // todo 未能在任务end事件来发送任务
], $botUser->userid, false, false, true); // todo 未能在任务end事件来发送任务
}
}
@ -471,7 +465,7 @@ class BotReceiveMsgTask extends AbstractTask
&& !Base::judgeClientVersion("0.29.11", $this->client['version'])) {
$error = 'The client version is low (required version ≥ v0.29.12).';
}
break;
break;
// 其他机器人
default:
$userBot = UserBot::whereBotId($botUser->userid)->first();

View File

@ -1614,5 +1614,5 @@ License Key
返回参数错误
未知错误
网络异常
请求失败
网络异常,请重试。
请求失败,请重试。

View File

@ -333,6 +333,11 @@
<!-- okr明细 -->
<MicroApps v-show="false" v-if="$route.name != 'manage-apps'" name="okr-details" :url="okrUrl" :datas="okrWindow"/>
<!--审批详情-->
<DrawerOverlay v-model="approveDetailsShow" placement="right" :size="600">
<ApproveDetails v-if="approveDetailsShow" :data="approveDetails" @onBack="approveDetailsShow=false"/>
</DrawerOverlay>
</div>
</template>
@ -361,10 +366,13 @@ import {Store} from "le5le-store";
import {MarkdownPreview} from "../store/markdown";
import UserSelect from "../components/UserSelect.vue";
import ImgUpload from "../components/ImgUpload.vue";
import ApproveDetails from "./manage/approve/details.vue";
export default {
components: {
ImgUpload, UserSelect,
ApproveDetails,
ImgUpload,
UserSelect,
TaskExport,
CheckinExport,
ApproveExport,
@ -443,6 +451,10 @@ export default {
needStartHome: false,
complaintShow: false,
approveDetails: {id: 0},
approveDetailsShow: false,
approveDetailsSubscribe: null,
}
},
@ -452,6 +464,7 @@ export default {
this.addTaskSubscribe = Store.subscribe('addTask', this.onAddTask);
this.createGroupSubscribe = Store.subscribe('createGroup', this.onCreateGroup);
this.dialogMsgSubscribe = Store.subscribe('dialogMsgPush', this.addDialogMsg);
this.approveDetailsSubscribe = Store.subscribe('approveDetails', this.openApproveDetails);
//
document.addEventListener('keydown', this.shortcutEvent);
},
@ -482,6 +495,10 @@ export default {
this.dialogMsgSubscribe.unsubscribe();
this.dialogMsgSubscribe = null;
}
if (this.approveDetailsSubscribe) {
this.approveDetailsSubscribe.unsubscribe();
this.approveDetailsSubscribe = null;
}
//
document.removeEventListener('keydown', this.shortcutEvent);
},
@ -1135,6 +1152,13 @@ export default {
}
},
openApproveDetails(id) {
this.approveDetailsShow = true;
this.$nextTick(() => {
this.approveDetails = {id};
})
},
handleLongpress(event, el) {
const projectId = $A.getAttr(el, 'data-id')
const projectItem = this.projectLists.find(item => item.id == projectId)

View File

@ -2,7 +2,7 @@
<div class="approve-details" :style="{'z-index':modalTransferIndex}">
<!-- 导航 -->
<div class="approve-details-nav">
<div class="common-nav-back" @click="goBack()">
<div class="common-nav-back" @click="onBack">
<i class="taskfont">&#xe676;</i>
</div>
<h2>{{$L('审批详情')}}</h2>
@ -279,6 +279,10 @@ export default {
this.getInfo()
}
},
//
onBack() {
this.$emit('onBack')
},
//
getTimeAgo(time, type) {
const timeDiff = $A.dayjs().unix() - $A.dayjs(time).unix(); // convert to seconds

View File

@ -251,6 +251,7 @@ import ImgUpload from "../../../components/ImgUpload";
import ApproveSetting from "./setting";
import ApproveExport from "../components/ApproveExport";
import {mapState} from 'vuex'
import {Store} from "le5le-store";
export default {
components: {list, listDetails, DrawerOverlay, ImgUpload, ApproveSetting, ApproveExport},
@ -491,7 +492,7 @@ export default {
})
//
if (window.innerWidth < 426) {
this.goForward({name: 'manage-approve-details', query: {id: item.id}});
Store.set('approveDetails', item.id);
return;
}
if (window.innerWidth < 1010) {

View File

@ -51,6 +51,7 @@
@on-view-text="onViewText"
@on-view-file="onViewFile"
@on-down-file="onDownFile"
@on-click-template="onClickTemplate"
@on-reply-list="onReplyList"
@on-error="onError"
@on-emoji="onEmoji"
@ -252,6 +253,10 @@ export default {
this.dispatch("on-down-file", data)
},
onClickTemplate(e) {
this.dispatch("on-click-template", e)
},
onReplyList(data) {
this.dispatch("on-reply-list", data)
},

View File

@ -26,7 +26,7 @@
<!--详情-->
<div ref="content" class="dialog-content" :class="contentClass">
<!--文本-->
<TextMsg v-if="msgData.type === 'text'" :msg="msgData.msg" @click="viewText"/>
<TextMsg v-if="msgData.type === 'text'" :msg="msgData.msg" @viewText="viewText"/>
<!--文件-->
<FileMsg v-else-if="msgData.type === 'file'" :msg="msgData.msg" @viewFile="viewFile" @downFile="downFile"/>
<!--录音-->
@ -37,6 +37,8 @@
<WordChainMsg v-else-if="msgData.type === 'word-chain'" :msg="msgData.msg" :msgId="msgData.id" :unfoldWordChainData="unfoldWordChainData" @unfoldWordChain="unfoldWordChain(msgData)" @onWordChain="onWordChain"/>
<!--投票-->
<VoteMsg v-else-if="msgData.type === 'vote'" :msg="msgData.msg" :voteData="voteData" @onVote="onVote($event, msgData)"/>
<!--模板-->
<TemplateMsg v-else-if="msgData.type === 'template'" :msg="msgData.msg" @clickTemplate="clickTemplate"/>
<!--等待-->
<LoadMsg v-else-if="isLoading" :error="msgData.error"/>
<!--未知-->
@ -179,6 +181,7 @@ import RecordMsg from "./record.vue";
import MeetingMsg from "./meet.vue";
import WordChainMsg from "./word-chain.vue";
import VoteMsg from "./vote.vue";
import TemplateMsg from "./template";
import LoadMsg from "./load.vue";
import UnknownMsg from "./unknown.vue";
@ -187,6 +190,7 @@ export default {
components: {
UnknownMsg,
LoadMsg,
TemplateMsg,
VoteMsg,
WordChainMsg,
MeetingMsg,
@ -538,14 +542,6 @@ export default {
this.$emit("on-show-emoji-user", item)
},
onWordChain() {
this.$store.state.dialogDroupWordChain = {
type: 'participate',
dialog_id: this.msgData.dialog_id,
msgData: this.msgData,
}
},
unfoldWordChain(msg) {
if (this.unfoldWordChainData.indexOf(msg.id) == -1) {
const data = JSON.parse(window.localStorage.getItem('__cache:unfoldWordChain__')) || [];
@ -555,6 +551,14 @@ export default {
}
},
onWordChain() {
this.$store.state.dialogDroupWordChain = {
type: 'participate',
dialog_id: this.msgData.dialog_id,
msgData: this.msgData,
}
},
onVote(type, msgData) {
if (type != 'vote') {
$A.modalConfirm({
@ -594,6 +598,10 @@ export default {
this.$set(msgData.msg, '_loadIng', 0)
});
},
clickTemplate(e) {
this.$emit("on-click-template", e)
},
}
}
</script>

View File

@ -0,0 +1,32 @@
<template>
<div class="open-approve-details" :data-id="msg.data.id">
<b>{{ msg.data.comment_nickname }}评论了此审批</b>
<div class="cause">
<p>申请人<span class="mark-color">@{{ msg.data.nickname }}</span> {{ msg.data.department }}</p>
<b>评论内容</b>
<p>{{ msg.data.comment_content }}</p>
<p v-if="isPicture">[图片]</p>
</div>
<div class="btn-raw no-dark-content">
<button class="ivu-btn ivu-btn-grey">查看详情</button>
</div>
</div>
</template>
<script lang="ts">
export default {
props: {
msg: Object,
},
data() {
return {};
},
computed: {
isPicture() {
const {comment_pictures} = this.msg.data
return $A.isArray(comment_pictures) && comment_pictures.length > 0
},
},
methods: {},
}
</script>

View File

@ -0,0 +1,30 @@
<template>
<div class="open-approve-details" :data-id="msg.data.id">
<b>抄送{{ msg.data.nickname }}提交的{{ msg.data.proc_def_name }}记录</b>
<div class="cause">
<p>申请人<span class="mark-color">@{{ msg.data.nickname }}</span> {{ msg.data.department }}</p>
<b>详情</b>
<p v-if="msg.data.type">假期类型{{ msg.data.type }}</p>
<p>开始时间{{ msg.data.start_time }} ({{ msg.data.start_day_of_week }})</p>
<p>结束时间{{ msg.data.end_time }} ({{ msg.data.end_day_of_week }})</p>
<p>事由{{ msg.data.description }}</p>
</div>
<div class="btn-raw no-dark-content">
<button v-if="msg.is_finished" class="ivu-btn ivu-btn-grey">已同意</button>
<button v-else class="ivu-btn ivu-btn-grey">查看详情</button>
</div>
</div>
</template>
<script lang="ts">
export default {
props: {
msg: Object,
},
data() {
return {};
},
computed: {},
methods: {},
}
</script>

View File

@ -0,0 +1,35 @@
<template>
<div class="open-approve-details" :data-id="msg.data.id">
<b>{{ msg.data.nickname }}提交的{{ msg.data.proc_def_name }}待你审批</b>
<div class="cause">
<p>申请人<span class="mark-color">@{{ msg.data.nickname }}</span> {{ msg.data.department }}</p>
<b>详情</b>
<p v-if="msg.data.type">假期类型{{ msg.data.type }}</p>
<p>开始时间{{ msg.data.start_time }} ({{ msg.data.start_day_of_week }})</p>
<p>结束时间{{ msg.data.end_time }} ({{ msg.data.end_day_of_week }})</p>
<p>事由{{ msg.data.description }}</p>
</div>
<div class="btn-raw no-dark-content">
<button v-if="msg.action === 'pass'" class="ivu-btn ivu-btn-grey">已同意</button>
<button v-else-if="msg.action === 'refuse'" class="ivu-btn ivu-btn-grey">已拒绝</button>
<button v-else-if="msg.action === 'withdraw'" class="ivu-btn ivu-btn-grey">已撤销</button>
<template v-else>
<button class="ivu-btn ivu-btn-primary">同意</button>
<button class="ivu-btn ivu-btn-error">拒绝</button>
</template>
</div>
</div>
</template>
<script lang="ts">
export default {
props: {
msg: Object,
},
data() {
return {};
},
computed: {},
methods: {},
}
</script>

View File

@ -0,0 +1,35 @@
<template>
<div class="open-approve-details" :data-id="msg.data.id">
<b>{{ desc }}</b>
<div class="cause">
<p>申请人<span class="mark-color">@{{ msg.data.start_nickname }}</span> {{ msg.data.department }}</p>
<b>详情</b>
<p v-if="msg.data.type">假期类型{{ msg.data.type }}</p>
<p>开始时间{{ msg.data.start_time }} ({{ msg.data.start_day_of_week }})</p>
<p>结束时间{{ msg.data.end_time }} ({{ msg.data.end_day_of_week }})</p>
<p>事由{{ msg.data.description }}</p>
</div>
<div class="btn-raw no-dark-content">
<button v-if="msg.action === 'pass'" class="ivu-btn ivu-btn-grey">已同意</button>
<button v-else-if="msg.action === 'refuse'" class="ivu-btn ivu-btn-grey">已拒绝</button>
<button v-else-if="msg.action === 'withdraw'" class="ivu-btn ivu-btn-grey">已撤销</button>
</div>
</div>
</template>
<script lang="ts">
export default {
props: {
msg: Object,
},
data() {
return {};
},
computed: {
desc({msg}) {
return msg.action === 'pass' ? `您发起的「${msg.data.proc_def_name}」已通过` : `您发起的「${msg.data.proc_def_name}」被${msg.data.nickname}拒绝`
}
},
methods: {},
}
</script>

View File

@ -0,0 +1,42 @@
<template>
<div>
<p>你可以通过执行以下命令来请求我:</p>
<p>&nbsp;</p>
<p><b>发送文本消息</b></p>
<p>curl --request POST '{{ $A.apiUrl('dialog/msg/sendtext') }}' \</p>
<p>--header 'version: {{ $version }}' \</p>
<p>--header 'token: <span class="mark-color">{机器人Token}</span>' \</p>
<p>--form 'dialog_id="<span class="mark-color">{对话ID}</span>"' \</p>
<p>--form 'text="<span class="mark-color">{消息内容}</span>"'</p>
<p>--form 'text_type="<span class="mark-color">[html|md]</span>"'</p>
<p>--form 'silence="<span class="mark-color">[yes|no]</span>"'</p>
<p>--form 'reply_id="<span class="mark-color">[回复指定消息ID]</span>"'</p>
<p>&nbsp;</p>
<p><b>Webhook说明</b></p>
<p>机器人收到消息后会将消息POST推送到Webhook地址请求超时为10秒请求参数如下</p>
<p><span class="mark-color">text</span>: 消息文本</p>
<p><span class="mark-color">token</span>: 机器人Token</p>
<p><span class="mark-color">dialog_id</span>: 对话ID</p>
<p><span class="mark-color">dialog_type</span>: 对话类型</p>
<p><span class="mark-color">msg_id</span>: 消息ID</p>
<p><span class="mark-color">msg_uid</span>: 消息发送人ID</p>
<p><span class="mark-color">mention</span>: 是否被@</p>
<p><span class="mark-color">bot_uid</span>: 机器人ID</p>
<p><span class="mark-color">version</span>: 系统版本</p>
</div>
</template>
<script lang="ts">
export default {
props: {
msg: Object,
},
data() {
return {};
},
computed: {},
methods: {},
}
</script>

View File

@ -0,0 +1,24 @@
<template>
<div>
<p><b>设置保留消息时间</b></p>
<p>&nbsp;</p>
<p>机器人ID<span class="mark-color">{{ msg.data.userid }}</span></p>
<p>机器人名称<span class="mark-color">{{ msg.data.nickname }}</span></p>
<p>清理周期<span class="mark-color">{{ msg.data.clear_day }}</span></p>
<p>下次清理<span class="mark-color">{{ msg.data.clear_at }}</span></p>
</div>
</template>
<script lang="ts">
export default {
props: {
msg: Object,
},
data() {
return {};
},
computed: {},
methods: {},
}
</script>

View File

@ -0,0 +1,22 @@
<template>
<div>
<p><b>删除成功</b></p>
<p>&nbsp;</p>
<p>机器人ID<span class="mark-color">{{ msg.data.userid }}</span></p>
<p>机器人名称<span class="mark-color">{{ msg.data.nickname }}</span></p>
</div>
</template>
<script lang="ts">
export default {
props: {
msg: Object,
},
data() {
return {};
},
computed: {},
methods: {},
}
</script>

View File

@ -0,0 +1,24 @@
<template>
<div>
<p><b>机器人 <span class="mark-color">{{ msg.data.nickname }} (ID:{{ msg.data.userid }})</span> 已加入的会话</b></p>
<p>&nbsp;</p>
<p><b>会话ID | 会话名称</b></p>
<p v-for="item in msg.data.list">
{{ item.id }} | {{ item.name }}{{ item.type == 'user' ? ' (个人)' : '' }}
</p>
</div>
</template>
<script lang="ts">
export default {
props: {
msg: Object,
},
data() {
return {};
},
computed: {},
methods: {},
}
</script>

View File

@ -0,0 +1,50 @@
<template>
<div>
<p>您可以通过发送以下命令来控制我</p>
<p>&nbsp;</p>
<template v-if="msg.manager">
<p><span class="mark-color">/list</span> - 机器人列表</p>
<p><span class="mark-color">/newbot {机器人名称}</span> - 创建机器人</p>
</template>
<template v-else>
<p><span class="mark-color">/info</span> - 查看机器人详情</p>
</template>
<p>&nbsp;</p>
<p><b>修改机器人</b></p>
<p><span class="mark-color">/setname{{IDLabel}} {机器人名称}</span> - 修改机器人名称</p>
<p><span class="mark-color">/deletebot{{IDLabel}}</span> - 删除机器人</p>
<p><span class="mark-color">/clearday{{IDLabel}} {天数}</span> - 设置保留消息时间默认30天</p>
<p><span class="mark-color">/webhook{{IDLabel}} [url]</span> - 设置消息Webhook详情请看 <u>Api接口文档</u></p>
<p>&nbsp;</p>
<p><b>机器人设置</b></p>
<p><span class="mark-color">/token{{IDLabel}}</span> - 生成Token令牌</p>
<p><span class="mark-color">/revoke{{IDLabel}}</span> - 撤销机器人Token令牌</p>
<p>&nbsp;</p>
<p><b>会话管理</b></p>
<p><span class="mark-color">/dialog{{IDLabel}} [搜索关键词]</span> - 查看会话ID</p>
<p>&nbsp;</p>
<p><b>Api接口文档</b></p>
<p><span class="mark-color">/api</span> - 查看接口列表</p>
</div>
</template>
<script lang="ts">
export default {
props: {
msg: Object,
},
data() {
return {};
},
computed: {
IDLabel() {
return this.msg.manager ? ' {机器人ID}' : '';
},
},
}
</script>

View File

@ -0,0 +1,26 @@
<template>
<div>
<p><b>机器人详情</b></p>
<p>&nbsp;</p>
<p>机器人ID<span class="mark-color">{{ msg.data.userid }}</span></p>
<p>机器人名称<span class="mark-color">{{ msg.data.nickname }}</span></p>
<p>保留消息时间<span class="mark-color">{{ msg.data.clear_day }}</span></p>
<p>最后一次清理时间<span class="mark-color">{{ msg.data.clear_at || '-' }}</span></p>
<p>Webhook地址<span class="mark-color">{{ msg.data.webhook_url || '-' }}</span></p>
<p>Webhook请求次数<span class="mark-color">{{ msg.data.webhook_num }}</span></p>
</div>
</template>
<script lang="ts">
export default {
props: {
msg: Object,
},
data() {
return {};
},
computed: {},
methods: {},
}
</script>

View File

@ -0,0 +1,22 @@
<template>
<div>
<p><b>我的机器人</b></p>
<p>&nbsp;</p>
<p><b>ID | 名称 | 清理时间 | Webhook</b></p>
<p v-for="item in msg.data">{{ item.userid }} | {{ item.nickname }} | {{ item.clear_day }} | {{ item.webhook_url ? '' : '-' }}</p>
</div>
</template>
<script lang="ts">
export default {
props: {
msg: Object,
},
data() {
return {};
},
computed: {},
methods: {},
}
</script>

View File

@ -0,0 +1,22 @@
<template>
<div>
<p><b>创建成功</b></p>
<p>&nbsp;</p>
<p>机器人ID<span class="mark-color">{{ msg.data.userid }}</span></p>
<p>机器人名称<span class="mark-color">{{ msg.data.nickname }}</span></p>
</div>
</template>
<script lang="ts">
export default {
props: {
msg: Object,
},
data() {
return {};
},
computed: {},
methods: {},
}
</script>

View File

@ -0,0 +1,22 @@
<template>
<div>
<p><b>撤销机器人Token令牌</b></p>
<p>&nbsp;</p>
<p>机器人ID<span class="mark-color">{{ msg.data.userid }}</span></p>
<p>机器人名称<span class="mark-color">{{ msg.data.nickname }}</span></p>
</div>
</template>
<script lang="ts">
export default {
props: {
msg: Object,
},
data() {
return {};
},
computed: {},
methods: {},
}
</script>

View File

@ -0,0 +1,22 @@
<template>
<div>
<p><b>设置名称成功</b></p>
<p>&nbsp;</p>
<p>机器人ID<span class="mark-color">{{ msg.data.userid }}</span></p>
<p>机器人名称<span class="mark-color">{{ msg.data.nickname }}</span></p>
</div>
</template>
<script lang="ts">
export default {
props: {
msg: Object,
},
data() {
return {};
},
computed: {},
methods: {},
}
</script>

View File

@ -0,0 +1,23 @@
<template>
<div>
<p><b>生成Token令牌</b></p>
<p>&nbsp;</p>
<p>机器人ID<span class="mark-color">{{ msg.data.userid }}</span></p>
<p>机器人名称<span class="mark-color">{{ msg.data.nickname }}</span></p>
<p>Token<span class="mark-color">{{ msg.data.token }}</span></p>
</div>
</template>
<script lang="ts">
export default {
props: {
msg: Object,
},
data() {
return {};
},
computed: {},
methods: {},
}
</script>

View File

@ -0,0 +1,23 @@
<template>
<div>
<p><b>设置Webhook地址</b></p>
<p>&nbsp;</p>
<p>机器人ID<span class="mark-color">{{ msg.data.userid }}</span></p>
<p>机器人名称<span class="mark-color">{{ msg.data.nickname }}</span></p>
<p>Webhook地址<span class="mark-color">{{ msg.data.webhook_url }}</span></p>
</div>
</template>
<script lang="ts">
export default {
props: {
msg: Object,
},
data() {
return {};
},
computed: {},
methods: {},
}
</script>

View File

@ -0,0 +1,84 @@
<template>
<div :class="`content-template no-dark-content ${msg.type}`" @click="onClick">
<component :is="currentTemplate" :msg="msg"/>
</div>
</template>
<script lang="ts">
import BotHelp from "./bot-help.vue";
import BotList from "./bot-list.vue";
import BotInfo from "./bot-info.vue";
import BotNewbot from "./bot-newbot.vue";
import BotSetname from "./bot-setname.vue";
import BotDeletebot from "./bot-deletebot.vue";
import BotToken from "./bot-token.vue";
import BotRevoke from "./bot-revoke.vue";
import BotWebhook from "./bot-webhook.vue";
import BotClearday from "./bot-clearday.vue";
import BotDialog from "./bot-dialog.vue";
import BotApi from "./bot-api.vue";
import Notice from "./notice.vue";
import ApproveReviewer from "./approve-reviewer.vue";
import ApproveNotifier from "./approve-notifier.vue";
import ApproveCommentNotifier from "./approve-comment-notifier.vue";
import ApproveSubmitter from "./approve-submitter.vue";
import Other from "./other.vue";
export default {
props: {
msg: Object,
},
data() {
return {};
},
computed: {
currentTemplate() {
switch (this.msg.type) {
case '/help':
return BotHelp;
case '/list':
return BotList;
case '/info':
return BotInfo;
case '/newbot':
return BotNewbot;
case '/setname':
return BotSetname;
case '/deletebot':
return BotDeletebot;
case '/token':
return BotToken;
case '/revoke':
return BotRevoke;
case '/webhook':
return BotWebhook;
case '/clearday':
return BotClearday;
case '/dialog':
return BotDialog;
case '/api':
return BotApi;
case 'approve_reviewer':
return ApproveReviewer;
case 'approve_notifier':
return ApproveNotifier;
case 'approve_comment_notifier':
return ApproveCommentNotifier;
case 'approve_submitter':
return ApproveSubmitter;
case 'notice':
return Notice;
default:
return Other;
}
},
},
methods: {
onClick(e) {
this.$emit('clickTemplate', e);
},
},
}
</script>

View File

@ -0,0 +1,16 @@
<template>
<div>
{{msg.notice}}
</div>
</template>
<script lang="ts">
export default {
props: {
msg: Object,
},
data() {
return {};
},
methods: {},
}
</script>

View File

@ -0,0 +1,25 @@
<template>
<div v-if="isBot">
你好我是你的机器人助理你可以发送 <span class="mark-color">/help</span> 查看帮助菜单
</div>
<div v-else>
未知消息类型
</div>
</template>
<script lang="ts">
export default {
props: {
msg: Object,
},
data() {
return {};
},
computed: {
isBot() {
return this.msg.type.startsWith('/');
},
},
methods: {},
}
</script>

View File

@ -14,8 +14,8 @@ export default {
msg: Object,
},
methods: {
viewText() {
this.$emit('viewText');
viewText(e) {
this.$emit('viewText', e);
},
},
}

View File

@ -204,6 +204,7 @@
@on-view-text="onViewText"
@on-view-file="onViewFile"
@on-down-file="onDownFile"
@on-click-template="onClickTemplate"
@on-reply-list="onReplyList"
@on-error="onError"
@on-emoji="onEmoji"
@ -640,11 +641,6 @@
</div>
</DrawerOverlay>
<!--审批详情-->
<DrawerOverlay v-model="approveDetailsShow" placement="right" :size="600">
<ApproveDetails v-if="approveDetailsShow" :data="approveDetails" style="height: 100%;border-radius: 10px;"></ApproveDetails>
</DrawerOverlay>
<!-- 群接龙 -->
<DialogGroupWordChain/>
@ -668,7 +664,6 @@ import {Store} from "le5le-store";
import ImgUpload from "../../../components/ImgUpload.vue";
import {choiceEmojiOne} from "./ChatInput/one";
import ApproveDetails from "../../../pages/manage/approve/details.vue";
import UserSelect from "../../../components/UserSelect.vue";
import UserAvatarTip from "../../../components/UserAvatar/tip.vue";
import DialogGroupWordChain from "./DialogGroupWordChain";
@ -689,7 +684,6 @@ export default {
DialogGroupInfo,
DrawerOverlay,
DialogUpload,
ApproveDetails,
DialogGroupWordChain,
DialogGroupVote,
DialogComplaint,
@ -822,8 +816,6 @@ export default {
scrollIng: 0,
scrollGroup: null,
approveDetails: {id: 0},
approveDetailsShow: false,
approvaUserStatus: '',
observers: [],
@ -3130,25 +3122,8 @@ export default {
return
}
//
let approveElement = target;
while (approveElement) {
if (approveElement.classList.contains('dialog-scroller')) {
break;
}
if (approveElement.classList.contains('open-approve-details')) {
const dataId = approveElement.getAttribute("data-id")
if (window.innerWidth < 426) {
this.goForward({name: 'manage-approve-details', query: {id: approveElement.getAttribute("data-id")}});
} else {
this.approveDetailsShow = true;
this.$nextTick(() => {
this.approveDetails = {id: dataId};
})
}
return;
}
approveElement = approveElement.parentElement;
if (this.onClickTemplate({target})) {
return;
}
switch (target.nodeName) {
@ -3332,6 +3307,26 @@ export default {
});
},
onClickTemplate({target}) {
if (this.operateVisible) {
return false
}
//
let approveElement = target;
while (approveElement) {
if (approveElement.classList.contains('dialog-scroller')) {
break;
}
if (approveElement.classList.contains('open-approve-details')) {
Store.set('approveDetails', approveElement.getAttribute("data-id"));
return true;
}
approveElement = approveElement.parentElement;
}
return false
},
onReplyList(data) {
if (this.operateVisible) {
return
@ -3619,28 +3614,27 @@ export default {
},
actionPermission(item, permission) {
if (permission === 'forward') {
if (['word-chain', 'vote'].includes(item.type)) {
return false //
}
if (item.type === 'text') {
return typeof item.msg.approve_type === 'undefined' //
}
} else if (permission === 'newTask') {
if (item.type === 'text') {
return typeof item.msg.approve_type === 'undefined' //
}
return false
} else if (permission === 'voice2text') {
if (item.type !== 'record') {
return false;
}
if (item.msg.text) {
return false;
}
if (this.isLoad(`msg-${item.id}`)) {
return false;
}
switch (permission) {
case 'forward':
if (['word-chain', 'vote', 'template'].includes(item.type)) {
return false //
}
break;
case 'newTask':
return item.type === 'text' //
case 'voice2text':
if (item.type !== 'record') {
return false;
}
if (item.msg.text) {
return false;
}
if (this.isLoad(`msg-${item.id}`)) {
return false;
}
break;
}
return true // true
},

View File

@ -39,11 +39,6 @@ export default [
path: 'approve',
component: () => import('./pages/manage/approve/index.vue'),
},
{
name: 'manage-approve-details',
path: 'approve/details',
component: () => import('./pages/manage/approve/details.vue'),
},
{
name: 'manage-apps',
path: 'apps/*',

View File

@ -235,9 +235,9 @@ export default {
state.ajaxNetworkException = networkException
}
if (networkException) {
reject({ret: -1001, data: {}, msg: $A.L('网络异常')})
reject({ret: -1001, data: {}, msg: $A.L('网络异常,请重试。')})
} else {
reject({ret: -1, data: {}, msg: $A.L('请求失败')})
reject({ret: -1, data: {}, msg: $A.L('请求失败,请重试。')})
}
console.error(xhr, status);
}

View File

@ -949,52 +949,6 @@
background-color: $primary-color;
}
}
.open-approve-details {
width: 260px;
display: inline-block;
max-width: 100%;
.cause {
border-bottom: 1px solid #e3e3e3;
border-top: 1px solid #e3e3e3;
padding-bottom: 10px;
margin-top: 10px;
> span:first-child {
display: inline-block;
padding: 15px 0;
}
> b {
display: inline-block;
margin-bottom: 5px;
}
> span {
display: inline-block;
margin-bottom: 3px;
}
}
.btn-raw {
display: flex;
text-align: center;
padding: 12px 0 5px 0;
> button {
&.ivu-btn {
flex: 1;
}
&.ivu-btn-primary {
margin-right: 12px;
}
&.ivu-btn-small {
height: 32px;
}
}
}
}
}
}
@ -1250,6 +1204,13 @@
}
}
.content-template {
color: #ffffff;
.mark-color {
color: $primary-color;
}
}
.content-loading {
display: flex;
align-items: center;
@ -1422,6 +1383,58 @@
}
}
}
.open-approve-details {
width: 260px;
display: inline-block;
max-width: 100%;
.cause {
border-bottom: 1px solid #e3e3e3;
border-top: 1px solid #e3e3e3;
padding-bottom: 10px;
margin-top: 10px;
> b {
display: inline-block;
margin-bottom: 5px;
}
> p {
display: block;
margin-bottom: 3px;
&:first-child {
padding: 15px 0;
}
}
> span {
display: inline-block;
margin-bottom: 3px;
&:first-child {
padding: 15px 0;
}
}
}
.btn-raw {
display: flex;
text-align: center;
padding: 12px 0 5px 0;
> button {
&.ivu-btn {
flex: 1;
}
&.ivu-btn-primary {
margin-right: 12px;
}
&.ivu-btn-small {
height: 32px;
}
}
}
}
}
.dialog-emoji {
@ -1737,6 +1750,13 @@
color: #23241f;
}
}
.open-approve-details {
.ivu-btn-grey {
background-color: #efefef;
border-color: #f3f3f3;
}
}
}
.dialog-emoji {
@ -1768,13 +1788,6 @@
display: flex;
}
}
.open-approve-details {
.ivu-btn-grey {
background-color: #efefef;
border-color: #f3f3f3;
}
}
}
}
}

View File

@ -60,13 +60,13 @@
.ivu-input-wrapper{
max-width: 200px;
}
@media (max-width: 515px) {
.ivu-btn{
min-width: 45px;
}
}
}
.approve-load {
@ -200,6 +200,8 @@
display: flex;
flex-direction: column;
border: 1px solid #eeeeee;
height: 100%;
border-radius: 10px;
background: #fff;
.approve-details-nav{
@ -466,7 +468,7 @@
font-weight: 500;
color: #135de6;
}
.divider{
margin: 12px 0;
margin-bottom: 9px;
@ -502,11 +504,11 @@
}
}
//
//
body.window-portrait {
.page-approve{
.approve-head {
margin: 24px 16px 6px 16px;
}
}
}
}

View File

@ -1,185 +0,0 @@
@if ($type === '/help')
您可以通过发送以下命令来控制我:
@if ($manager)
<span style="color:#84c56a">/list</span> - 机器人列表
<span style="color:#84c56a">/newbot {机器人名称}</span> - 创建机器人
@else
<span style="color:#84c56a">/info</span> - 查看机器人详情
@endif
<b>修改机器人</b>
<span style="color:#84c56a">/setname {机器人ID} {机器人名称}</span> - 修改机器人名称
<span style="color:#84c56a">/deletebot {机器人ID}</span> - 删除机器人
<span style="color:#84c56a">/clearday {机器人ID} {天数}</span> - 设置保留消息时间默认30天
<span style="color:#84c56a">/webhook {机器人ID} [url]</span> - 设置消息Webhook详情请看 <u>Api接口文档</u>
<b>机器人设置</b>
<span style="color:#84c56a">/token {机器人ID}</span> - 生成Token令牌
<span style="color:#84c56a">/revoke {机器人ID}</span> - 撤销机器人Token令牌
<b>会话管理</b>
<span style="color:#84c56a">/dialog {机器人ID} [搜索关键词]</span> - 查看会话ID
<b>Api接口文档</b>
<span style="color:#84c56a">/api</span> - 查看接口列表
@elseif ($type === '/list')
<b>我的机器人。</b>
<b>ID | 名称 | 清理时间 | Webhook</b>
@foreach($data as $item)
{{$item->userid}} | {{$item->nickname}} | {{$item->clear_day}} | {{$item->webhook_url ? '✅' : '-'}}
@endforeach
@elseif ($type === '/info')
<b>机器人详情。</b>
机器人ID<span style="color:#84c56a">{{$data->userid}}</span>
机器人名称:<span style="color:#84c56a">{{$data->nickname}}</span>
保留消息时间:<span style="color:#84c56a">{{$data->clear_day}}</span>
最后一次清理时间:<span style="color:#84c56a">{{$data->clear_at ?: '-'}}</span>
Webhook地址<span style="color:#84c56a">{{$data->webhook_url ?: '-'}}</span>
Webhook请求次数<span style="color:#84c56a">{{$data->webhook_num}}</span>
@elseif ($type === '/newbot')
<b>创建成功。</b>
机器人ID<span style="color:#84c56a">{{$data->userid}}</span>
机器人名称:<span style="color:#84c56a">{{$data->nickname}}</span>
@elseif ($type === '/setname')
<b>设置名称成功。</b>
机器人ID<span style="color:#84c56a">{{$data->userid}}</span>
机器人名称:<span style="color:#84c56a">{{$data->nickname}}</span>
@elseif ($type === '/deletebot')
<b>删除成功。</b>
机器人ID<span style="color:#84c56a">{{$data->userid}}</span>
机器人名称:<span style="color:#84c56a">{{$data->nickname}}</span>
@elseif ($type === '/token')
<b>生成Token令牌。</b>
机器人ID<span style="color:#84c56a">{{$data->userid}}</span>
机器人名称:<span style="color:#84c56a">{{$data->nickname}}</span>
Token<span style="color:#84c56a">{{$data->token}}</span>
@elseif ($type === '/revoke')
<b>撤销机器人Token令牌。</b>
机器人ID<span style="color:#84c56a">{{$data->userid}}</span>
机器人名称:<span style="color:#84c56a">{{$data->nickname}}</span>
@elseif ($type === '/webhook')
<b>设置Webhook地址。</b>
机器人ID<span style="color:#84c56a">{{$data->userid}}</span>
机器人名称:<span style="color:#84c56a">{{$data->nickname}}</span>
Webhook地址<span style="color:#84c56a">{{$data->webhook_url}}</span>
@elseif ($type === '/clearday')
<b>设置保留消息时间。</b>
机器人ID<span style="color:#84c56a">{{$data->userid}}</span>
机器人名称:<span style="color:#84c56a">{{$data->nickname}}</span>
清理周期:<span style="color:#84c56a">{{$data->clear_day}}</span>
下次清理:<span style="color:#84c56a">{{$data->clear_at}}</span>
@elseif ($type === '/dialog')
<b>机器人 <span style="color:#84c56a">{{$data->nickname}} (ID:{{$data->userid}})</span> 已加入的会话:</b>
<b>会话ID | 会话名称</b>
@foreach($data->list as $item)
{{$item->id}} | {{$item->name}}{{$item->type == 'user' ? ' (个人)' : ''}}
@endforeach
@elseif ($type === '/api')
你可以通过执行以下命令来请求我:
<b>发送文本消息:</b>
curl --request POST '{{url('api/dialog/msg/sendtext')}}' \
--header 'version: {{ $version }}' \
--header 'token: <span style="color:#84c56a">{机器人Token}</span>' \
--form 'dialog_id="<span style="color:#84c56a">{对话ID}</span>"' \
--form 'text="<span style="color:#84c56a">{消息内容}</span>"'
--form 'text_type="<span style="color:#84c56a">[html|md]</span>"'
--form 'silence="<span style="color:#84c56a">[yes|no]</span>"'
--form 'reply_id="<span style="color:#84c56a">[回复指定消息ID]</span>"'
<b>Webhook说明</b>
机器人收到消息后会将消息POST推送到Webhook地址请求超时为10秒请求参数如下
<span style="color:#84c56a">text</span>: 消息文本
<span style="color:#84c56a">token</span>: 机器人Token
<span style="color:#84c56a">dialog_id</span>: 对话ID
<span style="color:#84c56a">dialog_type</span>: 对话类型
<span style="color:#84c56a">msg_id</span>: 消息ID
<span style="color:#84c56a">msg_uid</span>: 消息发送人ID
<span style="color:#84c56a">mention</span>: 是否被@
<span style="color:#84c56a">bot_uid</span>: 机器人ID
<span style="color:#84c56a">version</span>: 系统版本
@elseif ($type === 'notice')
{{$notice}}
@elseif ($type === 'approve_reviewer')
<span class="open-approve-details" data-id="{{$data->id}}"><b>{{$data->nickname}}提交的「{{$data->proc_def_name}}」待你审批</b>
<div class="cause"><span>申请人:<span style="color:#84c56a">{{'@'}}{{$data->nickname}}</span> {{$data->department}}</span>
<b>详情</b>
@if ($data->type)
<span>假期类型:{{$data->type}}</span>
@endif
<span>开始时间:{{$data->start_time}} ({{ $data->start_day_of_week }})</span>
<span>结束时间:{{$data->end_time}} ({{ $data->end_day_of_week }})</span>
<span>事由:{{$data->description}}</span>
</div><div class="btn-raw no-dark-content">
@if ($action === 'pass')
<button class="ivu-btn ivu-btn-grey">已同意</button>
@elseif ($action === 'refuse')
<button class="ivu-btn ivu-btn-grey">已拒绝</button>
@elseif ($action === 'withdraw')
<button class="ivu-btn ivu-btn-grey">已撤销</button>
@else
<button class="ivu-btn ivu-btn-primary">同意</button>
<button class="ivu-btn ivu-btn-error">拒绝</button>
@endif
</div></span>
@elseif ($type === 'approve_notifier')
<span class="open-approve-details" data-id="{{$data->id}}"><b>抄送{{$data->nickname}}提交的「{{$data->proc_def_name}}」记录</b>
<div class="cause"><span>申请人:<span style="color:#84c56a">{{'@'}}{{$data->nickname}}</span> {{$data->department}}</span>
<b>详情</b>
@if ($data->type)
<span>假期类型:{{$data->type}}</span>
@endif
<span>开始时间:{{$data->start_time}} ({{ $data->start_day_of_week }})</span>
<span>结束时间:{{$data->end_time}} ({{ $data->end_day_of_week }})</span>
<span>事由:{{$data->description}}</span>
</div><div class="btn-raw no-dark-content">
@if ($is_finished == 1)
<button class="ivu-btn ivu-btn-grey">已同意</button>
@else
<button class="ivu-btn ivu-btn-grey">查看详情</button>
@endif
</div></span>
@elseif ($type === 'approve_comment_notifier')
<span class="open-approve-details" data-id="{{$data->id}}"><b>{{$data->comment_nickname}}评论了此审批</b>
<div class="cause"><span>申请人:<span style="color:#84c56a">{{'@'}}{{$data->nickname}}</span> {{$data->department}}</span>
<b>评论内容</b>
<span>{{$data->comment_content}}</span>
@if ($data->comment_pictures)
<span>[图片]</span>
@endif
</div><div class="btn-raw no-dark-content">
<button class="ivu-btn ivu-btn-grey">查看详情</button>
</div></span>
@elseif ($type === 'approve_submitter')
<span class="open-approve-details" data-id="{{$data->id}}"><b>@if ($action === 'pass')您发起的「{{$data->proc_def_name}}」已通过 @else您发起的「{{$data->proc_def_name}}」被{{$data->nickname}}拒绝 @endif</b>
<div class="cause"><span>申请人:<span style="color:#84c56a">{{'@'}}{{$data->start_nickname}}</span> {{$data->department}}</span>
<b>详情</b>
@if ($data->type)
<span>假期类型:{{$data->type}}</span>
@endif
<span>开始时间:{{$data->start_time}} ({{ $data->start_day_of_week }})</span>
<span>结束时间:{{$data->end_time}} ({{ $data->end_day_of_week }})</span>
<span>事由:{{$data->description}}</span>
</div><div class="btn-raw no-dark-content">
@if ($action === 'pass')
<button class="ivu-btn ivu-btn-grey">已同意</button>
@elseif ($action === 'refuse')
<button class="ivu-btn ivu-btn-grey">已拒绝</button>
@elseif ($action === 'withdraw')
<button class="ivu-btn ivu-btn-grey">已撤销</button>
@endif
</div></span>
@else
你好,我是你的机器人助理,你可以发送 <span style="color:#84c56a">/help</span> 查看帮助菜单。
@endif