diff --git a/src/api/system/dept.ts b/src/api/system/dept.ts index 54ac5e5..6cfa90e 100644 --- a/src/api/system/dept.ts +++ b/src/api/system/dept.ts @@ -47,13 +47,4 @@ export function deptDelete(deptId) { url: '/dept/delete/'+deptId, method: 'DELETE', }); -} -/** - * @description: 批量删除部门 - */ -export function deptBatchDelete(deptId) { - return http.request({ - url: '/dept/batchDelete/'+deptId, - method: 'DELETE', - }); } \ No newline at end of file diff --git a/src/api/system/operLog.ts b/src/api/system/operLog.ts new file mode 100644 index 0000000..280ad8a --- /dev/null +++ b/src/api/system/operLog.ts @@ -0,0 +1,40 @@ +import { http } from '@/utils/http/axios'; + +/** + * @description: 操作日志列表 + */ +export function getOperLogList(params?) { + return http.request({ + url: '/oper/log/page', + method: 'GET', + params, + }); +} +/** + * @description: 根据ID获取详情 + */ +export function getOperLogDetail(id) { + return http.request({ + url: '/oper/log/detail/'+id, + method: 'get', + }); +} +/** + * @description: 删除操作日志 + */ +export function operLogDelete(id) { + return http.request({ + url: '/oper/log/delete/'+id, + method: 'DELETE', + }); +} +/** + * @description: 批量删除操作日志 + */ +export function operLogBatchDelete(data:any) { + return http.request({ + url: '/oper/log/batchDelete', + method: 'DELETE', + data + }); +} \ No newline at end of file diff --git a/src/views/system/operLog/columns.ts b/src/views/system/operLog/columns.ts new file mode 100644 index 0000000..15a3e05 --- /dev/null +++ b/src/views/system/operLog/columns.ts @@ -0,0 +1,71 @@ +import { h } from 'vue'; +import { ElTag } from 'element-plus'; + +export const columns = [ + { + type: 'selection', + }, + { + label: '日志标题', + prop: 'title', + }, + { + label: '操作用户', + prop: 'createUser', + }, + { + label: '请求ip', + prop: 'ip', + }, + { + label: '浏览器', + prop: 'browser', + }, + { + label: '操作系统', + prop: 'os', + }, + { + label: '操作类型', + prop: 'typeText', + }, + { + label: '操作来源', + prop: 'sourceText', + }, + { + label: '请求方式', + prop: 'requestMethod', + }, + { + label: '请求URL', + prop: 'url', + }, + { + label: '请求地区', + prop: 'location', + }, + { + label: '请求耗时', + prop: 'consumeTime', + }, + { + label: '状态', + prop: 'status', + render(record) { + return h( + ElTag, + { + type: record.row.status ==0 ? 'success' : 'danger', + }, + { + default: () => (record.row.status ==0 ? '正常' : '异常'), + }, + ); + }, + }, + { + label: '创建时间', + prop: 'createTime', + }, +]; diff --git a/src/views/system/operLog/edit.vue b/src/views/system/operLog/edit.vue new file mode 100644 index 0000000..051e949 --- /dev/null +++ b/src/views/system/operLog/edit.vue @@ -0,0 +1,112 @@ +<template> + <el-dialog + v-model="props.visible" + :title="props.positionId?'编辑':'新增'" + :append-to-body="true" + width="500" + :close-on-click-modal="false" + :before-close="dialogClose" + > + <el-form + class="ls-form" + ref="formRef" + :model="formData" + label-width="80px" + > + <el-form-item + label="名称" + prop="name" + :rules="{ required: true, message: '请输入名称', trigger: 'blur' }" + > + <el-input + class="ls-input" + v-model="formData.name" + placeholder="请输入名称" + clearable + /> + </el-form-item> + <el-form-item label="岗位状态" prop="status"> + <el-radio-group v-model="formData.status" name="status"> + <el-radio :value="1">正常</el-radio> + <el-radio :value="2">禁用</el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="排序" prop="sort"> + <el-input-number v-model="formData.sort"/> + </el-form-item> + <el-form-item label="备注" prop="note"> + <el-input v-model="formData.note" type="textarea" placeholder="请输入备注" clearable /> + </el-form-item> + </el-form> + <template #footer> + <span class="dialog-footer"> + <el-button @click="dialogClose">取消</el-button> + <el-button :loading="subLoading" type="primary" @click="submit"> + 确定 + </el-button> + </span> + </template> + </el-dialog> +</template> +<script lang="ts" setup> +import type {FormInstance} from "element-plus"; +import {getPositionDetail,positionAdd,positionUpdate} from "@/api/system/position"; +import {onMounted, reactive, shallowRef} from "vue"; +import {message} from "@/utils/auth"; +import {useLockFn} from "@/utils/useLockFn"; + +const emit = defineEmits(["success", "update:visible"]); +const formRef = shallowRef<FormInstance>(); +const formData = reactive({ + id: "", + name: "", + status: 1, + sort: 0, + note:'', +}); + +const props = defineProps({ + visible: { + type: Boolean, + required: true, + default: false + }, + positionId: { + type: Number, + required: true, + default: 0 + } +}); + +const handleSubmit = async () => { + await formRef.value?.validate(); + props.positionId ? await positionUpdate(formData) : await positionAdd(formData); + message("操作成功"); + emit("update:visible", false); + emit("success"); +}; + +const dialogClose = () => { + emit("update:visible", false); +}; + +const { isLock:subLoading,lockFn: submit } = useLockFn(handleSubmit); + + +const setFormData = async () => { + const data = await getPositionDetail(props.positionId); + for (const key in formData) { + if (data[key] != null && data[key] != undefined) { + //@ts-ignore + formData[key] = data[key]; + } + } +}; + +onMounted(() => { + if (props.positionId) { + setFormData(); + } +}); + +</script> diff --git a/src/views/system/operLog/index.vue b/src/views/system/operLog/index.vue new file mode 100644 index 0000000..9c25428 --- /dev/null +++ b/src/views/system/operLog/index.vue @@ -0,0 +1,147 @@ +<template> + <PageWrapper> + <el-card :bordered="false" class="pt-3 mb-3 proCard"> + <BasicForm @register="register" @submit="handleSubmit" @reset="handleReset"></BasicForm> + </el-card> + <el-card :bordered="false" class="proCard"> + <BasicTable + :columns="columns" + :request="loadDataTable" + :row-key="(row) => row.id" + ref="tableRef" + :actionColumn="actionColumn" + @selection-change="onSelectionChange" + > + <template #tableTitle> + <el-button type="danger" @click="handleDelete()" :disabled="!selectionData.length"> + <template #icon> + <el-icon class="el-input__icon"> + <Delete /> + </el-icon> + </template> + 删除 + </el-button> + </template> + + <template #action> + <TableAction /> + </template> + </BasicTable> + </el-card> + + <editDialog + v-if="editVisible" + :positionId="positionId" + v-model:visible="editVisible" + @success="reloadTable" + > + </editDialog> + </PageWrapper> +</template> + +<script lang="ts" setup> + import { reactive, ref, h,nextTick,defineAsyncComponent } from 'vue'; + import { ColProps } from 'element-plus'; + import { schemas } from './querySchemas'; + import { BasicForm, useForm } from '@/components/Form/index'; + import { BasicTable, TableAction } from '@/components/Table'; + import { getOperLogList,operLogDelete,operLogBatchDelete } from '@/api/system/operLog'; + import { columns } from './columns'; + import { PlusOutlined } from '@vicons/antd'; + import {message,confirm} from "@/utils/auth"; + const editDialog = defineAsyncComponent(() => + import('./edit.vue') +) +const positionId =ref(0) +const editVisible=ref(false) + const selectionData = ref([]) + const tableRef = ref(); + const formParams = reactive({ + type:'', + status:'' + }); + const actionColumn = reactive({ + width: 250, + label: '操作', + prop: 'action', + fixed: 'right', + render(record) { + return h(TableAction, { + style: 'button', + actions: [ + // { + // label: '编辑', + // type: 'warning', + // onClick: handleEdit.bind(null, record), + // ifShow: () => { + // return true; + // }, + // auth: ['basic_list'], + // }, + { + label: '删除', + type: 'danger', + onClick: handleDelete.bind(null, record), + // 根据业务控制是否显示 isShow 和 auth 是并且关系 + ifShow: () => { + return true; + }, + // 根据权限控制是否显示: 有权限,会显示,支持多个 + // auth: ['basic_list'], + }, + ], + }); + }, + }); + + const loadDataTable = async (res: any) => { + const result = await getOperLogList({ ...formParams, ...res }); + return result; + }; + + function reloadTable() { + tableRef.value.reload({pageNo:1}); + } + const [register, {}] = useForm({ + labelWidth: 80, + layout: 'horizontal', + colProps: { span: 6 } as ColProps, + submitOnReset:true, + schemas + }); + function handleSubmit(values: Recordable) { + for (const key in formParams) { + if (values[key] != null && values[key] != undefined) { + formParams[key] = values[key]; + } + } + reloadTable(); + } + + function handleReset() { + for (const key in formParams) { + formParams[key] =''; + } + } +const handleEdit = async (record: Recordable) => { + positionId.value=record.row.id + await nextTick(); + editVisible.value=true +}; + +async function handleDelete(record: Recordable) { + let ids = [] + if(!record){ + ids = selectionData.value.map(({id}) => id); + } + await confirm('确定要删除?'); + record? await operLogDelete(record.row.id):await operLogBatchDelete(ids); + message("删除成功"); + reloadTable() + } +function onSelectionChange(value){ + selectionData.value = value + } +</script> + +<style lang="scss" scoped></style> diff --git a/src/views/system/operLog/querySchemas.ts b/src/views/system/operLog/querySchemas.ts new file mode 100644 index 0000000..d362940 --- /dev/null +++ b/src/views/system/operLog/querySchemas.ts @@ -0,0 +1,39 @@ +import { FormSchema } from '@/components/Form/index'; +export const schemas: FormSchema[] = [ + { + field: 'type', + component: 'Select', + label: '请求类型', + componentProps: { + placeholder: '请选择请求类型', + options: [ + { + label: '登录', + value: '0', + }, + { + label: '退出', + value: '1', + }, + ], + }, + }, + { + field: 'status', + component: 'Select', + label: '请求状态', + componentProps: { + placeholder: '请选择状态', + options: [ + { + label: '正常', + value: '0', + }, + { + label: '异常', + value: '1', + }, + ], + }, + }, +]; diff --git a/src/views/system/position/index.vue b/src/views/system/position/index.vue index 9e6ab83..e018db0 100644 --- a/src/views/system/position/index.vue +++ b/src/views/system/position/index.vue @@ -62,7 +62,7 @@ ) const positionId =ref(0) const editVisible=ref(false) - const selectionData = ref([]) +const selectionData = ref([]) const tableRef = ref(); const formParams = reactive({ name:'',