作者 lixiang

1、增加参会证生成功能

2、增加指定人员参会证下载功能
3、增加批量下载参会证功能
import request from '@/utils/request'
// 查询签到状态列表
export function listMeetingattendance(query) {
return request({
... ... @@ -104,3 +106,38 @@ export function downloadBadgeBatch(params) {
}
});
}
// 获取参会/未参会人员列表
export function getAttendeesForMeeting(meetingId, isAttending) {
return request({
url: '/xvisit/meetingattendance/getAttendeesForMeeting',
method: 'get',
params: { meetingId, isAttending }
})
}
// 批量添加参会人员
export function batchAddAttendees(data) {
return request({
url: '/xvisit/meetingattendance/batchAddAttendees',
method: 'post',
data: data
})
}
export function getAttendeesStatus(meetingId) {
return request({
url: '/xvisit/meetingattendance/getAttendeesStatus',
method: 'get',
params: { meetingId }
})
}
export function batchUpdateAttendees(data) {
return request({
url: '/xvisit/meetingattendance/batchUpdateAttendees',
method: 'post',
data: data
})
}
... ...
... ... @@ -227,7 +227,11 @@ export default {
},
meetatt: {
select_meeting: 'ミーティングの選択',
participants: '参会者',
participants_title: ['参加者', '未参加者'],
name: '名前',
add_attendees: '参加者を追加',
query: '検索',
reset: 'リセット',
add: '追加',
... ... @@ -238,24 +242,19 @@ export default {
del: '削除',
cancel: 'キャンセル',
submit: '確認',
add_title: '訪問者の追加',
edit_title: '訪問者の変更',
import_title: 'X',
sign_sts_0: '署名なし',
sign_sts_1: '署名あり',
pay_sts_0: '未払い',
pay_sts_1: '払い済',
add_msg: '追加サクセス',
edit_msg: '修正サクセス',
import_msg: 'インポート結果',
del_msg: '削除サクセス',
del_msgInfo: '削除しますか?',
add_msg_NG: '追加に失敗、メンバーIDは既に存在',
attendee_id: '個人ID',
attendee_name: '個人',
meeting_id: '会議ID',
... ... @@ -284,21 +283,21 @@ export default {
memo_P: 'X',
del_flag_P: 'X',
code_P: 'QRコードを入力してください',
zh_pass: "中文参会证",
ja_pass: "日文参会证",
zh_pass: "中国語参会証",
ja_pass: "日本語参会証",
attendee_id_R: '個人IDは空白にできない',
meeting_id_R: '会議IDを空にすることはできません',
generate_badge:'参加証を生成',
download: "参加証をダウンロード",
generate_badge:'参会証を生成',
download: "参会証をダウンロード",
download_zh: "中国語版",
download_ja: "日本語版",
download_confirm: "参加証をダウンロードしますか?",
download_success: "参加証のダウンロードが成功しました",
download_confirm: "参会証をダウンロードしますか?",
download_success: "参会証のダウンロードが成功しました",
download_fail: "ダウンロード失敗:",
download_fail_empty: "ダウンロード内容が空です",
download_cancel: "ダウンロードをキャンセルしました",
badge: "参証",
badge: "参証",
batch_download :"一括ダウンロード"
},
tab: {
... ...
... ... @@ -43,6 +43,10 @@
<el-button type="info" plain icon="el-icon-download" size="mini" @click="handleBatchDownload"
:disabled="multiple" v-hasPermi="['xvisit:meetingattendance:downloadZip']">{{ $t('meetatt.batch_download') }}</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-user" size="mini" @click="openAddAttendeeDialog"
v-hasPermi="['xvisit:meetingattendance:add']">{{ $t('meetatt.add_attendees') }}</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="meetingattendanceList" @selection-change="handleSelectionChange">
... ... @@ -62,6 +66,7 @@
<template #default="scope">
<el-tag v-if="scope.row.paySts == '0'">{{ $t('meetatt.pay_sts_0') }}</el-tag>
<el-tag v-else-if="scope.row.paySts == '1'">{{ $t('meetatt.pay_sts_1') }}</el-tag>
<el-tag v-else>{{ $t('meetatt.pay_sts_0') }}</el-tag>
</template>
</el-table-column>
<el-table-column :label="$t('meetatt.code')" align="center" prop="attendeeCode" />
... ... @@ -119,7 +124,9 @@
v-hasPermi="['xvisit:meetingattendance:edit']">{{ $t('meetatt.edit') }}</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['xvisit:meetingattendance:remove']">{{ $t('meetatt.del') }}</el-button>
<el-button size="mini" type="text" icon="el-icon-download" @click="handleDownload(scope.row)"
<el-button
v-if="scope.row.conferencePassZhBase64 || scope.row.conferencePassJaBase64"
size="mini" type="text" icon="el-icon-download" @click="handleDownload(scope.row)"
v-hasPermi="['xvisit:meetingattendance:download']">{{ $t('meetatt.download') }}</el-button>
</template>
</el-table-column>
... ... @@ -128,6 +135,47 @@
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
@pagination="getList" />
<!-- 添加参会人员对话框 -->
<el-dialog :title="$t('meetatt.add_attendees')" :visible.sync="addAttendeeDialogVisible" width="800px">
<el-form :model="form" label-width="100px">
<el-form-item :label="$t('meetatt.select_meeting')" prop="meetingId">
<el-select
v-model="selectedMeeting"
:placeholder="$t('meetatt.select_meeting')"
@change="handleMeetingChange"
style="width: 100%"
>
<el-option
v-for="item in meetingOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('meetatt.participants')">
<el-transfer
v-model="selectedAttendees"
:data="transferData"
:titles="$t('meetatt.participants_title')"
:props="{
key: 'attendeeId',
label: 'name'
}"
filterable
:filter-placeholder="$t('meetatt.name')"
@change="handleTransferChange"
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitAddAttendees">{{ $t('meetatt.submit') }}</el-button>
<el-button @click="addAttendeeDialogVisible = false">{{ $t('meetatt.cancel') }}</el-button>
</div>
</el-dialog>
<!-- 添加会议状态对话框 -->
<el-dialog :title="title" :visible.sync="open" width="400px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
... ... @@ -191,7 +239,11 @@ import {
checkDataExists,
generateBadges,
downloadBadge,
downloadBadgeBatch
downloadBadgeBatch,
getAttendeesForMeeting,
batchAddAttendees,
getAttendeesStatus,
batchUpdateAttendees
} from "@/api/xvisit/meetingattendance";
import { listMeeting } from "@/api/xvisit/meeting";
... ... @@ -201,6 +253,23 @@ export default {
name: "Meetingattendance",
data() {
return {
addAttendeeDialogVisible: false,
selectedMeeting: null,
meetingOptions: [],
// 穿梭框数据
selectedAttendees: [], // 选中的参会人员ID数组
attendingAttendees: [], // 已参会人员
nonAttendingAttendees: [], // 未参会人员
transferData: [] ,
leftAttendees: [], // 左侧:已参会人员(attending)
rightAttendees: [], // 右侧:未参会人员(nonAttending)
allAttendees: [], // 所有人员数据(供穿梭框内部使用)
transferProps: {
key: 'attendeeId',
label: 'name',
disabled: 'disabled'
},
// 遮罩层
loading: true,
// 选中数组
... ... @@ -268,6 +337,8 @@ export default {
},
//add 0 upd 1
sts: 0,
toAdd:[],
toRemove:[]
};
},
... ... @@ -279,6 +350,116 @@ export default {
},
methods: {
// 打开添加参会人员对话框
openAddAttendeeDialog() {
this.toAdd = [];
this.toRemove = [];
this.addAttendeeDialogVisible = true;
this.selectedMeeting = null;
this.selectedAttendees = [];
this.attendingAttendees = [];
this.nonAttendingAttendees = [];
this.transferData = [];
// 加载会议列表
listMeeting({ pageNum: 1, pageSize: 1000 }).then(response => {
this.meetingOptions = response.rows.map(item => ({
value: item.meetingId,
label: item.meetingName
}));
});
},
// 会议选择变化时触发
handleMeetingChange(meetingId) {
if (!meetingId) {
this.attendingAttendees = [];
this.nonAttendingAttendees = [];
this.transferData = [];
this.selectedAttendees = [];
return;
}
// 获取参会人员状态
getAttendeesStatus(meetingId).then(response => {
if (response.code === 200) {
// 已参会人员
this.attendingAttendees = response.data.attending || [];
// 未参会人员
this.nonAttendingAttendees = response.data.nonAttending || [];
// 更新穿梭框数据:未参会人员在前,已参会人员在后
this.transferData = [
...this.nonAttendingAttendees,
...this.attendingAttendees
];
// 默认选中未参会人员
this.selectedAttendees = this.nonAttendingAttendees.map(item => item.attendeeId);
}
});
},
// 穿梭框数据变化时触发
handleTransferChange(newSelectedAttendees, direction, movedKeys) {
//新增
if (direction === 'left'){
if (this.toRemove.includes(movedKeys)) {
const index = this.toRemove.indexOf(movedKeys);
if (index !== -1) {
this.toRemove.splice(index, 1); // 删除该元素
}
}
this.toAdd.push(movedKeys)
}
//删除
if (direction === 'right'){
if (this.toAdd.includes(movedKeys)) {
const index = this.toAdd.indexOf(movedKeys);
if (index !== -1) {
this.toAdd.splice(index, 1); // 删除该元素
}
}
this.toRemove.push(movedKeys)
}
// 不需要额外处理,selectedAttendees会自动更新
},
// 提交添加参会人员
submitAddAttendees() {
if (!this.selectedMeeting) {
this.$modal.msgError('请选择会议');
return;
}
console.log(" this.toAdd", this.toAdd)
console.log(" this.toRemove", this.toRemove)
// 将数组转换为字符串
const toAddString = this.toAdd.join(',');
const toRemoveString = this.toRemove.join(',');
if (!toAddString && !toRemoveString) {
this.$modal.msgWarning('没有变更的参会人员');
return;
}
console.log("toRemoveString",toRemoveString)
// 调用API批量更新
batchUpdateAttendees({
meetingId: this.selectedMeeting,
addAttendeeIds: toAddString,
removeAttendeeIds: toRemoveString
}).then(response => {
if (response.code === 200) {
this.$modal.msgSuccess('参会人员更新成功');
this.addAttendeeDialogVisible = false;
this.getList(); // 刷新列表
}
});
},
/** 批量下载参会证按钮操作 */
handleBatchDownload() {
if (this.ids.length === 0) {
... ... @@ -572,6 +753,7 @@ export default {
generateBadges(params).then(res => {
if (res.code === 200) {
this.$modal.msgSuccess("参会证生成成功");
this.getList();
} else {
this.$modal.msgError(res.msg);
}
... ... @@ -617,4 +799,90 @@ export default {
.no-image {
color: #999;
}
.transfer-footer {
padding: 6px 12px;
text-align: center;
color: #666;
border-top: 1px solid #ebeef5;
}
.transfer-panel__header {
padding: 10px;
background-color: #f5f7fa;
border-bottom: 1px solid #ebeef5;
font-weight: bold;
}
.transfer-item {
padding: 8px 10px;
border-bottom: 1px solid #f0f0f0;
cursor: pointer;
}
.transfer-item:hover {
background-color: #f5f7fa;
}
.transfer-panel__header {
padding: 10px;
background-color: #f5f7fa;
border-bottom: 1px solid #ebeef5;
font-weight: bold;
}
.transfer-item {
padding: 8px 10px;
border-bottom: 1px solid #f0f0f0;
cursor: pointer;
}
.transfer-item:hover {
background-color: #f5f7fa;
}
.transfer-panel {
height: 400px;
display: flex;
flex-direction: column;
}
.transfer-panel__body {
flex: 1;
overflow-y: auto;
padding: 10px;
}
.transfer-panel {
border: 1px solid #ebeef5;
border-radius: 4px;
overflow: hidden;
height: 400px;
display: flex;
flex-direction: column;
}
.transfer-panel__header {
padding: 10px;
background-color: #f5f7fa;
border-bottom: 1px solid #ebeef5;
font-weight: bold;
}
.transfer-panel__body {
flex: 1;
overflow-y: auto;
padding: 10px;
}
.transfer-item {
padding: 8px 10px;
border-bottom: 1px solid #f0f0f0;
}
</style>
... ...