开放平台的实践|8月更文挑战

568 阅读1分钟

背景

公司需要向外开放一些能力,为了方便接入和管理,需要一个开放平台,目的是连接开发者 供应商 和企业系统

image.png

需要包含的模块

  1. 账号体系 Developer

  • 开发者身份注册
  • 登陆
  • 创建应用
  • 数据权限
  1. 文档中心 Doc

  • 概述
  • 使用说明:注册->创建->绑定->配置->接入上线
  • 接口文档
  1. 开放能力 Platform

  • 管理开发者应用
  • 查看接口权限
  • 在线测试工具
  1. 管理后台 Admin

  • 开发者管理
  • 应用管理
  • 配置管理
  • 数据库管理
  • 权限管理
  • 监控报表
  1. 常见问题 Questions

  • 问题列表
  • 联系我们

安全层面

  • 加密
  • 应用秘钥
  • 应用接口权限控制
  • 访问黑白名单
  • 字段脱敏还原等

技术实践

文档中心

  • Markdown

md转html:github.com/markedjs/ma…

json转md:github.com/IonicaBizau…

json转table:www.npmjs.com/package/jso…

  • 代码高亮

github.com/highlightjs…

import React, { useEffect, useState } from 'react';
import marked from 'marked';
import hljs from 'highlight.js';
import 'highlight.js/styles/monokai-sublime.css';
import Tocify from '../Component/tocify';
import json2md from 'json2md';

const renderer = new marked.Renderer();
let tocify = new Tocify();
interface jsonType {
    [key: string]: string | jsonType[] | string[] | jsonType;
}

const jsonData: jsonType[] = [
    { h1: 'JSON To Markdown' },
    { blockquote: 'A JSON to Markdown converter.' },
    {
        img: [
            { title: 'Some image', source: 'https://example.com/some-image.png' },
            { title: 'Another image', source: 'https://example.com/some-image1.png' },
            {
            title: 'Yet another image',
            source: 'https://example.com/some-image2.png',
            },
        ],
    },
    { h2: 'Features' },
    {
        ul: [
            'Easy to use',
            'You can programmatically generate Markdown content',
            '...',
        ],
    },
];

const { TextArea } = Input;

function AddArticle() {
// 渲染标题时触发,将标题添加到tocify目录列表中
renderer.heading = function (text, level, raw) {
    const anchor = tocify.add(text, level);
    return `<a id="${anchor}" href="#${anchor}" class="anchor-fix"><h${level}>${text}</h${level}></a>\n`;
};

marked.setOptions({
    renderer,
    highlight: function (code) {
    return hljs.highlightAuto(code).value;
    }, //代码高亮
    gfm: true, // 允许 Git Hub标准的markdown.
    pedantic: false, // 不纠正原始模型任何的不良行为和错误(默认为false)
    sanitize: false, // 对输出进行过滤(清理),将忽略任何已经输入的html代码(标签)
    breaks: true, // 允许回车换行(该选项要求 gfm 为true)
    smartLists: false, // 使用比原生markdown更时髦的列表
    smartypants: false, // 使用更为时髦的标点
});

const initMD = json2md(jsonData);

const [articleContent, setArticleContent] = useState(initMD); //markdown的编辑内容
const [markdownContent, setMarkdownContent] = useState(marked(initMD)); //html内容


return (
    <div>
        {/* markdown内容 */}
        <TextArea
        className="markdown-content"
        rows={35}
        placeholder="编辑内容"
        value={articleContent}
        />

        {/* html内容 */}
        <div
        className={css({
            border: '1px solid #d9d9d9',
            background: '#ffffff',
            height: '100%',
        })}
        dangerouslySetInnerHTML={{ __html: markdownContent }}></div>

        {/* 目录 */}
        <div className="toc" >
            {tocify && tocify.render()}
        </div>
    </div>
    );
}

export default AddArticle;

../Component/Tocify

// tocify 生成目录 hash定位
import React from 'react';
import { Anchor } from 'antd';
import { last } from 'lodash';

const { Link } = Anchor;
export interface TocItem {
    anchor: string;
    level: number;
    text: string;
    children?: TocItem[];
}
export type TocItems = TocItem[]; // TOC目录树结构
export default class Tocify {
    anchors: string[];
    tocItems: TocItems = [];
    constructor() {
        this.anchors = [];
        this.tocItems = [];
    }

    add(text: string, level: number, id: string = '') {
        const count = this.anchors.filter((anchor) => anchor === text).length;
        const anchor = id || (count ? `${text}${count}` : text);
        this.anchors.push(anchor);
        const item = { anchor, level, text };
        const items = this.tocItems;
        if (items.length === 0) {
        // 第一个 item 直接 push
            items.push(item);
        } else {
            let lastItem = last(items) as TocItem; // 最后一个 item
            if (item.level > lastItem.level) {
                // item 是 lastItem 的 children
                for (let i = lastItem.level + 1; i <= 6; i++) {
                    const { children } = lastItem;
                    if (!children) {
                        // 如果 children 不存在
                        lastItem.children = [item];
                        break;
                    }
                    lastItem = last(children) as TocItem; // 重置 lastItem 为 children 的最后一个 item
                    if (item.level <= lastItem.level) {
                        // item level 小于或等于 lastItem level 都视为与 children 同级
                        children.push(item);
                        break;
                    }
                }
            }else{
                // 置于最顶级
                items.push(item);
            }
        }
        return anchor;
    }

    reset = () => {
        this.tocItems = [];
        this.anchors = [];
    };
    renderToc(items: TocItem[]) {
        // 递归 render
        return items.map((item) => (
            <Link key={item.anchor} href={`#${item.anchor}`} title={item.text}>
            {item.children && this.renderToc(item.children)}
            </Link>
        ));
    }

    render() {
        return (
            <Anchor style={{ padding: 24 }} affix showInkInFixed>
            {this.renderToc(this.tocItems)}
            </Anchor>
        );
    }
}