diff --git a/src/classes/groups.js b/src/classes/groups.js index 10f323da..80567c73 100644 --- a/src/classes/groups.js +++ b/src/classes/groups.js @@ -1549,6 +1549,7 @@ export default class extends baseClass { isGroupGalleryLoading: false, loadMoreGroupMembersParams: {}, groupMemberModerationTableForceUpdate: 0, + isGroupLogsExportDialogVisible: false, groupDialog: { visible: false, @@ -1701,7 +1702,37 @@ export default class extends baseClass { layout: 'sizes,prev,pager,next,total', pageSizes: [10, 15, 25, 50, 100] } - } + }, + checkedGroupLogsExportLogsOptions: [ + 'created_at', + 'eventType', + 'actorDisplayName', + 'description', + 'data' + ], + checkGroupsLogsExportLogsOptions: [ + { + label: 'created_at', + text: 'dialog.group_member_moderation.created_at' + }, + { + label: 'eventType', + text: 'dialog.group_member_moderation.type' + }, + { + label: 'actorDisplayName', + text: 'dialog.group_member_moderation.display_name' + }, + { + label: 'description', + text: 'dialog.group_member_moderation.description' + }, + { + label: 'data', + text: 'dialog.group_member_moderation.data' + } + ], + groupLogsExportContent: '' }; _methods = { @@ -3565,6 +3596,62 @@ export default class extends baseClass { D.selectedUsers.set(member.userId, member); D.selectedUsersArray = Array.from(D.selectedUsers.values()); this.groupMemberModerationTableForceUpdate++; + }, + showGroupLogsExportDialog() { + this.$nextTick(() => + $app.adjustDialogZ(this.$refs.groupLogsExportDialogRef.$el) + ); + this.groupLogsExportContent = ''; + this.updateGrouptLogsExporContent(); + this.isGroupLogsExportDialogVisible = true; + }, + handleCopyGroupLogsExportContent(event) { + event.target.tagName === 'TEXTAREA' && event.target.select(); + navigator.clipboard + .writeText(this.groupLogsExportContent) + .then(() => { + this.$message({ + message: 'Copied successfully!', + type: 'success', + duration: 2000 + }); + }) + .catch((err) => { + console.error('Copy failed:', err); + this.$message.error('Copy failed!'); + }); + }, + updateGrouptLogsExporContent() { + const formatter = (str) => + /[\x00-\x1f,"]/.test(str) + ? `"${str.replace(/"/g, '""')}"` + : str; + + const sortedCheckedOptions = this.checkGroupsLogsExportLogsOptions + .filter((option) => + this.checkedGroupLogsExportLogsOptions.includes( + option.label + ) + ) + .map((option) => option.label); + + const header = sortedCheckedOptions.join(',') + '\n'; + + const content = this.groupLogsModerationTable.data + .map((item) => + sortedCheckedOptions + .map((key) => + formatter( + key === 'data' + ? JSON.stringify(item[key]) + : item[key] + ) + ) + .join(',') + ) + .join('\n'); + + this.groupLogsExportContent = header + content; } }; } diff --git a/src/localization/en/en.json b/src/localization/en/en.json index fd48cef9..5fc24fec 100644 --- a/src/localization/en/en.json +++ b/src/localization/en/en.json @@ -1490,7 +1490,8 @@ "choose_roles_placeholder": "Choose Roles", "selected_roles": "Selected Roles", "remove_roles": "Remove Roles", - "add_roles": "Add Roles" + "add_roles": "Add Roles", + "export_logs": "Export Logs" }, "group_post_edit": { "header": "Create/Edit Post", diff --git a/src/mixins/dialogs/groups.pug b/src/mixins/dialogs/groups.pug index 4db1533f..d9f05d0d 100644 --- a/src/mixins/dialogs/groups.pug +++ b/src/mixins/dialogs/groups.pug @@ -234,12 +234,16 @@ mixin groups() el-button(type="default" @click="getAllGroupLogs(groupMemberModeration.id)" size="mini" icon="el-icon-refresh" :loading="isGroupMembersLoading" circle) span(style="font-size:14px;margin-left:5px;margin-right:5px") {{ groupLogsModerationTable.data.length }} br - el-select(v-model="groupMemberModeration.selectedAuditLogTypes" multiple collapse-tags :placeholder="$t('dialog.group_member_moderation.filter_type')") - el-option-group(:label="$t('dialog.group_member_moderation.select_type')") - el-option.x-friend-item(v-for="type in groupMemberModeration.auditLogTypes" :key="type" :label="getAuditLogTypeName(type)" :value="type") - .detail - span.name(v-text="getAuditLogTypeName(type)") - el-input(v-model="groupLogsModerationTable.filters[0].value" :placeholder="$t('dialog.group_member_moderation.search_placeholder')" style="display:inline-block;width:150px;margin:10px") + div(style="display:flex;justify-content:space-between;align-items:center") + div + el-select(v-model="groupMemberModeration.selectedAuditLogTypes" multiple collapse-tags :placeholder="$t('dialog.group_member_moderation.filter_type')") + el-option-group(:label="$t('dialog.group_member_moderation.select_type')") + el-option.x-friend-item(v-for="type in groupMemberModeration.auditLogTypes" :key="type" :label="getAuditLogTypeName(type)" :value="type") + .detail + span.name(v-text="getAuditLogTypeName(type)") + el-input(v-model="groupLogsModerationTable.filters[0].value" :placeholder="$t('dialog.group_member_moderation.search_placeholder')" style="display:inline-block;width:150px;margin:10px") + div + el-button(@click="showGroupLogsExportDialog") {{ $t('dialog.group_member_moderation.export_logs') }} br data-tables(v-bind="groupLogsModerationTable" style="margin-top:10px") el-table-column(:label="$t('dialog.group_member_moderation.created_at')" width="170" prop="created_at" sortable) @@ -332,3 +336,11 @@ mixin groups() el-button(size="small" @click="groupPostEditDialog.visible = false") {{ $t('dialog.group_post_edit.cancel') }} el-button(v-if="groupPostEditDialog.postId" size="small" @click="editGroupPost") {{ $t('dialog.group_post_edit.edit_post') }} el-button(v-else size="small" @click="createGroupPost") {{ $t('dialog.group_post_edit.create_post') }} + + //- dialog: export logs + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" :visible.sync="isGroupLogsExportDialogVisible" :title="$t('dialog.group_member_moderation.export_logs')" width="650px" ref="groupLogsExportDialogRef" ) + el-checkbox-group(v-model="checkedGroupLogsExportLogsOptions" @change="updateGrouptLogsExporContent()" style="margin-bottom:10px") + template(v-for="option in checkGroupsLogsExportLogsOptions" :key="option.label") + el-checkbox(:label="option.label") {{ $t(option.text) }} + br + el-input(type="textarea" v-model="groupLogsExportContent" size="mini" rows="15" resize="none" readonly style="margin-top:15px" @click.native="handleCopyGroupLogsExportContent")