From f7090d3dbc2978f899a557b856a143bbe6506e18 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Mon, 22 May 2023 12:12:11 +0800 Subject: [PATCH] =?UTF-8?q?perf(projects):=20=E4=BC=98=E5=8C=96any?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mock/api/crud/base.ts | 182 +++++++++++++++----------- mock/api/crud/modules/demo.ts | 41 +++--- mock/api/crud/modules/header-group.ts | 53 ++++---- src/plugins/fast-crud/index.tsx | 29 ++-- src/views/crud/demo/api.ts | 12 +- src/views/crud/demo/crud.tsx | 4 +- src/views/crud/header_group/api.ts | 12 +- src/views/crud/header_group/crud.tsx | 22 ++-- 8 files changed, 197 insertions(+), 158 deletions(-) diff --git a/mock/api/crud/base.ts b/mock/api/crud/base.ts index 40bb0055..f9937028 100644 --- a/mock/api/crud/base.ts +++ b/mock/api/crud/base.ts @@ -1,21 +1,34 @@ -// eslint-disable-next-line max-params -function copyList(originList: any, newList: any, options: any, parentId?: number) { +export type ListItem = { + id?: number; + children?: ListItem[]; + [key: string]: any; +}; +export type BaseMockOptions = { name: string; copyTimes?: number; list: ListItem[]; idGenerator: number }; +type CopyListParams = { originList: ListItem[]; newList: ListItem[]; options: BaseMockOptions; parentId?: number }; + +function copyList(props: CopyListParams) { + const { originList, newList, options, parentId } = props; for (const item of originList) { - const newItem = { ...item, parentId }; + const newItem: ListItem = { ...item, parentId }; newItem.id = options.idGenerator; options.idGenerator += 1; newList.push(newItem); if (item.children) { newItem.children = []; - copyList(item.children, newItem.children, options, newItem.id); + copyList({ + originList: item.children, + newList: newItem.children, + options, + parentId: newItem.id + }); } } } -function delById(req: any, list: any[]) { +function delById(req: Service.MockOption, list: any[]) { for (let i = 0; i < list.length; i += 1) { const item = list[i]; - if (item.id === parseInt(req.params.id, 10)) { + if (item.id === parseInt(req.query.id, 10)) { list.splice(i, 1); break; } @@ -25,7 +38,7 @@ function delById(req: any, list: any[]) { } } -function findById(id: number, list: any[]): any { +function findById(id: number, list: ListItem[]): any { for (const item of list) { if (item.id === id) { return item; @@ -39,22 +52,94 @@ function findById(id: number, list: any[]): any { } return null; } + +function matchWithArrayCondition(value: any[], item: ListItem, key: string) { + if (value.length === 0) { + return true; + } + let matched = false; + for (const i of value) { + if (item[key] instanceof Array) { + for (const j of item[key]) { + if (i === j) { + matched = true; + break; + } + } + if (matched) { + break; + } + } else if (item[key] === i || (typeof item[key] === 'string' && item[key].indexOf(`${i}`) >= 0)) { + matched = true; + break; + } + if (matched) { + break; + } + } + return matched; +} + +function matchWithObjectCondition(value: any, item: ListItem, key: string) { + let matched = true; + for (const key2 of Object.keys(value)) { + const v = value[key2]; + if (v && item[key] && v !== item[key][key2]) { + matched = false; + break; + } + } + return matched; +} + +function searchFromList(list: ListItem[], query: any) { + const filter = (item: ListItem) => { + let allFound = true; // 是否所有条件都符合 + for (const key of Object.keys(query)) { + const value = query[key]; + if (value === undefined || value === null || value === '') { + // no nothing + } else if (value instanceof Array) { + // 如果条件中的value是数组的话,只要查到一个就行 + const matched = matchWithArrayCondition(value, item, key); + if (!matched) { + allFound = false; + } + } else if (value instanceof Object) { + // 如果条件中的value是对象的话,需要每个key都匹配 + const matched = matchWithObjectCondition(value, item, key); + if (!matched) { + allFound = false; + } + } else if (item[key] !== value) { + allFound = false; + } + } + return allFound; + }; + return list.filter(filter); +} + export default { - buildMock(options: { name: string; copyTimes: number; list: any[]; idGenerator: number }) { + buildMock(options: BaseMockOptions) { const name = options.name; if (!options.copyTimes) { options.copyTimes = 29; } const list: any[] = []; for (let i = 0; i < options.copyTimes; i += 1) { - copyList(options.list, list, options); + copyList({ + originList: options.list, + newList: list, + options + }); } options.list = list; return [ { path: `/mock/${name}/page`, method: 'post', - handle(req: any) { + handle(req: Service.MockOption) { let data = [...list]; let limit = 20; let offset = 0; @@ -67,74 +152,15 @@ export default { let orderAsc: any; let orderProp: any; if (req && req.body) { - const { page, query, sort } = req.body; + const { page, query } = req.body; if (page.limit) { limit = parseInt(page.limit, 10); } if (page.offset) { offset = parseInt(page.offset, 10); } - orderProp = sort.prop; - orderAsc = sort.asc; - if (Object.keys(query).length > 0) { - // eslint-disable-next-line complexity - data = list.filter(item => { - let allFound = true; // 是否所有条件都符合 - // eslint-disable-next-line guard-for-in - for (const key in query) { - // 判定某一个条件 - const value = query[key]; - if (value === undefined || value === null || value === '') { - // eslint-disable-next-line no-continue - continue; - } - if (value instanceof Array) { - // 如果条件中的value是数组的话,只要查到一个就行 - if (value.length === 0) { - // eslint-disable-next-line no-continue - continue; - } - let found = false; - for (const i of value) { - if (item[key] instanceof Array) { - // eslint-disable-next-line max-depth - for (const j of item[key]) { - // eslint-disable-next-line max-depth - if (i === j) { - found = true; - break; - } - } - // eslint-disable-next-line max-depth - if (found) { - break; - } - } else if (item[key] === i || (typeof item[key] === 'string' && item[key].indexOf(`${i}`) >= 0)) { - found = true; - break; - } - if (found) { - break; - } - } - if (!found) { - allFound = false; - } - } else if (value instanceof Object) { - // eslint-disable-next-line max-depth,guard-for-in - for (const key2 in value) { - const v = value[key2]; - if (v && item[key] && v !== item[key][key2]) { - return false; - } - } - } else if (item[key] !== value) { - allFound = false; - } - } - return allFound; - }); + data = searchFromList(list, query); } } @@ -150,7 +176,7 @@ export default { let ret = 0; if (a[orderProp] > b[orderProp]) { ret = 1; - } else { + } else if (a[orderProp] < b[orderProp]) { ret = -1; } return orderAsc ? ret : -ret; @@ -177,8 +203,8 @@ export default { { path: `/mock/${name}/get`, method: 'get', - handle(req: any) { - let id = req.params.id; + handle(req: Service.MockOption) { + let id = req.query.id; id = parseInt(id, 10); let current = null; for (const item of list) { @@ -197,7 +223,7 @@ export default { { path: `/mock/${name}/add`, method: 'post', - handle(req: any) { + handle(req: Service.MockOption) { req.body.id = options.idGenerator; options.idGenerator += 1; list.unshift(req.body); @@ -211,7 +237,7 @@ export default { { path: `/mock/${name}/update`, method: 'post', - handle(req: any) { + handle(req: Service.MockOption) { const item = findById(req.body.id, list); if (item) { Object.assign(item, req.body); @@ -226,7 +252,7 @@ export default { { path: `/mock/${name}/delete`, method: 'post', - handle(req: any) { + handle(req: Service.MockOption) { delById(req, list); return { code: 200, @@ -238,7 +264,7 @@ export default { { path: `/mock/${name}/batchDelete`, method: 'post', - handle(req: any) { + handle(req: Service.MockOption) { const ids = req.body.ids; for (let i = list.length - 1; i >= 0; i -= 1) { const item = list[i]; diff --git a/mock/api/crud/modules/demo.ts b/mock/api/crud/modules/demo.ts index 662b679e..0f262f04 100644 --- a/mock/api/crud/modules/demo.ts +++ b/mock/api/crud/modules/demo.ts @@ -1,27 +1,28 @@ import type { MethodType, MockMethod } from 'vite-plugin-mock'; +import type { BaseMockOptions } from '../base'; import mockBase from '../base'; +import MockOption = Service.MockOption; -const options: any = { +const options: BaseMockOptions = { name: 'crud/demo', - idGenerator: 0 + idGenerator: 0, + list: [ + { + select: '1', + text: '文本测试', + copyable: '文本可复制', + avatar: 'http://greper.handsfree.work/extends/avatar.jpg', + richtext: '富文本', + datetime: '2023-01-30 11:11:11' + }, + { + select: '2' + }, + { + select: '0' + } + ] }; -const list: any[] = [ - { - select: '1', - text: '文本测试', - copyable: '文本可复制', - avatar: 'http://greper.handsfree.work/extends/avatar.jpg', - richtext: '富文本', - datetime: '2023-01-30 11:11:11' - }, - { - select: '2' - }, - { - select: '0' - } -]; -options.list = list; const mockedApis = mockBase.buildMock(options); const apis: MockMethod[] = [ @@ -46,7 +47,7 @@ for (const mockedApi of mockedApis) { apis.push({ url: mockedApi.path, method: mockedApi.method as MethodType, - response: (request: any) => { + response: (request: MockOption) => { return mockedApi.handle(request); } }); diff --git a/mock/api/crud/modules/header-group.ts b/mock/api/crud/modules/header-group.ts index 15210de8..4c6d63ff 100644 --- a/mock/api/crud/modules/header-group.ts +++ b/mock/api/crud/modules/header-group.ts @@ -1,33 +1,34 @@ import type { MethodType, MockMethod } from 'vite-plugin-mock'; +import type { BaseMockOptions } from '../base'; import mockBase from '../base'; +import MockOption = Service.MockOption; -const options: any = { +const options: BaseMockOptions = { name: 'crud/header-group', - idGenerator: 0 + idGenerator: 0, + list: [ + { + name: '张三', + age: 18, + province: '广东省', + city: '深圳市', + county: '南山区', + street: '粤海街道' + }, + { + name: '李四', + age: 26, + province: '浙江省', + city: '杭州市', + county: '西湖区', + street: '西湖街道' + }, + { + name: '王五', + age: 24 + } + ] }; -const list: any[] = [ - { - name: '张三', - age: 18, - province: '广东省', - city: '深圳市', - county: '南山区', - street: '粤海街道' - }, - { - name: '李四', - age: 26, - province: '浙江省', - city: '杭州市', - county: '西湖区', - street: '西湖街道' - }, - { - name: '王五', - age: 24 - } -]; -options.list = list; const mockedApis = mockBase.buildMock(options); const apis: MockMethod[] = []; @@ -36,7 +37,7 @@ for (const mockedApi of mockedApis) { apis.push({ url: mockedApi.path, method: mockedApi.method as MethodType, - response: (request: any) => { + response: (request: MockOption) => { return mockedApi.handle(request); } }); diff --git a/src/plugins/fast-crud/index.tsx b/src/plugins/fast-crud/index.tsx index 8e3bcfff..c15d1522 100644 --- a/src/plugins/fast-crud/index.tsx +++ b/src/plugins/fast-crud/index.tsx @@ -5,6 +5,7 @@ import { FastCrud } from '@fast-crud/fast-crud'; import '@fast-crud/fast-crud/dist/style.css'; import './common.scss'; +import type { FsUploaderOptions } from '@fast-crud/fast-extends'; import { FsExtendsCopyable, FsExtendsEditor, @@ -15,6 +16,7 @@ import { import '@fast-crud/fast-extends/dist/style.css'; import UiNaive from '@fast-crud/ui-naive'; import axios from 'axios'; +import type { VueI18n } from 'vue-i18n'; import { mockRequest, request } from '@/service/request'; import { setupNaive } from '@/plugins/fast-crud/naive'; @@ -24,7 +26,10 @@ import { setupNaive } from '@/plugins/fast-crud/naive'; * @param app * @param options */ -function install(app: App, options: any = {}) { +export type FsSetupOpts = { + i18n?: VueI18n; +}; +function install(app: App, options: FsSetupOpts = {}) { // 安装naive ui 常用组件 setupNaive(app); app.use(UiNaive); @@ -32,7 +37,7 @@ function install(app: App, options: any = {}) { i18n: options.i18n, async dictRequest(context: { url: string }) { const url = context.url; - let res: any; + let res: Service.SuccessResult | Service.FailedResult; if (url && url.startsWith('/mock')) { // 如果是crud开头的dict请求视为mock res = await mockRequest.get(url.replace('/mock', '')); @@ -44,7 +49,6 @@ function install(app: App, options: any = {}) { }, /** * useCrud时会被执行 - * @param context,useCrud的参数 */ commonOptions() { return { @@ -85,7 +89,7 @@ function install(app: App, options: any = {}) { }; }, // page请求结果转换 - transformRes: (originPageRes: { res: any; query: any }) => { + transformRes: originPageRes => { const { res } = originPageRes; const pageSize = res.limit; let currentPage = res.offset / pageSize; @@ -115,29 +119,29 @@ function install(app: App, options: any = {}) { app.use(FsExtendsJson); app.use(FsExtendsCopyable); // 安装uploader 公共参数 - app.use(FsExtendsUploader, { + const uploaderOptions: FsUploaderOptions = { defaultType: 'form', form: { action: 'http://www.docmirror.cn:7070/api/upload/form/upload', name: 'file', withCredentials: false, - uploadRequest: async (props: { action: string; file: File; onProgress: (progress: any) => void }) => { + uploadRequest: async props => { const { action, file, onProgress } = props; const data = new FormData(); data.append('file', file); - const res: any = await axios.post(action, data, { + const res = await axios.post(action, data, { headers: { 'Content-Type': 'multipart/form-data' }, timeout: 60000, - onUploadProgress(progress: any) { - onProgress({ percent: Math.round((progress.loaded / progress.total) * 100) }); + onUploadProgress(progress) { + onProgress({ percent: Math.round((progress.loaded / progress.total!) * 100) }); } }); // 上传完成后的结果,一般返回个url 或者key,具体看你的后台返回啥 return res.data.data; }, - successHandle(ret: string) { + async successHandle(ret: string) { // 上传完成后的结果处理, 此处应转换格式为{url:xxx,key:xxx} return { url: `http://www.docmirror.cn:7070${ret}`, @@ -145,7 +149,8 @@ function install(app: App, options: any = {}) { }; } } - } as any); + }; + app.use(FsExtendsUploader, uploaderOptions); // 安装editor app.use(FsExtendsEditor, { @@ -161,6 +166,6 @@ export default { install }; -export function setupFastCrud(app: App, options: any = {}) { +export function setupFastCrud(app: App, options: FsSetupOpts = {}) { install(app, options); } diff --git a/src/views/crud/demo/api.ts b/src/views/crud/demo/api.ts index e212e960..38914e25 100644 --- a/src/views/crud/demo/api.ts +++ b/src/views/crud/demo/api.ts @@ -1,22 +1,28 @@ +import type { UserPageQuery } from '@fast-crud/fast-crud'; import { mockRequest } from '@/service/request'; const request = mockRequest; const apiPrefix = '/crud/demo'; +export type DemoRecord = { + id: number; + [key: string]: any; +}; + function resHandle(res: any) { return res.data; } -export async function GetList(query: any) { +export async function GetList(query: UserPageQuery) { const res = await request.post(`${apiPrefix}/page`, query); return resHandle(res); } -export async function AddObj(obj: any) { +export async function AddObj(obj: DemoRecord) { const res = await request.post(`${apiPrefix}/add`, obj); return resHandle(res); } -export async function UpdateObj(obj: any) { +export async function UpdateObj(obj: DemoRecord) { const res = await request.post(`${apiPrefix}/update`, obj); return resHandle(res); } diff --git a/src/views/crud/demo/crud.tsx b/src/views/crud/demo/crud.tsx index 76df52ea..e3db8760 100644 --- a/src/views/crud/demo/crud.tsx +++ b/src/views/crud/demo/crud.tsx @@ -1,10 +1,10 @@ -import type { AddReq, CreateCrudOptionsRet, DelReq, EditReq } from '@fast-crud/fast-crud'; +import type { AddReq, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes } from '@fast-crud/fast-crud'; import { dict } from '@fast-crud/fast-crud'; import dayjs from 'dayjs'; import * as api from './api'; export default function createCrudOptions(): CreateCrudOptionsRet { - const pageRequest = async (query: any) => { + const pageRequest = async (query: UserPageQuery): Promise => { return api.GetList(query); }; const editRequest = async (ctx: EditReq) => { diff --git a/src/views/crud/header_group/api.ts b/src/views/crud/header_group/api.ts index c11517d2..387a93f0 100644 --- a/src/views/crud/header_group/api.ts +++ b/src/views/crud/header_group/api.ts @@ -1,22 +1,28 @@ +import type { UserPageQuery } from '@fast-crud/fast-crud'; import { mockRequest } from '@/service/request'; const request = mockRequest; const apiPrefix = '/crud/header-group'; +export type HeaderGroupRecord = { + id: number; + [key: string]: any; +}; + function resHandle(res: any) { return res.data; } -export async function GetList(query: any) { +export async function GetList(query: UserPageQuery) { const res = await request.post(`${apiPrefix}/page`, query); return resHandle(res); } -export async function AddObj(obj: any) { +export async function AddObj(obj: HeaderGroupRecord) { const res = await request.post(`${apiPrefix}/add`, obj); return resHandle(res); } -export async function UpdateObj(obj: any) { +export async function UpdateObj(obj: HeaderGroupRecord) { const res = await request.post(`${apiPrefix}/update`, obj); return resHandle(res); } diff --git a/src/views/crud/header_group/crud.tsx b/src/views/crud/header_group/crud.tsx index e2afaf4a..880a4cb8 100644 --- a/src/views/crud/header_group/crud.tsx +++ b/src/views/crud/header_group/crud.tsx @@ -1,22 +1,22 @@ -import type { CreateCrudOptionsRet } from '@fast-crud/fast-crud'; -import { dict } from '@fast-crud/fast-crud'; +import type { CreateCrudOptionsRet, UserPageQuery, UserPageRes } from '@fast-crud/fast-crud'; +import type { HeaderGroupRecord } from './api'; import * as api from './api'; export default function createCrudOptions(): CreateCrudOptionsRet { - const pageRequest = async (query: any) => { + const pageRequest = async (query: UserPageQuery): Promise => { return api.GetList(query); }; - const editRequest = async (ctx: { form: any; row: any }) => { + const editRequest = async (ctx: { form: HeaderGroupRecord; row: HeaderGroupRecord }) => { const { form, row } = ctx; form.id = row.id; return api.UpdateObj(form); }; - const delRequest = async (ctx: { row: any }) => { + const delRequest = async (ctx: { row: HeaderGroupRecord }) => { const { row } = ctx; return api.DelObj(row.id); }; - const addRequest = async (ctx: { form: any }) => { + const addRequest = async (ctx: { form: HeaderGroupRecord }) => { const { form } = ctx; return api.AddObj(form); }; @@ -69,14 +69,8 @@ export default function createCrudOptions(): CreateCrudOptionsRet { children: { province: { title: '省', - search: { show: true }, - type: 'dict-select', - dict: dict({ - data: [ - { value: '广东省', label: '广东省' }, - { value: '浙江省', label: '浙江省' } - ] - }) + type: 'text', + search: { show: true } }, city: { title: '市',