amisadmin / fastapi-amis-admin

FastAPI-Amis-Admin is a high-performance, efficient and easily extensible FastAPI admin framework. Inspired by django-admin, and has as many powerful functions as django-admin.
http://docs.amis.work
Apache License 2.0
1.05k stars 154 forks source link

希望把 amis 拆开来独立一仓库维护 #185

Open InfernalAzazel opened 1 month ago

InfernalAzazel commented 1 month ago
  1. 读取模版使用 jinja2 这样那个框架都能用
  2. 维护变得更加容易
  3. 各个框架通用

例如:

from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple, Union

from jinja2 import Environment, FileSystemLoader
from pydantic import Field
from typing_extensions import Literal

try:
    from pydantic import SerializeAsAny
except ImportError:
    from typing import Union as SerializeAsAny
from .constants import (
    BarcodeEnum,
    DisplayModeEnum,
    LevelEnum,
    PlacementEnum,
    ProgressEnum,
    SizeEnum,
    StepStatusEnum,
    TabsModeEnum,
    TriggerEnum,
)
from .types import (
    API,
    AmisNode,
    BaseAmisModel,
    Expression,
    OptionsNode,
    SchemaNode,
    Template,
    Tpl,
)

env = Environment(loader=FileSystemLoader(Path(__file__).parent / 'templates')) # <- 这条新增

RemarkT = Union[str, "Remark"]

class Html(AmisNode):
    """Html"""

    type: str = "html"  # specify as html component
    html: str  # html When you need to get variables in the data field, use Tpl.

class Icon(AmisNode):
    """icon"""

    type: str = "icon"  # specify the component type
    className: Optional[str] = None  # Outer CSS class name
    icon: Optional[str] = None  # icon name, support fontawesome v4 or use url
    vendor: Optional[
        str] = None  # icon vendor, icon supports fontawesome v4 by default, if you want to support fontawesome v5
    # and v6, please set vendor to an empty string.

class Remark(AmisNode):
    """mark"""

    type: str = "remark"  # remark
    className: Optional[str] = None  # Outer CSS class name
    content: Optional[str] = None  # prompt text
    placement: Optional[str] = None  # Popup position
    trigger: Optional[str] = None  # Trigger condition['hover','focus']
    icon: Optional[str] = None  # "fa fa-question-circle" # icon

class Badge(AmisNode):
    """Subscript"""

    mode: str = "dot"  # Corner type, can be dot/text/ribbon
    text: Union[int, str, None] = None  # Corner text, supports strings and numbers, invalid when mode='dot'
    size: Optional[int] = None  # Angular size
    level: Optional[
        str] = None  # The level of the corner label, which can be info/success/warning/danger, after setting the
    # background color of the corner label is different
    overflowCount: Optional[int] = None  # 99 # Set the capped number value
    position: Optional[str] = None  # "top-right" # Corner position, can be top-right/top-left/bottom-right/bottom-left
    offset: Optional[
        int] = None  # The position of the corner label, the priority is greater than the position, when the
    # offset is set, the position is positioned as the top-right reference number[top, left]
    className: Optional[str] = None  # The class name of the outer dom
    animation: Optional[bool] = None  # whether the corner icon displays animation
    style: Optional[dict] = None  # Custom style for corner labels
    visibleOn: Optional[Expression] = None  # Controls the display and hiding of corner labels

class Page(AmisNode):
    """page"""

    __default_template_path__: str = 'page.jinja2'

    type: str = "page"  # Specify as Page component
    title: SerializeAsAny[Optional[SchemaNode]] = None  # page title
    subTitle: SerializeAsAny[Optional[SchemaNode]] = None  # Page subtitle
    remark: Optional[
        RemarkT] = None  # A prompt icon will appear near the title, and the content will be prompted when the
    # mouse is placed on it.
    aside: SerializeAsAny[Optional[SchemaNode]] = None  # Add content to the sidebar area of the page
    asideResizor: Optional[bool] = None  # whether the width of the sidebar area of the page can be adjusted
    asideMinWidth: Optional[int] = None  # The minimum width of the sidebar area of the page
    asideMaxWidth: Optional[int] = None  # The maximum width of the sidebar area of the page
    toolbar: SerializeAsAny[Optional[SchemaNode]] = None  # Add content to the upper right corner of the page.
    # It should be noted that when there is a title, the area is in the upper right corner,
    # and when there is no title, the area is at the top
    body: SerializeAsAny[Optional[SchemaNode]] = None  # Add content to the content area of the page
    className: Optional[str] = None  # Outer dom class name
    cssVars: Optional[dict] = None  # Custom CSS variables, please refer to styles
    css: Optional[str] = None  # Custom CSS styles, please refer to used theme styles
    mobileCSS: Optional[str] = None  # Custom mobile CSS styles, please refer to used theme styles
    toolbarClassName: Optional[str] = None  # "v-middle wrapper text-right bg-light bb" # Toolbar dom class name
    bodyClassName: Optional[str] = None  # "wrapper" # Body dom class name
    asideClassName: Optional[str] = None  # "w page-aside-region bg-auto" # Aside dom class name
    headerClassName: Optional[str] = None  # "bg-light bb wrapper" # Header area dom class name
    initApi: Optional[
        API] = None  # The api that Page uses to get initial data. The returned data can be used at the entire
    # page level.
    initFetch: Optional[bool] = None  # True # whether to start pulling initApi
    initFetchOn: Optional[Expression] = None  # whether to start pulling initApi, configure by expression
    interval: Optional[int] = None  # refresh time (minimum 1000)
    silentPolling: Optional[
        bool] = None  # False # whether to show the loading animation when the configuration is refreshed
    stopAutoRefreshWhen: Optional[
        Expression] = None  # Configure the conditions for stopping refresh through expressions
    regions: Optional[List[str]] = None

    def render(
            self,
            template_path: str = "",
            locale: str = "zh_CN",
            cdn: str = "https://unpkg.com",
            pkg: str = "amis@1.10.2",
            site_title: str = "Amis",
            site_icon: str = "",
            theme: str = "cxd",
    ):
        """Render html template"""
        template_path = template_path or self.__default_template_path__
        #  这个改成这样
        return env.get_template(template_path).render(
            {
                "AmisSchemaJson": self.json(),
                "locale": locale.replace("_", "-"),  # Fix #50
                "cdn": cdn,
                "pkg": pkg,
                "site_title": site_title,
                "site_icon": site_icon,
                "theme": theme,
            }
        )

fastapi 使用

from fastapi import FastAPI
from fastapi.responses import HTMLResponse

from amis.components import App

app = FastAPI()

@app.get("/", response_class=HTMLResponse)
async def read_root():
    amis_app = App()
    amis_app.type = 'page'
    amis_app.body = {
        'type': 'form',
        'mode': 'horizontal',
        'api': '/saveForm',
        'body': [
            {
                'label': 'Name',
                'type': 'input-text',
                'name': 'name'
            },
            {
                'label': 'Email',
                'type': 'input-email',
                'name': 'email'
            }
        ]
    }

    return HTMLResponse(content=amis_app.render())