|
@@ -43,6 +43,10 @@ |
|
@@ -43,6 +43,10 @@ |
|
43
|
<el-button type="info" plain icon="el-icon-download" size="mini" @click="handleBatchDownload"
|
43
|
<el-button type="info" plain icon="el-icon-download" size="mini" @click="handleBatchDownload"
|
|
44
|
:disabled="multiple" v-hasPermi="['xvisit:meetingattendance:downloadZip']">{{ $t('meetatt.batch_download') }}</el-button>
|
44
|
:disabled="multiple" v-hasPermi="['xvisit:meetingattendance:downloadZip']">{{ $t('meetatt.batch_download') }}</el-button>
|
|
45
|
</el-col>
|
45
|
</el-col>
|
|
|
|
46
|
+ <el-col :span="1.5">
|
|
|
|
47
|
+ <el-button type="primary" plain icon="el-icon-user" size="mini" @click="openAddAttendeeDialog"
|
|
|
|
48
|
+ v-hasPermi="['xvisit:meetingattendance:add']">{{ $t('meetatt.add_attendees') }}</el-button>
|
|
|
|
49
|
+ </el-col>
|
|
46
|
</el-row>
|
50
|
</el-row>
|
|
47
|
|
51
|
|
|
48
|
<el-table v-loading="loading" :data="meetingattendanceList" @selection-change="handleSelectionChange">
|
52
|
<el-table v-loading="loading" :data="meetingattendanceList" @selection-change="handleSelectionChange">
|
|
@@ -62,6 +66,7 @@ |
|
@@ -62,6 +66,7 @@ |
|
62
|
<template #default="scope">
|
66
|
<template #default="scope">
|
|
63
|
<el-tag v-if="scope.row.paySts == '0'">{{ $t('meetatt.pay_sts_0') }}</el-tag>
|
67
|
<el-tag v-if="scope.row.paySts == '0'">{{ $t('meetatt.pay_sts_0') }}</el-tag>
|
|
64
|
<el-tag v-else-if="scope.row.paySts == '1'">{{ $t('meetatt.pay_sts_1') }}</el-tag>
|
68
|
<el-tag v-else-if="scope.row.paySts == '1'">{{ $t('meetatt.pay_sts_1') }}</el-tag>
|
|
|
|
69
|
+ <el-tag v-else>{{ $t('meetatt.pay_sts_0') }}</el-tag>
|
|
65
|
</template>
|
70
|
</template>
|
|
66
|
</el-table-column>
|
71
|
</el-table-column>
|
|
67
|
<el-table-column :label="$t('meetatt.code')" align="center" prop="attendeeCode" />
|
72
|
<el-table-column :label="$t('meetatt.code')" align="center" prop="attendeeCode" />
|
|
@@ -119,7 +124,9 @@ |
|
@@ -119,7 +124,9 @@ |
|
119
|
v-hasPermi="['xvisit:meetingattendance:edit']">{{ $t('meetatt.edit') }}</el-button>
|
124
|
v-hasPermi="['xvisit:meetingattendance:edit']">{{ $t('meetatt.edit') }}</el-button>
|
|
120
|
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
|
125
|
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
|
|
121
|
v-hasPermi="['xvisit:meetingattendance:remove']">{{ $t('meetatt.del') }}</el-button>
|
126
|
v-hasPermi="['xvisit:meetingattendance:remove']">{{ $t('meetatt.del') }}</el-button>
|
|
122
|
- <el-button size="mini" type="text" icon="el-icon-download" @click="handleDownload(scope.row)"
|
127
|
+ <el-button
|
|
|
|
128
|
+ v-if="scope.row.conferencePassZhBase64 || scope.row.conferencePassJaBase64"
|
|
|
|
129
|
+ size="mini" type="text" icon="el-icon-download" @click="handleDownload(scope.row)"
|
|
123
|
v-hasPermi="['xvisit:meetingattendance:download']">{{ $t('meetatt.download') }}</el-button>
|
130
|
v-hasPermi="['xvisit:meetingattendance:download']">{{ $t('meetatt.download') }}</el-button>
|
|
124
|
</template>
|
131
|
</template>
|
|
125
|
</el-table-column>
|
132
|
</el-table-column>
|
|
@@ -128,6 +135,47 @@ |
|
@@ -128,6 +135,47 @@ |
|
128
|
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
|
135
|
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
|
|
129
|
@pagination="getList" />
|
136
|
@pagination="getList" />
|
|
130
|
|
137
|
|
|
|
|
138
|
+ <!-- 添加参会人员对话框 -->
|
|
|
|
139
|
+ <el-dialog :title="$t('meetatt.add_attendees')" :visible.sync="addAttendeeDialogVisible" width="800px">
|
|
|
|
140
|
+ <el-form :model="form" label-width="100px">
|
|
|
|
141
|
+ <el-form-item :label="$t('meetatt.select_meeting')" prop="meetingId">
|
|
|
|
142
|
+ <el-select
|
|
|
|
143
|
+ v-model="selectedMeeting"
|
|
|
|
144
|
+ :placeholder="$t('meetatt.select_meeting')"
|
|
|
|
145
|
+ @change="handleMeetingChange"
|
|
|
|
146
|
+ style="width: 100%"
|
|
|
|
147
|
+ >
|
|
|
|
148
|
+ <el-option
|
|
|
|
149
|
+ v-for="item in meetingOptions"
|
|
|
|
150
|
+ :key="item.value"
|
|
|
|
151
|
+ :label="item.label"
|
|
|
|
152
|
+ :value="item.value">
|
|
|
|
153
|
+ </el-option>
|
|
|
|
154
|
+ </el-select>
|
|
|
|
155
|
+ </el-form-item>
|
|
|
|
156
|
+
|
|
|
|
157
|
+ <el-form-item :label="$t('meetatt.participants')">
|
|
|
|
158
|
+ <el-transfer
|
|
|
|
159
|
+ v-model="selectedAttendees"
|
|
|
|
160
|
+ :data="transferData"
|
|
|
|
161
|
+ :titles="$t('meetatt.participants_title')"
|
|
|
|
162
|
+ :props="{
|
|
|
|
163
|
+ key: 'attendeeId',
|
|
|
|
164
|
+ label: 'name'
|
|
|
|
165
|
+ }"
|
|
|
|
166
|
+ filterable
|
|
|
|
167
|
+ :filter-placeholder="$t('meetatt.name')"
|
|
|
|
168
|
+ @change="handleTransferChange"
|
|
|
|
169
|
+ />
|
|
|
|
170
|
+ </el-form-item>
|
|
|
|
171
|
+ </el-form>
|
|
|
|
172
|
+
|
|
|
|
173
|
+ <div slot="footer" class="dialog-footer">
|
|
|
|
174
|
+ <el-button type="primary" @click="submitAddAttendees">{{ $t('meetatt.submit') }}</el-button>
|
|
|
|
175
|
+ <el-button @click="addAttendeeDialogVisible = false">{{ $t('meetatt.cancel') }}</el-button>
|
|
|
|
176
|
+ </div>
|
|
|
|
177
|
+ </el-dialog>
|
|
|
|
178
|
+
|
|
131
|
<!-- 添加会议状态对话框 -->
|
179
|
<!-- 添加会议状态对话框 -->
|
|
132
|
<el-dialog :title="title" :visible.sync="open" width="400px" append-to-body>
|
180
|
<el-dialog :title="title" :visible.sync="open" width="400px" append-to-body>
|
|
133
|
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
181
|
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
|
@@ -191,7 +239,11 @@ import { |
|
@@ -191,7 +239,11 @@ import { |
|
191
|
checkDataExists,
|
239
|
checkDataExists,
|
|
192
|
generateBadges,
|
240
|
generateBadges,
|
|
193
|
downloadBadge,
|
241
|
downloadBadge,
|
|
194
|
- downloadBadgeBatch
|
242
|
+ downloadBadgeBatch,
|
|
|
|
243
|
+ getAttendeesForMeeting,
|
|
|
|
244
|
+ batchAddAttendees,
|
|
|
|
245
|
+ getAttendeesStatus,
|
|
|
|
246
|
+ batchUpdateAttendees
|
|
195
|
} from "@/api/xvisit/meetingattendance";
|
247
|
} from "@/api/xvisit/meetingattendance";
|
|
196
|
|
248
|
|
|
197
|
import { listMeeting } from "@/api/xvisit/meeting";
|
249
|
import { listMeeting } from "@/api/xvisit/meeting";
|
|
@@ -201,6 +253,23 @@ export default { |
|
@@ -201,6 +253,23 @@ export default { |
|
201
|
name: "Meetingattendance",
|
253
|
name: "Meetingattendance",
|
|
202
|
data() {
|
254
|
data() {
|
|
203
|
return {
|
255
|
return {
|
|
|
|
256
|
+ addAttendeeDialogVisible: false,
|
|
|
|
257
|
+ selectedMeeting: null,
|
|
|
|
258
|
+ meetingOptions: [],
|
|
|
|
259
|
+ // 穿梭框数据
|
|
|
|
260
|
+ selectedAttendees: [], // 选中的参会人员ID数组
|
|
|
|
261
|
+ attendingAttendees: [], // 已参会人员
|
|
|
|
262
|
+ nonAttendingAttendees: [], // 未参会人员
|
|
|
|
263
|
+ transferData: [] ,
|
|
|
|
264
|
+
|
|
|
|
265
|
+ leftAttendees: [], // 左侧:已参会人员(attending)
|
|
|
|
266
|
+ rightAttendees: [], // 右侧:未参会人员(nonAttending)
|
|
|
|
267
|
+ allAttendees: [], // 所有人员数据(供穿梭框内部使用)
|
|
|
|
268
|
+ transferProps: {
|
|
|
|
269
|
+ key: 'attendeeId',
|
|
|
|
270
|
+ label: 'name',
|
|
|
|
271
|
+ disabled: 'disabled'
|
|
|
|
272
|
+ },
|
|
204
|
// 遮罩层
|
273
|
// 遮罩层
|
|
205
|
loading: true,
|
274
|
loading: true,
|
|
206
|
// 选中数组
|
275
|
// 选中数组
|
|
@@ -268,6 +337,8 @@ export default { |
|
@@ -268,6 +337,8 @@ export default { |
|
268
|
},
|
337
|
},
|
|
269
|
//add 0 upd 1
|
338
|
//add 0 upd 1
|
|
270
|
sts: 0,
|
339
|
sts: 0,
|
|
|
|
340
|
+ toAdd:[],
|
|
|
|
341
|
+ toRemove:[]
|
|
271
|
};
|
342
|
};
|
|
272
|
},
|
343
|
},
|
|
273
|
|
344
|
|
|
@@ -279,6 +350,116 @@ export default { |
|
@@ -279,6 +350,116 @@ export default { |
|
279
|
},
|
350
|
},
|
|
280
|
|
351
|
|
|
281
|
methods: {
|
352
|
methods: {
|
|
|
|
353
|
+
|
|
|
|
354
|
+ // 打开添加参会人员对话框
|
|
|
|
355
|
+ openAddAttendeeDialog() {
|
|
|
|
356
|
+ this.toAdd = [];
|
|
|
|
357
|
+ this.toRemove = [];
|
|
|
|
358
|
+ this.addAttendeeDialogVisible = true;
|
|
|
|
359
|
+ this.selectedMeeting = null;
|
|
|
|
360
|
+ this.selectedAttendees = [];
|
|
|
|
361
|
+ this.attendingAttendees = [];
|
|
|
|
362
|
+ this.nonAttendingAttendees = [];
|
|
|
|
363
|
+ this.transferData = [];
|
|
|
|
364
|
+
|
|
|
|
365
|
+ // 加载会议列表
|
|
|
|
366
|
+ listMeeting({ pageNum: 1, pageSize: 1000 }).then(response => {
|
|
|
|
367
|
+ this.meetingOptions = response.rows.map(item => ({
|
|
|
|
368
|
+ value: item.meetingId,
|
|
|
|
369
|
+ label: item.meetingName
|
|
|
|
370
|
+ }));
|
|
|
|
371
|
+ });
|
|
|
|
372
|
+ },
|
|
|
|
373
|
+
|
|
|
|
374
|
+ // 会议选择变化时触发
|
|
|
|
375
|
+ handleMeetingChange(meetingId) {
|
|
|
|
376
|
+ if (!meetingId) {
|
|
|
|
377
|
+ this.attendingAttendees = [];
|
|
|
|
378
|
+ this.nonAttendingAttendees = [];
|
|
|
|
379
|
+ this.transferData = [];
|
|
|
|
380
|
+ this.selectedAttendees = [];
|
|
|
|
381
|
+ return;
|
|
|
|
382
|
+ }
|
|
|
|
383
|
+
|
|
|
|
384
|
+ // 获取参会人员状态
|
|
|
|
385
|
+ getAttendeesStatus(meetingId).then(response => {
|
|
|
|
386
|
+ if (response.code === 200) {
|
|
|
|
387
|
+ // 已参会人员
|
|
|
|
388
|
+ this.attendingAttendees = response.data.attending || [];
|
|
|
|
389
|
+ // 未参会人员
|
|
|
|
390
|
+ this.nonAttendingAttendees = response.data.nonAttending || [];
|
|
|
|
391
|
+
|
|
|
|
392
|
+ // 更新穿梭框数据:未参会人员在前,已参会人员在后
|
|
|
|
393
|
+ this.transferData = [
|
|
|
|
394
|
+ ...this.nonAttendingAttendees,
|
|
|
|
395
|
+ ...this.attendingAttendees
|
|
|
|
396
|
+ ];
|
|
|
|
397
|
+
|
|
|
|
398
|
+ // 默认选中未参会人员
|
|
|
|
399
|
+ this.selectedAttendees = this.nonAttendingAttendees.map(item => item.attendeeId);
|
|
|
|
400
|
+ }
|
|
|
|
401
|
+ });
|
|
|
|
402
|
+ },
|
|
|
|
403
|
+ // 穿梭框数据变化时触发
|
|
|
|
404
|
+ handleTransferChange(newSelectedAttendees, direction, movedKeys) {
|
|
|
|
405
|
+ //新增
|
|
|
|
406
|
+ if (direction === 'left'){
|
|
|
|
407
|
+ if (this.toRemove.includes(movedKeys)) {
|
|
|
|
408
|
+ const index = this.toRemove.indexOf(movedKeys);
|
|
|
|
409
|
+ if (index !== -1) {
|
|
|
|
410
|
+ this.toRemove.splice(index, 1); // 删除该元素
|
|
|
|
411
|
+ }
|
|
|
|
412
|
+ }
|
|
|
|
413
|
+ this.toAdd.push(movedKeys)
|
|
|
|
414
|
+ }
|
|
|
|
415
|
+ //删除
|
|
|
|
416
|
+ if (direction === 'right'){
|
|
|
|
417
|
+ if (this.toAdd.includes(movedKeys)) {
|
|
|
|
418
|
+ const index = this.toAdd.indexOf(movedKeys);
|
|
|
|
419
|
+ if (index !== -1) {
|
|
|
|
420
|
+ this.toAdd.splice(index, 1); // 删除该元素
|
|
|
|
421
|
+ }
|
|
|
|
422
|
+ }
|
|
|
|
423
|
+ this.toRemove.push(movedKeys)
|
|
|
|
424
|
+ }
|
|
|
|
425
|
+
|
|
|
|
426
|
+
|
|
|
|
427
|
+ // 不需要额外处理,selectedAttendees会自动更新
|
|
|
|
428
|
+ },
|
|
|
|
429
|
+
|
|
|
|
430
|
+ // 提交添加参会人员
|
|
|
|
431
|
+ submitAddAttendees() {
|
|
|
|
432
|
+ if (!this.selectedMeeting) {
|
|
|
|
433
|
+ this.$modal.msgError('请选择会议');
|
|
|
|
434
|
+ return;
|
|
|
|
435
|
+ }
|
|
|
|
436
|
+
|
|
|
|
437
|
+ console.log(" this.toAdd", this.toAdd)
|
|
|
|
438
|
+ console.log(" this.toRemove", this.toRemove)
|
|
|
|
439
|
+
|
|
|
|
440
|
+
|
|
|
|
441
|
+ // 将数组转换为字符串
|
|
|
|
442
|
+ const toAddString = this.toAdd.join(',');
|
|
|
|
443
|
+ const toRemoveString = this.toRemove.join(',');
|
|
|
|
444
|
+
|
|
|
|
445
|
+ if (!toAddString && !toRemoveString) {
|
|
|
|
446
|
+ this.$modal.msgWarning('没有变更的参会人员');
|
|
|
|
447
|
+ return;
|
|
|
|
448
|
+ }
|
|
|
|
449
|
+ console.log("toRemoveString",toRemoveString)
|
|
|
|
450
|
+ // 调用API批量更新
|
|
|
|
451
|
+ batchUpdateAttendees({
|
|
|
|
452
|
+ meetingId: this.selectedMeeting,
|
|
|
|
453
|
+ addAttendeeIds: toAddString,
|
|
|
|
454
|
+ removeAttendeeIds: toRemoveString
|
|
|
|
455
|
+ }).then(response => {
|
|
|
|
456
|
+ if (response.code === 200) {
|
|
|
|
457
|
+ this.$modal.msgSuccess('参会人员更新成功');
|
|
|
|
458
|
+ this.addAttendeeDialogVisible = false;
|
|
|
|
459
|
+ this.getList(); // 刷新列表
|
|
|
|
460
|
+ }
|
|
|
|
461
|
+ });
|
|
|
|
462
|
+ },
|
|
282
|
/** 批量下载参会证按钮操作 */
|
463
|
/** 批量下载参会证按钮操作 */
|
|
283
|
handleBatchDownload() {
|
464
|
handleBatchDownload() {
|
|
284
|
if (this.ids.length === 0) {
|
465
|
if (this.ids.length === 0) {
|
|
@@ -572,6 +753,7 @@ export default { |
|
@@ -572,6 +753,7 @@ export default { |
|
572
|
generateBadges(params).then(res => {
|
753
|
generateBadges(params).then(res => {
|
|
573
|
if (res.code === 200) {
|
754
|
if (res.code === 200) {
|
|
574
|
this.$modal.msgSuccess("参会证生成成功");
|
755
|
this.$modal.msgSuccess("参会证生成成功");
|
|
|
|
756
|
+ this.getList();
|
|
575
|
} else {
|
757
|
} else {
|
|
576
|
this.$modal.msgError(res.msg);
|
758
|
this.$modal.msgError(res.msg);
|
|
577
|
}
|
759
|
}
|
|
@@ -617,4 +799,90 @@ export default { |
|
@@ -617,4 +799,90 @@ export default { |
|
617
|
.no-image {
|
799
|
.no-image {
|
|
618
|
color: #999;
|
800
|
color: #999;
|
|
619
|
}
|
801
|
}
|
|
|
|
802
|
+
|
|
|
|
803
|
+.transfer-footer {
|
|
|
|
804
|
+ padding: 6px 12px;
|
|
|
|
805
|
+ text-align: center;
|
|
|
|
806
|
+ color: #666;
|
|
|
|
807
|
+ border-top: 1px solid #ebeef5;
|
|
|
|
808
|
+}
|
|
|
|
809
|
+
|
|
|
|
810
|
+
|
|
|
|
811
|
+.transfer-panel__header {
|
|
|
|
812
|
+ padding: 10px;
|
|
|
|
813
|
+ background-color: #f5f7fa;
|
|
|
|
814
|
+ border-bottom: 1px solid #ebeef5;
|
|
|
|
815
|
+ font-weight: bold;
|
|
|
|
816
|
+}
|
|
|
|
817
|
+
|
|
|
|
818
|
+
|
|
|
|
819
|
+
|
|
|
|
820
|
+.transfer-item {
|
|
|
|
821
|
+ padding: 8px 10px;
|
|
|
|
822
|
+ border-bottom: 1px solid #f0f0f0;
|
|
|
|
823
|
+ cursor: pointer;
|
|
|
|
824
|
+}
|
|
|
|
825
|
+
|
|
|
|
826
|
+.transfer-item:hover {
|
|
|
|
827
|
+ background-color: #f5f7fa;
|
|
|
|
828
|
+}
|
|
|
|
829
|
+
|
|
|
|
830
|
+
|
|
|
|
831
|
+
|
|
|
|
832
|
+.transfer-panel__header {
|
|
|
|
833
|
+ padding: 10px;
|
|
|
|
834
|
+ background-color: #f5f7fa;
|
|
|
|
835
|
+ border-bottom: 1px solid #ebeef5;
|
|
|
|
836
|
+ font-weight: bold;
|
|
|
|
837
|
+}
|
|
|
|
838
|
+
|
|
|
|
839
|
+
|
|
|
|
840
|
+
|
|
|
|
841
|
+.transfer-item {
|
|
|
|
842
|
+ padding: 8px 10px;
|
|
|
|
843
|
+ border-bottom: 1px solid #f0f0f0;
|
|
|
|
844
|
+ cursor: pointer;
|
|
|
|
845
|
+}
|
|
|
|
846
|
+
|
|
|
|
847
|
+.transfer-item:hover {
|
|
|
|
848
|
+ background-color: #f5f7fa;
|
|
|
|
849
|
+}
|
|
|
|
850
|
+.transfer-panel {
|
|
|
|
851
|
+ height: 400px;
|
|
|
|
852
|
+ display: flex;
|
|
|
|
853
|
+ flex-direction: column;
|
|
|
|
854
|
+}
|
|
|
|
855
|
+
|
|
|
|
856
|
+.transfer-panel__body {
|
|
|
|
857
|
+ flex: 1;
|
|
|
|
858
|
+ overflow-y: auto;
|
|
|
|
859
|
+ padding: 10px;
|
|
|
|
860
|
+}
|
|
|
|
861
|
+
|
|
|
|
862
|
+.transfer-panel {
|
|
|
|
863
|
+ border: 1px solid #ebeef5;
|
|
|
|
864
|
+ border-radius: 4px;
|
|
|
|
865
|
+ overflow: hidden;
|
|
|
|
866
|
+ height: 400px;
|
|
|
|
867
|
+ display: flex;
|
|
|
|
868
|
+ flex-direction: column;
|
|
|
|
869
|
+}
|
|
|
|
870
|
+
|
|
|
|
871
|
+.transfer-panel__header {
|
|
|
|
872
|
+ padding: 10px;
|
|
|
|
873
|
+ background-color: #f5f7fa;
|
|
|
|
874
|
+ border-bottom: 1px solid #ebeef5;
|
|
|
|
875
|
+ font-weight: bold;
|
|
|
|
876
|
+}
|
|
|
|
877
|
+
|
|
|
|
878
|
+.transfer-panel__body {
|
|
|
|
879
|
+ flex: 1;
|
|
|
|
880
|
+ overflow-y: auto;
|
|
|
|
881
|
+ padding: 10px;
|
|
|
|
882
|
+}
|
|
|
|
883
|
+
|
|
|
|
884
|
+.transfer-item {
|
|
|
|
885
|
+ padding: 8px 10px;
|
|
|
|
886
|
+ border-bottom: 1px solid #f0f0f0;
|
|
|
|
887
|
+}
|
|
620
|
</style> |
888
|
</style> |