feat: 会议提交剩余时间+解冻 + 会务/劳务材料批量下载 + 多角色人员/账号模块完善
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -37,7 +37,6 @@
|
||||
<div class="batch-bar">
|
||||
<el-button type="primary" @click="goNew">新建人员</el-button>
|
||||
<el-button @click="openImport">批量导入</el-button>
|
||||
<span class="filter-tip">*批量导入模板与列表表项一致</span>
|
||||
</div>
|
||||
|
||||
<!-- ========== 表格 ========== -->
|
||||
@@ -52,6 +51,16 @@
|
||||
<el-tag :type="statusTagType(row.status)" disable-transitions>{{ row.status === '1' ? '禁用' : '正常' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 管理员 switch: 仅 admin 可见, 指定机构管理员 (MAIN) -->
|
||||
<el-table-column v-if="isAdmin" label="管理员" width="90" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-switch
|
||||
:model-value="row.accountType === 'MAIN'"
|
||||
:disabled="switchingId === row.personId"
|
||||
@change="onChangeAdmin(row)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="260" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<!-- 查看 (只读详情): 两角色都有, 跳独立详情页 -->
|
||||
@@ -78,32 +87,42 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- ========== 批量导入 ========== -->
|
||||
<el-dialog v-model="importOpen" title="批量导入" width="520px" :close-on-click-modal="false">
|
||||
<el-form label-width="100px">
|
||||
<el-form-item label="选择文件">
|
||||
<el-upload ref="uploadRef" :auto-upload="false" :limit="1" accept=".xls,.xlsx" :on-change="onFileChange" :on-remove="onFileRemove">
|
||||
<el-button>选择文件</el-button>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="">
|
||||
<el-button link type="primary" @click="downloadTemplate">批量导入模板下载</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item><span class="filter-tip">*导入列: 姓名/手机号/所属公司/部门/职务/角色</span></el-form-item>
|
||||
</el-form>
|
||||
<!-- ========== 批量导入 (沿用 executor-people 模式: drag + 模板下载在框外 + ImportResultDialog) ========== -->
|
||||
<el-dialog v-model="importOpen" title="批量导入" width="400px" append-to-body :close-on-click-modal="false">
|
||||
<el-upload
|
||||
v-if="importOpen"
|
||||
ref="uploadRef"
|
||||
:limit="1"
|
||||
accept=".xlsx, .xls"
|
||||
:on-change="onFileChange"
|
||||
:on-remove="onFileRemove"
|
||||
:auto-upload="false"
|
||||
drag
|
||||
>
|
||||
<el-icon class="el-icon--upload"><upload /></el-icon>
|
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||
</el-upload>
|
||||
<!-- 模板下载: 必须放在 el-upload 框外(下面), 否则点击会被 drag 区域吞掉, 触发的是文件选择器 -->
|
||||
<div style="margin-top:10px;font-size:13px;text-align:center">
|
||||
<span style="color:#909399;margin-right:8px">仅允许导入 xls、xlsx 格式文件</span>
|
||||
<el-link type="primary" :underline="false" @click="downloadTemplate">下载模板</el-link>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="importOpen = false">取消</el-button>
|
||||
<el-button type="primary" :loading="importing" @click="submitImport">确定</el-button>
|
||||
<el-button @click="importOpen=false">取 消</el-button>
|
||||
<el-button type="primary" :loading="importing" @click="submitImport">确 定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<ImportResultDialog v-model="importResultOpen" :result="importResult" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, computed, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { bizList, bizUpdate, importPerson, downloadImportTemplate } from '@/api/public'
|
||||
import { bizList, bizUpdate, importPerson, downloadImportTemplate, changePersonAdmin } from '@/api/public'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Upload } from '@element-plus/icons-vue'
|
||||
import ImportResultDialog from '@/components/ImportResultDialog.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
@@ -171,6 +190,30 @@ async function onToggleStatus(row) {
|
||||
} catch (e) { ElMessage.error(e?.msg || '操作失败') }
|
||||
}
|
||||
|
||||
// ========== 更换机构管理员 (仅 admin) ==========
|
||||
const switchingId = ref('')
|
||||
async function onChangeAdmin(row) {
|
||||
// switch 受控 (:model-value), 当前管理员 (MAIN) 的 switch 恒为开, 无法直接关掉
|
||||
if (row.accountType === 'MAIN') { ElMessage.info('已是该机构管理员'); return }
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确定将「${row.name}」设为该机构管理员吗?`,
|
||||
'更换管理员',
|
||||
{ type: 'warning' }
|
||||
)
|
||||
} catch { return }
|
||||
switchingId.value = row.personId
|
||||
try {
|
||||
await changePersonAdmin(row.personId)
|
||||
ElMessage.success('已更换管理员')
|
||||
load()
|
||||
} catch (e) {
|
||||
ElMessage.error(e?.msg || e?.message || '更换失败')
|
||||
} finally {
|
||||
switchingId.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 跳转 (按角色) ==========
|
||||
function goNew() {
|
||||
router.push({
|
||||
@@ -193,8 +236,10 @@ const importOpen = ref(false)
|
||||
const importing = ref(false)
|
||||
const uploadRef = ref()
|
||||
const importFile = ref(null)
|
||||
const importResultOpen = ref(false)
|
||||
const importResult = ref(null)
|
||||
|
||||
function openImport() { importFile.value = null; importOpen.value = true }
|
||||
function openImport() { importFile.value = null; importResult.value = null; importOpen.value = true }
|
||||
function onFileChange(file) { importFile.value = file.raw }
|
||||
function onFileRemove() { importFile.value = null }
|
||||
async function downloadTemplate() {
|
||||
@@ -213,21 +258,18 @@ async function submitImport() {
|
||||
if (!importFile.value) { ElMessage.warning('请先选择文件'); return }
|
||||
importing.value = true
|
||||
try {
|
||||
const res = await importPerson('sponsor', importFile.value)
|
||||
const res = await importPerson('sponsor', importFile.value, orgId.value)
|
||||
const payload = res.data || res
|
||||
const ok = payload.ok ?? 0
|
||||
const total = payload.total ?? 0
|
||||
const failed = (payload.results || []).filter(r => !r.ok)
|
||||
if (failed.length === 0) {
|
||||
ElMessage.success(`导入成功 ${ok}/${total}`)
|
||||
} else {
|
||||
ElMessageBox.alert(
|
||||
`成功 ${ok} 条, 失败 ${failed.length} 条:\n` +
|
||||
failed.map(f => ` 第${f.rowNo}行 ${f.name || ''}: ${f.message}`).join('\n'),
|
||||
'导入结果', { type: 'warning' }
|
||||
)
|
||||
// 映射为 ImportResultDialog 期望的形状 { okNum, ngNum, ngList: [{rowNum, message}] }
|
||||
importResult.value = {
|
||||
okNum: ok,
|
||||
ngNum: failed.length,
|
||||
ngList: failed.map(f => ({ rowNum: f.rowNo, message: (f.name ? f.name + ': ' : '') + (f.message || '') }))
|
||||
}
|
||||
importOpen.value = false
|
||||
importResultOpen.value = true
|
||||
load()
|
||||
} catch (e) {
|
||||
ElMessage.error(e?.msg || '导入失败')
|
||||
|
||||
Reference in New Issue
Block a user