mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-06-09 00:42:23 +00:00
Compare commits
23 Commits
main
...
v1.1.5-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db5f035de2 | ||
|
|
ded3f66b61 | ||
|
|
8678684eef | ||
|
|
2513f3e66f | ||
|
|
cce9bbf04b | ||
|
|
5fd1527663 | ||
|
|
d88be3d91e | ||
|
|
d75e72a54a | ||
|
|
2ae6254c7e | ||
|
|
39bfff3e9d | ||
|
|
b275697742 | ||
|
|
d00d8bf449 | ||
|
|
9f216d45e2 | ||
|
|
42fee1c3ee | ||
|
|
6b91417d36 | ||
|
|
73a35b5e7d | ||
|
|
568302820c | ||
|
|
4111f6eecb | ||
|
|
a05a36b06c | ||
|
|
dfa1fcda12 | ||
|
|
cf993af632 | ||
|
|
0c92794ac5 | ||
|
|
237b1bed31 |
23
.github/workflows/pr comment by chatgpt.yml
vendored
Normal file
23
.github/workflows/pr comment by chatgpt.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
name: Pull Request Review By ChatGPT
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
code-review:
|
||||
name: Code Review
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
# 判断用户是否有写仓库权限
|
||||
- name: 'Check User Permission'
|
||||
uses: 'lannonbr/repo-permission-check-action@2.0.0'
|
||||
with:
|
||||
permission: 'write'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- uses: opensumi/actions/.github/actions/code-review@main
|
||||
env:
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
@ -29,12 +29,17 @@ sidebar_position: 0
|
||||
- node-children 节点孩子
|
||||
- props 属性集
|
||||
- prop 属性
|
||||
- setting-prop-entry 设置属性
|
||||
- setting-field 设置属性
|
||||
- setting-top-entry 设置属性集
|
||||
- component-meta 物料元数据
|
||||
- selection 画布选中
|
||||
- detecting 画布 hover
|
||||
- history 操作历史
|
||||
- window 低代码设计器窗口模型
|
||||
- detecting 画布节点悬停模型
|
||||
- modal-nodes-manager 模态节点管理器模型
|
||||
- plugin-instance 插件实例
|
||||
- drop-location 拖拽放置位置模型
|
||||
|
||||
|
||||
## API 设计约定
|
||||
|
||||
@ -9,7 +9,7 @@ sidebar_position: 10
|
||||
## 模块简介
|
||||
提供 init 等方法
|
||||
## 方法
|
||||
#### 1. init
|
||||
#### init
|
||||
初始化引擎
|
||||
|
||||
**方法定义**
|
||||
|
||||
@ -1,113 +0,0 @@
|
||||
---
|
||||
title: Config
|
||||
sidebar_position: 16
|
||||
---
|
||||
> **@types** [IPublicModelEngineConfig](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/engine-config.ts)<br/>
|
||||
> **@since** v1.1.3
|
||||
|
||||
## 方法
|
||||
### has
|
||||
|
||||
判断指定 key 是否有值
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* 判断指定 key 是否有值
|
||||
* check if config has certain key configed
|
||||
* @param key
|
||||
* @returns
|
||||
*/
|
||||
has(key: string): boolean;
|
||||
```
|
||||
|
||||
### get
|
||||
|
||||
获取指定 key 的值
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* 获取指定 key 的值
|
||||
* get value by key
|
||||
* @param key
|
||||
* @param defaultValue
|
||||
* @returns
|
||||
*/
|
||||
get(key: string, defaultValue?: any): any;
|
||||
```
|
||||
|
||||
### set
|
||||
|
||||
设置指定 key 的值
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* 设置指定 key 的值
|
||||
* set value for certain key
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
set(key: string, value: any): void;
|
||||
```
|
||||
|
||||
### setConfig
|
||||
批量设值,set 的对象版本
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* 批量设值,set 的对象版本
|
||||
* set multiple config key-values
|
||||
* @param config
|
||||
*/
|
||||
setConfig(config: { [key: string]: any }): void;
|
||||
```
|
||||
|
||||
### getPreference
|
||||
获取全局 Preference, 用于管理全局浏览器侧用户 Preference,如 Panel 是否钉住
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* 获取全局 Preference, 用于管理全局浏览器侧用户 Preference,如 Panel 是否钉住
|
||||
* get global user preference manager, which can be use to store
|
||||
* user`s preference in user localstorage, such as a panel is pinned or not.
|
||||
* @returns {IPublicModelPreference}
|
||||
* @since v1.1.0
|
||||
*/
|
||||
getPreference(): IPublicModelPreference;
|
||||
```
|
||||
|
||||
相关类型:[IPublicModelPreference](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/preference.ts)
|
||||
|
||||
## 事件
|
||||
|
||||
### onGot
|
||||
获取指定 key 的值,函数回调模式,若多次被赋值,回调会被多次调用
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* 获取指定 key 的值,函数回调模式,若多次被赋值,回调会被多次调用
|
||||
* set callback for event of value set for some key
|
||||
* this will be called each time the value is set
|
||||
* @param key
|
||||
* @param fn
|
||||
* @returns
|
||||
*/
|
||||
onGot(key: string, fn: (data: any) => void): IPublicTypeDisposable;
|
||||
```
|
||||
|
||||
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
|
||||
|
||||
### onceGot
|
||||
获取指定 key 的值,若此时还未赋值,则等待,若已有值,则直接返回值
|
||||
> 注:此函数返回 Promise 实例,只会执行(fullfill)一次
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* 获取指定 key 的值,若此时还未赋值,则等待,若已有值,则直接返回值
|
||||
* 注:此函数返回 Promise 实例,只会执行(fullfill)一次
|
||||
* wait until value of certain key is set, will only be
|
||||
* triggered once.
|
||||
* @param key
|
||||
* @returns
|
||||
*/
|
||||
onceGot(key: string): Promise<any>;
|
||||
```
|
||||
@ -254,6 +254,8 @@ sidebar_position: 1
|
||||
|
||||
`@type {IPublicModelSettingTopEntry}`
|
||||
|
||||
相关章节:[设置器顶层操作对象](./setting-top-entry)
|
||||
|
||||
相关类型:[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts)
|
||||
|
||||
### visible
|
||||
|
||||
342
docs/docs/api/model/setting-field.md
Normal file
342
docs/docs/api/model/setting-field.md
Normal file
@ -0,0 +1,342 @@
|
||||
---
|
||||
title: SettingField
|
||||
sidebar_position: 6
|
||||
---
|
||||
> **@types** [IPublicModelSettingField](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-field.ts)<br/>
|
||||
|
||||
## 基本介绍
|
||||
|
||||
setter 设置器操作对象
|
||||
|
||||
## 属性
|
||||
|
||||
#### isGroup
|
||||
|
||||
获取设置属性的 isGroup
|
||||
|
||||
`@type {boolean}`
|
||||
|
||||
|
||||
#### id
|
||||
|
||||
获取设置属性的 id
|
||||
|
||||
`@type {string}`
|
||||
|
||||
#### name
|
||||
|
||||
获取设置属性的 name
|
||||
|
||||
`@type {string | number | undefined}`
|
||||
|
||||
#### key
|
||||
|
||||
获取设置属性的 key
|
||||
|
||||
`@type {string | number | undefined}`
|
||||
|
||||
#### path
|
||||
|
||||
获取设置属性的 path
|
||||
|
||||
`@type {(string | number)[]}`
|
||||
|
||||
#### title
|
||||
|
||||
获取设置属性的 title
|
||||
|
||||
`@type {string}`
|
||||
|
||||
#### setter
|
||||
|
||||
获取设置属性的 setter
|
||||
|
||||
`@type {IPublicTypeSetterType | null}`
|
||||
|
||||
#### expanded
|
||||
|
||||
获取设置属性的 expanded
|
||||
|
||||
`@type {boolean}`
|
||||
|
||||
#### extraProps
|
||||
|
||||
获取设置属性的 extraProps
|
||||
|
||||
`@type {IPublicTypeFieldExtraProps}`
|
||||
|
||||
#### props
|
||||
|
||||
`@type {IPublicModelSettingTopEntry}`
|
||||
|
||||
相关章节:[设置器顶层操作对象](./setting-top-entry)
|
||||
|
||||
相关类型:[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts)
|
||||
|
||||
#### node
|
||||
|
||||
获取设置属性对应的节点实例
|
||||
|
||||
`@type {IPublicModelNode | null}`
|
||||
|
||||
|
||||
#### parent
|
||||
|
||||
获取设置属性的父设置属性
|
||||
|
||||
`@type {IPublicModelSettingTopEntry | IPublicModelSettingField}`
|
||||
|
||||
相关章节:[设置器顶层操作对象](./setting-top-entry)
|
||||
|
||||
相关类型:[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts)
|
||||
|
||||
#### top
|
||||
|
||||
获取顶级设置属性
|
||||
|
||||
`@type {IPublicModelSettingTopEntry}`
|
||||
|
||||
相关章节:[设置器顶层操作对象](./setting-top-entry)
|
||||
|
||||
相关类型:[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts)
|
||||
|
||||
#### isSettingField
|
||||
|
||||
是否是 SettingField 实例
|
||||
|
||||
`@type {boolean}`
|
||||
|
||||
#### componentMeta
|
||||
|
||||
`@type {IPublicModelComponentMeta}`
|
||||
|
||||
相关类型:[IPublicModelComponentMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts)
|
||||
|
||||
#### items
|
||||
|
||||
获取设置属性的 items
|
||||
|
||||
`@type {Array<IPublicModelSettingField | IPublicTypeCustomView>}`
|
||||
|
||||
相关类型:[IPublicTypeCustomView](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/custom-view.ts)
|
||||
|
||||
## 方法
|
||||
|
||||
#### setKey
|
||||
|
||||
设置 key 值
|
||||
|
||||
```
|
||||
/**
|
||||
* 设置 key 值
|
||||
* @param key
|
||||
*/
|
||||
setKey(key: string | number): void;
|
||||
```
|
||||
|
||||
#### setValue
|
||||
|
||||
设置值
|
||||
|
||||
```
|
||||
/**
|
||||
* 设置值
|
||||
* @param val 值
|
||||
*/
|
||||
setValue(val: IPublicTypeCompositeValue, extraOptions?: IPublicTypeSetValueOptions): void;
|
||||
```
|
||||
|
||||
相关类型:
|
||||
- [IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts)
|
||||
- [IPublicTypeSetValueOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/set-value-options.ts)
|
||||
|
||||
#### setPropValue
|
||||
|
||||
设置子级属性值
|
||||
|
||||
```
|
||||
/**
|
||||
* 设置子级属性值
|
||||
* @param propName 子属性名
|
||||
* @param value 值
|
||||
*/
|
||||
setPropValue(propName: string | number, value: any): void;
|
||||
```
|
||||
|
||||
#### clearPropValue
|
||||
|
||||
清空指定属性值
|
||||
|
||||
```
|
||||
/**
|
||||
* 清空指定属性值
|
||||
* @param propName
|
||||
*/
|
||||
clearPropValue(propName: string | number): void;
|
||||
```
|
||||
|
||||
#### getDefaultValue
|
||||
|
||||
获取配置的默认值
|
||||
|
||||
```
|
||||
/**
|
||||
* 获取配置的默认值
|
||||
* @returns
|
||||
*/
|
||||
getDefaultValue(): any;
|
||||
```
|
||||
|
||||
#### getValue
|
||||
|
||||
获取值
|
||||
|
||||
```
|
||||
/**
|
||||
* 获取值
|
||||
* @returns
|
||||
*/
|
||||
getValue(): any;
|
||||
```
|
||||
|
||||
#### getPropValue
|
||||
|
||||
获取子级属性值
|
||||
|
||||
```
|
||||
/**
|
||||
* 获取子级属性值
|
||||
* @param propName 子属性名
|
||||
* @returns
|
||||
*/
|
||||
getPropValue(propName: string | number): any;
|
||||
```
|
||||
|
||||
#### getExtraPropValue
|
||||
|
||||
获取顶层附属属性值
|
||||
|
||||
```
|
||||
/**
|
||||
* 获取顶层附属属性值
|
||||
*/
|
||||
getExtraPropValue(propName: string): any;
|
||||
```
|
||||
|
||||
#### setExtraPropValue
|
||||
|
||||
设置顶层附属属性值
|
||||
|
||||
```
|
||||
/**
|
||||
* 设置顶层附属属性值
|
||||
*/
|
||||
setExtraPropValue(propName: string, value: any): void;
|
||||
```
|
||||
|
||||
#### getProps
|
||||
|
||||
获取设置属性集
|
||||
|
||||
```
|
||||
/**
|
||||
* 获取设置属性集
|
||||
* @returns
|
||||
*/
|
||||
getProps(): IPublicModelSettingTopEntry;
|
||||
```
|
||||
|
||||
相关章节:[设置器顶层操作对象](./setting-top-entry)
|
||||
|
||||
相关类型:[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts)
|
||||
|
||||
#### isUseVariable
|
||||
|
||||
是否绑定了变量
|
||||
|
||||
```
|
||||
/**
|
||||
* 是否绑定了变量
|
||||
* @returns
|
||||
*/
|
||||
isUseVariable(): boolean;
|
||||
```
|
||||
|
||||
#### setUseVariable
|
||||
|
||||
设置绑定变量
|
||||
|
||||
```
|
||||
/**
|
||||
* 设置绑定变量
|
||||
* @param flag
|
||||
*/
|
||||
setUseVariable(flag: boolean): void;
|
||||
```
|
||||
|
||||
#### createField
|
||||
|
||||
创建一个设置 field 实例
|
||||
|
||||
```
|
||||
/**
|
||||
* 创建一个设置 field 实例
|
||||
* @param config
|
||||
* @returns
|
||||
*/
|
||||
createField(config: IPublicTypeFieldConfig): IPublicModelSettingField;
|
||||
```
|
||||
|
||||
相关类型:[IPublicTypeFieldConfig](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/field-config.ts)
|
||||
|
||||
#### getMockOrValue
|
||||
|
||||
获取值,当为变量时,返回 mock
|
||||
|
||||
```
|
||||
/**
|
||||
* 获取值,当为变量时,返回 mock
|
||||
* @returns
|
||||
*/
|
||||
getMockOrValue(): any;
|
||||
|
||||
```
|
||||
|
||||
#### purge
|
||||
|
||||
销毁当前 field 实例
|
||||
|
||||
```
|
||||
/**
|
||||
* 销毁当前 field 实例
|
||||
*/
|
||||
purge(): void;
|
||||
```
|
||||
|
||||
#### remove
|
||||
|
||||
移除当前 field 实例
|
||||
|
||||
```
|
||||
/**
|
||||
* 移除当前 field 实例
|
||||
*/
|
||||
remove(): void;
|
||||
```
|
||||
|
||||
## 事件
|
||||
|
||||
#### onEffect
|
||||
|
||||
设置 autorun
|
||||
|
||||
```
|
||||
/**
|
||||
* 设置 autorun
|
||||
* @param action
|
||||
* @returns
|
||||
*/
|
||||
onEffect(action: () => void): IPublicTypeDisposable;
|
||||
```
|
||||
|
||||
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
|
||||
74
docs/docs/api/model/setting-top-entry.md
Normal file
74
docs/docs/api/model/setting-top-entry.md
Normal file
@ -0,0 +1,74 @@
|
||||
---
|
||||
title: SettingTopEntry
|
||||
sidebar_position: 6
|
||||
---
|
||||
> **@types** [IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts)<br/>
|
||||
|
||||
## 基本介绍
|
||||
|
||||
setter 设置器顶层操作对象
|
||||
|
||||
## 属性
|
||||
|
||||
#### node
|
||||
|
||||
返回所属的节点实例
|
||||
|
||||
`@type {IPublicModelNode | null}`
|
||||
|
||||
## 方法
|
||||
|
||||
#### get
|
||||
|
||||
获取子级属性对象
|
||||
|
||||
```
|
||||
/**
|
||||
* 获取子级属性对象
|
||||
* @param propName
|
||||
* @returns
|
||||
*/
|
||||
get(propName: string | number): IPublicModelSettingField | null;
|
||||
```
|
||||
相关章节:[设置器操作对象](./setting-field)
|
||||
|
||||
相关类型:[IPublicModelSettingField](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-field.ts)
|
||||
|
||||
|
||||
#### getPropValue
|
||||
|
||||
获取指定 propName 的值
|
||||
|
||||
```
|
||||
/**
|
||||
* 获取指定 propName 的值
|
||||
* @param propName
|
||||
* @returns
|
||||
*/
|
||||
getPropValue(propName: string | number): any;
|
||||
```
|
||||
|
||||
#### setPropValue
|
||||
|
||||
设置指定 propName 的值
|
||||
|
||||
```
|
||||
/**
|
||||
* 设置指定 propName 的值
|
||||
* @param propName
|
||||
* @param value
|
||||
*/
|
||||
setPropValue(propName: string | number, value: any): void;
|
||||
```
|
||||
|
||||
#### clearPropValue
|
||||
|
||||
清除指定 propName 的值
|
||||
|
||||
```
|
||||
/**
|
||||
* 清除指定 propName 的值
|
||||
* @param propName
|
||||
*/
|
||||
clearPropValue(propName: string | number): void;
|
||||
```
|
||||
@ -252,6 +252,35 @@ setI18n(value: object): void;
|
||||
|
||||
**@since v1.0.17**
|
||||
|
||||
### setConfig
|
||||
设置当前项目配置
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* 设置当前项目配置
|
||||
* set config for this project
|
||||
* @param value object
|
||||
* @since v1.1.4
|
||||
*/
|
||||
setConfig(value: IPublicTypeAppConfig): void;
|
||||
setConfig<T extends keyof IPublicTypeAppConfig>(key: T, value: IPublicTypeAppConfig[T]): void;
|
||||
```
|
||||
|
||||
**@since v1.1.4**
|
||||
|
||||
#### 如何扩展项目配置
|
||||
|
||||
```typescript
|
||||
// shims.d.ts
|
||||
declare module '@alilc/lowcode-types' {
|
||||
export interface IPublicTypeAppConfig {
|
||||
customProp: CustomPropType
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
```
|
||||
|
||||
|
||||
## 事件
|
||||
|
||||
|
||||
@ -3,17 +3,17 @@ title: 低代码引擎相关文章资料
|
||||
---
|
||||
|
||||
## 官方文章
|
||||
|
||||
- [基于 LowCodeEngine 的低代码组件体系的建设和实践](https://mp.weixin.qq.com/s/rnvbGHImGt6oJuX2wCtaqw)
|
||||
- [低代码多分支协同开发的建设与实践](https://mp.weixin.qq.com/s/DmwxL67htHfTUP1U966N-Q)
|
||||
- [低代码引擎半岁啦,来跟大家唠唠嗑...](https://segmentfault.com/a/1190000042884409)
|
||||
- [低代码技术在研发团队的应用模式探讨](https://mp.weixin.qq.com/s/Ynk_wjJbmNw7fEG6UtGZbQ)
|
||||
- [关于 LowCode&ProCode 混合研发的思考](https://mp.weixin.qq.com/s/TY3VXjkSmsQoT47xma3wig)
|
||||
- [低代码渲染那些事](https://mp.weixin.qq.com/s/yqYey76qLGYPfDtpGkVFfA)
|
||||
- [阿里低代码引擎和生态建设实战及思考](https://mp.weixin.qq.com/s/MI6MrUKKydtnSdO4xq6jwA)
|
||||
- [磁贴布局在钉钉宜搭报表设计引擎中的实现](https://mp.weixin.qq.com/s/PSTut5ahAB8nlJ9kBpBaxw)
|
||||
- [2B 领域下的低代码探索之路](https://mp.weixin.qq.com/s/HAxrMHLT43dPH488RiEIdw)
|
||||
- [阿里低代码引擎 LowCodeEngine 正式开源!](https://mp.weixin.qq.com/s/T66LghtWLz2Oh048XqaniA)
|
||||
- [2023/03/23 低代码引擎 LowCodeEngine 茁壮成长的一年](https://mp.weixin.qq.com/s/DDt4LQLFUBQ2-F5ehZGBKg)
|
||||
- [2023/02/21 基于 LowCodeEngine 的低代码组件体系的建设和实践](https://mp.weixin.qq.com/s/rnvbGHImGt6oJuX2wCtaqw)
|
||||
- [2022/12/21 低代码多分支协同开发的建设与实践](https://mp.weixin.qq.com/s/DmwxL67htHfTUP1U966N-Q)
|
||||
- [2022/11/24 低代码引擎半岁啦,来跟大家唠唠嗑...](https://segmentfault.com/a/1190000042884409)
|
||||
- [2022/10/27 低代码技术在研发团队的应用模式探讨](https://mp.weixin.qq.com/s/Ynk_wjJbmNw7fEG6UtGZbQ)
|
||||
- [2022/06/23 低代码渲染那些事](https://mp.weixin.qq.com/s/yqYey76qLGYPfDtpGkVFfA)
|
||||
- [2022/06/16 关于 LowCode&ProCode 混合研发的思考](https://mp.weixin.qq.com/s/TY3VXjkSmsQoT47xma3wig)
|
||||
- [2022/04/07 磁贴布局在钉钉宜搭报表设计引擎中的实现](https://mp.weixin.qq.com/s/PSTut5ahAB8nlJ9kBpBaxw)
|
||||
- [2022/03/23 阿里低代码引擎 LowCodeEngine 正式开源!](https://mp.weixin.qq.com/s/T66LghtWLz2Oh048XqaniA)
|
||||
- [2022/01/10 阿里低代码引擎和生态建设实战及思考](https://mp.weixin.qq.com/s/MI6MrUKKydtnSdO4xq6jwA)
|
||||
- [2021/04/14 2B 领域下的低代码探索之路](https://mp.weixin.qq.com/s/HAxrMHLT43dPH488RiEIdw)
|
||||
|
||||
## Portal 设计项目实战
|
||||
#### 直播回放
|
||||
|
||||
@ -44,6 +44,6 @@ sidebar_position: 3
|
||||
| @alifd/fusion-ui | [https://github.com/alibaba/lowcode-materials](https://github.com/alibaba/lowcode-materials) | packages/fusion-ui |
|
||||
| @alilc/lowcode-materials | [https://github.com/alibaba/lowcode-materials](https://github.com/alibaba/lowcode-materials) | packages/fusion-lowcode-materials |
|
||||
| @alilc/antd-lowcode-materials | [https://github.com/alibaba/lowcode-materials](https://github.com/alibaba/lowcode-materials) | packages/antd-lowcode-materials |
|
||||
| | | |
|
||||
| @alifd/layout(原 @alifd/pro-layout 升级后的版本) | [https://github.com/alibaba-fusion/layout](https://github.com/alibaba-fusion/layout) | |
|
||||
| | | |
|
||||
| | | |
|
||||
|
||||
74
docs/docs/guide/appendix/setterDetails/function.md
Normal file
74
docs/docs/guide/appendix/setterDetails/function.md
Normal file
@ -0,0 +1,74 @@
|
||||
---
|
||||
title: FunctionSetter
|
||||
---
|
||||
## 简介
|
||||
可以将function绑定在物料上
|
||||
|
||||
## 设置器返回
|
||||
|
||||
设置器返回一个Function对象,调用function()运行Function对象得到运行结果。
|
||||
|
||||
如下是一个典型的使用案例:
|
||||
|
||||
```javascript
|
||||
export type TestProps = React.ComponentProps<typeof Test> & {
|
||||
testFunction?: Function | undefined;
|
||||
};
|
||||
|
||||
const getTestData = () => {
|
||||
if(this.props.testFunction === undefined){
|
||||
return undefined;
|
||||
}else{
|
||||
return this.props.testFunction() // 返回testFunction()方法的运行结果;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 参数设置
|
||||
|
||||
如果需要额外传参,需要将扩展参数设置打开,在代码面板中,编辑参数内容。
|
||||
|
||||
注意:
|
||||
|
||||
- 额外参数必须被包装成一个对象,如参数模板中所示
|
||||
- 可以使用动态变量例如 (this.items,this.state.xxx)
|
||||
```javascript
|
||||
{
|
||||
testKey: this.state.text,
|
||||
}
|
||||
```
|
||||
|
||||
- 该参数是额外参数,会加在原有参数后面,例如在 onClick 中加入扩展传参,最终函数消费的时候应该如下所示
|
||||
```javascript
|
||||
// e 为 onClick 原有函数传参,extParams 为自定义传参
|
||||
onClick(e, extParams) {
|
||||
this.setState({
|
||||
isShowDialog: extParams.isShowDialog,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## 事件新建函数模板
|
||||
有时候我们创建的函数会有用到一些通用的函数模板,我们可以在物料协议的 meta.ts 中创建一个模板,如下
|
||||
|
||||
```TypeScript
|
||||
{
|
||||
name: 'onChange',
|
||||
title: {
|
||||
label: 'onChange',
|
||||
tip: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
|
||||
},
|
||||
propType: 'func',
|
||||
setter: [
|
||||
{
|
||||
componentName: 'FunctionSetter',
|
||||
props: {
|
||||
template: 'onTableChange(value,${extParams}){\n\n}',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
其中 ${extParams} 为扩展参数占位符,如果用户没有声明扩展参数,会移除对应的参数声明。
|
||||
@ -14,7 +14,7 @@ sidebar_position: 4
|
||||
| DateYearSetter || 日期型 - 年数据设置器 | |
|
||||
| [EventSetter](./setterDetails/event) | function | 事件绑定设置器 |  |
|
||||
| [IconSetter](./setterDetails/icon) | string | 图标设置器 |  |
|
||||
| FunctionSetter | any | 函数型数据设置器 |  |
|
||||
| [FunctionSetter](./setterDetails/function) | function | 函数型数据设置器 |  |
|
||||
| JsonSetter | object | json 型数据设置器 |  |
|
||||
| [MixedSetter](./setterDetails/mixed) | any | 混合型数据设置器 |  |
|
||||
| [NumberSetter](./setterDetails/number) | number | 数值型数据设置器 |  |
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@alilc/lowcode-engine-docs",
|
||||
"version": "1.0.21",
|
||||
"version": "1.0.24",
|
||||
"description": "低代码引擎版本化文档",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"lerna": "4.0.0",
|
||||
"version": "1.1.4",
|
||||
"version": "1.1.5-beta.6",
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"packages": [
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@alilc/lowcode-code-generator",
|
||||
"version": "1.0.8",
|
||||
"version": "1.1.0",
|
||||
"description": "出码引擎 for LowCode Engine",
|
||||
"license": "MIT",
|
||||
"main": "lib/index.js",
|
||||
|
||||
@ -9,6 +9,7 @@ import { createModuleBuilder } from './generator/ModuleBuilder';
|
||||
import { createDiskPublisher } from './publisher/disk';
|
||||
import { createZipPublisher } from './publisher/zip';
|
||||
import createIceJsProjectBuilder, { plugins as reactPlugins } from './solutions/icejs';
|
||||
import createIce3JsProjectBuilder, { plugins as icejs3Plugins } from './solutions/icejs3';
|
||||
import createRaxAppProjectBuilder, { plugins as raxPlugins } from './solutions/rax-app';
|
||||
|
||||
// 引入说明
|
||||
@ -32,6 +33,7 @@ import * as CONSTANTS from './const';
|
||||
|
||||
// 引入内置解决方案模块
|
||||
import icejs from './plugins/project/framework/icejs';
|
||||
import icejs3 from './plugins/project/framework/icejs3';
|
||||
import rax from './plugins/project/framework/rax';
|
||||
|
||||
export default {
|
||||
@ -39,10 +41,12 @@ export default {
|
||||
createModuleBuilder,
|
||||
solutions: {
|
||||
icejs: createIceJsProjectBuilder,
|
||||
icejs3: createIce3JsProjectBuilder,
|
||||
rax: createRaxAppProjectBuilder,
|
||||
},
|
||||
solutionParts: {
|
||||
icejs,
|
||||
icejs3,
|
||||
rax,
|
||||
},
|
||||
publishers: {
|
||||
@ -74,6 +78,9 @@ export default {
|
||||
i18n,
|
||||
utils,
|
||||
},
|
||||
icejs3: {
|
||||
...icejs3Plugins,
|
||||
},
|
||||
},
|
||||
postprocessor: {
|
||||
prettier,
|
||||
|
||||
@ -16,7 +16,7 @@ import {
|
||||
IWithDependency,
|
||||
} from '../../types';
|
||||
|
||||
import { isValidIdentifier, isValidComponentName } from '../../utils/validate';
|
||||
import { isValidIdentifier } from '../../utils/validate';
|
||||
|
||||
// TODO: main 这个信息到底怎么用,是不是外部包不需要使用?
|
||||
const DEP_MAIN_BLOCKLIST = ['lib', 'lib/index', 'es', 'es/index', 'main'];
|
||||
@ -261,7 +261,7 @@ function buildPackageImport(
|
||||
if (!isValidIdentifier(name)) {
|
||||
throw new CodeGeneratorError(`Invalid Identifier [${name}]`);
|
||||
}
|
||||
if (info.nodeIdentifier && !isValidComponentName(info.nodeIdentifier)) {
|
||||
if (info.nodeIdentifier && !isValidIdentifier(info.nodeIdentifier)) {
|
||||
throw new CodeGeneratorError(`Invalid Identifier [${info.nodeIdentifier}]`);
|
||||
}
|
||||
});
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
import template from './template';
|
||||
import globalStyle from './plugins/globalStyle';
|
||||
import packageJSON from './plugins/packageJSON';
|
||||
import layout from './plugins/layout';
|
||||
import appConfig from './plugins/appConfig';
|
||||
import buildConfig from './plugins/buildConfig';
|
||||
|
||||
export default {
|
||||
template,
|
||||
plugins: {
|
||||
appConfig,
|
||||
buildConfig,
|
||||
globalStyle,
|
||||
packageJSON,
|
||||
layout,
|
||||
},
|
||||
};
|
||||
@ -0,0 +1,50 @@
|
||||
import {
|
||||
BuilderComponentPlugin,
|
||||
BuilderComponentPluginFactory,
|
||||
ChunkType,
|
||||
FileType,
|
||||
ICodeStruct,
|
||||
} from '../../../../../types';
|
||||
import { COMMON_CHUNK_NAME } from '../../../../../const/generator';
|
||||
|
||||
export interface AppConfigPluginConfig {
|
||||
|
||||
}
|
||||
|
||||
function getContent() {
|
||||
return `import { defineAppConfig } from 'ice';
|
||||
|
||||
// App config, see https://v3.ice.work/docs/guide/basic/app
|
||||
export default defineAppConfig(() => ({
|
||||
// Set your configs here.
|
||||
app: {
|
||||
rootId: 'App',
|
||||
},
|
||||
router: {
|
||||
type: 'browser',
|
||||
basename: '/',
|
||||
},
|
||||
}));`;
|
||||
}
|
||||
|
||||
const pluginFactory: BuilderComponentPluginFactory<AppConfigPluginConfig> = () => {
|
||||
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
||||
const next: ICodeStruct = {
|
||||
...pre,
|
||||
};
|
||||
|
||||
next.chunks.push({
|
||||
type: ChunkType.STRING,
|
||||
fileType: FileType.TS,
|
||||
name: COMMON_CHUNK_NAME.FileMainContent,
|
||||
content: getContent(),
|
||||
linkAfter: [],
|
||||
});
|
||||
|
||||
return next;
|
||||
};
|
||||
|
||||
return plugin;
|
||||
};
|
||||
|
||||
export default pluginFactory;
|
||||
@ -0,0 +1,165 @@
|
||||
import {
|
||||
BuilderComponentPlugin,
|
||||
BuilderComponentPluginFactory,
|
||||
ChunkType,
|
||||
FileType,
|
||||
ICodeStruct,
|
||||
} from '../../../../../types';
|
||||
import { COMMON_CHUNK_NAME } from '../../../../../const/generator';
|
||||
import { format } from '../../../../../utils/format';
|
||||
import { getThemeInfo } from '../../../../../utils/theme';
|
||||
|
||||
export interface BuildConfigPluginConfig {
|
||||
|
||||
/** 包名 */
|
||||
themePackage?: string;
|
||||
}
|
||||
|
||||
function getContent(cfg?: BuildConfigPluginConfig, routesContent?: string) {
|
||||
return `
|
||||
import { join } from 'path';
|
||||
import { defineConfig } from '@ice/app';
|
||||
import _ from 'lodash';
|
||||
import fusion from '@ice/plugin-fusion';
|
||||
import locales from '@ice/plugin-moment-locales';
|
||||
import type { Plugin } from '@ice/app/esm/types';
|
||||
|
||||
interface PluginOptions {
|
||||
id: string;
|
||||
}
|
||||
|
||||
const plugin: Plugin<PluginOptions> = (options) => ({
|
||||
// name 可选,插件名称
|
||||
name: 'plugin-name',
|
||||
// setup 必选,用于定制工程构建配置
|
||||
setup: ({ onGetConfig, modifyUserConfig }) => {
|
||||
modifyUserConfig('codeSplitting', 'page');
|
||||
|
||||
onGetConfig((config) => {
|
||||
config.entry = {
|
||||
web: join(process.cwd(), '.ice/entry.client.tsx'),
|
||||
};
|
||||
|
||||
config.cssFilename = '[name].css';
|
||||
|
||||
config.configureWebpack = config.configureWebpack || [];
|
||||
config.configureWebpack?.push((webpackConfig) => {
|
||||
if (webpackConfig.output) {
|
||||
webpackConfig.output.filename = '[name].js';
|
||||
webpackConfig.output.chunkFilename = '[name].js';
|
||||
}
|
||||
return webpackConfig;
|
||||
});
|
||||
|
||||
config.swcOptions = _.merge(config.swcOptions, {
|
||||
compilationConfig: {
|
||||
jsc: {
|
||||
transform: {
|
||||
react: {
|
||||
runtime: 'classic',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
// 解决 webpack publicPath 问题
|
||||
config.transforms = config.transforms || [];
|
||||
config.transforms.push((source: string, id: string) => {
|
||||
if (id.includes('.ice/entry.client.tsx')) {
|
||||
let code = \`
|
||||
if (!__webpack_public_path__?.startsWith('http') && document.currentScript) {
|
||||
// @ts-ignore
|
||||
__webpack_public_path__ = document.currentScript.src.replace(/^(.*\\\\/)[^/]+$/, '$1');
|
||||
window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {};
|
||||
window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__;
|
||||
}
|
||||
\`;
|
||||
code += source;
|
||||
return { code };
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// The project config, see https://v3.ice.work/docs/guide/basic/config
|
||||
const minify = process.env.NODE_ENV === 'production' ? 'swc' : false;
|
||||
export default defineConfig(() => ({
|
||||
ssr: false,
|
||||
ssg: false,
|
||||
minify,
|
||||
${routesContent}
|
||||
externals: {
|
||||
react: 'React',
|
||||
'react-dom': 'ReactDOM',
|
||||
'react-dom/client': 'ReactDOM',
|
||||
'@alifd/next': 'Next',
|
||||
lodash: 'var window._',
|
||||
'@alilc/lowcode-engine': 'var window.AliLowCodeEngine',
|
||||
},
|
||||
plugins: [
|
||||
fusion(${cfg?.themePackage ? `{
|
||||
importStyle: 'sass',
|
||||
themePackage: '${getThemeInfo(cfg.themePackage).name}',
|
||||
}` : `{
|
||||
importStyle: true,
|
||||
}`}),
|
||||
locales(),
|
||||
plugin(),
|
||||
]
|
||||
}));
|
||||
`;
|
||||
}
|
||||
|
||||
function getRoutesContent(navData: any, needShell = true) {
|
||||
const routes = [
|
||||
'routes: {',
|
||||
' defineRoutes: route => {',
|
||||
];
|
||||
function _getRoutes(nav: any, _routes: string[] = []) {
|
||||
const { slug, children } = nav;
|
||||
if (children && children.length > 0) {
|
||||
children.forEach((_nav: any) => _getRoutes(_nav, _routes));
|
||||
} else if (slug) {
|
||||
_routes.push(`route('/${slug}', '${slug}/index.jsx');`);
|
||||
}
|
||||
}
|
||||
if (needShell) {
|
||||
routes.push(" route('/', 'layout.jsx', () => {");
|
||||
}
|
||||
navData?.forEach((nav: any) => {
|
||||
_getRoutes(nav, routes);
|
||||
});
|
||||
if (needShell) {
|
||||
routes.push(' });');
|
||||
}
|
||||
routes.push(' }'); // end of defineRoutes
|
||||
routes.push(' },'); // end of routes
|
||||
return routes.join('\n');
|
||||
}
|
||||
|
||||
const pluginFactory: BuilderComponentPluginFactory<BuildConfigPluginConfig> = (cfg?) => {
|
||||
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
||||
const next: ICodeStruct = {
|
||||
...pre,
|
||||
};
|
||||
|
||||
const { navConfig } = next.contextData;
|
||||
const routesContent = navConfig?.data ? getRoutesContent(navConfig.data, true) : '';
|
||||
|
||||
next.chunks.push({
|
||||
type: ChunkType.STRING,
|
||||
fileType: FileType.MTS,
|
||||
name: COMMON_CHUNK_NAME.FileMainContent,
|
||||
content: format(getContent(cfg, routesContent)),
|
||||
linkAfter: [],
|
||||
});
|
||||
|
||||
return next;
|
||||
};
|
||||
|
||||
return plugin;
|
||||
};
|
||||
|
||||
export default pluginFactory;
|
||||
@ -0,0 +1,56 @@
|
||||
import { COMMON_CHUNK_NAME } from '../../../../../const/generator';
|
||||
|
||||
import {
|
||||
BuilderComponentPlugin,
|
||||
BuilderComponentPluginFactory,
|
||||
ChunkType,
|
||||
FileType,
|
||||
ICodeStruct,
|
||||
IProjectInfo,
|
||||
} from '../../../../../types';
|
||||
|
||||
const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
||||
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
||||
const next: ICodeStruct = {
|
||||
...pre,
|
||||
};
|
||||
|
||||
const ir = next.ir as IProjectInfo;
|
||||
|
||||
next.chunks.push({
|
||||
type: ChunkType.STRING,
|
||||
fileType: FileType.SCSS,
|
||||
name: COMMON_CHUNK_NAME.StyleDepsImport,
|
||||
content: `
|
||||
// 引入默认全局样式
|
||||
@import '@alifd/next/reset.scss';
|
||||
`,
|
||||
linkAfter: [],
|
||||
});
|
||||
|
||||
next.chunks.push({
|
||||
type: ChunkType.STRING,
|
||||
fileType: FileType.SCSS,
|
||||
name: COMMON_CHUNK_NAME.StyleCssContent,
|
||||
content: `
|
||||
body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
`,
|
||||
linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport],
|
||||
});
|
||||
|
||||
next.chunks.push({
|
||||
type: ChunkType.STRING,
|
||||
fileType: FileType.SCSS,
|
||||
name: COMMON_CHUNK_NAME.StyleCssContent,
|
||||
content: ir.css || '',
|
||||
linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport],
|
||||
});
|
||||
|
||||
return next;
|
||||
};
|
||||
return plugin;
|
||||
};
|
||||
|
||||
export default pluginFactory;
|
||||
@ -0,0 +1,41 @@
|
||||
import {
|
||||
BuilderComponentPlugin,
|
||||
BuilderComponentPluginFactory,
|
||||
ChunkType,
|
||||
FileType,
|
||||
ICodeStruct,
|
||||
} from '../../../../../types';
|
||||
import { COMMON_CHUNK_NAME } from '../../../../../const/generator';
|
||||
|
||||
const pluginFactory: BuilderComponentPluginFactory<unknown> = () => {
|
||||
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
||||
const next: ICodeStruct = {
|
||||
...pre,
|
||||
};
|
||||
|
||||
next.chunks.push({
|
||||
type: ChunkType.STRING,
|
||||
fileType: FileType.JSX,
|
||||
name: COMMON_CHUNK_NAME.FileMainContent,
|
||||
content: `
|
||||
import { Outlet } from 'ice';
|
||||
import BasicLayout from '@/layouts/BasicLayout';
|
||||
|
||||
export default function Layout() {
|
||||
return (
|
||||
<BasicLayout>
|
||||
<Outlet />
|
||||
</BasicLayout>
|
||||
);;
|
||||
}
|
||||
`,
|
||||
linkAfter: [],
|
||||
});
|
||||
|
||||
return next;
|
||||
};
|
||||
|
||||
return plugin;
|
||||
};
|
||||
|
||||
export default pluginFactory;
|
||||
@ -0,0 +1,119 @@
|
||||
import { PackageJSON } from '@alilc/lowcode-types';
|
||||
|
||||
import { COMMON_CHUNK_NAME } from '../../../../../const/generator';
|
||||
|
||||
import {
|
||||
BuilderComponentPlugin,
|
||||
BuilderComponentPluginFactory,
|
||||
ChunkType,
|
||||
FileType,
|
||||
ICodeStruct,
|
||||
IProjectInfo,
|
||||
} from '../../../../../types';
|
||||
import { buildDataSourceDependencies } from '../../../../../utils/dataSource';
|
||||
|
||||
interface IIceJs3PackageJSON extends PackageJSON {
|
||||
originTemplate: string;
|
||||
}
|
||||
|
||||
export type IceJs3PackageJsonPluginConfig = {
|
||||
|
||||
/**
|
||||
* 数据源配置
|
||||
*/
|
||||
datasourceConfig?: {
|
||||
|
||||
/** 数据源引擎的版本 */
|
||||
engineVersion?: string;
|
||||
|
||||
/** 数据源引擎的包名 */
|
||||
enginePackage?: string;
|
||||
|
||||
/** 数据源 handlers 的版本 */
|
||||
handlersVersion?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
|
||||
/** 数据源 handlers 的包名 */
|
||||
handlersPackages?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
};
|
||||
|
||||
/** 包名 */
|
||||
packageName?: string;
|
||||
|
||||
/** 版本 */
|
||||
packageVersion?: string;
|
||||
};
|
||||
|
||||
const pluginFactory: BuilderComponentPluginFactory<IceJs3PackageJsonPluginConfig> = (cfg) => {
|
||||
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
||||
const next: ICodeStruct = {
|
||||
...pre,
|
||||
};
|
||||
|
||||
const ir = next.ir as IProjectInfo;
|
||||
|
||||
const packageJson: IIceJs3PackageJSON = {
|
||||
name: cfg?.packageName || 'icejs3-demo-app',
|
||||
version: cfg?.packageVersion || '0.1.5',
|
||||
description: 'icejs 3 轻量级模板,使用 JavaScript,仅包含基础的 Layout。',
|
||||
dependencies: {
|
||||
moment: '^2.24.0',
|
||||
react: '^18.2.0',
|
||||
'react-dom': '^18.2.0',
|
||||
'react-router': '^6.9.0',
|
||||
'react-router-dom': '^6.9.0',
|
||||
'intl-messageformat': '^9.3.6',
|
||||
'@alifd/next': '1.26.15',
|
||||
'@ice/runtime': '^1.0.0',
|
||||
// 数据源相关的依赖:
|
||||
...buildDataSourceDependencies(ir, cfg?.datasourceConfig),
|
||||
},
|
||||
devDependencies: {
|
||||
'@ice/app': '^3.0.0',
|
||||
'@types/react': '^18.0.0',
|
||||
'@types/react-dom': '^18.0.0',
|
||||
'@types/node': '^18.11.17',
|
||||
'@ice/plugin-fusion': '^1.0.1',
|
||||
'@ice/plugin-moment-locales': '^1.0.0',
|
||||
eslint: '^6.0.1',
|
||||
stylelint: '^13.2.0',
|
||||
},
|
||||
scripts: {
|
||||
start: 'ice start',
|
||||
build: 'ice build',
|
||||
lint: 'npm run eslint && npm run stylelint',
|
||||
eslint: 'eslint --cache --ext .js,.jsx ./',
|
||||
stylelint: 'stylelint ./**/*.scss',
|
||||
},
|
||||
engines: {
|
||||
node: '>=14.0.0',
|
||||
},
|
||||
repository: {
|
||||
type: 'git',
|
||||
url: 'http://gitlab.xxx.com/msd/leak-scan/tree/master',
|
||||
},
|
||||
private: true,
|
||||
originTemplate: '@alifd/scaffold-lite-js',
|
||||
};
|
||||
|
||||
ir.packages.forEach((packageInfo) => {
|
||||
packageJson.dependencies[packageInfo.package] = packageInfo.version;
|
||||
});
|
||||
|
||||
next.chunks.push({
|
||||
type: ChunkType.JSON,
|
||||
fileType: FileType.JSON,
|
||||
name: COMMON_CHUNK_NAME.FileMainContent,
|
||||
content: packageJson,
|
||||
linkAfter: [],
|
||||
});
|
||||
|
||||
return next;
|
||||
};
|
||||
return plugin;
|
||||
};
|
||||
|
||||
export default pluginFactory;
|
||||
@ -0,0 +1,12 @@
|
||||
import { ResultFile } from '@alilc/lowcode-types';
|
||||
import { createResultFile } from '../../../../../../utils/resultHelper';
|
||||
|
||||
export default function getFile(): [string[], ResultFile] {
|
||||
const file = createResultFile(
|
||||
'README',
|
||||
'md',
|
||||
'This project is generated by lowcode-code-generator & lowcode-solution-icejs3.',
|
||||
);
|
||||
|
||||
return [[], file];
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
import { ResultFile } from '@alilc/lowcode-types';
|
||||
import { createResultFile } from '../../../../../../utils/resultHelper';
|
||||
|
||||
export default function getFile(): [string[], ResultFile] {
|
||||
const file = createResultFile(
|
||||
'.browserslistrc',
|
||||
'',
|
||||
`defaults
|
||||
ios_saf 9
|
||||
`,
|
||||
);
|
||||
|
||||
return [[], file];
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
import { ResultFile } from '@alilc/lowcode-types';
|
||||
import { createResultFile } from '../../../../../../utils/resultHelper';
|
||||
|
||||
/* eslint-disable max-len */
|
||||
export default function getFile(): [string[], ResultFile] {
|
||||
const file = createResultFile(
|
||||
'document',
|
||||
'tsx',
|
||||
`import React from 'react';
|
||||
import { Meta, Title, Links, Main, Scripts } from 'ice';
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<html>
|
||||
<head>
|
||||
<meta charSet="utf-8" />
|
||||
<meta name="description" content="ice.js 3 lite scaffold" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
|
||||
<Meta />
|
||||
<Title />
|
||||
<Links />
|
||||
</head>
|
||||
<body>
|
||||
<Main />
|
||||
<script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" />
|
||||
<script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" />
|
||||
<script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" />
|
||||
<script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" />
|
||||
<script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" />
|
||||
<script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" />
|
||||
<Scripts />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}`,
|
||||
);
|
||||
|
||||
return [['src'], file];
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
import { ResultFile } from '@alilc/lowcode-types';
|
||||
import { createResultFile } from '../../../../../../utils/resultHelper';
|
||||
|
||||
export default function getFile(): [string[], ResultFile] {
|
||||
const file = createResultFile(
|
||||
'.gitignore',
|
||||
'',
|
||||
`
|
||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
|
||||
# production
|
||||
build/
|
||||
dist/
|
||||
tmp/
|
||||
lib/
|
||||
|
||||
# misc
|
||||
.idea/
|
||||
.happypack
|
||||
.DS_Store
|
||||
*.swp
|
||||
*.dia~
|
||||
.ice
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
index.module.scss.d.ts
|
||||
`,
|
||||
);
|
||||
|
||||
return [[], file];
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
import { ResultFile } from '@alilc/lowcode-types';
|
||||
import { createResultFile } from '../../../../../../../../../../../utils/resultHelper';
|
||||
|
||||
export default function getFile(): [string[], ResultFile] {
|
||||
const file = createResultFile(
|
||||
'index',
|
||||
'jsx',
|
||||
`
|
||||
import React from 'react';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<p className={styles.footer}>
|
||||
<span className={styles.logo}>Alibaba Fusion</span>
|
||||
<br />
|
||||
<span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>
|
||||
</p>
|
||||
);
|
||||
}
|
||||
`,
|
||||
);
|
||||
|
||||
return [['src', 'layouts', 'BasicLayout', 'components', 'Footer'], file];
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
import { ResultFile } from '@alilc/lowcode-types';
|
||||
import { createResultFile } from '../../../../../../../../../../../utils/resultHelper';
|
||||
|
||||
export default function getFile(): [string[], ResultFile] {
|
||||
const file = createResultFile(
|
||||
'index',
|
||||
'module.scss',
|
||||
`
|
||||
.footer {
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.copyright {
|
||||
font-size: 12px;
|
||||
}
|
||||
`,
|
||||
);
|
||||
|
||||
return [['src', 'layouts', 'BasicLayout', 'components', 'Footer'], file];
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
import { ResultFile } from '@alilc/lowcode-types';
|
||||
import { createResultFile } from '../../../../../../../../../../../utils/resultHelper';
|
||||
|
||||
export default function getFile(): [string[], ResultFile] {
|
||||
const file = createResultFile(
|
||||
'index',
|
||||
'jsx',
|
||||
`
|
||||
import React from 'react';
|
||||
import { Link } from 'ice';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
export default function Logo({ image, text, url }) {
|
||||
return (
|
||||
<div className="logo">
|
||||
<Link to={url || '/'} className={styles.logo}>
|
||||
{image && <img src={image} alt="logo" />}
|
||||
<span>{text}</span>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
`,
|
||||
);
|
||||
|
||||
return [['src', 'layouts', 'BasicLayout', 'components', 'Logo'], file];
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
import { ResultFile } from '@alilc/lowcode-types';
|
||||
import { createResultFile } from '../../../../../../../../../../../utils/resultHelper';
|
||||
|
||||
export default function getFile(): [string[], ResultFile] {
|
||||
const file = createResultFile(
|
||||
'index',
|
||||
'module.scss',
|
||||
`
|
||||
.logo{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: $color-text1-1;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
|
||||
&:visited, &:link {
|
||||
color: $color-text1-1;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 24px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
`,
|
||||
);
|
||||
|
||||
return [['src', 'layouts', 'BasicLayout', 'components', 'Logo'], file];
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
import { ResultFile } from '@alilc/lowcode-types';
|
||||
import { createResultFile } from '../../../../../../../../../../../utils/resultHelper';
|
||||
|
||||
export default function getFile(): [string[], ResultFile] {
|
||||
const file = createResultFile(
|
||||
'index',
|
||||
'jsx',
|
||||
`import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link, useLocation } from 'ice';
|
||||
import { Nav } from '@alifd/next';
|
||||
import { asideMenuConfig } from '../../menuConfig';
|
||||
|
||||
const { SubNav } = Nav;
|
||||
const NavItem = Nav.Item;
|
||||
|
||||
function getNavMenuItems(menusData) {
|
||||
if (!menusData) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return menusData
|
||||
.filter(item => item.name && !item.hideInMenu)
|
||||
.map((item, index) => getSubMenuOrItem(item, index));
|
||||
}
|
||||
|
||||
function getSubMenuOrItem(item, index) {
|
||||
if (item.children && item.children.some(child => child.name)) {
|
||||
const childrenItems = getNavMenuItems(item.children);
|
||||
|
||||
if (childrenItems && childrenItems.length > 0) {
|
||||
const subNav = (
|
||||
<SubNav key={index} icon={item.icon} label={item.name}>
|
||||
{childrenItems}
|
||||
</SubNav>
|
||||
);
|
||||
return subNav;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const navItem = (
|
||||
<NavItem key={item.path} icon={item.icon}>
|
||||
<Link to={item.path}>{item.name}</Link>
|
||||
</NavItem>
|
||||
);
|
||||
return navItem;
|
||||
}
|
||||
|
||||
const Navigation = (props, context) => {
|
||||
const location = useLocation();
|
||||
const { pathname } = location;
|
||||
const { isCollapse } = context;
|
||||
return (
|
||||
<Nav
|
||||
type="primary"
|
||||
selectedKeys={[pathname]}
|
||||
defaultSelectedKeys={[pathname]}
|
||||
embeddable
|
||||
openMode="single"
|
||||
iconOnly={isCollapse}
|
||||
hasArrow={false}
|
||||
mode={isCollapse ? 'popup' : 'inline'}
|
||||
>
|
||||
{getNavMenuItems(asideMenuConfig)}
|
||||
</Nav>
|
||||
);
|
||||
};
|
||||
|
||||
Navigation.contextTypes = {
|
||||
isCollapse: PropTypes.bool,
|
||||
};
|
||||
export default Navigation;
|
||||
`,
|
||||
);
|
||||
|
||||
return [['src', 'layouts', 'BasicLayout', 'components', 'PageNav'], file];
|
||||
}
|
||||
@ -0,0 +1,92 @@
|
||||
import { ResultFile } from '@alilc/lowcode-types';
|
||||
import { createResultFile } from '../../../../../../../../../utils/resultHelper';
|
||||
|
||||
export default function getFile(): [string[], ResultFile] {
|
||||
const file = createResultFile(
|
||||
'index',
|
||||
'jsx',
|
||||
`
|
||||
import React, { useState } from 'react';
|
||||
import { Shell, ConfigProvider } from '@alifd/next';
|
||||
import PageNav from './components/PageNav';
|
||||
import Logo from './components/Logo';
|
||||
import Footer from './components/Footer';
|
||||
|
||||
(function() {
|
||||
const throttle = function(type, name, obj = window) {
|
||||
let running = false;
|
||||
|
||||
const func = () => {
|
||||
if (running) {
|
||||
return;
|
||||
}
|
||||
|
||||
running = true;
|
||||
requestAnimationFrame(() => {
|
||||
obj.dispatchEvent(new CustomEvent(name));
|
||||
running = false;
|
||||
});
|
||||
};
|
||||
|
||||
obj.addEventListener(type, func);
|
||||
};
|
||||
|
||||
throttle('resize', 'optimizedResize');
|
||||
})();
|
||||
|
||||
export default function BasicLayout({ children }) {
|
||||
const getDevice = width => {
|
||||
const isPhone =
|
||||
typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);
|
||||
|
||||
if (width < 680 || isPhone) {
|
||||
return 'phone';
|
||||
}
|
||||
if (width < 1280 && width > 680) {
|
||||
return 'tablet';
|
||||
}
|
||||
return 'desktop';
|
||||
};
|
||||
|
||||
const [device, setDevice] = useState(getDevice(NaN));
|
||||
window.addEventListener('optimizedResize', e => {
|
||||
setDevice(getDevice(e && e.target && e.target.innerWidth));
|
||||
});
|
||||
return (
|
||||
<ConfigProvider device={device}>
|
||||
<Shell
|
||||
type="dark"
|
||||
style={{
|
||||
minHeight: '100vh',
|
||||
}}
|
||||
>
|
||||
<Shell.Branding>
|
||||
<Logo
|
||||
image="https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png"
|
||||
text="Logo"
|
||||
/>
|
||||
</Shell.Branding>
|
||||
<Shell.Navigation
|
||||
direction="hoz"
|
||||
style={{
|
||||
marginRight: 10,
|
||||
}}
|
||||
></Shell.Navigation>
|
||||
<Shell.Action></Shell.Action>
|
||||
<Shell.Navigation>
|
||||
<PageNav />
|
||||
</Shell.Navigation>
|
||||
|
||||
<Shell.Content>{children}</Shell.Content>
|
||||
<Shell.Footer>
|
||||
<Footer />
|
||||
</Shell.Footer>
|
||||
</Shell>
|
||||
</ConfigProvider>
|
||||
);
|
||||
}
|
||||
`,
|
||||
);
|
||||
|
||||
return [['src', 'layouts', 'BasicLayout'], file];
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
import { ResultFile } from '@alilc/lowcode-types';
|
||||
import { createResultFile } from '../../../../../../../../../utils/resultHelper';
|
||||
|
||||
export default function getFile(): [string[], ResultFile] {
|
||||
const file = createResultFile(
|
||||
'menuConfig',
|
||||
'js',
|
||||
`
|
||||
const headerMenuConfig = [];
|
||||
const asideMenuConfig = [
|
||||
{
|
||||
name: 'Dashboard',
|
||||
path: '/',
|
||||
icon: 'smile',
|
||||
},
|
||||
];
|
||||
export { headerMenuConfig, asideMenuConfig };
|
||||
`,
|
||||
);
|
||||
|
||||
return [['src', 'layouts', 'BasicLayout'], file];
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
import { ResultFile } from '@alilc/lowcode-types';
|
||||
import { createResultFile } from '../../../../../../utils/resultHelper';
|
||||
|
||||
export default function getFile(): [string[], ResultFile] {
|
||||
const file = createResultFile(
|
||||
'tsconfig',
|
||||
'json',
|
||||
`
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"module": "ESNext",
|
||||
"target": "ESNext",
|
||||
"lib": ["DOM", "ESNext", "DOM.Iterable"],
|
||||
"jsx": "react-jsx",
|
||||
"moduleResolution": "node",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"noImplicitAny": false,
|
||||
"importHelpers": true,
|
||||
"strictNullChecks": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"skipLibCheck": true,
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
"ice": [".ice"]
|
||||
}
|
||||
},
|
||||
"include": ["src", ".ice"],
|
||||
"exclude": ["build"]
|
||||
}
|
||||
`,
|
||||
);
|
||||
|
||||
return [[], file];
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
import { ResultFile } from '@alilc/lowcode-types';
|
||||
import { createResultFile } from '../../../../../../utils/resultHelper';
|
||||
|
||||
export default function getFile(): [string[], ResultFile] {
|
||||
const file = createResultFile(
|
||||
'typings.d',
|
||||
'ts',
|
||||
`/// <reference types="@ice/app/types" />
|
||||
|
||||
export {};
|
||||
declare global {
|
||||
interface Window {
|
||||
g_config: Record<string, any>;
|
||||
}
|
||||
}
|
||||
`,
|
||||
);
|
||||
|
||||
return [['src'], file];
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
import { IProjectTemplate } from '../../../../../types';
|
||||
import { generateStaticFiles } from './static-files';
|
||||
|
||||
const icejs3Template: IProjectTemplate = {
|
||||
slots: {
|
||||
components: {
|
||||
path: ['src', 'components'],
|
||||
fileName: 'index',
|
||||
},
|
||||
pages: {
|
||||
path: ['src', 'pages'],
|
||||
fileName: 'index',
|
||||
},
|
||||
entry: {
|
||||
path: ['src'],
|
||||
fileName: 'app',
|
||||
},
|
||||
constants: {
|
||||
path: ['src'],
|
||||
fileName: 'constants',
|
||||
},
|
||||
utils: {
|
||||
path: ['src'],
|
||||
fileName: 'utils',
|
||||
},
|
||||
i18n: {
|
||||
path: ['src'],
|
||||
fileName: 'i18n',
|
||||
},
|
||||
globalStyle: {
|
||||
path: ['src'],
|
||||
fileName: 'global',
|
||||
},
|
||||
packageJSON: {
|
||||
path: [],
|
||||
fileName: 'package',
|
||||
},
|
||||
appConfig: {
|
||||
path: ['src'],
|
||||
fileName: 'app',
|
||||
},
|
||||
buildConfig: {
|
||||
path: [],
|
||||
fileName: 'ice.config',
|
||||
},
|
||||
layout: {
|
||||
path: ['src', 'pages'],
|
||||
fileName: 'layout',
|
||||
},
|
||||
},
|
||||
|
||||
generateTemplate() {
|
||||
return generateStaticFiles();
|
||||
},
|
||||
};
|
||||
|
||||
export default icejs3Template;
|
||||
@ -0,0 +1,33 @@
|
||||
import { ResultDir } from '@alilc/lowcode-types';
|
||||
import { createResultDir } from '../../../../../utils/resultHelper';
|
||||
import { runFileGenerator } from '../../../../../utils/templateHelper';
|
||||
|
||||
import file1 from './files/gitignore';
|
||||
import file2 from './files/README.md';
|
||||
import file3 from './files/browserslistrc';
|
||||
import file4 from './files/typings';
|
||||
import file5 from './files/document';
|
||||
import file6 from './files/src/layouts/BasicLayout/components/Footer/index.jsx';
|
||||
import file7 from './files/src/layouts/BasicLayout/components/Footer/index.style';
|
||||
import file8 from './files/src/layouts/BasicLayout/components/Logo/index.jsx';
|
||||
import file9 from './files/src/layouts/BasicLayout/components/Logo/index.style';
|
||||
import file10 from './files/src/layouts/BasicLayout/components/PageNav/index.jsx';
|
||||
import file11 from './files/src/layouts/BasicLayout/index.jsx';
|
||||
import file12 from './files/src/layouts/BasicLayout/menuConfig.js';
|
||||
|
||||
export function generateStaticFiles(root = createResultDir('.')): ResultDir {
|
||||
runFileGenerator(root, file1);
|
||||
runFileGenerator(root, file2);
|
||||
runFileGenerator(root, file3);
|
||||
runFileGenerator(root, file4);
|
||||
runFileGenerator(root, file5);
|
||||
runFileGenerator(root, file6);
|
||||
runFileGenerator(root, file7);
|
||||
runFileGenerator(root, file8);
|
||||
runFileGenerator(root, file9);
|
||||
runFileGenerator(root, file10);
|
||||
runFileGenerator(root, file11);
|
||||
runFileGenerator(root, file12);
|
||||
|
||||
return root;
|
||||
}
|
||||
109
modules/code-generator/src/solutions/icejs3.ts
Normal file
109
modules/code-generator/src/solutions/icejs3.ts
Normal file
@ -0,0 +1,109 @@
|
||||
import { IProjectBuilder, IProjectBuilderOptions } from '../types';
|
||||
|
||||
import { createProjectBuilder } from '../generator/ProjectBuilder';
|
||||
|
||||
import esmodule from '../plugins/common/esmodule';
|
||||
import containerClass from '../plugins/component/react/containerClass';
|
||||
import containerInitState from '../plugins/component/react/containerInitState';
|
||||
import containerInjectContext from '../plugins/component/react/containerInjectContext';
|
||||
import containerInjectUtils from '../plugins/component/react/containerInjectUtils';
|
||||
import containerInjectDataSourceEngine from '../plugins/component/react/containerInjectDataSourceEngine';
|
||||
import containerInjectConstants from '../plugins/component/react/containerInjectConstants';
|
||||
import containerInjectI18n from '../plugins/component/react/containerInjectI18n';
|
||||
import containerLifeCycle from '../plugins/component/react/containerLifeCycle';
|
||||
import containerMethod from '../plugins/component/react/containerMethod';
|
||||
import jsx from '../plugins/component/react/jsx';
|
||||
import reactCommonDeps from '../plugins/component/react/reactCommonDeps';
|
||||
import css from '../plugins/component/style/css';
|
||||
import constants from '../plugins/project/constants';
|
||||
import i18n from '../plugins/project/i18n';
|
||||
import utils from '../plugins/project/utils';
|
||||
|
||||
import icejs3 from '../plugins/project/framework/icejs3';
|
||||
|
||||
import { prettier } from '../postprocessor';
|
||||
|
||||
export type IceJs3ProjectBuilderOptions = IProjectBuilderOptions;
|
||||
|
||||
export default function createIceJsProjectBuilder(
|
||||
options?: IceJs3ProjectBuilderOptions,
|
||||
): IProjectBuilder {
|
||||
return createProjectBuilder({
|
||||
inStrictMode: options?.inStrictMode,
|
||||
extraContextData: { ...options },
|
||||
template: icejs3.template,
|
||||
plugins: {
|
||||
components: [
|
||||
reactCommonDeps(),
|
||||
esmodule({
|
||||
fileType: 'jsx',
|
||||
}),
|
||||
containerClass(),
|
||||
containerInjectContext(),
|
||||
containerInjectUtils(),
|
||||
containerInjectDataSourceEngine(),
|
||||
containerInjectI18n(),
|
||||
containerInitState(),
|
||||
containerLifeCycle(),
|
||||
containerMethod(),
|
||||
jsx({
|
||||
nodeTypeMapping: {
|
||||
Div: 'div',
|
||||
Component: 'div',
|
||||
Page: 'div',
|
||||
Block: 'div',
|
||||
},
|
||||
}),
|
||||
css(),
|
||||
],
|
||||
pages: [
|
||||
reactCommonDeps(),
|
||||
esmodule({
|
||||
fileType: 'jsx',
|
||||
}),
|
||||
containerClass(),
|
||||
containerInjectContext(),
|
||||
containerInjectUtils(),
|
||||
containerInjectDataSourceEngine(),
|
||||
containerInjectI18n(),
|
||||
containerInjectConstants(),
|
||||
containerInitState(),
|
||||
containerLifeCycle(),
|
||||
containerMethod(),
|
||||
jsx({
|
||||
nodeTypeMapping: {
|
||||
Div: 'div',
|
||||
Component: 'div',
|
||||
Page: 'div',
|
||||
Block: 'div',
|
||||
Box: 'div',
|
||||
},
|
||||
}),
|
||||
css(),
|
||||
],
|
||||
constants: [constants()],
|
||||
utils: [esmodule(), utils('react')],
|
||||
i18n: [i18n()],
|
||||
globalStyle: [icejs3.plugins.globalStyle()],
|
||||
packageJSON: [icejs3.plugins.packageJSON()],
|
||||
buildConfig: [icejs3.plugins.buildConfig()],
|
||||
appConfig: [icejs3.plugins.appConfig()],
|
||||
layout: [icejs3.plugins.layout()],
|
||||
},
|
||||
postProcessors: [prettier()],
|
||||
customizeBuilderOptions: options?.customizeBuilderOptions,
|
||||
});
|
||||
}
|
||||
|
||||
export const plugins = {
|
||||
containerClass,
|
||||
containerInitState,
|
||||
containerInjectContext,
|
||||
containerInjectUtils,
|
||||
containerInjectI18n,
|
||||
containerInjectDataSourceEngine,
|
||||
containerLifeCycle,
|
||||
containerMethod,
|
||||
jsx,
|
||||
commonDeps: reactCommonDeps,
|
||||
};
|
||||
12
modules/code-generator/src/utils/format.ts
Normal file
12
modules/code-generator/src/utils/format.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import prettier from 'prettier';
|
||||
import parserBabel from 'prettier/parser-babel';
|
||||
|
||||
export function format(content: string, options = {}) {
|
||||
return prettier.format(content, {
|
||||
parser: 'babel',
|
||||
plugins: [parserBabel],
|
||||
singleQuote: true,
|
||||
jsxSingleQuote: false,
|
||||
...options,
|
||||
});
|
||||
}
|
||||
20
modules/code-generator/src/utils/theme.ts
Normal file
20
modules/code-generator/src/utils/theme.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* 获取主题信息
|
||||
* @param theme theme 形如 @alife/theme-97 或者 @alife/theme-97@^1.0.0
|
||||
*/
|
||||
|
||||
export interface ThemeInfo {
|
||||
name: string;
|
||||
version?: string;
|
||||
}
|
||||
|
||||
export function getThemeInfo(theme: string): ThemeInfo {
|
||||
const sepIdx = theme.indexOf('@', 1);
|
||||
if (sepIdx === -1) {
|
||||
return { name: theme };
|
||||
}
|
||||
return {
|
||||
name: theme.slice(0, sepIdx),
|
||||
version: theme.slice(sepIdx + 1),
|
||||
};
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
defaults
|
||||
ios_saf 9
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
|
||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
|
||||
# production
|
||||
build/
|
||||
dist/
|
||||
tmp/
|
||||
lib/
|
||||
|
||||
# misc
|
||||
.idea/
|
||||
.happypack
|
||||
.DS_Store
|
||||
*.swp
|
||||
*.dia~
|
||||
.ice
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
index.module.scss.d.ts
|
||||
|
||||
@ -0,0 +1 @@
|
||||
This project is generated by lowcode-code-generator & lowcode-solution-icejs3.
|
||||
@ -0,0 +1,90 @@
|
||||
import { join } from 'path';
|
||||
import { defineConfig } from '@ice/app';
|
||||
import _ from 'lodash';
|
||||
import fusion from '@ice/plugin-fusion';
|
||||
import locales from '@ice/plugin-moment-locales';
|
||||
import type { Plugin } from '@ice/app/esm/types';
|
||||
|
||||
interface PluginOptions {
|
||||
id: string;
|
||||
}
|
||||
|
||||
const plugin: Plugin<PluginOptions> = (options) => ({
|
||||
// name 可选,插件名称
|
||||
name: 'plugin-name',
|
||||
// setup 必选,用于定制工程构建配置
|
||||
setup: ({ onGetConfig, modifyUserConfig }) => {
|
||||
modifyUserConfig('codeSplitting', 'page');
|
||||
|
||||
onGetConfig((config) => {
|
||||
config.entry = {
|
||||
web: join(process.cwd(), '.ice/entry.client.tsx'),
|
||||
};
|
||||
|
||||
config.cssFilename = '[name].css';
|
||||
|
||||
config.configureWebpack = config.configureWebpack || [];
|
||||
config.configureWebpack?.push((webpackConfig) => {
|
||||
if (webpackConfig.output) {
|
||||
webpackConfig.output.filename = '[name].js';
|
||||
webpackConfig.output.chunkFilename = '[name].js';
|
||||
}
|
||||
return webpackConfig;
|
||||
});
|
||||
|
||||
config.swcOptions = _.merge(config.swcOptions, {
|
||||
compilationConfig: {
|
||||
jsc: {
|
||||
transform: {
|
||||
react: {
|
||||
runtime: 'classic',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// 解决 webpack publicPath 问题
|
||||
config.transforms = config.transforms || [];
|
||||
config.transforms.push((source: string, id: string) => {
|
||||
if (id.includes('.ice/entry.client.tsx')) {
|
||||
let code = `
|
||||
if (!__webpack_public_path__?.startsWith('http') && document.currentScript) {
|
||||
// @ts-ignore
|
||||
__webpack_public_path__ = document.currentScript.src.replace(/^(.*\\/)[^/]+$/, '$1');
|
||||
window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {};
|
||||
window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__;
|
||||
}
|
||||
`;
|
||||
code += source;
|
||||
return { code };
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// The project config, see https://v3.ice.work/docs/guide/basic/config
|
||||
const minify = process.env.NODE_ENV === 'production' ? 'swc' : false;
|
||||
export default defineConfig(() => ({
|
||||
ssr: false,
|
||||
ssg: false,
|
||||
minify,
|
||||
|
||||
externals: {
|
||||
react: 'React',
|
||||
'react-dom': 'ReactDOM',
|
||||
'react-dom/client': 'ReactDOM',
|
||||
'@alifd/next': 'Next',
|
||||
lodash: 'var window._',
|
||||
'@alilc/lowcode-engine': 'var window.AliLowCodeEngine',
|
||||
},
|
||||
plugins: [
|
||||
fusion({
|
||||
importStyle: true,
|
||||
}),
|
||||
locales(),
|
||||
plugin(),
|
||||
],
|
||||
}));
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "icejs3-demo-app",
|
||||
"version": "0.1.5",
|
||||
"description": "icejs 3 轻量级模板,使用 JavaScript,仅包含基础的 Layout。",
|
||||
"dependencies": {
|
||||
"moment": "^2.24.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router": "^6.9.0",
|
||||
"react-router-dom": "^6.9.0",
|
||||
"intl-messageformat": "^9.3.6",
|
||||
"@alifd/next": "1.19.18",
|
||||
"@ice/runtime": "^1.0.0",
|
||||
"@alilc/lowcode-datasource-engine": "^1.0.0",
|
||||
"@alilc/lowcode-datasource-url-params-handler": "^1.0.0",
|
||||
"@alilc/lowcode-datasource-fetch-handler": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ice/app": "^3.0.0",
|
||||
"@types/react": "^18.0.0",
|
||||
"@types/react-dom": "^18.0.0",
|
||||
"@types/node": "^18.11.17",
|
||||
"@ice/plugin-fusion": "^1.0.1",
|
||||
"@ice/plugin-moment-locales": "^1.0.0",
|
||||
"eslint": "^6.0.1",
|
||||
"stylelint": "^13.2.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "ice start",
|
||||
"build": "ice build",
|
||||
"lint": "npm run eslint && npm run stylelint",
|
||||
"eslint": "eslint --cache --ext .js,.jsx ./",
|
||||
"stylelint": "stylelint ./**/*.scss"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://gitlab.xxx.com/msd/leak-scan/tree/master"
|
||||
},
|
||||
"private": true,
|
||||
"originTemplate": "@alifd/scaffold-lite-js"
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
import { defineAppConfig } from 'ice';
|
||||
|
||||
// App config, see https://v3.ice.work/docs/guide/basic/app
|
||||
export default defineAppConfig(() => ({
|
||||
// Set your configs here.
|
||||
app: {
|
||||
rootId: 'App',
|
||||
},
|
||||
router: {
|
||||
type: 'browser',
|
||||
basename: '/',
|
||||
},
|
||||
}));
|
||||
@ -0,0 +1,3 @@
|
||||
const __$$constants = { ENV: 'prod', DOMAIN: 'xxx.xxx.com' };
|
||||
|
||||
export default __$$constants;
|
||||
@ -0,0 +1,29 @@
|
||||
import React from 'react';
|
||||
import { Meta, Title, Links, Main, Scripts } from 'ice';
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<html>
|
||||
<head>
|
||||
<meta charSet="utf-8" />
|
||||
<meta name="description" content="ice.js 3 lite scaffold" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
|
||||
<Meta />
|
||||
<Title />
|
||||
<Links />
|
||||
</head>
|
||||
<body>
|
||||
<Main />
|
||||
<script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" />
|
||||
<script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" />
|
||||
<script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" />
|
||||
<script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" />
|
||||
<script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" />
|
||||
<script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" />
|
||||
<Scripts />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
// 引入默认全局样式
|
||||
@import '@alifd/next/reset.scss';
|
||||
|
||||
body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 12px;
|
||||
}
|
||||
.table {
|
||||
width: 100px;
|
||||
}
|
||||
@ -0,0 +1,77 @@
|
||||
const i18nConfig = {};
|
||||
|
||||
let locale =
|
||||
typeof navigator === 'object' && typeof navigator.language === 'string'
|
||||
? navigator.language
|
||||
: 'zh-CN';
|
||||
|
||||
const getLocale = () => locale;
|
||||
|
||||
const setLocale = (target) => {
|
||||
locale = target;
|
||||
};
|
||||
|
||||
const isEmptyVariables = (variables) =>
|
||||
(Array.isArray(variables) && variables.length === 0) ||
|
||||
(typeof variables === 'object' &&
|
||||
(!variables || Object.keys(variables).length === 0));
|
||||
|
||||
// 按低代码规范里面的要求进行变量替换
|
||||
const format = (msg, variables) =>
|
||||
typeof msg === 'string'
|
||||
? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '')
|
||||
: msg;
|
||||
|
||||
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
|
||||
const msg =
|
||||
i18nConfig[locale]?.[id] ??
|
||||
i18nConfig[locale.replace('-', '_')]?.[id] ??
|
||||
defaultMessage;
|
||||
if (msg == null) {
|
||||
console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);
|
||||
return fallback === undefined ? `${id}` : fallback;
|
||||
}
|
||||
|
||||
return format(msg, variables);
|
||||
};
|
||||
|
||||
const i18n = (id, params) => {
|
||||
return i18nFormat({ id }, params);
|
||||
};
|
||||
|
||||
// 将国际化的一些方法注入到目标对象&上下文中
|
||||
const _inject2 = (target) => {
|
||||
target.i18n = i18n;
|
||||
target.getLocale = getLocale;
|
||||
target.setLocale = (locale) => {
|
||||
setLocale(locale);
|
||||
target.forceUpdate();
|
||||
};
|
||||
target._i18nText = (t) => {
|
||||
// 优先取直接传过来的语料
|
||||
const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];
|
||||
if (localMsg != null) {
|
||||
return format(localMsg, t.params);
|
||||
}
|
||||
|
||||
// 其次用项目级别的
|
||||
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
|
||||
if (projectMsg != null) {
|
||||
return projectMsg;
|
||||
}
|
||||
|
||||
// 兜底用 use 指定的或默认语言的
|
||||
return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);
|
||||
};
|
||||
|
||||
// 注入到上下文中去
|
||||
if (target._context && target._context !== target) {
|
||||
Object.assign(target._context, {
|
||||
i18n,
|
||||
getLocale,
|
||||
setLocale: target.setLocale,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
|
||||
@ -0,0 +1,14 @@
|
||||
|
||||
import React from 'react';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<p className={styles.footer}>
|
||||
<span className={styles.logo}>Alibaba Fusion</span>
|
||||
<br />
|
||||
<span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
|
||||
.footer {
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.copyright {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@ -0,0 +1,16 @@
|
||||
|
||||
import React from 'react';
|
||||
import { Link } from 'ice';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
export default function Logo({ image, text, url }) {
|
||||
return (
|
||||
<div className="logo">
|
||||
<Link to={url || '/'} className={styles.logo}>
|
||||
{image && <img src={image} alt="logo" />}
|
||||
<span>{text}</span>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
|
||||
.logo{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: $color-text1-1;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
|
||||
&:visited, &:link {
|
||||
color: $color-text1-1;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 24px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,68 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link, useLocation } from 'ice';
|
||||
import { Nav } from '@alifd/next';
|
||||
import { asideMenuConfig } from '../../menuConfig';
|
||||
|
||||
const { SubNav } = Nav;
|
||||
const NavItem = Nav.Item;
|
||||
|
||||
function getNavMenuItems(menusData) {
|
||||
if (!menusData) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return menusData
|
||||
.filter(item => item.name && !item.hideInMenu)
|
||||
.map((item, index) => getSubMenuOrItem(item, index));
|
||||
}
|
||||
|
||||
function getSubMenuOrItem(item, index) {
|
||||
if (item.children && item.children.some(child => child.name)) {
|
||||
const childrenItems = getNavMenuItems(item.children);
|
||||
|
||||
if (childrenItems && childrenItems.length > 0) {
|
||||
const subNav = (
|
||||
<SubNav key={index} icon={item.icon} label={item.name}>
|
||||
{childrenItems}
|
||||
</SubNav>
|
||||
);
|
||||
return subNav;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const navItem = (
|
||||
<NavItem key={item.path} icon={item.icon}>
|
||||
<Link to={item.path}>{item.name}</Link>
|
||||
</NavItem>
|
||||
);
|
||||
return navItem;
|
||||
}
|
||||
|
||||
const Navigation = (props, context) => {
|
||||
const location = useLocation();
|
||||
const { pathname } = location;
|
||||
const { isCollapse } = context;
|
||||
return (
|
||||
<Nav
|
||||
type="primary"
|
||||
selectedKeys={[pathname]}
|
||||
defaultSelectedKeys={[pathname]}
|
||||
embeddable
|
||||
openMode="single"
|
||||
iconOnly={isCollapse}
|
||||
hasArrow={false}
|
||||
mode={isCollapse ? 'popup' : 'inline'}
|
||||
>
|
||||
{getNavMenuItems(asideMenuConfig)}
|
||||
</Nav>
|
||||
);
|
||||
};
|
||||
|
||||
Navigation.contextTypes = {
|
||||
isCollapse: PropTypes.bool,
|
||||
};
|
||||
export default Navigation;
|
||||
|
||||
@ -0,0 +1,81 @@
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { Shell, ConfigProvider } from '@alifd/next';
|
||||
import PageNav from './components/PageNav';
|
||||
import Logo from './components/Logo';
|
||||
import Footer from './components/Footer';
|
||||
|
||||
(function() {
|
||||
const throttle = function(type, name, obj = window) {
|
||||
let running = false;
|
||||
|
||||
const func = () => {
|
||||
if (running) {
|
||||
return;
|
||||
}
|
||||
|
||||
running = true;
|
||||
requestAnimationFrame(() => {
|
||||
obj.dispatchEvent(new CustomEvent(name));
|
||||
running = false;
|
||||
});
|
||||
};
|
||||
|
||||
obj.addEventListener(type, func);
|
||||
};
|
||||
|
||||
throttle('resize', 'optimizedResize');
|
||||
})();
|
||||
|
||||
export default function BasicLayout({ children }) {
|
||||
const getDevice = width => {
|
||||
const isPhone =
|
||||
typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);
|
||||
|
||||
if (width < 680 || isPhone) {
|
||||
return 'phone';
|
||||
}
|
||||
if (width < 1280 && width > 680) {
|
||||
return 'tablet';
|
||||
}
|
||||
return 'desktop';
|
||||
};
|
||||
|
||||
const [device, setDevice] = useState(getDevice(NaN));
|
||||
window.addEventListener('optimizedResize', e => {
|
||||
setDevice(getDevice(e && e.target && e.target.innerWidth));
|
||||
});
|
||||
return (
|
||||
<ConfigProvider device={device}>
|
||||
<Shell
|
||||
type="dark"
|
||||
style={{
|
||||
minHeight: '100vh',
|
||||
}}
|
||||
>
|
||||
<Shell.Branding>
|
||||
<Logo
|
||||
image="https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png"
|
||||
text="Logo"
|
||||
/>
|
||||
</Shell.Branding>
|
||||
<Shell.Navigation
|
||||
direction="hoz"
|
||||
style={{
|
||||
marginRight: 10,
|
||||
}}
|
||||
></Shell.Navigation>
|
||||
<Shell.Action></Shell.Action>
|
||||
<Shell.Navigation>
|
||||
<PageNav />
|
||||
</Shell.Navigation>
|
||||
|
||||
<Shell.Content>{children}</Shell.Content>
|
||||
<Shell.Footer>
|
||||
<Footer />
|
||||
</Shell.Footer>
|
||||
</Shell>
|
||||
</ConfigProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
|
||||
const headerMenuConfig = [];
|
||||
const asideMenuConfig = [
|
||||
{
|
||||
name: 'Dashboard',
|
||||
path: '/',
|
||||
icon: 'smile',
|
||||
},
|
||||
];
|
||||
export { headerMenuConfig, asideMenuConfig };
|
||||
|
||||
@ -0,0 +1,195 @@
|
||||
// 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。
|
||||
// 例外:react 框架的导出名和各种组件名除外。
|
||||
import React from 'react';
|
||||
|
||||
import { Form, Input, NumberPicker, Select, Button } from '@alifd/next';
|
||||
|
||||
import { createUrlParamsHandler as __$$createUrlParamsRequestHandler } from '@alilc/lowcode-datasource-url-params-handler';
|
||||
|
||||
import { createFetchHandler as __$$createFetchRequestHandler } from '@alilc/lowcode-datasource-fetch-handler';
|
||||
|
||||
import { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';
|
||||
|
||||
import utils, { RefsManager } from '../../utils';
|
||||
|
||||
import * as __$$i18n from '../../i18n';
|
||||
|
||||
import __$$constants from '../../constants';
|
||||
|
||||
import './index.css';
|
||||
|
||||
class Test$$Page extends React.Component {
|
||||
_context = this;
|
||||
|
||||
_dataSourceConfig = this._defineDataSourceConfig();
|
||||
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, {
|
||||
runtimeConfig: true,
|
||||
requestHandlersMap: {
|
||||
urlParams: __$$createUrlParamsRequestHandler(window.location.search),
|
||||
fetch: __$$createFetchRequestHandler(),
|
||||
},
|
||||
});
|
||||
|
||||
get dataSourceMap() {
|
||||
return this._dataSourceEngine.dataSourceMap || {};
|
||||
}
|
||||
|
||||
reloadDataSource = async () => {
|
||||
await this._dataSourceEngine.reloadDataSource();
|
||||
};
|
||||
|
||||
get constants() {
|
||||
return __$$constants || {};
|
||||
}
|
||||
|
||||
constructor(props, context) {
|
||||
super(props);
|
||||
|
||||
this.utils = utils;
|
||||
|
||||
this._refsManager = new RefsManager();
|
||||
|
||||
__$$i18n._inject2(this);
|
||||
|
||||
this.state = { text: 'outter' };
|
||||
}
|
||||
|
||||
$ = (refName) => {
|
||||
return this._refsManager.get(refName);
|
||||
};
|
||||
|
||||
$$ = (refName) => {
|
||||
return this._refsManager.getAll(refName);
|
||||
};
|
||||
|
||||
_defineDataSourceConfig() {
|
||||
const _this = this;
|
||||
return {
|
||||
list: [
|
||||
{
|
||||
id: 'urlParams',
|
||||
type: 'urlParams',
|
||||
isInit: function () {
|
||||
return undefined;
|
||||
}.bind(_this),
|
||||
options: function () {
|
||||
return undefined;
|
||||
}.bind(_this),
|
||||
},
|
||||
{
|
||||
id: 'user',
|
||||
type: 'fetch',
|
||||
options: function () {
|
||||
return {
|
||||
method: 'GET',
|
||||
uri: 'https://shs.xxx.com/mock/1458/demo/user',
|
||||
isSync: true,
|
||||
};
|
||||
}.bind(_this),
|
||||
dataHandler: function (response) {
|
||||
if (!response.data.success) {
|
||||
throw new Error(response.data.message);
|
||||
}
|
||||
return response.data.data;
|
||||
},
|
||||
isInit: function () {
|
||||
return undefined;
|
||||
}.bind(_this),
|
||||
},
|
||||
{
|
||||
id: 'orders',
|
||||
type: 'fetch',
|
||||
options: function () {
|
||||
return {
|
||||
method: 'GET',
|
||||
uri: 'https://shs.xxx.com/mock/1458/demo/orders',
|
||||
isSync: true,
|
||||
};
|
||||
}.bind(_this),
|
||||
dataHandler: function (response) {
|
||||
if (!response.data.success) {
|
||||
throw new Error(response.data.message);
|
||||
}
|
||||
return response.data.data.result;
|
||||
},
|
||||
isInit: function () {
|
||||
return undefined;
|
||||
}.bind(_this),
|
||||
},
|
||||
],
|
||||
dataHandler: function (dataMap) {
|
||||
console.info('All datasources loaded:', dataMap);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._dataSourceEngine.reloadDataSource();
|
||||
|
||||
console.log('componentDidMount');
|
||||
}
|
||||
|
||||
render() {
|
||||
const __$$context = this._context || this;
|
||||
const { state } = __$$context;
|
||||
return (
|
||||
<div ref={this._refsManager.linkRef('outterView')} autoLoading={true}>
|
||||
<Form
|
||||
labelCol={__$$eval(() => this.state.colNum)}
|
||||
style={{}}
|
||||
ref={this._refsManager.linkRef('testForm')}
|
||||
>
|
||||
<Form.Item label="姓名:" name="name" initValue="李雷">
|
||||
<Input placeholder="请输入" size="medium" style={{ width: 320 }} />
|
||||
</Form.Item>
|
||||
<Form.Item label="年龄:" name="age" initValue="22">
|
||||
<NumberPicker size="medium" type="normal" />
|
||||
</Form.Item>
|
||||
<Form.Item label="职业:" name="profession">
|
||||
<Select
|
||||
dataSource={[
|
||||
{ label: '教师', value: 't' },
|
||||
{ label: '医生', value: 'd' },
|
||||
{ label: '歌手', value: 's' },
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<Button.Group>
|
||||
{__$$evalArray(() => ['a', 'b', 'c']).map((item, index) =>
|
||||
((__$$context) =>
|
||||
!!__$$eval(() => index >= 1) && (
|
||||
<Button type="primary" style={{ margin: '0 5px 0 5px' }}>
|
||||
{__$$eval(() => item)}
|
||||
</Button>
|
||||
))(__$$createChildContext(__$$context, { item, index }))
|
||||
)}
|
||||
</Button.Group>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Test$$Page;
|
||||
|
||||
function __$$eval(expr) {
|
||||
try {
|
||||
return expr();
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
function __$$evalArray(expr) {
|
||||
const res = __$$eval(expr);
|
||||
return Array.isArray(res) ? res : [];
|
||||
}
|
||||
|
||||
function __$$createChildContext(oldContext, ext) {
|
||||
const childContext = {
|
||||
...oldContext,
|
||||
...ext,
|
||||
};
|
||||
childContext.__proto__ = oldContext;
|
||||
return childContext;
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
import { Outlet } from 'ice';
|
||||
import BasicLayout from '@/layouts/BasicLayout';
|
||||
|
||||
export default function Layout() {
|
||||
return (
|
||||
<BasicLayout>
|
||||
<Outlet />
|
||||
</BasicLayout>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
/// <reference types="@ice/app/types" />
|
||||
|
||||
export {};
|
||||
declare global {
|
||||
interface Window {
|
||||
g_config: Record<string, any>;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,47 @@
|
||||
import { createRef } from 'react';
|
||||
|
||||
export class RefsManager {
|
||||
constructor() {
|
||||
this.refInsStore = {};
|
||||
}
|
||||
|
||||
clearNullRefs() {
|
||||
Object.keys(this.refInsStore).forEach((refName) => {
|
||||
const filteredInsList = this.refInsStore[refName].filter(
|
||||
(insRef) => !!insRef.current
|
||||
);
|
||||
if (filteredInsList.length > 0) {
|
||||
this.refInsStore[refName] = filteredInsList;
|
||||
} else {
|
||||
delete this.refInsStore[refName];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get(refName) {
|
||||
this.clearNullRefs();
|
||||
if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {
|
||||
return this.refInsStore[refName][0].current;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
getAll(refName) {
|
||||
this.clearNullRefs();
|
||||
if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {
|
||||
return this.refInsStore[refName].map((i) => i.current);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
linkRef(refName) {
|
||||
const refIns = createRef();
|
||||
this.refInsStore[refName] = this.refInsStore[refName] || [];
|
||||
this.refInsStore[refName].push(refIns);
|
||||
return refIns;
|
||||
}
|
||||
}
|
||||
|
||||
export default {};
|
||||
276
modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/schema.json5
vendored
Normal file
276
modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/schema.json5
vendored
Normal file
@ -0,0 +1,276 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"componentsMap": [
|
||||
{
|
||||
"componentName": "Button",
|
||||
"package": "@alifd/next",
|
||||
"version": "1.19.18",
|
||||
"destructuring": true,
|
||||
"exportName": "Button"
|
||||
},
|
||||
{
|
||||
"componentName": "Button.Group",
|
||||
"package": "@alifd/next",
|
||||
"version": "1.19.18",
|
||||
"destructuring": true,
|
||||
"exportName": "Button",
|
||||
"subName": "Group"
|
||||
},
|
||||
{
|
||||
"componentName": "Input",
|
||||
"package": "@alifd/next",
|
||||
"version": "1.19.18",
|
||||
"destructuring": true,
|
||||
"exportName": "Input"
|
||||
},
|
||||
{
|
||||
"componentName": "Form",
|
||||
"package": "@alifd/next",
|
||||
"version": "1.19.18",
|
||||
"destructuring": true,
|
||||
"exportName": "Form"
|
||||
},
|
||||
{
|
||||
"componentName": "Form.Item",
|
||||
"package": "@alifd/next",
|
||||
"version": "1.19.18",
|
||||
"destructuring": true,
|
||||
"exportName": "Form",
|
||||
"subName": "Item"
|
||||
},
|
||||
{
|
||||
"componentName": "NumberPicker",
|
||||
"package": "@alifd/next",
|
||||
"version": "1.19.18",
|
||||
"destructuring": true,
|
||||
"exportName": "NumberPicker"
|
||||
},
|
||||
{
|
||||
"componentName": "Select",
|
||||
"package": "@alifd/next",
|
||||
"version": "1.19.18",
|
||||
"destructuring": true,
|
||||
"exportName": "Select"
|
||||
}
|
||||
],
|
||||
"componentsTree": [
|
||||
{
|
||||
"componentName": "Page",
|
||||
"id": "node$1",
|
||||
"meta": {
|
||||
"title": "测试",
|
||||
"router": "/"
|
||||
},
|
||||
"props": {
|
||||
"ref": "outterView",
|
||||
"autoLoading": true
|
||||
},
|
||||
"fileName": "test",
|
||||
"state": {
|
||||
"text": "outter"
|
||||
},
|
||||
"lifeCycles": {
|
||||
"componentDidMount": {
|
||||
"type": "JSFunction",
|
||||
"value": "function() { console.log('componentDidMount'); }"
|
||||
}
|
||||
},
|
||||
dataSource: {
|
||||
list: [
|
||||
{
|
||||
id: 'urlParams',
|
||||
type: 'urlParams',
|
||||
},
|
||||
// 示例数据源:https://shs.xxx.com/mock/1458/demo/user
|
||||
{
|
||||
id: 'user',
|
||||
type: 'fetch',
|
||||
options: {
|
||||
method: 'GET',
|
||||
uri: 'https://shs.xxx.com/mock/1458/demo/user',
|
||||
isSync: true,
|
||||
},
|
||||
dataHandler: {
|
||||
type: 'JSExpression',
|
||||
value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data;\n}',
|
||||
},
|
||||
},
|
||||
// 示例数据源:https://shs.xxx.com/mock/1458/demo/orders
|
||||
{
|
||||
id: 'orders',
|
||||
type: 'fetch',
|
||||
options: {
|
||||
method: 'GET',
|
||||
uri: "https://shs.xxx.com/mock/1458/demo/orders",
|
||||
isSync: true,
|
||||
},
|
||||
dataHandler: {
|
||||
type: 'JSExpression',
|
||||
value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data.result;\n}',
|
||||
},
|
||||
},
|
||||
],
|
||||
dataHandler: {
|
||||
type: 'JSExpression',
|
||||
value: 'function (dataMap) {\n console.info("All datasources loaded:", dataMap);\n}',
|
||||
},
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "Form",
|
||||
"id": "node$2",
|
||||
"props": {
|
||||
"labelCol": {
|
||||
"type": "JSExpression",
|
||||
"value": "this.state.colNum"
|
||||
},
|
||||
"style": {},
|
||||
"ref": "testForm"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "Form.Item",
|
||||
"id": "node$3",
|
||||
"props": {
|
||||
"label": "姓名:",
|
||||
"name": "name",
|
||||
"initValue": "李雷"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "Input",
|
||||
"id": "node$4",
|
||||
"props": {
|
||||
"placeholder": "请输入",
|
||||
"size": "medium",
|
||||
"style": {
|
||||
"width": 320
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"componentName": "Form.Item",
|
||||
"id": "node$5",
|
||||
"props": {
|
||||
"label": "年龄:",
|
||||
"name": "age",
|
||||
"initValue": "22"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "NumberPicker",
|
||||
"id": "node$6",
|
||||
"props": {
|
||||
"size": "medium",
|
||||
"type": "normal"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"componentName": "Form.Item",
|
||||
"id": "node$7",
|
||||
"props": {
|
||||
"label": "职业:",
|
||||
"name": "profession"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "Select",
|
||||
"id": "node$8",
|
||||
"props": {
|
||||
"dataSource": [
|
||||
{
|
||||
"label": "教师",
|
||||
"value": "t"
|
||||
},
|
||||
{
|
||||
"label": "医生",
|
||||
"value": "d"
|
||||
},
|
||||
{
|
||||
"label": "歌手",
|
||||
"value": "s"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"componentName": "Div",
|
||||
"id": "node$9",
|
||||
"props": {
|
||||
"style": {
|
||||
"textAlign": "center"
|
||||
}
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "Button.Group",
|
||||
"id": "node$a",
|
||||
"props": {},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "Button",
|
||||
"id": "node$b",
|
||||
"condition": {
|
||||
"type": "JSExpression",
|
||||
"value": "this.index >= 1"
|
||||
},
|
||||
"loop": ["a", "b", "c"],
|
||||
"props": {
|
||||
"type": "primary",
|
||||
"style": {
|
||||
"margin": "0 5px 0 5px"
|
||||
},
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "JSExpression",
|
||||
"value": "this.item"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"constants": {
|
||||
"ENV": "prod",
|
||||
"DOMAIN": "xxx.xxx.com"
|
||||
},
|
||||
"css": "body {font-size: 12px;} .table { width: 100px;}",
|
||||
"config": {
|
||||
"sdkVersion": "1.0.3",
|
||||
"historyMode": "hash",
|
||||
"targetRootID": "J_Container",
|
||||
"layout": {
|
||||
"componentName": "BasicLayout",
|
||||
"props": {
|
||||
"logo": "...",
|
||||
"name": "测试网站"
|
||||
}
|
||||
},
|
||||
"theme": {
|
||||
"package": "@alife/theme-fusion",
|
||||
"version": "^0.1.0",
|
||||
"primary": "#ff9966"
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"name": "demo应用",
|
||||
"git_group": "appGroup",
|
||||
"project_name": "app_demo",
|
||||
"description": "这是一个测试应用",
|
||||
"spma": "spa23d",
|
||||
"creator": "月飞"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
defaults
|
||||
ios_saf 9
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
|
||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
|
||||
# production
|
||||
build/
|
||||
dist/
|
||||
tmp/
|
||||
lib/
|
||||
|
||||
# misc
|
||||
.idea/
|
||||
.happypack
|
||||
.DS_Store
|
||||
*.swp
|
||||
*.dia~
|
||||
.ice
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
index.module.scss.d.ts
|
||||
|
||||
@ -0,0 +1 @@
|
||||
This project is generated by lowcode-code-generator & lowcode-solution-icejs3.
|
||||
@ -0,0 +1,90 @@
|
||||
import { join } from 'path';
|
||||
import { defineConfig } from '@ice/app';
|
||||
import _ from 'lodash';
|
||||
import fusion from '@ice/plugin-fusion';
|
||||
import locales from '@ice/plugin-moment-locales';
|
||||
import type { Plugin } from '@ice/app/esm/types';
|
||||
|
||||
interface PluginOptions {
|
||||
id: string;
|
||||
}
|
||||
|
||||
const plugin: Plugin<PluginOptions> = (options) => ({
|
||||
// name 可选,插件名称
|
||||
name: 'plugin-name',
|
||||
// setup 必选,用于定制工程构建配置
|
||||
setup: ({ onGetConfig, modifyUserConfig }) => {
|
||||
modifyUserConfig('codeSplitting', 'page');
|
||||
|
||||
onGetConfig((config) => {
|
||||
config.entry = {
|
||||
web: join(process.cwd(), '.ice/entry.client.tsx'),
|
||||
};
|
||||
|
||||
config.cssFilename = '[name].css';
|
||||
|
||||
config.configureWebpack = config.configureWebpack || [];
|
||||
config.configureWebpack?.push((webpackConfig) => {
|
||||
if (webpackConfig.output) {
|
||||
webpackConfig.output.filename = '[name].js';
|
||||
webpackConfig.output.chunkFilename = '[name].js';
|
||||
}
|
||||
return webpackConfig;
|
||||
});
|
||||
|
||||
config.swcOptions = _.merge(config.swcOptions, {
|
||||
compilationConfig: {
|
||||
jsc: {
|
||||
transform: {
|
||||
react: {
|
||||
runtime: 'classic',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// 解决 webpack publicPath 问题
|
||||
config.transforms = config.transforms || [];
|
||||
config.transforms.push((source: string, id: string) => {
|
||||
if (id.includes('.ice/entry.client.tsx')) {
|
||||
let code = `
|
||||
if (!__webpack_public_path__?.startsWith('http') && document.currentScript) {
|
||||
// @ts-ignore
|
||||
__webpack_public_path__ = document.currentScript.src.replace(/^(.*\\/)[^/]+$/, '$1');
|
||||
window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {};
|
||||
window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__;
|
||||
}
|
||||
`;
|
||||
code += source;
|
||||
return { code };
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// The project config, see https://v3.ice.work/docs/guide/basic/config
|
||||
const minify = process.env.NODE_ENV === 'production' ? 'swc' : false;
|
||||
export default defineConfig(() => ({
|
||||
ssr: false,
|
||||
ssg: false,
|
||||
minify,
|
||||
|
||||
externals: {
|
||||
react: 'React',
|
||||
'react-dom': 'ReactDOM',
|
||||
'react-dom/client': 'ReactDOM',
|
||||
'@alifd/next': 'Next',
|
||||
lodash: 'var window._',
|
||||
'@alilc/lowcode-engine': 'var window.AliLowCodeEngine',
|
||||
},
|
||||
plugins: [
|
||||
fusion({
|
||||
importStyle: true,
|
||||
}),
|
||||
locales(),
|
||||
plugin(),
|
||||
],
|
||||
}));
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "icejs3-demo-app",
|
||||
"version": "0.1.5",
|
||||
"description": "icejs 3 轻量级模板,使用 JavaScript,仅包含基础的 Layout。",
|
||||
"dependencies": {
|
||||
"moment": "^2.24.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router": "^6.9.0",
|
||||
"react-router-dom": "^6.9.0",
|
||||
"intl-messageformat": "^9.3.6",
|
||||
"@alifd/next": "1.26.15",
|
||||
"@ice/runtime": "^1.0.0",
|
||||
"@alilc/lowcode-datasource-engine": "^1.0.0",
|
||||
"@alilc/lowcode-datasource-url-params-handler": "^1.0.0",
|
||||
"@alilc/b6-page": "^0.1.0",
|
||||
"@alilc/b6-text": "^0.1.0",
|
||||
"@alilc/b6-compact-legao-builtin": "1.x",
|
||||
"antd": "3.x",
|
||||
"@alilc/b6-util-mocks": "1.x"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ice/app": "^3.0.0",
|
||||
"@types/react": "^18.0.0",
|
||||
"@types/react-dom": "^18.0.0",
|
||||
"@types/node": "^18.11.17",
|
||||
"@ice/plugin-fusion": "^1.0.1",
|
||||
"@ice/plugin-moment-locales": "^1.0.0",
|
||||
"eslint": "^6.0.1",
|
||||
"stylelint": "^13.2.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "ice start",
|
||||
"build": "ice build",
|
||||
"lint": "npm run eslint && npm run stylelint",
|
||||
"eslint": "eslint --cache --ext .js,.jsx ./",
|
||||
"stylelint": "stylelint ./**/*.scss"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://gitlab.xxx.com/msd/leak-scan/tree/master"
|
||||
},
|
||||
"private": true,
|
||||
"originTemplate": "@alifd/scaffold-lite-js"
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
import { defineAppConfig } from 'ice';
|
||||
|
||||
// App config, see https://v3.ice.work/docs/guide/basic/app
|
||||
export default defineAppConfig(() => ({
|
||||
// Set your configs here.
|
||||
app: {
|
||||
rootId: 'App',
|
||||
},
|
||||
router: {
|
||||
type: 'browser',
|
||||
basename: '/',
|
||||
},
|
||||
}));
|
||||
@ -0,0 +1,3 @@
|
||||
const __$$constants = {};
|
||||
|
||||
export default __$$constants;
|
||||
@ -0,0 +1,29 @@
|
||||
import React from 'react';
|
||||
import { Meta, Title, Links, Main, Scripts } from 'ice';
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<html>
|
||||
<head>
|
||||
<meta charSet="utf-8" />
|
||||
<meta name="description" content="ice.js 3 lite scaffold" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
|
||||
<Meta />
|
||||
<Title />
|
||||
<Links />
|
||||
</head>
|
||||
<body>
|
||||
<Main />
|
||||
<script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" />
|
||||
<script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" />
|
||||
<script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" />
|
||||
<script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" />
|
||||
<script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" />
|
||||
<script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" />
|
||||
<Scripts />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
// 引入默认全局样式
|
||||
@import '@alifd/next/reset.scss';
|
||||
|
||||
body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
@ -0,0 +1,77 @@
|
||||
const i18nConfig = {};
|
||||
|
||||
let locale =
|
||||
typeof navigator === 'object' && typeof navigator.language === 'string'
|
||||
? navigator.language
|
||||
: 'zh-CN';
|
||||
|
||||
const getLocale = () => locale;
|
||||
|
||||
const setLocale = (target) => {
|
||||
locale = target;
|
||||
};
|
||||
|
||||
const isEmptyVariables = (variables) =>
|
||||
(Array.isArray(variables) && variables.length === 0) ||
|
||||
(typeof variables === 'object' &&
|
||||
(!variables || Object.keys(variables).length === 0));
|
||||
|
||||
// 按低代码规范里面的要求进行变量替换
|
||||
const format = (msg, variables) =>
|
||||
typeof msg === 'string'
|
||||
? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '')
|
||||
: msg;
|
||||
|
||||
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
|
||||
const msg =
|
||||
i18nConfig[locale]?.[id] ??
|
||||
i18nConfig[locale.replace('-', '_')]?.[id] ??
|
||||
defaultMessage;
|
||||
if (msg == null) {
|
||||
console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);
|
||||
return fallback === undefined ? `${id}` : fallback;
|
||||
}
|
||||
|
||||
return format(msg, variables);
|
||||
};
|
||||
|
||||
const i18n = (id, params) => {
|
||||
return i18nFormat({ id }, params);
|
||||
};
|
||||
|
||||
// 将国际化的一些方法注入到目标对象&上下文中
|
||||
const _inject2 = (target) => {
|
||||
target.i18n = i18n;
|
||||
target.getLocale = getLocale;
|
||||
target.setLocale = (locale) => {
|
||||
setLocale(locale);
|
||||
target.forceUpdate();
|
||||
};
|
||||
target._i18nText = (t) => {
|
||||
// 优先取直接传过来的语料
|
||||
const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];
|
||||
if (localMsg != null) {
|
||||
return format(localMsg, t.params);
|
||||
}
|
||||
|
||||
// 其次用项目级别的
|
||||
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
|
||||
if (projectMsg != null) {
|
||||
return projectMsg;
|
||||
}
|
||||
|
||||
// 兜底用 use 指定的或默认语言的
|
||||
return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);
|
||||
};
|
||||
|
||||
// 注入到上下文中去
|
||||
if (target._context && target._context !== target) {
|
||||
Object.assign(target._context, {
|
||||
i18n,
|
||||
getLocale,
|
||||
setLocale: target.setLocale,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
|
||||
@ -0,0 +1,14 @@
|
||||
|
||||
import React from 'react';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<p className={styles.footer}>
|
||||
<span className={styles.logo}>Alibaba Fusion</span>
|
||||
<br />
|
||||
<span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
|
||||
.footer {
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.copyright {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@ -0,0 +1,16 @@
|
||||
|
||||
import React from 'react';
|
||||
import { Link } from 'ice';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
export default function Logo({ image, text, url }) {
|
||||
return (
|
||||
<div className="logo">
|
||||
<Link to={url || '/'} className={styles.logo}>
|
||||
{image && <img src={image} alt="logo" />}
|
||||
<span>{text}</span>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
|
||||
.logo{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: $color-text1-1;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
|
||||
&:visited, &:link {
|
||||
color: $color-text1-1;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 24px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,68 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link, useLocation } from 'ice';
|
||||
import { Nav } from '@alifd/next';
|
||||
import { asideMenuConfig } from '../../menuConfig';
|
||||
|
||||
const { SubNav } = Nav;
|
||||
const NavItem = Nav.Item;
|
||||
|
||||
function getNavMenuItems(menusData) {
|
||||
if (!menusData) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return menusData
|
||||
.filter(item => item.name && !item.hideInMenu)
|
||||
.map((item, index) => getSubMenuOrItem(item, index));
|
||||
}
|
||||
|
||||
function getSubMenuOrItem(item, index) {
|
||||
if (item.children && item.children.some(child => child.name)) {
|
||||
const childrenItems = getNavMenuItems(item.children);
|
||||
|
||||
if (childrenItems && childrenItems.length > 0) {
|
||||
const subNav = (
|
||||
<SubNav key={index} icon={item.icon} label={item.name}>
|
||||
{childrenItems}
|
||||
</SubNav>
|
||||
);
|
||||
return subNav;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const navItem = (
|
||||
<NavItem key={item.path} icon={item.icon}>
|
||||
<Link to={item.path}>{item.name}</Link>
|
||||
</NavItem>
|
||||
);
|
||||
return navItem;
|
||||
}
|
||||
|
||||
const Navigation = (props, context) => {
|
||||
const location = useLocation();
|
||||
const { pathname } = location;
|
||||
const { isCollapse } = context;
|
||||
return (
|
||||
<Nav
|
||||
type="primary"
|
||||
selectedKeys={[pathname]}
|
||||
defaultSelectedKeys={[pathname]}
|
||||
embeddable
|
||||
openMode="single"
|
||||
iconOnly={isCollapse}
|
||||
hasArrow={false}
|
||||
mode={isCollapse ? 'popup' : 'inline'}
|
||||
>
|
||||
{getNavMenuItems(asideMenuConfig)}
|
||||
</Nav>
|
||||
);
|
||||
};
|
||||
|
||||
Navigation.contextTypes = {
|
||||
isCollapse: PropTypes.bool,
|
||||
};
|
||||
export default Navigation;
|
||||
|
||||
@ -0,0 +1,81 @@
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { Shell, ConfigProvider } from '@alifd/next';
|
||||
import PageNav from './components/PageNav';
|
||||
import Logo from './components/Logo';
|
||||
import Footer from './components/Footer';
|
||||
|
||||
(function() {
|
||||
const throttle = function(type, name, obj = window) {
|
||||
let running = false;
|
||||
|
||||
const func = () => {
|
||||
if (running) {
|
||||
return;
|
||||
}
|
||||
|
||||
running = true;
|
||||
requestAnimationFrame(() => {
|
||||
obj.dispatchEvent(new CustomEvent(name));
|
||||
running = false;
|
||||
});
|
||||
};
|
||||
|
||||
obj.addEventListener(type, func);
|
||||
};
|
||||
|
||||
throttle('resize', 'optimizedResize');
|
||||
})();
|
||||
|
||||
export default function BasicLayout({ children }) {
|
||||
const getDevice = width => {
|
||||
const isPhone =
|
||||
typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi);
|
||||
|
||||
if (width < 680 || isPhone) {
|
||||
return 'phone';
|
||||
}
|
||||
if (width < 1280 && width > 680) {
|
||||
return 'tablet';
|
||||
}
|
||||
return 'desktop';
|
||||
};
|
||||
|
||||
const [device, setDevice] = useState(getDevice(NaN));
|
||||
window.addEventListener('optimizedResize', e => {
|
||||
setDevice(getDevice(e && e.target && e.target.innerWidth));
|
||||
});
|
||||
return (
|
||||
<ConfigProvider device={device}>
|
||||
<Shell
|
||||
type="dark"
|
||||
style={{
|
||||
minHeight: '100vh',
|
||||
}}
|
||||
>
|
||||
<Shell.Branding>
|
||||
<Logo
|
||||
image="https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png"
|
||||
text="Logo"
|
||||
/>
|
||||
</Shell.Branding>
|
||||
<Shell.Navigation
|
||||
direction="hoz"
|
||||
style={{
|
||||
marginRight: 10,
|
||||
}}
|
||||
></Shell.Navigation>
|
||||
<Shell.Action></Shell.Action>
|
||||
<Shell.Navigation>
|
||||
<PageNav />
|
||||
</Shell.Navigation>
|
||||
|
||||
<Shell.Content>{children}</Shell.Content>
|
||||
<Shell.Footer>
|
||||
<Footer />
|
||||
</Shell.Footer>
|
||||
</Shell>
|
||||
</ConfigProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
|
||||
const headerMenuConfig = [];
|
||||
const asideMenuConfig = [
|
||||
{
|
||||
name: 'Dashboard',
|
||||
path: '/',
|
||||
icon: 'smile',
|
||||
},
|
||||
];
|
||||
export { headerMenuConfig, asideMenuConfig };
|
||||
|
||||
@ -0,0 +1,118 @@
|
||||
// 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。
|
||||
// 例外:react 框架的导出名和各种组件名除外。
|
||||
import React from 'react';
|
||||
|
||||
import { Page } from '@alilc/b6-page';
|
||||
|
||||
import { Text } from '@alilc/b6-text';
|
||||
|
||||
import { createUrlParamsHandler as __$$createUrlParamsRequestHandler } from '@alilc/lowcode-datasource-url-params-handler';
|
||||
|
||||
import { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime';
|
||||
|
||||
import utils from '../../utils';
|
||||
|
||||
import * as __$$i18n from '../../i18n';
|
||||
|
||||
import __$$constants from '../../constants';
|
||||
|
||||
import './index.css';
|
||||
|
||||
class Aaaa$$Page extends React.Component {
|
||||
_context = this;
|
||||
|
||||
_dataSourceConfig = this._defineDataSourceConfig();
|
||||
_dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, {
|
||||
runtimeConfig: true,
|
||||
requestHandlersMap: {
|
||||
urlParams: __$$createUrlParamsRequestHandler(window.location.search),
|
||||
},
|
||||
});
|
||||
|
||||
get dataSourceMap() {
|
||||
return this._dataSourceEngine.dataSourceMap || {};
|
||||
}
|
||||
|
||||
reloadDataSource = async () => {
|
||||
await this._dataSourceEngine.reloadDataSource();
|
||||
};
|
||||
|
||||
get constants() {
|
||||
return __$$constants || {};
|
||||
}
|
||||
|
||||
constructor(props, context) {
|
||||
super(props);
|
||||
|
||||
this.utils = utils;
|
||||
|
||||
__$$i18n._inject2(this);
|
||||
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
$ = () => null;
|
||||
|
||||
$$ = () => [];
|
||||
|
||||
_defineDataSourceConfig() {
|
||||
const _this = this;
|
||||
return {
|
||||
list: [
|
||||
{
|
||||
id: 'urlParams',
|
||||
type: 'urlParams',
|
||||
description: 'URL参数',
|
||||
options: function () {
|
||||
return {
|
||||
uri: '',
|
||||
};
|
||||
}.bind(_this),
|
||||
isInit: function () {
|
||||
return undefined;
|
||||
}.bind(_this),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._dataSourceEngine.reloadDataSource();
|
||||
}
|
||||
|
||||
render() {
|
||||
const __$$context = this._context || this;
|
||||
const { state } = __$$context;
|
||||
return (
|
||||
<div title="" backgroundColor="#fff" textColor="#333" style={{}}>
|
||||
<Text
|
||||
content="欢迎使用 BuildSuccess!sadsad"
|
||||
style={{}}
|
||||
fieldId="text_kp6ci11t"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Aaaa$$Page;
|
||||
|
||||
function __$$eval(expr) {
|
||||
try {
|
||||
return expr();
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
function __$$evalArray(expr) {
|
||||
const res = __$$eval(expr);
|
||||
return Array.isArray(res) ? res : [];
|
||||
}
|
||||
|
||||
function __$$createChildContext(oldContext, ext) {
|
||||
const childContext = {
|
||||
...oldContext,
|
||||
...ext,
|
||||
};
|
||||
childContext.__proto__ = oldContext;
|
||||
return childContext;
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
import { Outlet } from 'ice';
|
||||
import BasicLayout from '@/layouts/BasicLayout';
|
||||
|
||||
export default function Layout() {
|
||||
return (
|
||||
<BasicLayout>
|
||||
<Outlet />
|
||||
</BasicLayout>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
/// <reference types="@ice/app/types" />
|
||||
|
||||
export {};
|
||||
declare global {
|
||||
interface Window {
|
||||
g_config: Record<string, any>;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,61 @@
|
||||
import legaoBuiltin from '@alilc/b6-compact-legao-builtin';
|
||||
|
||||
import { message, Modal as modal } from 'antd';
|
||||
|
||||
import { mocks } from '@alilc/b6-util-mocks';
|
||||
|
||||
import { createRef } from 'react';
|
||||
|
||||
export class RefsManager {
|
||||
constructor() {
|
||||
this.refInsStore = {};
|
||||
}
|
||||
|
||||
clearNullRefs() {
|
||||
Object.keys(this.refInsStore).forEach((refName) => {
|
||||
const filteredInsList = this.refInsStore[refName].filter(
|
||||
(insRef) => !!insRef.current
|
||||
);
|
||||
if (filteredInsList.length > 0) {
|
||||
this.refInsStore[refName] = filteredInsList;
|
||||
} else {
|
||||
delete this.refInsStore[refName];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get(refName) {
|
||||
this.clearNullRefs();
|
||||
if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {
|
||||
return this.refInsStore[refName][0].current;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
getAll(refName) {
|
||||
this.clearNullRefs();
|
||||
if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) {
|
||||
return this.refInsStore[refName].map((i) => i.current);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
linkRef(refName) {
|
||||
const refIns = createRef();
|
||||
this.refInsStore[refName] = this.refInsStore[refName] || [];
|
||||
this.refInsStore[refName].push(refIns);
|
||||
return refIns;
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
legaoBuiltin,
|
||||
|
||||
message,
|
||||
|
||||
mocks,
|
||||
|
||||
modal,
|
||||
};
|
||||
123
modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/schema.json5
vendored
Normal file
123
modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/schema.json5
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
{
|
||||
version: '1.0.0',
|
||||
componentsMap: [
|
||||
{
|
||||
package: '@alilc/b6-page',
|
||||
version: '^0.1.0',
|
||||
componentName: 'Page',
|
||||
destructuring: true,
|
||||
exportName: 'Page',
|
||||
},
|
||||
{
|
||||
package: '@alilc/b6-text',
|
||||
version: '^0.1.0',
|
||||
componentName: 'Text',
|
||||
destructuring: true,
|
||||
exportName: 'Text',
|
||||
},
|
||||
],
|
||||
componentsTree: [
|
||||
{
|
||||
componentName: 'Page',
|
||||
id: 'node_ockp6ci0hm1',
|
||||
props: {
|
||||
title: '',
|
||||
backgroundColor: '#fff',
|
||||
textColor: '#333',
|
||||
style: {},
|
||||
},
|
||||
fileName: 'aaaa',
|
||||
dataSource: {
|
||||
list: [
|
||||
{
|
||||
id: 'urlParams',
|
||||
type: 'urlParams',
|
||||
description: 'URL参数',
|
||||
options: {
|
||||
uri: '',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
componentName: 'Text',
|
||||
id: 'node_ockp6ci0hm2',
|
||||
props: {
|
||||
content: '欢迎使用 BuildSuccess!sadsad',
|
||||
style: {},
|
||||
fieldId: 'text_kp6ci11t',
|
||||
},
|
||||
},
|
||||
],
|
||||
meta: {
|
||||
router: '/aaaa',
|
||||
},
|
||||
methodsModule: {
|
||||
type: 'JSModule',
|
||||
compiled: '"use strict";\n\nObject.defineProperty(exports, "__esModule", {\n value: true\n});\nexports.helloPage = helloPage;\n\n/**\n * Private, and can be re-used functions\n * Actions panel help documentation:\n * @see https://yuque.antfin.com/docs/share/89ca7965-6387-4e3a-9964-81929ed48f1e\n */\nfunction printLog(obj) {\n console.info(obj);\n}\n/**\n * page function\n */\n\n\nfunction helloPage() {\n console.log(\'hello page\');\n}',
|
||||
source: "/**\n * Private, and can be re-used functions\n * Actions panel help documentation:\n * @see https://yuque.antfin.com/docs/share/89ca7965-6387-4e3a-9964-81929ed48f1e\n */\nfunction printLog(obj) {\n console.info(obj);\n}\n\n/**\n * page function\n */\nexport function helloPage() {\n console.log('hello page');\n}",
|
||||
},
|
||||
},
|
||||
],
|
||||
i18n: {},
|
||||
utils: [
|
||||
{
|
||||
name: 'legaoBuiltin',
|
||||
type: 'npm',
|
||||
content: {
|
||||
exportName: 'legaoBuiltin',
|
||||
package: '@alilc/b6-compact-legao-builtin',
|
||||
version: '1.x',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'message',
|
||||
type: 'npm',
|
||||
content: {
|
||||
package: 'antd',
|
||||
version: '3.x',
|
||||
destructuring: true,
|
||||
exportName: 'message',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'mocks',
|
||||
type: 'npm',
|
||||
content: {
|
||||
package: '@alilc/b6-util-mocks',
|
||||
version: '1.x',
|
||||
exportName: 'mocks',
|
||||
destructuring: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'modal',
|
||||
type: 'npm',
|
||||
content: {
|
||||
package: 'antd',
|
||||
version: '3.x',
|
||||
destructuring: true,
|
||||
exportName: 'Modal',
|
||||
},
|
||||
},
|
||||
],
|
||||
constants: {},
|
||||
dataSource: {
|
||||
list: [],
|
||||
},
|
||||
config: {
|
||||
sdkVersion: '1.0.3',
|
||||
historyMode: 'hash',
|
||||
targetRootID: 'root',
|
||||
miniAppBuildType: 'runtime',
|
||||
},
|
||||
meta: {
|
||||
name: 'jinyuan-test2',
|
||||
git_group: 'b6',
|
||||
project_name: 'jinyuan-test2',
|
||||
description: '瑾源测试',
|
||||
spma: 'spmademo',
|
||||
creator: '张三',
|
||||
},
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
defaults
|
||||
ios_saf 9
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
|
||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
|
||||
# production
|
||||
build/
|
||||
dist/
|
||||
tmp/
|
||||
lib/
|
||||
|
||||
# misc
|
||||
.idea/
|
||||
.happypack
|
||||
.DS_Store
|
||||
*.swp
|
||||
*.dia~
|
||||
.ice
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
index.module.scss.d.ts
|
||||
|
||||
@ -0,0 +1 @@
|
||||
This project is generated by lowcode-code-generator & lowcode-solution-icejs3.
|
||||
@ -0,0 +1,90 @@
|
||||
import { join } from 'path';
|
||||
import { defineConfig } from '@ice/app';
|
||||
import _ from 'lodash';
|
||||
import fusion from '@ice/plugin-fusion';
|
||||
import locales from '@ice/plugin-moment-locales';
|
||||
import type { Plugin } from '@ice/app/esm/types';
|
||||
|
||||
interface PluginOptions {
|
||||
id: string;
|
||||
}
|
||||
|
||||
const plugin: Plugin<PluginOptions> = (options) => ({
|
||||
// name 可选,插件名称
|
||||
name: 'plugin-name',
|
||||
// setup 必选,用于定制工程构建配置
|
||||
setup: ({ onGetConfig, modifyUserConfig }) => {
|
||||
modifyUserConfig('codeSplitting', 'page');
|
||||
|
||||
onGetConfig((config) => {
|
||||
config.entry = {
|
||||
web: join(process.cwd(), '.ice/entry.client.tsx'),
|
||||
};
|
||||
|
||||
config.cssFilename = '[name].css';
|
||||
|
||||
config.configureWebpack = config.configureWebpack || [];
|
||||
config.configureWebpack?.push((webpackConfig) => {
|
||||
if (webpackConfig.output) {
|
||||
webpackConfig.output.filename = '[name].js';
|
||||
webpackConfig.output.chunkFilename = '[name].js';
|
||||
}
|
||||
return webpackConfig;
|
||||
});
|
||||
|
||||
config.swcOptions = _.merge(config.swcOptions, {
|
||||
compilationConfig: {
|
||||
jsc: {
|
||||
transform: {
|
||||
react: {
|
||||
runtime: 'classic',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// 解决 webpack publicPath 问题
|
||||
config.transforms = config.transforms || [];
|
||||
config.transforms.push((source: string, id: string) => {
|
||||
if (id.includes('.ice/entry.client.tsx')) {
|
||||
let code = `
|
||||
if (!__webpack_public_path__?.startsWith('http') && document.currentScript) {
|
||||
// @ts-ignore
|
||||
__webpack_public_path__ = document.currentScript.src.replace(/^(.*\\/)[^/]+$/, '$1');
|
||||
window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {};
|
||||
window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__;
|
||||
}
|
||||
`;
|
||||
code += source;
|
||||
return { code };
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// The project config, see https://v3.ice.work/docs/guide/basic/config
|
||||
const minify = process.env.NODE_ENV === 'production' ? 'swc' : false;
|
||||
export default defineConfig(() => ({
|
||||
ssr: false,
|
||||
ssg: false,
|
||||
minify,
|
||||
|
||||
externals: {
|
||||
react: 'React',
|
||||
'react-dom': 'ReactDOM',
|
||||
'react-dom/client': 'ReactDOM',
|
||||
'@alifd/next': 'Next',
|
||||
lodash: 'var window._',
|
||||
'@alilc/lowcode-engine': 'var window.AliLowCodeEngine',
|
||||
},
|
||||
plugins: [
|
||||
fusion({
|
||||
importStyle: true,
|
||||
}),
|
||||
locales(),
|
||||
plugin(),
|
||||
],
|
||||
}));
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "icejs3-demo-app",
|
||||
"version": "0.1.5",
|
||||
"description": "icejs 3 轻量级模板,使用 JavaScript,仅包含基础的 Layout。",
|
||||
"dependencies": {
|
||||
"moment": "^2.24.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router": "^6.9.0",
|
||||
"react-router-dom": "^6.9.0",
|
||||
"intl-messageformat": "^9.3.6",
|
||||
"@alifd/next": "1.19.18",
|
||||
"@ice/runtime": "^1.0.0",
|
||||
"@alilc/lowcode-datasource-engine": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ice/app": "^3.0.0",
|
||||
"@types/react": "^18.0.0",
|
||||
"@types/react-dom": "^18.0.0",
|
||||
"@types/node": "^18.11.17",
|
||||
"@ice/plugin-fusion": "^1.0.1",
|
||||
"@ice/plugin-moment-locales": "^1.0.0",
|
||||
"eslint": "^6.0.1",
|
||||
"stylelint": "^13.2.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "ice start",
|
||||
"build": "ice build",
|
||||
"lint": "npm run eslint && npm run stylelint",
|
||||
"eslint": "eslint --cache --ext .js,.jsx ./",
|
||||
"stylelint": "stylelint ./**/*.scss"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://gitlab.xxx.com/msd/leak-scan/tree/master"
|
||||
},
|
||||
"private": true,
|
||||
"originTemplate": "@alifd/scaffold-lite-js"
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
import { defineAppConfig } from 'ice';
|
||||
|
||||
// App config, see https://v3.ice.work/docs/guide/basic/app
|
||||
export default defineAppConfig(() => ({
|
||||
// Set your configs here.
|
||||
app: {
|
||||
rootId: 'App',
|
||||
},
|
||||
router: {
|
||||
type: 'browser',
|
||||
basename: '/',
|
||||
},
|
||||
}));
|
||||
@ -0,0 +1,3 @@
|
||||
const __$$constants = { ENV: 'prod', DOMAIN: 'xxx.xxx.com' };
|
||||
|
||||
export default __$$constants;
|
||||
@ -0,0 +1,29 @@
|
||||
import React from 'react';
|
||||
import { Meta, Title, Links, Main, Scripts } from 'ice';
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<html>
|
||||
<head>
|
||||
<meta charSet="utf-8" />
|
||||
<meta name="description" content="ice.js 3 lite scaffold" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
|
||||
<Meta />
|
||||
<Title />
|
||||
<Links />
|
||||
</head>
|
||||
<body>
|
||||
<Main />
|
||||
<script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" />
|
||||
<script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" />
|
||||
<script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" />
|
||||
<script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" />
|
||||
<script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" />
|
||||
<script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" />
|
||||
<Scripts />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
// 引入默认全局样式
|
||||
@import '@alifd/next/reset.scss';
|
||||
|
||||
body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 12px;
|
||||
}
|
||||
.table {
|
||||
width: 100px;
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
const i18nConfig = {
|
||||
'zh-CN': {
|
||||
'i18n-jwg27yo4': '你好',
|
||||
'i18n-jwg27yo3': '中国',
|
||||
},
|
||||
'en-US': {
|
||||
'i18n-jwg27yo4': 'Hello',
|
||||
'i18n-jwg27yo3': 'China',
|
||||
},
|
||||
};
|
||||
|
||||
let locale =
|
||||
typeof navigator === 'object' && typeof navigator.language === 'string'
|
||||
? navigator.language
|
||||
: 'zh-CN';
|
||||
|
||||
const getLocale = () => locale;
|
||||
|
||||
const setLocale = (target) => {
|
||||
locale = target;
|
||||
};
|
||||
|
||||
const isEmptyVariables = (variables) =>
|
||||
(Array.isArray(variables) && variables.length === 0) ||
|
||||
(typeof variables === 'object' &&
|
||||
(!variables || Object.keys(variables).length === 0));
|
||||
|
||||
// 按低代码规范里面的要求进行变量替换
|
||||
const format = (msg, variables) =>
|
||||
typeof msg === 'string'
|
||||
? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '')
|
||||
: msg;
|
||||
|
||||
const i18nFormat = ({ id, defaultMessage, fallback }, variables) => {
|
||||
const msg =
|
||||
i18nConfig[locale]?.[id] ??
|
||||
i18nConfig[locale.replace('-', '_')]?.[id] ??
|
||||
defaultMessage;
|
||||
if (msg == null) {
|
||||
console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale);
|
||||
return fallback === undefined ? `${id}` : fallback;
|
||||
}
|
||||
|
||||
return format(msg, variables);
|
||||
};
|
||||
|
||||
const i18n = (id, params) => {
|
||||
return i18nFormat({ id }, params);
|
||||
};
|
||||
|
||||
// 将国际化的一些方法注入到目标对象&上下文中
|
||||
const _inject2 = (target) => {
|
||||
target.i18n = i18n;
|
||||
target.getLocale = getLocale;
|
||||
target.setLocale = (locale) => {
|
||||
setLocale(locale);
|
||||
target.forceUpdate();
|
||||
};
|
||||
target._i18nText = (t) => {
|
||||
// 优先取直接传过来的语料
|
||||
const localMsg = t[locale] ?? t[String(locale).replace('-', '_')];
|
||||
if (localMsg != null) {
|
||||
return format(localMsg, t.params);
|
||||
}
|
||||
|
||||
// 其次用项目级别的
|
||||
const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params);
|
||||
if (projectMsg != null) {
|
||||
return projectMsg;
|
||||
}
|
||||
|
||||
// 兜底用 use 指定的或默认语言的
|
||||
return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params);
|
||||
};
|
||||
|
||||
// 注入到上下文中去
|
||||
if (target._context && target._context !== target) {
|
||||
Object.assign(target._context, {
|
||||
i18n,
|
||||
getLocale,
|
||||
setLocale: target.setLocale,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export { getLocale, setLocale, i18n, i18nFormat, _inject2 };
|
||||
@ -0,0 +1,14 @@
|
||||
|
||||
import React from 'react';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<p className={styles.footer}>
|
||||
<span className={styles.logo}>Alibaba Fusion</span>
|
||||
<br />
|
||||
<span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span>
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
|
||||
.footer {
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.copyright {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@ -0,0 +1,16 @@
|
||||
|
||||
import React from 'react';
|
||||
import { Link } from 'ice';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
export default function Logo({ image, text, url }) {
|
||||
return (
|
||||
<div className="logo">
|
||||
<Link to={url || '/'} className={styles.logo}>
|
||||
{image && <img src={image} alt="logo" />}
|
||||
<span>{text}</span>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user