# 前端扩展参考

# 1、项目独立

    统一提供源代码,直接修改。

# 2、前后端分离

      1)devops-web项目:基于VUE(ElementUI)的前端项目

# 3、前后端接口同步

       1) 修改 scripts/buildApi.js 中 swagger.json 的在线地址

       2) 运行 npm run build:api
...  
...  
(function () {
 // 读取 在线 swagger
 var url = "http://10.15.15.109:8080/swagger/swagger.json";
 execute(url).then((data) => {
   console.log(`read ${url} ...`)
   mapAction(data)
 }).then(() => {
   console.log('create controller')
   createController()
 })
})()

# 4、静态资源

    (图片文件, 非npm管理的第三方js库) 统一放在 /static 目录下

# 5、动态表单自定义事件扩展

      1) 所有自定义事件统一写在 该文件里  /src/views/project/deploy/release/env-deploy/dynamic-form-events.js

      2) 提供三种事件  init (控件初始化时执行), onvaluechanged (控件值变化时执行) , all (以上两者都执行).

      3) 事件接受两个参数 (attrValue, $this) 分别为控件当前值 attrValue 和 表单上下文&this, 其中$this提供以下 api

           1.    $this.getCtrl(refName)                                                 ------------  获得控件对象

           2.    $this.getSelectObject(refName)                                  ------------  获得选中的控件对象

           3.    $this.setAttrValue(refName, attrValue)                        ------------  设置控件值

           4.    $this.getAttrValue(refName)                                        ------------  获得控件值

           5.    $this.hiddenComponents.add(refName)                     ------------  隐藏控件

           6.    $this.hiddenComponents.delete(refName)                  ------------ 显示控件

           7.   $this.getCtrl(refName).setUrl(url)                                  ------------ 设置下拉列表数据源

示例如下:

"10000000": { //defId
 "defName": 'scriptType',
"events": {
   "onvaluechanged": (attrValue, $this) => {
      $this.hiddenComponents.add("resources")
      $this.getAttrValue("resources")
      $this.setAttrValue("resources","demo")
      $this.hiddenComponents.delete("resources")
      $this.getCtrl("resources").setUrl("/api/demo?name=demo")
   },
   "init": (attrValue, $this) => {
     ...
   },
   "all": (attrValue, $this) => {
     ...
   },
}
},

# 6、权限扩展

      1)   在 /src/permission/FuncCode.txt 里增加权限代码 名称 类型, 注意中间用 空格 隔开

      2)   运行 npm run build:permission (需提前安装 babel-node: npm i -g babel-node )

# 7、路由扩展

      1) 修改 /src/router/index.js

# 后端扩展参考

# 1、实现:

    统一使用springbean实现业务逻辑,所有的接口,均存放于devops-specs项目的com.primeton.devops.specs.api构件包中 

注意: 包名需要是com.primeton.devops.为前缀的,否则需要在spring.xml中配置包扫描。

1)单实现业务:
使用@Order注解实现(值越小,优先级越高,系统提供的实现为int最大值),使用@Autowired注解注入引用。示例如下:

//业务实现
@Service
@Order(100)
public class UserServiceExtend extends UserService {

  @Override
  public LoginResult login(String userName, String password) throws  Exception {
      
     ...
  }

  ...
}

@Controller
public class UserController implements IUserController {
  //引用注入
  @Autowired
  private IUserService userService;

  ...

}

2)多实现业务:
使用EnforcedServiceLoader方式引用加载,配置文件在构件包的META-INF/services目录下,文件名为接口名。示例如下:

配置文件com.primeton.devops.specs.api.pcm.IWorklistApprovalActionService:

#com.primeton.devops.specs.api.pcm.IWorklistApprovalActionService接口实现
com.primeton.devops.pcm.helper.ReleaseWorklistApprovalActionService,WorklistType=RELEASE_APPROVAL
com.primeton.devops.pcm.helper.ReleaseConfirmWorklistApprovalActionService,WorklistType=RELEASE_CONFIRM
com.primeton.devops.pcm.helper.ReleaseTaskConfirmWorklistApprovalActionService,WorklistType=RELEASE_TASK_CONFIRM
com.primeton.devops.pcm.helper.CodeMergeWorklistApprovalActionService,WorklistType=CODE_MERGE_APPROVAL
com.primeton.devops.pcm.helper.ProjectCreateApprovalActionService,WorklistType=PROJECT_CREATE_APPROVAL

实现使用加载示例代码:

EnforcedServiceLoader<IWorklistApprovalActionService> serviceLoader = EnforcedServiceLoader.load(IWorklistApprovalActionService.class);

Map<String, String> property = new HashMap<String, String>();

property.put("WorklistType", worklistApproval.getWorklistType());

IWorklistApprovalActionService worklistApprovalActionService = serviceLoader.getService(property, false, false);

# 2、事务控制

    如果是自己写的独立线程发起,需要调用TransitionUtil的方法进行业务处理;否则不用关心事务问题。TransitionUtil方法如下:
/**
   * 生成包含事务控制的固定的线程执行器
   *
   * @param nThreads 线程数
   * @param isDaemon 是否是daemon线程
   * @param threadName 线程名称
   * @return 线程执行器
   */
public static ThreadPoolExecutorWithTx newFixedThreadPoolExecutorWithTx(int nThreads, boolean isDaemon, String threadName);

/**
   * 生成包含事务控制的线程
   *
   * @param isDaemon 是否是daemon线程
   * @param threadName 线程名称
   * @return 线程
   */
public static ThreadWithTx newThreadWithTx(boolean isDaemon, String threadName);

/**
   * 在事务中执行,没有线程的情况下
   */
public static <T> T executeWithTx(Callable<T> call) throws Exception;

# 3、错误信息统一前后端处理,处理规范如下:

1) 定义一个实现com.primeton.devops.specs.exception.DevOps.ErrorCode接口的枚举类,错误信息由错误码、错误信息和格式化参数构成,使用异常抛出。

 注意:错误信息可以有国际化,如果有国际化,前端会显示国际化后的错误信息,否则会统一显示“系统错误,请联系管理员.”。

定义示例:

//有国际化信息  
PROJECT_ALREADY_EXISTED("en=>Project[{0}] already existed.", "zh_CN=>项目[{0}]已存在。"),  
//无国际化  
LOCK_ACQUIRED_TIMEOUT("Lock acquired tomeout: [lockType={0}][lockId={1}][timeout={2}]."),

使用示例:

throw new DevOpsException(DevOps.PM.PROJECT_ALREADY_EXISTED, >project.getProjectCode());

扩展示例:

public enum XXX implements ErrorCode {
        
       XXXXX_ALREADY_EXISTED("en=>XXXXX[{0}] already existed.", "zh_CN=>XXXXX[{0}]已存在。"),
       ...
       ;
       private XXX(String... localeMessages) {
           setMessages(localeMessages);
       }
}

2) 前端请求是设置head中的“Locale”信息,得到的错误信息对象格式(Json串):

{
 "errorCode": "DEVOPS_PM_PROJECT_ALREADY_EXISTED",
 "errorLocalizedMessage": "项目[DEMOA]已存在。",
 "errorMessage": "Project[DEMOA] already existed."
}

# 4、devops的后端jar包(包含所有的接口和实现类)

 如果是Maven工程,可以把jar包上传到maven仓库中。GAV信息设置如下:     
<groupId>com.primeton.devops</groupId>
<artifactId>devops</artifactId>
<version>6.2.0.0</version>
上次更新: 2023-4-11 14:15:15