first commit
This commit is contained in:
@@ -0,0 +1,439 @@
|
||||
<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>
|
||||
|
||||
Reference in New Issue
Block a user