diff --git "a/doc/\345\212\237\350\203\275\346\261\240\350\256\276\350\256\241\350\277\207\347\250\213.md" "b/doc/\345\212\237\350\203\275\346\261\240\350\256\276\350\256\241\350\277\207\347\250\213.md" new file mode 100644 index 0000000000000000000000000000000000000000..73a4f1732643764b038ffc9d5ad0d74e30c57459 --- /dev/null +++ "b/doc/\345\212\237\350\203\275\346\261\240\350\256\276\350\256\241\350\277\207\347\250\213.md" @@ -0,0 +1,189 @@ + + +# 简述 + +本工具需要提供非常多的数据处理相关功能,这些功能无非是让用户做一些必要的选择,确定后,并应用到数据中。并且能生成相应的操作代码。 + +但是,如果每个功能都需要作者进行独立开发,或者说每个功能都需要单独制作界面,是非常耗时耗力。 + +功能池的作用主要在于,让开发者只需要定义py处理函数,功能就能自动生成对于的操作界面。提供快速开发功能的功效。 + + + + + +# 思路 + +app 启动后,读取指定目录的符合条件的py文件 + +解析里面定义的函数,只要符合条件(比如打上特定装饰器的函数),则提取相关信息(功能名、uid等) + +界面获取这些信息后,在"功能池"页面,为每个功能生成一个按钮(名字是功能名) + +当用户点击某个功能按钮时,界面把id发送给后台 + +后台通过id获取定义的函数参数信息,生成对应的json数据,并返回界面 + +界面根据json数据,生成操作界面。比如,参数是字符串,那么界面会生成一个文本输入框;参数是列表,界面生成一个下拉选择框等等 + + + + + + + +# api 数据交互流程 + +启动时,前端 get 后台功能数据,后台返回如下: + +api/cus_fun/desc + +```json +[{"function_name": "功能A", "uid": "test001"},{"function_name": "功能B", "uid": "test002"}] +``` + +定义: + +```typescript +export interface CusFunDesc { + function_name: string; + uid: string; +} + +``` + + + + + + + + + +用户点选某个功能按钮时,前端 get 后端,发送如下: + +api/cus_fun/model + +```json +{"uid":"test001"} +``` + + + + + +后端检索 id ,执行对应的 json ui model 函数,序列化为对应的json ,返回如下: + +```json + { + "contents": [ + { + "defaultValue": null, + "source": "data_columns", + "title": "请选择列", + "type": "select", + "var_name": "org_name" + }, + { + "defaultValue": null, + "source": null, + "title": "新列名字", + "type": "input", + "var_name": "new_name" + } + ], + "function_name": "修改列名", + "uid": "test001" + } +``` + +定义: + +```typescript +export interface CusFunUIModel { + contents: Content[]; + function_name: string; + uid: string; +} + +export interface Content { + defaultValue: object; + source: string | object; + title: string; + type: string; + var_name: string; +} + +``` + + + + + + + +前端按需生成界面,用户填写数据后,点击按钮 + +前端发送数据到后台,如下: + +api/cus_fun/input + +```json +{ + "contents": [ + { + "content": { + "defaultValue": null, + "source": "data_columns", + "title": "请选择列", + "type": "select", + "var_name": "org_name" + }, + "input": "姓名" + }, + { + "content": { + "defaultValue": null, + "source": null, + "title": "新列名字", + "type": "input", + "var_name": "new_name" + }, + "input": "名字" + } + ], + "uid": "test001" +} +``` + + + +定义: + +```typescript +export interface CusFunInputRet { + contents: InputRet[]; + uid: string; +} + +export interface InputRet { + content: Content; + input: any; +} + + + +``` + + + + + + + + + + + + + diff --git a/py/main.py b/py/main.py index a894e3007815b2b63a26b8ad7cddaf8d2099bc63..af7c4af1ec3e10ada8ca5312747fd341e85ba261 100644 --- a/py/main.py +++ b/py/main.py @@ -6,18 +6,18 @@ import numpy as np import json import traceback import sys +from src.cusFuns.core.FunsPool import auto_register -from werkzeug.exceptions import default_exceptions from src.helper.utils import json_converter from src.dataModel.pandasCmd import PandasCmd from src.core.Proxy import ProxyManager import webbrowser -# from threading import Timer import os m_proxys = ProxyManager() +auto_register(r'src/cusFuns') app = Flask(__name__, template_folder='./web/templates', @@ -164,6 +164,42 @@ def df2json(df: pd.DataFrame, head_tail_num=10): return ret +@app.route('/api/cus_fun', methods=['post']) +def cus_fun(): + param = get_data_from_post() + data = param['data'] + + m_proxys.run_cus_fun(data) + + return df2json(m_proxys.get_df_data()) + + +@app.route('/api/cus_fun/desc') +def get_cus_funcs_desc(): + ret = m_proxys.get_cus_funcs_desc() + ret = flask.json.dumps(ret, default=json_converter) + return ret + + +@app.route('/api/cus_fun/model', methods=['get']) +def get_cus_funcs_ui_model(): + + uid = str(request.args.get('uid')) + + ret = m_proxys.get_ui_model(uid) + ret = flask.json.dumps(ret, default=json_converter) + return ret + + +@app.route('/api/cus_fun/input', methods=['post']) +def get_cus_funcs_input(): + param = get_data_from_post() + data = param['data'] + + m_proxys.input_cus_funcs(data) + return df2json(m_proxys.get_df_data()) + + def main(): port = 5551 diff --git a/py/src/core/Proxy.py b/py/src/core/Proxy.py index 2051cdb764d1a7bd26563e55a7b1f44a4c00749d..91b04b69d9132967755e155e4c6314542d643c97 100644 --- a/py/src/core/Proxy.py +++ b/py/src/core/Proxy.py @@ -1,5 +1,9 @@ -from typing import Iterable, List +from typing import Dict, Iterable, List + +from ..cusFuns.core.UIModl import CusFunInputRet, FunModel, InputRet + +from ..cusFuns.core.FunsPool import FunsPool from .CodeFormatter import CodeFormatter @@ -139,6 +143,7 @@ df.columns=cols''') self.df_proxy.set_obj_to_var('df', self.source_cache) ret = self.df_proxy.run('df') self.df_proxy.cmdManager.clear_all_var() + self.df_proxy.set_obj_to_var('pd', pd) return ret def query(self, query_str: str): @@ -186,12 +191,8 @@ df.columns=cols''') '''cond = {cond} df = df[cond]'''.format(cond=cond_code)) - # with df_px.with_cmd(cmd_name) as cmd: - # cmd.create_statement('df', 'cond') - # df_px.eval(cond) - - # cmd.create_statement('df', 'df') - # df_px[ArgVar('cond')] + def run_cus_fun(self, data): + print(data) def _get_all_cmds(self) -> Iterable[Commander]: return ( @@ -204,6 +205,29 @@ df = df[cond]'''.format(cond=cond_code)) cmds = list(self._get_all_cmds()) return cmds + def get_ui_model(self, uid: str): + return FunsPool.get_once().get_ui_model(uid) + + def get_cus_funcs_desc(self): + ret = FunsPool.get_once().get_all_desc() + return ret + + def input_cus_funcs(self, data: Dict): + + input_ret = CusFunInputRet.from_dict(data) + + uid = input_ret.uid + cf = FunsPool.get_once().get_cusFunc(uid) + + input_args = { + c.var_name: c.input + for c in input_ret.contents + } + + with self.df_proxy.with_cmd(cf.fun_name) as cmd: + code = cf.to_code(**input_args) + cmd.create_code_statement(code) + def remove_cmd(self, cmd_id: str): for p in self._get_all_proxys(): p.cmdManager.remove_cmd(uuid.UUID(cmd_id)) diff --git a/py/src/cusFuns/columnNameChanger/index.py b/py/src/cusFuns/columnNameChanger/index.py new file mode 100644 index 0000000000000000000000000000000000000000..085c6926bf37dc9f23d1d3be741b7d8ab8adebe5 --- /dev/null +++ b/py/src/cusFuns/columnNameChanger/index.py @@ -0,0 +1,15 @@ +from ..core.DecoratorFuns import dt_handle_func, dt_args, dt_source_code +from ..core import Args as ty +import pandas as pd + + +def generate_code(*args, **kwargs): + kws = {kwargs['org_name']: kwargs['new_name']} + return f'''df = df.rename(columns={kws})''' + + +@dt_source_code(generate_code) +@dt_handle_func('修改列名') +@dt_args(org_name=ty.ColumnSelect('待修改列:'), new_name=ty.Input('新列名:', placeholder='输入新的列名')) +def change_column_name(df, org_name, new_name): + return df.rename(columns={org_name: new_name}) diff --git a/py/src/cusFuns/columnRemover/index.py b/py/src/cusFuns/columnRemover/index.py new file mode 100644 index 0000000000000000000000000000000000000000..7fe3a0117d072bf4047adb50faa10cc890bb934f --- /dev/null +++ b/py/src/cusFuns/columnRemover/index.py @@ -0,0 +1,9 @@ +from ..core.DecoratorFuns import dt_handle_func, dt_args +from ..core import Args as ty +import pandas as pd + + +@dt_handle_func('删除列') +@dt_args(org_name=ty.ColumnSelect('待删除的列:')) +def remove_cols(df: pd.DataFrame, org_name: str): + return df.drop(columns=org_name) diff --git a/py/src/cusFuns/core/Args.py b/py/src/cusFuns/core/Args.py new file mode 100644 index 0000000000000000000000000000000000000000..728739ac933102166dff60ae7ff8dcc688696df2 --- /dev/null +++ b/py/src/cusFuns/core/Args.py @@ -0,0 +1,55 @@ + + +from .UIModl import Content + + +class AbcArgs(object): + """ + docstring + """ + pass + + def __init__(self, title, default=None, required=True) -> None: + self.title = title + self.default = default + self.required = required + self.var_name: str = None + + def set_var_name(self, var_name) -> 'AbcArgs': + self.var_name = var_name + return self + + def to_content(self) -> Content: + raise NotImplementedError + + +class ColumnSelect(AbcArgs): + + def __init__(self, title, default=None, required=True) -> None: + super().__init__(title, default=default, required=required) + + def to_content(self) -> Content: + ct = Content(self.title, 'select', self.var_name, + source='data_columns', defaultValue=self.default) + return ct + + +class Input(AbcArgs): + + def __init__(self, title, placeholder=None, default=None, required=True) -> None: + super().__init__(title, default=default, required=required) + self.placeholder = placeholder + + def to_content(self) -> Content: + ct = Content(self.title, 'input', self.var_name, defaultValue=self.default) + return ct + + +class Select(AbcArgs): + + def __init__(self, title, default=None, required=True) -> None: + super().__init__(title, default=default, required=required) + + def to_content(self) -> Content: + ct = Content(self.title, 'select', self.var_name, defaultValue=self.default) + return ct diff --git a/py/src/cusFuns/core/DecoratorFuns.py b/py/src/cusFuns/core/DecoratorFuns.py new file mode 100644 index 0000000000000000000000000000000000000000..4a0677951fa59332b8fb3175374662a91e51d58b --- /dev/null +++ b/py/src/cusFuns/core/DecoratorFuns.py @@ -0,0 +1,77 @@ + + +from typing import Any, Callable, List + +from .UIModl import FunModel + +from .Args import AbcArgs + + +class CusFunsWrapper(object): + def __init__(self, org_func) -> None: + self.org_func = org_func + + +class HandleWrapper(CusFunsWrapper): + + @staticmethod + def create_if_not(func) -> 'HandleWrapper': + if not isinstance(func, HandleWrapper): + func = HandleWrapper(func) + return func + + def __init__(self, org_func) -> None: + super().__init__(org_func) + self.handle_func: Callable = None + self.fun_name: str = None + self.ui_json_func: Callable = None + self.code_func: Callable = None + self.args: List[AbcArgs] = [] + + def auto_create_ui_func(self): + if self.ui_json_func is not None: + return + + def _ui_json_func() -> FunModel: + fm = FunModel(self.fun_name) + for a in self.args: + fm.add_content(a.to_content()) + + return fm + + self.ui_json_func = _ui_json_func + + +def dt_handle_func(fun_name=None, ui_json_func=None): + + def wrapper(func): + func = HandleWrapper.create_if_not(func) + + func.handle_func = func.org_func + func.fun_name = fun_name + func.ui_json_func = ui_json_func + return func + + return wrapper + + +def dt_args(**kwargs): + + def wrapper(func): + func = HandleWrapper.create_if_not(func) + + func.args.extend((arg.set_var_name(var_name) + for var_name, arg in kwargs.items())) + return func + + return wrapper + + +def dt_source_code(generate_func: Callable): + def wrapper(func): + func = HandleWrapper.create_if_not(func) + func.code_func = generate_func + + return func + + return wrapper diff --git a/py/src/cusFuns/core/FunsPool.py b/py/src/cusFuns/core/FunsPool.py new file mode 100644 index 0000000000000000000000000000000000000000..558f27163ec2ab127709efbd055f94a34b0610ad --- /dev/null +++ b/py/src/cusFuns/core/FunsPool.py @@ -0,0 +1,129 @@ + + +from typing import Callable, Dict +import uuid +import pathlib +import importlib +import inspect +import os + + +from ..core.DecoratorFuns import CusFunsWrapper, HandleWrapper +from .UIModl import FunModel + + +class CusFunc(object): + """ + docstring + """ + pass + + def __init__(self) -> None: + self.call_func: Callable = None + self.uid: str = None + self.ui_json_func: Callable = None + self.code_func: Callable = None + self.fun_name: str = None + + self.reset_uid() + + def reset_uid(self): + self.uid = str(uuid.uuid1().int) + + def get_ui_json_model(self) -> FunModel: + fm: FunModel = self.ui_json_func() + fm.uid = self.uid + return fm + + def run(self, data): + """ + docstring + """ + pass + + @staticmethod + def _drop_decoreator(code: str) -> str: + lines = code.split('\n') + lines = [n for n in lines if n and n[0] != '@'] + return '\n'.join(lines) + + def to_code(self, *args, **kwargs) -> str: + if self.code_func: + return self.code_func(*args, **kwargs) + + def_code = inspect.getsource(self.call_func) + def_code = CusFunc._drop_decoreator(def_code) + + func_name = self.call_func.__name__ + call_code = f'''df = {func_name}(df,*{args},**{kwargs})''' + return '\n'.join([def_code, call_code]) + + +class FunsPool(object): + s_instance: 'FunsPool' = None + + @staticmethod + def get_once() -> 'FunsPool': + FunsPool.s_instance = FunsPool.s_instance or FunsPool() + return FunsPool.s_instance + + def __init__(self) -> None: + self._mapping: Dict[str, CusFunc] = {} + + def register(self, cusFunc: CusFunc): + self._mapping[cusFunc.uid] = cusFunc + + def get_cusFunc(self, uid: str) -> CusFunc: + return self._mapping[uid] + + def get_all_desc(self): + def _to_dict(fm: FunModel): + return { + 'function_name': fm.function_name, + 'uid': fm.uid + } + + models = (cf.get_ui_json_model() for cf in self._mapping.values()) + + ret = [_to_dict(f) + for f in models] + return ret + + def get_ui_model(self, uid: str): + ret = self.get_cusFunc(uid).get_ui_json_model() + return ret + + +def _register_module(module_path: str): + ''' + module_path : str + 'src.cusFuns.columnNameChanger.columnNameChanger' + ''' + module = importlib.import_module(module_path) + # [('name',obj)] + funcs = [(name, func) for name, func in module.__dict__.items() + if isinstance(func, CusFunsWrapper)] + + cf = CusFunc() + + for name, func in funcs: + if isinstance(func, HandleWrapper): + func.auto_create_ui_func() + + cf.call_func = func.handle_func + cf.ui_json_func = func.ui_json_func + cf.fun_name = func.fun_name or '未命名操作' + cf.code_func = func.code_func + + FunsPool.get_once().register(cf) + + +def auto_register(base_folder: str): + files = (p for p in pathlib.Path(base_folder).glob('*/*.py') + if p.parent.parts[-1] != 'core') + + for md_name in files: + md_name = str(md_name)[:-3] + md_name = md_name.replace(os.path.sep, '.') + + _register_module(md_name) diff --git a/py/src/cusFuns/core/UIModl.py b/py/src/cusFuns/core/UIModl.py new file mode 100644 index 0000000000000000000000000000000000000000..4e27f8a106e075a86debb81f79c0db31f99bec87 --- /dev/null +++ b/py/src/cusFuns/core/UIModl.py @@ -0,0 +1,51 @@ + + +from typing import Dict, List + +from ...helper.utils import CanJson + + +class Content(CanJson): + def __init__(self, title: str, type: str, var_name: str, source=None, defaultValue=None) -> None: + self.title = title + self.type = type + self.var_name = var_name + self.source = source + self.defaultValue = defaultValue + + +class FunModel(CanJson): + + def __init__(self, fun_name: str) -> None: + self.uid: str = None + self.function_name = fun_name + self.contents: List[Content] = [] + + def add_content(self, content: Content): + self.contents.append(content) + + +class InputRet(object): + + def __init__(self, var_name: str, input: object) -> None: + self.var_name = var_name + self.input = input + + +class CusFunInputRet(object): + + @staticmethod + def from_dict(data: Dict) -> 'CusFunInputRet': + pass + ret = CusFunInputRet() + ret.uid = data['uid'] + + cts = [InputRet(c['content']['var_name'], c['input']) + for c in data['contents']] + + ret.contents = cts + return ret + + def __init__(self) -> None: + self.contents: List[InputRet] = [] + self.uid: str = '' diff --git a/py/test.json b/py/test.json index 4bb4d734df77d74daeccd7b8cd92f76fec38c1dd..6fcc1951e8134bdfa7c48ed5827a23469921d2a9 100644 --- a/py/test.json +++ b/py/test.json @@ -1,10 +1,26 @@ -{ - "code": [ - "Traceback (most recent call last):\n", - " File \"d:\\ProgramData\\Anaconda3\\lib\\site-packages\\flask\\app.py\", line 1949, in full_dispatch_request\n rv = self.dispatch_request()\n", - " File \"d:\\ProgramData\\Anaconda3\\lib\\site-packages\\flask\\app.py\", line 1935, in dispatch_request\n return self.view_functions[rule.endpoint](**req.view_args)\n", - "AttributeError: 'NoneType' object has no attribute 'cmds'\n" - ], - "message": "AttributeError(\"'NoneType' object has no attribute 'cmds'\")", - "type": "error" -} \ No newline at end of file +[ + { + "_id": "90a1e608-435c-11eb-8471-c858c009ba5f", + "code": "#\u5bfc\u5165\u6a21\u5757\nimport pandas as pd", + "hasError": false, + "name": "\u5bfc\u5165\u6a21\u5757" + }, + { + "_id": "90a1e609-435c-11eb-a701-c858c009ba5f", + "code": "#\u52a0\u8f7d\u6570\u636e\ndf = pd.read_excel('data.xlsx',sheet_name = 0,header = 0,engine = 'openpyxl')", + "hasError": false, + "name": "\u52a0\u8f7d\u6570\u636e" + }, + { + "_id": "90a53f0c-435c-11eb-a0d2-c858c009ba5f", + "code": "#\u8868\u5934\u7edf\u4e00\u8f6c\u6587\u672c\ncols = [str(c) for c in df.columns]\ndf.columns=cols", + "hasError": false, + "name": "\u8868\u5934\u7edf\u4e00\u8f6c\u6587\u672c" + }, + { + "_id": "9b7d53e2-435c-11eb-8fc1-c858c009ba5f", + "code": "#None\ndef change_column_name(df: pd.DataFrame, org_name: str, new_name: str) -> pd.DataFrame: return df.rename(columns={org_name: new_name})\ndf = change_column_name(df,*(),**{'org_name': 'sex', 'new_name': 'dfdfd'})", + "hasError": true, + "name": null + } +] \ No newline at end of file diff --git a/py/test.py b/py/test.py index ead443de5c13c9c6e532ebd2befa34f8345abaec..a364b5f6b85e051642bab493c5e3803be2a71ae2 100644 --- a/py/test.py +++ b/py/test.py @@ -1,6 +1,23 @@ -df = pd.read_excel('titanic_full.xlsx', sheet_name=0, header=0)cond = df.eval("(sex == 'male')")df = df[cond]df = df.query(' 10 { + await updateCodeStore() + }) +} + + + + + export async function tableHandle(tableHandle: TableHandle) { let ret = await api.tableHandle(tableHandle) switch (ret.type) { diff --git a/ui/src/components/Commons/CustomizeFunction copy.tsx b/ui/src/components/Commons/CustomizeFunction copy.tsx new file mode 100644 index 0000000000000000000000000000000000000000..b3e9ecb1a33fc4445175d40341befb78d37651c9 --- /dev/null +++ b/ui/src/components/Commons/CustomizeFunction copy.tsx @@ -0,0 +1,74 @@ +// // import { defineComponent, h ,PropType } from "vue"; + +// import { defineComponent, PropType, ref,h, VNode, ComponentPublicInstance } from "vue"; +// import Form from 'ant-design-vue/lib/form/Form'; +// import FormItem from 'ant-design-vue/lib/form/FormItem'; +// import Input from 'ant-design-vue/lib/input'; +// import Button from 'ant-design-vue/lib/button'; + +// interface FunctionDesc { +// function_name: string; +// contents: Content[]; +// } + +// interface Content { +// title: string; +// type: string; +// source?: string; +// } + + + + + +// export default defineComponent({ +// name: "CustomizeFunction", +// props: {data:{ +// type:Object as PropType, +// required :true +// }}, +// data: () => ({ +// inputsMap: new Map(), +// }), + +// render() { + +// const get_input = (content:Content) => { +// this.inputsMap.set(content.title,'') + +// if (content.type=='input') { +// return +// } + +// return <> +// } + + +// const onApply = ()=>{ +// const ret = this.inputsMap +// alert(ret) +// } + + +// const cs = this.data.contents + + +// const items= cs.map(v=>{ + +// return +// {get_input(v)} +// + +// }) + + + +// return
+// {items} +// +// +// +//
+ +// }, +// }); \ No newline at end of file diff --git a/ui/src/components/Commons/CustomizeFunction.vue b/ui/src/components/Commons/CustomizeFunction.vue new file mode 100644 index 0000000000000000000000000000000000000000..08a71f95dc667e18a63253339bad5ffb0379bd70 --- /dev/null +++ b/ui/src/components/Commons/CustomizeFunction.vue @@ -0,0 +1,70 @@ + + + + + + + + + diff --git a/ui/src/components/Commons/CustomizeFunctionTest.vue b/ui/src/components/Commons/CustomizeFunctionTest.vue new file mode 100644 index 0000000000000000000000000000000000000000..d6ba1d4486b4efb28cb668988ca810e334d0792d --- /dev/null +++ b/ui/src/components/Commons/CustomizeFunctionTest.vue @@ -0,0 +1,60 @@ + + + + + + + + + + + diff --git a/ui/src/components/Commons/CustomizeItem.tsx b/ui/src/components/Commons/CustomizeItem.tsx new file mode 100644 index 0000000000000000000000000000000000000000..ce5f2f5bebd2f476d5d2f6820a4232e956f894f8 --- /dev/null +++ b/ui/src/components/Commons/CustomizeItem.tsx @@ -0,0 +1,166 @@ +import DfStore from "@/store/DfStore"; +import { defineComponent, PropType, Ref } from "vue"; +import * as cfModel from "@/models/CusFuns"; + +type optType = { + value: string; + text: string; +}; + +export default defineComponent({ + name: "CustomizeItem", + props: { + typeMessage: { + type: Object as PropType, + required: true, + }, + + value: { + required: true, + }, + }, + // emits:['update-value'], + data: () => ({ + inputsMap: new Map(), + }), + + render() { + const createOptsFromSource = ( + source: unknown, + createFunc: (opt: optType) => any + ) => { + const opts = (source as optType[]).map((v) => { + return createFunc(v); + }); + + return opts; + }; + + if (this.$props.typeMessage.type === "input") { + const onChange = (event: any) => { + this.$emit("update:value", event.target.value); + }; + + return ( + + ); + } + + if (this.$props.typeMessage.type === "select") { + let opts = null; + + if (this.$props.typeMessage.source === "data_columns") { + const colsInfos = DfStore.getStateReadonly().columnInfo.map( + (v) => { + return { value: v.field, text: v.label }; + } + ); + + opts = createOptsFromSource(colsInfos, (v) => ( + {v.text} + )); + } else { + opts = createOptsFromSource( + this.$props.typeMessage.source, + (v) => ( + + {v.text} + + ) + ); + } + + const onChange = (value: any, option: any) => { + this.$emit("update:value", value); + }; + + return ( + + {opts} + + ); + } + + if (this.$props.typeMessage.type === "date-select") { + const onChange = (time: string, timeString: string) => { + this.$emit("update:value", timeString); + }; + + return ( + + ); + } + + if (this.$props.typeMessage.type === "checkbox") { + const onChange = (event: any) => { + this.$emit("update:value", event); + }; + + const opts = createOptsFromSource( + this.$props.typeMessage.source, + (v) => ( + + {v.text} + + ) + ); + + return ( + + {opts} + + ); + } + + if (this.$props.typeMessage.type === "switch") { + const onChange = (checked: Boolean, event: Event) => { + this.$emit("update:value", checked); + }; + + return ( + + ); + } + + if (this.$props.typeMessage.type === "radio") { + const onChange = (event: any) => { + this.$emit("update:value", event.target.value); + }; + + const opts = createOptsFromSource( + this.$props.typeMessage.source, + (v) => ( + + {v.text} + + ) + ); + + return ( + + {opts} + + ); + } + }, +}); diff --git a/ui/src/components/FunctionTabs/FunsPool/index.vue b/ui/src/components/FunctionTabs/FunsPool/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..f55be622526716b4e664f764b34c137ff80f5e90 --- /dev/null +++ b/ui/src/components/FunctionTabs/FunsPool/index.vue @@ -0,0 +1,66 @@ + + + + + + + diff --git a/ui/src/components/FunctionTabs/index.vue b/ui/src/components/FunctionTabs/index.vue index 97b5cafbd91f2883db4b8258dbaf65913b0ecf83..2da7d95f04000c24c6dae4d7cb7f0b03c1e3a0e7 100644 --- a/ui/src/components/FunctionTabs/index.vue +++ b/ui/src/components/FunctionTabs/index.vue @@ -26,16 +26,29 @@ 期待!!!! + + + + + + +