mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-09-24 04:16:38 +08:00
perf(projects): 优化any
This commit is contained in:
parent
59af204a4c
commit
f7090d3dbc
@ -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];
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
@ -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<Element>, options: any = {}) {
|
||||
export function setupFastCrud(app: App<Element>, options: FsSetupOpts = {}) {
|
||||
install(app, options);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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<UserPageRes> => {
|
||||
return api.GetList(query);
|
||||
};
|
||||
const editRequest = async (ctx: EditReq) => {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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<UserPageRes> => {
|
||||
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: '市',
|
||||
|
Loading…
Reference in New Issue
Block a user