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\ReportLink;
use App\Models\ReportReceive; use App\Models\ReportReceive;
use App\Models\User; use App\Models\User;
use App\Models\WebSocketDialog;
use App\Models\WebSocketDialogMsg;
use App\Module\Base; use App\Module\Base;
use App\Module\Doo; use App\Module\Doo;
use App\Tasks\PushTask; use App\Tasks\PushTask;
@ -29,6 +31,7 @@ class ReportController extends AbstractController
/** /**
* @api {get} api/report/my 01. 我发送的汇报 * @api {get} api/report/my 01. 我发送的汇报
* *
* @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup report * @apiGroup report
* @apiName my * @apiName my
@ -75,6 +78,7 @@ class ReportController extends AbstractController
/** /**
* @api {get} api/report/receive 02. 我接收的汇报 * @api {get} api/report/receive 02. 我接收的汇报
* *
* @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup report * @apiGroup report
* @apiName receive * @apiName receive
@ -142,6 +146,7 @@ class ReportController extends AbstractController
/** /**
* @api {get} api/report/store 03. 保存并发送工作汇报 * @api {get} api/report/store 03. 保存并发送工作汇报
* *
* @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup report * @apiGroup report
* @apiName store * @apiName store
@ -267,6 +272,7 @@ class ReportController extends AbstractController
/** /**
* @api {get} api/report/template 04. 生成汇报模板 * @api {get} api/report/template 04. 生成汇报模板
* *
* @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup report * @apiGroup report
* @apiName template * @apiName template
@ -438,6 +444,7 @@ class ReportController extends AbstractController
/** /**
* @api {get} api/report/detail 05. 报告详情 * @api {get} api/report/detail 05. 报告详情
* *
* @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup report * @apiGroup report
* @apiName detail * @apiName detail
@ -487,6 +494,7 @@ class ReportController extends AbstractController
/** /**
* @api {get} api/report/mark 06. 标记已读/未读 * @api {get} api/report/mark 06. 标记已读/未读
* *
* @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup report * @apiGroup report
* @apiName mark * @apiName mark
@ -526,9 +534,106 @@ class ReportController extends AbstractController
return Base::retSuccess("操作成功"); 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. 获取最后一次提交的接收人 * @api {get} api/report/last_submitter 07. 获取最后一次提交的接收人
* *
* @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup report * @apiGroup report
* @apiName last_submitter * @apiName last_submitter
@ -546,6 +651,7 @@ class ReportController extends AbstractController
/** /**
* @api {get} api/report/unread 08. 获取未读 * @api {get} api/report/unread 08. 获取未读
* *
* @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup report * @apiGroup report
* @apiName unread * @apiName unread
@ -570,6 +676,7 @@ class ReportController extends AbstractController
/** /**
* @api {get} api/report/read 09. 标记汇报已读,可批量 * @api {get} api/report/read 09. 标记汇报已读,可批量
* *
* @apiDescription 需要token身份
* @apiVersion 1.0.0 * @apiVersion 1.0.0
* @apiGroup report * @apiGroup report
* @apiName read * @apiName read

View File

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