فهرست منبع

feat: 添加保密保卫-人员管理

wyf 7 ماه پیش
والد
کامیت
bbb126c6a5

+ 222 - 3
src/views/security-confidentiality/person-management/inner-person/InnerPerson.vue

@@ -1,7 +1,226 @@
 <template>
-  <div> overview </div>
+  <div class="safety-platform-container">
+    <header class="safety-platform-container__header">
+      <div class="breadcrumb-title"> 内部人员门禁出入记录 </div>
+    </header>
+    <main class="safety-platform-container__main">
+      <div class="search-table-container">
+        <header>
+          <div class="table-search">
+            <section class="select-box">
+              <SelectableInput ref="selectableInputRef" :options="INNER_PERSON_TABLE_SEARCH_OPTIONS" />
+              <div class="select-box--item">
+                <span>部门:</span>
+                <el-cascader
+                  style="width: 265px"
+                  v-model="searchData.todobumen"
+                  :options="deptTree"
+                  :props="cascaderProp"
+                  clearable
+                  collapse-tags
+                  :show-all-levels="false"
+                  :max-collapse-tags="1"
+                  placeholder="请选择责任部门"
+                >
+                </el-cascader>
+              </div>
+              <div class="select-box--item">
+                <span>事件:</span>
+                <el-select
+                  v-model="searchData.todoshijian"
+                  placeholder="请选择通知状态"
+                  class="select-box--select"
+                  clearable
+                >
+                  <el-option
+                    v-for="item in OCCURRENCE_TYPE_OPTIONS"
+                    :key="item.value"
+                    :value="item.value"
+                    :label="item.label"
+                    :disabled="item.disabled"
+                  />
+                </el-select>
+              </div>
+              <div>
+                <span>时间:</span>
+                <el-date-picker
+                  v-model="searchTime"
+                  type="datetimerange"
+                  range-separator="至"
+                  start-placeholder="开始时间"
+                  end-placeholder="结束时间"
+                />
+              </div>
+            </section>
+            <section class="search-btn">
+              <el-button type="primary" @click="handleSearch">查询</el-button>
+              <el-button @click="handleReset">重置</el-button>
+              <el-button @click="handleDownload">导出</el-button>
+            </section>
+          </div>
+        </header>
+        <!-- 表格 -->
+        <BasicTable
+          ref="basicTableRef"
+          :tableData="tableData"
+          :tableConfig="tableConfig"
+          @update:pageSize="handleSizeChange"
+          @update:pageNumber="handleCurrentChange"
+        >
+        </BasicTable>
+      </div>
+    </main>
+  </div>
 </template>
 
-<script setup lang="ts"></script>
+<script setup lang="ts">
+  import BasicTable from '@/components/BasicTable.vue';
+  import useTableConfig from '@/hooks/useTableConfigHook';
+  import SelectableInput from '@/components/formItems/selectableInput/SelectableInput.vue';
+  import { TABLE_OPTIONS, INNER_PERSON_TABEL_COLUMNS } from './configs/table';
+  import { onMounted, reactive, ref } from 'vue';
+  import { QueryPageRequest, QueryPageResponse } from '@/types/basic-query';
+  import type { InnerPersonTableData, InnerPersonTableQuery } from './types';
+  import { INNER_PERSON_TABLE_SEARCH_OPTIONS, OCCURRENCE_TYPE_OPTIONS } from './constants';
 
-<style scoped></style>
+  import { DeptTree } from '@/types/dept/type';
+  import { getAllDepartments } from '@/api/auth/dept';
+
+  const searchData = reactive<InnerPersonTableQuery>({});
+  const searchTime = ref<string[]>([]);
+  const selectableInputRef = ref<InstanceType<typeof SelectableInput>>();
+
+  function getQuery() {
+    const query = {
+      todoxinming: selectableInputRef.value?.getValue(),
+      ...searchData,
+      startTime: searchTime.value[0],
+      endTime: searchTime.value[1],
+    };
+  }
+  async function getTableData() {
+    tableConfig.loading = true;
+    const res = await new Promise<QueryPageResponse<InnerPersonTableData>>((resolve) => {
+      resolve({
+        totalRow: 1,
+        records: [
+          {
+            todoxinming: '张三',
+            todokahao: 'aaa',
+            todobumen: '部门1',
+            todoshijian: 1,
+            tododidian: '地点1',
+            todojinchushijian: '2023-01-01 00:00:00',
+          },
+        ],
+      });
+    });
+    tableData.value = res.records;
+    pagination.total = res.totalRow;
+    tableConfig.loading = false;
+  }
+
+  const { tableConfig, pagination } = useTableConfig(INNER_PERSON_TABEL_COLUMNS, TABLE_OPTIONS);
+
+  const tableData = ref<InnerPersonTableData[]>([]);
+
+  const tableQuery = reactive<QueryPageRequest<InnerPersonTableQuery>>({
+    pageNumber: pagination.pageNumber,
+    pageSize: pagination.pageSize,
+    queryParam: {},
+  });
+
+  const handleSizeChange = (value: number) => {
+    pagination.pageSize = value;
+    tableQuery.pageSize = value;
+    getTableData();
+  };
+  const handleCurrentChange = (value: number) => {
+    pagination.pageNumber = value;
+    tableQuery.pageNumber = value;
+    getTableData();
+  };
+
+  function handleSearch() {
+    getQuery();
+    getTableData();
+  }
+
+  function handleReset() {
+    selectableInputRef.value?.clearValue();
+    for (const key in searchData) {
+      if (searchData.hasOwnProperty(key)) {
+        searchData[key] = undefined;
+      }
+    }
+    handleSearch();
+  }
+
+  async function handleDownload() {
+    getQuery();
+    // try {
+    //   const res = await exportActViolation(tableQuery.queryParam);
+    //   if (res.size === 0) return;
+    //   const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
+    //   const url = window.URL.createObjectURL(blob);
+    //   downloadFile(url, '违规行为记录.xlsx');
+    // } catch (e) {
+    //   ElMessage.error('下载失败');
+    //   console.log(e);
+    // }
+  }
+
+  // 获取级联部门数据
+  const deptTree = ref<DeptTree[]>();
+  const loadDeptTreeData = async () => {
+    const result = await getAllDepartments();
+    deptTree.value = result[0].children;
+  };
+
+  const cascaderProp = {
+    multiple: true,
+    expandTrigger: 'hover',
+    checkStrictly: true,
+    emitPath: false,
+    value: 'id',
+    label: 'deptName',
+  };
+
+  onMounted(() => {
+    loadDeptTreeData();
+    getTableData();
+  });
+</script>
+
+<style scoped lang="scss">
+  @use '@/styles/page-details-layout.scss' as *;
+  @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
+
+  .table-search {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    width: 100%;
+  }
+  .select-box {
+    display: flex;
+    align-items: center;
+    flex-wrap: wrap;
+    gap: 32px;
+    &--item {
+      @include flex-center;
+      white-space: nowrap;
+    }
+    span {
+      color: rgba(0, 0, 0, 0.85);
+      font-size: 14px;
+    }
+    .el-select {
+      width: 200px;
+    }
+  }
+  .search-btn {
+    display: flex;
+  }
+</style>

+ 45 - 0
src/views/security-confidentiality/person-management/inner-person/configs/table.ts

@@ -0,0 +1,45 @@
+export const TABLE_OPTIONS = {
+  emptyText: '暂无数据',
+  loading: true,
+  maxHeight: 'calc(70vh - 150px)',
+};
+
+export const INNER_PERSON_TABEL_COLUMNS = [
+  {
+    prop: 'todoxinming',
+    label: '姓名',
+    align: 'center',
+    minWidth: '120px',
+  },
+  {
+    prop: 'todokahao',
+    label: '卡号',
+    align: 'center',
+    minWidth: '120px',
+  },
+  {
+    prop: 'todobumen',
+    label: '部门',
+    align: 'center',
+    minWidth: '120px',
+  },
+  {
+    prop: 'todoshijian',
+    label: '事件',
+    slot: 'todoshijian',
+    align: 'center',
+    minWidth: '120px',
+  },
+  {
+    prop: 'tododidian',
+    label: '进出地点',
+    align: 'center',
+    minWidth: '120px',
+  },
+  {
+    prop: 'todojinchushijian',
+    label: '进门时间',
+    align: 'center',
+    minWidth: '120px',
+  },
+];

+ 40 - 0
src/views/security-confidentiality/person-management/inner-person/constants.ts

@@ -0,0 +1,40 @@
+export const INNER_PERSON_TABLE_SEARCH_OPTIONS: SelectOption[] = [
+  {
+    label: '姓名',
+    value: 'todoxinming',
+    disabled: false,
+  },
+  {
+    label: '卡号',
+    value: 'todokahao',
+    disabled: false,
+  },
+  {
+    label: '进出地点',
+    value: 'tododidian',
+    disabled: false,
+  },
+];
+
+export enum OCCURRENCE_TYPE {
+  ENTER = 1,
+  EXIT = 2,
+}
+
+export const OCCURRENCE_TYPE_LABEL = {
+  [OCCURRENCE_TYPE.ENTER]: '进门',
+  [OCCURRENCE_TYPE.EXIT]: '出门',
+};
+
+export const OCCURRENCE_TYPE_OPTIONS: SelectOption[] = [
+  {
+    label: OCCURRENCE_TYPE_LABEL[OCCURRENCE_TYPE.ENTER],
+    value: OCCURRENCE_TYPE.ENTER,
+    disabled: false,
+  },
+  {
+    label: OCCURRENCE_TYPE_LABEL[OCCURRENCE_TYPE.EXIT],
+    value: OCCURRENCE_TYPE.EXIT,
+    disabled: false,
+  },
+];

+ 18 - 0
src/views/security-confidentiality/person-management/inner-person/types.ts

@@ -0,0 +1,18 @@
+export interface InnerPersonTableQuery {
+  todoxinming?: string | null;
+  todokahao?: string | null;
+  todobumen?: string | null;
+  todoshijian?: number | null;
+  tododidian?: string | null;
+  startTime?: string | null;
+  endTime?: string | null;
+}
+
+export interface InnerPersonTableData {
+  todoxinming: string;
+  todokahao: string;
+  todobumen: string;
+  todoshijian: number;
+  tododidian: string;
+  todojinchushijian: string;
+}

+ 44 - 3
src/views/security-confidentiality/person-management/outer-person/OuterPerson.vue

@@ -1,7 +1,48 @@
 <template>
-  <div> overview </div>
+  <div class="safety-platform-container">
+    <header class="safety-platform-container__header">
+      <div class="breadcrumb-title"> 外部人员管理 </div>
+      <el-tabs v-model="activeName">
+        <el-tab-pane v-for="item in SUBPAGES" :key="item.value" :label="item.label" :name="item.value" />
+      </el-tabs>
+    </header>
+    <main class="safety-platform-container__main">
+      <component :is="dynamicComponent" ref="dynamicComponentRef" />
+    </main>
+  </div>
 </template>
 
-<script setup lang="ts"></script>
+<script setup lang="ts">
+  import { ref, computed, defineAsyncComponent, onUnmounted } from 'vue';
+  import { SUBPAGES } from './constants';
 
-<style scoped></style>
+  const activeName = ref(sessionStorage.getItem('person-management-active') || SUBPAGES[0].value);
+
+  const dynamicComponent = computed(() => {
+    switch (activeName.value) {
+      case SUBPAGES[0].value:
+        return defineAsyncComponent(() => import('./components/BreakInto.vue'));
+      case SUBPAGES[1].value:
+        return defineAsyncComponent(() => import('./components/Visitor.vue'));
+    }
+  });
+
+  onUnmounted(() => {
+    sessionStorage.setItem('person-management-active', activeName.value);
+  });
+</script>
+
+<style scoped lang="scss">
+  @use '@/styles/page-details-layout.scss' as *;
+  @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
+  .safety-platform-container__header {
+    padding-bottom: 0 !important;
+  }
+  :deep(.el-tabs__header) {
+    margin: 0;
+  }
+  :deep(.el-tabs__item) {
+    font-size: 14px !important;
+  }
+</style>

+ 162 - 0
src/views/security-confidentiality/person-management/outer-person/components/BreakInto.vue

@@ -0,0 +1,162 @@
+<template>
+  <div class="search-table-container">
+    <header>
+      <div class="table-search">
+        <section class="select-box">
+          <div class="select-box--item">
+            <span>地点:</span>
+            <el-input v-model="searchData.todoshijian" placeholder="请输入地点" clearable> </el-input>
+          </div>
+          <div>
+            <span>时间:</span>
+            <el-date-picker
+              v-model="searchTime"
+              type="datetimerange"
+              range-separator="至"
+              start-placeholder="开始时间"
+              end-placeholder="结束时间"
+            />
+          </div>
+        </section>
+        <section class="search-btn">
+          <el-button type="primary" @click="handleSearch">查询</el-button>
+          <el-button @click="handleReset">重置</el-button>
+          <el-button @click="handleDownload">导出</el-button>
+        </section>
+      </div>
+    </header>
+    <!-- 表格 -->
+    <BasicTable
+      ref="basicTableRef"
+      :tableData="tableData"
+      :tableConfig="tableConfig"
+      @update:pageSize="handleSizeChange"
+      @update:pageNumber="handleCurrentChange"
+    >
+    </BasicTable>
+  </div>
+</template>
+
+<script setup lang="ts">
+  import BasicTable from '@/components/BasicTable.vue';
+  import useTableConfig from '@/hooks/useTableConfigHook';
+  import { onMounted, reactive, ref } from 'vue';
+  import { QueryPageRequest, QueryPageResponse } from '@/types/basic-query';
+  import { BreakTableData, BreakTableQuery } from '../types';
+  import { OUTER_PERSON_BREAK_TABEL_COLUMNS, TABLE_OPTIONS } from '../configs/table';
+
+  const searchData = reactive<any>({});
+  const searchTime = ref<string[]>([]);
+
+  const { tableConfig, pagination } = useTableConfig(OUTER_PERSON_BREAK_TABEL_COLUMNS, TABLE_OPTIONS);
+
+  const tableData = ref<BreakTableData[]>([]);
+
+  const tableQuery = reactive<QueryPageRequest<BreakTableQuery>>({
+    pageNumber: pagination.pageNumber,
+    pageSize: pagination.pageSize,
+    queryParam: {},
+  });
+  function getQuery() {
+    const query = {
+      ...searchData,
+      startTime: searchTime.value[0],
+      endTime: searchTime.value[1],
+    };
+  }
+  async function getTableData() {
+    tableConfig.loading = true;
+    const res = await new Promise<QueryPageResponse<BreakTableData>>((resolve) => {
+      resolve({
+        totalRow: 1,
+        records: [
+          {
+            todoshijian: 1,
+            todozhuapaididian: 'aaa',
+            todozhuapaishijian: '2023-01-01 00:00:00',
+            todozhuapaitupian: '',
+            todolaiyuan: 1,
+          },
+        ],
+      });
+    });
+    tableData.value = res.records;
+    pagination.total = res.totalRow;
+    tableConfig.loading = false;
+  }
+
+  const handleSizeChange = (value: number) => {
+    pagination.pageSize = value;
+    tableQuery.pageSize = value;
+    getTableData();
+  };
+  const handleCurrentChange = (value: number) => {
+    pagination.pageNumber = value;
+    tableQuery.pageNumber = value;
+    getTableData();
+  };
+
+  function handleSearch() {
+    getQuery();
+    getTableData();
+  }
+
+  function handleReset() {
+    for (const key in searchData) {
+      if (searchData.hasOwnProperty(key)) {
+        searchData[key] = undefined;
+      }
+    }
+    handleSearch();
+  }
+
+  async function handleDownload() {
+    getQuery();
+    // try {
+    //   const res = await exportActViolation(tableQuery.queryParam);
+    //   if (res.size === 0) return;
+    //   const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
+    //   const url = window.URL.createObjectURL(blob);
+    //   downloadFile(url, '违规行为记录.xlsx');
+    // } catch (e) {
+    //   ElMessage.error('下载失败');
+    //   console.log(e);
+    // }
+  }
+  onMounted(() => {
+    getTableData();
+  });
+</script>
+
+<style scoped lang="scss">
+  @use '@/styles/page-details-layout.scss' as *;
+  @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
+
+  .table-search {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    width: 100%;
+  }
+  .select-box {
+    display: flex;
+    align-items: center;
+    flex-wrap: wrap;
+    gap: 32px;
+    &--item {
+      @include flex-center;
+      white-space: nowrap;
+    }
+    span {
+      color: rgba(0, 0, 0, 0.85);
+      font-size: 14px;
+    }
+    .el-select {
+      width: 200px;
+    }
+  }
+  .search-btn {
+    display: flex;
+  }
+</style>

+ 168 - 0
src/views/security-confidentiality/person-management/outer-person/components/Visitor.vue

@@ -0,0 +1,168 @@
+<template>
+  <div class="search-table-container">
+    <header>
+      <div class="table-search">
+        <section class="select-box">
+          <div class="select-box--item">
+            <span>地点:</span>
+            <el-input v-model="searchData.todoshijian" placeholder="请输入地点" clearable> </el-input>
+          </div>
+          <div>
+            <span>时间:</span>
+            <el-date-picker
+              v-model="searchTime"
+              type="datetimerange"
+              range-separator="至"
+              start-placeholder="开始时间"
+              end-placeholder="结束时间"
+            />
+          </div>
+        </section>
+        <section class="search-btn">
+          <el-button type="primary" @click="handleSearch">查询</el-button>
+          <el-button @click="handleReset">重置</el-button>
+          <el-button @click="handleDownload">导出</el-button>
+        </section>
+      </div>
+    </header>
+    <!-- 表格 -->
+    <BasicTable
+      ref="basicTableRef"
+      :tableData="tableData"
+      :tableConfig="tableConfig"
+      @update:pageSize="handleSizeChange"
+      @update:pageNumber="handleCurrentChange"
+    >
+    </BasicTable>
+  </div>
+</template>
+
+<script setup lang="ts">
+  import BasicTable from '@/components/BasicTable.vue';
+  import useTableConfig from '@/hooks/useTableConfigHook';
+  import { onMounted, reactive, ref } from 'vue';
+  import { QueryPageRequest, QueryPageResponse } from '@/types/basic-query';
+  import { VisitorTableData, VisitorTableQuery } from '../types';
+  import { OUTER_PERSON_VISITOR_TABEL_COLUMNS, TABLE_OPTIONS } from '../configs/table';
+
+  const searchData = reactive<any>({});
+  const searchTime = ref<string[]>([]);
+
+  const { tableConfig, pagination } = useTableConfig(OUTER_PERSON_VISITOR_TABEL_COLUMNS, TABLE_OPTIONS);
+
+  const tableData = ref<VisitorTableData[]>([]);
+
+  const tableQuery = reactive<QueryPageRequest<VisitorTableQuery>>({
+    pageNumber: pagination.pageNumber,
+    pageSize: pagination.pageSize,
+    queryParam: {},
+  });
+  function getQuery() {
+    const query = {
+      ...searchData,
+      startTime: searchTime.value[0],
+      endTime: searchTime.value[1],
+    };
+  }
+  async function getTableData() {
+    tableConfig.loading = true;
+    const res = await new Promise<QueryPageResponse<VisitorTableData>>((resolve) => {
+      resolve({
+        totalRow: 1,
+        records: [
+          {
+            todoxinming: 'string',
+            todoshenfenxinxi: 'string',
+            todoshoujihaoma: 'string',
+            todoshifouwailian: 0,
+            tododanwei: 'string',
+            todolaifangshiyou: 'string',
+            todobeifangren: 'string',
+            todobeifangrengonghao: 'string',
+            todofangwenzhuangtai: 0,
+            tododaofangshijian: 'string',
+            todolikaishijian: 'string',
+          },
+        ],
+      });
+    });
+    tableData.value = res.records;
+    pagination.total = res.totalRow;
+    tableConfig.loading = false;
+  }
+
+  const handleSizeChange = (value: number) => {
+    pagination.pageSize = value;
+    tableQuery.pageSize = value;
+    getTableData();
+  };
+  const handleCurrentChange = (value: number) => {
+    pagination.pageNumber = value;
+    tableQuery.pageNumber = value;
+    getTableData();
+  };
+
+  function handleSearch() {
+    getQuery();
+    getTableData();
+  }
+
+  function handleReset() {
+    for (const key in searchData) {
+      if (searchData.hasOwnProperty(key)) {
+        searchData[key] = undefined;
+      }
+    }
+    handleSearch();
+  }
+
+  async function handleDownload() {
+    getQuery();
+    // try {
+    //   const res = await exportActViolation(tableQuery.queryParam);
+    //   if (res.size === 0) return;
+    //   const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
+    //   const url = window.URL.createObjectURL(blob);
+    //   downloadFile(url, '违规行为记录.xlsx');
+    // } catch (e) {
+    //   ElMessage.error('下载失败');
+    //   console.log(e);
+    // }
+  }
+  onMounted(() => {
+    getTableData();
+  });
+</script>
+
+<style scoped lang="scss">
+  //   @use '@/styles/page-details-layout.scss' as *;
+  //   @use '@/styles/page-main-layout.scss' as *;
+  //   @use '@/styles/basic-table-action.scss' as *;
+
+  .table-search {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    width: 100%;
+  }
+  .select-box {
+    display: flex;
+    align-items: center;
+    flex-wrap: wrap;
+    gap: 32px;
+    &--item {
+      @include flex-center;
+      white-space: nowrap;
+    }
+    span {
+      color: rgba(0, 0, 0, 0.85);
+      font-size: 14px;
+    }
+    .el-select {
+      width: 200px;
+    }
+  }
+  .search-btn {
+    display: flex;
+  }
+</style>

+ 117 - 0
src/views/security-confidentiality/person-management/outer-person/configs/table.ts

@@ -0,0 +1,117 @@
+import type { TableColumnProps } from '@/types/basic-table';
+
+// 基础表格样式配置
+export const TABLE_OPTIONS = {
+  emptyText: '暂无数据',
+  loading: true,
+  maxHeight: 'calc(70vh - 150px)',
+};
+
+export const OUTER_PERSON_BREAK_TABEL_COLUMNS: TableColumnProps[] = [
+  {
+    label: '序号',
+    align: 'center',
+    width: '80px',
+    type: 'index',
+  },
+  {
+    prop: 'todoshijian',
+    label: '事件',
+    slot: 'todoshijian',
+    align: 'center',
+    minWidth: '120px',
+  },
+  {
+    prop: 'todozhuapaididian',
+    label: '抓拍地点',
+    align: 'center',
+    minWidth: '120px',
+  },
+  {
+    prop: 'todozhuapaishijian',
+    label: '抓拍时间',
+    align: 'center',
+    minWidth: '120px',
+  },
+  {
+    prop: 'todozhuapaitupian',
+    label: '抓拍图片',
+    slot: 'todozhuapaitupian',
+    align: 'center',
+    minWidth: '120px',
+  },
+  {
+    prop: 'todolaiyuan',
+    label: '来源',
+    slot: 'todolaiyuan',
+    align: 'center',
+    minWidth: '120px',
+  },
+];
+
+export const OUTER_PERSON_VISITOR_TABEL_COLUMNS: TableColumnProps[] = [
+  {
+    label: '姓名',
+    align: 'center',
+    minWidth: '120px',
+    prop: 'todoxinming',
+  },
+  {
+    label: '身份信息',
+    align: 'center',
+    minWidth: '240px',
+    prop: 'todoshenfenxinxi',
+  },
+  {
+    label: '手机号码',
+    align: 'center',
+    minWidth: '240px',
+    prop: 'todoshoujihaoma',
+  },
+  {
+    label: '是否外链',
+    align: 'center',
+    minWidth: '120px',
+    prop: 'todoshifouwailian',
+    slot: 'todoshifouwailian',
+  },
+  {
+    label: '单位',
+    align: 'center',
+    minWidth: '360px',
+    prop: 'tododanwei',
+  },
+  {
+    label: '来访事由',
+    align: 'center',
+    minWidth: '120px',
+    prop: 'todolaifangshiyou',
+    slot: 'todolaifangshiyou',
+  },
+  {
+    label: '被访人',
+    align: 'center',
+    minWidth: '120px',
+    prop: 'todobeifangren',
+  },
+  {
+    label: '访问状态',
+    align: 'center',
+    minWidth: '120px',
+    prop: 'todofangwenzhuangtai',
+    slot: 'todofangwenzhuangtai',
+  },
+
+  {
+    label: '到访时间',
+    align: 'center',
+    minWidth: '360px',
+    prop: 'tododaofaoshijian',
+  },
+  {
+    label: '离开时间',
+    align: 'center',
+    minWidth: '120px',
+    prop: 'todolikaishijian',
+  },
+];

+ 43 - 0
src/views/security-confidentiality/person-management/outer-person/constants.ts

@@ -0,0 +1,43 @@
+export const SUBPAGES = [
+  {
+    label: '闯入记录',
+    value: 'break',
+  },
+  {
+    label: '访客记录',
+    value: 'enter',
+  },
+];
+
+export const VISITOR_TABLE_SEARCH_OPTIONS: SelectOption[] = [
+  {
+    label: '姓名',
+    value: 'todoxinming',
+    disabled: false,
+  },
+  {
+    label: '身份信息',
+    value: 'todoshenfenxinxi',
+    disabled: false,
+  },
+  {
+    label: '手机号码',
+    value: 'todoshoujihaoma',
+    disabled: false,
+  },
+  {
+    label: '单位',
+    value: 'tododanwei',
+    disabled: false,
+  },
+  {
+    label: '来访事由',
+    value: 'todolaifangshiyou',
+    disabled: false,
+  },
+  {
+    label: '被访问姓名',
+    value: 'todobeifangren',
+    disabled: false,
+  },
+];

+ 38 - 0
src/views/security-confidentiality/person-management/outer-person/types.ts

@@ -0,0 +1,38 @@
+export interface BreakTableQuery {
+  todozhuapaididian?: string | null;
+  startTime?: string | null;
+  endTime?: string | null;
+}
+
+export interface BreakTableData {
+  todoshijian: number;
+  todozhuapaididian: string;
+  todozhuapaishijian: string;
+  todozhuapaitupian: string;
+  todolaiyuan: number;
+}
+
+export interface VisitorTableQuery {
+  todoxinming?: string | null;
+  todoshenfenxinxi?: string | null;
+  todoshoujihaoma?: string | null;
+  tododanwei?: string | null;
+  todolaifangshiyou?: string | null;
+  todobeifangren?: string | null;
+  startTime?: string | null;
+  endTime?: string | null;
+}
+
+export interface VisitorTableData {
+  todoxinming: string;
+  todoshenfenxinxi: string;
+  todoshoujihaoma: string;
+  todoshifouwailian: number;
+  tododanwei: string;
+  todolaifangshiyou: string;
+  todobeifangren: string;
+  todobeifangrengonghao: string;
+  todofangwenzhuangtai: number;
+  tododaofangshijian: string;
+  todolikaishijian: string;
+}