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 vote down vote up
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 vote down vote up
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 vote down vote up
/**
 * 查询模板列表
 *
 * @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 vote down vote up
/**
 * 查询标签
 *
 * @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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
/**
   * 封装 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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 />}
              />
              &nbsp;
              {!isEditing ? (
                <Button
                  type="default"
                  className={s.toggle}
                  onClick={toggleEdit}
                  icon={<EditOutlined />}
                />
              ) : null}
              {isEditing ? (
                <Button
                  type="default"
                  className={s.toggle}
                  onClick={toggleEdit}
                  icon={<EyeOutlined />}
                />
              ) : null}
              &nbsp;
              <Button
                type="default"
                icon={<SettingOutlined />}
                onClick={() => setShowPageDrawer(true)}
              >
                页面
              </Button>
              &nbsp;
              <Button
                type="default"
                icon={<PlusOutlined />}
                onClick={() => setShowDrawer(true)}
              >
                组件
              </Button>
              
              <Undo />
              &nbsp;
              <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 ? <>
                &nbsp;
                <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 vote down vote up
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 ? (
                      <>
                        &nbsp;
                        <Button
                          size="small"
                          icon={<EditOutlined />}
                          onClick={() => onSelectedTemplate(item.id, "edit")}
                        />
                        &nbsp;
                        <Button
                          size="small"
                          icon={<DeleteOutlined />}
                          onClick={onDelete(item.id)}
                        />
                      </>
                    ) : null}
                    &nbsp;
                    <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
        }}
      />
    </>
  );
}