feat: 支持分享工作报告到消息

This commit is contained in:
kuaifan 2025-03-16 21:39:12 +08:00
parent 0ffbaaaeaa
commit 55ade32589
2 changed files with 238 additions and 87 deletions

View File

@ -9,6 +9,8 @@ use App\Models\Report;
use App\Models\ReportLink;
use App\Models\ReportReceive;
use App\Models\User;
use App\Models\WebSocketDialog;
use App\Models\WebSocketDialogMsg;
use App\Module\Base;
use App\Module\Doo;
use App\Tasks\PushTask;
@ -29,6 +31,7 @@ class ReportController extends AbstractController
/**
* @api {get} api/report/my 01. 我发送的汇报
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup report
* @apiName my
@ -75,6 +78,7 @@ class ReportController extends AbstractController
/**
* @api {get} api/report/receive 02. 我接收的汇报
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup report
* @apiName receive
@ -142,6 +146,7 @@ class ReportController extends AbstractController
/**
* @api {get} api/report/store 03. 保存并发送工作汇报
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup report
* @apiName store
@ -267,6 +272,7 @@ class ReportController extends AbstractController
/**
* @api {get} api/report/template 04. 生成汇报模板
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup report
* @apiName template
@ -438,6 +444,7 @@ class ReportController extends AbstractController
/**
* @api {get} api/report/detail 05. 报告详情
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup report
* @apiName detail
@ -487,6 +494,7 @@ class ReportController extends AbstractController
/**
* @api {get} api/report/mark 06. 标记已读/未读
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup report
* @apiName mark
@ -526,9 +534,106 @@ class ReportController extends AbstractController
return Base::retSuccess("操作成功");
}
/**
* @api {get} api/report/share 06. 分享报告到消息
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup report
* @apiName share
*
* @apiParam {Number} id 报告id
* @apiParam {Array} dialogids 转发给的对话ID
* @apiParam {Array} userids 转发给的成员ID
* @apiParam {String} leave_message 转发留言
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function share()
{
$user = User::auth();
//
$id = Request::input('id');
$dialogids = Request::input('dialogids');
$userids = Request::input('userids');
$leave_message = Request::input('leave_message');
//
if (is_array($id)) {
if (count(Base::arrayRetainInt($id)) > 20) {
return Base::retError("最多只能操作20条数据");
}
$builder = Report::whereIn("id", Base::arrayRetainInt($id));
} else {
$builder = Report::whereId(intval($id));
}
$reportMsgs = [];
$builder ->chunkById(100, function ($list) use (&$reportMsgs, $user) {
/** @var Report $item */
foreach ($list as $item) {
$reportLink = ReportLink::generateLink($item->id, $user->userid);
$reportMsgs[] = "<a class=\"mention report\" href=\"{{RemoteURL}}single/report/detail/{$reportLink['code']}\" target=\"_blank\">%{$item->title}</a>";
}
});
if (empty($reportMsgs)) {
return Base::retError("报告不存在或已被删除");
}
$reportTag = count($reportMsgs) > 1 ? 'li' : 'p';
$reportMsgs = array_map(function ($item) use ($reportTag) {
return "<{$reportTag}>{$item}</{$reportTag}>";
}, $reportMsgs);
if ($reportTag === 'li') {
array_unshift($reportMsgs, "<ol>");
$reportMsgs[] = "</ol>";
}
if ($leave_message) {
$reportMsgs[] = "<p>{$leave_message}</p>";
}
$msgText = implode("", $reportMsgs);
//
return AbstractModel::transaction(function() use ($user, $msgText, $userids, $dialogids) {
$msgs = [];
$already = [];
if ($dialogids) {
if (!is_array($dialogids)) {
$dialogids = [$dialogids];
}
foreach ($dialogids as $dialogid) {
$res = WebSocketDialogMsg::sendMsg(null, $dialogid, 'text', ['text' => $msgText], $user->userid);
if (Base::isSuccess($res)) {
$msgs[] = $res['data'];
$already[] = $dialogid;
}
}
}
if ($userids) {
if (!is_array($userids)) {
$userids = [$userids];
}
foreach ($userids as $userid) {
if (!User::whereUserid($userid)->exists()) {
continue;
}
$dialog = WebSocketDialog::checkUserDialog($user, $userid);
if ($dialog && !in_array($dialog->id, $already)) {
$res = WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => $msgText], $user->userid);
if (Base::isSuccess($res)) {
$msgs[] = $res['data'];
}
}
}
}
return Base::retSuccess('发送成功', [
'msgs' => $msgs
]);
});
}
/**
* @api {get} api/report/last_submitter 07. 获取最后一次提交的接收人
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup report
* @apiName last_submitter
@ -546,6 +651,7 @@ class ReportController extends AbstractController
/**
* @api {get} api/report/unread 08. 获取未读
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup report
* @apiName unread
@ -570,6 +676,7 @@ class ReportController extends AbstractController
/**
* @api {get} api/report/read 09. 标记汇报已读,可批量
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup report
* @apiName read

View File

@ -95,6 +95,7 @@
<Select v-model="selectAction" :disabled="selectIds.length==0" @on-change="groupSelect=true" :placeholder="$L('请选择')" transfer>
<Option value="read">{{ $L('标记已读') }}</Option>
<Option value="unread">{{ $L('标记未读') }}</Option>
<Option value="share">{{ $L('分享到消息') }}</Option>
</Select>
<Button :loading="loadIng > 0" type="primary" @click="selectClick" :disabled="selectAction=='' || selectIds.length==0">{{$L('执行')}}</Button>
</div>
@ -113,107 +114,121 @@
@on-page-size-change="setPageSize"/>
</div>
</div>
<!-- 分享到消息 -->
<Forwarder
ref="forwarder"
:title="$L('分享报告到消息')"
:confirm-title="$L('确认分享')"
:multiple-max="50"
:before-submit="onShare"
sender-hidden/>
</div>
</template>
<script>
import Forwarder from "./Forwarder/index.vue";
export default {
name: "ReportReceive",
components: {Forwarder},
data() {
return {
loadIng: 0,
columns: [{
type: 'selection',
width: 50,
align: 'right'
}, {
title: this.$L("标题"),
key: 'title',
sortable: true,
minWidth: 180,
render: (h, {row}) => {
const displayTitle = `${row.title || ""}`.replace(/(\[([^\[\]]*)\]\s*){0,2}$/, '');
const arr = []
const myUser = row.receives_user.find(({userid}) => userid == this.userId)
if (myUser && myUser.pivot.read == 0) {
arr.push(
h('Tag', {
props: { //
color: "orange",
},
style: {
flexShrink: 0,
}
}, this.$L("未读")),
h('AutoTip', displayTitle)
)
} else {
arr.push(
h('AutoTip', displayTitle)
)
}
return h('div', {
style: {
display: 'flex',
alignItems: 'center',
columns: [
{
type: 'selection',
width: 50,
align: 'right'
}, {
title: this.$L("标题"),
key: 'title',
sortable: true,
minWidth: 180,
render: (h, {row}) => {
const displayTitle = `${row.title || ""}`.replace(/(\[([^\[\]]*)\]\s*){0,2}$/, '');
const arr = []
const myUser = row.receives_user.find(({userid}) => userid == this.userId)
if (myUser && myUser.pivot.read == 0) {
arr.push(
h('Tag', {
props: { //
color: "orange",
},
style: {
flexShrink: 0,
}
}, this.$L("未读")),
h('AutoTip', displayTitle)
)
} else {
arr.push(
h('AutoTip', displayTitle)
)
}
}, arr)
}
}, {
title: this.$L("时间"),
key: 'time',
sortable: true,
minWidth: 180,
render: (h, {row}) => {
return h('AutoTip', $A.reportExtractTime(row.title) || '-');
}
}, {
title: this.$L("类型"),
key: 'type',
sortable: true,
width: 90,
render: (h, {row}) => {
return h('AutoTip', this.$L(row.type === 'daily' ? '日报' : '周报'))
}
}, {
title: this.$L("接收时间"),
key: 'receive_at',
align: 'center',
sortable: true,
width: 180,
}, {
title: this.$L("操作"),
align: 'center',
width: 90,
minWidth: 90,
render: (h, {column, row}) => {
if (!row.id) {
return null;
return h('div', {
style: {
display: 'flex',
alignItems: 'center',
}
}, arr)
}
return h('TableAction', {
props: {
column,
menu: [
{
icon: "md-eye",
action: "view",
}
]
},
on: {
action: (name) => {
if (name === 'view') {
this.$emit("on-view", row)
const myUser = row.receives_user.find(({userid}) => userid == this.userId)
if (myUser) {
this.$set(myUser.pivot, 'read', 1)
}, {
title: this.$L("时间"),
key: 'time',
sortable: true,
minWidth: 180,
render: (h, {row}) => {
return h('AutoTip', $A.reportExtractTime(row.title) || '-');
}
}, {
title: this.$L("类型"),
key: 'type',
sortable: true,
width: 90,
render: (h, {row}) => {
return h('AutoTip', this.$L(row.type === 'daily' ? '日报' : '周报'))
}
}, {
title: this.$L("接收时间"),
key: 'receive_at',
align: 'center',
sortable: true,
width: 180,
}, {
title: this.$L("操作"),
align: 'center',
width: 90,
minWidth: 90,
render: (h, {column, row}) => {
if (!row.id) {
return null;
}
return h('TableAction', {
props: {
column,
menu: [
{
icon: "md-eye",
action: "view",
}
]
},
on: {
action: (name) => {
if (name === 'view') {
this.$emit("on-view", row)
const myUser = row.receives_user.find(({userid}) => userid == this.userId)
if (myUser) {
this.$set(myUser.pivot, 'read', 1)
}
}
}
}
}
});
},
}],
});
},
}
],
lists: [],
listPage: 1,
listTotal: 0,
@ -310,6 +325,13 @@ export default {
case 'unread':
this.readReport(this.selectIds, this.selectAction)
break;
case 'share':
if (this.selectIds.length > 20) {
$A.messageWarning('每次最多分享20个');
return;
}
this.$refs.forwarder.onSelection()
break;
default:
$A.messageWarning('请选择执行方式');
break;
@ -342,6 +364,28 @@ export default {
}
});
},
onShare({dialogids, userids, message}) {
return new Promise((resolve, reject) => {
this.$store.dispatch("call", {
url: 'report/share',
data: {
id: this.selectIds,
dialogids,
userids,
leave_message: message,
}
}).then(({data, msg}) => {
this.$store.dispatch("saveDialogMsg", data.msgs);
this.$store.dispatch("updateDialogLastMsg", data.msgs);
$A.messageSuccess(msg);
resolve();
}).catch(({msg}) => {
$A.modalError(msg);
reject();
});
})
}
}
}
</script>