From a793a95da019467ae2ae1af3345b9b1cfec7f824 Mon Sep 17 00:00:00 2001 From: wangyilin <1454641981@qq.com> Date: Fri, 25 Apr 2025 11:27:57 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AF=BC=E8=88=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 2 +- package-lock.json | 6 + package.json | 1 + src/components/form/FormProMax.vue | 213 +++++++++++++++++++++++++ src/components/table/TableProMax.vue | 223 +++++++++++++++++++++++++++ src/components/tabsPane/index.vue | 2 +- src/global.d.ts | 83 ++++++++++ src/hooks/useTableProMax.ts | 134 ++++++++++++++++ src/types/components/form/index.ts | 75 +++++++++ src/types/components/table/index.ts | 55 +++++++ src/types/hooks/useTableProMax.ts | 26 ++++ src/views/home/index.vue | 9 +- src/views/product/dishes/index.vue | 167 +++++++++++++++++++- src/views/product/food/index.vue | 166 +++++++++++++++++++- yarn.lock | 5 + 15 files changed, 1148 insertions(+), 19 deletions(-) create mode 100644 src/components/form/FormProMax.vue create mode 100644 src/components/table/TableProMax.vue create mode 100644 src/hooks/useTableProMax.ts create mode 100644 src/types/components/form/index.ts create mode 100644 src/types/components/table/index.ts create mode 100644 src/types/hooks/useTableProMax.ts diff --git a/index.html b/index.html index 718afa1..183f5d3 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - 管理后台 + 食堂系统管理
diff --git a/package-lock.json b/package-lock.json index 3e3ea43..e0e1c60 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "pinia-plugin-persistedstate": "^3.2.0", "terser": "^5.19.2", "vue": "^3.3.4", + "vue-component-type-helpers": "^2.1.2", "vue-router": "4" }, "devDependencies": { @@ -2692,6 +2693,11 @@ "@vue/shared": "3.3.4" } }, + "node_modules/vue-component-type-helpers": { + "version": "2.2.10", + "resolved": "https://registry.npmmirror.com/vue-component-type-helpers/-/vue-component-type-helpers-2.2.10.tgz", + "integrity": "sha512-iDUO7uQK+Sab2tYuiP9D1oLujCWlhHELHMgV/cB13cuGbG4qwkLHvtfWb6FzvxrIOPDnU0oHsz2MlQjhYDeaHA==" + }, "node_modules/vue-router": { "version": "4.2.4", "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.2.4.tgz", diff --git a/package.json b/package.json index b5ff0a3..8ed0de6 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "nprogress": "^0.2.0", "pinia": "^2.1.6", "pinia-plugin-persistedstate": "^3.2.0", + "vue-component-type-helpers": "^2.1.2", "terser": "^5.19.2", "vue": "^3.3.4", "vue-router": "4" diff --git a/src/components/form/FormProMax.vue b/src/components/form/FormProMax.vue new file mode 100644 index 0000000..c4fb2c3 --- /dev/null +++ b/src/components/form/FormProMax.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/src/components/table/TableProMax.vue b/src/components/table/TableProMax.vue new file mode 100644 index 0000000..75e0e94 --- /dev/null +++ b/src/components/table/TableProMax.vue @@ -0,0 +1,223 @@ + + + + + diff --git a/src/components/tabsPane/index.vue b/src/components/tabsPane/index.vue index 71ec563..f6affce 100644 --- a/src/components/tabsPane/index.vue +++ b/src/components/tabsPane/index.vue @@ -55,7 +55,7 @@ const addTab = (route) => { if (!exists) { tabsList.value.push({ key: route.path, - title: route.name || "新tab", + title: route.name || "", closable: route.path !== "/home", //首页不能关闭 }); } diff --git a/src/global.d.ts b/src/global.d.ts index 59e048d..39a9a0a 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -46,3 +46,86 @@ interface RouterVo { /** 路由元数据 **/ meta: RouterMetaVo; } + +declare const __APP_ENV: ImportMetaEnv; + +/** + * 全局返回 + */ +interface JsonResult { + code: number; + message: string; + data?: T; +} + +/** + * 选择 + */ +class SelectNodeVo> { + value: T; + label: string; + options?: SelectNodeVo[] + orderIndex?: number; + disabled?: boolean; + extData?: E +} + +/** + * 树 + */ +class TreeNodeVo> { + value: T; + parentValue: T; + label: string; + orderIndex?: number; + children?: TreeNodeVo[] + extData?: E; +} + +/** + * 栅格布局 + */ +declare interface Grid { + //栅格占据的列数 + span?: number; + //栅格左侧的间隔格数 + offset?: number; + //栅格向右移动格数 + push?: number; + //栅格向左移动格数 + pull?: number; + //<768px 响应式栅格数或者栅格属性对象 + xs?: number; + //≥768px 响应式栅格数或者栅格属性对象 + sm?: number; + //≥992px 响应式栅格数或者栅格属性对象 + md?: number; + //≥1200px 响应式栅格数或者栅格属性对象 + lg?: number; + //≥1920px 响应式栅格数或者栅格属性对象 + xl?: number; +} + +interface BaseEnum { + value: T; + label: string +} + +interface TypeEnum { + value: string; + label: string +} +interface dataStatus { + account: string; + password: string; + remark: string; + checkStatus: { + extData: { + color: string; + }; + label: string; + value: number; + }; +} + + diff --git a/src/hooks/useTableProMax.ts b/src/hooks/useTableProMax.ts new file mode 100644 index 0000000..48fbeb0 --- /dev/null +++ b/src/hooks/useTableProMax.ts @@ -0,0 +1,134 @@ +import {ref, Ref} from "vue"; +import {Page, PageParams, PageResult} from "@/types/hooks/useTableProMax"; +import {FormInstance} from "ant-design-vue"; +import {BaseTableRowRecord, RequestApiType} from "@/types/components/table"; + +/** + * + * @param api 查询方法 + * @param searchFormRef 表单校验 + * @param searchParams 查询的参数 + * @param isPageTable 是否分页 + * @param dataCallBack 查询到数据后的回调 + * @param requestError 查询出错回调 + */ +export default | 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/src/types/components/form/index.ts b/src/types/components/form/index.ts new file mode 100644 index 0000000..f2ad150 --- /dev/null +++ b/src/types/components/form/index.ts @@ -0,0 +1,75 @@ +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' + | 'administrativeDivisionsTree'; + +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> + | FormProMaxItemProps<'administrativeDivisionsTree', ComponentProps>> +} + +export interface FormProMaxProps extends FormProps { + grid?: Grid + gutter?: number; + formItemOptions?: FormProMaxItemOptions | Ref> | UnwrapRef> +} diff --git a/src/types/components/table/index.ts b/src/types/components/table/index.ts new file mode 100644 index 0000000..9bdf17f --- /dev/null +++ b/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"; + + +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/src/types/hooks/useTableProMax.ts b/src/types/hooks/useTableProMax.ts new file mode 100644 index 0000000..3989828 --- /dev/null +++ b/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/src/views/home/index.vue b/src/views/home/index.vue index a214462..fdf7424 100644 --- a/src/views/home/index.vue +++ b/src/views/home/index.vue @@ -63,7 +63,7 @@ + \ No newline at end of file + .foodItem { + width: 100%; + height: calc(100vh - 100px); + overflow: hidden; + margin-top: 20px; + } +} + diff --git a/src/views/product/food/index.vue b/src/views/product/food/index.vue index 3dcbc65..ae97792 100644 --- a/src/views/product/food/index.vue +++ b/src/views/product/food/index.vue @@ -1,22 +1,174 @@ - +