소스 검색

chore: 日志管理优化

lujialiang 2 주 전
부모
커밋
7b6b684853

+ 5 - 1
src/locales/langs/zh-cn.ts

@@ -45,7 +45,8 @@ const local: App.I18n.Schema = {
     yesOrNo: {
       yes: '是',
       no: '否'
-    }
+    },
+    detail: '详细'
   },
   request: {
     logout: '请求失败后登出用户',
@@ -474,6 +475,9 @@ const local: App.I18n.Schema = {
         },
         addTitle: '添加岗位',
         editTitle: '编辑岗位'
+      },
+      sysOperLog: {
+        detailTitle: '操作日志详细'
       }
     }
   },

+ 1 - 1
src/router/elegant/imports.ts

@@ -21,9 +21,9 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
   "iframe-page": () => import("@/views/_builtin/iframe-page/[url].vue"),
   login: () => import("@/views/_builtin/login/index.vue"),
   about: () => import("@/views/about/index.vue"),
+  "admin_log_sys-login-log": () => import("@/views/admin/log/sys-login-log/index.vue"),
   "admin_log_sys-oper-log": () => import("@/views/admin/log/sys-oper-log/index.vue"),
   "admin_sys-dept": () => import("@/views/admin/sys-dept/index.vue"),
-  "admin_sys-login-log": () => import("@/views/admin/sys-login-log/index.vue"),
   "admin_sys-menu": () => import("@/views/admin/sys-menu/index.vue"),
   "admin_sys-post": () => import("@/views/admin/sys-post/index.vue"),
   "admin_sys-role": () => import("@/views/admin/sys-role/index.vue"),

+ 9 - 9
src/router/elegant/routes.ts

@@ -67,6 +67,15 @@ export const generatedRoutes: GeneratedRoute[] = [
           i18nKey: 'route.admin_log'
         },
         children: [
+          {
+            name: 'admin_log_sys-login-log',
+            path: '/admin/log/sys-login-log',
+            component: 'view.admin_log_sys-login-log',
+            meta: {
+              title: 'admin_log_sys-login-log',
+              i18nKey: 'route.admin_log_sys-login-log'
+            }
+          },
           {
             name: 'admin_log_sys-oper-log',
             path: '/admin/log/sys-oper-log',
@@ -87,15 +96,6 @@ export const generatedRoutes: GeneratedRoute[] = [
           i18nKey: 'route.admin_sys-dept'
         }
       },
-      {
-        name: 'admin_sys-login-log',
-        path: '/admin/sys-login-log',
-        component: 'view.admin_sys-login-log',
-        meta: {
-          title: 'admin_sys-login-log',
-          i18nKey: 'route.admin_sys-login-log'
-        }
-      },
       {
         name: 'admin_sys-menu',
         path: '/admin/sys-menu',

+ 1 - 1
src/router/elegant/transform.ts

@@ -179,9 +179,9 @@ const routeMap: RouteMap = {
   "about": "/about",
   "admin": "/admin",
   "admin_log": "/admin/log",
+  "admin_log_sys-login-log": "/admin/log/sys-login-log",
   "admin_log_sys-oper-log": "/admin/log/sys-oper-log",
   "admin_sys-dept": "/admin/sys-dept",
-  "admin_sys-login-log": "/admin/sys-login-log",
   "admin_sys-menu": "/admin/sys-menu",
   "admin_sys-post": "/admin/sys-post",
   "admin_sys-role": "/admin/sys-role",

+ 27 - 0
src/service/api/admin.ts

@@ -96,3 +96,30 @@ export function fetchOperList(params: object) {
     params
   });
 }
+
+// 删除操作记录
+export function fetchOperDel(data: object) {
+  return baseRequest({
+    url: '/api/v1/sys-opera-log',
+    method: 'delete',
+    data
+  });
+}
+
+// 查询登录日志列表
+export function fetchLoginlogList(params: object) {
+  return baseRequest({
+    url: '/api/v1/sys-login-log',
+    method: 'get',
+    params
+  });
+}
+
+// 删除登录日志
+export function fetchLoginlogDel(data: object) {
+  return baseRequest({
+    url: '/api/v1/sys-login-log',
+    method: 'delete',
+    data
+  });
+}

+ 1 - 1
src/typings/antd.d.ts

@@ -29,7 +29,7 @@ declare namespace AntDesign {
    * - add: add table item
    * - edit: edit table item
    */
-  type TableOperateType = 'add' | 'edit';
+  type TableOperateType = 'add' | 'edit' | 'detail';
 
   type GetTableData<A extends TableApiFn> = A extends TableApiFn<infer T> ? T : never;
 

+ 19 - 5
src/typings/api.d.ts

@@ -285,11 +285,25 @@ declare namespace Api {
       remark: string;
     }>;
 
-    interface CodeImg {
-      code: number;
-      data: object;
-      requestId: string;
-      msg: string;
+    interface SysOperLog {
+      id: number;
+      operUrl: string;
+      operName: string;
+      status: string;
+      operTime: string;
+      latencyTime: string;
+      requestMethod: string;
+      jsonResult: string;
+      operParam: string;
+      operIp: string;
+      operLocation: string;
+      errorMsg: string;
+    }
+
+    interface SysLoginLog {
+      username: string;
+      status: string;
+      ipaddr: string;
     }
   }
 }

+ 4 - 0
src/typings/app.d.ts

@@ -294,6 +294,7 @@ declare namespace App {
           yes: string;
           no: string;
         };
+        detail: string;
       };
       request: {
         logout: string;
@@ -640,6 +641,9 @@ declare namespace App {
             addTitle: string;
             editTitle: string;
           };
+          sysOperLog: {
+            detailTitle: string;
+          };
         };
       };
       form: {

+ 2 - 2
src/typings/elegant-router.d.ts

@@ -35,9 +35,9 @@ declare module "@elegant-router/types" {
     "about": "/about";
     "admin": "/admin";
     "admin_log": "/admin/log";
+    "admin_log_sys-login-log": "/admin/log/sys-login-log";
     "admin_log_sys-oper-log": "/admin/log/sys-oper-log";
     "admin_sys-dept": "/admin/sys-dept";
-    "admin_sys-login-log": "/admin/sys-login-log";
     "admin_sys-menu": "/admin/sys-menu";
     "admin_sys-post": "/admin/sys-post";
     "admin_sys-role": "/admin/sys-role";
@@ -146,9 +146,9 @@ declare module "@elegant-router/types" {
     | "iframe-page"
     | "login"
     | "about"
+    | "admin_log_sys-login-log"
     | "admin_log_sys-oper-log"
     | "admin_sys-dept"
-    | "admin_sys-login-log"
     | "admin_sys-menu"
     | "admin_sys-post"
     | "admin_sys-role"

+ 165 - 0
src/views/admin/log/sys-login-log/index.vue

@@ -0,0 +1,165 @@
+<script setup lang="tsx">
+import { useTable, useTableOperate, useTableScroll } from '@/hooks/common/table';
+import { $t } from '@/locales';
+import { fetchLoginlogDel, fetchLoginlogList, getDicts } from '@/service/api';
+import { Button } from 'ant-design-vue';
+import dayjs from 'dayjs';
+import { ref } from 'vue';
+import MOperateDrawer from './modules/m-operate-drawer.vue';
+import MSearch from './modules/m-search.vue';
+const { tableWrapperRef, scrollConfig } = useTableScroll();
+const apiParams = ref({
+  pageIndex: 1,
+  pageSize: 10,
+  createdAtOrder: 'desc'
+});
+
+const {
+  columns,
+  columnChecks,
+  data,
+  getData,
+  getDataByPage,
+  loading,
+  mobilePagination,
+  searchParams,
+  resetSearchParams
+} = useTable({
+  apiFn: fetchLoginlogList,
+  apiParams: apiParams.value,
+  showTotal: true,
+  columns: () => [
+    {
+      key: 'username',
+      dataIndex: 'username',
+      title: '用户名',
+      align: 'center',
+      minWidth: 100
+    },
+    {
+      key: 'msg',
+      dataIndex: 'msg',
+      title: '类型',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'status',
+      dataIndex: 'status',
+      title: '状态',
+      align: 'center',
+      minWidth: 100,
+      customRender: ({ record }) => {
+        let statusMap = {
+          '1': '停用',
+          '2': '正常',
+        }
+        let typeMap = {
+          '1': 'error',
+          '2': 'success',
+        }
+        return <a-tag color={typeMap[record.status]}>{statusMap[record.status]}</a-tag>
+      }
+    },
+    {
+      key: 'ipaddr',
+      dataIndex: 'ipaddr',
+      title: 'ip地址',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'loginTime',
+      dataIndex: 'loginTime',
+      title: '登录时间',
+      align: 'center',
+      minWidth: 150,
+      customRender: ({ record }) => {
+        return dayjs(record.loginTime).format('YYYY-MM-DD HH:mm:ss')
+      }
+    },
+    {
+      key: 'operate',
+      title: $t('common.operate'),
+      align: 'center',
+      fixed: 'right',
+      width: 180,
+      customRender: ({ record }) => (
+        <div class="flex-center gap-0.1rem">
+          {<Button type="primary" ghost size="small" onClick={() => handleRowDetail(record)} style="margin-right:5px">
+            {$t('common.detail')}
+          </Button>}
+        </div>
+      )
+    }
+  ]
+});
+const {
+  drawerVisible,
+  operateType,
+  editingData,
+  handleAdd,
+  checkedRowKeys,
+  onDeleted,
+  openDrawer,
+  rowSelection
+} = useTableOperate(data, getData);
+
+async function handleBatchDelete() {
+  // request
+  handleDelete(checkedRowKeys.value)
+}
+// 删除
+async function handleDelete(id: any) {
+  // request
+  let ids = []
+  typeof id === 'number' ? ids.push(id) : ids = [].concat(id)
+  console.log('handleDelete', ids)
+  const res = await fetchLoginlogDel({ ids })
+  if (res.code === 200) {
+    onDeleted();
+  } else {
+    window.$message?.error('删除失败!');
+  }
+}
+
+// 详情
+function handleRowDetail(row: AntDesign.TableData) {
+  operateType.value = 'detail'
+  editingData.value = row
+  openDrawer()
+}
+
+const deptStatus = ref<CommonType.Option<string>[]>([]);
+async function getDeptStatusOptions() {
+  const { data } = await getDicts('sys_common_status')
+  deptStatus.value = data || []
+}
+getDeptStatusOptions()
+</script>
+
+<template>
+  <div class="min-h-6.25rem flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
+    <MSearch v-model:model="searchParams" @reset="resetSearchParams" @search="getDataByPage" />
+    <ACard title="登录日志列表" :bordered="false" :body-style="{ flex: 1, overflow: 'hidden' }"
+      class="flex-col-stretch sm:flex-1-hidden card-wrapper">
+      <template #extra>
+
+        <TableHeaderOperation v-model:columns="columnChecks" :disabled-delete="checkedRowKeys.length === 0"
+          :loading="loading" @add="handleAdd" @delete="handleBatchDelete" @refresh="getData">
+          <template #default>
+            <span></span>
+          </template>
+        </TableHeaderOperation>
+      </template>
+      <ATable ref="tableWrapperRef" :columns="columns" :data-source="data" size="small" :scroll="scrollConfig"
+        :loading="loading" row-key="userId" :pagination="mobilePagination" class="h-full"
+        :row-selection="rowSelection" />
+
+      <MOperateDrawer v-model:visible="drawerVisible" :operate-type="operateType" :row-data="editingData"
+        @submitted="getDataByPage" />
+    </ACard>
+  </div>
+</template>
+
+<style scoped></style>

+ 149 - 0
src/views/admin/log/sys-login-log/modules/m-operate-drawer.vue

@@ -0,0 +1,149 @@
+<script setup lang="ts">
+import { useAntdForm } from '@/hooks/common/form';
+import { $t } from '@/locales';
+import { getDicts } from '@/service/api';
+import { computed, reactive, ref, watch, nextTick } from 'vue';
+import dayjs from 'dayjs';
+defineOptions({
+  name: 'MOperateDrawer'
+});
+
+interface Props {
+  /** the type of operation */
+  operateType: AntDesign.TableOperateType;
+  /** the edit row data */
+  rowData?: Api.Admin.SysOperLog | null;
+}
+
+const props = defineProps<Props>();
+
+interface Emits {
+  (e: 'submitted'): void;
+}
+
+const emit = defineEmits<Emits>();
+
+const visible = defineModel<boolean>('visible', {
+  default: false
+});
+
+const { formRef, resetFields } = useAntdForm();
+
+const title = computed(() => {
+  const titles: Record<AntDesign.TableOperateType, string> = {
+    detail: $t('page.admin.sysOperLog.detailTitle'),
+    add: '',
+    edit: ''
+  };
+  return titles[props.operateType];
+});
+
+type Model = Pick<
+  Api.Admin.SysOperLog,
+  'operUrl' | 'operName' | 'operIp' | 'operLocation' | 'requestMethod' | 'latencyTime' | 'operParam' | 'jsonResult' | 'status' | 'operTime' | 'errorMsg'>;
+
+const model: Model = reactive(createDefaultModel());
+
+function createDefaultModel(): Model {
+  return {
+    operUrl: '',
+    operName: '',
+    operIp: '',
+    operLocation: '',
+    requestMethod: '',
+    latencyTime: '',
+    operParam: '',
+    jsonResult: '',
+    status: '',
+    operTime: '',
+    errorMsg: '',
+  };
+}
+
+const commonStatus = ref<CommonType.Option<string>[]>([]);
+async function getDeptStatusOptions() {
+  const { data } = await getDicts('sys_common_status')
+  commonStatus.value = data || []
+}
+
+async function handleInitModel() {
+  Object.assign(model, createDefaultModel());
+  if (props.operateType === 'detail' && props.rowData) {
+    await nextTick();
+    Object.assign(model, props.rowData);
+  }
+}
+
+function closeDrawer() {
+  visible.value = false;
+}
+
+watch(visible, () => {
+  if (visible.value) {
+    handleInitModel()
+    resetFields()
+    getDeptStatusOptions()
+  }
+});
+</script>
+
+<template>
+  <AModal v-model:open="visible" :title="title" width="800px">
+    <AForm ref="formRef" :model="model" :label-col="{ lg: 8, xs: 4 }" label-wrap class="pr-20px">
+      <ARow wrap>
+        <ACol :span="24" :md="24" :xs="24">
+          <AFormItem label="请求地址" :label-col="{ lg: 4, xs: 2 }">
+            {{ model.operUrl }}
+          </AFormItem>
+        </ACol>
+        <ACol :span="12" :md="12" :xs="24">
+          <AFormItem label="登录信息">
+            {{ model.operName }} / {{ model.operIp }} / {{ model.operLocation }}
+          </AFormItem>
+        </ACol>
+        <ACol :span="12" :md="12" :xs="24">
+          <AFormItem label="请求方式">
+            {{ model.requestMethod }}
+          </AFormItem>
+        </ACol>
+        <ACol :span="12" :md="12" :xs="24">
+          <AFormItem label="耗时">
+            {{ model.latencyTime }}
+          </AFormItem>
+        </ACol>
+        <ACol :span="24" :md="24" :xs="24">
+          <AFormItem label="请求参数" :label-col="{ lg: 4, xs: 2 }">
+            {{ model.operParam }}
+          </AFormItem>
+        </ACol>
+        <ACol :span="24" :md="24" :xs="24">
+          <AFormItem label="返回参数" :label-col="{ lg: 4, xs: 2 }">
+            {{ model.jsonResult }}
+          </AFormItem>
+        </ACol>
+        <ACol :span="12" :md="12" :xs="24">
+          <AFormItem label="操作状态">
+            {{ model.status }}
+          </AFormItem>
+        </ACol>
+        <ACol :span="12" :md="12" :xs="24">
+          <AFormItem label="操作时间">
+            {{ dayjs(model.operTime).format('YYYY-MM-DD HH:mm:ss') }}
+          </AFormItem>
+        </ACol>
+        <ACol :span="24" :md="24" :xs="24">
+          <AFormItem label="异常信息" :label-col="{ lg: 4, xs: 2 }">
+            {{ model.errorMsg }}
+          </AFormItem>
+        </ACol>
+      </ARow>
+    </AForm>
+    <template #footer>
+      <ASpace :size="16">
+        <AButton @click="closeDrawer">{{ $t('common.cancel') }}</AButton>
+      </ASpace>
+    </template>
+  </AModal>
+</template>
+
+<style scoped></style>

+ 105 - 0
src/views/admin/log/sys-login-log/modules/m-search.vue

@@ -0,0 +1,105 @@
+<script setup lang="ts">
+import { useAntdForm, useFormRules } from '@/hooks/common/form';
+import { $t } from '@/locales';
+import { fetchGetdeptTreeList, getDicts } from '@/service/api';
+import { computed, onMounted, ref } from 'vue';
+defineOptions({
+  name: 'MSearch'
+});
+
+interface Emits {
+  (e: 'reset'): void;
+  (e: 'search'): void;
+}
+
+const emit = defineEmits<Emits>();
+const departOptions = ref<CommonType.Option<string>[]>([]);
+const { formRef, validate, resetFields } = useAntdForm();
+
+const model = defineModel<Api.Admin.SysLoginLog>('model', { required: true });
+
+type RuleKey = Extract<keyof Api.Admin.SysLoginLog, 'email' | 'phone'>;
+
+const rules = computed<Record<RuleKey, App.Global.FormRule>>(() => {
+  const { patternRules } = useFormRules(); // inside computed to make locale reactive
+
+  return {
+    email: patternRules.email,
+    phone: patternRules.phone
+  };
+});
+onMounted(() => {
+  getDeptTree()
+})
+async function getDeptTree() {
+  const { data } = await fetchGetdeptTreeList()
+  departOptions.value = data
+}
+async function reset() {
+  await resetFields();
+  emit('reset');
+}
+
+async function search() {
+  await validate();
+  emit('search');
+}
+
+const normalStatus = ref<CommonType.Option<string>[]>([]);
+async function getDeptStatusOptions() {
+  const { data } = await getDicts('sys_common_status')
+  normalStatus.value = data || []
+}
+getDeptStatusOptions()
+
+</script>
+
+<template>
+  <ACard :title="$t('common.search')" :bordered="false" class="card-wrapper">
+    <AForm ref="formRef" :model="model" :rules="rules" :label-col="{
+      span: 5,
+      md: 7
+    }">
+      <ARow :gutter="[16, 16]" wrap>
+        <ACol :span="24" :md="12" :lg="6">
+          <AFormItem label="用户名" name="username" class="m-0">
+            <AInput v-model:value.trim="model.username" placeholder="请输入用户名" @keyup.enter.native="search" allowClear />
+          </AFormItem>
+        </ACol>
+        <ACol :span="24" :md="12" :lg="6">
+          <AFormItem label="状态" name="status" class="m-0">
+            <ASelect v-model:value="model.status" placeholder="请选择状态" :options="normalStatus" @change="search"
+              allowClear />
+          </AFormItem>
+        </ACol>
+        <ACol :span="24" :md="12" :lg="6">
+          <AFormItem label="ip地址" name="ipaddr" class="m-0">
+            <AInput v-model:value.trim="model.ipaddr" placeholder="请输入ip地址" @keyup.enter.native="search" allowClear />
+          </AFormItem>
+        </ACol>
+
+
+        <div class="flex-1">
+          <AFormItem class="m-0">
+            <div class="w-full flex-y-center justify-end gap-12px">
+              <AButton @click="reset">
+                <template #icon>
+                  <icon-ic-round-refresh class="align-sub text-icon" />
+                </template>
+                <span class="ml-8px">{{ $t('common.reset') }}</span>
+              </AButton>
+              <AButton type="primary" ghost @click="search">
+                <template #icon>
+                  <icon-ic-round-search class="align-sub text-icon" />
+                </template>
+                <span class="ml-8px">{{ $t('common.search') }}</span>
+              </AButton>
+            </div>
+          </AFormItem>
+        </div>
+      </ARow>
+    </AForm>
+  </ACard>
+</template>
+
+<style scoped></style>

+ 19 - 20
src/views/admin/log/sys-oper-log/index.vue

@@ -1,8 +1,8 @@
 <script setup lang="tsx">
 import { useTable, useTableOperate, useTableScroll } from '@/hooks/common/table';
 import { $t } from '@/locales';
-import { fetchPostDel, fetchOperList, getDicts } from '@/service/api';
-import { Button, Popconfirm } from 'ant-design-vue';
+import { fetchOperDel, fetchOperList, getDicts } from '@/service/api';
+import { Button } from 'ant-design-vue';
 import { map, pick } from 'lodash';
 import dayjs from 'dayjs';
 import { ref } from 'vue';
@@ -12,7 +12,8 @@ import { excel } from '@/utils/download'
 const { tableWrapperRef, scrollConfig } = useTableScroll();
 const apiParams = ref({
   pageIndex: 1,
-  pageSize: 10
+  pageSize: 10,
+  createdAtOrder: 'desc'
 });
 
 const {
@@ -87,14 +88,9 @@ const {
       width: 180,
       customRender: ({ record }) => (
         <div class="flex-center gap-0.1rem">
-          {/* <Button type="primary" ghost size="small" onClick={() => handleRowEdit(record.postId)} style="margin-right:5px">
-            {$t('common.edit')}
-          </Button>
-          <Popconfirm title={$t('common.confirmDelete')} onConfirm={() => handleDelete(record.deptId)}>
-            <Button danger size="small" style="margin-right:5px">
-              {$t('common.delete')}
-            </Button>
-          </Popconfirm> */}
+          {<Button type="primary" ghost size="small" onClick={() => handleRowDetail(record)} style="margin-right:5px">
+            {$t('common.detail')}
+          </Button>}
         </div>
       )
     }
@@ -107,7 +103,8 @@ const {
   handleAdd,
   checkedRowKeys,
   onDeleted,
-  handleEdit
+  openDrawer,
+  rowSelection
 } = useTableOperate(data, getData);
 
 async function handleBatchDelete() {
@@ -120,7 +117,7 @@ async function handleDelete(id: any) {
   let ids = []
   typeof id === 'number' ? ids.push(id) : ids = [].concat(id)
   console.log('handleDelete', ids)
-  const res = await fetchPostDel({ ids })
+  const res = await fetchOperDel({ ids })
   if (res.code === 200) {
     onDeleted();
   } else {
@@ -128,21 +125,23 @@ async function handleDelete(id: any) {
   }
 }
 
-// 编辑
-function handleRowEdit(id: number) {
-  handleEdit(id, 'postId')
+// 详情
+function handleRowDetail(row: AntDesign.TableData) {
+  operateType.value = 'detail'
+  editingData.value = row
+  openDrawer()
 }
 
 const deptStatus = ref<CommonType.Option<string>[]>([]);
 async function getDeptStatusOptions() {
-  const { data } = await getDicts('sys_normal_disable')
+  const { data } = await getDicts('sys_common_status')
   deptStatus.value = data || []
 }
 getDeptStatusOptions()
 
 // 导出excel
 function handleExcel() {
-  let keysToPick = ['ID', 'title', 'businessType', 'method', 'operName', 'operIp', 'operLocation', 'status', 'operUrl', 'operTime']
+  let keysToPick = ['id', 'title', 'businessType', 'method', 'operName', 'operIp', 'operLocation', 'status', 'operUrl', 'operTime']
   excel(['日志编号', '系统模块', '操作类型', '请求方式', '操作人员', '主机', '操作地点', '操作状态', '操作url', '操作日期'], map(data.value, item => pick(item, keysToPick)), {
     fileName: "操作日志.xlsx"
   })
@@ -152,7 +151,7 @@ function handleExcel() {
 <template>
   <div class="min-h-6.25rem flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
     <MSearch v-model:model="searchParams" @reset="resetSearchParams" @search="getDataByPage" />
-    <ACard title="部门列表" :bordered="false" :body-style="{ flex: 1, overflow: 'hidden' }"
+    <ACard title="操作日志列表" :bordered="false" :body-style="{ flex: 1, overflow: 'hidden' }"
       class="flex-col-stretch sm:flex-1-hidden card-wrapper">
       <template #extra>
 
@@ -168,7 +167,7 @@ function handleExcel() {
       </template>
       <ATable ref="tableWrapperRef" :columns="columns" :data-source="data" size="small" :scroll="scrollConfig"
         :loading="loading" row-key="userId" :pagination="mobilePagination" class="h-full"
-        :defaultExpandAllRows="true" />
+        :row-selection="rowSelection" />
 
       <MOperateDrawer v-model:visible="drawerVisible" :operate-type="operateType" :row-data="editingData"
         @submitted="getDataByPage" />

+ 59 - 82
src/views/admin/log/sys-oper-log/modules/m-operate-drawer.vue

@@ -1,8 +1,9 @@
 <script setup lang="ts">
-import { useAntdForm, useFormRules } from '@/hooks/common/form';
+import { useAntdForm } from '@/hooks/common/form';
 import { $t } from '@/locales';
-import { getDicts, fetchPostDetail, fetchPostAdd, fetchPostEdit } from '@/service/api';
-import { computed, reactive, ref, watch } from 'vue';
+import { getDicts } from '@/service/api';
+import { computed, reactive, ref, watch, nextTick } from 'vue';
+import dayjs from 'dayjs';
 defineOptions({
   name: 'MOperateDrawer'
 });
@@ -11,7 +12,7 @@ interface Props {
   /** the type of operation */
   operateType: AntDesign.TableOperateType;
   /** the edit row data */
-  rowData?: Api.Admin.SysPost | null;
+  rowData?: Api.Admin.SysOperLog | null;
 }
 
 const props = defineProps<Props>();
@@ -26,63 +27,50 @@ const visible = defineModel<boolean>('visible', {
   default: false
 });
 
-const { formRef, validate, resetFields } = useAntdForm();
-const { defaultRequiredRule, createRequiredRule } = useFormRules();
+const { formRef, resetFields } = useAntdForm();
 
 const title = computed(() => {
   const titles: Record<AntDesign.TableOperateType, string> = {
-    add: $t('page.admin.sysPost.addTitle'),
-    edit: $t('page.admin.sysPost.editTitle')
+    detail: $t('page.admin.sysOperLog.detailTitle'),
+    add: '',
+    edit: ''
   };
   return titles[props.operateType];
 });
 
 type Model = Pick<
-  Api.Admin.SysPost,
-  'postId' | 'postName' | 'postCode' | 'sort' | 'status' | 'remark'>;
+  Api.Admin.SysOperLog,
+  'operUrl' | 'operName' | 'operIp' | 'operLocation' | 'requestMethod' | 'latencyTime' | 'operParam' | 'jsonResult' | 'status' | 'operTime' | 'errorMsg'>;
 
 const model: Model = reactive(createDefaultModel());
 
 function createDefaultModel(): Model {
   return {
-    postId: '',
-    postName: '',
-    postCode: '',
-    sort: 0,
-    status: '1',
-    remark: '',
+    operUrl: '',
+    operName: '',
+    operIp: '',
+    operLocation: '',
+    requestMethod: '',
+    latencyTime: '',
+    operParam: '',
+    jsonResult: '',
+    status: '',
+    operTime: '',
+    errorMsg: '',
   };
 }
 
-type RuleKey = Extract<keyof Model, 'postId' | 'postName' | 'postCode' | 'sort' | 'status' | 'remark'>;
-
-const rules: Record<RuleKey, App.Global.FormRule> = {
-  postId: defaultRequiredRule,
-  postName: createRequiredRule($t('page.admin.sysPost.form.postName')),
-  postCode: createRequiredRule($t('page.admin.sysPost.form.postName')),
-  sort: defaultRequiredRule,
-  status: defaultRequiredRule,
-  remark: defaultRequiredRule,
-};
-
-const deptStatus = ref<CommonType.Option<string>[]>([]);
+const commonStatus = ref<CommonType.Option<string>[]>([]);
 async function getDeptStatusOptions() {
-  const { data } = await getDicts('sys_normal_disable')
-  deptStatus.value = data || []
-}
-
-async function getDeptDetails() {
-  let postId = props.rowData?.postId + ''
-  const { data } = await fetchPostDetail(postId)
-  data.status = data.status + ''
-  data.orderNum = data.sort
-  Object.assign(model, data);
+  const { data } = await getDicts('sys_common_status')
+  commonStatus.value = data || []
 }
 
 async function handleInitModel() {
   Object.assign(model, createDefaultModel());
-  if (props.operateType === 'edit' && props.rowData) {
-    getDeptDetails()
+  if (props.operateType === 'detail' && props.rowData) {
+    await nextTick();
+    Object.assign(model, props.rowData);
   }
 }
 
@@ -90,31 +78,6 @@ function closeDrawer() {
   visible.value = false;
 }
 
-async function handleSubmit() {
-  await validate();
-  let fnMap = {
-    add: () => {
-      const { code, msg } = fetchPostAdd(model)
-      if (code === 200) {
-        window.$message?.success(msg);
-        closeDrawer();
-        emit('submitted');
-      }
-    },
-    edit: () => {
-      let postId = props.rowData?.postId + ''
-      const { code, msg } = fetchPostEdit(model, postId)
-      if (code === 200) {
-        window.$message?.success(msg);
-        closeDrawer();
-        emit('submitted');
-      }
-      console.log('edit')
-    }
-  }
-  fnMap[props.operateType] && fnMap[props.operateType]()
-}
-
 watch(visible, () => {
   if (visible.value) {
     handleInitModel()
@@ -126,36 +89,51 @@ watch(visible, () => {
 
 <template>
   <AModal v-model:open="visible" :title="title" width="800px">
-    <AForm ref="formRef" :model="model" :rules="rules" :label-col="{ lg: 8, xs: 4 }" label-wrap class="pr-20px">
+    <AForm ref="formRef" :model="model" :label-col="{ lg: 8, xs: 4 }" label-wrap class="pr-20px">
       <ARow wrap>
+        <ACol :span="24" :md="24" :xs="24">
+          <AFormItem label="请求地址" :label-col="{ lg: 4, xs: 2 }">
+            {{ model.operUrl }}
+          </AFormItem>
+        </ACol>
         <ACol :span="12" :md="12" :xs="24">
-          <AFormItem :label="$t('page.admin.sysPost.postName')" name="postName">
-            <AInput v-model:value="model.postName" :placeholder="$t('page.admin.sysPost.form.postName')" allowClear />
+          <AFormItem label="登录信息">
+            {{ model.operName }} / {{ model.operIp }} / {{ model.operLocation }}
           </AFormItem>
         </ACol>
         <ACol :span="12" :md="12" :xs="24">
-          <AFormItem :label="$t('page.admin.sysPost.postCode')" name="postCode">
-            <AInput v-model:value="model.postCode" :placeholder="$t('page.admin.sysPost.form.postCode')" allowClear />
+          <AFormItem label="请求方式">
+            {{ model.requestMethod }}
           </AFormItem>
         </ACol>
         <ACol :span="12" :md="12" :xs="24">
-          <AFormItem :label="$t('page.admin.sysPost.sort')" name="sort">
-            <AInputNumber v-model:value="model.sort" :min="0" :placeholder="$t('page.admin.sysPost.form.sort')"
-              allowClear />
+          <AFormItem label="耗时">
+            {{ model.latencyTime }}
+          </AFormItem>
+        </ACol>
+        <ACol :span="24" :md="24" :xs="24">
+          <AFormItem label="请求参数" :label-col="{ lg: 4, xs: 2 }">
+            {{ model.operParam }}
+          </AFormItem>
+        </ACol>
+        <ACol :span="24" :md="24" :xs="24">
+          <AFormItem label="返回参数" :label-col="{ lg: 4, xs: 2 }">
+            {{ model.jsonResult }}
           </AFormItem>
         </ACol>
         <ACol :span="12" :md="12" :xs="24">
-          <AFormItem :label="$t('page.admin.sysPost.status')" name="status">
-            <ARadioGroup v-model:value="model.status">
-              <ARadio v-for="item in deptStatus" :key="item.value" :value="item.value">
-                {{ item.label }}
-              </ARadio>
-            </ARadioGroup>
+          <AFormItem label="操作状态">
+            {{ model.status }}
           </AFormItem>
         </ACol>
         <ACol :span="12" :md="12" :xs="24">
-          <AFormItem :label="$t('page.admin.sysPost.remark')">
-            <ATextarea v-model:value="model.remark" :placeholder="$t('page.admin.sysPost.form.remark')" allowClear />
+          <AFormItem label="操作时间">
+            {{ dayjs(model.operTime).format('YYYY-MM-DD HH:mm:ss') }}
+          </AFormItem>
+        </ACol>
+        <ACol :span="24" :md="24" :xs="24">
+          <AFormItem label="异常信息" :label-col="{ lg: 4, xs: 2 }">
+            {{ model.errorMsg }}
           </AFormItem>
         </ACol>
       </ARow>
@@ -163,7 +141,6 @@ watch(visible, () => {
     <template #footer>
       <ASpace :size="16">
         <AButton @click="closeDrawer">{{ $t('common.cancel') }}</AButton>
-        <AButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</AButton>
       </ASpace>
     </template>
   </AModal>

+ 1 - 1
src/views/admin/log/sys-oper-log/modules/m-search.vue

@@ -47,7 +47,7 @@ async function search() {
 
 const normalStatus = ref<CommonType.Option<string>[]>([]);
 async function getDeptStatusOptions() {
-  const { data } = await getDicts('sys_normal_disable')
+  const { data } = await getDicts('sys_common_status')
   normalStatus.value = data || []
 }
 getDeptStatusOptions()

+ 0 - 220
src/views/admin/sys-login-log/index.vue

@@ -1,220 +0,0 @@
-<script setup lang="tsx">
-import { useTable, useTableOperate, useTableScroll } from '@/hooks/common/table';
-import { $t } from '@/locales';
-import { changeUserStatus, fetchDelteUser, fetchGetUserList } from '@/service/api';
-import { Button, Popconfirm } from 'ant-design-vue';
-import dayjs from 'dayjs';
-import { ref } from 'vue';
-import UserOperateDrawer from './modules/user-operate-drawer.vue';
-import UserResetPwdDialog from './modules/user-resetpwd-dialog.vue';
-import UserSearch from './modules/user-search.vue';
-const { tableWrapperRef, scrollConfig } = useTableScroll();
-const apiParams = ref({
-  pageIndex: 1,
-  pageSize: 10
-});
-let transUserId:number | null = null
-let userName = ''
-let resetDialogVisible = ref(false)
-
-const {
-  columns,
-  columnChecks,
-  data,
-  getData,
-  getDataByPage,
-  loading,
-  mobilePagination,
-  searchParams,
-  resetSearchParams
-} = useTable({
-  apiFn: fetchGetUserList,
-  apiParams:apiParams.value,
-  showTotal: true,
-  columns: () => [
-    {
-      key: 'userId',
-      title: '用户ID',
-      dataIndex: 'userId',
-      align: 'center',
-      width: 64
-    },
-    {
-      key: 'username',
-      dataIndex: 'username',
-      title: '登录名',
-      align: 'center',
-      minWidth: 120
-    },
-    {
-      key: 'nickName',
-      title: '昵称',
-      align: 'center',
-      dataIndex: 'nickName',
-      minWidth: 100
-    },
-    {
-      key: 'deptName',
-      dataIndex: 'deptName',
-      title: '部门',
-      align: 'center',
-      minWidth: 120,
-      customRender: ({ record }) => {
-        return record.dept.deptName;
-      }
-    },
-    {
-      key: 'phone',
-      dataIndex: 'phone',
-      title: $t('page.manage.user.userPhone'),
-      align: 'center',
-      minWidth: 120
-    },
-    {
-      key: 'status',
-      dataIndex: 'status',
-      title: $t('page.manage.user.userStatus'),
-      align: 'center',
-      minWidth: 100,
-      customRender: ({ record}) => {
-        let showStatus:boolean = record.status == '2' ? true : false;
-        const text:string = record.status == '2' ? '停用' : '启用';
-        return <Popconfirm title={`确定要${text}${record.username}的用户吗?`} onConfirm={() => handleChangeStatus(record, text)} >
-          <a-switch v-model:checked={showStatus} ></a-switch>
-        </Popconfirm>;
-      }
-    },
-    {
-      key: 'createdAt',
-      dataIndex: 'createdAt',
-      title: '创建时间',
-      align: 'center',
-      minWidth: 150,
-      customRender:({record})=>{
-        return dayjs(record.createdAt).format('YYYY-MM-DD HH:mm:ss')
-      }
-    },
-    {
-      key: 'operate',
-      title: $t('common.operate'),
-      align: 'center',
-      fixed: 'right',
-      width: 180,
-      customRender: ({ record }) => (
-        <div class="flex-center gap-0.1rem">
-          <Button type="primary" ghost size="small" onClick={() => handleRowEdit(record.userId)} style="margin-right:5px">
-            {$t('common.edit')}
-          </Button>
-          <Popconfirm title={$t('common.confirmDelete')} onConfirm={() => handleDelete(record.userId)}>
-            <Button danger size="small" style="margin-right:5px">
-              {$t('common.delete')}
-            </Button>
-          </Popconfirm>
-          <Button size="small" onClick={() => handleResetPwd(record)}>
-            重置
-          </Button>
-        </div>
-      )
-    }
-  ]
-});
-const {
-  drawerVisible,
-  operateType,
-  editingData,
-  handleAdd,
-  handleEdit,
-  checkedRowKeys,
-  rowSelection,
-  onDeleted
-  // closeDrawer
-} = useTableOperate(data, getData);
-
-async function handleBatchDelete() {
-  // request
-  handleDelete(checkedRowKeys.value)
-}
-async function handleChangeStatus(row:any, text:string){
-  const data = {
-    userId: row.userId,
-    status: text === '停用'? '1' : '2'
-  }
-  const res = await changeUserStatus(data)
-  if (res.code === 200) {
-    window.$message?.success('更新成功!');
-  } else {
-    window.$message?.error('更新失败!');
-  }
-  await getData()
-
-}
-// 删除
-async function handleDelete(id: any) {
-  // request
-  let ids = []
-  typeof id === 'number' ? ids.push(id) : ids = [].concat(id)
-  const res = await fetchDelteUser({ids})
-  if (res.code === 200) {
-    onDeleted();
-  } else {
-    window.$message?.error('删除失败!');
-  }
-}
-
-// 重置
-function handleResetPwd(row:any) {
-  resetDialogVisible.value = true
-  userName = row.username
-  transUserId = row.userId
-}
-
-// 编辑
-function handleRowEdit(id: number) {
-  handleEdit(id, 'userId');
-}
-</script>
-
-<template>
-  <div class="min-h-6.25rem flex-col-stretch gap-0.2rem overflow-hidden lt-sm:overflow-auto">
-    <UserSearch v-model:model="searchParams" @reset="resetSearchParams" @search="getDataByPage" />
-    <ACard
-      :title="$t('page.manage.user.title')"
-      :bordered="false"
-      :body-style="{ flex: 1, overflow: 'hidden' }"
-      class="flex-col-stretch sm:flex-1-hidden card-wrapper"
-    >
-      <template #extra>
-        <TableHeaderOperation
-          v-model:columns="columnChecks"
-          :disabled-delete="checkedRowKeys.length === 0"
-          :loading="loading"
-          @add="handleAdd"
-          @delete="handleBatchDelete"
-          @refresh="getData"
-        />
-      </template>
-      <ATable
-        ref="tableWrapperRef"
-        :columns="columns"
-        :data-source="data"
-        size="small"
-        :row-selection="rowSelection"
-        :scroll="scrollConfig"
-        :loading="loading"
-        row-key="userId"
-        :pagination="mobilePagination"
-        class="h-full"
-      />
-
-      <UserOperateDrawer
-        v-model:visible="drawerVisible"
-        :operate-type="operateType"
-        :row-data="editingData"
-        @submitted="getDataByPage"
-      />
-      <UserResetPwdDialog v-model:dialogVisible="resetDialogVisible" :userId="transUserId" :user-name="userName"/>
-    </ACard>
-  </div>
-</template>
-
-<style scoped></style>

+ 0 - 248
src/views/admin/sys-login-log/modules/user-operate-drawer.vue

@@ -1,248 +0,0 @@
-/* eslint-disable */
-<script setup lang="ts">
-import { useAntdForm, useFormRules } from '@/hooks/common/form';
-import { $t } from '@/locales';
-import { fetchAddUser, fetchGetAllRoles, fetchGetdeptTreeList, fetchGetPostList, getDicts } from '@/service/api';
-import { computed, nextTick, reactive, ref, watch } from 'vue';
-defineOptions({
-  name: 'UserOperateDrawer'
-});
-
-interface Props {
-  /** the type of operation */
-  operateType: AntDesign.TableOperateType;
-  /** the edit row data */
-  rowData?: Api.SystemManage.User | null;
-}
-
-const props = defineProps<Props>();
-
-interface Emits {
-  (e: 'submitted'): void;
-}
-
-const emit = defineEmits<Emits>();
-
-const visible = defineModel<boolean>('visible', {
-  default: false
-});
-
-const { formRef, validate, resetFields } = useAntdForm();
-const { defaultRequiredRule, formRules } = useFormRules();
-
-const title = computed(() => {
-  const titles: Record<AntDesign.TableOperateType, string> = {
-    add: $t('page.manage.user.addUser'),
-    edit: $t('page.manage.user.editUser')
-  };
-  return titles[props.operateType];
-});
-
-type Model = Pick<
-  Api.SystemManage.User,
-  'username' | 'sex' | 'nickName' | 'phone' | 'email' | 'status' | 'deptId' | 'password' | 'postId' | 'roleId' | 'remark'
->;
-
-const model: Model = reactive(createDefaultModel());
-
-function createDefaultModel(): Model {
-  return {
-    username: '',
-    sex: '',
-    nickName: '',
-    phone: '',
-    email: '',
-    status: '2',
-    deptId: '',
-    password: '',
-    postId: '',
-    roleId: '',
-    remark: ''
-  };
-}
-
-type RuleKey = Extract<keyof Model, 'username' | 'status'| 'nickName'| 'deptId' | 'password'| 'email' | 'phone'>;
-
-const rules: Record<RuleKey, App.Global.FormRule> = {
-  username: defaultRequiredRule,
-  nickName: defaultRequiredRule,
-  deptId: defaultRequiredRule,
-  password: defaultRequiredRule,
-  phone: formRules.phone,
-  email:formRules.email
-};
-
-/** the enabled role options */
-const roleOptions = ref<CommonType.Option<string>[]>([]);
-const userGenderOptions = ref<CommonType.Option<string>[]>([
-  {label: "男", value: "0"},
-  {label: "女", value: "1"},
-  {label: "未知", value: "2"}
-]);
-const enableStatusOptions = ref<CommonType.Option<string>[]>([]);
-const postOptions = ref<CommonType.Option<string>[]>([]);
-const departOptions = ref<CommonType.Option<string>[]>([]);
-
-async function getSixOptions(){
-  const { data } = await getDicts('sys_user_sex')
-  userGenderOptions.value = data || []
-}
-async function getStatusOptions(){
-  const { data } = await getDicts('sys_normal_disable')
-  enableStatusOptions.value = data || []
-}
-async function getPostOptions(){
-  const { data } = await fetchGetPostList({ pageSize: 1000 })
-  const options = data?.list.map((item:any) => ({
-    label: item.postName,
-    value: item.postId,
-    postCode: item.postCode
-  }));
-  postOptions.value = [...options] || []
-}
-async function getDeptTree(){
-  const { data } = await fetchGetdeptTreeList()
-  departOptions.value = data
-}
-
-async function getRoleOptions() {
-  const { data } = await fetchGetAllRoles({ pageSize: 1000 });
-  const options = data?.list.map((item:any) => ({
-    label: item.roleName,
-    value: item.roleId,
-    status: item.status
-  }));
-  roleOptions.value = [...options];
-}
-
-async function handleInitModel() {
-  Object.assign(model, createDefaultModel());
-
-  if (props.operateType === 'edit' && props.rowData) {
-    await nextTick();
-    Object.assign(model, props.rowData);
-  }
-}
-
-function closeDrawer() {
-  visible.value = false;
-}
-
-async function handleSubmit() {
-  await validate();
-  // request 新增method 是post 修改是put
-  let method = ''
-  if (props.operateType === 'add') {
-    method = 'post'
-  } else {
-    method = 'put'
-  }
-  const res = await fetchAddUser(model, method)
-  if (res.code === 200){
-    window.$message?.success(res.msg);
-  }
-  closeDrawer();
-  emit('submitted');
-}
-
-watch(visible, () => {
-  if (visible.value) {
-    handleInitModel();
-    resetFields();
-    getRoleOptions();
-    getSixOptions()
-    getStatusOptions()
-    getPostOptions()
-    getDeptTree()
-  }
-});
-</script>
-
-<template>
-  <AModal v-model:open="visible" :title="title" width="800px">
-    <AForm ref="formRef"  :model="model" :rules="rules" :label-col="{ lg: 8, xs: 4 }" label-wrap class="pr-20px">
-      <ARow  wrap>
-        <ACol :span="12" :md="12" :xs="24">
-          <AFormItem :label="$t('page.manage.user.nickName')" name="nickName">
-            <AInput v-model:value="model.nickName" :placeholder="$t('page.manage.user.form.nickName')" allowClear/>
-          </AFormItem>
-        </ACol>
-        <ACol :span="12" :md="12" :xs="24">
-          <AFormItem :label="$t('page.manage.user.deptId')" name="roleId">
-            <ATreeSelect v-model:value="model.deptId" show-search  :tree-data="departOptions"
-            :fieldNames="{value: 'id', children: 'children', label: 'label'}"
-              :placeholder="$t('page.manage.user.form.deptId')" allowClear/>
-          </AFormItem>
-        </ACol>
-      </ARow>
-      <ARow wrap>
-        <ACol :span="12" :md="12" :xs="24">
-          <AFormItem :label="$t('page.manage.user.userPhone')" name="phone">
-            <AInput v-model:value="model.phone" :placeholder="$t('page.manage.user.form.userPhone')" allowClear/>
-          </AFormItem>
-        </ACol>
-        <ACol :span="12" :md="12" :xs="24">
-          <AFormItem :label="$t('page.manage.user.userEmail')" name="email">
-            <AInput v-model:value="model.email" :placeholder="$t('page.manage.user.form.userEmail')" allowClear/>
-          </AFormItem>
-        </ACol>
-      </ARow>
-      <ARow wrap>
-        <ACol :span="12" :md="12" :xs="24">
-          <AFormItem :label="$t('page.manage.user.userName')" name="username">
-            <AInput v-model:value="model.username" :placeholder="$t('page.manage.user.form.userName')" allowClear/>
-          </AFormItem>
-        </ACol>
-        <ACol :span="12" :md="12" :xs="24" v-if="props.operateType === 'add'">
-          <AFormItem :label="$t('page.manage.user.password')" name="password" >
-            <AInput v-model:value="model.password" :placeholder="$t('page.manage.user.form.password')" allowClear/>
-          </AFormItem>
-        </ACol>
-        <ACol :span="12" :md="12" :xs="24">
-          <AFormItem :label="$t('page.manage.user.userGender')" name="sex">
-            <ARadioGroup v-model:value="model.sex">
-              <ARadio v-for="item in userGenderOptions" :key="item.value" :value="item.value">
-                {{item.label }}
-              </ARadio>
-            </ARadioGroup>
-          </AFormItem>
-        </ACol>
-        <ACol :span="12" :md="12" :xs="24">
-          <AFormItem :label="$t('page.manage.user.userStatus')" name="status">
-            <ARadioGroup v-model:value="model.status">
-              <ARadio v-for="item in enableStatusOptions" :key="item.value" :value="item.value">
-                {{ item.label }}
-              </ARadio>
-            </ARadioGroup>
-          </AFormItem>
-        </ACol>
-        <ACol :span="12" :md="12" :xs="24">
-          <AFormItem :label="$t('page.manage.user.postId')" name="postId">
-            <ASelect v-model:value="model.postId" :options="postOptions"
-              :placeholder="$t('page.manage.user.form.postId')" allowClear/>
-          </AFormItem>
-        </ACol>
-        <ACol :span="12" :md="props.operateType === 'add'? 12: 24" :xs="24">
-          <AFormItem :label="$t('page.manage.user.userRole')" name="roleId">
-            <ASelect v-model:value="model.roleId"  :options="roleOptions"
-              :placeholder="$t('page.manage.user.form.userRole')" allowClear/>
-          </AFormItem>
-        </ACol>
-        <ACol :span="24" :md="24" :xs="24">
-          <AFormItem :label-col="{ lg: 4, xs: 2 }" :label="$t('page.manage.user.remark')" name="remark">
-            <a-textarea v-model:value="model.remark" :placeholder="$t('page.manage.user.form.remark')"
-              :auto-size="{ minRows: 2, maxRows: 5 }" allowClear/>
-          </AFormItem>
-        </ACol>
-      </ARow>
-    </AForm>
-    <template #footer>
-      <ASpace :size="16">
-        <AButton @click="closeDrawer">{{ $t('common.cancel') }}</AButton>
-        <AButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</AButton>
-      </ASpace>
-    </template>
-  </AModal>
-</template>
-
-<style scoped></style>

+ 0 - 65
src/views/admin/sys-login-log/modules/user-resetpwd-dialog.vue

@@ -1,65 +0,0 @@
-/* eslint-disable */
-<script setup lang="ts">
-import { useAntdForm, useFormRules } from '@/hooks/common/form';
-import { fetchRestPwsUser } from '@/service/api';
-import { reactive, watch } from 'vue';
-defineOptions({
-  name: 'UserResetPwdDialog'
-});
-const visible = defineModel<boolean>('dialogVisible', {
-  default: false
-});
-interface Props {
-  userId: number | null,
-  userName: string | null
-}
-const props = defineProps<Props>();
-const model = reactive(createDefaultModel());
-const { formRef, validate, resetFields } = useAntdForm();
-const { formRules } = useFormRules();
-function createDefaultModel(){
-  return {
-    password: '',
-    userId: props.userId
-  };
-}
-const rules: Record<'password', App.Global.FormRule> = {
-  password: formRules.pwd,
-};
-
-function closeDrawer() {
-  visible.value = false;
-}
-async function handleSubmit() {
-  await validate();
-  model.userId = props.userId
-
-  const res = await fetchRestPwsUser(model)
-  if (res.code === 200){
-    window.$message?.success(res.msg);
-  }
-  closeDrawer();
-}
-watch(visible, () => {
-  if (visible.value) {
-    resetFields();
-  }
-});
-</script>
-<template>
-  <AModal v-model:open="visible" title="重置密码" width="420px">
-    <!-- <p style="margin-bottom: 10px;"></p> -->
-    <AForm ref="formRef" layout="vertical" :model="model" :rules="rules">
-      <AFormItem :label="`请输入${userName}的新密码`" name="password">
-        <AInput v-model:value="model.password" placeholder="请输入新密码" allowClear/>
-      </AFormItem>
-    </AForm>
-    <template #footer>
-      <ASpace :size="16">
-        <AButton @click="closeDrawer">{{ $t('common.cancel') }}</AButton>
-        <AButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</AButton>
-      </ASpace>
-    </template>
-  </AModal>
-</template>
-<style scoped></style>

+ 0 - 137
src/views/admin/sys-login-log/modules/user-search.vue

@@ -1,137 +0,0 @@
-/* eslint-disable */
-<script setup lang="ts">
-import { enableStatusOptions } from '@/constants/business';
-import { useAntdForm, useFormRules } from '@/hooks/common/form';
-import { $t } from '@/locales';
-import { fetchGetdeptTreeList } from '@/service/api';
-import { translateOptions } from '@/utils/common';
-import { computed, onMounted, ref } from 'vue';
-defineOptions({
-  name: 'UserSearch'
-});
-
-interface Emits {
-  (e: 'reset'): void;
-  (e: 'search'): void;
-}
-
-const emit = defineEmits<Emits>();
-const departOptions = ref<CommonType.Option<string>[]>([]);
-const { formRef, validate, resetFields } = useAntdForm();
-
-const model = defineModel<Api.SystemManage.UserSearchParams>('model', { required: true });
-
-type RuleKey = Extract<keyof Api.SystemManage.UserSearchParams, 'email' | 'phone'>;
-
-const rules = computed<Record<RuleKey, App.Global.FormRule>>(() => {
-  const { patternRules } = useFormRules(); // inside computed to make locale reactive
-
-  return {
-    email: patternRules.email,
-    phone: patternRules.phone
-  };
-});
-onMounted(()=>{
-  getDeptTree()
-})
-async function getDeptTree(){
-  const { data } = await fetchGetdeptTreeList()
-  departOptions.value = data
-}
-async function reset() {
-  await resetFields();
-  emit('reset');
-}
-
-async function search() {
-  await validate();
-  emit('search');
-}
-
-</script>
-
-<template>
-  <ACard :title="$t('common.search')" :bordered="false" class="card-wrapper">
-    <AForm
-      ref="formRef"
-      :model="model"
-      :rules="rules"
-      :label-col="{
-        span: 5,
-        md: 7
-      }"
-    >
-      <ARow :gutter="[16, 16]" wrap>
-        <ACol :span="24" :md="12" :lg="6">
-          <AFormItem :label="$t('page.manage.user.userName')" name="username" class="m-0">
-            <AInput v-model:value.trim="model.username" :placeholder="$t('page.manage.user.form.userName')" @keyup.enter.native="search" allowClear/>
-          </AFormItem>
-        </ACol>
-        <ACol :span="24" :md="12" :lg="6">
-          <AFormItem :label="$t('page.manage.user.deptId')" name="roleId">
-            <ATreeSelect v-model:value="model.deptId" show-search  :tree-data="departOptions"
-            :fieldNames="{value: 'id', children: 'children', label: 'label'}" @change="search"
-              :placeholder="$t('page.manage.user.form.deptId')" allowClear/>
-          </AFormItem>
-        </ACol>
-
-        <!-- <ACol :span="24" :md="12" :lg="6">
-          <AFormItem :label="$t('page.manage.user.userGender')" name="sex" class="m-0">
-            <ASelect
-              v-model:value="model.sex"
-              :placeholder="$t('page.manage.user.form.userGender')"
-              :options="translateOptions(userGenderOptions)"
-              clearable
-            />
-          </AFormItem>
-        </ACol> -->
-        <!-- <ACol :span="24" :md="12" :lg="6">
-          <AFormItem :label="$t('page.manage.user.nickName')" name="nickName" class="m-0">
-            <AInput v-model:value="model.nickName" :placeholder="$t('page.manage.user.form.nickName')" />
-          </AFormItem>
-        </ACol> -->
-        <ACol :span="24" :md="12" :lg="6">
-          <AFormItem :label="$t('page.manage.user.userPhone')" name="phone" class="m-0">
-            <AInput v-model:value.trim="model.phone" :placeholder="$t('page.manage.user.form.userPhone')" @keyup.enter.native="search" allowClear/>
-          </AFormItem>
-        </ACol>
-        <!-- <ACol :span="24" :md="12" :lg="6">
-          <AFormItem :label="$t('page.manage.user.userEmail')" name="email" class="m-0">
-            <AInput v-model:value="model.email" :placeholder="$t('page.manage.user.form.userEmail')" />
-          </AFormItem>
-        </ACol> -->
-        <ACol :span="24" :md="12" :lg="6">
-          <AFormItem :label="$t('page.manage.user.userStatus')" name="status" class="m-0">
-            <ASelect
-              v-model:value="model.status"
-              :placeholder="$t('page.manage.user.form.userStatus')"
-              :options="translateOptions(enableStatusOptions)"
-              @change="search"
-              allowClear
-            />
-          </AFormItem>
-        </ACol>
-        <div class="flex-1">
-          <AFormItem class="m-0">
-            <div class="w-full flex-y-center justify-end gap-12px">
-              <AButton @click="reset">
-                <template #icon>
-                  <icon-ic-round-refresh class="align-sub text-icon" />
-                </template>
-                <span class="ml-8px">{{ $t('common.reset') }}</span>
-              </AButton>
-              <AButton type="primary" ghost @click="search">
-                <template #icon>
-                  <icon-ic-round-search class="align-sub text-icon" />
-                </template>
-                <span class="ml-8px">{{ $t('common.search') }}</span>
-              </AButton>
-            </div>
-          </AFormItem>
-        </div>
-      </ARow>
-    </AForm>
-  </ACard>
-</template>
-
-<style scoped></style>