query-string#stringify TypeScript Examples
The following examples show how to use
query-string#stringify.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: use-url-state.ts From bext with MIT License | 7 votes |
useUrlState = <S extends UrlState = UrlState>(
initialState?: S | (() => S),
options?: Options,
) => {
type State = Partial<{ [key in keyof S]: any }>;
const { navigateMode = 'push' } = options || {};
const history = useHistory();
const update = useUpdate();
const initialStateRef = useRef(
typeof initialState === 'function'
? (initialState as () => S)()
: initialState || {},
);
const queryFromUrl = useMemo(() => {
return parse(location.search, parseConfig);
}, [location.search]);
const targetQuery: State = useMemo(
() => ({
...initialStateRef.current,
...queryFromUrl,
}),
[queryFromUrl],
);
const setState = (s: React.SetStateAction<State>) => {
const newQuery = typeof s === 'function' ? s(targetQuery) : s;
update();
history[navigateMode]({
hash: location.hash,
search: stringify({ ...queryFromUrl, ...newQuery }, parseConfig) || '?',
});
};
return [targetQuery, useMemoizedFn(setState)] as const;
}
Example #2
Source File: url-service.ts From pola-web with MIT License | 6 votes |
export function tagUrl(label: string, query: any) {
let tags = query.tags.slice();
const isTag = tags.find((tag: string) => tag === label);
if (!isTag) {
tags.push(label);
} else {
tags = tags.filter((tag: string) => tag !== label);
}
const encodedQuery = encodeQueryParams({ tags: withDefault(ArrayParam, []) }, { tags });
return `${urls.pola.news()}?${stringify(encodedQuery)}`;
}
Example #3
Source File: index.ts From yugong with MIT License | 6 votes |
/**
* 查询模板列表
*
* @export
* @param {queryTemplateParams} params
* @return {*} {Promise<queryTemplateParams[]>}
*/
export function queryTemplate(params: queryTemplateParams): Promise<{
rows: queryTemplateParams[];
limit: number;
offset: number;
count: number;
}> {
// git发布
if (isDemo) {
return request.get(
`${process.env.REACT_APP_PUBLIC_PATH || '/'}template/demoRow.json`,
);
}
const query = stringify(params);
return request.get(`/api/template?${query}`);
}
Example #4
Source File: index.ts From yugong with MIT License | 6 votes |
/**
* 查询标签
*
* @export
* @param {queryTagParams} [params]
* @return {*} {Promise<queryTagParams[]>}
*/
export function queryTag(params?: queryTagParams): Promise<queryTagParams[]> {
const query = stringify(params || {});
return request.get(`/api/tag/${query}`);
}
Example #5
Source File: middlewares.ts From yugong with MIT License | 6 votes |
params: Middleware = (context: Context, next: NextFunction) => {
if (context.params) {
const queryString = stringify(context.params);
const concatSymbol = context.url.indexOf('?') > -1 ? '&' : '?';
if (queryString) {
context.url = context.url + concatSymbol + queryString;
}
}
return next();
}
Example #6
Source File: middlewares.ts From yugong with MIT License | 6 votes |
type: Middleware = (context: Context<{ type: 'form' | 'json' | 'raw' }>, next: NextFunction) => {
if (methodWithBody(context.method)) {
context.headers = context.headers || {};
switch (context.type) {
case 'form':
context.headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
context.body = stringify(context.body as KeyValuePair<any>);
break;
case 'json':
context.headers['Content-Type'] = 'application/json;charset=utf-8';
context.body = JSON.stringify(context.body as KeyValuePair<any>);
break;
case 'raw':
default:
break;
}
}
return next();
}
Example #7
Source File: LinkToRelatedProducts.tsx From ra-enterprise-demo with MIT License | 6 votes |
LinkToRelatedProducts: FC<FieldProps<Category>> = ({ record }) => {
const translate = useTranslate();
const classes = useStyles();
return record ? (
<Button
size="small"
color="primary"
component={Link}
to={{
pathname: '/products',
search: stringify({
page: 1,
perPage: 25,
sort: 'id',
order: 'DESC',
filter: JSON.stringify({ category_id: record.id }),
}),
}}
className={classes.link}
>
<products.icon className={classes.icon} />
{translate('resources.categories.fields.products')}
</Button>
) : null;
}
Example #8
Source File: LinkToRelatedCustomers.tsx From ra-enterprise-demo with MIT License | 6 votes |
LinkToRelatedCustomers: FC<{ segment: Identifier }> = ({ segment }) => {
const translate = useTranslate();
const classes = useStyles();
return (
<Button
size="small"
color="primary"
component={Link}
to={{
pathname: '/customers',
search: stringify({
page: 1,
perPage: 25,
filter: JSON.stringify({ groups: segment }),
}),
}}
className={classes.link}
>
<visitors.icon className={classes.icon} />
{translate('resources.segments.fields.customers')}
</Button>
);
}
Example #9
Source File: index.tsx From whiteboard-demo with MIT License | 6 votes |
private async fetchWithMethod(method: string, inputParams: Readonly<FetcherParams> | string): Promise<any> {
const params = this.standardizeFetcherParams(inputParams);
if (params.body && typeof params.body === "object" && params.body.constructor === Object) {
params.body = JSON.stringify(params.body);
}
if (params.headers) {
params.headers["content-type"] = "application/json";
params.headers["Accept"] = "application/json";
} else {
params.headers = {
"content-type": "application/json",
"Accept": "application/json",
};
}
let url = `${this.apiOrigin}/${params.path}`;
if (params.query) {
url += "?" + stringify(params.query);
}
const requestInit: RequestInit = params as any;
requestInit.method = method;
const response = await this.fetchWithTimeout(url, requestInit);
const isSuccess = response.status >= 200 && response.status < 300;
if (!isSuccess) {
const message = await this.readErrorMessageFromResponse(response) || response.statusText;
console.log("response ", message, response);
throw new HttpError(response.status, message, response);
}
const myResponse = await response.json();
if (myResponse.code === 403) {
console.log("Permission not verified");
}
return myResponse;
}
Example #10
Source File: index.ts From ra-data-postgrest with MIT License | 6 votes |
getQuery = (primaryKey : PrimaryKey, ids: Identifier | Array<Identifier>, resource: string) : string => {
if (Array.isArray(ids) && ids.length > 1) {
// no standardized query with multiple ids possible for rpc endpoints which are api-exposed database functions
if (resource.startsWith('rpc/')) {
console.error('PostgREST\'s rpc endpoints are not intended to be handled as views. Therefore, no query generation for multiple key values implemented!');
return ;
}
if (isCompoundKey(primaryKey)) {
return `or=(
${ids.map(id => {
const primaryKeyParams = decodeId(id, primaryKey);
return `and(${primaryKey.map((key, i) => `${key}.eq.${primaryKeyParams[i]}`).join(',')})`;
})
}
)`;
} else {
return stringify({ [primaryKey[0]]: `in.(${ids.join(',')})` });
}
} else {
// if ids is one Identifier
const id : Identifier = ids.toString();
const primaryKeyParams = decodeId(id, primaryKey);
if (isCompoundKey(primaryKey)) {
if (resource.startsWith('rpc/'))
return `${primaryKey.map((key : string, i: any) => `${key}=${primaryKeyParams[i]}`).join('&')}`;
else
return `and=(${primaryKey.map((key : string, i: any) => `${key}.eq.${primaryKeyParams[i]}`).join(',')})`;
} else {
return stringify({ [primaryKey[0]]: `eq.${id}` });
}
}
}
Example #11
Source File: ajax.ts From joplin-utils with MIT License | 6 votes |
/**
* 封装 ajax 请求
* @param ajaxConfig
*/
async request(ajaxConfig: AjaxConfig): Promise<any> {
if (typeof fetch === 'undefined') {
Reflect.set(globalValue, 'fetch', require('node-fetch'))
}
if (typeof FormData === 'undefined') {
Reflect.set(globalValue, 'FormData', require('form-data'))
}
const config = { ...defaultConfig, ...ajaxConfig }
const resp = await fetch(config.url, {
...config,
method: config.method,
body: config.data instanceof FormData ? config.data : JSON.stringify(config.data),
})
if (!resp.ok) {
// console.log(resp.status)
throw new Error((await resp.json()).error)
}
switch (config.responseType) {
case 'json':
return await resp.json()
case 'arraybuffer':
return await resp.arrayBuffer()
case 'blob':
return await resp.blob()
case 'text':
return await resp.text()
default:
throw new Error(`Unsupported responseType: ${config.responseType}`)
}
}
Example #12
Source File: index.ts From ra-data-postgrest with MIT License | 5 votes |
encodeId = (data: any, primaryKey: PrimaryKey): Identifier => {
if (isCompoundKey(primaryKey)) {
return JSON.stringify(primaryKey.map(key => data[key]));
} else {
return data[primaryKey[0]];
}
}
Example #13
Source File: index.ts From ra-data-nestjsx-crud with MIT License | 5 votes |
composeQueryParams = (queryParams: any = {}): string => {
return stringify(fetchUtils.flattenObject(queryParams),{skipNull:true});
}
Example #14
Source File: ajax.ts From joplin-utils with MIT License | 5 votes |
baseUrl(url: string, param?: object): string {
const query = stringify({ ...param, token: this.config.token }, { arrayFormat: 'comma' })
const baseUrl = this.config.baseUrl.endsWith('/')
? this.config.baseUrl.slice(0, this.config.baseUrl.length - 1)
: this.config.baseUrl
return `${baseUrl}${url}?${query}`
}
Example #15
Source File: Responsive.tsx From yugong with MIT License | 4 votes |
Responsive: React.FC<Props> = () => {
useEffect(() => {
trackPageView('/首页');
}, []);
/**
* ----------
* 定义编辑模式
* ----------
*/
const { isEditing, auth } = useSelector(
(state: RootState) => state.controller,
);
const history = useHistory();
const appData = useSelector((state: RootState) => state.appData);
const activationItem = useSelector(
(state: RootState) => state.activationItem,
);
const stateTag = useSelector((state: RootState) => state.controller.stateTag);
const forceUpdateByStateTag =
useDispatch<Dispatch>().controller.forceUpdateByStateTag;
const setIsEditing = useDispatch<Dispatch>().controller.setIsEditing;
const updateAppData = useDispatch<Dispatch>().appData.updateAppData;
const updatePageData = useDispatch<Dispatch>().pageData.updatePage;
const setWindowHeight = useDispatch<Dispatch>().pageData.setWindowHeight;
const setWindowWidth = useDispatch<Dispatch>().pageData.setWindowWidth;
const updateActivationItem =
useDispatch<Dispatch>().activationItem.updateActivationItem;
const removeActivationItem =
useDispatch<Dispatch>().activationItem.removeActivationItem;
const setRunningTimes = useDispatch<Dispatch>().runningTimes.setRunningTimes;
const ref = useRef(null);
const pageData = useSelector((state: RootState) => state.pageData);
const runningTimes = useSelector((state: RootState) => state.runningTimes);
const setIsReady = useDispatch<Dispatch>().record.setIsReady;
const [, setLocalPageData] = useLocalStorage('pageData', null);
const [showDrawer, setShowDrawer] = useState(false);
const [showPageDrawer, setShowPageDrawer] = useState(false);
const [isCreate, setIsCreate] = useState(true);
const [showTemplateModal, setShowTemplateModal] = useState(false);
const [hideIframe, sethideIframe] = useState(true);
const [visibleQrcode, setVisibleQrcode] = useState(false);
// 创建postmessage通信 usePostMessage收集数据 redux 更新数据
const sendMessage = usePostMessage(({ tag, value }) => {
switch (tag) {
case 'setIsEditing':
setIsEditing(value);
break;
case 'updateAppData':
updateAppData(value);
// 同步更新被选模块的属性
if (activationItem.moduleId === undefined) return;
const asynAcactivationItem = (value as AppDataListTypes).find(
(item) => item.moduleId === activationItem.moduleId,
);
if (asynAcactivationItem?.moduleId) {
updateActivationItem(asynAcactivationItem);
}
break;
case 'updateRunningTimes':
setRunningTimes(value);
break;
case 'updatePage':
updatePageData(value);
break;
case 'id':
// 设置当前项正在被编辑
// 禁止重复设置当前编辑项
if (activationItem.moduleId === value) return;
for (let index = 0; index < appData.length; index++) {
const element = appData[index];
if (element.moduleId === value) {
updateActivationItem({ ...element });
break;
}
}
setShowDashboard(true);
break;
case 'record':
saveRecord(value)
break
default:
break;
}
});
// 收发处理,子窗口onload时向子窗口发送信息, 通知当前正处于编辑模式下,
const win: Window | null = ref.current
? (ref.current as any).contentWindow
: null;
useEffect(() => {
const windows = (document.getElementById('wrapiframe') as any)
?.contentWindow;
if (windows && !isCreate) {
windows.onload = () => {
sendMessage({ tag: 'setIsEditing', value: true }, windows);
setIsEditing(true);
setIsReady(true);
sethideIframe(false);
};
}
}, [sendMessage, setIsEditing, isCreate, setIsReady]);
useEffect(() => {
sendMessage({ tag: 'setIsEditing', value: true }, win);
setIsEditing(true);
}, [sendMessage, setIsEditing, win]);
const toggleEdit = useCallback(() => {
const states = !isEditing;
sendMessage({ tag: 'setIsEditing', value: states }, win);
setIsEditing(states);
}, [isEditing, sendMessage, setIsEditing, win]);
const toggleCreate = useCallback(() => {
setIsCreate(!isCreate);
}, [isCreate]);
// 收发处理,编辑完数据后通过sendMessage向子窗口发送最新数据。
useEffect(() => {
sendMessage(
{
tag: 'updateAppData',
value: appData,
},
win,
);
}, [sendMessage, win, appData]);
const onChangeRule = (
width: number,
height: number = window.innerHeight - 140,
) => {
setWindowWidth(width);
setWindowHeight(height);
const optPageData = { ...pageData };
optPageData.windowWidth = width;
optPageData.windowHeight = height;
setLocalPageData(optPageData);
if (win) {
sendMessage({ tag: 'updatePage', value: true }, win);
sendMessage({ tag: 'setIsEditing', value: isEditing }, win);
}
setIsEditing(true);
forceUpdateByStateTag();
};
const [showDashboard, setShowDashboard] = useState(false);
const [opacity, setOpacity] = useState('1');
// 无激活模块时隐藏设置面板
useEffect(() => {
if (!activationItem.moduleId) {
setShowDashboard(false);
}
}, [activationItem]);
const hideDashboard = useCallback(() => {
setShowDashboard(false);
removeActivationItem();
if (win) {
sendMessage({ tag: 'removeActivationItem', value: undefined }, win);
}
}, [removeActivationItem, sendMessage, win]);
const updateProject = useCallback(
(data: Template) => {
data.id = pageData.template?.id;
return updateTemplate(data);
},
[pageData],
);
interface TemplateAll extends Template {
pageData: string;
appData: string;
}
// 保存或更新项目
const onSaveProject = useCallback(
async ({
cove = [],
terminal,
isPublic,
describe,
tag,
title,
id,
}: TemplateInfo) => {
if (!auth?.isLogin) {
history.push('/login');
return;
}
// copy
const pageDataCopy = cloneDeep(pageData);
// template数据
const templateData: Template = {
title: title || pageData.pageTitle,
terminal,
cove: cove[0]?.thumbUrl,
describe,
tag: tag?.join(','),
isPublic: isPublic === true ? 1 : 0,
};
// 存入模板信息到pageData
if (!pageDataCopy.template) {
pageDataCopy.template = templateData;
}
// 完整数据
/**
* 完整数据包含页面数据、组件数据与模板信息三个部分,
* 页面数据同时也包含一份模板信息供页面处理
*/
const params: TemplateAll = {
pageData: JSON.stringify(pageData),
appData: JSON.stringify(appData),
id,
userId: auth.session?.id,
...templateData,
};
try {
loading.show();
// 更新
if (!!pageData.template?.id) {
await updateProject(params);
} else {
// 新增
const newId = await createTemplate(params);
pageDataCopy.template.id = newId;
}
message.success('已发布');
// 更新
updatePageData(pageDataCopy);
// 关闭弹窗
setShowTemplateModal(false);
// todo 展示二维码与模板访问链接,支持扫码访问
setVisibleQrcode(true);
loading.hide();
} catch (error) {
console.error(error);
loading.hide();
}
},
[
appData,
auth?.isLogin,
auth?.session?.id,
history,
pageData,
updatePageData,
updateProject,
],
);
const showPublishModal = useCallback(() => {
if (!auth?.isLogin) {
history.push('/login');
}
setShowTemplateModal(true);
}, [auth?.isLogin, history]);
const pageSearch = stringify({ tpl: pageData.template?.id, ...runningTimes.search });
const codeViewUrl = `${process.env.REACT_APP_SITE_PATH || ''}${pageSearch ? `?${pageSearch}` : ''}`;
const viewUrl = `${process.env.REACT_APP_SITE_PATH || ''}${window.location.search || '?isediting'
}`
return (
<>
{isCreate ? (
<CreateProject goBack={() => toggleCreate()} />
) : (
<div className={s.main}>
{showDashboard && isEditing ? (
<Draggable
axis="both"
handle={`.${s.header}`}
onDrag={() => setOpacity('0.5')}
onStop={() => setOpacity('1')}
>
<div className={s.dashboard} style={{ opacity }}>
<div className={s.header}>
<h3>设置面板</h3>
<CloseOutlined className={s.icon} onClick={hideDashboard} />
</div>
<MiniDashboard />
</div>
</Draggable>
) : null}
<div className={s.topmenu}>
<div className={s.create}>
<Button
type="primary"
onClick={toggleCreate}
icon={<FileAddOutlined />}
/>
{!isEditing ? (
<Button
type="default"
className={s.toggle}
onClick={toggleEdit}
icon={<EditOutlined />}
/>
) : null}
{isEditing ? (
<Button
type="default"
className={s.toggle}
onClick={toggleEdit}
icon={<EyeOutlined />}
/>
) : null}
<Button
type="default"
icon={<SettingOutlined />}
onClick={() => setShowPageDrawer(true)}
>
页面
</Button>
<Button
type="default"
icon={<PlusOutlined />}
onClick={() => setShowDrawer(true)}
>
组件
</Button>
<Undo />
<a href="https://github.com/eightfeet/yugong">
<Button type="default" icon={<GithubOutlined />}>
github
</Button>
</a>
</div>
<div className={s.save}>
<Button
type="primary"
icon={<CloudUploadOutlined />}
onClick={showPublishModal}
>
{pageData.template?.id ? '修改' : '发布'}
</Button>
{pageData.template?.id ? <>
<Button
icon={<QrcodeOutlined />}
onClick={() => setVisibleQrcode(true)}
/>
</> : null}
</div>
</div>
<Ruler onChange={onChangeRule} />
<Drawer
className={s.drawer}
title="页面设置"
width={580}
onClose={() => setShowPageDrawer(false)}
visible={showPageDrawer}
bodyStyle={{ padding: '0', overflow: 'auto' }}
maskStyle={{ backgroundColor: 'transparent' }}
footer={null}
>
{showPageDrawer ? <PageSetting /> : null}
</Drawer>
<Drawer
className={s.drawer}
title="组件库"
width={580}
onClose={() => setShowDrawer(false)}
visible={showDrawer}
bodyStyle={{ padding: '0px' }}
maskStyle={{ backgroundColor: 'transparent' }}
footer={null}
>
<Repository />
</Drawer>
<div className={s.box}>
<div
className={classNames({
[s.viewbg]: !isEditing,
})}
style={{ transition: 'all 0.5s' }}
/>
{!stateTag ? (
<div
className={s.iframebox}
style={{
width:
pageData.windowWidth === -1
? `100%`
: `${pageData.windowWidth}px`,
height: `${pageData.windowHeight}px`,
}}
>
<LoadingAnimate />
<iframe
ref={ref}
id="wrapiframe"
title="wrapiframe"
src={viewUrl}
style={{
border: 'none',
opacity: hideIframe ? 0 : 1,
minWidth: '100%',
minHeight: `${pageData.windowHeight}px`,
}}
/>
</div>
) : null}
</div>
</div>
)}
<TemplateInfoModal
visible={showTemplateModal}
onOk={onSaveProject}
onCancel={() => setShowTemplateModal(false)}
/>
<QrcodeModal
visible={visibleQrcode}
onCancel={() => setVisibleQrcode(false)}
sourceData={codeViewUrl}
title="请扫码访问"
info={<div className={s.viewurl}>访问地址:<a href={codeViewUrl} target={'_blank'} rel="noreferrer">{codeViewUrl}</a></div>}
options={{
width: 122,
margin: 1
}}
/>
</>
);
}
Example #16
Source File: TemplateList.tsx From yugong with MIT License | 4 votes |
TemplateList: React.FC<Props> = ({ onSelectedTemplate }) => {
const { auth } = useSelector((state: RootState) => state.controller);
const history = useHistory();
const [templateList, setTemplateList] = useState<queryTemplateParams[]>([]);
const [templateParams, setTemplateParams] = useState<queryTemplateParams>({
isPublic: 1,
limit: 8,
offset: 0,
});
// 总条数决定页数
const [total, setTotal] = useState<number>();
const runningTimes = useSelector((state: RootState) => state.runningTimes);
// 当前页
const [current, setCurrent] = useState(1)
const [visibleQrcode, setVisibleQrcode] = useState(0);
const [tags, setTags] = useState<queryTagParams[]>([]);
const getTags = useCallback(async () => {
try {
loading.show();
const tagsResult = await queryTag();
setTags(tagsResult);
loading.hide();
} catch (error) {
loading.hide();
console.error(error);
}
}, []);
useEffect(() => {
getTags();
}, [getTags]);
const renderTags = useCallback(
(tag: string) => {
const tagTsx = tag
.split(",")
.filter((item) => Number(item))
.map((el, ind) => (
<React.Fragment key={ind}>
{tags.map((one, index) =>
Number(el) === one.id ? <Tag key={index}>{one.name}</Tag> : null
)}
</React.Fragment>
));
return tagTsx;
},
[tags]
);
/**
* 获取列表
* @param type
*/
const getTemplateList = useCallback(
async (query?: queryTemplateParams, force?: boolean) => {
let params = {
...templateParams,
...query,
};
params = clearEmptyOfObject(params)
if (force) {
params = { ...query }
}
if (params.isPublic === 0) {
params.userId = auth?.session?.id
}
try {
loading.show();
const { rows = [], limit, offset, count } = await queryTemplate(params);
setTemplateList(rows);
setTotal(Math.ceil(count / limit) * limit);
setCurrent(offset / limit + 1);
loading.hide();
} catch (error) {
loading.hide();
console.error(error);
}
},
[auth?.session?.id, templateParams]
);
useEffect(() => {
getTemplateList({ isPublic: 1 });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const del = useCallback(
(id) => {
loading.show();
deleteTemplate(id).then(() => {
loading.hide();
getTemplateList();
}).catch(error => {
console.error(error)
loading.hide();
});
},
[getTemplateList]
);
const onChangeTab = useCallback(
(key) => {
// 拦截到登录
if (key === "0" && !auth?.isLogin) {
history.push("/login");
return;
}
setTemplateParams({
limit: templateParams.limit,
offset: 0,
isPublic: Number(key) as 1 | 0,
});
getTemplateList({
limit: templateParams.limit,
offset: 0,
isPublic: Number(key) as 1 | 0,
}, true)
},
[auth?.isLogin, getTemplateList, history, templateParams]
);
const onSearch = useCallback(
(data) => {
const optData = { ...templateParams, ...data };
if (!data.tag) {
delete optData.tag;
}
if (!data.title) {
delete optData.title;
}
if (!data.terminal) {
delete optData.terminal;
}
setTemplateParams(optData)
getTemplateList(optData, true);
},
[getTemplateList, templateParams]
);
const onDelete = useCallback(
(id) => () => {
confirm({
content: <div>确定要删除当前模板?</div>,
okText: "确定",
cancelText: "取消",
onCancel: () => { },
onOk: () => del(id),
});
},
[del]
);
const onChangePagination = useCallback(
(page) => {
const currentOffset = (page - 1) * (templateParams.limit || 0);
getTemplateList({
offset: currentOffset
});
},
[getTemplateList, templateParams.limit]
);
const handleShowQrCode = useCallback(
(item) => {
setVisibleQrcode(item.id);
},
[],
)
const pageSearch = stringify({ tpl: visibleQrcode, ...runningTimes.search });
const codeViewUrl = `${process.env.REACT_APP_SITE_PATH || ''}${pageSearch ? `?${pageSearch}` : ''}`;
return (
<>
<Tabs className={s.tab} defaultActiveKey="1" onChange={onChangeTab}>
<TabPane tab="公共模板" key="1"></TabPane>
<TabPane tab="我的项目" key="0"></TabPane>
</Tabs>
<Searchbar key={templateParams.isPublic} onClick={onSearch} tags={tags} />
<div className={s.container}>
{templateList.map((item: any, index) => (
<Card
hoverable
className={s.card}
bodyStyle={{ padding: "10px" }}
key={`${item.id}${index}`}
onDoubleClick={() => onSelectedTemplate(item.id, "create")}
cover={
<div className={classNames(s.projectcove, s.projectcovetpl)}>
{item.cove ? (
<img src={item.cove} alt={item.title} />
) : (
<EmptyIcon />
)}
</div>
}
>
<Meta
title={
<>
<h4 className={s.tpltitle}>{item.title}</h4>
<div className={s.tpldescript}>{item.describe}</div>
</>
}
description={
<>
<div className={s.tag}>{renderTags(item.tag)}</div>
<div className={s.buttonbar}>
<Button
size="small"
type="primary"
onClick={() => onSelectedTemplate(item.id, "create")}
>
从模板创建
</Button>
{auth?.session?.id === item.userId ? (
<>
<Button
size="small"
icon={<EditOutlined />}
onClick={() => onSelectedTemplate(item.id, "edit")}
/>
<Button
size="small"
icon={<DeleteOutlined />}
onClick={onDelete(item.id)}
/>
</>
) : null}
<Button
size="small"
icon={<QrcodeOutlined />}
onClick={() => handleShowQrCode(item)}
/>
</div>
</>
}
/>
</Card>
))}
</div>
{!!total && (
<Pagination
current={current}
pageSize={templateParams?.limit || 0}
onChange={onChangePagination}
total={total}
/>
)}
<QrcodeModal
visible={!!visibleQrcode}
onCancel={() => setVisibleQrcode(0)}
sourceData={codeViewUrl}
title="请扫码访问"
info={<div className={s.viewurl}>访问地址:<a href={codeViewUrl} target={'_blank'} rel="noreferrer">{codeViewUrl}</a></div>}
options={{
width: 122,
margin: 1
}}
/>
</>
);
}