440 lines
15 KiB
Vue
440 lines
15 KiB
Vue
<template>
|
||
<div class="space-y-6">
|
||
<!-- 页面头部 -->
|
||
<div class="flex items-center justify-between">
|
||
<div>
|
||
<h1 class="text-2xl font-bold text-gray-900">添加用户</h1>
|
||
<p class="text-gray-600 mt-1">创建新的系统用户</p>
|
||
</div>
|
||
<div class="flex space-x-3">
|
||
<button
|
||
@click="$router.back()"
|
||
class="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50"
|
||
>
|
||
返回
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 用户表单 -->
|
||
<div class="bg-white shadow rounded-lg">
|
||
<form @submit.prevent="handleSubmit" class="p-6 space-y-6">
|
||
<!-- 基本信息 -->
|
||
<div>
|
||
<h3 class="text-lg font-medium text-gray-900 mb-4">基本信息</h3>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||
<div>
|
||
<label for="name" class="block text-sm font-medium text-gray-700 mb-2">
|
||
姓名 *
|
||
</label>
|
||
<input
|
||
id="name"
|
||
v-model="userForm.name"
|
||
type="text"
|
||
required
|
||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||
placeholder="请输入用户姓名"
|
||
/>
|
||
</div>
|
||
|
||
<div>
|
||
<label for="email" class="block text-sm font-medium text-gray-700 mb-2">
|
||
邮箱地址 *
|
||
</label>
|
||
<input
|
||
id="email"
|
||
v-model="userForm.email"
|
||
type="email"
|
||
required
|
||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||
placeholder="请输入邮箱地址"
|
||
/>
|
||
</div>
|
||
|
||
<div>
|
||
<label for="phone" class="block text-sm font-medium text-gray-700 mb-2">
|
||
手机号码 *
|
||
</label>
|
||
<input
|
||
id="phone"
|
||
v-model="userForm.phone"
|
||
type="tel"
|
||
required
|
||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||
placeholder="请输入手机号码"
|
||
/>
|
||
</div>
|
||
|
||
<div>
|
||
<label for="role" class="block text-sm font-medium text-gray-700 mb-2">
|
||
用户角色 *
|
||
</label>
|
||
<select
|
||
id="role"
|
||
v-model="userForm.role"
|
||
required
|
||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||
>
|
||
<option value="">请选择用户角色</option>
|
||
<option value="user">普通用户</option>
|
||
<option value="interpreter">译员</option>
|
||
<option value="admin">管理员</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div>
|
||
<label for="gender" class="block text-sm font-medium text-gray-700 mb-2">
|
||
性别
|
||
</label>
|
||
<select
|
||
id="gender"
|
||
v-model="userForm.gender"
|
||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||
>
|
||
<option value="">请选择性别</option>
|
||
<option value="male">男</option>
|
||
<option value="female">女</option>
|
||
<option value="other">其他</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div>
|
||
<label for="birthDate" class="block text-sm font-medium text-gray-700 mb-2">
|
||
出生日期
|
||
</label>
|
||
<input
|
||
id="birthDate"
|
||
v-model="userForm.birthDate"
|
||
type="date"
|
||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 账户设置 -->
|
||
<div>
|
||
<h3 class="text-lg font-medium text-gray-900 mb-4">账户设置</h3>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||
<div>
|
||
<label for="password" class="block text-sm font-medium text-gray-700 mb-2">
|
||
初始密码 *
|
||
</label>
|
||
<input
|
||
id="password"
|
||
v-model="userForm.password"
|
||
type="password"
|
||
required
|
||
minlength="6"
|
||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||
placeholder="请输入初始密码(至少6位)"
|
||
/>
|
||
</div>
|
||
|
||
<div>
|
||
<label for="confirmPassword" class="block text-sm font-medium text-gray-700 mb-2">
|
||
确认密码 *
|
||
</label>
|
||
<input
|
||
id="confirmPassword"
|
||
v-model="userForm.confirmPassword"
|
||
type="password"
|
||
required
|
||
minlength="6"
|
||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||
placeholder="请再次输入密码"
|
||
/>
|
||
</div>
|
||
|
||
<div>
|
||
<label for="status" class="block text-sm font-medium text-gray-700 mb-2">
|
||
账户状态 *
|
||
</label>
|
||
<select
|
||
id="status"
|
||
v-model="userForm.status"
|
||
required
|
||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||
>
|
||
<option value="active">激活</option>
|
||
<option value="inactive">未激活</option>
|
||
<option value="suspended">暂停</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="flex items-center">
|
||
<input
|
||
id="requirePasswordChange"
|
||
v-model="userForm.requirePasswordChange"
|
||
type="checkbox"
|
||
class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
|
||
/>
|
||
<label for="requirePasswordChange" class="ml-2 block text-sm text-gray-900">
|
||
首次登录要求修改密码
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 译员专业信息(仅译员角色显示)-->
|
||
<div v-if="userForm.role === 'interpreter'">
|
||
<h3 class="text-lg font-medium text-gray-900 mb-4">译员专业信息</h3>
|
||
<div class="space-y-6">
|
||
<div>
|
||
<label class="block text-sm font-medium text-gray-700 mb-2">
|
||
专业语言 *
|
||
</label>
|
||
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||
<div v-for="lang in availableLanguages" :key="lang.code" class="flex items-center">
|
||
<input
|
||
:id="`lang_${lang.code}`"
|
||
v-model="userForm.languages"
|
||
:value="lang.code"
|
||
type="checkbox"
|
||
class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
|
||
/>
|
||
<label :for="`lang_${lang.code}`" class="ml-2 block text-sm text-gray-900">
|
||
{{ lang.name }}
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||
<div>
|
||
<label for="experience" class="block text-sm font-medium text-gray-700 mb-2">
|
||
工作经验(年)
|
||
</label>
|
||
<input
|
||
id="experience"
|
||
v-model.number="userForm.experience"
|
||
type="number"
|
||
min="0"
|
||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||
placeholder="请输入工作经验"
|
||
/>
|
||
</div>
|
||
|
||
<div>
|
||
<label for="hourlyRate" class="block text-sm font-medium text-gray-700 mb-2">
|
||
时薪(元/小时)
|
||
</label>
|
||
<input
|
||
id="hourlyRate"
|
||
v-model.number="userForm.hourlyRate"
|
||
type="number"
|
||
min="0"
|
||
step="0.01"
|
||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||
placeholder="请输入时薪"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<label for="specialties" class="block text-sm font-medium text-gray-700 mb-2">
|
||
专业领域
|
||
</label>
|
||
<div class="grid grid-cols-2 md:grid-cols-3 gap-4">
|
||
<div v-for="specialty in availableSpecialties" :key="specialty" class="flex items-center">
|
||
<input
|
||
:id="`specialty_${specialty}`"
|
||
v-model="userForm.specialties"
|
||
:value="specialty"
|
||
type="checkbox"
|
||
class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
|
||
/>
|
||
<label :for="`specialty_${specialty}`" class="ml-2 block text-sm text-gray-900">
|
||
{{ specialty }}
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<label for="certifications" class="block text-sm font-medium text-gray-700 mb-2">
|
||
资质证书
|
||
</label>
|
||
<textarea
|
||
id="certifications"
|
||
v-model="userForm.certifications"
|
||
rows="3"
|
||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||
placeholder="请输入相关资质证书信息"
|
||
></textarea>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 联系信息 -->
|
||
<div>
|
||
<h3 class="text-lg font-medium text-gray-900 mb-4">联系信息</h3>
|
||
<div class="space-y-6">
|
||
<div>
|
||
<label for="address" class="block text-sm font-medium text-gray-700 mb-2">
|
||
地址
|
||
</label>
|
||
<textarea
|
||
id="address"
|
||
v-model="userForm.address"
|
||
rows="3"
|
||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||
placeholder="请输入详细地址"
|
||
></textarea>
|
||
</div>
|
||
|
||
<div>
|
||
<label for="notes" class="block text-sm font-medium text-gray-700 mb-2">
|
||
备注
|
||
</label>
|
||
<textarea
|
||
id="notes"
|
||
v-model="userForm.notes"
|
||
rows="4"
|
||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||
placeholder="请输入备注信息"
|
||
></textarea>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 提交按钮 -->
|
||
<div class="flex justify-end space-x-3 pt-6 border-t border-gray-200">
|
||
<button
|
||
type="button"
|
||
@click="$router.back()"
|
||
class="px-6 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50"
|
||
>
|
||
取消
|
||
</button>
|
||
<button
|
||
type="submit"
|
||
:disabled="isSubmitting"
|
||
class="px-6 py-2 text-sm font-medium text-white bg-blue-600 border border-transparent rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed"
|
||
>
|
||
{{ isSubmitting ? '创建中...' : '创建用户' }}
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
// 页面元数据
|
||
definePageMeta({
|
||
middleware: 'auth'
|
||
})
|
||
|
||
// 页面标题
|
||
useHead({
|
||
title: '添加用户 - 翻译管理系统'
|
||
})
|
||
|
||
// 路由
|
||
const router = useRouter()
|
||
|
||
// 表单数据
|
||
const userForm = ref({
|
||
name: '',
|
||
email: '',
|
||
phone: '',
|
||
role: '',
|
||
gender: '',
|
||
birthDate: '',
|
||
password: '',
|
||
confirmPassword: '',
|
||
status: 'active',
|
||
requirePasswordChange: false,
|
||
languages: [],
|
||
experience: 0,
|
||
hourlyRate: 0,
|
||
specialties: [],
|
||
certifications: '',
|
||
address: '',
|
||
notes: ''
|
||
})
|
||
|
||
// 提交状态
|
||
const isSubmitting = ref(false)
|
||
|
||
// 可用语言列表
|
||
const availableLanguages = [
|
||
{ code: 'zh', name: '中文' },
|
||
{ code: 'en', name: '英文' },
|
||
{ code: 'ja', name: '日文' },
|
||
{ code: 'ko', name: '韩文' },
|
||
{ code: 'fr', name: '法文' },
|
||
{ code: 'de', name: '德文' },
|
||
{ code: 'es', name: '西班牙文' },
|
||
{ code: 'ru', name: '俄文' },
|
||
{ code: 'ar', name: '阿拉伯文' },
|
||
{ code: 'it', name: '意大利文' }
|
||
]
|
||
|
||
// 专业领域列表
|
||
const availableSpecialties = [
|
||
'商务会议',
|
||
'法律翻译',
|
||
'医疗翻译',
|
||
'技术翻译',
|
||
'学术会议',
|
||
'旅游陪同',
|
||
'展会翻译',
|
||
'政府会议',
|
||
'金融翻译',
|
||
'文学翻译'
|
||
]
|
||
|
||
// 处理表单提交
|
||
const handleSubmit = async () => {
|
||
try {
|
||
isSubmitting.value = true
|
||
|
||
// 基本验证
|
||
if (!userForm.value.name || !userForm.value.email || !userForm.value.phone ||
|
||
!userForm.value.role || !userForm.value.password || !userForm.value.confirmPassword) {
|
||
throw new Error('请填写所有必填字段')
|
||
}
|
||
|
||
// 密码确认验证
|
||
if (userForm.value.password !== userForm.value.confirmPassword) {
|
||
throw new Error('两次输入的密码不一致')
|
||
}
|
||
|
||
// 译员角色语言验证
|
||
if (userForm.value.role === 'interpreter' && userForm.value.languages.length === 0) {
|
||
throw new Error('译员角色需要选择至少一种专业语言')
|
||
}
|
||
|
||
// 模拟API调用
|
||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||
|
||
// 创建用户数据
|
||
const newUser = {
|
||
id: `usr_${Date.now()}`,
|
||
...userForm.value,
|
||
createdAt: new Date().toISOString(),
|
||
updatedAt: new Date().toISOString()
|
||
}
|
||
|
||
// 移除确认密码字段
|
||
delete newUser.confirmPassword
|
||
|
||
console.log('创建用户:', newUser)
|
||
|
||
// 显示成功消息
|
||
alert('用户创建成功')
|
||
|
||
// 返回用户列表页面
|
||
router.push('/users')
|
||
|
||
} catch (error) {
|
||
alert(error.message || '创建用户失败,请重试')
|
||
} finally {
|
||
isSubmitting.value = false
|
||
}
|
||
}
|
||
</script>
|
||
|