This commit is contained in:
wanggeng 2022-05-25 18:33:19 +08:00
commit d110ca4c4b
11 changed files with 1350 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.DS_Store

42
docs/.vuepress/config.js Normal file
View File

@ -0,0 +1,42 @@
module.exports = {
base: '/',
lang: 'zh-CN',
title: 'WGINK',
description: '',
themeConfig: {
sidebar: [
{
title: '首页',
path: '/',
sidebarDepth: 1,
children: []
},
{
title: '业务',
collapsable: true,
sidebarDepth: 5,
children: [
{
title: 'OA',
collapsable: true,
sidebarDepth: 5,
children: [
'/service/oa/backend.md',
'/service/oa/app.md',
],
},
],
},
{
title: '代码模板',
collapsable: true,
sidebarDepth: 5,
children: [
'/code-template/area-select',
'/code-template/excel-upload',
'/code-template/select'
],
}
]
}
}

0
docs/README.md Normal file
View File

View File

@ -0,0 +1,92 @@
# 地区选择
> 注意匹配ID
## 表单
css
```css
.select-area {position: relative;}
.select-area #areaName {width: 64%}
.select-area .select-btn {position: absolute; top: 0px; right: 0px; width: 36%; border-color: #e6e6e6;}
.select-area .select-btn button {height: 38px; width: 50%;}
```
html
```html
<div class="layui-form-item">
<label class="layui-form-label layui-form-label-up">选择地区</label>
<div class="layui-input-block layui-input-block-down select-area">
<input type="hidden" id="areaCode" name="areaCode">
<input type="text" id="areaName" name="areaName" class="layui-input" value="" placeholder="请选择地区" maxlength="255" readonly style="cursor:pointer;">
<div class="layui-btn-group select-btn">
<button type="button" id="areaSelectBtn" class="layui-btn layui-btn-sm layui-btn-primary" title="选择区域">
<i class="fa fa-circle-thin"></i>
</button>
<button type="button" id="areaCleanBtn" class="layui-btn layui-btn-sm layui-btn-primary" title="删除区域">
<i class="fa fa-times-circle"></i>
</button>
</div>
</div>
</div>
```
## 列表代码
css
```css
.table-select-area {position: relative; width: 200px;}
.table-select-area #areaName {width: 64%}
.table-select-area .select-btn {position: absolute; top: 0px; right: 0px; width: 36%; border-color: #e6e6e6;}
```
```html
<div class="layui-inline table-select-area">
<input type="hidden" id="areaCode">
<input type="text" id="areaName" class="layui-input search-item search-item-width-300" placeholder="选择地区" readonly>
<div class="layui-btn-group select-btn">
<button type="button" id="areaSelectBtn" class="layui-btn layui-btn-sm layui-btn-primary" title="选择区域">
<i class="fa fa-circle-thin"></i>
</button>
<button type="button" id="areaCleanBtn" class="layui-btn layui-btn-sm layui-btn-primary" title="删除区域">
<i class="fa fa-times-circle"></i>
</button>
</div>
</div>
```
## 事件
```javascript
$('#areaSelectBtn').on('click', function() {
top.dialog.open({
title: '选择地区',
url: top.restAjax.path('route/area/get-select?areaName={areaName}', [encodeURI($('#areaName').val())]),
width: '600px',
height: '225px',
onClose: function() {
var selectedAreaArray = top.dialog.dialogData.selectedAreaArray;
if(selectedAreaArray.length > 0) {
var areaCode = '';
var areaName = '';
areaCode = selectedAreaArray[selectedAreaArray.length - 1].areaCode;
for(var i = 0, item; item = selectedAreaArray[i++];) {
if(areaName) {
areaName += ' / ';
}
areaName += item.areaName;
}
$('#areaCode').val(areaCode);
$('#areaName').val(areaName);
}
}
})
});
$('#areaCleanBtn').on('click', function () {
$('#areaCode').val('');
$('#areaName').val('');
})
```

View File

@ -0,0 +1,284 @@
# EasyExcel 上传(导入)
以人口Population导入为例
1. 包含 **Excel实体类**、**错误实体类**、**导入监听器**,其中 **错误实体类** 非必须。
2. 如果不需要返回错误,可忽略输出错误文件的代码。
## Excel实体类
```java
import com.alibaba.excel.annotation.ExcelProperty;
public class PopulationExcel {
@ExcelProperty(index = 0)
private String name;
@ExcelProperty(index = 1)
private String idCard;
@ExcelProperty(index = 2)
private String areaCode;
@ExcelProperty(index = 3)
private String homeAddress;
// get set
}
```
## 错误试题类
```java
import com.alibaba.excel.annotation.ExcelProperty;
public class PopulationExcelError {
@ExcelProperty(index = 0)
private String name;
@ExcelProperty(index = 1)
private String idCard;
@ExcelProperty(index = 2)
private String areaCode;
@ExcelProperty(index = 3)
private String homeAddress;
@ExcelProperty(index = 4)
private String reason;
// get set
}
```
## 监听器
```java
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import java.util.ArrayList;
import java.util.List;
public abstract class PopulationExcelListener extends AnalysisEventListener<PopulationExcel> {
private static final Integer MAX_READ_COUNT = 100;
private List<PopulationExcel> populationExcels = new ArrayList<>();
@Override
public void invoke(PopulationExcel populationExcel, AnalysisContext analysisContext) {
if (populationExcels.size() > MAX_READ_COUNT) {
// 超过读取最大量,执行保存,
handle(populationExcels);
populationExcels.clear();
} else {
// 未达到读取最大量,继续读取
populationExcels.add(populationExcel);
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
handle(populationExcels);
populationExcels.clear();
}
/**
* 处理
*
* @param rows
*/
public abstract void handle(List<PopulationExcel> rows);
}
```
## 导入代码
### controller 层
```java
@ApiOperation(value = "试题Excel", notes = "试题Excel接口")
@ApiImplicitParams({
@ApiImplicitParam(name = "excel", value = "文件名称", paramType = "form"),
})
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
@PostMapping("import-excel")
public UploadExcelResultDTO importExcel(MultipartFile excel) throws IOException {
if (Objects.isNull(excel)) {
throw new ParamsException("Excel不能为空");
}
// 判断后缀
if (!excel.getOriginalFilename().endsWith(IFileConstant.EXCEL_SUFFIX_XLS)
&& !excel.getOriginalFilename().endsWith(IFileConstant.EXCEL_SUFFIX_XLSX)) {
throw new ParamsException("文件格式为Excel");
}
return populationService.importExcel(excel);
}
```
### service 层
```java
@Override
public UploadExcelResultDTO importExcel(MultipartFile excel) throws IOException {
// 要输出的错误内容
List<PopulationExcelError> populationExcelErrors = new ArrayList<>();
long startTime = System.currentTimeMillis();
// 读取 Excel
EasyExcel.read(excel.getInputStream(), PopulationExcel.class, new PopulationExcelListener() {
@Override
public void handle(List<PopulationExcel> populationExcels) {
// 这里处理数据,一般是入库
}
}).headRowNumber(2).sheet().doRead();
long endTime = System.currentTimeMillis();
// 生成的错误文件ID下载时使用
String excelFileId = null;
if (populationExcelErrors.size() > 0) {
excelFileId = new AbstractErrorExcelHandler<PopulationExcelError>(fileService) {
@Override
public List<List<String>> excelHeaderNames() {
// 构建错误 Excel 标题,与错误类对应
return simpleExcelHeader(new String[]{"序号", "姓名", "身份证", "错误原因"});
}
}.saveErrorExcel(populationExcelErrors);
}
// 返回实体类,
return new UploadExcelResultDTO(populationExcelErrors.size(), endTime - startTime, excelFileId);
}
```
## 模板下载接口
```java
@GetMapping("upload/upload-excel-template")
public void excelTemplate(HttpServletResponse response) throws IOException {
InputStream inputStream = PopulationRouteController.class.getClassLoader().getResourceAsStream("templates/population/upload/upload-excel-template.xls");
RequestUtil.download(response, inputStream, "人口导入模板.xls");
}
```
## 列表导入按钮
```html
<button type="button" class="layui-btn layui-btn-sm" id="uploadExcel">
<i class="fa fa-lg fa-cloud-upload"></i> 导入数据
</button>
```
## 列表导入事件
```javascript
$(document).on('click', '#uploadExcel', function() {
top.dialog.open({
url: top.restAjax.path('route/population/upload/upload-excel', []),
title: '导入人口数据',
width: '300px',
height: '196px',
onClose: function() {
reloadTable();
}
});
});
```
## 导入页面代码
```html
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<base th:href="${#request.getContextPath() + '/'}">
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" href="assets/fonts/font-awesome/css/font-awesome.css"/>
<link rel="stylesheet" href="assets/layuiadmin/layui/css/layui.css" media="all">
<link rel="stylesheet" href="assets/layuiadmin/style/admin.css" media="all">
</head>
<body>
<div class="layui-anim layui-anim-fadein">
<div class="layui-card" style="text-align: center;">
<div class="layui-card-body" style="padding: 15px;">
<blockquote class="layui-elem-quote">下载“下载模板”整理数据点击“导入数据”上传格式为xls或xlsx</blockquote>
<button id="downloadFile" type="button" class="layui-btn layui-btn" onclick="window.open('route/population/upload/upload-excel-template', 'downloadTarget')">
<i class="fa fa-lg fa-cloud-download"></i> 下载模板
</button>
<button type="button" class="layui-btn layui-btn" id="uploadExcel">
<i class="fa fa-lg fa-cloud-upload"></i> 导入数据
</button>
</div>
</div>
<iframe style="display: none" name="downloadTarget"></iframe>
</div>
<script src="assets/layuiadmin/layui/layui.js"></script>
<script>
layui.config({
base: 'assets/layuiadmin/' //静态资源所在路径
}).extend({
index: 'lib/index' //主入口模块
}).use(['index', 'upload', 'common'], function(){
var $ = layui.$;
var form = layui.form;
var common = layui.common;
function closeBox() {
parent.layer.close(parent.layer.getFrameIndex(window.name));
}
// 初始化Excel上传
function initExcelUpload() {
// Excel上传
var uploadLoading;
layui.upload.render({
elem: '#uploadExcel',
url: 'api/population/import-excel',
accept: 'file',
exts: 'xls|xlsx',
field: 'excel',
before: function() {
uploadLoading = layer.msg('正在上传,请稍后...', {icon: 16, time: 0, shade: 0.3});
},
done: function(data) {
layer.close(uploadLoading);
if(data.failedCount > 0) {
layer.open({
type: 1,
title: false,
closeBtn: 0,
shadeClose: true,
skin: '',
content: '<div style="padding: 15px;">' +
'<div>失败数量:'+ data.failedCount +'</div><br/>' +
'<div><a class="error-excel" href="javascript:void(0);" onclick="window.open(\'route/file/download/false/'+ data.errorExcel +'\');" target="downloadTarget">点击下载错误信息</a></div>' +
'</div>'
});
} else {
layer.msg('导入成功', {time: 2000}, function() {
closeBox();
});
}
},
error: function(data, index){
layer.close(uploadLoading);
if(data != null) {
top.dialog.msg(data.msg);
}
},
});
}
initExcelUpload();
$('.close').on('click', function() {
closeBox();
});
});
</script>
</body>
</html>
```

View File

@ -0,0 +1,98 @@
# 下拉选择
## 基于JQuery的下拉选择
### 直接选择
html
```html
<div class="layui-form-item">
<label class="layui-form-label"></label>
<div class="layui-input-block">
<select id="selector" name="selector" lay-filter="selectorSelect"></select>
</div>
</div>
```
js
```javascript
// 初始化
function initSelect(callback) {
top.restAjax.get(top.restAjax.path('url', ['']), {}, null, function(code, data) {
$('#selector').append('<option value="">请选择</option>');
$.each(data, function (index, item) {
$('#selector').append('<option value="+ item.dataName +" '+ (index === 0 ? 'selected' : '') +'>'+ item.dataName +'</option>');
});
// 渲染表单下拉框
form.render(null, 'dataForm');
callback ? callback() : null;
}, function(code, data) {
top.dialog.msg(data.msg);
})
}
```
### 选择并获取其他属性
以部门选择为例选择部门既要获取部门名称又要获取部门ID
html
```html
<div class="layui-form-item">
<label class="layui-form-label">接种单位名称 *</label>
<div class="layui-input-block">
<input type="hidden" id="departmentId" name="departmentId" class="layui-input" value="" maxlength="36">
<select id="departmentName" name="departmentName" lay-filter="departmentNameFilter" lay-verify="required"></select>
</div>
</div>
```
js
```javascript
// 初始化
function initDepartmentSelect(callback) {
top.restAjax.get(top.restAjax.path('api/department/list/0', []), {}, null, function(code, data) {
$('#departmentName').append('<option value="">请选择</option>');
$.each(data, function (index, item) {
$('#departmentName').append('<option value="'+ item.departmentName +'" data-department-id="'+ item.departmentId +'">'+ item.departmentName +'</option>');
});
// 渲染表单下拉框
form.render(null, 'dataForm');
callback ? callback() : null;
}, function(code, data) {
top.dialog.msg(data.msg);
})
// 添加监听事件
form.on('select(departmentNameFilter)', function(data) {
var value = data.value;
// 遍历 option 获取 option 上的属性
for(var i = 0, item; item = $(data.elem).children()[i++];) {
if(item.value == value) {
$('#departmentId').val(item.dataset.departmentId);
break;
}
}
});
}
```
### 列表上的选择
```html
<div class="layui-inline layui-form search-item">
<select id="type" name="type" lay-filter="typeFilter">
<option value="">选择类型</option>
<option value="type1">类型1</option>
<option value="type2">类型2</option>
</select>
</div>
```

View File

@ -0,0 +1,441 @@
# 用户拓展
在用户现有字段基础上,自定义 **拓展属性字段**,新增拓展表,通过 **user_id** 字段关联用户。
## 创建实体类
实体类继承自 `ink.wgink.pojo.dtos.user.UserDTO`
```java
import ink.wgink.pojo.dtos.user.UserDTO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
public class UserExpandDTO extends UserDTO {
private String userExpandId;
private String title;
private String company;
private String summary;
public UserExpandDTO() {
}
public UserExpandDTO(UserDTO userDTO) {
setUserDTO(userDTO);
}
public void setUserDTO(UserDTO userDTO) {
super.setUserId(userDTO.getUserId());
super.setUserUsername(userDTO.getUserUsername());
super.setUserName(userDTO.getUserName());
super.setUserAvatar(userDTO.getUserAvatar());
super.setUserEmail(userDTO.getUserEmail());
super.setUserLatitude(userDTO.getUserLatitude());
super.setUserExpiredDate(userDTO.getUserExpiredDate());
super.setUserLongitude(userDTO.getUserLongitude());
super.setUserPhone(userDTO.getUserPhone());
super.setUserState(userDTO.getUserState());
super.setUserType(userDTO.getUserType());
super.setUserUKey(userDTO.getUserUKey());
super.setDepartmentIds(userDTO.getDepartmentIds());
super.setDepartmentNames(userDTO.getDepartmentNames());
super.setPositionIds(userDTO.getPositionIds());
super.setPositionNames(userDTO.getPositionNames());
super.setRoleIds(userDTO.getRoleIds());
super.setRoleNames(userDTO.getRoleNames());
super.setGmtCreate(userDTO.getGmtCreate());
super.setLastLoginAddress(userDTO.getLastLoginAddress());
super.setLastLoginTime(userDTO.getLastLoginTime());
super.setLoginType(userDTO.getLoginType());
}
}
```
## 新建接口
实现或继承接口 `ink.wgink.interfaces.user.IUserExpandBaseService<UserExpandDTO extends UserDTO>`
可以直接实现,也可以通过接口继承
```java
import ink.wgink.interfaces.user.IUserExpandBaseService;
import java.util.List;
import java.util.Map;
public interface IUserExpandService extends IUserExpandBaseService<UserExpandDTO> {
/**
* 修改
*
* @param userId 用户ID
* @param userExpandVO 拓展属性
*/
void update(String userId, UserExpandVO userExpandVO);
/**
* 修改
*
* @param token
* @param userExpandVO
* @throws Exception
*/
void updateByToken(String token, UserExpandVO userExpandVO) throws Exception;
/**
* 用户拓展详情
*
* @param params
* @return
*/
UserExpandPO getPO(Map<String, Object> params);
/**
* 用户拓展详情
*
* @param userId
* @return
*/
UserExpandPO getPO(String userId);
/**
* 用户拓展列表
*
* @param params
* @return
*/
List<UserExpandPO> listPO(Map<String, Object> params);
/**
* 详情
*
* @param token
* @return
*/
UserExpandDTO getByToken(String token) throws Exception;
}
```
## 实现接口
当方法 `getRoute` 有返回值时,用户列表中会出现 <kbd>拓展属性</kbd> 按钮,用户通过点击按钮打开拓展属性的编辑页面。在编辑页面打开时,在 `window.location.href` 上会携带 `userId` 字段。
为了保证唯一,在提交时,需判断用户是否已经有值。如果有值则修改,反之新增。
示例代码中,没有完善的方法可根据情况自行处理。
```java
import ink.wgink.interfaces.user.IUserBaseService;
import ink.wgink.pojo.ListPage;
import ink.wgink.pojo.dtos.user.UserDTO;
import ink.wgink.pojo.result.SuccessResultList;
import ink.wgink.util.map.HashMapUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
@Service
public class UserExpandServiceImpl implements IUserExpandService {
@Autowired
private IUserExpandDao userExpandDao;
@Autowired
private IUserBaseService userBaseService;
@Override
public void update(String userId, UserExpandVO userExpandVO) {
UserExpandPO userExpandPO = getPO(userId);
if (userExpandPO != null) {
updateInfo(null, userId, userExpandVO);
} else {
saveInfo(null, userId, userExpandVO);
}
}
@Override
public void updateByToken(String token, UserExpandVO userExpandVO) throws Exception {
String userId = securityComponent.getAppTokenUser(token).getId();
UserExpandPO userExpandPO = getPO(userId);
if (userExpandPO != null) {
updateInfo(token, userId, userExpandVO);
} else {
saveInfo(token, userId, userExpandVO);
}
}
/**
* 保存
*
* @param token
* @param userId
* @param userExpandVO
*/
private void saveInfo(String token, String userId, UserExpandVO userExpandVO) {
Map<String, Object> params = HashMapUtil.beanToMap(userExpandVO);
params.put("userId", userId);
if (StringUtils.isNotBlank(token)) {
setAppSaveInfo(token, params);
} else {
setSaveInfo(params);
}
userExpandDao.save(params);
}
/**
* 修改
*
* @param token
* @param userId
* @param userExpandVO
*/
private void updateInfo(String token, String userId, UserExpandVO userExpandVO) {
Map<String, Object> params = HashMapUtil.beanToMap(userExpandVO);
params.put("userId", userId);
if (StringUtils.isNotBlank(token)) {
setAppUpdateInfo(token, params);
} else {
setUpdateInfo(params);
}
userExpandDao.update(params);
}
@Override
public UserExpandPO getPO(Map<String, Object> params) {
return userExpandDao.getPO(params);
}
@Override
public UserExpandPO getPO(String userId) {
Map<String, Object> params = getHashMap(2);
params.put("userId", userId);
return getPO(params);
}
@Override
public List<UserExpandPO> listPO(Map<String, Object> params) {
return userExpandDao.listPO(params);
}
@Override
public UserExpandDTO getByToken(String token) throws Exception {
String userId = securityComponent.getAppTokenUser(token).getId();
return get(userId);
}
@Override
public String getRoute() {
// 编辑页面的路径,只有详情页
return "route/userexpand/get.html";
}
private UserExpandDTO getDTO(Map<String, Object> params) {
return userExpandDao.get(params);
}
private UserExpandDTO getDTO(String userId) {
Map<String, Object> params = getHashMap(2);
params.put("userId", userId);
return getDTO(params);
}
@Override
public UserExpandDTO get(String userId) {
UserDTO userDTO = userBaseService.get(userId);
if (userDTO == null) {
return null;
}
UserExpandDTO userExpandDTO = getDTO(userId);
if (userExpandDTO == null) {
return new UserExpandDTO(userDTO);
}
userExpandDTO.setUserDTO(userDTO);
return userExpandDTO;
}
@Override
public UserExpandDTO getByUsername(String username) {
return null;
}
@Override
public List<UserExpandDTO> listByUserIds(List<String> userIds) {
return null;
}
@Override
public List<UserExpandDTO> listByUsernames(List<String> usernames) {
return null;
}
@Override
public List<UserExpandDTO> list(Map<String, Object> params) {
return null;
}
@Override
public SuccessResultList<List<UserExpandDTO>> listPage(ListPage page) {
return null;
}
@Override
public SuccessResultList<List<UserExpandDTO>> listPageByIds(List<String> userIds, ListPage page) {
return null;
}
@Override
public SuccessResultList<List<UserExpandDTO>> listPageByExcludeIds(List<String> excludeUserIds, ListPage page) {
return null;
}
@Override
public int countDateRange(String startDate, String endDate) {
return 0;
}
@Override
public int count() {
return 0;
}
@Override
public List<UserExpandDTO> listByKeywords(String keywords) {
return null;
}
}
```
## 页面
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" href="assets/fonts/font-awesome/css/font-awesome.css"/>
<link rel="stylesheet" href="assets/layuiadmin/layui/css/layui.css" media="all">
<link rel="stylesheet" href="assets/layuiadmin/style/admin.css" media="all">
</head>
<body>
<div class="layui-anim layui-anim-fadein">
<div class="layui-card">
<div class="layui-card-body" style="padding: 15px;">
<form class="layui-form layui-form-pane" lay-filter="dataForm">
<div class="layui-row">
<div class="layui-form-item">
<label class="layui-form-label">职称</label>
<div class="layui-input-block">
<input type="text" name="title" lay-verify="required" placeholder="请输入职称" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">单位</label>
<div class="layui-input-block">
<input type="text" name="company" lay-verify="required" placeholder="请输入单位" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">简介</label>
<div class="layui-input-block">
<textarea name="summary" placeholder="请输入简介" class="layui-textarea"></textarea>
</div>
</div>
</div>
<div class="layui-form-item layui-layout-admin">
<div class="layui-input-block">
<div class="layui-footer" style="left: 0;">
<button type="button" class="layui-btn" lay-submit lay-filter="submitForm">提交编辑</button>
<button type="button" class="layui-btn layui-btn-primary close">返回上级</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<script src="assets/layuiadmin/layui/layui.js"></script>
<script>
layui.config({
base: 'assets/layuiadmin/' //静态资源所在路径
}).extend({
index: 'lib/index' //主入口模块
}).use(['index', 'form', 'laydate'], function(){
var $ = layui.$;
var laydate = layui.laydate;
var form = layui.form;
var userId = top.restAjax.params(window.location.href).userId;
function closeBox() {
parent.layer.close(parent.layer.getFrameIndex(window.name));
}
function initDate() {}
initDate();
// 初始化
function initData() {
var self = this;
var loadLayerIndex;
top.restAjax.get(top.restAjax.path('api/user-expand/get/{userId}', [userId]), {}, null, function(code, data) {
form.val('dataForm', {
title: data.title,
company: data.company,
summary: data.summary
});
form.render(null, 'dataForm');
}, function(code, data) {
top.dialog.msg(data.msg);
}, function() {
loadLayerIndex = top.dialog.msg(top.dataMessage.loading, {icon: 16, time: 0, shade: 0.3});
}, function() {
top.dialog.close(loadLayerIndex);
});
}
initData();
// 提交表单
form.on('submit(submitForm)', function(formData) {
top.dialog.confirm(top.dataMessage.commit, function(index) {
top.dialog.close(index);
var loadLayerIndex;
top.restAjax.put(top.restAjax.path('api/user-expand/update/{userId}', [userId]), formData.field, null, function(code, data) {
var layerIndex = top.dialog.msg(top.dataMessage.commitSuccess, {
time: 0,
btn: [top.dataMessage.button.yes, top.dataMessage.button.no],
shade: 0.3,
yes: function(index) {
top.dialog.close(index);
window.location.reload();
},
btn2: function() {
closeBox();
}
});
}, function(code, data) {
top.dialog.msg(data.msg);
}, function() {
loadLayerIndex = top.dialog.msg(top.dataMessage.committing, {icon: 16, time: 0, shade: 0.3});
}, function() {
top.dialog.close(loadLayerIndex);
});
});
return false;
});
$('.close').on('click', function() {
closeBox();
});
});
</script>
</body>
</html>
```

319
docs/service/oa/app.md Normal file
View File

@ -0,0 +1,319 @@
# APP业务
js依赖
```html
<script src="static/form/js/app-oa-form-util.js?v="></script>
```
## 初始化
页面需要隐藏 `oa-form-footer-tool-bar`,由原生调用方法触发
> 页面加载 -> APP初始化
```js
appOaFormUtil.setForm(layui.form);
appOaFormUtil.initAppFormData(initObj);
```
参数
|名称|类型|说明|
|-|-|-|
|initObj|object|初始化对象|
initObj
|名称|类型|说明|
|-|-|-|
|confirmAssignees|array|[确认代理人](./app.md#代理人)列表|
|fields|array|[字段](./app.md#字段)列表|
|formButton|object|[表单按钮](./app.md#表单按钮)|
|currentUser|object|[当前用户](./app.md#当前用户)|
## 方法
### 字段赋值
> APP -> 页面字段
方法
```js
appOaFormUtil.setFieldValue(fieldName, fieldValue)
```
参数
|名称|类型|说明|参数值|
|-|-|-|-|
|fieldName|string|字段名|
|fieldValue|string|字段值|
### 附件赋值
方法
```js
appOaFormUtil.setAttachments(attachments)
```
参数
|名称|类型|说明|参数值|
|-|-|-|-|
|attachments|string|附件列表|格式附件1,附件2。附件格式ID:名称。英文冒号分割ID与名称英文逗号分割组。名称不能有英文冒号与逗号|
### 抄送人赋值
方法
```js
appOaFormUtil.setCcs(ccs)
```
参数
|名称|类型|说明|参数值|
|-|-|-|-|
|ccs|string|抄送人列表|格式抄送人ID1,抄送人ID2。英文逗号分割。|
### 提交表单
```js
appOaFormUtil.submitFormReport(btnIndex);
```
参数
|名称|类型|说明|参数值|
|-|-|-|-|
|btnIndex|int|按钮的下标||
## 事件
### 回退
- Method: **PUT**
- Content-Type: `application/json`
- URL`app/oa-form-report/update-go-back/process-instance-id/{processInstanceId}/task-id/{taskId}/node-id/{nodeId}`
- PathParams:
|参数|说明|
|-|-|
|processInstanceId|流程实例ID|
|taskId|当前任务ID|
|nodeId|回退到的节点ID|
- Headers:
```json
{
token: token
}
```
- RequestBody:
```json
{
reason: "原因"
}
```
- Response
状态码
|名称|值|
|-|-|
|200|请求成功|
|400|请求错误|
|401|权限不足|
|403|访问禁止|
|500|系统错误|
Body
```json
{
code: "错误编码",
msg: "错误原因"
}
```
### 强制结束
- Method: **PUT**
- Content-Type: `application/json`
- URL`app/oa-form-report/update-forced-end/process-instance-id/{processInstanceId}/task-id/{taskId}`
- PathParams:
|参数|说明|
|-|-|
|processInstanceId|流程实例ID|
|taskId|当前任务ID|
- Headers:
```json
{
token: token
}
```
- RequestBody:
```json
{
reason: "原因"
}
```
- Response
状态码
|名称|值|
|-|-|
|200|请求成功|
|400|请求错误|
|401|权限不足|
|403|访问禁止|
|500|系统错误|
Body
```json
{
code: "错误编码",
msg: "错误原因"
}
```
### 转交
- Method: **PUT**
- Content-Type: `application/json`
- URL`app/oa-form-report/update-assignee/process-instance-id/{processInstanceId}/task-id/{taskId}`
- PathParams:
|参数|说明|
|-|-|
|processInstanceId|流程实例ID|
|taskId|当前任务ID|
- Headers:
```json
{
token: token
}
```
- RequestBody:
```json
{
assignee: "接收人ID",
reason: "原因"
}
```
- Response
状态码
|名称|值|
|-|-|
|200|请求成功|
|400|请求错误|
|401|权限不足|
|403|访问禁止|
|500|系统错误|
Body
```json
{
code: "错误编码",
msg: "错误原因"
}
```
## 对象说明
### 代理人
|属性|类型|说明|参数值|
|-|-|-|-|
|assignees|Array|[代理人用户](./app.md#代理人用户)列表||
|btnExc|string|按钮条件||
|btnText|string|按钮名称||
|nextEndEvent|boolean|下节点是否为结束节点|truefalse否|
|nodeType|string|节点类型|normal普通单实例节点multiple多实例节点|
### 代理人用户
|属性|类型|说明|参数值|
|-|-|-|-|
|userId|string|用户ID||
|userName|string|用户昵称||
|userUsername|string|用户名||
|avatar|string|头像ID||
### 字段
|属性|类型|说明|参数值|
|-|-|-|-|
|fieldName|string|字段名称||
|isEditable|int|可编辑|01是|
|isVisible|int|可显示|01是|
|editHistory|string|编辑历史|noRecord不记录默认latest记录最新签批all记录全部会签
|autoBackFill|string|自动回填|noBackFill不回填默认currentUserName当前用户名currentUserDepartment当前用户部门|
### 表单按钮
|属性|类型|说明|参数值|
|-|-|-|-|
|btnAttachment|int|附件按钮|0未激活1已激活|
|btnForcedEnd|int|强制结束按钮|0未激活1已激活|
|btnPrint|int|打印按钮|0未激活1已激活
|btnCc|int|抄送按钮|0未激活1已激活|
|btnGoBack|int|回退按钮|0未激活1已激活|
|btnTransfer|int|转交按钮|0未激活1已激活|
|goBackUserTasks|array|[历史任务](./app.md#历史任务)列表(按执行顺序),当 <kbd>btnGoBack</kbd> 激活时有效||
### 历史任务
|属性|类型|说明|参数值|
|-|-|-|-|
|nodeId|string|节点ID||
|taskName|string|任务名称||
### 当前用户
|属性|类型|说明|参数值|
|-|-|-|-|
|userId|string|用户ID||
|userName|string|用户名||
|departments|array|[用户部门](./app.md#用户部门)列表||
### 用户部门
|属性|类型|说明|参数值|
|-|-|-|-|
|departmentId|string|部门ID||
|departmentParentId|string|部门上级ID||
|departmentName|string|部门名称||
|departmentCode|string|部门编码||
|departmentNo|string|部门编号||

View File

@ -0,0 +1,58 @@
# 后台业务
## 访问页面
### 新增页面
1. 设置下个节点的代理人列表
2. 设置新增页面模型
- 设置页面字段:绘制流程时每个节点的[字段](./backend.md#页面字段)设置
- 设置表单按钮以和历史任务
- 表单按钮:绘制流程时每个节点的[按钮](./backend.md#表单按钮)
- 历史任务:当前任务在流程中走过的[历史任务](./backend.md#历史任务)列表
3. 设置新增页面当前用户
4. 返回页面
## 对象说明
### 页面字段
> FieldVO
|属性|类型|说明|参数值|
|-|-|-|-|
|fieldName|string|字段名称||
|isEditable|int|可编辑|01是|
|isVisible|int|可显示|01是|
|editHistory|string|编辑历史|noRecord不记录默认latest记录最新签批all记录全部会签
|autoBackFill|string|自动回填|noBackFill不回填默认currentUserName当前用户名currentUserDepartment当前用户部门|
### 表单按钮
> FormButtonVO
|属性|类型|说明|参数值|
|-|-|-|-|
|btnAttachment|int|附件按钮|0未激活1已激活|
|btnForcedEnd|int|强制结束按钮|0未激活1已激活|
|btnPrint|int|打印按钮|0未激活1已激活
|btnCc|int|抄送按钮|0未激活1已激活|
|btnGoBack|int|回退按钮|0未激活1已激活|
|btnTransfer|int|转交按钮|0未激活1已激活|
|goBackUserTasks|List|[历史任务](./backend.md#历史任务)列表(按执行顺序),当 <kbd>btnGoBack</kbd> 激活时有效||
### 历史任务
> GoBackUserTaskVO
|属性|类型|说明|参数值|
|-|-|-|-|
|nodeId|string|节点ID||
|taskName|string|任务名称||

2
docs/standard/backend.md Normal file
View File

@ -0,0 +1,2 @@
# 后端规范

13
package.json Normal file
View File

@ -0,0 +1,13 @@
{
"devDependencies": {
"@vuepress/plugin-active-header-links": "^1.9.7",
"vuepress": "^2.0.0-beta.43"
},
"scripts": {
"docs:dev": "vuepress dev docs",
"docs:build": "vuepress build docs"
},
"dependencies": {
"@vuepress/theme-default": "^2.0.0-beta.45"
}
}