| PageParams>(api: RequestApiType,
+ searchFormRef: Ref,
+ searchParams: Ref,
+ isPageTable: boolean = true,
+ dataCallBack?: (data: T[]) => T[],
+ requestError?: (errorMsg: any) => void) => {
+
+ const dataSource = ref([]) as Ref;
+ const loading = ref(false);
+ const pageParams = ref({
+ current: 1,
+ size: 10,
+ total: 0
+ })
+
+ /**
+ * 获取表格数据
+ */
+ const requestGetTableData = async (isInit: boolean = false) => {
+ try {
+ //校验表单
+ !isInit && await searchFormRef.value?.validate();
+ //组装参数
+ let totalSearchParams;
+ if (isPageTable) {
+ totalSearchParams = {
+ params: searchParams.value,
+ page: {
+ current: pageParams.value.current,
+ size: pageParams.value.size
+ }
+ } as PageParams;
+ } else {
+ totalSearchParams = searchParams.value
+ }
+
+ loading.value = true;
+
+ const resp = await api(totalSearchParams as P);
+ let tableData: T[];
+
+ if (isPageTable) {
+ const { current, records, size, total } = resp.data as PageResult;
+ isPageTable && updatePageParams({
+ current: parseInt(current),
+ size: parseInt(size),
+ total: parseInt(total)
+ });
+ tableData = records;
+ } else {
+ tableData = resp.data as T[]
+ }
+ dataCallBack && (tableData = dataCallBack(tableData));
+ dataSource.value = tableData;
+ } catch (error) {
+ requestError && requestError(error);
+ } finally {
+ loading.value = false;
+ }
+ }
+
+ /**
+ * 更新分页信息
+ */
+ const updatePageParams = (ps: Page) => Object.assign(pageParams.value, ps)
+
+ /**
+ * 重置表格状态 包括 dataSource loading pageParams
+ */
+ const resetState = () => {
+ dataSource.value = [];
+ loading.value = false;
+ pageParams.value = {
+ current: 1,
+ size: 10,
+ total: 0
+ }
+ }
+
+ /**
+ * 表格数据查询 与 requestGetTableData 区别是会将页面重置为1
+ * 如果只做刷新数据请用 requestGetTableData
+ */
+ const search = async () => {
+ pageParams.value.current = 1;
+ await requestGetTableData();
+ };
+
+ /**
+ * @description 每页条数改变
+ * @param _
+ * @param {Number} size 页显示数量
+ */
+ const handleSizeChange = async (_: number, size: number) => {
+ pageParams.value.current = 1;
+ pageParams.value.size = size;
+ await requestGetTableData();
+ };
+
+ /**
+ * @description 当前页改变
+ * @param current 当前页
+ */
+ const handleCurrentChange = async (current: number) => {
+ pageParams.value.current = current;
+ await requestGetTableData();
+ };
+
+ return {
+ dataSource,
+ loading,
+ pageParams,
+ requestGetTableData,
+ search,
+ handleSizeChange,
+ handleCurrentChange,
+ resetState
+ };
+
+}
diff --git a/policeManagement/src/types/components/form/index.ts b/policeManagement/src/types/components/form/index.ts
new file mode 100644
index 0000000..32da75d
--- /dev/null
+++ b/policeManagement/src/types/components/form/index.ts
@@ -0,0 +1,73 @@
+import {
+ FormProps,
+ RangePicker,
+ Input,
+ InputNumber,
+ Textarea,
+ InputPassword,
+ RadioGroup,
+ Select,
+ TreeSelect,
+ Cascader,
+ CheckboxGroup,
+ DatePicker,
+ FormItem, TimeRangePicker, TimePicker,
+} from "ant-design-vue";
+import { Ref, UnwrapRef, VNode } from "vue";
+import { ComponentProps } from "vue-component-type-helpers";
+
+type FormProMaxItemType =
+ | 'custom'
+ | 'input'
+ | 'inputPassword'
+ | 'inputNumber'
+ | 'inputTextArea'
+ | 'radioGroup'
+ | 'select'
+ | 'selectIcon'
+ | 'selectUser'
+ | 'treeSelect'
+ | 'cascader'
+ | 'checkboxGroup'
+ | 'datePicker'
+ | 'rangePicker'
+ | 'timeRangePicker'
+ | 'timePicker';
+
+interface FormProMaxItemCommonProps extends ComponentProps {
+ label?: string,
+ grid?: Grid,
+ placeholder?: string,
+ remarkRender?: () => VNode | string,
+ customRender?: () => VNode;
+ options?: (SelectNodeVo | TreeNodeVo)[] | Ref<(SelectNodeVo | TreeNodeVo)[]>
+}
+
+export interface FormProMaxItemProps extends FormProMaxItemCommonProps {
+ type: T
+ componentsProps?: C
+}
+
+export type FormProMaxItemOptions = {
+ [key in keyof T | string]:
+ FormProMaxItemProps<'custom', ComponentProps>>
+ | FormProMaxItemProps<'input', ComponentProps>
+ | FormProMaxItemProps<'inputPassword', ComponentProps>
+ | FormProMaxItemProps<'inputNumber', ComponentProps>
+ | FormProMaxItemProps<'inputTextArea', ComponentProps>
+ | FormProMaxItemProps<'radioGroup', ComponentProps>
+ | FormProMaxItemProps<'select', ComponentProps>
+ | FormProMaxItemProps<'treeSelect', ComponentProps>
+ | FormProMaxItemProps<'cascader', ComponentProps>
+ | FormProMaxItemProps<'checkboxGroup', ComponentProps>
+ | FormProMaxItemProps<'datePicker', ComponentProps>
+ | FormProMaxItemProps<'rangePicker', ComponentProps>
+ | FormProMaxItemProps<'timeRangePicker', ComponentProps>
+ | FormProMaxItemProps<'timePicker', ComponentProps>
+}
+
+export interface FormProMaxProps extends FormProps {
+ grid?: Grid
+ gutter?: number;
+ formItemOptions?: FormProMaxItemOptions | Ref> | UnwrapRef>
+}
diff --git a/policeManagement/src/types/components/iconfont/IconFont.ts b/policeManagement/src/types/components/iconfont/IconFont.ts
new file mode 100644
index 0000000..9b3dd6e
--- /dev/null
+++ b/policeManagement/src/types/components/iconfont/IconFont.ts
@@ -0,0 +1,5 @@
+export interface IconFontProps {
+ fontClass?: string,
+ size?: number,
+ type?: 'class' | 'svg'
+}
\ No newline at end of file
diff --git a/policeManagement/src/types/components/table/index.ts b/policeManagement/src/types/components/table/index.ts
new file mode 100644
index 0000000..cffa49f
--- /dev/null
+++ b/policeManagement/src/types/components/table/index.ts
@@ -0,0 +1,55 @@
+import { PaginationProps, Table, TableProps } from "ant-design-vue";
+import { TableRowSelection } from "ant-design-vue/lib/table/interface";
+import { Ref, UnwrapRef } from "vue";
+import { ColumnType } from "ant-design-vue/es/table/interface";
+import { ComponentSlots } from "vue-component-type-helpers";
+import { FormProMaxItemOptions, FormProMaxProps } from "@/types/components/form";
+import { PageParams, PageResult } from "@/types/hooks/useTableProMax.ts";
+
+
+export type TableProMaxColumnType = Omit, 'dataIndex'> & {
+ dataIndex: keyof T | string | string[] | number | number[];
+}
+
+
+export type TableProMaxProps<
+ T extends BaseTableRowRecord = {},
+ P extends { [key: string]: any } = {}
+> = Partial, "dataSource" | 'pagination' | 'loading' | 'rowKey' | 'columns'>> & {
+ rowKey?: keyof T,
+ columns?: TableProMaxColumnType[],
+ searchFormProps?: Omit, 'formItems'>
+ searchFormOptions?: FormProMaxItemOptions | Ref> | UnwrapRef>,
+ defaultSearchParams?: { [key in keyof P | string]: any };
+ requestAuto?: boolean,
+ requestApi: RequestApiType,
+ requestError?: (errorMsg: any) => void,
+ dataCallback?: (data: T[]) => T[],
+ isPagination?: boolean,
+ paginationProps?: TableProMaxPaginationProps,
+ isSelection?: boolean,
+ selectionProps?: TableProMaxRowSelect,
+ isPrinter?: boolean,
+ needIndex?: boolean
+}
+
+export type TableProMaxSlots = ComponentSlots & {
+ tableHeader: (scope: { selectKeys: string[], selectRows: T[] }) => any,
+ tableHeaderRight: (scope: { selectKeys: string[], selectRows: T[] }) => any,
+}
+
+export type RequestApiType = (params: P | PageParams) => Promise>>;
+
+export type TableProMaxPaginationProps = Partial>;
+
+export type TableProMaxRowSelect = TableRowSelection;
+
+export interface BaseTableRowRecord {
+ snowFlakeId?: string;
+ createUserName?: string;
+ createTime?: Date | string;
+ updateUserName?: string;
+ updateTime?: Date | string
+}
diff --git a/policeManagement/src/types/config/index.ts b/policeManagement/src/types/config/index.ts
new file mode 100644
index 0000000..a2dab60
--- /dev/null
+++ b/policeManagement/src/types/config/index.ts
@@ -0,0 +1,13 @@
+import { RouteComponent } from "vue-router";
+
+export interface SystemMenu {
+ type: 'dir' | 'menu';
+ title: string;
+ path: string;
+ name: string;
+ icon?: string;
+
+ component?: RouteComponent;
+ children?: SystemMenu[];
+}
+
diff --git a/policeManagement/src/types/hooks/useTableProMax.ts b/policeManagement/src/types/hooks/useTableProMax.ts
new file mode 100644
index 0000000..3989828
--- /dev/null
+++ b/policeManagement/src/types/hooks/useTableProMax.ts
@@ -0,0 +1,26 @@
+/**
+ * 分页对象
+ */
+export interface Page {
+ current: number,
+ size: number,
+ total: number
+}
+
+/**
+ * 分页参数
+ */
+export interface PageParams = {}> {
+ params: T & { [key: string]: any },
+ page: Omit
+}
+
+/**
+ * 分页结果
+ */
+export interface PageResult {
+ current: string,
+ records: T[],
+ size: string,
+ total: string
+}
\ No newline at end of file
diff --git a/policeManagement/src/utils/index.ts b/policeManagement/src/utils/index.ts
new file mode 100644
index 0000000..257081a
--- /dev/null
+++ b/policeManagement/src/utils/index.ts
@@ -0,0 +1,17 @@
+import {ceil, divide} from "lodash-es";
+
+/**
+ * 将文件大小转为字符串格式
+ * @param fileSizeInBytes
+ */
+export const convertFileSizeToStr = (fileSizeInBytes: number): string => {
+ if (fileSizeInBytes < 1024) {
+ return fileSizeInBytes + "B";
+ } else if (fileSizeInBytes < 1024 * 1024) {
+ return (ceil(divide(fileSizeInBytes, 1024), 2)) + "KB";
+ } else if (fileSizeInBytes < 1024 * 1024 * 1024) {
+ return (ceil(divide(fileSizeInBytes, (1024 * 1024)), 2)) + "MB";
+ } else {
+ return (ceil(divide(fileSizeInBytes, (1024 * 1024 * 1024)), 2)) + "GB";
+ }
+}
diff --git a/policeManagement/src/utils/minioUtil.ts b/policeManagement/src/utils/minioUtil.ts
new file mode 100644
index 0000000..34c404d
--- /dev/null
+++ b/policeManagement/src/utils/minioUtil.ts
@@ -0,0 +1,26 @@
+import api from "@/axios";
+import dayjs from "dayjs";
+import { uuid } from "vue-uuid";
+
+/**
+ * 生成一个简单的对象文件地址
+ * @param fileName 原始文件名
+ * @param parentDir 上级目录
+ */
+export const generateSimpleObjectName = (fileName: string, parentDir?: String): string => {
+ let objectName = parentDir + dayjs().format('/YYYY/MM/DD/') + uuid.v4().replace(/-/g, '');
+ if (fileName && fileName.length > 0) {
+ objectName += fileName.substring(fileName.lastIndexOf('.'))
+ }
+ return objectName;
+}
+
+/**
+ * 获取生成预签名的 URL
+ */
+export const getResignedObjectUrl = async (bucketName: string, objectName: string): Promise => {
+ return (await api.get('/common/getResignedObjectUrl', {
+ bucketName,
+ objectName
+ })).data as string;
+}