|
|
@@ -34,13 +34,19 @@
|
|
|
{{ classNameOf(row.classId) }}
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
+ <el-table-column label="校友校验" width="100">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ <el-tag :type="alumniType(row.alumniVerify)" size="small">{{ alumniLabel(row.alumniVerify) }}</el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
<el-table-column prop="status" label="状态" width="90">
|
|
|
<template slot-scope="{ row }">
|
|
|
<el-tag :type="row.status === 'active' ? 'success' : 'danger'" size="small">{{ row.status === 'active' ? '已激活' : '已禁用' }}</el-tag>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="操作" width="220" fixed="right">
|
|
|
+ <el-table-column label="操作" width="280" fixed="right">
|
|
|
<template slot-scope="{ row }">
|
|
|
+ <el-button size="mini" type="primary" plain @click="openDetail(row)">详情</el-button>
|
|
|
<el-button size="mini" @click="toggleStatus(row)">{{ row.status === 'active' ? '禁用' : '激活' }}</el-button>
|
|
|
<el-button size="mini" type="warning" @click="openMoveClass(row)">调整班级</el-button>
|
|
|
</template>
|
|
|
@@ -57,28 +63,105 @@
|
|
|
style="margin-top:16px;text-align:right"
|
|
|
/>
|
|
|
|
|
|
- <el-dialog title="调整班级" :visible.sync="moveVisible" width="420px" @closed="moveForm = { uid: null, classId: null }">
|
|
|
- <el-form label-width="80px">
|
|
|
- <el-form-item label="学员">
|
|
|
- <span>{{ moveUserName }}</span>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="目标班级">
|
|
|
- <el-select v-model="moveForm.classId" placeholder="不选则移出班级(退班)" clearable style="width:100%">
|
|
|
- <el-option v-for="c in classes" :key="c.id" :label="c.name" :value="c.id" />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- <div class="tips">留空提交即学员退班,将同时清空其报名单班次</div>
|
|
|
- </el-form>
|
|
|
- <span slot="footer" class="dialog-footer">
|
|
|
- <el-button @click="moveVisible = false">取 消</el-button>
|
|
|
- <el-button type="primary" :loading="moveSubmitting" @click="handleMoveClass">确 定</el-button>
|
|
|
- </span>
|
|
|
- </el-dialog>
|
|
|
+<el-dialog title="调整班级" :visible.sync="moveVisible" width="420px" @closed="moveForm = { uid: null, classId: null }">
|
|
|
+ <el-form label-width="80px">
|
|
|
+ <el-form-item label="学员">
|
|
|
+ <span>{{ moveUserName }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="目标班级">
|
|
|
+ <el-select v-model="moveForm.classId" placeholder="不选则移出班级(退班)" clearable style="width:100%">
|
|
|
+ <el-option v-for="c in classes" :key="c.id" :label="c.name" :value="c.id" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <div class="tips">留空提交即学员退班,将同时清空其报名单班次</div>
|
|
|
+ </el-form>
|
|
|
+ <span slot="footer" class="dialog-footer">
|
|
|
+ <el-button @click="moveVisible = false">取 消</el-button>
|
|
|
+ <el-button type="primary" :loading="moveSubmitting" @click="handleMoveClass">确 定</el-button>
|
|
|
+ </span>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 学员详情弹窗 -->
|
|
|
+ <el-dialog :title="'学员详情 - ' + (detailUser && detailUser.name ? detailUser.name : '')" :visible.sync="detailVisible" width="820px" top="6vh">
|
|
|
+ <div v-loading="detailLoading">
|
|
|
+ <div class="detail-section" v-if="detailUser">
|
|
|
+ <h4>基本信息</h4>
|
|
|
+ <el-descriptions :column="3" size="small" border>
|
|
|
+ <el-descriptions-item label="用户ID">{{ detailUser.id }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="姓名">{{ detailUser.name }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="手机">{{ detailUser.phone || '-' }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="角色">{{ roleLabel[detailUser.role] || detailUser.role || '-' }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="班级">{{ classNameOf(detailUser.classId) }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="分组">{{ detailUser.groupName || '-' }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="校友校验">
|
|
|
+ <el-tag :type="alumniType(detailUser.alumniVerify)" size="small">{{ alumniLabel(detailUser.alumniVerify) }}</el-tag>
|
|
|
+ </el-descriptions-item>
|
|
|
+ <el-descriptions-item label="状态">
|
|
|
+ <el-tag :type="detailUser.status === 'active' ? 'success' : 'danger'" size="small">{{ detailUser.status === 'active' ? '已激活' : '已禁用' }}</el-tag>
|
|
|
+ </el-descriptions-item>
|
|
|
+ <el-descriptions-item label="邀请码">{{ detailUser.inviteCode || '-' }}</el-descriptions-item>
|
|
|
+ </el-descriptions>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="detail-section">
|
|
|
+ <h4>报名单</h4>
|
|
|
+ <el-table :data="detailEnrollments" size="small" border stripe style="width:100%">
|
|
|
+ <el-table-column prop="id" label="ID" width="70" />
|
|
|
+ <el-table-column prop="courseId" label="课程ID" width="80" />
|
|
|
+ <el-table-column label="状态" width="110">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ <el-tag :type="enrollStatusType(row.status)" size="small">{{ enrollStatusLabel(row.status) }}</el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="createdAt" label="报名时间" width="160" />
|
|
|
+ <el-table-column prop="source" label="来源" width="80">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ {{ row.source === 'invite' ? '邀请' : '场景' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="detail-section">
|
|
|
+ <h4>卡券</h4>
|
|
|
+ <el-table :data="detailCoupons" size="small" border stripe style="width:100%">
|
|
|
+ <el-table-column prop="id" label="ID" width="70" />
|
|
|
+ <el-table-column prop="type" label="类型" width="90" />
|
|
|
+ <el-table-column prop="code" label="卡券码" min-width="130" />
|
|
|
+ <el-table-column label="状态" width="90">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ <el-tag :type="couponStatusType(row.status)" size="small">{{ couponStatusLabel(row.status) }}</el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="trigger" label="来源" width="90" />
|
|
|
+ <el-table-column prop="grantedAt" label="发放时间" width="160" />
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="detail-section">
|
|
|
+ <h4>完课证书进度(离场验收六项)</h4>
|
|
|
+ <div v-if="detailCert">
|
|
|
+ <el-alert :title="detailCert.eligible ? '已达标:可领取完课证书' : '未达标:完成以下全部项目后可领取证书'" :type="detailCert.eligible ? 'success' : 'warning'" :closable="false" show-icon style="margin-bottom:10px" />
|
|
|
+ <el-table :data="detailCert.items || []" size="small" border stripe style="width:100%">
|
|
|
+ <el-table-column prop="label" label="校验项" min-width="200" />
|
|
|
+ <el-table-column label="状态" width="120">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ <el-tag :type="row.ok ? 'success' : 'info'" size="small">{{ row.ok ? '已完成' : '未完成' }}</el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <span slot="footer">
|
|
|
+ <el-button @click="detailVisible = false">关 闭</el-button>
|
|
|
+ </span>
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import { userList, setUserStatus } from '@/api/user'
|
|
|
+import { userList, setUserStatus, userDetail } from '@/api/user'
|
|
|
import { classList, moveUserClass } from '@/api/class'
|
|
|
|
|
|
export default {
|
|
|
@@ -97,7 +180,13 @@ export default {
|
|
|
moveUserName: '',
|
|
|
moveSubmitting: false,
|
|
|
roleLabel: { student: '学员', assistant: '助教', lecturer: '讲师', admin: '管理员' },
|
|
|
- roleTagMap: { student: 'info', assistant: 'warning', lecturer: '', admin: 'danger' }
|
|
|
+ roleTagMap: { student: 'info', assistant: 'warning', lecturer: '', admin: 'danger' },
|
|
|
+ detailVisible: false,
|
|
|
+ detailLoading: false,
|
|
|
+ detailUser: null,
|
|
|
+ detailEnrollments: [],
|
|
|
+ detailCoupons: [],
|
|
|
+ detailCert: null
|
|
|
}
|
|
|
},
|
|
|
mounted: function () {
|
|
|
@@ -119,6 +208,54 @@ export default {
|
|
|
})
|
|
|
return c ? c.name : '-'
|
|
|
},
|
|
|
+ alumniType: function (v) {
|
|
|
+ if (v === 'accepted') return 'success'
|
|
|
+ if (v === 'pending') return 'warning'
|
|
|
+ if (v === 'rejected') return 'danger'
|
|
|
+ return 'info'
|
|
|
+ },
|
|
|
+ alumniLabel: function (v) {
|
|
|
+ if (v === 'accepted') return '已认证'
|
|
|
+ if (v === 'pending') return '待认证'
|
|
|
+ if (v === 'rejected') return '未通过'
|
|
|
+ return '未校验'
|
|
|
+ },
|
|
|
+ enrollStatusType: function (s) {
|
|
|
+ var map = { confirmed: 'success', paid: '', reviewing: 'warning', pending: 'info', rejected: 'danger', cancelled: 'info' }
|
|
|
+ return map[s] || 'info'
|
|
|
+ },
|
|
|
+ enrollStatusLabel: function (s) {
|
|
|
+ var map = { pending: '待支付', paid: '已支付', reviewing: '进班待审核', confirmed: '已进班', rejected: '进班被拒', cancelled: '已取消' }
|
|
|
+ return map[s] || s || '-'
|
|
|
+ },
|
|
|
+ couponStatusType: function (s) {
|
|
|
+ var map = { unused: 'success', used: 'info', expired: 'danger' }
|
|
|
+ return map[s] || 'info'
|
|
|
+ },
|
|
|
+ couponStatusLabel: function (s) {
|
|
|
+ var map = { unused: '未使用', used: '已使用', expired: '已过期' }
|
|
|
+ return map[s] || s || '-'
|
|
|
+ },
|
|
|
+ openDetail: function (row) {
|
|
|
+ var self = this
|
|
|
+ self.detailVisible = true
|
|
|
+ self.detailLoading = true
|
|
|
+ self.detailUser = row
|
|
|
+ self.detailEnrollments = []
|
|
|
+ self.detailCoupons = []
|
|
|
+ self.detailCert = null
|
|
|
+ userDetail(row.id).then(function (res) {
|
|
|
+ var data = res.data || {}
|
|
|
+ self.detailUser = data.user || row
|
|
|
+ self.detailEnrollments = data.enrollments || []
|
|
|
+ self.detailCoupons = data.coupons || []
|
|
|
+ self.detailCert = data.cert || null
|
|
|
+ }).catch(function () {
|
|
|
+ self.$message.error('获取学员详情失败')
|
|
|
+ }).finally(function () {
|
|
|
+ self.detailLoading = false
|
|
|
+ })
|
|
|
+ },
|
|
|
fetchList: function () {
|
|
|
var self = this
|
|
|
self.loading = true
|
|
|
@@ -198,4 +335,17 @@ export default {
|
|
|
margin-top: 8px;
|
|
|
line-height: 1.4;
|
|
|
}
|
|
|
+
|
|
|
+.detail-section {
|
|
|
+ margin-bottom: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-section h4 {
|
|
|
+ margin: 0 0 10px;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #303133;
|
|
|
+ border-left: 3px solid #409eff;
|
|
|
+ padding-left: 8px;
|
|
|
+}
|
|
|
</style>
|