wip: baseline changes before channel-conversation-task boundary implementation

This commit is contained in:
2026-07-08 16:23:09 +08:00
parent 89c9e6a066
commit 1298a558e8
139 changed files with 11781 additions and 666 deletions

View File

@@ -1,62 +1,296 @@
<template>
<div>
<h2>用户管理</h2>
<el-form :model="form" inline>
<el-form-item label="用户名">
<el-input v-model="form.username" placeholder="用户名" />
</el-form-item>
<el-form-item label="密码">
<el-input v-model="form.password" type="password" placeholder="密码" />
</el-form-item>
<el-form-item label="真实姓名">
<el-input v-model="form.realName" placeholder="真实姓名" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleCreate">创建</el-button>
</el-form-item>
</el-form>
<div class="toolbar">
<el-select
v-model="selectedTenant"
placeholder="选择租户"
clearable
style="width: 200px; margin-right: 12px"
:disabled="!isPlatformAdmin"
@change="loadUsers"
>
<el-option
v-for="t in tenants"
:key="t.id"
:label="`${t.tenantName}${t.tenantCode}`"
:value="t.tenantCode"
/>
</el-select>
<el-button type="primary" @click="openCreateDialog">创建用户</el-button>
</div>
<el-table :data="users" border>
<el-table-column prop="id" label="ID" width="80" />
<el-table-column prop="tenantCode" label="租户编码" />
<el-table-column prop="username" label="用户名" />
<el-table-column prop="realName" label="真实姓名" />
<el-table-column prop="roleCodes" label="角色" />
<el-table-column prop="status" label="状态" />
<el-table-column prop="phone" label="手机号" />
<el-table-column prop="roleCodes" label="角色">
<template #default="{ row }">
{{ formatRoles(row.roleCodes) }}
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="100">
<template #default="{ row }">
<el-tag :type="row.status === 1 ? 'success' : 'info'">
{{ row.status === 1 ? '启用' : '禁用' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="260">
<template #default="{ row }">
<el-button size="small" @click="openEditDialog(row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleDelete(row)">删除</el-button>
<el-switch
v-model="row.status"
:active-value="1"
:inactive-value="0"
style="margin: 0 12px"
@change="(val: any) => handleStatusChange(row, val)"
/>
</template>
</el-table-column>
</el-table>
<el-dialog v-model="dialogVisible" :title="isEdit ? '编辑用户' : '创建用户'" width="600px">
<el-form :model="dialogForm" label-width="100px">
<el-form-item label="租户">
<el-select v-model="dialogForm.tenantCode" :disabled="isEdit" style="width: 100%">
<el-option
v-for="t in tenants"
:key="t.id"
:label="`${t.tenantName}${t.tenantCode}`"
:value="t.tenantCode"
/>
</el-select>
</el-form-item>
<el-form-item label="用户名">
<el-input v-model="dialogForm.username" :disabled="isEdit" placeholder="用户名" />
</el-form-item>
<el-form-item v-if="!isEdit" label="密码">
<el-input v-model="dialogForm.password" type="password" placeholder="密码" />
</el-form-item>
<el-form-item label="真实姓名">
<el-input v-model="dialogForm.realName" placeholder="真实姓名" />
</el-form-item>
<el-form-item label="手机号">
<el-input v-model="dialogForm.phone" placeholder="手机号" />
</el-form-item>
<el-form-item label="角色">
<el-select v-model="dialogForm.roleCodes" multiple placeholder="选择角色" style="width: 100%">
<el-option
v-for="r in roles"
:key="r.id"
:label="r.roleName"
:value="r.roleCode"
/>
</el-select>
</el-form-item>
<el-form-item label="状态">
<el-switch
v-model="dialogForm.status"
:active-value="1"
:inactive-value="0"
active-text="启用"
inactive-text="禁用"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSave">保存</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue'
import { ElMessage } from 'element-plus'
import { createUser, listUsers } from '@/api/account'
import { computed, onMounted, reactive, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useAuthStore } from '@/stores/auth'
import {
createUser,
deleteUser,
listRoles,
listTenants,
listUsers,
updateUser,
} from '@/api/account'
const form = reactive({
const authStore = useAuthStore()
const isPlatformAdmin = computed(() => authStore.roleCodes.includes('platform_admin'))
const users = ref<any[]>([])
const tenants = ref<any[]>([])
const roles = ref<any[]>([])
const selectedTenant = ref(authStore.tenantCode || '')
const dialogVisible = ref(false)
const isEdit = ref(false)
const editingId = ref<number | null>(null)
const dialogForm = reactive({
tenantCode: '',
username: '',
password: '',
realName: '',
phone: '',
roleCodes: [] as string[],
status: 1,
})
const users = ref<any[]>([])
function resetDialogForm() {
dialogForm.tenantCode = isPlatformAdmin.value ? '' : (authStore.tenantCode || '')
dialogForm.username = ''
dialogForm.password = ''
dialogForm.realName = ''
dialogForm.phone = ''
dialogForm.roleCodes = []
dialogForm.status = 1
}
function fillDialogForm(row: any) {
dialogForm.tenantCode = row.tenantCode ?? ''
dialogForm.username = row.username ?? ''
dialogForm.password = ''
dialogForm.realName = row.realName ?? ''
dialogForm.phone = row.phone ?? ''
dialogForm.roleCodes = row.roleCodes || []
dialogForm.status = row.status ?? 1
}
function openCreateDialog() {
isEdit.value = false
editingId.value = null
resetDialogForm()
dialogVisible.value = true
}
function openEditDialog(row: any) {
isEdit.value = true
editingId.value = row.id
fillDialogForm(row)
dialogVisible.value = true
}
function formatRoles(codes: string[] | undefined) {
if (!codes || codes.length === 0) return '-'
return codes
.map((code) => {
const role = roles.value.find((r) => r.roleCode === code)
return role ? role.roleName : code
})
.join('')
}
async function loadTenants() {
try {
const res: any = await listTenants()
tenants.value = res.data || []
} catch (e: any) {
ElMessage.error(e.message)
}
}
async function loadRoles() {
try {
const res: any = await listRoles()
roles.value = res.data || []
} catch (e: any) {
ElMessage.error(e.message)
}
}
async function loadUsers() {
try {
const res: any = await listUsers()
const res: any = await listUsers(selectedTenant.value || undefined)
users.value = res.data || []
} catch (e: any) {
ElMessage.error(e.message)
}
}
async function handleCreate() {
async function handleSave() {
if (!dialogForm.username) {
ElMessage.warning('请填写用户名')
return
}
if (!isEdit.value && !dialogForm.password) {
ElMessage.warning('请填写密码')
return
}
if (!dialogForm.tenantCode) {
ElMessage.warning('请选择租户')
return
}
try {
await createUser({ ...form, roleCodes: ['tenant_admin'] })
ElMessage.success('创建成功')
if (isEdit.value && editingId.value != null) {
await updateUser(editingId.value, {
realName: dialogForm.realName,
phone: dialogForm.phone,
status: dialogForm.status,
roleCodes: dialogForm.roleCodes,
})
ElMessage.success('更新成功')
} else {
await createUser(dialogForm.tenantCode, {
username: dialogForm.username,
password: dialogForm.password,
realName: dialogForm.realName,
phone: dialogForm.phone,
roleCodes: dialogForm.roleCodes,
})
ElMessage.success('创建成功')
}
dialogVisible.value = false
await loadUsers()
} catch (e: any) {
ElMessage.error(e.message)
}
}
onMounted(loadUsers)
async function handleStatusChange(row: any, val: any) {
try {
await updateUser(row.id, {
realName: row.realName,
phone: row.phone,
status: val,
roleCodes: row.roleCodes || [],
})
ElMessage.success('状态更新成功')
await loadUsers()
} catch (e: any) {
ElMessage.error(e.message)
await loadUsers()
}
}
async function handleDelete(row: any) {
try {
await ElMessageBox.confirm(
`确定删除用户「${row.username}${row.tenantCode})」吗?`,
'删除确认',
{ confirmButtonText: '删除', cancelButtonText: '取消', type: 'warning' }
)
await deleteUser(row.id)
ElMessage.success('删除成功')
await loadUsers()
} catch (e: any) {
if (e !== 'cancel') {
ElMessage.error(e.message || '删除失败')
}
}
}
onMounted(() => {
loadTenants()
loadRoles()
loadUsers()
})
</script>
<style scoped>
.toolbar {
margin-bottom: 16px;
}
</style>