|
...
|
...
|
@@ -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> |
...
|
...
|
|