提交 fb8b2339 authored 作者: 王鹏飞's avatar 王鹏飞

feat: 添加账号类型和有效期字段,支持教工和学生的批量导入与管理

上级 e71b0b3f
import httpRequest from '@/utils/axios'
// // 获取学生列表
export function getStaffList(params?: { name?: string; organ_id?: string; page?: string; ['per-page']?: string }) {
export function getStaffList(params?: {
name?: string
organ_id?: string
account_type?: string
status?: string
page?: string
['per-page']?: string
}) {
return httpRequest.get('/api/resource/v1/learning/teacher/list', { params })
}
// 添加学生
......@@ -12,6 +19,8 @@ export function addStaff(data?: {
mobile: string
role: string
email: string
account_type?: string
account_expired_time?: string
}) {
return httpRequest.post('/api/resource/v1/learning/teacher/create', data)
}
......@@ -28,6 +37,8 @@ export function updateStaff(data?: {
mobile: string
role: string
email: string
account_type?: string
account_expired_time?: string
}) {
return httpRequest.post('/api/resource/v1/learning/teacher/update', data)
}
......@@ -13,17 +13,17 @@ const ruleFormRef = ref<FormInstance>()
const emit = defineEmits<Emits>()
const props = defineProps({
isShowStaffDialog: {
type: Boolean
type: Boolean,
},
title: {
type: String
type: String,
},
isEdit: {
type: String
type: String,
},
id: {
type: String
}
type: String,
},
})
interface Emits {
(e: 'update:isShowStaffDialog', isShowStaffDialog: boolean): void
......@@ -40,7 +40,9 @@ const form: any = reactive({
mobile: '',
role: [],
email: '',
status: '1'
status: '1',
account_type: '1',
account_expired_time: '',
})
const rules = reactive<FormRules>({
......@@ -50,11 +52,12 @@ const rules = reactive<FormRules>({
gender: [{ required: true, message: '请选择性别', trigger: 'change' }],
mobile: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{ pattern: /^1(3|4|5|6|7|8|9)\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
{ pattern: /^1(3|4|5|6|7|8|9)\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' },
],
role: [{ required: true, message: '请选择角色类型', trigger: 'change' }],
email: [{ required: true, message: '请输入邮箱', trigger: 'blur' }],
status: [{ required: true, message: '请选择生效状态', trigger: 'change' }]
status: [{ required: true, message: '请选择生效状态', trigger: 'change' }],
account_type: [{ required: true, message: '请选择账号类型', trigger: 'change' }],
})
if (userStore.roles[0].name !== '超级管理员') {
form.organ_id = userStore.organization?.id
......@@ -67,11 +70,13 @@ const handleCancel = () => {
// 确定
const handleConfirm = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate(valid => {
await formEl.validate((valid) => {
if (valid) {
if (props.isEdit === '0') {
form.role = form.role.toString()
const params: any = Object.assign({}, form)
const params: any = Object.assign({}, form, {
role: form.role.toString(),
account_expired_time: form.account_expired_time || '',
})
if (userStore.roles[0].name === '部门管理员') {
params.organ_id = userStore.organization?.id
}
......@@ -81,8 +86,10 @@ const handleConfirm = async (formEl: FormInstance | undefined) => {
emit('create')
})
} else if (props.isEdit === '1') {
form.role = form.role.toString()
const params: any = Object.assign({ id: props.id }, form)
const params: any = Object.assign({ id: props.id }, form, {
role: form.role.toString(),
account_expired_time: form.account_expired_time || '',
})
updateStaff(params).then(() => {
ElMessage.success('更新教工成功')
emit('update:isShowStaffDialog', false)
......@@ -99,7 +106,7 @@ const handleConfirm = async (formEl: FormInstance | undefined) => {
if (props.isEdit === '2' || props.isEdit === '1') {
const params: any = { id: props.id }
getStaffDetail(params).then((res: any) => {
Object.keys(form).forEach(key => {
Object.keys(form).forEach((key) => {
form[key] = res.data[key]
})
form.role = res.data.role.split(',')
......@@ -116,14 +123,13 @@ if (props.isEdit === '2' || props.isEdit === '1') {
:disabled="props.isEdit === '2' || props.isEdit === '1'"
placeholder="请选择所属部门/学校"
style="width: 100%"
v-if="userStore.roles[0].name === '超级管理员'"
>
v-if="userStore.roles[0].name === '超级管理员'">
<el-option v-for="item in departmentList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
<el-input :placeholder="userStore.organization?.name" v-model="form.organ_id_name" v-else disabled> </el-input>
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" :disabled="props.isEdit === '2' || props.isEdit === '1'"></el-input>
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-radio-group v-model="form.gender" :disabled="props.isEdit === '2'">
......@@ -138,6 +144,20 @@ if (props.isEdit === '2' || props.isEdit === '1') {
<el-checkbox v-for="(item, index) in roleList" :key="index" :label="item.value">{{ item.label }}</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="账号类型" prop="account_type">
<el-radio-group v-model="form.account_type">
<el-radio label="1">正式</el-radio>
<el-radio label="2">试用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="有效期" prop="account_expired_time">
<el-date-picker
v-model="form.account_expired_time"
type="datetime"
placeholder="请选择有效期"
style="width: 100%"
value-format="YYYY-MM-DD HH:mm:ss" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" :disabled="props.isEdit === '2'" />
</el-form-item>
......
......@@ -105,6 +105,9 @@ const parseExcelData = (jsonData: any[]) => {
role: '',
role_name: row['角色类型'] || row['role_name'] || '',
email: row['邮箱'] || row['email'] || '',
account_type: '',
account_type_name: row['账号类型'] || '',
account_expired_time: row['账号有效期'] || row['有效期'] || '',
status: 'pending', // 初始状态:待导入
errorMsg: '', // 错误信息
}
......@@ -128,6 +131,14 @@ const parseExcelData = (jsonData: any[]) => {
item.gender = findValueByLabel(sexList.value, item.gender_name)
}
// 账号类型映射
if (item.account_type_name === '试用') {
item.account_type = '2'
} else {
item.account_type = '1'
item.account_type_name = '正式'
}
// 根据角色名称查找value(支持多个角色,用逗号分隔)
if (item.role_name) {
const roleNames = item.role_name.split(',').map((r: string) => r.trim())
......@@ -164,7 +175,7 @@ const handleBatchImport = async () => {
// 验证数据
const invalidData = tableData.value.filter(
(item) => !item.name || !item.organ_id || !item.gender || !item.mobile || !item.role || !item.email
(item) => !item.name || !item.organ_id || !item.gender || !item.mobile || !item.role || !item.email,
)
if (invalidData.length > 0) {
ElMessage.warning('存在数据不完整,请检查')
......@@ -189,6 +200,8 @@ const handleBatchImport = async () => {
role: item.role,
email: item.email,
status: '1',
account_type: item.account_type,
account_expired_time: item.account_expired_time || '',
}
await addStaff(params)
......@@ -275,6 +288,8 @@ const getStatusType = (status: string) => {
<el-table-column prop="gender_name" label="性别" align="center" />
<el-table-column prop="mobile" label="手机号" align="center" />
<el-table-column prop="role_name" label="角色类型" align="center" />
<el-table-column prop="account_type_name" label="账号类型" align="center" />
<el-table-column prop="account_expired_time" label="账号有效期" align="center" width="180" />
<el-table-column prop="email" label="邮箱" align="center" />
<el-table-column label="导入状态" align="center" width="120">
<template #default="{ row }">
......
......@@ -5,12 +5,14 @@ import ImportStaff from '../components/ImportStaff.vue'
import { useProjectList } from '@/composables/useGetProjectList'
import { getStaffList, updateStaff } from '../api'
import { useUserStore } from '@/stores/user'
import { useMapStore } from '@/stores/map'
// 判断当前用户是不是超级管理员
const user = useUserStore().roles
const isAdmin = !!user.find((item: any) => item.name === '超级管理员')
const departmentList: any = useProjectList('', '79806610719731712').departmentList
const statusList = useMapStore().getMapValuesByKey('system_status')
const appList = ref()
const studentId = ref('')
......@@ -25,11 +27,32 @@ const listOptions = $computed(() => {
params: {
name: '',
organ_id: '',
account_type: '',
status: '',
},
},
filters: [
{ type: 'input', prop: 'name', label: '姓名:', placeholder: '姓名' },
{ type: 'select', prop: 'organ_id', slots: 'filter-department' },
{
type: 'select',
prop: 'account_type',
label: '账号类型:',
options: [
{ label: '正式', id: '1' },
{ label: '试用', id: '2' },
],
labelKey: 'label',
valueKey: 'id',
},
{
type: 'select',
prop: 'status',
label: '生效状态:',
options: statusList,
labelKey: 'label',
valueKey: 'value',
},
],
columns: [
{ label: '序号', type: 'index', align: 'center' },
......@@ -39,6 +62,8 @@ const listOptions = $computed(() => {
{ label: '性别', prop: 'gender_name', align: 'center' },
{ label: '邮箱', prop: 'email', align: 'center', width: 200 },
{ label: '角色类型', prop: 'role_name', align: 'center' },
{ label: '账号类型', prop: 'account_type_name', align: 'center' },
{ label: '账号有效期', prop: 'account_expired_time', align: 'center', width: 200 },
{ label: '生效状态', slots: 'status', align: 'center' },
{ label: '更新时间', prop: 'updated_time', align: 'center', width: 200 },
{ label: '操作', slots: 'table-operate', align: 'center', width: 200, fixed: 'right' },
......
import httpRequest from '@/utils/axios'
// 获取学生列表
export function getStudentList(params?: { name?: string; organ_id?: string; page?: string; 'per-page'?: string }) {
export function getStudentList(params?: {
name?: string
organ_id?: string
mobile?: string
specialty_id?: string
class_id?: string
account_type?: string
status?: string
page?: string
'per-page'?: string
}) {
return httpRequest.get('/api/resource/v1/learning/student/list', { params })
}
// 导入学生
......@@ -15,7 +25,15 @@ export function batchUpdateStudent(data: { url: string; name: string; size: numb
}
// 导出学生
export function exportStudent(params: { name: string; organ_id: string }) {
export function exportStudent(params: {
name: string
organ_id: string
mobile?: string
specialty_id?: string
class_id?: string
account_type?: string
status?: string
}) {
return httpRequest.get('/api/resource/v1/learning/student/download', { params, responseType: 'blob' })
}
......@@ -30,6 +48,8 @@ export function addStudent(data?: {
sno_number: string
class_id?: string
specialty_id?: string
account_type?: string
account_expired_time?: string
}) {
return httpRequest.post('/api/resource/v1/learning/student/create', data)
}
......@@ -45,6 +65,8 @@ export function updateStudent(data?: {
sno_number: string
class_id?: string
specialty_id?: string
account_type?: string
account_expired_time?: string
}) {
return httpRequest.post('/api/resource/v1/learning/student/update', data)
}
......
......@@ -27,7 +27,9 @@ const form: any = reactive({
organ_id: '',
specialty_id: '',
class_id: '',
status: '1'
status: '1',
account_type: '1',
account_expired_time: '',
})
const rules = reactive<FormRules>({
sno_number: [{ required: true, message: '请输入学号', trigger: 'blur' }],
......@@ -37,21 +39,22 @@ const rules = reactive<FormRules>({
id_type: [{ required: true, message: '请选择证件类型', trigger: 'change' }],
id_number: [{ required: true, message: '请输入证件号码', trigger: 'blur' }],
organ_id: [{ required: true, message: '请选择部门/学校', trigger: 'change' }],
status: [{ required: true, message: '请选择状态', trigger: 'change' }]
status: [{ required: true, message: '请选择状态', trigger: 'change' }],
account_type: [{ required: true, message: '请选择账号类型', trigger: 'change' }],
})
const props = defineProps({
isShowAddDialog: {
type: Boolean
type: Boolean,
},
title: {
type: String
type: String,
},
id: {
type: String
type: String,
},
isEdit: {
type: String
}
type: String,
},
})
interface Emits {
(e: 'update:isShowAddDialog', isShowAddDialog: boolean): void
......@@ -70,7 +73,7 @@ watch(
if (form.organ_id !== '' || form.organ_id_name !== '') {
handleGetProList()
}
}
},
)
watch(
......@@ -79,7 +82,7 @@ watch(
if (form.specialty_id !== '') {
handleClassList()
}
}
},
)
// 修改部门/学校为空的时候班级专业要清除数据
......@@ -115,7 +118,7 @@ const handleClassList = () => {
searchClass({
specialty_id: form.specialty_id,
organ_id: form.organ_id || userStore.organization?.id,
'per-page': '100'
'per-page': '100',
}).then((res: any) => {
loading.value = false
classList.value = res.data.list.filter((item: any) => item.status === '1')
......@@ -130,11 +133,13 @@ const handleClassList = () => {
// 确认
const handleConfirm = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate(valid => {
await formEl.validate((valid) => {
if (valid) {
if (props.isEdit === '0') {
form.organ_id = form.organ_id || userStore.organization?.id
const params: any = Object.assign({}, form)
const params: any = Object.assign({}, form, {
account_expired_time: form.account_expired_time || '',
})
addStudent(params).then(() => {
ElMessage.success('新增学生成功')
emit('update:isShowAddDialog', false)
......@@ -143,7 +148,9 @@ const handleConfirm = async (formEl: FormInstance | undefined) => {
} else if (props.isEdit === '1') {
form.organ_id = form.organ_id || userStore.organization?.id
const params: any = Object.assign({ id: props.id }, form)
const params: any = Object.assign({ id: props.id }, form, {
account_expired_time: form.account_expired_time || '',
})
updateStudent(params).then(() => {
ElMessage.success('更新学生成功')
......@@ -161,7 +168,7 @@ const handleConfirm = async (formEl: FormInstance | undefined) => {
if (props.isEdit === '2' || props.isEdit === '1') {
const params: any = { id: props.id }
getStuDetail(params).then((res: any) => {
Object.keys(form).forEach(key => {
Object.keys(form).forEach((key) => {
form[key] = res.data[key]
})
if (res.data.specialty_id === '0') {
......@@ -205,8 +212,7 @@ if (props.isEdit === '2' || props.isEdit === '1') {
style="width: 100%"
placeholder="请选择所属部门/学校"
v-if="userStore.roles[0].name === '超级管理员'"
@change="handleChangeOrgan"
>
@change="handleChangeOrgan">
<el-option v-for="item in departmentList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
<el-input :placeholder="userStore.organization?.name" v-model="form.organ_id_name" v-else disabled> </el-input>
......@@ -219,8 +225,7 @@ if (props.isEdit === '2' || props.isEdit === '1') {
placeholder="请选择专业"
style="width: 100%"
@change="handleChangeSpe"
:disabled="props.isEdit === '2'"
>
:disabled="props.isEdit === '2'">
<el-option v-for="item in proList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
......@@ -231,11 +236,24 @@ if (props.isEdit === '2' || props.isEdit === '1') {
clearable
placeholder="请选择班级"
style="width: 100%"
:disabled="props.isEdit === '2'"
>
:disabled="props.isEdit === '2'">
<el-option v-for="item in classList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="账号类型" prop="account_type">
<el-radio-group v-model="form.account_type">
<el-radio label="1">正式</el-radio>
<el-radio label="2">试用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="有效期" prop="account_expired_time">
<el-date-picker
v-model="form.account_expired_time"
type="datetime"
placeholder="请选择有效期"
style="width: 100%"
value-format="YYYY-MM-DD HH:mm:ss" />
</el-form-item>
<el-form-item label="生效状态" prop="status">
<el-radio-group v-model="form.status" :disabled="props.isEdit === '2'">
<el-radio v-for="(item, id) in statusList" :key="id" :label="item.value">{{ item.label }}</el-radio>
......
......@@ -68,7 +68,7 @@ const fetchFileUpload = async (option: any) => {
clearInterval(timer)
loading.value = false
})
}, 1000)
}, 1000 * 3)
}
onUnmounted(() => {
timer && clearInterval(timer)
......
......@@ -67,7 +67,7 @@ const fetchFileUpload = async (option: any) => {
clearInterval(timer)
loading.value = false
})
}, 1000)
}, 1000 * 3)
}
const handleSubmitUpload = () => {
......
......@@ -8,12 +8,14 @@ import UpdateStudent from '../components/UpdateStudent.vue'
import { getStudentList, exportStudent, updateStudent } from '../api'
import { useUserStore } from '@/stores/user'
import { useMapStore } from '@/stores/map'
import { useClassList, useSpecialtyList } from '../composables/useData'
// 判断当前用户是不是超级管理员
const user = useUserStore().roles
const isAdmin = !!user.find((item: any) => item.name === '超级管理员')
const { departmentList } = useProjectList('', '79806610719731712')
const statusList = useMapStore().getMapValuesByKey('system_status')
const appList = ref()
const id = ref('')
const title = ref('')
......@@ -32,7 +34,15 @@ const listOptions = computed(() => {
return {
remote: {
httpRequest: getStudentList,
params: { name: '', organ_id: '', mobile: '', specialty_id: '', class_id: '' },
params: {
name: '',
organ_id: '',
mobile: '',
specialty_id: '',
class_id: '',
account_type: '',
status: '',
},
beforeRequest: (requestPrams: any) => {
params.organ_id = requestPrams.organ_id
params.specialty_id = requestPrams.specialty_id
......@@ -64,6 +74,25 @@ const listOptions = computed(() => {
labelKey: 'name',
valueKey: 'id',
},
{
type: 'select',
prop: 'account_type',
label: '账号类型:',
options: [
{ label: '正式', id: '1' },
{ label: '试用', id: '2' },
],
labelKey: 'label',
valueKey: 'id',
},
{
type: 'select',
prop: 'status',
label: '生效状态:',
options: statusList,
labelKey: 'label',
valueKey: 'value',
},
{ type: 'input', prop: 'name', label: '学生姓名:', placeholder: '学生姓名' },
{ type: 'input', prop: 'mobile', label: '学生电话:', placeholder: '学生电话' },
],
......@@ -74,6 +103,8 @@ const listOptions = computed(() => {
{ label: '姓名', prop: 'name', align: 'center', minWidth: '100' },
{ label: '性别', prop: 'gender_name', align: 'center' },
{ label: '联系电话', prop: 'mobile', align: 'center', minWidth: '200' },
{ label: '账号类型', prop: 'account_type_name', align: 'center' },
{ label: '账号有效期', prop: 'account_expired_time', align: 'center', minWidth: '200' },
{ label: '部门/学校', prop: 'organ_id_name', align: 'center', minWidth: '200' },
{ label: '专业', prop: 'specialty_id_name', align: 'center', minWidth: '200' },
{ label: '班级', prop: 'class_id_name', align: 'center', minWidth: '200' },
......@@ -156,7 +187,7 @@ const handleAnalysis = () => {
// isShowAnalysisDialog.value = true
window.open(
import.meta.env.VITE_BI_URL +
'/bi/?proc=1&action=viewer&hback=true&isInPreview=true&db=!7d2b!!8346!!6559!!80b2!e-SaaS!2f!!751f!!6e90!!5730!!5206!!5e03!.db&platform=PC&browserType=chrome'
'/bi/?proc=1&action=viewer&hback=true&isInPreview=true&db=!7d2b!!8346!!6559!!80b2!e-SaaS!2f!!751f!!6e90!!5730!!5206!!5e03!.db&platform=PC&browserType=chrome',
)
}
</script>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论