修改用户设置的新增用户的权限点击操作
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Plus, Delete, Refresh } from '@element-plus/icons-vue'
|
||||
import type { TagProps, UploadRequestOptions } from 'element-plus'
|
||||
import type { TagProps, UploadRequestOptions, UploadFile } from 'element-plus'
|
||||
import PageCard from '@/components/PageCard.vue'
|
||||
import {
|
||||
getDataConvertTasks,
|
||||
@@ -16,6 +16,8 @@ const loading = ref(false)
|
||||
const tasks = ref<DataConvertTask[]>([])
|
||||
const showCreate = ref(false)
|
||||
const form = ref({ name: '', outputName: 'converted-data' })
|
||||
const fileList = ref<UploadFile[]>([])
|
||||
const creating = ref(false)
|
||||
|
||||
async function load() {
|
||||
loading.value = true
|
||||
@@ -27,21 +29,91 @@ async function load() {
|
||||
}
|
||||
}
|
||||
|
||||
// 文件上传前的校验(仅校验文件格式)
|
||||
function beforeUpload(file: UploadFile) {
|
||||
// 检查文件类型
|
||||
const isJson = file.name.endsWith('.json') || file.raw?.type === 'application/json'
|
||||
if (!isJson) {
|
||||
ElMessage.error('只能上传 .json 格式的文件')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 手动点击"创建并上传"
|
||||
async function submitCreate() {
|
||||
if (!form.value.name) {
|
||||
// 校验任务名称
|
||||
if (!form.value.name || !form.value.name.trim()) {
|
||||
ElMessage.warning('请填写任务名称')
|
||||
return
|
||||
}
|
||||
await createDataConvertTask({
|
||||
name: form.value.name,
|
||||
output_filename: form.value.outputName + '.jsonl',
|
||||
})
|
||||
ElMessage.success('任务创建成功')
|
||||
showCreate.value = false
|
||||
form.value = { name: '', outputName: 'converted-data' }
|
||||
load()
|
||||
// 检查名称是否重复
|
||||
const exists = tasks.value.some((t) => t.name === form.value.name.trim())
|
||||
if (exists) {
|
||||
ElMessage.error(`数据集管理中已存在名为「${form.value.name}」的任务,请换一个名称`)
|
||||
return
|
||||
}
|
||||
// 检查是否选择了文件
|
||||
if (!fileList.value || fileList.value.length === 0) {
|
||||
ElMessage.warning('请选择要上传的 JSON 文件')
|
||||
return
|
||||
}
|
||||
|
||||
creating.value = true
|
||||
try {
|
||||
// 1. 创建转换任务
|
||||
const task = await createDataConvertTask({
|
||||
name: form.value.name.trim(),
|
||||
output_filename: form.value.outputName.trim() + '.jsonl',
|
||||
})
|
||||
|
||||
// 2. 获取任务 ID
|
||||
const taskId = (task as any)?.id || task?.id || (task as any)?.data?.id
|
||||
if (!taskId) {
|
||||
throw new Error('创建任务失败,服务端未返回任务 ID')
|
||||
}
|
||||
|
||||
// 3. 上传文件到刚创建的任务
|
||||
const file = fileList.value[0].raw
|
||||
if (!file) {
|
||||
throw new Error('文件信息丢失,请重新选择文件')
|
||||
}
|
||||
|
||||
const res = await uploadSourceFiles(taskId, [file])
|
||||
const data = (res as any)?.data || res
|
||||
|
||||
if (data?.auto_converted) {
|
||||
ElMessage.success(
|
||||
`创建成功!文件已上传并自动转换完成(输入 ${data.input_count} 条 / 输出 ${data.output_count} 条),结果已导入数据集`,
|
||||
)
|
||||
} else if (data?.error) {
|
||||
ElMessage.error(`文件上传成功但转换失败:${data.error}`)
|
||||
} else {
|
||||
ElMessage.warning('文件已上传,等待后台转换处理...')
|
||||
}
|
||||
|
||||
// 关闭弹窗并刷新列表
|
||||
showCreate.value = false
|
||||
resetForm()
|
||||
load()
|
||||
} catch (e: any) {
|
||||
// 根据错误类型给出更清晰的提示
|
||||
const msg = e?.message || e?.toString() || '未知错误'
|
||||
if (msg.includes('409') || msg.includes('conflict') || msg.includes('已存在') || msg.includes('duplicate')) {
|
||||
ElMessage.error(`数据集管理中已存在名为「${form.value.name}」的任务,请换一个名称`)
|
||||
} else if (msg.includes('400')) {
|
||||
ElMessage.error(`参数错误:${msg}`)
|
||||
} else if (msg.includes('403') || msg.includes('权限')) {
|
||||
ElMessage.error(`没有权限执行此操作:${msg}`)
|
||||
} else {
|
||||
ElMessage.error(`操作失败:${msg}`)
|
||||
}
|
||||
} finally {
|
||||
creating.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 自定义上传(表格中的上传按钮仍使用此方法)
|
||||
async function customUpload(options: UploadRequestOptions) {
|
||||
const taskId = options.data?.taskId as string
|
||||
if (!taskId) {
|
||||
@@ -59,11 +131,22 @@ async function customUpload(options: UploadRequestOptions) {
|
||||
ElMessage.warning('上传完成,但转换失败:' + (data?.error || '未知错误'))
|
||||
}
|
||||
load()
|
||||
} catch {
|
||||
ElMessage.error('上传失败')
|
||||
} catch (e: any) {
|
||||
ElMessage.error('上传失败:' + (e?.message || '未知错误'))
|
||||
}
|
||||
}
|
||||
|
||||
// 重置表单
|
||||
function resetForm() {
|
||||
form.value = { name: '', outputName: 'converted-data' }
|
||||
fileList.value = []
|
||||
}
|
||||
|
||||
// 移除已选文件
|
||||
function handleRemoveFile(file: UploadFile) {
|
||||
fileList.value = fileList.value.filter((f) => f.uid !== file.uid)
|
||||
}
|
||||
|
||||
async function handleDelete(task: DataConvertTask) {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
@@ -136,21 +219,42 @@ onMounted(load)
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 新建任务弹窗 -->
|
||||
<el-dialog v-model="showCreate" title="新建转换任务" width="480px">
|
||||
<!-- 新建任务弹窗(一步到位:填写信息 + 上传文件) -->
|
||||
<el-dialog v-model="showCreate" title="新建转换任务" width="520px" :close-on-click-modal="false">
|
||||
<el-form label-width="100px">
|
||||
<el-form-item label="任务名称" required>
|
||||
<el-input v-model="form.name" placeholder="请输入任务名称" />
|
||||
<el-input v-model="form.name" placeholder="请输入任务名称" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="输出文件名">
|
||||
<el-input v-model="form.outputName" placeholder="converted-data">
|
||||
<el-input v-model="form.outputName" placeholder="converted-data" clearable>
|
||||
<template #append>.jsonl</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="上传文件" required>
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
v-model:file-list="fileList"
|
||||
:auto-upload="false"
|
||||
:limit="1"
|
||||
accept=".json"
|
||||
:before-upload="beforeUpload"
|
||||
:on-remove="handleRemoveFile"
|
||||
:disabled="creating"
|
||||
drag
|
||||
>
|
||||
<el-icon class="el-icon--upload"><Plus /></el-icon>
|
||||
<div class="el-upload__text">将 JSON 文件拖到此处,或<em>点击上传</em></div>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip">仅支持 .json 格式文件,点击"创建并上传"按钮后自动创建任务并上传文件</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="showCreate = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitCreate">创建</el-button>
|
||||
<el-button @click="showCreate = false" :disabled="creating">取消</el-button>
|
||||
<el-button type="primary" :loading="creating" :disabled="!form.name || fileList.length === 0" @click="submitCreate">
|
||||
{{ creating ? '处理中...' : '创建并上传' }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</PageCard>
|
||||
@@ -162,4 +266,10 @@ onMounted(load)
|
||||
gap: 10px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
:deep(.el-upload-dragger) {
|
||||
width: 100%;
|
||||
.el-upload__text {
|
||||
padding: 20px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { reactive, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { createUser } from '@/api/modules/system'
|
||||
import type { CreateUserPayload, PermissionCode } from '@/types'
|
||||
import type { CreateUserPayload } from '@/types'
|
||||
|
||||
const router = useRouter()
|
||||
const submitting = ref(false)
|
||||
@@ -12,26 +12,11 @@ const form = reactive<CreateUserPayload>({
|
||||
username: '',
|
||||
display_name: '',
|
||||
password: 'platform123',
|
||||
role: 'viewer',
|
||||
role: 'user',
|
||||
status: 'active',
|
||||
permissions: ['dashboard'],
|
||||
permissions: [],
|
||||
})
|
||||
|
||||
const permissionOptions: PermissionCode[] = [
|
||||
'dashboard',
|
||||
'fine-tune',
|
||||
'model-eval',
|
||||
'model-inference',
|
||||
'model-manage',
|
||||
'dataset',
|
||||
'data-process',
|
||||
'data-convert',
|
||||
'compute',
|
||||
'hardware',
|
||||
'logs',
|
||||
'user-settings',
|
||||
]
|
||||
|
||||
async function submit() {
|
||||
submitting.value = true
|
||||
try {
|
||||
@@ -49,19 +34,18 @@ async function submit() {
|
||||
<h1>创建用户</h1>
|
||||
<el-form :model="form" label-width="110px" class="user-form">
|
||||
<el-form-item label="账号">
|
||||
<el-input v-model="form.username" />
|
||||
<el-input v-model="form.username" placeholder="登录用户名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="显示名称">
|
||||
<el-input v-model="form.display_name" />
|
||||
<el-input v-model="form.display_name" placeholder="如:张三" />
|
||||
</el-form-item>
|
||||
<el-form-item label="初始密码">
|
||||
<el-input v-model="form.password" type="password" show-password />
|
||||
</el-form-item>
|
||||
<el-form-item label="角色">
|
||||
<el-select v-model="form.role">
|
||||
<el-select v-model="form.role" style="width: 100%">
|
||||
<el-option label="管理员" value="admin" />
|
||||
<el-option label="操作员" value="operator" />
|
||||
<el-option label="观察员" value="viewer" />
|
||||
<el-option label="普通用户" value="user" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
@@ -70,10 +54,13 @@ async function submit() {
|
||||
<el-radio value="disabled">禁用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="页面权限">
|
||||
<el-checkbox-group v-model="form.permissions">
|
||||
<el-checkbox v-for="item in permissionOptions" :key="item" :value="item">{{ item }}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
<el-form-item label="权限说明">
|
||||
<el-alert type="info" :closable="false" show-icon>
|
||||
<template #title>
|
||||
<span v-if="form.role === 'admin'">管理员:拥有全部权限,包括用户管理、平台治理、算力节点</span>
|
||||
<span v-else>普通用户:可见服务看板、模型服务、数据治理、其他工具、平台性能、查看日志。数据集和微调模型仅创建者和被授权用户可见。</span>
|
||||
</template>
|
||||
</el-alert>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="router.back()">返回</el-button>
|
||||
@@ -89,6 +76,6 @@ async function submit() {
|
||||
}
|
||||
|
||||
.user-form {
|
||||
max-width: 760px;
|
||||
max-width: 640px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import {
|
||||
changeMyPassword,
|
||||
deleteUser,
|
||||
getUsers,
|
||||
resetUserPassword,
|
||||
@@ -81,39 +80,11 @@ async function confirmResetPwd() {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- 用户自改密码 ----------
|
||||
const myPwdDialog = reactive({ visible: false, oldPassword: '', newPassword: '', saving: false })
|
||||
function openChangeMyPwd() {
|
||||
myPwdDialog.oldPassword = ''
|
||||
myPwdDialog.newPassword = ''
|
||||
myPwdDialog.visible = true
|
||||
}
|
||||
async function confirmChangeMyPwd() {
|
||||
if (!myPwdDialog.oldPassword.trim() || !myPwdDialog.newPassword.trim()) {
|
||||
ElMessage.warning('请填写旧密码和新密码')
|
||||
return
|
||||
}
|
||||
if (myPwdDialog.newPassword.length < 6) {
|
||||
ElMessage.warning('新密码至少 6 位')
|
||||
return
|
||||
}
|
||||
myPwdDialog.saving = true
|
||||
try {
|
||||
await changeMyPassword(myPwdDialog.oldPassword.trim(), myPwdDialog.newPassword.trim())
|
||||
ElMessage.success('密码修改成功')
|
||||
myPwdDialog.visible = false
|
||||
} catch {
|
||||
ElMessage.error('密码修改失败,请检查旧密码是否正确')
|
||||
} finally {
|
||||
myPwdDialog.saving = false
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- 删除 ----------
|
||||
async function removeUser(row: SystemUser) {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确定删除用户 “${row.display_name}(${row.username})” 吗?该操作不可恢复。`,
|
||||
`确定删除用户 "${row.display_name}(${row.username})" 吗?该操作不可恢复。`,
|
||||
'删除用户',
|
||||
{ type: 'warning', confirmButtonText: '删除', cancelButtonText: '取消' },
|
||||
)
|
||||
@@ -139,7 +110,6 @@ async function removeUser(row: SystemUser) {
|
||||
<p>管理平台账号、角色状态与登录密码。</p>
|
||||
</div>
|
||||
<div>
|
||||
<el-button @click="openChangeMyPwd">修改密码</el-button>
|
||||
<el-button type="primary" @click="$router.push('/user-settings/create')">创建用户</el-button>
|
||||
</div>
|
||||
</header>
|
||||
@@ -147,7 +117,13 @@ async function removeUser(row: SystemUser) {
|
||||
<el-table :data="users" border>
|
||||
<el-table-column prop="username" label="账号" min-width="140" />
|
||||
<el-table-column prop="display_name" label="显示名称" min-width="160" />
|
||||
<el-table-column prop="role" label="角色" width="120" />
|
||||
<el-table-column prop="role" label="角色" width="120">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="asSystemUser(row).role === 'admin' ? 'danger' : 'info'" size="small">
|
||||
{{ asSystemUser(row).role === 'admin' ? '管理员' : '普通用户' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="130">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="statusTagType(asSystemUser(row).status)" size="small">{{ statusLabel(asSystemUser(row).status) }}</el-tag>
|
||||
@@ -189,22 +165,6 @@ async function removeUser(row: SystemUser) {
|
||||
<el-button type="primary" :loading="pwdDialog.saving" @click="confirmResetPwd">确定重置</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 修改自己的密码 -->
|
||||
<el-dialog v-model="myPwdDialog.visible" title="修改密码" width="420px">
|
||||
<el-form label-width="80px">
|
||||
<el-form-item label="旧密码">
|
||||
<el-input v-model="myPwdDialog.oldPassword" placeholder="请输入当前密码" show-password />
|
||||
</el-form-item>
|
||||
<el-form-item label="新密码">
|
||||
<el-input v-model="myPwdDialog.newPassword" placeholder="至少 6 位" show-password />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="myPwdDialog.visible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="myPwdDialog.saving" @click="confirmChangeMyPwd">确认修改</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user