目录
一、后端
1、新建子工程 pom.xml引入
<properties>
<flowable.version>6.5.0</flowable.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-base-common</artifactId>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>${flowable.version}</version>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-ui-modeler-rest</artifactId>
<version>${flowable.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-ui-modeler-conf</artifactId>
<version>${flowable.version}</version>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-rest</artifactId>
<version>${flowable.version}</version>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-ui-task-conf</artifactId>
<version>${flowable.version}</version>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-ui-admin-conf</artifactId>
<version>${flowable.version}</version>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-ui-idm-conf</artifactId>
<version>${flowable.version}</version>
</dependency>
</dependencies>
2、配置类
2.1 数据库连接
package org.jeecg.modules.oa.flowable;
import javax.sql.DataSource;
import org.flowable.rest.service.api.RestResponseFactory;
import org.flowable.spring.SpringProcessEngineConfiguration;
import org.flowable.spring.boot.EngineConfigurationConfigurer;
import org.flowable.spring.boot.FlowableSecurityAutoConfiguration;
import org.flowable.ui.common.service.exception.InternalServerErrorException;
import org.flowable.ui.common.service.idm.RemoteIdmService;
import org.flowable.ui.modeler.properties.FlowableModelerAppProperties;
import org.flowable.ui.modeler.rest.app.EditorGroupsResource;
import org.flowable.ui.modeler.rest.app.EditorUsersResource;
import org.flowable.ui.modeler.rest.app.ModelResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import com.fasterxml.jackson.databind.ObjectMapper;
import liquibase.Liquibase;
import liquibase.database.Database;
import liquibase.database.DatabaseConnection;
import liquibase.database.DatabaseFactory;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.DatabaseException;
import liquibase.resource.ClassLoaderResourceAccessor;
@Configuration
@EnableConfigurationProperties({ FlowableModelerAppProperties.class })
@ComponentScan(basePackages = { "org.flowable.ui.modeler.repository", "org.flowable.ui.modeler.service",
"org.flowable.ui.common.service", "org.flowable.ui.common.repository", "org.flowable.ui.common.tenant",
"org.flowable.ui.modeler.rest.app", "org.flowable.rest.service.api",
"org.flowable.ui.task.service.debugger" }, excludeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = RemoteIdmService.class),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = ModelResource.class),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = EditorUsersResource.class),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = EditorGroupsResource.class),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = FlowableSecurityAutoConfiguration.class) })
public class FlowableConfiguration implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {
public static final Logger log = LoggerFactory.getLogger(FlowableConfiguration.class);
@Value("${spring.datasource.dynamic.datasource.master.url}")
private String jdbcUrl;
@Value("${spring.datasource.dynamic.datasource.master.driver-class-name}")
private String jdbcDriverClassName;
@Value("${spring.datasource.dynamic.datasource.master.username}")
private String username;
@Value("${spring.datasource.dynamic.datasource.master.password}")
private String password;
@Override
public void configure(SpringProcessEngineConfiguration engineConfiguration) {
engineConfiguration.setJdbcUrl(jdbcUrl);
engineConfiguration.setJdbcDriver(jdbcDriverClassName);
engineConfiguration.setJdbcUsername(username);
engineConfiguration.setJdbcPassword(password);
engineConfiguration.setActivityFontName("\u5B8B\u4F53");
engineConfiguration.setLabelFontName("\u5B8B\u4F53");
}
@Autowired
protected ObjectMapper objectMapper;
@ConditionalOnMissingBean
@Bean
public RestResponseFactory restResponseFactory() {
return new RestResponseFactory(objectMapper);
}
@Bean
public Liquibase liquibase(DataSource dataSource) {
log.info("Configuring Liquibase");
Liquibase liquibase = null;
try {
DatabaseConnection connection = new JdbcConnection(dataSource.getConnection());
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(connection);
database.setDatabaseChangeLogTableName("ACT_DE_" + database.getDatabaseChangeLogTableName());
database.setDatabaseChangeLogLockTableName("ACT_DE_" + database.getDatabaseChangeLogLockTableName());
liquibase = new Liquibase("META-INF/liquibase/flowable-modeler-app-db-changelog.xml",
new ClassLoaderResourceAccessor(), database);
liquibase.update("flowable");
return liquibase;
} catch (Exception e) {
throw new InternalServerErrorException("Error creating liquibase database", e);
} finally {
closeDatabase(liquibase);
}
}
private void closeDatabase(Liquibase liquibase) {
if (liquibase != null) {
Database database = liquibase.getDatabase();
if (database != null) {
try {
database.close();
} catch (DatabaseException e) {
log.warn("Error closing database", e);
}
}
}
}
}
2.2 权限配置
package org.jeecg.modules.oa.flowable;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.firewall.DefaultHttpFirewall;
import org.springframework.security.web.firewall.HttpFirewall;
@Configuration
@EnableWebSecurity
public class FlowbleSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().antMatchers("/**").permitAll().anyRequest().authenticated().and()
.httpBasic();
}
@Bean
public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
return new DefaultHttpFirewall();
}
}
2.3 这个主要是用来覆盖flowable获取当前用户的逻辑
这个设置比较重要,不设置的话,发起流程的start_user_id将会是anonymousUser。
package org.jeecg.modules.oa.flowable;
import java.security.Principal;
import org.flowable.common.engine.api.identity.AuthenticationContext;
import org.flowable.ui.common.security.SecurityUtils;
/**
* Default implementation of the {@link AuthenticationContext} that uses a {@link ThreadLocal} that stores the {@link Principal}
*
* @author Filip Hrisafov
*/
public class MyAuthenticationContext implements AuthenticationContext {
@Override
public String getAuthenticatedUserId() {
return SecurityUtils.getCurrentUserId();
}
@Override
public Principal getPrincipal() {
return null;
}
@Override
public void setPrincipal(Principal principal) {
}
}
package org.jeecg.modules.oa.flowable;
import org.flowable.common.engine.impl.identity.Authentication;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
/**
* 启动成功后的处理
* @author 76920
*
*/
@Component
public class FlowableStartedListener implements ApplicationListener<ContextRefreshedEvent>{
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
Authentication.setAuthenticationContext(new MyAuthenticationContext());
}
}
3、主工程
3.1 重写类 SecurityUtils
这个是放在主工程里面的
package org.flowable.ui.common.security;
import java.util.ArrayList;
import org.flowable.idm.api.User;
import org.flowable.ui.common.model.RemoteUser;
import org.jeecg.common.system.vo.LoginUser;
/**
* Utility class for Spring Security.
*/
public class SecurityUtils {
private static User assumeUser;
private SecurityUtils() {
}
/**
* Get the login of the current user.
*/
public static String getCurrentUserId() {
LoginUser sysUser = (LoginUser)org.apache.shiro.SecurityUtils.getSubject().getPrincipal();
if (sysUser != null) {
return sysUser.getId();
}
return null;
}
/**
* @return the {@link User} object associated with the current logged in user.
*/
public static User getCurrentUserObject() {
if (assumeUser != null) {
return assumeUser;
}
User user = new RemoteUser();
LoginUser sysUser = (LoginUser)org.apache.shiro.SecurityUtils.getSubject().getPrincipal();
if (sysUser != null) {
user.setId(sysUser.getId());
user.setDisplayName(sysUser.getUsername());
user.setPassword(sysUser.getPassword());
}
return user;
}
public static FlowableAppUser getCurrentFlowableAppUser() {
User s = getCurrentUserObject();
FlowableAppUser user = new FlowableAppUser(s, s.getId(), new ArrayList<>());
return user;
}
public static boolean currentUserHasCapability(String capability) {
return true;
}
public static void assumeUser(User user) {
assumeUser = user;
}
public static void clearAssumeUser() {
assumeUser = null;
}
}
3.2 新增发布流程的逻辑
package org.jeecg.modules.oa.flowable.controller;
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.editor.language.json.converter.BpmnJsonConverter;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.DeploymentBuilder;
import org.flowable.idm.api.User;
import org.flowable.ui.common.security.SecurityUtils;
import org.flowable.ui.common.service.exception.BadRequestException;
import org.flowable.ui.common.service.exception.ConflictingRequestException;
import org.flowable.ui.common.service.exception.InternalServerErrorException;
import org.flowable.ui.modeler.domain.Model;
import org.flowable.ui.modeler.model.ModelKeyRepresentation;
import org.flowable.ui.modeler.model.ModelRepresentation;
import org.flowable.ui.modeler.repository.ModelRepository;
import org.flowable.ui.modeler.serviceapi.ModelService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.text.ParseException;
import java.util.Date;
@RestController
@RequestMapping("/app")
public class MyModelResources {
private static final Logger LOGGER = LoggerFactory.getLogger(MyModelResources.class);
private static final String RESOLVE_ACTION_OVERWRITE = "overwrite";
private static final String RESOLVE_ACTION_SAVE_AS = "saveAs";
private static final String RESOLVE_ACTION_NEW_VERSION = "newVersion";
@Autowired
protected ModelService modelService;
@Autowired
protected ModelRepository modelRepository;
@Autowired
protected ObjectMapper objectMapper;
@Autowired
private RepositoryService repositoryService;
protected BpmnJsonConverter bpmnJsonConverter = new BpmnJsonConverter();
protected BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();
@PostMapping("publish/{modelId}")
public JSONObject publish(@PathVariable("modelId") String modelId) {
Model model = modelService.getModel(modelId);
String name = model.getName().replaceAll(" ", "_") + ".bpmn20.xml";
BpmnModel bpmnModel = modelService.getBpmnModel(model);
byte[] xmlBytes = modelService.getBpmnXML(bpmnModel);
BufferedInputStream in = new BufferedInputStream(new ByteArrayInputStream(xmlBytes));
DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
deploymentBuilder.addInputStream(name, in);
deploymentBuilder.name(model.getName());
deploymentBuilder.key(model.getKey());
deploymentBuilder.tenantId(model.getTenantId());
Deployment deployment = deploymentBuilder.deploy();
JSONObject rs = new JSONObject();
rs.put("success", true);
rs.put("data", deployment.getId());
return rs;
}
/**
* GET /rest/models/{modelId} -> Get process model
*/
@GetMapping(value = "/rest/models/{modelId}", produces = "application/json")
public ModelRepresentation getModel(@PathVariable String modelId) {
return modelService.getModelRepresentation(modelId);
}
/**
* GET /rest/models/{modelId}/thumbnail -> Get process model thumbnail
*/
@GetMapping(value = "/rest/models/{modelId}/thumbnail", produces = MediaType.IMAGE_PNG_VALUE)
public byte[] getModelThumbnail(@PathVariable String modelId) {
Model model = modelService.getModel(modelId);
return model.getThumbnail();
}
/**
* PUT /rest/models/{modelId} -> update process model properties
*/
@PutMapping(value = "/rest/models/{modelId}")
public ModelRepresentation updateModel(@PathVariable String modelId, @RequestBody ModelRepresentation updatedModel) {
// Get model, write-permission required if not a favorite-update
Model model = modelService.getModel(modelId);
ModelKeyRepresentation modelKeyInfo = modelService.validateModelKey(model, model.getModelType(), updatedModel.getKey());
if (modelKeyInfo.isKeyAlreadyExists()) {
throw new BadRequestException("Model with provided key already exists " + updatedModel.getKey());
}
try {
updatedModel.updateModel(model);
if (model.getModelType() != null) {
ObjectNode modelNode = (ObjectNode) objectMapper.readTree(model.getModelEditorJson());
modelNode.put("name", model.getName());
modelNode.put("key", model.getKey());
if (Model.MODEL_TYPE_BPMN == model.getModelType()) {
ObjectNode propertiesNode = (ObjectNode) modelNode.get("properties");
propertiesNode.put("process_id", model.getKey());
propertiesNode.put("name", model.getName());
if (StringUtils.isNotEmpty(model.getDescription())) {
propertiesNode.put("documentation", model.getDescription());
}
modelNode.set("properties", propertiesNode);
}
model.setModelEditorJson(modelNode.toString());
}
modelRepository.save(model);
ModelRepresentation result = new ModelRepresentation(model);
return result;
} catch (Exception e) {
throw new BadRequestException("Model cannot be updated: " + modelId);
}
}
/**
* DELETE /rest/models/{modelId} -> delete process model or, as a non-owner, remove the share info link for that user specifically
*/
@ResponseStatus(value = HttpStatus.OK)
@DeleteMapping(value = "/rest/models/{modelId}")
public void deleteModel(@PathVariable String modelId) {
// Get model to check if it exists, read-permission required for delete
Model model = modelService.getModel(modelId);
try {
modelService.deleteModel(model.getId());
} catch (Exception e) {
LOGGER.error("Error while deleting: ", e);
throw new BadRequestException("Model cannot be deleted: " + modelId);
}
}
/**
* GET /rest/models/{modelId}/editor/json -> get the JSON model
*/
@GetMapping(value = "/rest/models/{modelId}/editor/json", produces = "application/json")
public ObjectNode getModelJSON(@PathVariable String modelId) {
Model model = modelService.getModel(modelId);
ObjectNode modelNode = objectMapper.createObjectNode();
modelNode.put("modelId", model.getId());
modelNode.put("name", model.getName());
modelNode.put("key", model.getKey());
modelNode.put("description", model.getDescription());
modelNode.putPOJO("lastUpdated", model.getLastUpdated());
modelNode.put("lastUpdatedBy", model.getLastUpdatedBy());
if (StringUtils.isNotEmpty(model.getModelEditorJson())) {
try {
ObjectNode editorJsonNode = (ObjectNode) objectMapper.readTree(model.getModelEditorJson());
editorJsonNode.put("modelType", "model");
modelNode.set("model", editorJsonNode);
} catch (Exception e) {
LOGGER.error("Error reading editor json {}", modelId, e);
throw new InternalServerErrorException("Error reading editor json " + modelId);
}
} else {
ObjectNode editorJsonNode = objectMapper.createObjectNode();
editorJsonNode.put("id", "canvas");
editorJsonNode.put("resourceId", "canvas");
ObjectNode stencilSetNode = objectMapper.createObjectNode();
stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
editorJsonNode.put("modelType", "model");
modelNode.set("model", editorJsonNode);
}
return modelNode;
}
/**
* POST /rest/models/{modelId}/editor/json -> save the JSON model
*/
@PostMapping(value = "/rest/models/{modelId}/editor/json")
public ModelRepresentation saveModel(@PathVariable String modelId, @RequestBody MultiValueMap<String, String> values) {
// Validation: see if there was another update in the meantime
long lastUpdated = -1L;
String lastUpdatedString = values.getFirst("lastUpdated");
if (lastUpdatedString == null) {
throw new BadRequestException("Missing lastUpdated date");
}
try {
Date readValue = objectMapper.getDeserializationConfig().getDateFormat().parse(lastUpdatedString);
lastUpdated = readValue.getTime();
} catch (ParseException e) {
throw new BadRequestException("Invalid lastUpdated date: '" + lastUpdatedString + "'");
}
Model model = modelService.getModel(modelId);
User currentUser = SecurityUtils.getCurrentUserObject();
boolean currentUserIsOwner = model.getLastUpdatedBy().equals(currentUser.getId());
String resolveAction = values.getFirst("conflictResolveAction");
// If timestamps differ, there is a conflict or a conflict has been resolved by the user
if (model.getLastUpdated().getTime() != lastUpdated) {
if (RESOLVE_ACTION_SAVE_AS.equals(resolveAction)) {
String saveAs = values.getFirst("saveAs");
String json = values.getFirst("json_xml");
return createNewModel(saveAs, model.getDescription(), model.getModelType(), json);
} else if (RESOLVE_ACTION_OVERWRITE.equals(resolveAction)) {
return updateModel(model, values, false);
} else if (RESOLVE_ACTION_NEW_VERSION.equals(resolveAction)) {
return updateModel(model, values, true);
} else {
// Exception case: the user is the owner and selected to create a new version
String isNewVersionString = values.getFirst("newversion");
return updateModel(model, values, true);
}
} else {
// Actual, regular, update
return updateModel(model, values, false);
}
}
/**
* POST /rest/models/{modelId}/newversion -> create a new model version
*/
@PostMapping(value = "/rest/models/{modelId}/newversion")
public ModelRepresentation importNewVersion(@PathVariable String modelId, @RequestParam("file") MultipartFile file) {
InputStream modelStream = null;
try {
modelStream = file.getInputStream();
} catch (Exception e) {
throw new BadRequestException("Error reading file inputstream", e);
}
return modelService.importNewVersion(modelId, file.getOriginalFilename(), modelStream);
}
protected ModelRepresentation updateModel(Model model, MultiValueMap<String, String> values, boolean forceNewVersion) {
String name = values.getFirst("name");
String key = values.getFirst("key").replaceAll(" ", "");
String description = values.getFirst("description");
String isNewVersionString = values.getFirst("newversion");
String newVersionComment = null;
ModelKeyRepresentation modelKeyInfo = modelService.validateModelKey(model, model.getModelType(), key);
if (modelKeyInfo.isKeyAlreadyExists()) {
throw new BadRequestException("Model with provided key already exists " + key);
}
boolean newVersion = false;
if (forceNewVersion) {
newVersion = true;
newVersionComment = values.getFirst("comment");
} else {
if (isNewVersionString != null) {
newVersion = "true".equals(isNewVersionString);
newVersionComment = values.getFirst("comment");
}
}
String json = values.getFirst("json_xml");
try {
ObjectNode editorJsonNode = (ObjectNode) objectMapper.readTree(json);
ObjectNode propertiesNode = (ObjectNode) editorJsonNode.get("properties");
String processId = key;
propertiesNode.put("process_id", processId);
propertiesNode.put("name", name);
if (StringUtils.isNotEmpty(description)) {
propertiesNode.put("documentation", description);
}
editorJsonNode.set("properties", propertiesNode);
model = modelService.saveModel(model.getId(), name, key, description, editorJsonNode.toString(), newVersion,
newVersionComment, SecurityUtils.getCurrentUserObject());
return new ModelRepresentation(model);
} catch (Exception e) {
LOGGER.error("Error saving model {}", model.getId(), e);
throw new BadRequestException("Process model could not be saved " + model.getId());
}
}
protected ModelRepresentation createNewModel(String name, String description, Integer modelType, String editorJson) {
ModelRepresentation model = new ModelRepresentation();
model.setName(name);
model.setDescription(description);
model.setModelType(modelType);
Model newModel = modelService.createModel(model, editorJson, SecurityUtils.getCurrentUserObject());
return new ModelRepresentation(newModel);
}
}
3.2 配置文件
加了标记部分,其余不变。
mybatis-plus:
mapper-locations: classpath*:org/jeecg/modules/**/xml/*Mapper.xml,classpath:/META-INF/modeler-mybatis-mappings/*.xml
configuration-properties:
blobType: BLOB
boolValue: true
prefix: ''
还有excludeUrls放开了一部分url
可以根据自己需要来
/app/rest/process-instances/history/*/model-json,/app/rest/process-instances/*/model-json,/app/rest/process-definitions/*/model-json,/repository/process-definitions/*/image,/app/rest/models/*/*
数据库连接注意加上设置:nullCatalogMeansCurrent=true
url: jdbc:mysql://127.0.0.1:3306/jeecg-boot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
因为flowable启动扫描表用了这个getTables方法
二、前端
1、去官网下载包,然后把flowable-modeler的static复制到前端工程public目录下
2、修改配置
2.1 修改 app-cfg.js
此处/jeecg-boot 与 vue.config.js 的配置对应
2.2 修改public/flowable/scripts/common/providers-config.js angular请求拦截器,放入jeecg的token
request: function(config) {
config.headers = config.headers || {}
if (localStorage.getItem('pro__Access-Token')) {
config.headers['X-Access-Token'] = JSON.parse(localStorage.getItem('pro__Access-Token')).value;
};
return config || $q.when(config)
},
3、vue组件引入
<template>
<div class="flowable-main">
<iframe src="/flowable/index.html" width="100%" height="100%" frameborder="0"></iframe>
</div>
</template>
<script>
export default {
name: 'Main'
}
</script>
<style scoped>
.flowable-main {
height: 650px
}
</style>
然后菜单配置下就ok了。