440 lines
15 KiB
Vue
Raw Permalink Normal View History

2025-06-26 11:24:11 +08:00
<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>