dev-zcx
parent
95a198eab1
commit
99ed1be271
@ -0,0 +1,122 @@ |
||||
<template> |
||||
<Dialog v-model="dialogVisible" :title="dialogTitle"> |
||||
<el-form |
||||
ref="formRef" |
||||
v-loading="formLoading" |
||||
:model="formData" |
||||
:rules="formRules" |
||||
label-width="80px" |
||||
> |
||||
<el-form-item label="字典名称" prop="name"> |
||||
<el-input v-model="formData.name" placeholder="请输入字典名称" /> |
||||
</el-form-item> |
||||
<el-form-item label="字典类型" prop="type"> |
||||
<el-input |
||||
v-model="formData.type" |
||||
:disabled="typeof formData.id !== 'undefined'" |
||||
placeholder="请输入参数名称" |
||||
/> |
||||
</el-form-item> |
||||
<el-form-item label="状态" prop="status"> |
||||
<el-radio-group v-model="formData.status"> |
||||
<el-radio |
||||
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" |
||||
:key="dict.value" |
||||
:label="dict.value" |
||||
> |
||||
{{ dict.label }} |
||||
</el-radio> |
||||
</el-radio-group> |
||||
</el-form-item> |
||||
<el-form-item label="备注" prop="remark"> |
||||
<el-input v-model="formData.remark" placeholder="请输入内容" type="textarea" /> |
||||
</el-form-item> |
||||
</el-form> |
||||
<template #footer> |
||||
<el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> |
||||
<el-button @click="dialogVisible = false">取 消</el-button> |
||||
</template> |
||||
</Dialog> |
||||
</template> |
||||
<script lang="ts" name="SystemDictTypeForm" setup> |
||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' |
||||
import * as DictTypeApi from '@/api/system/dict/dict.type' |
||||
import { CommonStatusEnum } from '@/utils/constants' |
||||
|
||||
const { t } = useI18n() // 国际化 |
||||
const message = useMessage() // 消息弹窗 |
||||
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示 |
||||
const dialogTitle = ref('') // 弹窗的标题 |
||||
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 |
||||
const formType = ref('') // 表单的类型:create - 新增;update - 修改 |
||||
const formData = ref({ |
||||
id: undefined, |
||||
name: '', |
||||
type: '', |
||||
status: CommonStatusEnum.ENABLE, |
||||
remark: '' |
||||
}) |
||||
const formRules = reactive({ |
||||
name: [{ required: true, message: '字典名称不能为空', trigger: 'blur' }], |
||||
type: [{ required: true, message: '字典类型不能为空', trigger: 'blur' }], |
||||
status: [{ required: true, message: '状态不能为空', trigger: 'change' }] |
||||
}) |
||||
const formRef = ref() // 表单 Ref |
||||
|
||||
/** 打开弹窗 */ |
||||
const open = async (type: string, id?: number) => { |
||||
dialogVisible.value = true |
||||
dialogTitle.value = t('action.' + type) |
||||
formType.value = type |
||||
resetForm() |
||||
// 修改时,设置数据 |
||||
if (id) { |
||||
formLoading.value = true |
||||
try { |
||||
formData.value = await DictTypeApi.getDictType(id) |
||||
} finally { |
||||
formLoading.value = false |
||||
} |
||||
} |
||||
} |
||||
defineExpose({ open }) // 提供 open 方法,用于打开弹窗 |
||||
|
||||
/** 提交表单 */ |
||||
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 |
||||
const submitForm = async () => { |
||||
// 校验表单 |
||||
if (!formRef.value) return |
||||
const valid = await formRef.value.validate() |
||||
if (!valid) return |
||||
// 提交请求 |
||||
formLoading.value = true |
||||
try { |
||||
const data = formData.value as DictTypeApi.DictTypeVO |
||||
if (formType.value === 'create') { |
||||
await DictTypeApi.createDictType(data) |
||||
message.success(t('common.createSuccess')) |
||||
} else { |
||||
await DictTypeApi.updateDictType(data) |
||||
message.success(t('common.updateSuccess')) |
||||
} |
||||
dialogVisible.value = false |
||||
// 发送操作成功的事件 |
||||
emit('success') |
||||
} finally { |
||||
formLoading.value = false |
||||
} |
||||
} |
||||
|
||||
/** 重置表单 */ |
||||
const resetForm = () => { |
||||
formData.value = { |
||||
id: undefined, |
||||
type: '', |
||||
name: '', |
||||
status: CommonStatusEnum.ENABLE, |
||||
remark: '' |
||||
} |
||||
formRef.value?.resetFields() |
||||
} |
||||
</script> |
@ -0,0 +1,181 @@ |
||||
<template> |
||||
<Dialog v-model="dialogVisible" :title="dialogTitle"> |
||||
<el-form |
||||
ref="formRef" |
||||
v-loading="formLoading" |
||||
:model="formData" |
||||
:rules="formRules" |
||||
label-width="80px" |
||||
> |
||||
<el-form-item label="字典类型" prop="type"> |
||||
<el-input |
||||
v-model="formData.dictType" |
||||
:disabled="typeof formData.id !== 'undefined'" |
||||
placeholder="请输入参数名称" |
||||
/> |
||||
</el-form-item> |
||||
<el-form-item label="数据标签" prop="label"> |
||||
<el-input v-model="formData.label" placeholder="请输入数据标签" /> |
||||
</el-form-item> |
||||
<el-form-item label="数据键值" prop="value"> |
||||
<el-input v-model="formData.value" placeholder="请输入数据键值" /> |
||||
</el-form-item> |
||||
<el-form-item label="显示排序" prop="sort"> |
||||
<el-input-number v-model="formData.sort" :min="0" controls-position="right" /> |
||||
</el-form-item> |
||||
<el-form-item label="状态" prop="status"> |
||||
<el-radio-group v-model="formData.status"> |
||||
<el-radio |
||||
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" |
||||
:key="dict.value" |
||||
:label="dict.value" |
||||
> |
||||
{{ dict.label }} |
||||
</el-radio> |
||||
</el-radio-group> |
||||
</el-form-item> |
||||
<el-form-item label="颜色类型" prop="colorType"> |
||||
<el-select v-model="formData.colorType"> |
||||
<el-option |
||||
v-for="item in colorTypeOptions" |
||||
:key="item.value" |
||||
:label="item.label + '(' + item.value + ')'" |
||||
:value="item.value" |
||||
/> |
||||
</el-select> |
||||
</el-form-item> |
||||
<el-form-item label="CSS Class" prop="cssClass"> |
||||
<el-input v-model="formData.cssClass" placeholder="请输入 CSS Class" /> |
||||
</el-form-item> |
||||
<el-form-item label="备注" prop="remark"> |
||||
<el-input v-model="formData.remark" placeholder="请输入内容" type="textarea" /> |
||||
</el-form-item> |
||||
</el-form> |
||||
<template #footer> |
||||
<el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> |
||||
<el-button @click="dialogVisible = false">取 消</el-button> |
||||
</template> |
||||
</Dialog> |
||||
</template> |
||||
<script lang="ts" name="SystemDictDataForm" setup> |
||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' |
||||
import * as DictDataApi from '@/api/system/dict/dict.data' |
||||
import { CommonStatusEnum } from '@/utils/constants' |
||||
|
||||
const { t } = useI18n() // 国际化 |
||||
const message = useMessage() // 消息弹窗 |
||||
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示 |
||||
const dialogTitle = ref('') // 弹窗的标题 |
||||
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 |
||||
const formType = ref('') // 表单的类型:create - 新增;update - 修改 |
||||
const formData = ref({ |
||||
id: undefined, |
||||
sort: undefined, |
||||
label: '', |
||||
value: '', |
||||
dictType: '', |
||||
status: CommonStatusEnum.ENABLE, |
||||
colorType: '', |
||||
cssClass: '', |
||||
remark: '' |
||||
}) |
||||
const formRules = reactive({ |
||||
label: [{ required: true, message: '数据标签不能为空', trigger: 'blur' }], |
||||
value: [{ required: true, message: '数据键值不能为空', trigger: 'blur' }], |
||||
sort: [{ required: true, message: '数据顺序不能为空', trigger: 'blur' }], |
||||
status: [{ required: true, message: '状态不能为空', trigger: 'change' }] |
||||
}) |
||||
const formRef = ref() // 表单 Ref |
||||
|
||||
// 数据标签回显样式 |
||||
const colorTypeOptions = readonly([ |
||||
{ |
||||
value: 'default', |
||||
label: '默认' |
||||
}, |
||||
{ |
||||
value: 'primary', |
||||
label: '主要' |
||||
}, |
||||
{ |
||||
value: 'success', |
||||
label: '成功' |
||||
}, |
||||
{ |
||||
value: 'info', |
||||
label: '信息' |
||||
}, |
||||
{ |
||||
value: 'warning', |
||||
label: '警告' |
||||
}, |
||||
{ |
||||
value: 'danger', |
||||
label: '危险' |
||||
} |
||||
]) |
||||
|
||||
/** 打开弹窗 */ |
||||
const open = async (type: string, id?: number, dictType?: string) => { |
||||
dialogVisible.value = true |
||||
dialogTitle.value = t('action.' + type) |
||||
formType.value = type |
||||
resetForm() |
||||
if (dictType) { |
||||
formData.value.dictType = dictType |
||||
} |
||||
// 修改时,设置数据 |
||||
if (id) { |
||||
formLoading.value = true |
||||
try { |
||||
formData.value = await DictDataApi.getDictData(id) |
||||
} finally { |
||||
formLoading.value = false |
||||
} |
||||
} |
||||
} |
||||
defineExpose({ open }) // 提供 open 方法,用于打开弹窗 |
||||
|
||||
/** 提交表单 */ |
||||
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 |
||||
const submitForm = async () => { |
||||
// 校验表单 |
||||
if (!formRef.value) return |
||||
const valid = await formRef.value.validate() |
||||
if (!valid) return |
||||
// 提交请求 |
||||
formLoading.value = true |
||||
try { |
||||
const data = formData.value as DictDataApi.DictDataVO |
||||
if (formType.value === 'create') { |
||||
await DictDataApi.createDictData(data) |
||||
message.success(t('common.createSuccess')) |
||||
} else { |
||||
await DictDataApi.updateDictData(data) |
||||
message.success(t('common.updateSuccess')) |
||||
} |
||||
dialogVisible.value = false |
||||
// 发送操作成功的事件 |
||||
emit('success') |
||||
} finally { |
||||
formLoading.value = false |
||||
} |
||||
} |
||||
|
||||
/** 重置表单 */ |
||||
const resetForm = () => { |
||||
formData.value = { |
||||
id: undefined, |
||||
sort: undefined, |
||||
label: '', |
||||
value: '', |
||||
dictType: '', |
||||
status: CommonStatusEnum.ENABLE, |
||||
colorType: '', |
||||
cssClass: '', |
||||
remark: '' |
||||
} |
||||
formRef.value?.resetFields() |
||||
} |
||||
</script> |
@ -0,0 +1,207 @@ |
||||
<template> |
||||
<ContentWrap> |
||||
<el-form |
||||
class="-mb-15px" |
||||
:model="queryParams" |
||||
ref="queryFormRef" |
||||
:inline="true" |
||||
label-width="68px" |
||||
> |
||||
<el-form-item label="字典名称" prop="dictType"> |
||||
<el-select v-model="queryParams.dictType" class="!w-240px"> |
||||
<el-option |
||||
v-for="item in dictTypeList" |
||||
:key="item.type" |
||||
:label="item.name" |
||||
:value="item.type" |
||||
/> |
||||
</el-select> |
||||
</el-form-item> |
||||
<el-form-item label="字典标签" prop="label"> |
||||
<el-input |
||||
v-model="queryParams.label" |
||||
placeholder="请输入字典标签" |
||||
clearable |
||||
@keyup.enter="handleQuery" |
||||
class="!w-240px" |
||||
/> |
||||
</el-form-item> |
||||
<el-form-item label="状态" prop="status"> |
||||
<el-select v-model="queryParams.status" placeholder="数据状态" clearable class="!w-240px"> |
||||
<el-option |
||||
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" |
||||
:key="dict.value" |
||||
:label="dict.label" |
||||
:value="dict.value" |
||||
/> |
||||
</el-select> |
||||
</el-form-item> |
||||
<el-form-item> |
||||
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> |
||||
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> |
||||
<el-button |
||||
type="primary" |
||||
plain |
||||
@click="openForm('create')" |
||||
v-hasPermi="['system:dict:create']" |
||||
> |
||||
<Icon icon="ep:plus" class="mr-5px" /> 新增 |
||||
</el-button> |
||||
<el-button |
||||
type="success" |
||||
plain |
||||
@click="handleExport" |
||||
:loading="exportLoading" |
||||
v-hasPermi="['system:dict:export']" |
||||
> |
||||
<Icon icon="ep:download" class="mr-5px" /> 导出 |
||||
</el-button> |
||||
</el-form-item> |
||||
</el-form> |
||||
</ContentWrap> |
||||
|
||||
<!-- 列表 --> |
||||
<ContentWrap> |
||||
<el-table v-loading="loading" :data="list"> |
||||
<el-table-column label="字典编码" align="center" prop="id" /> |
||||
<el-table-column label="字典标签" align="center" prop="label" /> |
||||
<el-table-column label="字典键值" align="center" prop="value" /> |
||||
<el-table-column label="字典排序" align="center" prop="sort" /> |
||||
<el-table-column label="状态" align="center" prop="status"> |
||||
<template #default="scope"> |
||||
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="颜色类型" align="center" prop="colorType" /> |
||||
<el-table-column label="CSS Class" align="center" prop="cssClass" /> |
||||
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip /> |
||||
<el-table-column |
||||
label="创建时间" |
||||
align="center" |
||||
prop="createTime" |
||||
width="180" |
||||
:formatter="dateFormatter" |
||||
/> |
||||
<el-table-column label="操作" align="center"> |
||||
<template #default="scope"> |
||||
<el-button |
||||
link |
||||
type="primary" |
||||
@click="openForm('update', scope.row.id)" |
||||
v-hasPermi="['system:dict:update']" |
||||
> |
||||
修改 |
||||
</el-button> |
||||
<el-button |
||||
link |
||||
type="danger" |
||||
@click="handleDelete(scope.row.id)" |
||||
v-hasPermi="['system:dict:delete']" |
||||
> |
||||
删除 |
||||
</el-button> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
<!-- 分页 --> |
||||
<Pagination |
||||
:total="total" |
||||
v-model:page="queryParams.pageNo" |
||||
v-model:limit="queryParams.pageSize" |
||||
@pagination="getList" |
||||
/> |
||||
</ContentWrap> |
||||
|
||||
<!-- 表单弹窗:添加/修改 --> |
||||
<DictDataForm ref="formRef" @success="getList" /> |
||||
</template> |
||||
<script setup lang="ts" name="SystemDictData"> |
||||
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' |
||||
import { dateFormatter } from '@/utils/formatTime' |
||||
import download from '@/utils/download' |
||||
import * as DictDataApi from '@/api/system/dict/dict.data' |
||||
import * as DictTypeApi from '@/api/system/dict/dict.type' |
||||
import DictDataForm from './DictDataForm.vue' |
||||
const message = useMessage() // 消息弹窗 |
||||
const { t } = useI18n() // 国际化 |
||||
const route = useRoute() // 路由 |
||||
|
||||
const loading = ref(true) // 列表的加载中 |
||||
const total = ref(0) // 列表的总页数 |
||||
const list = ref([]) // 列表的数据 |
||||
const queryParams = reactive({ |
||||
pageNo: 1, |
||||
pageSize: 10, |
||||
label: '', |
||||
status: undefined, |
||||
dictType: route.params.dictType |
||||
}) |
||||
const queryFormRef = ref() // 搜索的表单 |
||||
const exportLoading = ref(false) // 导出的加载中 |
||||
const dictTypeList = ref<DictTypeApi.DictTypeVO[]>() // 字典类型的列表 |
||||
|
||||
/** 查询列表 */ |
||||
const getList = async () => { |
||||
loading.value = true |
||||
try { |
||||
const data = await DictDataApi.getDictDataPage(queryParams) |
||||
list.value = data.list |
||||
total.value = data.total |
||||
} finally { |
||||
loading.value = false |
||||
} |
||||
} |
||||
|
||||
/** 搜索按钮操作 */ |
||||
const handleQuery = () => { |
||||
queryParams.pageNo = 1 |
||||
getList() |
||||
} |
||||
|
||||
/** 重置按钮操作 */ |
||||
const resetQuery = () => { |
||||
queryFormRef.value.resetFields() |
||||
handleQuery() |
||||
} |
||||
|
||||
/** 添加/修改操作 */ |
||||
const formRef = ref() |
||||
const openForm = (type: string, id?: number) => { |
||||
formRef.value.open(type, id, queryParams.dictType) |
||||
} |
||||
|
||||
/** 删除按钮操作 */ |
||||
const handleDelete = async (id: number) => { |
||||
try { |
||||
// 删除的二次确认 |
||||
await message.delConfirm() |
||||
// 发起删除 |
||||
await DictDataApi.deleteDictData(id) |
||||
message.success(t('common.delSuccess')) |
||||
// 刷新列表 |
||||
await getList() |
||||
} catch {} |
||||
} |
||||
|
||||
/** 导出按钮操作 */ |
||||
const handleExport = async () => { |
||||
try { |
||||
// 导出的二次确认 |
||||
await message.exportConfirm() |
||||
// 发起导出 |
||||
exportLoading.value = true |
||||
const data = await DictDataApi.exportDictData(queryParams) |
||||
download.excel(data, '字典数据.xls') |
||||
} catch { |
||||
} finally { |
||||
exportLoading.value = false |
||||
} |
||||
} |
||||
|
||||
/** 初始化 **/ |
||||
onMounted(async () => { |
||||
await getList() |
||||
// 查询字典(精简)列表 |
||||
dictTypeList.value = await DictTypeApi.getSimpleDictTypeList() |
||||
}) |
||||
</script> |
@ -0,0 +1,229 @@ |
||||
<template> |
||||
<!-- 搜索工作栏 --> |
||||
<ContentWrap> |
||||
<el-form |
||||
ref="queryFormRef" |
||||
:inline="true" |
||||
:model="queryParams" |
||||
class="-mb-15px" |
||||
label-width="68px" |
||||
> |
||||
<el-form-item label="字典名称" prop="name"> |
||||
<el-input |
||||
v-model="queryParams.name" |
||||
class="!w-240px" |
||||
clearable |
||||
placeholder="请输入字典名称" |
||||
@keyup.enter="handleQuery" |
||||
/> |
||||
</el-form-item> |
||||
<el-form-item label="字典类型" prop="type"> |
||||
<el-input |
||||
v-model="queryParams.type" |
||||
class="!w-240px" |
||||
clearable |
||||
placeholder="请输入字典类型" |
||||
@keyup.enter="handleQuery" |
||||
/> |
||||
</el-form-item> |
||||
<el-form-item label="状态" prop="status"> |
||||
<el-select |
||||
v-model="queryParams.status" |
||||
class="!w-240px" |
||||
clearable |
||||
placeholder="请选择字典状态" |
||||
> |
||||
<el-option |
||||
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" |
||||
:key="dict.value" |
||||
:label="dict.label" |
||||
:value="dict.value" |
||||
/> |
||||
</el-select> |
||||
</el-form-item> |
||||
<el-form-item label="创建时间" prop="createTime"> |
||||
<el-date-picker |
||||
v-model="queryParams.createTime" |
||||
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" |
||||
class="!w-240px" |
||||
end-placeholder="结束日期" |
||||
start-placeholder="开始日期" |
||||
type="daterange" |
||||
value-format="yyyy-MM-dd HH:mm:ss" |
||||
/> |
||||
</el-form-item> |
||||
<el-form-item> |
||||
<el-button @click="handleQuery"> |
||||
<Icon class="mr-5px" icon="ep:search" /> |
||||
搜索 |
||||
</el-button> |
||||
<el-button @click="resetQuery"> |
||||
<Icon class="mr-5px" icon="ep:refresh" /> |
||||
重置 |
||||
</el-button> |
||||
<el-button |
||||
v-hasPermi="['system:dict:create']" |
||||
plain |
||||
type="primary" |
||||
@click="openForm('create')" |
||||
> |
||||
<Icon class="mr-5px" icon="ep:plus" /> |
||||
新增 |
||||
</el-button> |
||||
<el-button |
||||
v-hasPermi="['system:dict:export']" |
||||
:loading="exportLoading" |
||||
plain |
||||
type="success" |
||||
@click="handleExport" |
||||
> |
||||
<Icon class="mr-5px" icon="ep:download" /> |
||||
导出 |
||||
</el-button> |
||||
</el-form-item> |
||||
</el-form> |
||||
</ContentWrap> |
||||
|
||||
<!-- 列表 --> |
||||
<ContentWrap> |
||||
<el-table v-loading="loading" :data="list"> |
||||
<el-table-column align="center" label="字典编号" prop="id" /> |
||||
<el-table-column align="center" label="字典名称" prop="name" show-overflow-tooltip /> |
||||
<el-table-column align="center" label="字典类型" prop="type" width="300" /> |
||||
<el-table-column align="center" label="状态" prop="status"> |
||||
<template #default="scope"> |
||||
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column align="center" label="备注" prop="remark" /> |
||||
<el-table-column |
||||
:formatter="dateFormatter" |
||||
align="center" |
||||
label="创建时间" |
||||
prop="createTime" |
||||
width="180" |
||||
/> |
||||
<el-table-column align="center" label="操作"> |
||||
<template #default="scope"> |
||||
<el-button |
||||
v-hasPermi="['system:dict:update']" |
||||
link |
||||
type="primary" |
||||
@click="openForm('update', scope.row.id)" |
||||
> |
||||
修改 |
||||
</el-button> |
||||
<router-link :to="'/dict/type/data/' + scope.row.type"> |
||||
<el-button link type="primary">数据</el-button> |
||||
</router-link> |
||||
<el-button |
||||
v-hasPermi="['system:dict:delete']" |
||||
link |
||||
type="danger" |
||||
@click="handleDelete(scope.row.id)" |
||||
> |
||||
删除 |
||||
</el-button> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
<!-- 分页 --> |
||||
<Pagination |
||||
v-model:limit="queryParams.pageSize" |
||||
v-model:page="queryParams.pageNo" |
||||
:total="total" |
||||
@pagination="getList" |
||||
/> |
||||
</ContentWrap> |
||||
|
||||
<!-- 表单弹窗:添加/修改 --> |
||||
<DictTypeForm ref="formRef" @success="getList" /> |
||||
</template> |
||||
|
||||
<script lang="ts" name="SystemDictType" setup> |
||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' |
||||
import { dateFormatter } from '@/utils/formatTime' |
||||
import * as DictTypeApi from '@/api/system/dict/dict.type' |
||||
import DictTypeForm from './DictTypeForm.vue' |
||||
import download from '@/utils/download' |
||||
|
||||
const message = useMessage() // 消息弹窗 |
||||
const { t } = useI18n() // 国际化 |
||||
|
||||
const loading = ref(true) // 列表的加载中 |
||||
const total = ref(0) // 列表的总页数 |
||||
const list = ref([]) // 字典表格数据 |
||||
const queryParams = reactive({ |
||||
pageNo: 1, |
||||
pageSize: 10, |
||||
name: '', |
||||
type: '', |
||||
status: undefined, |
||||
createTime: [] |
||||
}) |
||||
const queryFormRef = ref() // 搜索的表单 |
||||
const exportLoading = ref(false) // 导出的加载中 |
||||
|
||||
/** 查询字典类型列表 */ |
||||
const getList = async () => { |
||||
loading.value = true |
||||
try { |
||||
const data = await DictTypeApi.getDictTypePage(queryParams) |
||||
list.value = data.list |
||||
total.value = data.total |
||||
} finally { |
||||
loading.value = false |
||||
} |
||||
} |
||||
|
||||
/** 搜索按钮操作 */ |
||||
const handleQuery = () => { |
||||
queryParams.pageNo = 1 |
||||
getList() |
||||
} |
||||
|
||||
/** 重置按钮操作 */ |
||||
const resetQuery = () => { |
||||
queryFormRef.value.resetFields() |
||||
handleQuery() |
||||
} |
||||
|
||||
/** 添加/修改操作 */ |
||||
const formRef = ref() |
||||
const openForm = (type: string, id?: number) => { |
||||
formRef.value.open(type, id) |
||||
} |
||||
|
||||
/** 删除按钮操作 */ |
||||
const handleDelete = async (id: number) => { |
||||
try { |
||||
// 删除的二次确认 |
||||
await message.delConfirm() |
||||
// 发起删除 |
||||
await DictTypeApi.deleteDictType(id) |
||||
message.success(t('common.delSuccess')) |
||||
// 刷新列表 |
||||
await getList() |
||||
} catch {} |
||||
} |
||||
|
||||
/** 导出按钮操作 */ |
||||
const handleExport = async () => { |
||||
try { |
||||
// 导出的二次确认 |
||||
await message.exportConfirm() |
||||
// 发起导出 |
||||
exportLoading.value = true |
||||
const data = await DictTypeApi.exportDictType(queryParams) |
||||
download.excel(data, '字典类型.xls') |
||||
} catch { |
||||
} finally { |
||||
exportLoading.value = false |
||||
} |
||||
} |
||||
|
||||
/** 初始化 **/ |
||||
onMounted(() => { |
||||
getList() |
||||
}) |
||||
</script> |
@ -0,0 +1,83 @@ |
||||
<template> |
||||
<div> |
||||
<el-table v-loading="loading" :data="tableList" border> |
||||
<el-table-column type="index" width="50" /> |
||||
<el-table-column |
||||
v-for="col in columns" |
||||
:prop="col.prop" |
||||
:key="col.prop" |
||||
:label="col.label" |
||||
:width="col.width" |
||||
/> |
||||
<el-table-column label="状态" key="status"> |
||||
<template #default="scope"> |
||||
<el-switch |
||||
v-model="scope.row.status" |
||||
:active-value="0" |
||||
active-text="在职" |
||||
inactive-text="离职" |
||||
:inactive-value="1" |
||||
disabled |
||||
/> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
<Pagination |
||||
v-model:limit="pageSize" |
||||
v-model:page="currentPage" |
||||
:total="total" |
||||
@pagination="getList" |
||||
/> |
||||
</div> |
||||
</template> |
||||
|
||||
<script setup name="RoleEmployee"> |
||||
import { getRoleUsers } from '@/api/system/role' |
||||
|
||||
const props = defineProps({ |
||||
roleId: { |
||||
type: Number |
||||
} |
||||
}) |
||||
|
||||
watch( |
||||
() => props.roleId, |
||||
(newValue) => { |
||||
getList(newValue) |
||||
} |
||||
) |
||||
|
||||
const loading = ref(false) |
||||
const tableList = ref([]) |
||||
const total = ref(0) |
||||
const pageSize = ref(20) |
||||
const currentPage = ref(1) |
||||
|
||||
const columns = ref([ |
||||
{ prop: 'name', label: '姓名', width: '200px' }, |
||||
{ prop: 'mobile', label: '手机号', width: '150px' }, |
||||
{ prop: 'deptName', label: '部门' }, |
||||
{ prop: 'roles', label: '角色' } |
||||
]) |
||||
|
||||
async function getList() { |
||||
loading.value = true |
||||
try { |
||||
const data = await getRoleUsers({ |
||||
pageNo: currentPage.value, |
||||
pageSize: pageSize.value, |
||||
id: props.roleId |
||||
}) |
||||
tableList.value = data.list |
||||
total.value = data.total |
||||
} finally { |
||||
loading.value = false |
||||
} |
||||
} |
||||
|
||||
onMounted(() => { |
||||
getList() |
||||
}) |
||||
</script> |
||||
|
||||
<style lang="scss" scoped></style> |
@ -0,0 +1,99 @@ |
||||
<template> |
||||
<div> |
||||
<el-form ref="formRef" v-loading="formLoading" label-width="0px"> |
||||
<el-form-item> |
||||
<el-tree |
||||
ref="treeRef" |
||||
:data="menuOptions" |
||||
:props="defaultProps" |
||||
empty-text="加载中,请稍候" |
||||
node-key="id" |
||||
show-checkbox |
||||
style="width: 100%" |
||||
/> |
||||
</el-form-item> |
||||
<el-form-item> |
||||
<el-button |
||||
:disabled="formLoading" |
||||
type="primary" |
||||
@click="submitForm" |
||||
v-hasPermi="['basic:role:update-menu']" |
||||
>保存权限</el-button |
||||
> |
||||
</el-form-item> |
||||
</el-form> |
||||
</div> |
||||
</template> |
||||
<script lang="ts" name="RoleAssignMenuForm" setup> |
||||
import { defaultProps, handleTree } from '@/utils/tree' |
||||
import * as MenuApi from '@/api/system/menu' |
||||
import * as PermissionApi from '@/api/system/permission' |
||||
|
||||
const { t } = useI18n() // 国际化 |
||||
const message = useMessage() // 消息弹窗 |
||||
|
||||
const props = defineProps({ |
||||
roleId: { |
||||
type: Number |
||||
} |
||||
}) |
||||
|
||||
watch( |
||||
() => props.roleId, |
||||
(newValue) => { |
||||
getCheckedMenu(newValue) |
||||
} |
||||
) |
||||
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示 |
||||
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 |
||||
const formRef = ref() // 表单 Ref |
||||
const menuOptions = ref<any[]>([]) // 菜单树形结构 |
||||
const treeRef = ref() // 菜单树组件 Ref |
||||
|
||||
/** 提交表单 */ |
||||
const submitForm = async () => { |
||||
// 提交请求 |
||||
formLoading.value = true |
||||
try { |
||||
const data = { |
||||
roleId: props.roleId, |
||||
menuIds: [ |
||||
...(treeRef.value.getCheckedKeys(false) as unknown as Array<number>), // 获得当前选中节点 |
||||
...(treeRef.value.getHalfCheckedKeys() as unknown as Array<number>) // 获得半选中的父节点 |
||||
] |
||||
} |
||||
await PermissionApi.assignRoleMenu(data) |
||||
message.success(t('common.updateSuccess')) |
||||
dialogVisible.value = false |
||||
} finally { |
||||
formLoading.value = false |
||||
} |
||||
} |
||||
|
||||
const checkedMenuIds = ref([]) |
||||
|
||||
async function init() { |
||||
menuOptions.value = handleTree(await MenuApi.getSimpleMenusList()) |
||||
getCheckedMenu(props.roleId) |
||||
} |
||||
|
||||
async function getCheckedMenu(id) { |
||||
formLoading.value = true |
||||
try { |
||||
checkedMenuIds.value = await PermissionApi.getRoleMenuList(id) |
||||
treeRef.value.setCheckedKeys([], false) |
||||
// 设置选中 |
||||
checkedMenuIds.value.forEach((menuId: number) => { |
||||
treeRef.value.setChecked(menuId, true, false) |
||||
}) |
||||
} finally { |
||||
formLoading.value = false |
||||
} |
||||
} |
||||
|
||||
onMounted(() => { |
||||
init() |
||||
}) |
||||
</script> |
||||
<style lang="scss" scoped></style> |
@ -0,0 +1,166 @@ |
||||
<template> |
||||
<el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="80px"> |
||||
<el-form-item label="权限范围"> |
||||
<el-select v-model="formData.dataScope"> |
||||
<el-option |
||||
v-for="item in dataScopeOptions" |
||||
:key="item.value" |
||||
:label="item.label" |
||||
:value="item.value" |
||||
/> |
||||
</el-select> |
||||
</el-form-item> |
||||
<el-form-item |
||||
v-if="formData.dataScope === SystemDataScopeEnum.DEPT_CUSTOM" |
||||
label="权限范围" |
||||
style="display: flex" |
||||
> |
||||
<el-card class="card" shadow="never"> |
||||
<template #header> |
||||
全选/全不选: |
||||
<el-switch |
||||
v-model="treeNodeAll" |
||||
active-text="是" |
||||
inactive-text="否" |
||||
inline-prompt |
||||
@change="handleCheckedTreeNodeAll()" |
||||
/> |
||||
全部展开/折叠: |
||||
<el-switch |
||||
v-model="deptExpand" |
||||
active-text="展开" |
||||
inactive-text="折叠" |
||||
inline-prompt |
||||
@change="handleCheckedTreeExpand" |
||||
/> |
||||
父子联动(选中父节点,自动选择子节点): |
||||
<el-switch v-model="checkStrictly" active-text="是" inactive-text="否" inline-prompt /> |
||||
</template> |
||||
<el-tree |
||||
ref="treeRef" |
||||
:check-strictly="!checkStrictly" |
||||
:data="deptOptions" |
||||
:props="defaultProps" |
||||
default-expand-all |
||||
empty-text="加载中,请稍后" |
||||
node-key="id" |
||||
show-checkbox |
||||
/> |
||||
</el-card> |
||||
</el-form-item> |
||||
<el-form-item label-width="0"> |
||||
<el-button |
||||
:disabled="formLoading" |
||||
type="primary" |
||||
@click="submitForm" |
||||
v-hasPermi="['basic:role:update-data']" |
||||
>保存权限</el-button |
||||
> |
||||
</el-form-item> |
||||
</el-form> |
||||
</template> |
||||
<script lang="ts" name="RoleDataPermissionForm" setup> |
||||
import { defaultProps, handleTree } from '@/utils/tree' |
||||
import { SystemDataScopeEnum } from '@/utils/constants' |
||||
|
||||
import * as DeptApi from '@/api/system/dept' |
||||
import * as PermissionApi from '@/api/system/permission' |
||||
import * as RoleApi from '@/api/system/role' |
||||
|
||||
const { t } = useI18n() // 国际化 |
||||
const message = useMessage() // 消息弹窗 |
||||
|
||||
const props = defineProps({ |
||||
roleId: { |
||||
type: Number |
||||
} |
||||
}) |
||||
|
||||
watch( |
||||
() => props.roleId, |
||||
(newValue) => { |
||||
getRoleInfo(newValue) |
||||
} |
||||
) |
||||
|
||||
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 |
||||
const formData = ref({ |
||||
id: 0, |
||||
name: '', |
||||
dataScope: undefined, |
||||
dataScopeDeptIds: [] |
||||
}) |
||||
const formRef = ref() // 表单 Ref |
||||
const deptOptions = ref<any[]>([]) // 部门树形结构 |
||||
const deptExpand = ref(false) // 展开/折叠 |
||||
const treeRef = ref() // 菜单树组件 Ref |
||||
const treeNodeAll = ref(false) // 全选/全不选 |
||||
const checkStrictly = ref(true) // 是否严格模式,即父子不关联 |
||||
|
||||
// const dataScopeOptions = getIntDictOptions(DICT_TYPE.SYSTEM_DATA_SCOPE) |
||||
const dataScopeOptions = [ |
||||
{ label: '全部数据权限', value: 1 }, |
||||
{ label: '指定部门数据权限', value: 2 }, |
||||
{ label: '部门数据权限', value: 3 }, |
||||
{ label: '部门及以下数据权限', value: 4 }, |
||||
{ label: '仅本人数据权限', value: 5 } |
||||
] |
||||
|
||||
async function getRoleInfo(id) { |
||||
try { |
||||
formData.value = await RoleApi.getRole(id) |
||||
nextTick(() => { |
||||
treeRef.value.setCheckedKeys(formData.value.dataScopeDeptIds) |
||||
}) |
||||
} catch (error) { |
||||
console.log(error) |
||||
} |
||||
} |
||||
|
||||
/** 提交表单 */ |
||||
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 |
||||
const submitForm = async () => { |
||||
formLoading.value = true |
||||
try { |
||||
const data = { |
||||
roleId: formData.value.id, |
||||
dataScope: formData.value.dataScope, |
||||
dataScopeDeptIds: |
||||
formData.value.dataScope !== SystemDataScopeEnum.DEPT_CUSTOM |
||||
? [] |
||||
: treeRef.value.getCheckedKeys(false) |
||||
} |
||||
await PermissionApi.assignRoleDataScope(data) |
||||
message.success(t('common.updateSuccess')) |
||||
// 发送操作成功的事件 |
||||
emit('success') |
||||
} finally { |
||||
formLoading.value = false |
||||
} |
||||
} |
||||
|
||||
/** 全选/全不选 */ |
||||
const handleCheckedTreeNodeAll = () => { |
||||
treeRef.value.setCheckedNodes(treeNodeAll.value ? deptOptions.value : []) |
||||
} |
||||
|
||||
/** 展开/折叠全部 */ |
||||
const handleCheckedTreeExpand = () => { |
||||
const nodes = treeRef.value?.store.nodesMap |
||||
for (let node in nodes) { |
||||
if (nodes[node].expanded === deptExpand.value) { |
||||
continue |
||||
} |
||||
nodes[node].expanded = deptExpand.value |
||||
} |
||||
} |
||||
|
||||
async function init() { |
||||
getRoleInfo(props.roleId) |
||||
deptOptions.value = handleTree(await DeptApi.getSimpleDeptList()) |
||||
} |
||||
|
||||
onMounted(() => { |
||||
init() |
||||
}) |
||||
</script> |
@ -0,0 +1,96 @@ |
||||
<template> |
||||
<Dialog v-model="dialogVisible" :title="dialogTitle" width="400px"> |
||||
<el-form |
||||
ref="formRef" |
||||
v-loading="formLoading" |
||||
:model="formData" |
||||
:rules="formRules" |
||||
label-width="80px" |
||||
> |
||||
<el-row :gutter="20"> |
||||
<el-col :span="24" :offset="0"> |
||||
<el-form-item label="角色名称" prop="name"> |
||||
<el-input v-model="formData.name" placeholder="请输入角色名称" /> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
</el-form> |
||||
<template #footer> |
||||
<el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> |
||||
<el-button @click="dialogVisible = false">取 消</el-button> |
||||
</template> |
||||
</Dialog> |
||||
</template> |
||||
<script lang="ts" name="SystemRoleForm" setup> |
||||
// import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' |
||||
import * as RoleApi from '@/api/system/role' |
||||
|
||||
const { t } = useI18n() // 国际化 |
||||
const message = useMessage() // 消息弹窗 |
||||
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示 |
||||
const dialogTitle = ref('') // 弹窗的标题 |
||||
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 |
||||
const formType = ref('') // 表单的类型:create - 新增;update - 修改 |
||||
const formData = ref({ |
||||
id: undefined, |
||||
name: '' |
||||
}) |
||||
const formRules = reactive({ |
||||
name: [{ required: true, message: '角色名称不能为空', trigger: 'blur' }] |
||||
}) |
||||
const formRef = ref() // 表单 Ref |
||||
|
||||
/** 打开弹窗 */ |
||||
const open = async (type: string, id?: number) => { |
||||
dialogVisible.value = true |
||||
dialogTitle.value = t('action.' + type) |
||||
formType.value = type |
||||
resetForm() |
||||
// 修改时,设置数据 |
||||
if (id) { |
||||
formLoading.value = true |
||||
try { |
||||
formData.value = await RoleApi.getRole(id) |
||||
} finally { |
||||
formLoading.value = false |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** 重置表单 */ |
||||
const resetForm = () => { |
||||
formData.value = { |
||||
id: undefined, |
||||
name: '' |
||||
} |
||||
formRef.value?.resetFields() |
||||
} |
||||
defineExpose({ open }) // 提供 open 方法,用于打开弹窗 |
||||
|
||||
/** 提交表单 */ |
||||
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 |
||||
const submitForm = async () => { |
||||
// 校验表单 |
||||
if (!formRef.value) return |
||||
const valid = await formRef.value.validate() |
||||
if (!valid) return |
||||
// 提交请求 |
||||
formLoading.value = true |
||||
try { |
||||
const data = formData.value as unknown as RoleApi.RoleVO |
||||
if (formType.value === 'create') { |
||||
await RoleApi.createRole(data) |
||||
message.success(t('common.createSuccess')) |
||||
} else { |
||||
await RoleApi.updateRole(data) |
||||
message.success(t('common.updateSuccess')) |
||||
} |
||||
dialogVisible.value = false |
||||
// 发送操作成功的事件 |
||||
emit('success') |
||||
} finally { |
||||
formLoading.value = false |
||||
} |
||||
} |
||||
</script> |
@ -0,0 +1,147 @@ |
||||
<template> |
||||
<div class="flex"> |
||||
<el-card shadow="always" :body-style="{ padding: '10px' }"> |
||||
<div class="flex justify-between items-center" style="width: 300px"> |
||||
<div class="text-16px font-bold">角色列表</div> |
||||
<el-button |
||||
type="primary" |
||||
style="padding: 0px" |
||||
text |
||||
@click="openForm('create')" |
||||
v-hasPermi="['basic:role:add']" |
||||
> |
||||
新增 |
||||
</el-button> |
||||
</div> |
||||
<div class="border-top-1px mt-10px pt-10px"> |
||||
<div |
||||
class="flex justify-between items-center pl-10px pr-10px cursor-pointer pt-5px pb-5px" |
||||
v-for="(item, index) in list" |
||||
:key="index" |
||||
:class="{ actived: libraryIndex == index }" |
||||
@click="libraryIndex = index" |
||||
> |
||||
<div class="flex-1 text-14px">{{ item.name }}</div> |
||||
<div class="ml-10px"> |
||||
<el-button |
||||
type="primary" |
||||
style="padding: 0px" |
||||
text |
||||
v-hasPermi="['basic:role:update']" |
||||
@click="openForm('update', item.id)" |
||||
> |
||||
修改 |
||||
</el-button> |
||||
<el-button |
||||
type="primary" |
||||
class="ml-10px" |
||||
style="padding: 0px" |
||||
text |
||||
v-hasPermi="['basic:role:delete']" |
||||
@click="handleDelete(item.id)" |
||||
> |
||||
删除 |
||||
</el-button> |
||||
</div> |
||||
</div> |
||||
<Pagination |
||||
v-model:limit="queryParams.pageSize" |
||||
v-model:page="queryParams.pageNo" |
||||
layout="total, prev, pager, next" |
||||
small |
||||
:total="total" |
||||
@pagination="getList" |
||||
/> |
||||
</div> |
||||
</el-card> |
||||
<el-card class="ml-20px" style="flex: 1" shadow="always" :body-style="{ padding: '10px' }"> |
||||
<el-tabs v-if="list && list.length" v-model="roleOperateIndex" type="card"> |
||||
<el-tab-pane label="角色用户" :name="1"> |
||||
<RoleEmployee v-if="roleOperateIndex == 1" :roleId="list[libraryIndex].id" /> |
||||
</el-tab-pane> |
||||
<el-tab-pane label="菜单权限" :name="2"> |
||||
<RoleAssignMenuForm |
||||
v-if="roleOperateIndex == 2" |
||||
ref="assignMenuFormRef" |
||||
:roleId="list[libraryIndex].id" |
||||
@success="getList" |
||||
/> |
||||
</el-tab-pane> |
||||
<el-tab-pane label="数据权限" :name="3"> |
||||
<RoleDataPermissionForm |
||||
v-if="roleOperateIndex == 3" |
||||
ref="dataPermissionFormRef" |
||||
:roleId="list[libraryIndex].id" |
||||
@success="getList" |
||||
/> |
||||
</el-tab-pane> |
||||
</el-tabs> |
||||
</el-card> |
||||
<!-- 表单弹窗:添加/修改 --> |
||||
<RoleForm ref="formRef" @success="getList" /> |
||||
</div> |
||||
</template> |
||||
<script lang="ts" name="SystemRole" setup> |
||||
import RoleForm from './RoleForm.vue' |
||||
import RoleEmployee from './Comp/RoleEmployee.vue' |
||||
import RoleAssignMenuForm from './RoleAssignMenuForm.vue' |
||||
import RoleDataPermissionForm from './RoleDataPermissionForm.vue' |
||||
import * as RoleApi from '@/api/system/role' |
||||
|
||||
const message = useMessage() // 消息弹窗 |
||||
const { t } = useI18n() // 国际化 |
||||
|
||||
const total = ref(0) // 列表的总页数 |
||||
const list = ref<any>([]) // 列表的数据 |
||||
|
||||
const libraryIndex = ref(0) |
||||
const queryParams = reactive({ |
||||
pageNo: 1, |
||||
pageSize: 20 |
||||
}) |
||||
|
||||
/** 查询角色列表 */ |
||||
const getList = async () => { |
||||
const data = await RoleApi.getRolePage(queryParams) |
||||
list.value = data.list |
||||
total.value = data.total |
||||
} |
||||
|
||||
/** 添加/修改操作 */ |
||||
const formRef = ref() |
||||
const openForm = (type: string, id?: number) => { |
||||
formRef.value.open(type, id) |
||||
} |
||||
|
||||
/** 数据权限操作 */ |
||||
const dataPermissionFormRef = ref() |
||||
|
||||
/** 菜单权限操作 */ |
||||
const assignMenuFormRef = ref() |
||||
|
||||
/** 删除按钮操作 */ |
||||
const handleDelete = async (id: number) => { |
||||
try { |
||||
// 删除的二次确认 |
||||
await message.delConfirm() |
||||
// 发起删除 |
||||
await RoleApi.deleteRole(id) |
||||
message.success(t('common.delSuccess')) |
||||
// 刷新列表 |
||||
await getList() |
||||
} catch {} |
||||
} |
||||
|
||||
const roleOperateIndex = ref(1) |
||||
|
||||
/** 初始化 **/ |
||||
onMounted(() => { |
||||
getList() |
||||
}) |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.actived { |
||||
background-color: var(--el-color-primary-light-9); |
||||
} |
||||
</style> |
@ -0,0 +1,56 @@ |
||||
<template> |
||||
<div class="head-container"> |
||||
<el-input v-model="deptName" class="mb-20px" clearable placeholder="请输入部门名称"> |
||||
<template #prefix> |
||||
<Icon icon="ep:search" /> |
||||
</template> |
||||
</el-input> |
||||
</div> |
||||
<div class="head-container"> |
||||
<el-tree |
||||
ref="treeRef" |
||||
:data="deptList" |
||||
:expand-on-click-node="false" |
||||
:filter-node-method="filterNode" |
||||
:props="defaultProps" |
||||
default-expand-all |
||||
highlight-current |
||||
node-key="id" |
||||
@node-click="handleNodeClick" |
||||
/> |
||||
</div> |
||||
</template> |
||||
|
||||
<script lang="ts" name="SystemUserDeptTree" setup> |
||||
import { ElTree } from 'element-plus' |
||||
import * as DeptApi from '@/api/system/dept' |
||||
import { defaultProps, handleTree } from '@/utils/tree' |
||||
|
||||
const deptName = ref('') |
||||
const deptList = ref<Tree[]>([]) // 树形结构 |
||||
const treeRef = ref<InstanceType<typeof ElTree>>() |
||||
|
||||
/** 获得部门树 */ |
||||
const getTree = async () => { |
||||
const res = await DeptApi.getSimpleDeptList() |
||||
deptList.value = [] |
||||
deptList.value.push(...handleTree(res)) |
||||
} |
||||
|
||||
/** 基于名字过滤 */ |
||||
const filterNode = (name: string, data: Tree) => { |
||||
if (!name) return true |
||||
return data.name.includes(name) |
||||
} |
||||
|
||||
/** 处理部门被点击 */ |
||||
const handleNodeClick = async (row: { [key: string]: any }) => { |
||||
emits('node-click', row) |
||||
} |
||||
const emits = defineEmits(['node-click']) |
||||
|
||||
/** 初始化 */ |
||||
onMounted(async () => { |
||||
await getTree() |
||||
}) |
||||
</script> |
@ -0,0 +1,228 @@ |
||||
<template> |
||||
<Dialog v-model="dialogVisible" :title="dialogTitle" style="width: 800px"> |
||||
<el-form |
||||
ref="formRef" |
||||
v-loading="formLoading" |
||||
:model="formData" |
||||
:rules="formRules" |
||||
label-width="80px" |
||||
> |
||||
<el-row :gutter="20"> |
||||
<el-col :span="12"> |
||||
<el-form-item label="用户姓名" prop="nickname"> |
||||
<el-input v-model="formData.nickname" placeholder="请输入用户姓名" /> |
||||
</el-form-item> |
||||
</el-col> |
||||
<!-- <el-col :span="12"> |
||||
<el-form-item label="用户性别"> |
||||
<el-radio-group v-model="formData.sex"> |
||||
<el-radio :value="1"> 男 </el-radio> |
||||
<el-radio :value="2"> 女 </el-radio> |
||||
</el-radio-group> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
<el-row :gutter="20"> |
||||
<el-col :span="12"> |
||||
<el-form-item label="归属部门" prop="deptId"> |
||||
<el-tree-select |
||||
v-model="formData.deptId" |
||||
:data="deptList" |
||||
:props="defaultProps" |
||||
check-strictly |
||||
node-key="id" |
||||
placeholder="请选择归属部门" |
||||
/> |
||||
</el-form-item> |
||||
</el-col> --> |
||||
<el-col :span="12"> |
||||
<el-form-item label="角色" prop="role"> |
||||
<el-select |
||||
v-model="formData.roleIds" |
||||
multiple |
||||
collapse-tags |
||||
collapse-tags-tooltip |
||||
:max-collapse-tags="2" |
||||
placeholder="请选择角色" |
||||
> |
||||
<el-option |
||||
v-for="item in roleOptions" |
||||
:key="item.id" |
||||
:label="item.name" |
||||
:value="item.id" |
||||
/> |
||||
</el-select> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
<el-row :gutter="20"> |
||||
<el-col :span="12"> |
||||
<el-form-item label="手机号码" prop="mobile"> |
||||
<el-input v-model="formData.mobile" maxlength="11" placeholder="请输入手机号码" /> |
||||
</el-form-item> |
||||
</el-col> |
||||
<el-col :span="12"> |
||||
<el-form-item label="邮箱" prop="email"> |
||||
<el-input v-model="formData.email" maxlength="50" placeholder="请输入邮箱" /> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
<el-row :gutter="20"> |
||||
<el-col :span="12"> |
||||
<el-form-item v-if="formData.id === undefined" label="登录账号" prop="username"> |
||||
<el-input v-model="formData.username" placeholder="请输入登录账号" /> |
||||
</el-form-item> |
||||
</el-col> |
||||
<el-col :span="12"> |
||||
<el-form-item v-if="formData.id === undefined" label="用户密码" prop="password"> |
||||
<el-input |
||||
v-model="formData.password" |
||||
placeholder="请输入用户密码" |
||||
show-password |
||||
type="password" |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
<!-- <el-row :gutter="20"> |
||||
<el-col :span="12" :offset="0"> |
||||
<el-form-item label="入职日期" prop="hireDate"> |
||||
<el-date-picker |
||||
v-model="formData.hireDate" |
||||
type="date" |
||||
format="YYYY-MM-DD" |
||||
value-format="YYYY-MM-DD" |
||||
placeholder="选择日期时间" |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> --> |
||||
<el-row :gutter="20"> |
||||
<el-col :span="24"> |
||||
<el-form-item label="备注"> |
||||
<el-input v-model="formData.remark" placeholder="请输入内容" type="textarea" /> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
</el-form> |
||||
<template #footer> |
||||
<el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> |
||||
<el-button @click="dialogVisible = false">取 消</el-button> |
||||
</template> |
||||
</Dialog> |
||||
</template> |
||||
<script lang="ts" name="SystemUserForm" setup> |
||||
import { CommonStatusEnum } from '@/utils/constants' |
||||
// import { defaultProps, handleTree } from '@/utils/tree' |
||||
import { handleTree } from '@/utils/tree' |
||||
import { formatDate } from '@/utils/formatTime' |
||||
|
||||
import * as RoleApi from '@/api/system/role' |
||||
import * as DeptApi from '@/api/system/dept' |
||||
import * as UserApi from '@/api/system/user' |
||||
|
||||
const { t } = useI18n() // 国际化 |
||||
const message = useMessage() // 消息弹窗 |
||||
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示 |
||||
const dialogTitle = ref('') // 弹窗的标题 |
||||
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 |
||||
const formType = ref('') // 表单的类型:create - 新增;update - 修改 |
||||
const formData = ref({ |
||||
nickname: '', |
||||
deptId: '', |
||||
mobile: '', |
||||
email: '', |
||||
id: undefined, |
||||
username: '', |
||||
password: '', |
||||
sex: 1, |
||||
remark: '', |
||||
status: CommonStatusEnum.ENABLE, |
||||
roleIds: [], |
||||
hireDate: '' |
||||
}) |
||||
const formRules = ref<any>({ |
||||
username: [{ required: true, message: '登录账号不能为空', trigger: 'blur' }], |
||||
nickname: [{ required: true, message: '用户姓名不能为空', trigger: 'blur' }], |
||||
password: [{ required: true, message: '用户密码不能为空', trigger: 'blur' }], |
||||
email: [ |
||||
{ |
||||
type: 'email', |
||||
message: '请输入正确的邮箱地址', |
||||
trigger: ['blur', 'change'] |
||||
} |
||||
], |
||||
mobile: [{ required: true, message: '手机号不能为空', trigger: 'blur' }] |
||||
}) |
||||
const formRef = ref() // 表单 Ref |
||||
const deptList = ref<Tree[]>([]) // 树形结构 |
||||
const roleOptions = ref<any>([]) |
||||
|
||||
/** 打开弹窗 */ |
||||
const open = async (type: string, id?: number) => { |
||||
dialogVisible.value = true |
||||
dialogTitle.value = t('action.' + type) |
||||
formType.value = type |
||||
resetForm() |
||||
// 修改时,设置数据 |
||||
if (id) { |
||||
formLoading.value = true |
||||
try { |
||||
formData.value = await UserApi.getUser(id) |
||||
} finally { |
||||
formLoading.value = false |
||||
} |
||||
} |
||||
// 加载部门树 |
||||
deptList.value = handleTree(await DeptApi.getSimpleDeptList({ allFlag: false })) |
||||
// 加载岗位列表 |
||||
roleOptions.value = await RoleApi.getSimpleRoleList() |
||||
} |
||||
defineExpose({ open }) // 提供 open 方法,用于打开弹窗 |
||||
|
||||
/** 提交表单 */ |
||||
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 |
||||
const submitForm = async () => { |
||||
// 校验表单 |
||||
if (!formRef.value) return |
||||
const valid = await formRef.value.validate() |
||||
if (!valid) return |
||||
// 提交请求 |
||||
formLoading.value = true |
||||
try { |
||||
const data = formData.value as unknown as UserApi.UserVO |
||||
if (formType.value === 'create') { |
||||
await UserApi.createUser(data) |
||||
message.success(t('common.createSuccess')) |
||||
} else { |
||||
await UserApi.updateUser(data) |
||||
message.success(t('common.updateSuccess')) |
||||
} |
||||
dialogVisible.value = false |
||||
// 发送操作成功的事件 |
||||
emit('success') |
||||
} finally { |
||||
formLoading.value = false |
||||
} |
||||
} |
||||
|
||||
/** 重置表单 */ |
||||
const resetForm = () => { |
||||
formData.value = { |
||||
nickname: '', |
||||
deptId: '', |
||||
mobile: '', |
||||
email: '', |
||||
id: undefined, |
||||
username: '', |
||||
password: '', |
||||
sex: 1, |
||||
remark: '', |
||||
status: CommonStatusEnum.ENABLE, |
||||
roleIds: [], |
||||
hireDate: formatDate(new Date(), 'YYYY-MM-DD') |
||||
} |
||||
formRef.value?.resetFields() |
||||
} |
||||
</script> |
@ -0,0 +1,209 @@ |
||||
<template> |
||||
<!-- <el-row :gutter="20"> --> |
||||
<!-- 左侧部门树 --> |
||||
<!-- <el-col :span="4" :xs="24"> |
||||
<DeptTree @node-click="handleDeptNodeClick" /> |
||||
</el-col> |
||||
<el-col :span="20" :xs="24"> --> |
||||
<!-- 搜索 --> |
||||
<el-form :model="queryParams" ref="queryFormRef" inline label-width="0"> |
||||
<el-form-item prop="nickname"> |
||||
<el-input |
||||
v-model="queryParams.nickname" |
||||
placeholder="请输入姓名" |
||||
clearable |
||||
@keyup.enter="handleQuery" |
||||
class="!w-240px" |
||||
/> |
||||
</el-form-item> |
||||
<el-form-item prop="mobile"> |
||||
<el-input |
||||
v-model="queryParams.mobile" |
||||
placeholder="请输入手机号码" |
||||
clearable |
||||
@keyup.enter="handleQuery" |
||||
class="!w-240px" |
||||
/> |
||||
</el-form-item> |
||||
<el-form-item> |
||||
<el-button @click="handleQuery" v-hasPermi="['basic:employee:search']">搜索</el-button> |
||||
<el-button @click="resetQuery" v-hasPermi="['basic:employee:reset']">重置</el-button> |
||||
<el-button |
||||
type="primary" |
||||
plain |
||||
@click="openForm('create')" |
||||
v-hasPermi="['basic:employee:add']" |
||||
> |
||||
新增 |
||||
</el-button> |
||||
</el-form-item> |
||||
</el-form> |
||||
<el-table v-loading="loading" :data="list"> |
||||
<el-table-column label="用户编号" key="id" prop="id" /> |
||||
<el-table-column label="登录账号" prop="username" /> |
||||
<el-table-column label="用户姓名" prop="nickname" /> |
||||
<!-- <el-table-column label="部门" key="deptName" prop="deptName" /> --> |
||||
<el-table-column label="手机号码" prop="mobile" width="120" /> |
||||
<el-table-column label="状态" key="status"> |
||||
<template #default="scope"> |
||||
<el-switch |
||||
v-model="scope.row.status" |
||||
:active-value="0" |
||||
:inactive-value="1" |
||||
active-text="在职" |
||||
inactive-text="离职" |
||||
v-hasPermi="['basic:employee:update']" |
||||
@change="handleStatusChange(scope.row)" |
||||
/> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="创建时间" prop="createTime" width="180" :formatter="dateFormatter" /> |
||||
<el-table-column label="操作" width="260"> |
||||
<template #default="scope"> |
||||
<el-button |
||||
type="primary" |
||||
link |
||||
@click="openForm('update', scope.row.id)" |
||||
v-hasPermi="['basic:employee:update']" |
||||
> |
||||
修改 |
||||
</el-button> |
||||
<el-button |
||||
type="primary" |
||||
link |
||||
@click="handleDelete(scope.row.id)" |
||||
v-hasPermi="['basic:employee:delete']" |
||||
> |
||||
删除 |
||||
</el-button> |
||||
<el-button |
||||
type="primary" |
||||
link |
||||
@click="handleResetPwd(scope.row)" |
||||
v-hasPermi="['basic:employee:password']" |
||||
> |
||||
重置密码 |
||||
</el-button> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
<Pagination |
||||
:total="total" |
||||
v-model:page="queryParams.pageNo" |
||||
v-model:limit="queryParams.pageSize" |
||||
@pagination="getList" |
||||
/> |
||||
<!-- </el-col> --> |
||||
<!-- </el-row> --> |
||||
|
||||
<!-- 添加或修改用户对话框 --> |
||||
<UserForm ref="formRef" @success="getList" /> |
||||
</template> |
||||
<script setup lang="ts" name="SystemUser"> |
||||
import { CommonStatusEnum } from '@/utils/constants' |
||||
import { dateFormatter } from '@/utils/formatTime' |
||||
import * as UserApi from '@/api/system/user' |
||||
import UserForm from './UserForm.vue' |
||||
// import DeptTree from './DeptTree.vue' |
||||
const message = useMessage() // 消息弹窗 |
||||
const { t } = useI18n() // 国际化 |
||||
|
||||
const loading = ref(true) // 列表的加载中 |
||||
const total = ref(0) // 列表的总页数 |
||||
const list = ref([]) // 列表的数 |
||||
const queryParams = reactive({ |
||||
pageNo: 1, |
||||
pageSize: 10, |
||||
username: undefined, |
||||
nickname: undefined, |
||||
mobile: undefined, |
||||
deptId: undefined |
||||
}) |
||||
const queryFormRef = ref() // 搜索的表单 |
||||
|
||||
/** 查询列表 */ |
||||
const getList = async () => { |
||||
loading.value = true |
||||
try { |
||||
const data = await UserApi.getUserPage(queryParams) |
||||
list.value = data.list |
||||
total.value = data.total |
||||
} finally { |
||||
loading.value = false |
||||
} |
||||
} |
||||
|
||||
/** 搜索按钮操作 */ |
||||
const handleQuery = () => { |
||||
queryParams.pageNo = 1 |
||||
getList() |
||||
} |
||||
|
||||
/** 重置按钮操作 */ |
||||
const resetQuery = () => { |
||||
queryFormRef.value?.resetFields() |
||||
handleQuery() |
||||
} |
||||
|
||||
// /** 处理部门被点击 */ |
||||
// const handleDeptNodeClick = async (row) => { |
||||
// queryParams.deptId = row.id |
||||
// await getList() |
||||
// } |
||||
|
||||
/** 添加/修改操作 */ |
||||
const formRef = ref() |
||||
const openForm = (type: string, id?: number) => { |
||||
formRef.value.open(type, id) |
||||
} |
||||
|
||||
/** 修改用户状态 */ |
||||
const handleStatusChange = async (row: UserApi.UserVO) => { |
||||
try { |
||||
// 修改状态的二次确认 |
||||
const text = row.status === CommonStatusEnum.ENABLE ? '启用' : '停用' |
||||
await message.confirm('确认要"' + text + '""' + row.username + '"用户吗?') |
||||
// 发起修改状态 |
||||
await UserApi.updateUserStatus(row.id, row.status) |
||||
// 刷新列表 |
||||
await getList() |
||||
} catch { |
||||
// 取消后,进行恢复按钮 |
||||
row.status = |
||||
row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.DISABLE : CommonStatusEnum.ENABLE |
||||
} |
||||
} |
||||
|
||||
/** 删除按钮操作 */ |
||||
const handleDelete = async (id: number) => { |
||||
try { |
||||
// 删除的二次确认 |
||||
await message.delConfirm() |
||||
// 发起删除 |
||||
await UserApi.deleteUser(id) |
||||
message.success(t('common.delSuccess')) |
||||
// 刷新列表 |
||||
await getList() |
||||
} catch {} |
||||
} |
||||
|
||||
/** 重置密码 */ |
||||
const handleResetPwd = async (row: UserApi.UserVO) => { |
||||
try { |
||||
// 重置的二次确认 |
||||
const result = await message.prompt( |
||||
'请输入"' + row.username + '"的新密码', |
||||
t('common.reminder') |
||||
) |
||||
const password = result.value |
||||
// 发起重置 |
||||
await UserApi.resetUserPwd(row.id, password) |
||||
message.success('修改成功,新密码是:' + password) |
||||
} catch {} |
||||
} |
||||
|
||||
/** 初始化 */ |
||||
onMounted(() => { |
||||
getList() |
||||
}) |
||||
</script> |
@ -0,0 +1,344 @@ |
||||
<template> |
||||
<el-dialog |
||||
title="试题" |
||||
:close-on-click-modal="false" |
||||
append-to-body |
||||
v-model="visible" |
||||
width="900px" |
||||
> |
||||
<div> |
||||
<el-form |
||||
ref="dialogFormRef" |
||||
:model="dialogForm" |
||||
:rules="dataRule" |
||||
label-width="auto" |
||||
label-position="right" |
||||
@keyup.enter="dialogFormSubmit()" |
||||
> |
||||
<el-row> |
||||
<el-col :span="24"> |
||||
<el-form-item label="题目" prop="question"> |
||||
<el-input |
||||
v-model="dialogForm.question" |
||||
maxlength="200" |
||||
placeholder="请输入题目" |
||||
clearable |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
<el-row> |
||||
<el-col :span="24"> |
||||
<el-form-item label="题目关键字" prop="titleWords"> |
||||
<el-input |
||||
v-model="dialogForm.titleWords" |
||||
maxlength="1000" |
||||
placeholder="请输入" |
||||
clearable |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
<el-row :gutter="20"> |
||||
<el-col :span="12"> |
||||
<el-form-item label="专项" prop="categoryTitle"> |
||||
<el-input |
||||
v-model="dialogForm.categoryTitle" |
||||
maxlength="1000" |
||||
placeholder="请输入" |
||||
clearable |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
<el-col :span="12"> |
||||
<el-form-item label="章节" prop="chapter"> |
||||
<el-select v-model="dialogForm.chapter" style="width: 100%"> |
||||
<el-option |
||||
v-for="dict in chapterOptions" |
||||
:key="dict.chapterId" |
||||
:label="dict.chapterName" |
||||
:value="dict.chapterId" |
||||
/> |
||||
</el-select> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
|
||||
<el-row :gutter="20"> |
||||
<el-col :span="12"> |
||||
<el-form-item label="题型" prop="type"> |
||||
<el-radio-group v-model="dialogForm.type"> |
||||
<el-radio label="1" value="1">判断题</el-radio> |
||||
<el-radio label="2" value="2">单选题</el-radio> |
||||
<el-radio label="3" value="3">多选题</el-radio> |
||||
</el-radio-group> |
||||
</el-form-item> |
||||
</el-col> |
||||
|
||||
<el-col :span="12"> |
||||
<el-form-item label="排序" prop="showOrder"> |
||||
<el-input |
||||
v-model="dialogForm.showOrder" |
||||
maxlength="20" |
||||
placeholder="请输入" |
||||
clearable |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
<el-row :gutter="20"> |
||||
<el-col :span="12"> |
||||
<el-form-item label="选项A" prop="chooseA"> |
||||
<el-input |
||||
v-model="dialogForm.chooseA" |
||||
maxlength="200" |
||||
placeholder="请输入" |
||||
clearable |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
<el-col :span="12"> |
||||
<el-form-item label="选项B" prop="chooseB"> |
||||
<el-input |
||||
v-model="dialogForm.chooseB" |
||||
maxlength="200" |
||||
placeholder="请输入" |
||||
clearable |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
<el-row :gutter="20"> |
||||
<el-col :span="12"> |
||||
<el-form-item label="选项C" prop="chooseC"> |
||||
<el-input |
||||
v-model="dialogForm.chooseC" |
||||
maxlength="200" |
||||
placeholder="请输入" |
||||
clearable |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
<el-col :span="12"> |
||||
<el-form-item label="选项D" prop="chooseD"> |
||||
<el-input |
||||
v-model="dialogForm.chooseD" |
||||
maxlength="200" |
||||
placeholder="请输入" |
||||
clearable |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
<el-row> |
||||
<el-col :span="24"> |
||||
<el-form-item label="答案" prop="trueAnswer"> |
||||
<el-input |
||||
v-model="dialogForm.trueAnswer" |
||||
maxlength="200" |
||||
placeholder="请输入" |
||||
clearable |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
<el-row> |
||||
<el-col :span="24"> |
||||
<el-form-item label="难点分析" prop="bestAnswer"> |
||||
<el-input |
||||
v-model="dialogForm.bestAnswer" |
||||
maxlength="1000" |
||||
placeholder="请输入" |
||||
clearable |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
<el-row> |
||||
<el-col :span="24"> |
||||
<el-form-item label="答题技巧" prop="skillInfo"> |
||||
<el-input |
||||
v-model="dialogForm.skillInfo" |
||||
maxlength="1000" |
||||
placeholder="请输入" |
||||
clearable |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
|
||||
<el-row> |
||||
<el-col :span="24"> |
||||
<el-form-item label="技巧关键字" prop="skillWords"> |
||||
<el-input |
||||
v-model="dialogForm.skillWords" |
||||
maxlength="1000" |
||||
placeholder="请输入" |
||||
clearable |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
<el-row> |
||||
<el-col :span="24"> |
||||
<el-form-item label="车型" prop="carTypeId"> |
||||
<span v-if="dialogForm.carTypeId == '1001'">小车</span> |
||||
<span v-if="dialogForm.carTypeId == '1002'">摩托车</span> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
<el-row> |
||||
<el-col :span="24"> |
||||
<el-form-item label="科目" prop="subject"> |
||||
<span v-if="dialogForm.subject == '1'">科一</span> |
||||
<span v-if="dialogForm.subject == '4'">科四</span> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
<el-row :gutter="20"> |
||||
<el-form-item label="题目图片" prop="imageUrl"> |
||||
<el-upload |
||||
action="#" |
||||
accept=".png,.jpg,.jpeg,.gif" |
||||
:limit="1" |
||||
:http-request="handleImport" |
||||
:on-exceed="handleExceed" |
||||
:show-file-list="false" |
||||
> |
||||
<img v-if="imgUrl" :src="imgUrl" style="width: 200px" /> |
||||
<i v-else class="el-icon-plus"></i> |
||||
</el-upload> |
||||
</el-form-item> |
||||
</el-row> |
||||
</el-form> |
||||
</div> |
||||
<template #footer> |
||||
<span class="dialog-footer"> |
||||
<el-button plain @click="visible = false">取消</el-button> |
||||
<el-button type="primary" :disabled="!canSubmit" @click="dialogFormSubmit()"> |
||||
确定 |
||||
</el-button> |
||||
</span> |
||||
</template> |
||||
</el-dialog> |
||||
</template> |
||||
|
||||
<script setup name="QuesAddForm"> |
||||
import { addQuestion, updateQuestion, uploadFile } from '@/api/xjapplet/xjdatabase' |
||||
|
||||
const message = useMessage() // 消息弹窗 |
||||
|
||||
const emit = defineEmits(['update']) |
||||
|
||||
const visible = ref(false) |
||||
const canSubmit = ref(true) |
||||
const imgUrl = ref(undefined) |
||||
const chapterOptions = ref([]) |
||||
const dialogForm = ref({ |
||||
id: undefined, |
||||
showOrder: 0, |
||||
categoryTitle: undefined, |
||||
question: undefined, |
||||
bestAnswer: undefined, |
||||
chooseA: undefined, |
||||
chooseB: undefined, |
||||
chooseC: undefined, |
||||
chooseD: undefined, |
||||
imageUrl: undefined, |
||||
type: undefined, |
||||
trueAnswer: undefined, |
||||
carTypeId: undefined, |
||||
skillInfoPic: undefined, |
||||
source: undefined |
||||
}) |
||||
|
||||
const dataRule = { |
||||
schoolName: [{ required: true, message: '驾校名称不能为空', trigger: 'blur' }], |
||||
status: [{ required: true, message: '状态不能为空', trigger: 'blur' }] |
||||
} |
||||
|
||||
const open = (info = undefined, opts) => { |
||||
visible.value = true |
||||
chapterOptions.value = opts |
||||
resetDialogForm() |
||||
if (info) { |
||||
dialogForm.value = { ...info, chapter: parseInt(info.chapter) } |
||||
if (dialogForm.value.imageUrl) { |
||||
imgUrl.value = 'https://ss-cloud.ahduima.com/xjxc/pic/' + dialogForm.value.imageUrl |
||||
} |
||||
} |
||||
info.source = info.source |
||||
} |
||||
|
||||
defineExpose({ |
||||
open |
||||
}) |
||||
|
||||
const resetDialogForm = () => { |
||||
dialogForm.value = { |
||||
id: undefined, |
||||
showOrder: 0, |
||||
question: undefined, |
||||
bestAnswer: undefined, |
||||
chooseA: undefined, |
||||
chooseB: undefined, |
||||
chooseC: undefined, |
||||
chooseD: undefined, |
||||
imageUrl: undefined, |
||||
type: undefined, |
||||
trueAnswer: undefined, |
||||
carTypeId: undefined, |
||||
skillInfoPic: undefined, |
||||
skillInfo: undefined, |
||||
jqtp: undefined, |
||||
biaoji: undefined, |
||||
titleWords: undefined, |
||||
skillWords: undefined, |
||||
optaWords: undefined, |
||||
optbWords: undefined, |
||||
optcWords: undefined, |
||||
optdWords: undefined, |
||||
carTypeId: undefined, |
||||
source: undefined |
||||
} |
||||
} |
||||
const dialogFormRef = ref(null) |
||||
// 表单提交 |
||||
const dialogFormSubmit = async () => { |
||||
if (!dialogFormRef.value) return |
||||
const valid = await dialogFormRef.value.validate() |
||||
if (!valid) return |
||||
|
||||
if (dialogForm.value.questionId) { |
||||
updateQuestion(dialogForm.value).then((response) => { |
||||
if (response) { |
||||
message.success('修改成功') |
||||
emit('update') |
||||
visible.value = false |
||||
} |
||||
}) |
||||
} else { |
||||
addQuestion(dialogForm.value).then((response) => { |
||||
if (response) { |
||||
message.success('新增成功') |
||||
visible.value = false |
||||
emit('update') |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
const handleImport = (opt) => { |
||||
const data = new FormData() |
||||
data.append('file', opt.file) |
||||
uploadFile(data).then((resp) => { |
||||
if (resp.code == 200) { |
||||
message.success('文件上传成功') |
||||
dialogForm.value.imageUrl = resp.data |
||||
imgUrl.value = 'https://ss-cloud.ahduima.com/xjxc/pic/' + dialogForm.value.imageUrl |
||||
} |
||||
}) |
||||
} |
||||
const handleExceed = (files) => { |
||||
handleImport({ file: files[0] }) |
||||
} |
||||
</script> |
@ -0,0 +1,228 @@ |
||||
<template> |
||||
<div class="app-container" style="text-align: center"> |
||||
<el-tabs v-model="queryParams.source" @tab-click="handleChangeSource"> |
||||
<el-tab-pane |
||||
v-for="item in sourceOptions" |
||||
:key="item.key" |
||||
:label="item.label" |
||||
:name="item.key" |
||||
> |
||||
<el-form :inline="true" label-width="68px" @submit.prevent> |
||||
<el-row :gutter="20"> |
||||
<el-form-item label="车型"> |
||||
<el-radio-group v-model="queryParams.carTypeId" @change="getQuestionChapter"> |
||||
<el-radio label="1001" value="1001">小车</el-radio> |
||||
<el-radio label="1002" value="1002">摩托车</el-radio> |
||||
</el-radio-group> |
||||
</el-form-item> |
||||
<el-form-item label="科目"> |
||||
<el-radio-group v-model="queryParams.subject" @change="getQuestionChapter"> |
||||
<el-radio label="1" value="1">科一</el-radio> |
||||
<el-radio label="4" value="4">科四</el-radio> |
||||
</el-radio-group> |
||||
</el-form-item> |
||||
|
||||
<el-form-item label="有图片"> |
||||
<el-radio-group v-model="queryParams.isPic"> |
||||
<el-radio :label="true" :value="true">有</el-radio> |
||||
<el-radio :label="false" :value="false">无</el-radio> |
||||
</el-radio-group> |
||||
</el-form-item> |
||||
</el-row> |
||||
<el-row :gutter="20"> |
||||
<el-form-item label="题目"> |
||||
<el-input |
||||
v-model="queryParams.question" |
||||
placeholder="请输入题目" |
||||
clearable |
||||
style="width: 400px" |
||||
@keyup.enter="handleQuery" |
||||
/> |
||||
</el-form-item> |
||||
<el-form-item> |
||||
<el-button |
||||
type="primary" |
||||
@click="handleQuery" |
||||
v-hasPermi="['question:database:search']" |
||||
> |
||||
搜索 |
||||
</el-button> |
||||
<el-button type="primary" @click="handleAdd" v-hasPermi="['question:database:add']"> |
||||
新增 |
||||
</el-button> |
||||
</el-form-item> |
||||
</el-row> |
||||
</el-form> |
||||
|
||||
<el-table |
||||
v-loading="loading" |
||||
:data="tableList" |
||||
highlight-current-row |
||||
max-height="calc(100vh - 260px)" |
||||
> |
||||
<el-table-column type="index" width="55" align="center" /> |
||||
<el-table-column label="题目" align="left" prop="question" min-width="140" /> |
||||
<el-table-column label="选项" align="left" min-width="140"> |
||||
<template #default="{ row }"> |
||||
<p v-if="row.chooseA">A:{{ row.chooseA }}</p> |
||||
<p v-if="row.chooseB">B:{{ row.chooseB }}</p> |
||||
<p v-if="row.chooseC">C:{{ row.chooseC }}</p> |
||||
<p v-if="row.chooseD">D:{{ row.chooseD }}</p> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="答案" align="center" prop="trueAnswer" width="100" /> |
||||
<el-table-column label="科目" align="center" prop="subject" width="100"> |
||||
<template #default="{ row }"> |
||||
<span v-if="row.subject == '1'">科一</span> |
||||
<span v-if="row.subject == '4'">科四</span> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="章节" align="center" prop="chapterName" min-width="100" /> |
||||
<el-table-column label="图片" align="center" width="100"> |
||||
<template #default="{ row }"> |
||||
<el-image |
||||
v-if="row.imageUrl" |
||||
:src="`https://ss-cloud.ahduima.com/xjxc/pic/${row.imageUrl}`" |
||||
:preview-src-list="[`https://ss-cloud.ahduima.com/xjxc/pic/${row.imageUrl}`]" |
||||
:lazy="true" |
||||
style="width: 80px" |
||||
preview-teleported |
||||
/> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="状态" width="100"> |
||||
<template #default="{ row }"> |
||||
<el-tag v-if="row.isActive == 0" type="success">使用中</el-tag> |
||||
<el-tag v-else type="danger">已删除</el-tag> |
||||
</template> |
||||
</el-table-column> |
||||
|
||||
<el-table-column label="操作" align="center" width="140"> |
||||
<template #default="scope"> |
||||
<el-button |
||||
type="primary" |
||||
link |
||||
@click="handleEdit(scope.row)" |
||||
v-hasPermi="['question:database:edit']" |
||||
> |
||||
修改 |
||||
</el-button> |
||||
<el-button |
||||
type="primary" |
||||
link |
||||
@click="handleDelete(scope.row.id)" |
||||
v-hasPermi="['question:database:remove']" |
||||
> |
||||
删除 |
||||
</el-button> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
|
||||
<pagination |
||||
v-show="total > 0" |
||||
:total="total" |
||||
v-model:page="queryParams.pageNo" |
||||
v-model:limit="queryParams.pageSize" |
||||
@pagination="getList" |
||||
/> |
||||
</el-tab-pane> |
||||
</el-tabs> |
||||
|
||||
<QuestionAddForm ref="dialogAddForm" @update="getList" /> |
||||
</div> |
||||
</template> |
||||
|
||||
<script setup name="XjDatabase"> |
||||
import { searchQuestion, deleteQuestion, getQuestionSort } from '@/api/xjapplet/xjdatabase' |
||||
import QuestionAddForm from './components/QuestionAddForm.vue' |
||||
|
||||
const loading = ref(false) |
||||
const total = ref(0) |
||||
const tableList = ref([]) |
||||
const queryParams = ref({ |
||||
source: '1', |
||||
question: '', |
||||
carTypeId: '1001', |
||||
subject: '1', |
||||
isPic: undefined, |
||||
pageNo: 1, |
||||
pageSize: 100 |
||||
}) |
||||
|
||||
const sourceOptions = [ |
||||
{ |
||||
key: '1', |
||||
label: '驾考精灵' |
||||
}, |
||||
{ |
||||
key: '2', |
||||
label: '驾校一点通' |
||||
} |
||||
] |
||||
|
||||
onMounted(() => { |
||||
getQuestionChapter() |
||||
}) |
||||
|
||||
const chapterOptions = ref([]) |
||||
const getQuestionChapter = () => { |
||||
getQuestionSort({ |
||||
carTypeId: queryParams.value.carTypeId, |
||||
subject: queryParams.value.subject, |
||||
source: queryParams.value.source |
||||
}).then((data) => { |
||||
chapterOptions.value = data |
||||
}) |
||||
} |
||||
|
||||
function getList() { |
||||
loading.value = true |
||||
searchQuestion(queryParams.value).then((response) => { |
||||
tableList.value = response.list |
||||
total.value = response.total |
||||
loading.value = false |
||||
}) |
||||
} |
||||
|
||||
function handleQuery() { |
||||
getList() |
||||
} |
||||
|
||||
const dialogAddForm = ref(null) |
||||
function handleEdit(item) { |
||||
dialogAddForm.value.open(item, chapterOptions.value) |
||||
} |
||||
|
||||
function handleAdd() { |
||||
dialogAddForm.value.open( |
||||
{ |
||||
subject: queryParams.value.subject, |
||||
carTypeId: queryParams.value.carTypeId, |
||||
source: queryParams.value.source |
||||
}, |
||||
chapterOptions.value |
||||
) |
||||
} |
||||
|
||||
function handleDelete(id) { |
||||
deleteQuestion(id).then(() => { |
||||
getList() |
||||
}) |
||||
} |
||||
|
||||
function handleChangeSource() { |
||||
const obj = { |
||||
question: '', |
||||
carTypeId: '1001', |
||||
subject: '1', |
||||
isPic: undefined, |
||||
pageNo: 1 |
||||
} |
||||
queryParams.value = { ...obj, source: queryParams.value.source } |
||||
getQuestionChapter() |
||||
getList() |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped></style> |
@ -0,0 +1,7 @@ |
||||
<template> |
||||
<div> 基础设置 </div> |
||||
</template> |
||||
|
||||
<script setup name="QuestionSetting"></script> |
||||
|
||||
<style lang="scss" scoped></style> |
@ -0,0 +1,7 @@ |
||||
<template> |
||||
<div> 无人机题库 </div> |
||||
</template> |
||||
|
||||
<script setup name="UAV"></script> |
||||
|
||||
<style lang="scss" scoped></style> |
@ -0,0 +1,7 @@ |
||||
<template> |
||||
<div> 无人机VIP </div> |
||||
</template> |
||||
|
||||
<script setup name="UAVVip"></script> |
||||
|
||||
<style lang="scss" scoped></style> |
@ -0,0 +1,310 @@ |
||||
<template> |
||||
<div> |
||||
<el-form inline label-width="68px" @submit.prevent> |
||||
<el-row :gutter="20"> |
||||
<el-form-item label="车型" @change="searchMj"> |
||||
<el-radio-group v-model="queryParams.carTypeId"> |
||||
<el-radio label="1001" value="1001">小车</el-radio> |
||||
<el-radio label="1002" value="1002">摩托车</el-radio> |
||||
</el-radio-group> |
||||
</el-form-item> |
||||
<el-form-item label="科目"> |
||||
<el-radio-group v-model="queryParams.subject" @change="searchMj"> |
||||
<el-radio label="1" value="1">科一</el-radio> |
||||
<el-radio label="4" value="4">科四</el-radio> |
||||
</el-radio-group> |
||||
</el-form-item> |
||||
</el-row> |
||||
</el-form> |
||||
<div style="display: flex; padding: 10px; border: 1px solid #eee; height: calc(100vh - 80px)"> |
||||
<div style="width: 300px; border-right: 1px solid #eee"> |
||||
<div style="display: flex; justify-content: space-between; padding-right: 20px"> |
||||
<div style="font-size: 18px; font-weight: bold">密卷</div> |
||||
<el-button |
||||
type="primary" |
||||
link |
||||
@click="addMjItem" |
||||
v-hasPermi="['questiont:vip-data:mj:add']" |
||||
>新增</el-button |
||||
> |
||||
</div> |
||||
<el-radio-group |
||||
v-model="mjIndex" |
||||
style="width: 100%; display: block; margin-top: 20px" |
||||
@change="getQuestionList" |
||||
> |
||||
<el-radio v-for="(item, index) in mjList" :key="index" :label="index" class="flex-radio"> |
||||
<div style="flex: 1; width: 100px">{{ getMjTitle(index) }}</div> |
||||
<div style="padding-right: 15px"> |
||||
<el-button |
||||
type="primary" |
||||
link |
||||
@click="removeMj(item)" |
||||
v-hasPermi="['questiont:vip-data:mj:remove']" |
||||
>删除</el-button |
||||
> |
||||
<el-button |
||||
type="primary" |
||||
link |
||||
@click="clearMjDetail(item)" |
||||
v-hasPermi="['questiont:vip-data:mj:clear']" |
||||
>清空</el-button |
||||
> |
||||
</div> |
||||
</el-radio> |
||||
</el-radio-group> |
||||
</div> |
||||
<div style="flex: 1; padding-left: 20px; padding-right: 20px"> |
||||
<div |
||||
v-if="mjList.length > 0" |
||||
style="display: flex; justify-content: space-between; align-items: center" |
||||
> |
||||
<div style="font-size: 20px; font-weight: bold"> |
||||
当前密卷:{{ getMjTitle(mjIndex) }} |
||||
</div> |
||||
<div style="margin-left: 10px; margin-right: 10px"> 题目数:{{ tableList.length }} </div> |
||||
<el-button |
||||
type="primary" |
||||
@click="addMjDetail" |
||||
v-hasPermi="['questiont:vip-data:mj:add-question']" |
||||
>新增密卷试题</el-button |
||||
> |
||||
</div> |
||||
<el-table |
||||
v-loading="loading" |
||||
:data="tableList" |
||||
style="margin-top: 10px" |
||||
max-height="calc(100vh - 280px)" |
||||
> |
||||
<el-table-column type="index" width="55" align="center" /> |
||||
<el-table-column label="题目" align="left" prop="question" min-width="140" /> |
||||
<el-table-column label="选项" align="left" min-width="140"> |
||||
<template #default="{ row }"> |
||||
<p v-if="row.chooseA">A:{{ row.chooseA }}</p> |
||||
<p v-if="row.chooseB">B:{{ row.chooseB }}</p> |
||||
<p v-if="row.chooseC">C:{{ row.chooseC }}</p> |
||||
<p v-if="row.chooseD">D:{{ row.chooseD }}</p> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="答案" align="center" prop="trueAnswer" width="100" /> |
||||
<el-table-column label="科目" align="center" prop="subject" width="100"> |
||||
<template #default="{ row }"> |
||||
<span v-if="row.subject == '1'">科一</span> |
||||
<span v-if="row.subject == '4'">科四</span> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="章节" align="center" prop="chapterName" min-width="100" /> |
||||
<el-table-column label="图片" align="center" width="100"> |
||||
<template #default="{ row }"> |
||||
<el-image |
||||
v-if="row.imageUrl" |
||||
:src="`https://ss-cloud.ahduima.com/xjxc/pic/${row.imageUrl}`" |
||||
:preview-src-list="[`https://ss-cloud.ahduima.com/xjxc/pic/${row.imageUrl}`]" |
||||
:lazy="true" |
||||
style="width: 80px" |
||||
/> |
||||
</template> |
||||
</el-table-column> |
||||
|
||||
<el-table-column label="操作" align="center" width="100px"> |
||||
<template #default="{ row }"> |
||||
<el-button |
||||
type="primary" |
||||
link |
||||
@click="takeoutMj(row)" |
||||
v-hasPermi="['questiont:vip-data:mj:remove-question']" |
||||
>移出密卷</el-button |
||||
> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
</div> |
||||
</div> |
||||
|
||||
<el-dialog v-model="showDialog" title="新增试题" width="80%"> |
||||
<div style="display: flex; align-items: center; margin-bottom: 20px"> |
||||
<el-input v-model="quesName" placeholder="请输入题目" clearable @keyup.enter="searchQues" /> |
||||
<el-button style="margin-left: 20px" type="primary" @click="searchQues">搜索</el-button> |
||||
</div> |
||||
<el-table :data="quesLit" highlight-current-row height="calc(100vh - 260px)"> |
||||
<el-table-column label="题目" align="left" prop="question" min-width="140" /> |
||||
<el-table-column label="选项" align="left" min-width="140"> |
||||
<template #default="{ row }"> |
||||
<p v-if="row.chooseA">A:{{ row.chooseA }}</p> |
||||
<p v-if="row.chooseB">B:{{ row.chooseB }}</p> |
||||
<p v-if="row.chooseC">C:{{ row.chooseC }}</p> |
||||
<p v-if="row.chooseD">D:{{ row.chooseD }}</p> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="答案" align="center" prop="trueAnswer" width="100" /> |
||||
<el-table-column label="章节" align="center" prop="chapterName" min-width="100" /> |
||||
<el-table-column label="图片" align="center" width="100"> |
||||
<template #default="{ row }"> |
||||
<el-image |
||||
v-if="row.imageUrl" |
||||
:src="`https://ss-cloud.ahduima.com/xjxc/pic/${row.imageUrl}`" |
||||
:preview-src-list="[`https://ss-cloud.ahduima.com/xjxc/pic/${row.imageUrl}`]" |
||||
:lazy="true" |
||||
style="width: 80px" |
||||
/> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="操作" width="100px"> |
||||
<template #default="{ row }"> |
||||
<el-button type="primary" link @click="sureAddQues(row)">加入密卷</el-button> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
</el-dialog> |
||||
</div> |
||||
</template> |
||||
|
||||
<script setup name="SimpleData"> |
||||
import { |
||||
getMjList, |
||||
addMj, |
||||
delMj, |
||||
clearMj, |
||||
getMjQuestionList, |
||||
addMjQuestion, |
||||
delMjQuestion |
||||
} from '@/api/xjapplet/vipdatabase.js' |
||||
import { searchQuestion } from '@/api/xjapplet/xjdatabase.js' |
||||
const message = useMessage() // 消息弹窗 |
||||
|
||||
const props = defineProps({ |
||||
source: { |
||||
type: String, |
||||
default: '1' |
||||
} |
||||
}) |
||||
|
||||
watch( |
||||
() => props.source, |
||||
(newValue) => { |
||||
queryParams.value.source = newValue |
||||
searchMj() |
||||
} |
||||
) |
||||
|
||||
const queryParams = ref({ |
||||
carTypeId: '1001', |
||||
subject: '1' |
||||
}) |
||||
const mjIndex = ref(0) |
||||
const mjList = ref([]) |
||||
const loading = ref(false) |
||||
const tableList = ref([]) |
||||
const showDialog = ref(false) |
||||
const quesName = ref('') |
||||
const quesLit = ref([]) |
||||
|
||||
onMounted(() => { |
||||
searchMj() |
||||
}) |
||||
|
||||
function addMjItem() { |
||||
addMj(queryParams.value).then((res) => { |
||||
if (res) { |
||||
searchMj() |
||||
message.success('添加成功') |
||||
} else { |
||||
message.error('添加失败') |
||||
} |
||||
}) |
||||
} |
||||
function getMjTitle(idx) { |
||||
// const cjObj = { |
||||
// 1001: '小车', |
||||
// 1002: '摩托车' |
||||
// } |
||||
// const kmObj = { |
||||
// 1: '科一', |
||||
// 4: '科四' |
||||
// } |
||||
// return `${cjObj[queryParams.value.carTypeId]}${kmObj[queryParams.value.subject]}考前密卷 第${ |
||||
// idx + 1 |
||||
// }套` |
||||
return `考前密卷 第${idx + 1}套` |
||||
} |
||||
function removeMj(item) { |
||||
message |
||||
.confirm('是否确认删除密卷?') |
||||
.then(function () { |
||||
return delMj(item.secretId) |
||||
}) |
||||
.then(() => { |
||||
searchMj() |
||||
message.success('删除成功') |
||||
}) |
||||
.catch(() => {}) |
||||
} |
||||
function clearMjDetail(item) { |
||||
message |
||||
.confirm('是否确认清空密卷题目?') |
||||
.then(function () { |
||||
return clearMj(item.secretId) |
||||
}) |
||||
.then(() => { |
||||
getQuestionList() |
||||
message.success('清空题目成功') |
||||
}) |
||||
.catch(() => {}) |
||||
} |
||||
function searchMj() { |
||||
getMjList(queryParams.value).then((resp) => { |
||||
mjList.value = resp || [] |
||||
if (mjList.value.length > 0) { |
||||
mjIndex.value = 0 |
||||
getQuestionList() |
||||
} |
||||
}) |
||||
} |
||||
function addMjDetail() { |
||||
showDialog.value = true |
||||
} |
||||
function searchQues() { |
||||
searchQuestion({ |
||||
...queryParams.value, |
||||
pageNo: 1, |
||||
pageSize: 1000, |
||||
question: quesName.value |
||||
}).then((response) => { |
||||
quesLit.value = response.list |
||||
}) |
||||
} |
||||
function takeoutMj(row) { |
||||
message |
||||
.confirm('是否确认将该题移出密卷?') |
||||
.then(function () { |
||||
return delMjQuestion(row.id) |
||||
}) |
||||
.then(() => { |
||||
getQuestionList() |
||||
message.success('清空题目成功') |
||||
}) |
||||
.catch(() => {}) |
||||
} |
||||
function getQuestionList() { |
||||
getMjQuestionList({ |
||||
secretId: mjList.value[mjIndex.value].secretId |
||||
}).then((resp) => { |
||||
tableList.value = resp |
||||
}) |
||||
} |
||||
function sureAddQues(row) { |
||||
addMjQuestion({ |
||||
secretId: mjList.value[mjIndex.value].secretId, |
||||
subId: row.subId |
||||
}) |
||||
.then((resp) => { |
||||
if (resp) { |
||||
message.success('添加成功') |
||||
getQuestionList() |
||||
} |
||||
}) |
||||
.catch(() => {}) |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped></style> |
@ -0,0 +1,211 @@ |
||||
<template> |
||||
<div> |
||||
<el-form inline label-width="68px" @submit.prevent> |
||||
<el-row :gutter="20"> |
||||
<el-form-item label="车型"> |
||||
<el-radio-group v-model="queryParams.carTypeId"> |
||||
<el-radio label="1001" value="1001">小车</el-radio> |
||||
<el-radio label="1002" value="1002">摩托车</el-radio> |
||||
<!-- <el-radio label="B2">货车</el-radio> --> |
||||
</el-radio-group> |
||||
</el-form-item> |
||||
<el-form-item label="科目"> |
||||
<el-radio-group v-model="queryParams.subject"> |
||||
<el-radio label="1" value="1">科一</el-radio> |
||||
<el-radio label="4" value="4">科四</el-radio> |
||||
</el-radio-group> |
||||
</el-form-item> |
||||
<el-form-item> |
||||
<el-button |
||||
type="primary" |
||||
v-hasPermi="['question:vip-data:jx:search']" |
||||
@click=" |
||||
() => { |
||||
queryParams.pageNo = 1 |
||||
getQuestionList() |
||||
} |
||||
" |
||||
> |
||||
查询 |
||||
</el-button> |
||||
<el-button type="primary" @click="addMjDetail" v-hasPermi="['question:vip-data:jx:add']"> |
||||
新增精选试题 |
||||
</el-button> |
||||
</el-form-item> |
||||
</el-row> |
||||
</el-form> |
||||
<el-table v-loading="loading" :data="tableList" height="calc(100vh - 250px)"> |
||||
<el-table-column type="index" width="55" align="center" /> |
||||
<el-table-column label="题目" align="left" prop="question" min-width="140" /> |
||||
<el-table-column label="选项" align="left" min-width="140"> |
||||
<template #default="{ row }"> |
||||
<p v-if="row.chooseA">A:{{ row.chooseA }}</p> |
||||
<p v-if="row.chooseB">B:{{ row.chooseB }}</p> |
||||
<p v-if="row.chooseC">C:{{ row.chooseC }}</p> |
||||
<p v-if="row.chooseD">D:{{ row.chooseD }}</p> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="答案" align="center" prop="trueAnswer" width="100" /> |
||||
<el-table-column label="科目" align="center" prop="subject" width="100"> |
||||
<template #default="{ row }"> |
||||
<span v-if="row.subject == '1'">科一</span> |
||||
<span v-if="row.subject == '4'">科四</span> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="图片" align="center" width="100"> |
||||
<template #default="{ row }"> |
||||
<el-image |
||||
v-if="row.imageUrl" |
||||
:src="`https://ss-cloud.ahduima.com/xjxc/pic/${row.imageUrl}`" |
||||
:preview-src-list="[`https://ss-cloud.ahduima.com/xjxc/pic/${row.imageUrl}`]" |
||||
:lazy="true" |
||||
style="width: 80px" |
||||
/> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="操作" align="center" width="100px"> |
||||
<template #default="{ row }"> |
||||
<el-button |
||||
size="small" |
||||
type="primary" |
||||
link |
||||
@click="takeoutMj(row)" |
||||
v-hasPermi="['question:vip-data:jx:remove']" |
||||
> |
||||
移出精选 |
||||
</el-button> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
<pagination |
||||
v-show="total > 0" |
||||
:total="total" |
||||
v-model:page="queryParams.pageNo" |
||||
v-model:limit="queryParams.pageSize" |
||||
@pagination="getQuestionList" |
||||
/> |
||||
|
||||
<el-dialog v-model="showDialog" title="新增试题" width="80%"> |
||||
<div style="display: flex; align-items: center; margin-bottom: 20px"> |
||||
<el-input v-model="quesName" placeholder="请输入题目" clearable @keyup.enter="searchQues" /> |
||||
<el-button style="margin-left: 20px" type="primary" @click="searchQues">搜索</el-button> |
||||
</div> |
||||
<el-table :data="quesLit" highlight-current-row height="calc(100vh - 260px)"> |
||||
<el-table-column label="题目" align="left" prop="question" min-width="140" /> |
||||
<el-table-column label="选项" align="left" min-width="140"> |
||||
<template #default="{ row }"> |
||||
<p v-if="row.chooseA">A:{{ row.chooseA }}</p> |
||||
<p v-if="row.chooseB">B:{{ row.chooseB }}</p> |
||||
<p v-if="row.chooseC">C:{{ row.chooseC }}</p> |
||||
<p v-if="row.chooseD">D:{{ row.chooseD }}</p> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="答案" align="center" prop="trueAnswer" width="100" /> |
||||
<el-table-column label="章节" align="center" prop="chapterName" min-width="100" /> |
||||
<el-table-column label="图片" align="center" width="100"> |
||||
<template #default="{ row }"> |
||||
<el-image |
||||
v-if="row.imageUrl" |
||||
:src="`https://ss-cloud.ahduima.com/xjxc/pic/${row.imageUrl}`" |
||||
:preview-src-list="[`https://ss-cloud.ahduima.com/xjxc/pic/${row.imageUrl}`]" |
||||
:lazy="true" |
||||
style="width: 80px" |
||||
/> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="操作" width="100px"> |
||||
<template #default="{ row }"> |
||||
<el-button type="primary" link @click="sureAddQues(row)">加入精选</el-button> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
</el-dialog> |
||||
</div> |
||||
</template> |
||||
|
||||
<script setup name="SimpleData"> |
||||
import { getJxQuestionList, addJx, delJxData } from '@/api/xjapplet/vipdatabase.js' |
||||
import { searchQuestion } from '@/api/xjapplet/xjdatabase.js' |
||||
|
||||
const props = defineProps({ |
||||
source: { |
||||
type: String, |
||||
default: '1' |
||||
} |
||||
}) |
||||
watch( |
||||
() => props.source, |
||||
(newValue) => { |
||||
queryParams.value.source = newValue |
||||
getQuestionList() |
||||
} |
||||
) |
||||
|
||||
const message = useMessage() // 消息弹窗 |
||||
|
||||
const queryParams = ref({ |
||||
carTypeId: '1001', |
||||
subject: '1', |
||||
pageNo: 1, |
||||
pageSize: 100 |
||||
}) |
||||
|
||||
const total = ref(0) |
||||
|
||||
const loading = ref(false) |
||||
const tableList = ref([]) |
||||
const showDialog = ref(false) |
||||
const quesName = ref('') |
||||
const quesLit = ref([]) |
||||
|
||||
onMounted(() => { |
||||
getQuestionList() |
||||
}) |
||||
function addMjDetail() { |
||||
showDialog.value = true |
||||
} |
||||
function searchQues() { |
||||
searchQuestion({ |
||||
...queryParams.value, |
||||
pageNo: 1, |
||||
pageSize: 1000, |
||||
question: quesName.value |
||||
}).then((response) => { |
||||
quesLit.value = response.list |
||||
}) |
||||
} |
||||
function takeoutMj(row) { |
||||
message |
||||
.confirm('是否确认将该题移出精选?') |
||||
.then(function () { |
||||
return delJxData(row.id) |
||||
}) |
||||
.then(() => { |
||||
getQuestionList() |
||||
message.success('清空题目成功') |
||||
}) |
||||
.catch(() => {}) |
||||
} |
||||
function getQuestionList() { |
||||
getJxQuestionList(queryParams.value).then((resp) => { |
||||
tableList.value = resp.list |
||||
total.value = resp.total |
||||
}) |
||||
} |
||||
function sureAddQues(row) { |
||||
addJx({ |
||||
questionId: row.questionId, |
||||
carTypeId: queryParams.value.carTypeId, |
||||
subject: queryParams.value.subject |
||||
}) |
||||
.then((resp) => { |
||||
if (resp) { |
||||
message.success('添加成功') |
||||
getQuestionList() |
||||
} |
||||
}) |
||||
.catch(() => {}) |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped></style> |
@ -0,0 +1,30 @@ |
||||
<template> |
||||
<el-tabs v-model="source" @tab-click="handleChangeSource"> |
||||
<el-tab-pane v-for="item in sourceOptions" :key="item.key" :label="item.label" :name="item.key"> |
||||
<el-tabs v-model="tabIndex" tab-position="left" style="height: 400px" class="profile-tabs"> |
||||
<el-tab-pane label="精选题" :name="1" v-if="checkPermi(['question:vip-data:jx'])"> |
||||
<SimpleData v-if="tabIndex == 1" :source="source" /> |
||||
</el-tab-pane> |
||||
<el-tab-pane label="密卷" :name="2" v-if="checkPermi(['question:vip-data:mj'])"> |
||||
<SecretData v-if="tabIndex == 2" :source="source" /> |
||||
</el-tab-pane> |
||||
</el-tabs> |
||||
</el-tab-pane> |
||||
</el-tabs> |
||||
</template> |
||||
|
||||
<script setup name="VipData"> |
||||
import { checkPermi } from '@/utils/permission' |
||||
import SimpleData from './conponents/SimpleData.vue' |
||||
import SecretData from './conponents/SecretData.vue' |
||||
|
||||
const tabIndex = ref(1) |
||||
const source = ref('1') |
||||
const sourceOptions = [ |
||||
{ key: '1', label: '驾考精灵' }, |
||||
{ key: '2', label: '驾校一点通' } |
||||
] |
||||
const handleChangeSource = () => {} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped></style> |
Loading…
Reference in new issue