From 32dbcd0a1f349b1d3cd92c077e97cb6c8586b7cb Mon Sep 17 00:00:00 2001 From: yumoqing Date: Thu, 11 Dec 2025 21:59:36 +0800 Subject: [PATCH] bugfix --- kdb/example.dspy | 5 +- kdb/example.ui | 3 + kdb/rule.md | 708 ++++++++++++++++++++++++++++++++++++++++++ req/.pricing.req.swp | Bin 12288 -> 0 bytes req/txt | 712 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1425 insertions(+), 3 deletions(-) create mode 100644 kdb/rule.md delete mode 100644 req/.pricing.req.swp create mode 100644 req/txt diff --git a/kdb/example.dspy b/kdb/example.dspy index b64081d..55cb640 100644 --- a/kdb/example.dspy +++ b/kdb/example.dspy @@ -1,4 +1,3 @@ -""" dspy脚本可用的变量 ahserver/globalEnv.py程序中推送到ServerEnv中的变量 各个模块init_mymodule函数推送的变量 @@ -25,8 +24,8 @@ async with db.sqlorContext('sage') as sor: ns = DictObject(**ns) x = await sms_engine.send_validate_code(params_kw.cell_no, ns.code) info(f'{params_kw.cell_no}, {ns.code=}, send_validatecode() return {x}') - return PopMessage(title='SMS', message=f'validate code send to {params_kw.cell_no}') + return UiMessage(title='SMS', message=f'validate code send to {params_kw.cell_no}') -return PopError(title='Error', message=f'{params_kw.cell_no} generate validate code error') +return UiError(title='Error', message=f'{params_kw.cell_no} generate validate code error') ``` diff --git a/kdb/example.ui b/kdb/example.ui index 4769849..4cde024 100644 --- a/kdb/example.ui +++ b/kdb/example.ui @@ -1,3 +1,5 @@ +## ui文件例子 +``` { "widgettype":"VBox", "options":{ @@ -73,3 +75,4 @@ } ] } +``` diff --git a/kdb/rule.md b/kdb/rule.md new file mode 100644 index 0000000..f4c2692 --- /dev/null +++ b/kdb/rule.md @@ -0,0 +1,708 @@ +## 模块目录结构 +模块名称为“mymodule", 以下为mymodule模块的目录文件结构 +``` +mymodule + | + +--mymodule # 存放模块的主要逻辑py代码 + | | + | +--init.py # 模块初始化脚本,需要定义一个load_mymodule()函数,此函数将在ui和dspy文件中用到的模块变量通过ServerEnv实例传过去 + | | + | +--__init__.py #python模块所需 + | | + | +--其他源码.py # 模块中需要的其他py源码文件 + | + +--wwwroot # 目录,存放以.ui和.dspy结束的文件,ui文件支持jinja2模板,前端控件文件,内容为json格式的控件描述文本, dspy是ahserver支持的受限python脚本,可以按照需要设置下级目录 + | + +--models # 存放数据表文件的目录 + | + +--json # 存放CRUD描述文件的目录 + | + +--pyproject.toml # pip打包文件, 其中项目名字与mymodule相同 + | + +--README.md # 模块自说明文件 + | + +--init # 模块初始化目录 + | + +--data.xlsx # 初始化数据,一个sheet一个表,一行一个记录,第一行为字>段名 + | + +--script.py # 初始化脚本 +``` +## 要求 + +* 模块中的主要逻辑用py源码实现,放在mymodule目录下 + +* 客户端业务功能放在wwwroot目录下,以.ui和.dspy后缀结束,用.ui文件遵守jinja2规范, 而.dspy文件是一个受控的脚本 + +* .dspy中不允许import模块 + +* 假设模块名为”mymodule“ +## mymodule目录 +“mymodule”为模块名称, 模块目录下存放以py结束的代码文件,其中init.py文件为必须 +在此目录下的代码中可以通过ahserver.serverenv模块的ServerEnv来引用其他模块的放进来的变量 + +### init.py的主要内容 +``` +from ahserver.serverenv import ServerEnv +from appPublic.worker import awaitify +from .x import a, b, c # 从同目录下的源码x.py中import a,b, c是协程 +from .y import x, y # 从同目录下源码y.py中import x, y是普通函数 + +def load_mymodule(): # mymodule需替换为实际的模块名字 + env = ServerEnv() + env.a = a # 脚本中用"a" 调用"a" + env.b = b # 脚本中用"b"调用"b" + env.cc = c # 脚本中用"cc"调用"c" + env.y = awaitify(y) # 将函数包装为协程 + env.x = awaitify(x) # 将函数包装为协程 +``` +注释:这里的load_mymodule中的mymodule是模块名字,而不是“mymodule”本身 + +模块的其他代码都需要放在这个目录中,而模块中所有需要在ui,dspy脚本中用到的变量均需要通过init.py函数的load_mymodule()函数传递 + +## ui, dspy可以直接使用的变量 + + +### request +aiohttp.Request实例,每个客户端请求有一个独立的Request实例 + +request._run_ns可以获得所有在.ui和.dspy源码中可以使用的变量,通过ahserver.ServerEnv 传递 + +### params_kw +DictObject(dict子类, 支持a.b方式获取属性)实例,接收到客户端传来的数据,如果有文件>,文件都保存在服务器指定的位置,params_kw中属性名保存的是其相对路径,可用FileStorage().realPath(params_kw.myfile)来获得文件在服务器中的实际路径。 + +### get_user() +来自rbac模块,协程函数,获得当前登录用户,如果用户没有登录,返回None + +### get_userorgid() +来自rbac模块,协程函数,获得当前登录用户的机构id,如果用户没有登录,返回None + +### 各个模块通过load_xxxx()放到ServerEnv()中的变量 +XXXX是模块名称 + +## pyproject.toml和README.md +编写pyproject.toml文件和README.md文件 + +## 模块中使用的编码 +模块中如果用到编码,编码需保存在appbase模块的appcodes表和appcodes_kv两个表中 +appcodes(编码表)有如下字段: +[ + "id" # str 32, 主键,可设置为数据表字段名称 + "name" # 编码名称 + "hierarchy_flg", # str 1, '0':单级编码,“1”:多级编码 +] +appcodes_kv(编码键值表)字段如下 +[ + "id", # str, 32,主键,唯一值 + "parentid" # str, 32, 一级编码为appcodes表的id, 否则为上级编码键值记录的id + “k" # str 32, 编码值 + “v” “ str 255,编码显示文本 +] + +## 数据库表定义规范 +模块中需要定义数据表要遵守一下规范 + +数据库表用一个json格式文件或数据来定义,具体规范如下 + +{ + "summary":[ # 仅一条记录 + { + "name" # 表名 + "title" # 表标题 + "primary" # 主键=“id”, 所有表均以id为主键 + "catelog" # 可选项:entity relation dimession indication + } + ], + "fields":[ # 字段 + { + "name" + "title" + "type" #可选项有:str char short long llong date time timestamp float double ddouble decimal text + "length" + "dec" + "nullable" # 可选项:yes no + "default" + "comments" # 注释 + } + ] + "indexes":[ + { + "name" # 每个索引一个,idxname不能重复一个表中 + "idxtype" # unique or index + "idxfields" # 字段名或字段名数组[f1,f1] + } + ] + “codes":[ # 如果一个字段数据可以从其他表中获得,可以通过下面的模式定义选择输入逻 +辑 + { + "field" # 字段的名字 + "table" # 数据来源表 + "valuefield" # 数据来源表值字段 + "textfield" # 数据来源表显示字段 + "cond" # 检索条件 + } + ] +] +说明: +id字段全部使用str 32类型 +字典中的length:如果type是str char float double ddouble decimal中的一个,则必为>0的>数字 +字典中的dec: 如果type是float double ddouble decimal中的一个,则必须是>0的数字 + +## 列表形式的数据表crud定义 + +当一张数据表不是树形结构的就是表形结构的crud + +表形机构表的crud的json说明 +{ + "tblname" # 表名 + "alias" # 别名,当需多个crud界面时,可用alias来生成份不同的功能 + "title" # 标题,如果不给定,使用数据表定义中的表标题 + "params":{ # crud 的参数 + "sortby" # 指定排序字段,可以多个字段,用["a desc", "b"]>形式给出按照多个字段排序,"desc“表示倒排,不给定就是正排 + "logined_userorgid" # 可选,如果表中有机构编码id,并且需要按照机构过滤 + "logined_userid" # 可选,如果表中有用户id,并且需要登录用户过滤 + "confidential_fields" # 可选,敏感字段名数组,如果表中有敏感字段,要填写 + "editor":{ # 给定编辑时form初始化参数 + # 需要参考bricks的Form控件 + "binds":[ # 比如添加事件处理 + { + "wid":"province_id", # 指定form的事件名 + "event":"changed", # 事件,比如数据变化 + "actiontype":"script", # 事件处理类型 + "target":"city_id", # 目标控件 + "script": # 脚本内容,规定用js脚本 + } + ] + }, + "browserfields": { # 列表显示的参数 + "exclouded": ["id"], # 不显示的字段列表 + "alters": { # 需要改变的字段属性 + "field1":{ # 例子:将字段field1改为选项输入 + "uitype":"code", # 设置输入类型为"code" + # uitype类型也可以用dataurl设置一个url从服务器获取数据 + # 如果设置了打他URL, datamethod和dataparams可选 + "data":[ # 设置选项数据内容 + { + "value":"v1", # value是数据值 + "text": "显示项"# text是此值对应的显示内容 + }, + ... + ] + } + } + }, + "editexclouded": [ # 编辑时不包含的字段列表 + ], + "subtables":[ # 可选,外键清单(表中存在字段指向本表主键记录) + { + "field" # 外键表字段 + "title" # 可选,不选用外键表的表标题 + "url" # 当alias定义时需要,用{{entire_url(...)方式定义 +指向表的url + "subtable" # 外键表名称 + } + ] + } +} + +## 树形结构的数据表crud +当一张数据表中存在一个父节点的字段指向本表中另条记录的主键id,那么这个表就是一个树形>结构的表 + +树形机构表的crud的json数据说明 +{ + "tblname" # 表名 + "alias" # 别名,当需多个crud界面时,可用alias来生成份不同的功能 + "uitype": "tree"# 给定uitype为"tree"指定用树状结构数据crud + "title" # 标题,如果不给定,使用数据表定义中的表标题 + "params":{ # crud 的参数 + "idField": # 必须,指定树节点的id字段 + "textField" # 指定树节点显示内容字段 + "sortby" # 指定排序字段,可以多个字段,用[a desc, b]形式>给出按照多个字段排序,"desc“表示倒排,不给定就是正排 + "confidential_fields" # 可选,敏感字段名数组,如果表中有敏感字段,要填写 + "browserfields": { # 列表显示的参数 + "alters": {} # 需要改变的字段属性 + } + "logined_userorgid" # 可选,如果表中有机构编码id,并且需要按照机构过滤 + "logined_userid" # 可选,如果表中有用户id,并且需要登录用户过滤 + "editable" # true代表可编辑,false表示不可编辑,通常给定true + "edit_exclouded_fields" # 设置不参与编辑(新增和修改)字段,数组 + "parentField" # 父节点字段 + "subtables":[ # 外键清单(表中存在字段指向本表主键记录) + { + "field" # 外键表字段 + "title" # 可选,不选用外键表的表标题 + "url" # 当alias定义时需要,用{{entire_url(...)方式定义 +指向表的url + "subtable" # 外键表名称 + } + ], + } +} + +from sqlor.dbpools import DBPools +from ahserver.serverenv import ServerEnv +# 假设当前模块名称为"mymodule" + +async def subcoro(sor, pid): + sql = "select * from appcoodes_kw where parentid=${pid}$" + r = await sor.sqlExe(sql, {'pid': pid}) + return r + +“”“ + sor.R() + sor.sqlExe() 的select语句 + 如果ns中有‘page'属性,返回数据格式如下 + { + "total" # 查询结果总记录数 + "rows": page指定的页数据, 缺省每页返回80条记录,pagerows属性可设置每页记录数 + } + 否则返回全部记录的数组 +""" +async def sqlor_op(): + db = DBPools() + env = ServerEnv() + dbname = env.get_module_dbname() + async with db.sqlorContext(dbname) as sor: + id = env.uuid() + # 事务中,如果代码或sql失败全部滚回,正常结束自动提交 + await sor.C('user', {'id':id, 'username':'john'}) + # 添加数据表“user”数据 + await sor.D('user', {'id': 'yuewfiuwe'}) + # await sor.U('user', {'id', 'email':'test@abc.com'}) + # await sor.R('user', {'id': 'yuewfiuwe'}) + return subcoro(sor, 'test_data') + +# 前端设计要求 +使用bricks框架,前台设计完成界面的每个控件的设计 +每个控件设计产出内容: +1 界面源码文件名,以".ui“结束 +2 控件名称 +3 构造参数 +4 事件处理 +5 无法用现有控件实现的功能,请用bricks的控件扩展方法,为bricks扩展控件文件保存在wwwroot目录下 + +# bricks框架简介 +## 目录 +* bricks目标 +* bricks概念 +* bricks开发方法 +* bricks运行 + +## bricks目标 +* 无前端代码或极少代码 +* 降低前端开发技术难度 +* 数据驱动 +* 常用控件包装 +* 纯json开发 + +## bricks概念 +* 控件与控件继承 +* 事件以及事件处理 +* 控件嵌套和页面组装 + +### 控件与控件继承 +bricks采用控件这一概念来描述web GUI的显示部件,每个控件均映射到一个html +的标签类型的一个javascript类。每个控件均可以实例化,并可在页面显示。 +控件分为:基本控件,容器控件。控件有内置方法,也能触发事件。 + +* 基本控件 + +基本控件是一个原子控件,不能有子控件。 + +* 容器控件 + +容器控件可以有子控件,bricks通过在容器控件添加子控件,以及在子容器控件中 +在添加子子控件的方式来构造复杂的web页面。 + +bricks已实现的控件请参看[控件清单](widgets.md) + +### 控件扩展 +如果现有的控件没法满足系统要求,bricks支持控件扩展,控件扩展需遵守: +* 控件class继承自某一个控件的class + +* 按照需求实现控件逻辑 + +* 在需要的地方用this.dispatch触发此控件的事件 + +假设需要扩展一个名字叫ExtContainer的控件 +``` +bricks.ExtContainer = class extends bricks.VBox { + constructor(opts){ + super(opts); + /* 新控件的创建代码 */ + } + ...... + /* 对象的其他方法,在需要的时候,在某个方法中,使用this.dispatch('new_event', data)方法引发事件 */ +} +bricks.register('ExtContainer', bricks.ExtContainer); /* 注册新控件 */ +``` +新控件的使用,example.ui +``` +{ + "widgettype":"ExtContainer", + "options":{ + .... + }, + "subwidgets":[ + ... + ], + "binds":[ + { + "wid":"self", + "event":"new_event", + "actiontype":"urlwidget", + "target":"some_container", + "options":{ + "url":"{{entire_url('./some_ui.ui')}}" + } + } + ] +} +``` + +### 事件以及事件处理 +每个控件都能触发所映射dom元素的事件,以及控件js类的成员函数以及祖先类的 +成员函数中dispatch出的事件 + +所以bricks控件的事件来源于两类,dom元素原生事件以及控件类中自定义的事件。 +两类事件处理方式相同。 + +### 控件表达形式 +在服务器的后台,以json文件的形式表达控件,每个ui文件定义一个控件, +对于容器控件,可以在ui文件中的subwidgets子属性中为此控件添加子控件 + +#### id属性 +字符串属性,定义控件的id,让控件可以用getWidgetById找到,如果不给定,系统会自动生成一个id +#### options属性 +字典属性,创建控件时的选项,每个控件可接受的选项请参看控件选项说明 +#### binds属性 +数组属性,定义零到多个事件响应,每个bind字典需要遵守[事件](event.md)要求 +#### 容器控件特有属性 +##### subwidgets +数组属性,定义容器控件的子控件,每个元素定义一个子控件,子控件遵守控件的数据要素要求 + +## 应用开发开发 +使用存放在服务器后台的.ui后缀的json格式文件来开发,每个.ui文件定义一个控件, 支持基本控件和容器空间。 + +关于如何书写ui文件请参考[UI文件格式](descjson.md) + +## 调试 +ui文件可以直接调试,如在服务器根目录下的test目录下有一个hello.ui文件, +就可以在浏览器中用url:https://sername/test/hello.ui调试 + +# bricks控件 +bricks内置许多的显示控件,所有显示控件都继承自JsWidget,容器控件Layout就继承自JsWidget,其他的容器HBox, VBox继承自Layout + +## 基础控件 +* [Form](form.md):输入表单控件 +自动根据options中的fields数组下的每个field的uitype属性值构造表单输入项,目前uitype属性支持的数据类型有: +** 'str' 对应的控件为: bricks.UiStr +** 'hide' 对应的控件为: bricks.UiHide +** 'tel' 对应的控件为: bricks.UiTel +** 'date' 对应的控件为: bricks.UiDate +** 'int' 对应的控件为: bricks.UiInt +** 'float' 对应的控件为: bricks.UiFloat +** 'check' 对应的控件为: bricks.UiCheck +** 'checkbox' 对应的控件为: bricks.UiCheckBox +** 'email' 对应的控件为: bricks.UiEmail +** 'file' 对应的控件为: bricks.UiFile +** 'image' 对应的控件为: bricks.UiImage +** 'code' 对应的控件为: bricks.UiCode +** 'text' 对应的控件为: bricks.UiText +** 'password' 对应的控件为: bricks.UiPassword +** 'audio' 对应的控件为: bricks.UiAudio +** 'video' 对应的控件为: bricks.UiVideo +上述控件都在[输入定义](inout.js)中注册为输入项控件 + +* [Accordion](accordion.md) bricks.Accordion +手风琴控件,支持多个标题,内容组成的控件,内容和展开和折叠 +* [AudioPlayer](audio.md) bricks.AudioPlayer +音频播放控件 + +* [ChartBar](bar.md) bricks.ChartBar +将后台数据显示为条形图表 +* [Button](button.md) bricks.Button +按钮控件 + +* [Cols](cols.md) bricks.Cols +列式排列控件,可动态填满父控件的宽度 +* [Conform](conform.md) bricks.Conform +确认控件,弹出窗口显示内容,并要求用户确认 + +* [Countdown](countdown.md) bricks.Countdown +时间倒计时控件,显示从还剩下的时间 +* [TimePassed](countdown.md) bricks.TimePassed +时间消耗控件,显示从开始计时开始所消耗的时间 +* [DataGrid](datagrid.md) bricks.DataGrid +数据表格控件 +* [DataRow](datarow.md) bricks.DataRow +数据行控件 +* [DataViewer](dataviewer.md) bricks.DataViewer +数据显示控件,DynamicColumn控件的后代控件 +* [DOCXviewer](docxviewer.md) bricks.DOCXviewer +docx文件显示控件 +* [EXCELviewer](docxviewer.md) bricks.EXCELviewer +excel文件显示控件 +* [PDFviewer](accordion.md) bricks.PDFviewer +pdf显示控件 +* [DynamicAccordion](dynamicaccordion.md) bricks.DynamicAccordion +动态手风琴控件 +* [IconBar](floaticonbar.md) bricks.IconBar +图标条控件 +* [IconTextBar](floaticonbar.md) bricks.IconTextBar +图标文本条控件 +* [FloatIconBar](floaticonbar.md) bricks.FloatIconBar +浮动图标条,平时显示一个标识图标,点击此标识图标后显示图标条 +* [FloatIconTextBar](floaticonbar.md) bricks.FloatIconTextBar +浮动图标正文条,平时显示一个标识图标,点击此图标后显示图标正文条 + +* [Html](html.md) bricks.Html +HTML控件,直接显示html内容 +* [IconbarPage](iconbarpage.md) bricks.IconbarPage +图标条页控件,显示图标条,不同的图标点击后显示图标对应的内容 + +* [NewWindow](iframe.md) bricks.NewWindow +新浏览器页签或窗口控件,浏览器创建新的窗口或页签显示url的内容 +* [Iframe](iframe.md) bricks.Iframe +Iframe控件,用于显示外部网站内容 +* [Image](image.md) bricks.Image +图像控件 +* [StatedIcon](image.md) bricks.StatedIcon +多站台图标,点击后状态改变,支持多个状态,并发出状态改变事件 +* [Icon](image.md) bricks.Icon +图标控件,支持多种图像格式url +* [BlankIcon](image.md) bricks.BlankIcon +空白图标占位控件 + +* [ChartLine](line.md) bricks.ChartLine +* [LlmIO](llm.md) bricks.LlmIO +* [LlmOut](llm.md) bricks.LlmOut +* [MarkdownViewer](markdownviewer.md) bricks.MarkdownViewer +* [MdWidget](markdownviewer.md) bricks.MdWidget +* [Menu](menu.md) bricks.Menu +* [Message](message.md) bricks.Message +* [Error](message.md) bricks.Error + +* [MultipleStateImage](multiple_state_image.md) bricks.MultipleStateImage +多状态图像控件 +* [PeriodDays](period.md) bricks.PeriodDays +日期期间控件,自动计算时间段的起始日期 +* [ChartPie](pie.md) bricks.ChartPie +饼图控件,基于echrts +* [ProgressBar](progressbar.md) bricks.ProgressBar +进度条控件 +* [SysCamera](recorder.md) bricks.SysCamera +照相控件,可拍摄照片 +* [WidgetRecorder](recorder.md) bricks.WidgetRecorder +控件视频录制控件,可录制浏览器播放的视频 +* [SysAudioRecorder](recorder.md) bricks.SysAudioRecorder +浏览器音频录制控件,用来录制音频 +* [SysVideoRecorder](recorder.md) bricks.SysVideoRecorder +浏览器视频录制控件,用来录制视频 +* [Running](running.md) bricks.Running +运行图标控件,modal模式显示正在运行,相关控件不可操作,需要在完成 任务后dismiss它 +* [Splitter](splitter.md) bricks.Splitter +分割器控件,显示水平或垂直分割线 +* [Svg](svg.md) bricks.Svg +Svg图标控件 +* [StatedSvg](svg.md) bricks.StatedSvg +带状态的svg图标控件,不同状态显示不同的图标 +* [MultipleStateIcon](svg.md) bricks.MultipleStateIcon +多状态图标控件 + +* [TabPanel](tab.md) bricks.TabPanel +页签控件 +* [Tabular](tabular.md) bricks.Tabular +数据列表形式的数据维护控件,支持数据的显示,增加,修改和删除 + +[xls2ddl](https://git.opencomputing.cn/yumoqing/xls2ddl)工具能根据数据表结构自动生成数据Tabular控件以及相关的数据维护dspy + +* [Toolbar](toolbar.md) bricks.Toolbar +工具条控件 +* [Tree](tree.md) bricks.Tree +树形控件 +* [VadText](vadtext.md) bricks.VadText +自动捕获语音并将捕获的语音发送给服务器 +* [VideoPlayer](videoplayer.md) bricks.VideoPlayer + +视频播放控件,支持浏览器支持的视频格式外,还支持m3u8流媒体和Dash流媒体, +bricks已在3parties目录中包含了所依赖的hls和dash包 + +* [Video](videoplayer.md) bricks.VideoPlayer +视频播放控件同VideoPlayer +* [WebSocket](websocket.md) bricks.WebSocket + +支持websocket + +* [WebTTS](webspeech.js.md) bricks.WebTTS +为完成控件,浏览器内置文本转语音能力 +* [WebASR](webspeech.js.md) bricks.WebASR +未完成控件,浏览器内部的语音识别能力 +* [Tooltip](widget.md) bricks.Tooltip + +Tooltip控件,不直接创建,而是在控件中添加“tip":"提示字符串“属性为控件添加Tooltip控件 + +* [Text](widget.md) bricks.Text + +文本控件 + +* [Title1](widget.md) bricks.Title1 + +第一号标题 + +* [Title2](widget.md) bricks.Title2 + +第二号标题 + +* [Title3](widget.md) bricks.Title3 + +第三号标题 + +* [Title4](widget.md) bricks.Title4 + +第四号标题 + +* [Title5](widget.md) bricks.Title5 + +第五号标题 + +* [Title6](widget.md) bricks.Title6 + +第六号标题 + +* [Wterm](wterm.md) bricks.Wterm + +xterm.js在bricks中的实现 + +## 容器类控件 +* [VScrollPanel](accordion.md) bricks.VScrollPanel +垂直滚动容器,需要设置固定的高度或占满全部父容器高度 +* [HScrollPanel](accordion.md) bricks.HScrollPanel +水平滚动容器,需要设置固定的宽度或占满全部父容器宽度 +* [Popup](accordion.md) bricks.Popup +弹出容器,置于当前全部控件最上面 +* [PopupWindow](accordion.md) bricks.PopupWindow +弹出窗口,置于当前全部控件最上面 +* [HBox](accordion.md) bricks.HBox +水平扩展容器,全部子控件水平排放 +* [VBox](accordion.md) bricks.VBox +垂直扩展容器,全部子控件垂直排放 +* [Filler](accordion.md) bricks.Filler +占满父容器剩余控件,如果父容器有多个Filler控件,则平均分配剩余控件,Filler容器下可添加子控件 + +* [DynamicColumn](dynamiccolumn.md) bricks.DynamicColumn +子控件需要设置固定宽度,动态从左到右,从上到下排列子控件 + +* [ResponsableBox](layout.md) bricks.ResponsableBox +自适应容器,当宽度大则水平排列子控件,而高度大时则水平排列子控件, 并能根据宽高变化自动改变。 + +* [Modal](modal.md) bricks.Modal +modal容器 +dspy脚本可用的变量 +ahserver/globalEnv.py程序中推送到ServerEnv中的变量 +各个模块init_mymodule函数推送的变量 +request +``` +info(f'{params_kw=}, {request.url=}, {request.path=}') +def vcode(): + codes = [ str(random.randint(0, 10)) for i in range(6) ] + return ''.join(codes) + +db = DBPools() + +async with db.sqlorContext('sage') as sor: + ns = { + 'id':params_kw.codeid, + 'code':vcode() + } + r = await sor.R('validatecode', {'id':params_kw.codeid}) + if len(r) == 0: + await sor.C('validatecode', ns.copy()) + else: + ns = r[0] + + ns = DictObject(**ns) + x = await sms_engine.send_validate_code(params_kw.cell_no, ns.code) + info(f'{params_kw.cell_no}, {ns.code=}, send_validatecode() return {x}') + return UiMessage(title='SMS', message=f'validate code send to {params_kw.cell_no}') + + +return UiError(title='Error', message=f'{params_kw.cell_no} generate validate code error') +``` +## ui文件例子 +``` +{ + "widgettype":"VBox", + "options":{ + "width":"100%", + "height":"100%" + }, + "subwidgets":[ + { + "widgettype":"Filler", + "options":{}, + "subwidgets":[ + { + "id":"dialog", + "widgettype":"LlmDialog", + "options":{ + "models":[{ + "url":"{{entire_url('llm/doubao.llm')}}", + "mapi":"chat", + "icon":"{{entire_url('imgs/doubao.png')}}", + "model":"ep-20240614051803-shld5" + } + ] + } + } + ] + }, + { + "widgettype":"HBox", + "options":{ + "cheight":5 + }, + "subwidgets":[ + { + "id":"prompt", + "widgettype":"UiAudioText", + "options":{ + "css":"filler", + "upload_url":"https://sage.opencomputing.cn/stt/generate", + "name":"prompt" + } + }, + { + "widgettype":"IconBar", + "id":"prompt_bar", + "options":{ + "tools":[ + { + "name":"submit", + "icon":"{{entire_url('imgs/submit.png')}}" + } + ] + } + } + ] + } + ], + "binds":[ + { + "wid":"prompt_bar", + "event":"submit", + "actiontype":"script", + "target":"dialog", + "script":"console.log(params); this.set_prompt(params.prompt);", + "datawidget":"prompt", + "datamethod":"getValue" + }, + { + "wid":"prompt_bar", + "event":"submit", + "actiontype":"script", + "target":"prompt", + "script":"this.setValue('')" + } + ] +} +``` diff --git a/req/.pricing.req.swp b/req/.pricing.req.swp deleted file mode 100644 index 4d53c431e44f0ebdcc1d983b09279245121a304d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2K~ED=5XT=JO;DppFQ{i|0Zq`0XJd>fjfuusX$u>%1zHbWv_LCc+0q7EDrMV3 zLIH`ikkrz4x5mVipTf&~Z+E@alV@l977|T}2M&g0Hkp0X_h$Yx^V_{N?KAg-+jo11 z`v(bJ=LvcI^``WbJnepR?-H4QF=_Aq^O6FguqQC$>yyU){^=VY>6naHAn2O%O$1#Y zX(Z_Nfj{Y*n36`Mz-T}C$E4vl5G_PacKx+FA8|nfNB{{S0VIF~kN^@u0!RP} zAOR$R1Wq9VkC%{JJ%r4G*}wlEe*gb*j*u^455c~jCFBv*SomnXzRg zfCP{L5=jFjC7I9DO!(M z>9X*7rb_EOe0!bcv&L$fwK6REmM_m!t!Ct+p)ue1cz+*oxP3!ZnJG9;udn}Qmtpo_Pb%iN0 z)~LdrtFm26PadWAl52L6@@L3mx&{jYYcyRS2TT(!oujyn6sjQzQSTPsx8~qIA1oB`;T-ybzVV&>+v3tX$gI)M!1yQi?bsP9L2&#_qZEijm*P2HYzE diff --git a/req/txt b/req/txt new file mode 100644 index 0000000..6e54f06 --- /dev/null +++ b/req/txt @@ -0,0 +1,712 @@ +定价模块,要求 +1)orgid机构id用来隔离不同机构 +2)每个定价按有效时间期间可以有多套定价,但一个资源某一天只有一套定价 +3)如果一个资源是其他一到多个资源作为此资源的部件,其部件的定价直接引用原资源定价,而非重新定义 +4)设计定价类型,设计一套计费规则,针对具体资源只需按照规则给定成本和价格 +5)要支持tokens消耗类型的计费(100万/K为计费单位),包年包月模式的计费 +模块名字:pricing +要求生成一键生成整个模块目录及文件的shell.sh +按照以下规范要求: + +## 模块目录结构 +模块名称为“mymodule", 以下为mymodule模块的目录文件结构 +``` +mymodule + | + +--mymodule # 存放模块的主要逻辑py代码 + | | + | +--init.py # 模块初始化脚本,需要定义一个load_mymodule()函数,此函数将在ui和dspy文件中用到的模块变量通过ServerEnv实例传过去 + | | + | +--__init__.py #python模块所需 + | | + | +--其他源码.py # 模块中需要的其他py源码文件 + | + +--wwwroot # 目录,存放以.ui和.dspy结束的文件,ui文件支持jinja2模板,前端控件文件,内容为json格式的控件描述文本, dspy是ahserver支持的受限python脚本,可以按照需要设置下级目录 + | + +--models # 存放数据表文件的目录 + | + +--json # 存放CRUD描述文件的目录 + | + +--pyproject.toml # pip打包文件, 其中项目名字与mymodule相同 + | + +--README.md # 模块自说明文件 + | + +--init # 模块初始化目录 + | + +--data.xlsx # 初始化数据,一个sheet一个表,一行一个记录,第一行为字>段名 + | + +--script.py # 初始化脚本 +``` +## 要求 + +* 模块中的主要逻辑用py源码实现,放在mymodule目录下 + +* 客户端业务功能放在wwwroot目录下,以.ui和.dspy后缀结束,用.ui文件遵守jinja2规范, 而.dspy文件是一个受控的脚本 + +* .dspy中不允许import模块 + +* 假设模块名为”mymodule“ +## mymodule目录 +“mymodule”为模块名称, 模块目录下存放以py结束的代码文件,其中init.py文件为必须 +在此目录下的代码中可以通过ahserver.serverenv模块的ServerEnv来引用其他模块的放进来的变量 + +### init.py的主要内容 +``` +from ahserver.serverenv import ServerEnv +from appPublic.worker import awaitify +from .x import a, b, c # 从同目录下的源码x.py中import a,b, c是协程 +from .y import x, y # 从同目录下源码y.py中import x, y是普通函数 + +def load_mymodule(): # mymodule需替换为实际的模块名字 + env = ServerEnv() + env.a = a # 脚本中用"a" 调用"a" + env.b = b # 脚本中用"b"调用"b" + env.cc = c # 脚本中用"cc"调用"c" + env.y = awaitify(y) # 将函数包装为协程 + env.x = awaitify(x) # 将函数包装为协程 +``` +注释:这里的load_mymodule中的mymodule是模块名字,而不是“mymodule”本身 + +模块的其他代码都需要放在这个目录中,而模块中所有需要在ui,dspy脚本中用到的变量均需要通过init.py函数的load_mymodule()函数传递 + +## ui, dspy可以直接使用的变量 + + +### request +aiohttp.Request实例,每个客户端请求有一个独立的Request实例 + +request._run_ns可以获得所有在.ui和.dspy源码中可以使用的变量,通过ahserver.ServerEnv 传递 + +### params_kw +DictObject(dict子类, 支持a.b方式获取属性)实例,接收到客户端传来的数据,如果有文件>,文件都保存在服务器指定的位置,params_kw中属性名保存的是其相对路径,可用FileStorage().realPath(params_kw.myfile)来获得文件在服务器中的实际路径。 + +### get_user() +来自rbac模块,协程函数,获得当前登录用户,如果用户没有登录,返回None + +### get_userorgid() +来自rbac模块,协程函数,获得当前登录用户的机构id,如果用户没有登录,返回None + +### 各个模块通过load_xxxx()放到ServerEnv()中的变量 +XXXX是模块名称 + +## pyproject.toml和README.md +编写pyproject.toml文件和README.md文件 + +## 模块中使用的编码 +模块中如果用到编码,编码需保存在appbase模块的appcodes表和appcodes_kv两个表中 +appcodes(编码表)有如下字段: +[ + "id" # str 32, 主键,可设置为数据表字段名称 + "name" # 编码名称 + "hierarchy_flg", # str 1, '0':单级编码,“1”:多级编码 +] +appcodes_kv(编码键值表)字段如下 +[ + "id", # str, 32,主键,唯一值 + "parentid" # str, 32, 一级编码为appcodes表的id, 否则为上级编码键值记录的id + “k" # str 32, 编码值 + “v” “ str 255,编码显示文本 +] + +## 数据库表定义规范 +模块中需要定义数据表要遵守一下规范 + +数据库表用一个json格式文件或数据来定义,具体规范如下 + +{ + "summary":[ # 仅一条记录 + { + "name" # 表名 + "title" # 表标题 + "primary" # 主键=“id”, 所有表均以id为主键 + "catelog" # 可选项:entity relation dimession indication + } + ], + "fields":[ # 字段 + { + "name" + "title" + "type" #可选项有:str char short long llong date time timestamp float double ddouble decimal text + "length" + "dec" + "nullable" # 可选项:yes no + "default" + "comments" # 注释 + } + ] + "indexes":[ + { + "name" # 每个索引一个,idxname不能重复一个表中 + "idxtype" # unique or index + "idxfields" # 字段名或字段名数组[f1,f1] + } + ] + “codes":[ # 如果一个字段数据可以从其他表中获得,可以通过下面的模式定义选择输入逻 +辑 + { + "field" # 字段的名字 + "table" # 数据来源表 + "valuefield" # 数据来源表值字段 + "textfield" # 数据来源表显示字段 + "cond" # 检索条件 + } + ] +] +说明: +id字段全部使用str 32类型 +字典中的length:如果type是str char float double ddouble decimal中的一个,则必为>0的>数字 +字典中的dec: 如果type是float double ddouble decimal中的一个,则必须是>0的数字 + +## 列表形式的数据表crud定义 + +当一张数据表不是树形结构的就是表形结构的crud + +表形机构表的crud的json说明 +{ + "tblname" # 表名 + "alias" # 别名,当需多个crud界面时,可用alias来生成份不同的功能 + "title" # 标题,如果不给定,使用数据表定义中的表标题 + "params":{ # crud 的参数 + "sortby" # 指定排序字段,可以多个字段,用["a desc", "b"]>形式给出按照多个字段排序,"desc“表示倒排,不给定就是正排 + "logined_userorgid" # 可选,如果表中有机构编码id,并且需要按照机构过滤 + "logined_userid" # 可选,如果表中有用户id,并且需要登录用户过滤 + "confidential_fields" # 可选,敏感字段名数组,如果表中有敏感字段,要填写 + "editor":{ # 给定编辑时form初始化参数 + # 需要参考bricks的Form控件 + "binds":[ # 比如添加事件处理 + { + "wid":"province_id", # 指定form的事件名 + "event":"changed", # 事件,比如数据变化 + "actiontype":"script", # 事件处理类型 + "target":"city_id", # 目标控件 + "script": # 脚本内容,规定用js脚本 + } + ] + }, + "browserfields": { # 列表显示的参数 + "exclouded": ["id"], # 不显示的字段列表 + "alters": { # 需要改变的字段属性 + "field1":{ # 例子:将字段field1改为选项输入 + "uitype":"code", # 设置输入类型为"code" + # uitype类型也可以用dataurl设置一个url从服务器获取数据 + # 如果设置了打他URL, datamethod和dataparams可选 + "data":[ # 设置选项数据内容 + { + "value":"v1", # value是数据值 + "text": "显示项"# text是此值对应的显示内容 + }, + ... + ] + } + } + }, + "editexclouded": [ # 编辑时不包含的字段列表 + ], + "subtables":[ # 可选,外键清单(表中存在字段指向本表主键记录) + { + "field" # 外键表字段 + "title" # 可选,不选用外键表的表标题 + "url" # 当alias定义时需要,用{{entire_url(...)方式定义 +指向表的url + "subtable" # 外键表名称 + } + ] + } +} + +## 树形结构的数据表crud +当一张数据表中存在一个父节点的字段指向本表中另条记录的主键id,那么这个表就是一个树形>结构的表 + +树形机构表的crud的json数据说明 +{ + "tblname" # 表名 + "alias" # 别名,当需多个crud界面时,可用alias来生成份不同的功能 + "uitype": "tree"# 给定uitype为"tree"指定用树状结构数据crud + "title" # 标题,如果不给定,使用数据表定义中的表标题 + "params":{ # crud 的参数 + "idField": # 必须,指定树节点的id字段 + "textField" # 指定树节点显示内容字段 + "sortby" # 指定排序字段,可以多个字段,用[a desc, b]形式>给出按照多个字段排序,"desc“表示倒排,不给定就是正排 + "confidential_fields" # 可选,敏感字段名数组,如果表中有敏感字段,要填写 + "browserfields": { # 列表显示的参数 + "alters": {} # 需要改变的字段属性 + } + "logined_userorgid" # 可选,如果表中有机构编码id,并且需要按照机构过滤 + "logined_userid" # 可选,如果表中有用户id,并且需要登录用户过滤 + "editable" # true代表可编辑,false表示不可编辑,通常给定true + "edit_exclouded_fields" # 设置不参与编辑(新增和修改)字段,数组 + "parentField" # 父节点字段 + "subtables":[ # 外键清单(表中存在字段指向本表主键记录) + { + "field" # 外键表字段 + "title" # 可选,不选用外键表的表标题 + "url" # 当alias定义时需要,用{{entire_url(...)方式定义 +指向表的url + "subtable" # 外键表名称 + } + ], + } +} + +## 数据库操作规范 +from sqlor.dbpools import DBPools +from ahserver.serverenv import ServerEnv +# 假设当前模块名称为"mymodule" + +async def subcoro(sor, pid): + sql = "select * from appcoodes_kw where parentid=${pid}$" + r = await sor.sqlExe(sql, {'pid': pid}) + return r + +“”“ + sor.R() + sor.sqlExe() 的select语句 + 如果ns中有‘page'属性,返回数据格式如下 + { + "total" # 查询结果总记录数 + "rows": page指定的页数据, 缺省每页返回80条记录,pagerows属性可设置每页记录数 + } + 否则返回全部记录的数组 +""" +async def sqlor_op(): + db = DBPools() + env = ServerEnv() + dbname = env.get_module_dbname() + async with db.sqlorContext(dbname) as sor: + id = env.uuid() + # 事务中,如果代码或sql失败全部滚回,正常结束自动提交 + await sor.C('user', {'id':id, 'username':'john'}) + # 添加数据表“user”数据 + await sor.D('user', {'id': 'yuewfiuwe'}) + # await sor.U('user', {'id', 'email':'test@abc.com'}) + # await sor.R('user', {'id': 'yuewfiuwe'}) + return subcoro(sor, 'test_data') + +# bricks框架简介 +## 目录 +* bricks目标 +* bricks概念 +* bricks开发方法 +* bricks运行 + +## bricks目标 +* 无前端代码或极少代码 +* 降低前端开发技术难度 +* 数据驱动 +* 常用控件包装 +* 纯json开发 + +## bricks概念 +* 控件与控件继承 +* 事件以及事件处理 +* 控件嵌套和页面组装 + +### 控件与控件继承 +bricks采用控件这一概念来描述web GUI的显示部件,每个控件均映射到一个html +的标签类型的一个javascript类。每个控件均可以实例化,并可在页面显示。 +控件分为:基本控件,容器控件。控件有内置方法,也能触发事件。 + +* 基本控件 + +基本控件是一个原子控件,不能有子控件。 + +* 容器控件 + +容器控件可以有子控件,bricks通过在容器控件添加子控件,以及在子容器控件中 +在添加子子控件的方式来构造复杂的web页面。 + +bricks已实现的控件请参看[控件清单](widgets.md) + +### 控件扩展 +如果现有的控件没法满足系统要求,bricks支持控件扩展,控件扩展需遵守: +* 控件class继承自某一个控件的class + +* 按照需求实现控件逻辑 + +* 在需要的地方用this.dispatch触发此控件的事件 + +假设需要扩展一个名字叫ExtContainer的控件 +``` +bricks.ExtContainer = class extends bricks.VBox { + constructor(opts){ + super(opts); + /* 新控件的创建代码 */ + } + ...... + /* 对象的其他方法,在需要的时候,在某个方法中,使用this.dispatch('new_event', data)方法引发事件 */ +} +bricks.register('ExtContainer', bricks.ExtContainer); /* 注册新控件 */ +``` +新控件的使用,example.ui +``` +{ + "widgettype":"ExtContainer", + "options":{ + .... + }, + "subwidgets":[ + ... + ], + "binds":[ + { + "wid":"self", + "event":"new_event", + "actiontype":"urlwidget", + "target":"some_container", + "options":{ + "url":"{{entire_url('./some_ui.ui')}}" + } + } + ] +} +``` + +### 事件以及事件处理 +每个控件都能触发所映射dom元素的事件,以及控件js类的成员函数以及祖先类的 +成员函数中dispatch出的事件 + +所以bricks控件的事件来源于两类,dom元素原生事件以及控件类中自定义的事件。 +两类事件处理方式相同。 + +### 控件表达形式 +在服务器的后台,以json文件的形式表达控件,每个ui文件定义一个控件, +对于容器控件,可以在ui文件中的subwidgets子属性中为此控件添加子控件 + +#### id属性 +字符串属性,定义控件的id,让控件可以用getWidgetById找到,如果不给定,系统会自动生成一个id +#### options属性 +字典属性,创建控件时的选项,每个控件可接受的选项请参看控件选项说明 +#### binds属性 +数组属性,定义零到多个事件响应,每个bind字典需要遵守[事件](event.md)要求 +#### 容器控件特有属性 +##### subwidgets +数组属性,定义容器控件的子控件,每个元素定义一个子控件,子控件遵守控件的数据要素要求 + +## 应用开发开发 +使用存放在服务器后台的.ui后缀的json格式文件来开发,每个.ui文件定义一个控件, 支持基本控件和容器空间。 + +关于如何书写ui文件请参考[UI文件格式](descjson.md) + +## 调试 +ui文件可以直接调试,如在服务器根目录下的test目录下有一个hello.ui文件, +就可以在浏览器中用url:https://sername/test/hello.ui调试 + +# bricks控件 +bricks内置许多的显示控件,所有显示控件都继承自JsWidget,容器控件Layout就继承自JsWidget,其他的容器HBox, VBox继承自Layout + +## 基础控件 +* [Form](form.md):输入表单控件 +自动根据options中的fields数组下的每个field的uitype属性值构造表单输入项,目前uitype属性支持的数据类型有: +** 'str' 对应的控件为: bricks.UiStr +** 'hide' 对应的控件为: bricks.UiHide +** 'tel' 对应的控件为: bricks.UiTel +** 'date' 对应的控件为: bricks.UiDate +** 'int' 对应的控件为: bricks.UiInt +** 'float' 对应的控件为: bricks.UiFloat +** 'check' 对应的控件为: bricks.UiCheck +** 'checkbox' 对应的控件为: bricks.UiCheckBox +** 'email' 对应的控件为: bricks.UiEmail +** 'file' 对应的控件为: bricks.UiFile +** 'image' 对应的控件为: bricks.UiImage +** 'code' 对应的控件为: bricks.UiCode +** 'text' 对应的控件为: bricks.UiText +** 'password' 对应的控件为: bricks.UiPassword +** 'audio' 对应的控件为: bricks.UiAudio +** 'video' 对应的控件为: bricks.UiVideo +上述控件都在[输入定义](inout.js)中注册为输入项控件 + +* [Accordion](accordion.md) bricks.Accordion +手风琴控件,支持多个标题,内容组成的控件,内容和展开和折叠 +* [AudioPlayer](audio.md) bricks.AudioPlayer +音频播放控件 + +* [ChartBar](bar.md) bricks.ChartBar +将后台数据显示为条形图表 +* [Button](button.md) bricks.Button +按钮控件 + +* [Cols](cols.md) bricks.Cols +列式排列控件,可动态填满父控件的宽度 +* [Conform](conform.md) bricks.Conform +确认控件,弹出窗口显示内容,并要求用户确认 + +* [Countdown](countdown.md) bricks.Countdown +时间倒计时控件,显示从还剩下的时间 +* [TimePassed](countdown.md) bricks.TimePassed +时间消耗控件,显示从开始计时开始所消耗的时间 +* [DataGrid](datagrid.md) bricks.DataGrid +数据表格控件 +* [DataRow](datarow.md) bricks.DataRow +数据行控件 +* [DataViewer](dataviewer.md) bricks.DataViewer +数据显示控件,DynamicColumn控件的后代控件 +* [DOCXviewer](docxviewer.md) bricks.DOCXviewer +docx文件显示控件 +* [EXCELviewer](docxviewer.md) bricks.EXCELviewer +excel文件显示控件 +* [PDFviewer](accordion.md) bricks.PDFviewer +pdf显示控件 +* [DynamicAccordion](dynamicaccordion.md) bricks.DynamicAccordion +动态手风琴控件 +* [IconBar](floaticonbar.md) bricks.IconBar +图标条控件 +* [IconTextBar](floaticonbar.md) bricks.IconTextBar +图标文本条控件 +* [FloatIconBar](floaticonbar.md) bricks.FloatIconBar +浮动图标条,平时显示一个标识图标,点击此标识图标后显示图标条 +* [FloatIconTextBar](floaticonbar.md) bricks.FloatIconTextBar +浮动图标正文条,平时显示一个标识图标,点击此图标后显示图标正文条 + +* [Html](html.md) bricks.Html +HTML控件,直接显示html内容 +* [IconbarPage](iconbarpage.md) bricks.IconbarPage +图标条页控件,显示图标条,不同的图标点击后显示图标对应的内容 + +* [NewWindow](iframe.md) bricks.NewWindow +新浏览器页签或窗口控件,浏览器创建新的窗口或页签显示url的内容 +* [Iframe](iframe.md) bricks.Iframe +Iframe控件,用于显示外部网站内容 +* [Image](image.md) bricks.Image +图像控件 +* [StatedIcon](image.md) bricks.StatedIcon +多站台图标,点击后状态改变,支持多个状态,并发出状态改变事件 +* [Icon](image.md) bricks.Icon +图标控件,支持多种图像格式url +* [BlankIcon](image.md) bricks.BlankIcon +空白图标占位控件 + +* [ChartLine](line.md) bricks.ChartLine +* [LlmIO](llm.md) bricks.LlmIO +* [LlmOut](llm.md) bricks.LlmOut +* [MarkdownViewer](markdownviewer.md) bricks.MarkdownViewer +* [MdWidget](markdownviewer.md) bricks.MdWidget +* [Menu](menu.md) bricks.Menu +* [Message](message.md) bricks.Message +* [Error](message.md) bricks.Error + +* [MultipleStateImage](multiple_state_image.md) bricks.MultipleStateImage +多状态图像控件 +* [PeriodDays](period.md) bricks.PeriodDays +日期期间控件,自动计算时间段的起始日期 +* [ChartPie](pie.md) bricks.ChartPie +饼图控件,基于echrts +* [ProgressBar](progressbar.md) bricks.ProgressBar +进度条控件 +* [SysCamera](recorder.md) bricks.SysCamera +照相控件,可拍摄照片 +* [WidgetRecorder](recorder.md) bricks.WidgetRecorder +控件视频录制控件,可录制浏览器播放的视频 +* [SysAudioRecorder](recorder.md) bricks.SysAudioRecorder +浏览器音频录制控件,用来录制音频 +* [SysVideoRecorder](recorder.md) bricks.SysVideoRecorder +浏览器视频录制控件,用来录制视频 +* [Running](running.md) bricks.Running +运行图标控件,modal模式显示正在运行,相关控件不可操作,需要在完成 任务后dismiss它 +* [Splitter](splitter.md) bricks.Splitter +分割器控件,显示水平或垂直分割线 +* [Svg](svg.md) bricks.Svg +Svg图标控件 +* [StatedSvg](svg.md) bricks.StatedSvg +带状态的svg图标控件,不同状态显示不同的图标 +* [MultipleStateIcon](svg.md) bricks.MultipleStateIcon +多状态图标控件 + +* [TabPanel](tab.md) bricks.TabPanel +页签控件 +* [Tabular](tabular.md) bricks.Tabular +数据列表形式的数据维护控件,支持数据的显示,增加,修改和删除 + +[xls2ddl](https://git.opencomputing.cn/yumoqing/xls2ddl)工具能根据数据表结构自动生成数据Tabular控件以及相关的数据维护dspy + +* [Toolbar](toolbar.md) bricks.Toolbar +工具条控件 +* [Tree](tree.md) bricks.Tree +树形控件 +* [VadText](vadtext.md) bricks.VadText +自动捕获语音并将捕获的语音发送给服务器 +* [VideoPlayer](videoplayer.md) bricks.VideoPlayer + +视频播放控件,支持浏览器支持的视频格式外,还支持m3u8流媒体和Dash流媒体, +bricks已在3parties目录中包含了所依赖的hls和dash包 + +* [Video](videoplayer.md) bricks.VideoPlayer +视频播放控件同VideoPlayer +* [WebSocket](websocket.md) bricks.WebSocket + +支持websocket + +* [WebTTS](webspeech.js.md) bricks.WebTTS +为完成控件,浏览器内置文本转语音能力 +* [WebASR](webspeech.js.md) bricks.WebASR +未完成控件,浏览器内部的语音识别能力 +* [Tooltip](widget.md) bricks.Tooltip + +Tooltip控件,不直接创建,而是在控件中添加“tip":"提示字符串“属性为控件添加Tooltip控件 + +* [Text](widget.md) bricks.Text + +文本控件 + +* [Title1](widget.md) bricks.Title1 + +第一号标题 + +* [Title2](widget.md) bricks.Title2 + +第二号标题 + +* [Title3](widget.md) bricks.Title3 + +第三号标题 + +* [Title4](widget.md) bricks.Title4 + +第四号标题 + +* [Title5](widget.md) bricks.Title5 + +第五号标题 + +* [Title6](widget.md) bricks.Title6 + +第六号标题 + +* [Wterm](wterm.md) bricks.Wterm + +xterm.js在bricks中的实现 + +## 容器类控件 +* [VScrollPanel](accordion.md) bricks.VScrollPanel +垂直滚动容器,需要设置固定的高度或占满全部父容器高度 +* [HScrollPanel](accordion.md) bricks.HScrollPanel +水平滚动容器,需要设置固定的宽度或占满全部父容器宽度 +* [Popup](accordion.md) bricks.Popup +弹出容器,置于当前全部控件最上面 +* [PopupWindow](accordion.md) bricks.PopupWindow +弹出窗口,置于当前全部控件最上面 +* [HBox](accordion.md) bricks.HBox +水平扩展容器,全部子控件水平排放 +* [VBox](accordion.md) bricks.VBox +垂直扩展容器,全部子控件垂直排放 +* [Filler](accordion.md) bricks.Filler +占满父容器剩余控件,如果父容器有多个Filler控件,则平均分配剩余控件,Filler容器下可添加子控件 + +* [DynamicColumn](dynamiccolumn.md) bricks.DynamicColumn +子控件需要设置固定宽度,动态从左到右,从上到下排列子控件 + +* [ResponsableBox](layout.md) bricks.ResponsableBox +自适应容器,当宽度大则水平排列子控件,而高度大时则水平排列子控件, 并能根据宽高变化自动改变。 + +* [Modal](modal.md) bricks.Modal +modal容器 + +## ui文件例子 +``` +{ + "widgettype":"VBox", + "options":{ + "width":"100%", + "height":"100%" + }, + "subwidgets":[ + { + "widgettype":"Filler", + "options":{}, + "subwidgets":[ + { + "id":"dialog", + "widgettype":"LlmDialog", + "options":{ + "models":[{ + "url":"{{entire_url('llm/doubao.llm')}}", + "mapi":"chat", + "icon":"{{entire_url('imgs/doubao.png')}}", + "model":"ep-20240614051803-shld5" + } + ] + } + } + ] + }, + { + "widgettype":"HBox", + "options":{ + "cheight":5 + }, + "subwidgets":[ + { + "id":"prompt", + "widgettype":"UiAudioText", + "options":{ + "css":"filler", + "upload_url":"https://sage.opencomputing.cn/stt/generate", + "name":"prompt" + } + }, + { + "widgettype":"IconBar", + "id":"prompt_bar", + "options":{ + "tools":[ + { + "name":"submit", + "icon":"{{entire_url('imgs/submit.png')}}" + } + ] + } + } + ] + } + ], + "binds":[ + { + "wid":"prompt_bar", + "event":"submit", + "actiontype":"script", + "target":"dialog", + "script":"console.log(params); this.set_prompt(params.prompt);", + "datawidget":"prompt", + "datamethod":"getValue" + }, + { + "wid":"prompt_bar", + "event":"submit", + "actiontype":"script", + "target":"prompt", + "script":"this.setValue('')" + } + ] +} +``` +## dspy文件例子 +dspy脚本可用的变量 +ahserver/globalEnv.py程序中推送到ServerEnv中的变量 +各个模块init_mymodule函数推送的变量 +request +``` +info(f'{params_kw=}, {request.url=}, {request.path=}') +def vcode(): + codes = [ str(random.randint(0, 10)) for i in range(6) ] + return ''.join(codes) + +db = DBPools() + +async with db.sqlorContext('sage') as sor: + ns = { + 'id':params_kw.codeid, + 'code':vcode() + } + r = await sor.R('validatecode', {'id':params_kw.codeid}) + if len(r) == 0: + await sor.C('validatecode', ns.copy()) + else: + ns = r[0] + + ns = DictObject(**ns) + x = await sms_engine.send_validate_code(params_kw.cell_no, ns.code) + info(f'{params_kw.cell_no}, {ns.code=}, send_validatecode() return {x}') + return UiMessage(title='SMS', message=f'validate code send to {params_kw.cell_no}') + + +return UiError(title='Error', message=f'{params_kw.cell_no} generate validate code error') +```