Browse Source

完成扫码入库功能

lwx_dev
erdanergou 3 years ago
parent
commit
780428a2c8
  1. 1
      .idea/encodings.xml
  2. 55
      src/main/java/com/dreamchaser/depository_manage/config/PortConfig.java
  3. 54
      src/main/java/com/dreamchaser/depository_manage/controller/DepositoryRecordController.java
  4. 98
      src/main/java/com/dreamchaser/depository_manage/controller/MaterialController.java
  5. 98
      src/main/java/com/dreamchaser/depository_manage/controller/PageController.java
  6. 27
      src/main/java/com/dreamchaser/depository_manage/controller/PlaceController.java
  7. 7
      src/main/java/com/dreamchaser/depository_manage/entity/ApplicationOutRecord.java
  8. 43
      src/main/java/com/dreamchaser/depository_manage/entity/ApplicationOutRecordMin.java
  9. 7
      src/main/java/com/dreamchaser/depository_manage/mapper/DepositoryMapper.java
  10. 10
      src/main/java/com/dreamchaser/depository_manage/mapper/DepositoryMapper.xml
  11. 21
      src/main/java/com/dreamchaser/depository_manage/mapper/DepositoryRecordMapper.java
  12. 52
      src/main/java/com/dreamchaser/depository_manage/mapper/DepositoryRecordMapper.xml
  13. 2
      src/main/java/com/dreamchaser/depository_manage/mapper/MaterialMapper.xml
  14. 5
      src/main/java/com/dreamchaser/depository_manage/pojo/ApplicationOutRecordP.java
  15. 3
      src/main/java/com/dreamchaser/depository_manage/pojo/MaterialP.java
  16. 24
      src/main/java/com/dreamchaser/depository_manage/service/DepositoryRecordService.java
  17. 7
      src/main/java/com/dreamchaser/depository_manage/service/DepositoryService.java
  18. 3
      src/main/java/com/dreamchaser/depository_manage/service/PlaceService.java
  19. 87
      src/main/java/com/dreamchaser/depository_manage/service/impl/DepositoryRecordServiceImpl.java
  20. 10
      src/main/java/com/dreamchaser/depository_manage/service/impl/DepositoryServiceImpl.java
  21. 2
      src/main/resources/static/js/VueQrcodeReader.umd.min.js
  22. 15
      src/main/resources/static/js/ZXing.js
  23. 10100
      src/main/resources/static/js/jsQR.js
  24. 12551
      src/main/resources/static/js/library.min.js
  25. 5
      src/main/resources/static/js/respond.min.js
  26. 2
      src/main/resources/static/js/vue/common/permission.js
  27. 25
      src/main/resources/static/js/vue/router.js
  28. 3146
      src/main/resources/static/js/vue/vue-router.js
  29. 6
      src/main/resources/static/js/vue/vue-router.min.js
  30. 307
      src/main/resources/static/vuePage/index.vue
  31. 166
      src/main/resources/static/vuePage/scanCode.vue
  32. 23
      src/main/resources/templates/index.html
  33. 1
      src/main/resources/templates/pages/application/application-in.html
  34. 25
      src/main/resources/templates/pages/application/application-in_back.html
  35. 634
      src/main/resources/templates/pages/application/application-in_scanQrCode.html
  36. 91
      src/main/resources/templates/pages/application/application-out.html
  37. 40
      src/main/resources/templates/pages/application/application-out_back.html
  38. 243
      src/main/resources/templates/pages/application/application-out_scanQrCode.html
  39. 2
      src/main/resources/templates/pages/application/application-review.html
  40. 4
      src/main/resources/templates/pages/depository/table-stock.html
  41. 333
      src/main/resources/templates/pages/scanQrCode/ScanQrCode.html
  42. 150
      src/main/resources/templates/pages/scanQrCode/scanQrCode2.html
  43. 10
      target/classes/com/dreamchaser/depository_manage/mapper/DepositoryMapper.xml
  44. 52
      target/classes/com/dreamchaser/depository_manage/mapper/DepositoryRecordMapper.xml
  45. 2
      target/classes/com/dreamchaser/depository_manage/mapper/MaterialMapper.xml
  46. BIN
      target/classes/static/images/cam.png
  47. BIN
      target/classes/static/images/vid.png
  48. 2
      target/classes/static/js/VueQrcodeReader.umd.min.js
  49. 15
      target/classes/static/js/ZXing.js
  50. 1
      target/classes/static/js/html5.min.js
  51. 10100
      target/classes/static/js/jsQR.js
  52. 12551
      target/classes/static/js/library.min.js
  53. 5
      target/classes/static/js/respond.min.js
  54. 84
      target/classes/static/js/scan/ga.js
  55. 1
      target/classes/static/js/scan/llqrcode.js
  56. 0
      target/classes/static/js/scan/plusone.js
  57. 240
      target/classes/static/js/scan/webqr.js
  58. 0
      target/classes/static/js/vue/common/helper.js
  59. 2
      target/classes/static/js/vue/common/permission.js
  60. 25
      target/classes/static/js/vue/router.js
  61. 3146
      target/classes/static/js/vue/vue-router.js
  62. 6
      target/classes/static/js/vue/vue-router.min.js
  63. 11944
      target/classes/static/js/vue/vue.js
  64. 6
      target/classes/static/js/vue/vue.min.js
  65. 40
      target/classes/static/lib/http-vue-loader/.gitignore
  66. 40
      target/classes/static/lib/http-vue-loader/.npmignore
  67. 316
      target/classes/static/lib/http-vue-loader/README.md
  68. 24
      target/classes/static/lib/http-vue-loader/package.json
  69. 478
      target/classes/static/lib/http-vue-loader/src/httpVueLoader.js
  70. 3
      target/classes/static/lib/vue-qrcode-reader/.browserslistrc
  71. 18
      target/classes/static/lib/vue-qrcode-reader/.editorconfig
  72. 25
      target/classes/static/lib/vue-qrcode-reader/.eslintrc.js
  73. 28
      target/classes/static/lib/vue-qrcode-reader/.github/ISSUE_TEMPLATE/bug_report.md
  74. 19
      target/classes/static/lib/vue-qrcode-reader/.github/ISSUE_TEMPLATE/wrong_camera.md
  75. BIN
      target/classes/static/lib/vue-qrcode-reader/.github/browserstack-logo.png
  76. BIN
      target/classes/static/lib/vue-qrcode-reader/.github/screenshot1.png
  77. BIN
      target/classes/static/lib/vue-qrcode-reader/.github/screenshot2.png
  78. BIN
      target/classes/static/lib/vue-qrcode-reader/.github/screenshot3.png
  79. BIN
      target/classes/static/lib/vue-qrcode-reader/.github/travis-logo.png
  80. 33
      target/classes/static/lib/vue-qrcode-reader/.github/workflows/main.yml
  81. 26
      target/classes/static/lib/vue-qrcode-reader/.gitignore
  82. 4
      target/classes/static/lib/vue-qrcode-reader/.releaserc.yml
  83. 23
      target/classes/static/lib/vue-qrcode-reader/CONTRIBUTING.md
  84. 183
      target/classes/static/lib/vue-qrcode-reader/README.md
  85. 3
      target/classes/static/lib/vue-qrcode-reader/babel.config.js
  86. 54
      target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/DemoWrapper.vue
  87. 92
      target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/demos/CustomTracking.vue
  88. 62
      target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/demos/DecodeAll.vue
  89. 80
      target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/demos/DragDrop.vue
  90. 115
      target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/demos/Fullscreen.vue
  91. 61
      target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/demos/LoadingIndicator.vue
  92. 78
      target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/demos/ScanSameQrcodeMoreThanOnce.vue
  93. 82
      target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/demos/SwitchCamera.vue
  94. 64
      target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/demos/Torch.vue
  95. 47
      target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/demos/Upload.vue
  96. 118
      target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/demos/Validate.vue
  97. 41
      target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/config.js
  98. 1
      target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/public/camera-switch.svg
  99. 1
      target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/public/checkmark.svg
  100. 102
      target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/public/debug-memory-leak.html

1
.idea/encodings.xml

@ -3,5 +3,6 @@
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources/templates/pages/scanQrCode/scanQrCode2.html" charset="UTF-8" />
</component>
</project>

55
src/main/java/com/dreamchaser/depository_manage/config/PortConfig.java

@ -1,6 +1,20 @@
package com.dreamchaser.depository_manage.config;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dreamchaser.depository_manage.controller.PageController;
import com.dreamchaser.depository_manage.entity.Administration;
import com.dreamchaser.depository_manage.entity.Post;
import com.dreamchaser.depository_manage.entity.UserByPort;
import com.dreamchaser.depository_manage.utils.HttpUtils;
import lombok.Data;
import org.apache.http.protocol.HTTP;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 用于
@ -13,4 +27,45 @@ public class PortConfig {
public static String external_url_6666 = "http://172.20.2.87:6666";
// public static String external_url_6666 = "http://127.0.0.1:6666";
/**
* 获取相应部门的部门负责人
* @param administration
* @return
*/
public static List<UserByPort> findDepartmentHeadByUser(Administration administration){
String url = PortConfig.external_url + "/org/positionlist";
Integer maindeparment = administration.getId();
Map<String,Object> map = new HashMap<>();
map.put("organization",maindeparment.toString());
map.put("incharge",1);
String jsonString = JSONObject.toJSONString(map);
JSONObject paramObject = JSONObject.parseObject(jsonString);
String post = null;
try {
post = HttpUtils.send(url, paramObject, HTTP.UTF_8);
} catch (IOException e) {
e.printStackTrace();
}
JSONObject jsonObject = JSONObject.parseObject(post);
JSONObject data = (JSONObject) jsonObject.get("data");
JSONArray list = (JSONArray) data.get("list");
if(list == null){
list = new JSONArray();
}
List<Post> userPostList = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
Post userPost = JSONObject.toJavaObject((JSONObject) list.get(i), Post.class);
userPostList.add(userPost);
}
List<UserByPort> userByPortList = new ArrayList<>();
for (int i = 0; i < userPostList.size(); i++) {
Map<String,Object> param = new HashMap<>();
Post userPost = userPostList.get(i);
param.put("position",userPost.getId());
List<UserByPort> userByPorts = PageController.FindUserByMap(param);
userByPortList.addAll(userByPorts);
}
return userByPortList;
}
}

54
src/main/java/com/dreamchaser/depository_manage/controller/DepositoryRecordController.java

@ -121,7 +121,7 @@ public class DepositoryRecordController {
List<Object> errMsg = new ArrayList<>();
List<Object> successMsg = new ArrayList<>();
for (int i = 0; i < params.size(); i++) {
Integer temp = params.get(i);
Integer temp = ObjectFormatUtil.toInteger(params.get(i));
Map<String,Object> insert = new HashMap<>();
Integer placeId = ObjectFormatUtil.toInteger(map.get("placeId"+temp));
insert.put("applicantId",userToken.getId());
@ -198,21 +198,41 @@ public class DepositoryRecordController {
List<Integer> params = (List<Integer>) map.get("params");
Integer integer = 0;
if(params.size() < 1 && map.size() > 3){
integer += depositoryRecordService.insertApplicationOutRecord(map);
Integer res = depositoryRecordService.insertApplicationOutRecord(map,userToken); // 插入主订单
if(res == 1){ // 如果插入成功
Object id = map.get("id"); // 获取主订单编号
if(id != null){
map.remove("id");
map.put("parentId",id);
}
integer += depositoryRecordService.insertApplicationOutMin(map);
}
}else{
// 插入主订单
// map.put("departmenthead",departmentHeadByUser.getId());
Integer res = depositoryRecordService.insertApplicationOutRecord(map,userToken);
if(res == 1) {
for (int i = 0; i < params.size(); i++) {
Integer temp = params.get(i);
Map<String,Object> insert = new HashMap<>();
insert.put("applicantId",userToken.getId());
// insert.put("departmenthead",departmentHeadByUser.getId());
insert.put("mid",map.get("mid"+temp));
insert.put("quantity",map.get("quantity"+temp));
insert.put("applyRemark",map.get("applyRemark"+temp));
insert.put("code",map.get("code"+temp));
insert.put("placeId",map.get("placeId"+temp));
integer += depositoryRecordService.insertApplicationOutRecord(insert);
Map<String, Object> insert = new HashMap<>();
insert.put("applicantId", userToken.getId());
insert.put("mid", map.get("mid" + temp));
insert.put("quantity", map.get("quantity" + temp));
insert.put("applyRemark", map.get("applyRemark" + temp));
insert.put("code", map.get("code"));
insert.put("placeId", map.get("placeId" + temp));
// 获取主订单编号
insert.put("parentId", map.get("id"));
// 插入子订单
integer += depositoryRecordService.insertApplicationOutMin(insert);
}
// 插入子订单
map.put("parentId", map.get("id"));
map.remove("id");
// 插入子订单
integer += depositoryRecordService.insertApplicationOutMin(map);
}
integer += depositoryRecordService.insertApplicationOutRecord(map);
}
if(integer != 0 && params.size() < 1){
return CrudUtil.postHandle(integer,1);
@ -328,7 +348,7 @@ public class DepositoryRecordController {
map.remove("depositoryId");
Integer integer = 0;
if(params.size() < 1 && map.size() > 4){
integer += depositoryRecordService.transferApply(map);
integer += depositoryRecordService.transferApply(map,userToken);
}else if(params.size() > 0){
for (int i = 0; i < params.size(); i++) {
Integer temp = params.get(i);
@ -340,9 +360,9 @@ public class DepositoryRecordController {
insert.put("quantity",map.get("quantity"+temp));
insert.put("applyRemark",map.get("applyRemark"+temp));
insert.put("code",map.get("code"+temp));
integer += depositoryRecordService.transferApply(insert);
integer += depositoryRecordService.transferApply(insert,userToken);
}
integer += depositoryRecordService.transferApply(map);
integer += depositoryRecordService.transferApply(map,userToken);
}
if(params.size() < 1) {
return CrudUtil.postHandle(integer, 1);
@ -439,7 +459,7 @@ public class DepositoryRecordController {
}else if("out".equals(type)){
UserByPort departmentHeadByUser = findDepartmentHeadByUser(userToken);
map.put("departmenthead",departmentHeadByUser.getId());
success += depositoryRecordService.insertApplicationOutRecord(map);
success += depositoryRecordService.insertApplicationOutRecord(map,userToken);
}
if(success == 0){
return new RestResponse("",666,new StatusInfo("申请失败","超出最大存储容量"));
@ -493,7 +513,7 @@ public class DepositoryRecordController {
outRecord.put("applyRemark",applyRemark);
UserByPort departmentHeadByUser = findDepartmentHeadByUser(userToken);
outRecord.put("departmenthead",departmentHeadByUser.getId());
success += depositoryRecordService.insertApplicationOutRecord(outRecord);
success += depositoryRecordService.insertApplicationOutRecord(outRecord,userToken);
}
}
if(success == 0){

98
src/main/java/com/dreamchaser/depository_manage/controller/MaterialController.java

@ -1,5 +1,7 @@
package com.dreamchaser.depository_manage.controller;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dreamchaser.depository_manage.entity.*;
import com.dreamchaser.depository_manage.exception.MyException;
import com.dreamchaser.depository_manage.pojo.*;
@ -12,6 +14,7 @@ import com.dreamchaser.depository_manage.utils.CrudUtil;
import com.dreamchaser.depository_manage.utils.ObjectFormatUtil;
import com.sun.mail.imap.protocol.ID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
@ -37,6 +40,9 @@ public class MaterialController {
@Autowired
PlaceService placeService;
@Autowired
private RedisTemplate<Object,Object> redisTemplate;
/**
* 根据物料进行查询
* @param map
@ -199,6 +205,8 @@ public class MaterialController {
return new RestResponse(materialPByCondition,materialService.findCountByCondition(map),200);
}
// 构造物料二维码
@GetMapping("/createQrCode")
public RestResponse createQrCode(@RequestParam("mid") Integer mid) {
Material materialById = materialService.findMaterialById(mid);
@ -214,4 +222,94 @@ public class MaterialController {
return new RestResponse("err: "+e.getMessage(),678,new StatusInfo("失败","请联系开发人员"));
}
}
// 将数据暂存到redis中
@PostMapping("/temporaryValue")
public RestResponse temporaryValue(@RequestBody Map<String,Object> map,HttpServletRequest request){
UserByPort userByPort = (UserByPort) request.getAttribute("userToken");
ArrayList arrayList = (ArrayList) map.get("materialList");
ArrayList materailList = new ArrayList();
for (int i = 0; i < arrayList.size(); i++) {
if(materailList.indexOf(arrayList.get(i)) == -1){
materailList.add(arrayList.get(i));
}
}
map.put("materialList",materailList);
redisTemplate.opsForValue().set("scanQrCodeValue"+userByPort.getNumber(),JSONObject.toJSONString(map));
return new RestResponse();
}
// 判断当前扫描的物料是否存在
@GetMapping("/IsMaterialExist")
public RestResponse IsMaterialExist(HttpServletRequest request){
UserByPort userByPort = (UserByPort) request.getAttribute("userToken");
String scanQrCodeValue = redisTemplate.opsForValue().get("scanQrCodeValue"+userByPort.getNumber()).toString();
redisTemplate.delete("scanQrCodeValue"+userByPort.getNumber());
JSONObject jsonObject = JSONObject.parseObject(scanQrCodeValue);
JSONObject depository = (JSONObject) jsonObject.get("depository"); // 扫描的仓库
JSONObject place = (JSONObject) jsonObject.get("place"); // 扫描的库位
JSONArray materialList = (JSONArray) jsonObject.get("materialList"); // 扫描的物料集合
ArrayList<Object> newMaterialList = new ArrayList();
Map<String,Object> map = new HashMap<>();
for (int i = 0; i < materialList.size(); i++) {
JSONObject obj = (JSONObject) materialList.get(i);;
map.put("code",obj.get("code"));
if(depository != null){
map.put("depositoryId",depository.get("did"));
}
if(place != null){
map.put("depositoryId",place.get("depositoryId"));
}
List<MaterialP> inventory = materialService.findInventory(map);
if(inventory.size() > 0){
MaterialP materialP = inventory.get(0);
Map<String,Object> params = new HashMap<>();
// 有该物料
// 重新缓存到redis中
params.put("mid",materialP.getId());
params.put("mname",materialP.getMname());
params.put("code",materialP.getCode());
params.put("version",materialP.getVersion());
newMaterialList.add(params);
}else{
// 没有该物料
continue;
}
}
map.put("depository",depository);
map.put("place",place);
map.put("materialList",newMaterialList);
redisTemplate.opsForValue().set("scanQrCodeValue"+userByPort.getNumber(),JSONObject.toJSONString(map));
return new RestResponse();
}
//用于判断当前出库数量是否合适
@PostMapping("/MaterialQuantityIsTrue")
public RestResponse MaterialQuantityIsTrue(@RequestBody Map<String,Object> map,HttpServletRequest request){
UserByPort userByPort = (UserByPort) request.getAttribute("userToken");
// 当前出库数量
Integer quantity = ObjectFormatUtil.toInteger(map.get("quantity"));
// 标志变量,用于标识当前数量是否合适
Boolean flag = false;
map.remove("quantity");
// 获取当前用户所在部门关闭的仓库及公共仓库
List<Depository> depositoryByAdminorg = depositoryService.findDepositoryByAdminorg(userByPort.getMaindeparment().toString());
for (int i = 0; i < depositoryByAdminorg.size(); i++) {
map.put("depositoryId",depositoryByAdminorg.get(i).getId());
List<MaterialP> inventory = materialService.findInventory(map);
if(inventory.size() > 0){ // 如果有库存
for (int j = 0; j < inventory.size(); j++) {
MaterialP materialP = inventory.get(j);
if(quantity < materialP.getQuantity()){ // 如果当前数量合适则跳出循环
flag = true;
break;
}
}
}
}
return new RestResponse(flag);
}
}

98
src/main/java/com/dreamchaser/depository_manage/controller/PageController.java

@ -20,6 +20,7 @@ import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@ -62,6 +63,8 @@ public class PageController {
@Autowired
private PlaceService placeService;
@Autowired
private RedisTemplate<Object,Object> redisTemplate;
@ -521,8 +524,11 @@ public class PageController {
ModelAndView mv = new ModelAndView();
Material materialById = new Material();
Depository depositoryRecordById = new Depository();
if(mid != null && depositoryId != null){
if(mid != null ){
materialById = materialService.findMaterialById(mid);
}
if(depositoryId != null){
depositoryRecordById = depositoryService.findDepositoryRecordById(depositoryId);
}
mv.addObject("materialById",materialById);
@ -549,14 +555,23 @@ public class PageController {
}
@GetMapping("/application_out_back")
public ModelAndView application_out_back(Integer mid) {
public ModelAndView application_out_back(Integer code,String depositoryCode) {
ModelAndView mv = new ModelAndView();
mv.setViewName("pages/application/application-out_back");
Material materialById = new Material();
if(mid != null) {
materialById = materialService.findMaterialById(mid);
}
MaterialP materialById = new MaterialP();
if(code != null) {
Map<String,Object> map = new HashMap<>();
Depository depositoryByCode = depositoryService.findDepositoryByCode(depositoryCode);
map.put("depositoryId",depositoryByCode.getId());
map.put("code",code);
List<MaterialP> inventory = materialService.findInventory(map);
if(inventory.size() < 1){
mv.addObject("materialById",new Material());
}else{
materialById = inventory.get(0);
mv.addObject("materialById",materialById);
}
}
return mv;
}
@ -816,7 +831,7 @@ public class PageController {
// 用于二维码存放数据
Map<String,Object> param = new HashMap<>();
param.put("code",depositoryRecordById.getCode());
param.put("id",depositoryRecordById.getId());
param.put("did",depositoryRecordById.getId());
param.put("dname",depositoryRecordById.getDname());
param.put("introduce",depositoryRecordById.getIntroduce());
String context = JSONObject.toJSONString(param);
@ -866,17 +881,21 @@ public class PageController {
Place placeById = placeService.findPlaceById(id);
// 用于二维码存放数据
Map<String,Object> param = new HashMap<>();
param.put("id",placeById.getId());
param.put("pid",placeById.getId());
Depository depositoryRecordById = depositoryService.findDepositoryRecordById(placeById.getDid());
param.put("dname",depositoryRecordById.getDname());
param.put("code",depositoryRecordById.getCode() +"-"+placeById.getCode());
param.put("code",placeById.getCode());
param.put("depositoryId",depositoryRecordById.getId());
List<MaterialAndPlace> placeAndMaterialByPid = placeService.findPlaceAndMaterialByPid(placeById.getId());
StringBuilder mname = new StringBuilder();
StringBuilder midList = new StringBuilder();
for (int i = 0; i < placeAndMaterialByPid.size(); i++) {
Material materialById = materialService.findMaterialById(placeAndMaterialByPid.get(i).getMid());
mname.append(materialById.getMname()).append(", ");
midList.append(materialById.getId()).append(",");
}
param.put("mname",mname);
param.put("midList",midList);
String context = JSONObject.toJSONString(param);
String qrCode = "";
try {
@ -1013,7 +1032,7 @@ public class PageController {
UserByPort userByPort = FindUserById(recordP.getApplicantId());
// 部门负责人
UserByPort departmenthead = FindUserById(recordP.getDepartmenthead());
// 仓库管理员
// 仓储中心负责人
String manager = recordP.getDepositoryManager();
String[] depositoryManagerId = new String[0];
if(manager != null){
@ -1027,8 +1046,10 @@ public class PageController {
depositoryManager.add(user);
depositoryManagerNames += user.getName() +",";
}
if(recordP.getPlaceId() != null) {
Place placeById = placeService.findPlaceById(recordP.getPlaceId());
recordP.setPCode(placeById.getCode());
}
recordP.setApplicantTime(DateUtil.TimeStampToDateTime(Long.valueOf(recordP.getApplicantTime())));
recordP.setDepartmentheadTime(DateUtil.TimeStampToDateTime(Long.valueOf(recordP.getDepartmentheadTime())));
recordP.setDepositoryManagerName(depositoryManagerNames);
@ -1062,7 +1083,11 @@ public class PageController {
ModelAndView mv = new ModelAndView();
mv.setViewName("pages/application/form-step-look_back");
if (id != null) {
// 获取出库主单
ApplicationOutRecordP applicationOutRecordPById = depositoryRecordService.findApplicationOutRecordPById(id);
// 获取出库子单
List<ApplicationOutRecordMin> applicationOutRecordMinByParent = depositoryRecordService.findApplicationOutRecordMinByParent(applicationOutRecordPById.getId());
// 申请人
UserByPort userByPort = FindUserById(applicationOutRecordPById.getApplicantId());
// 部门负责人
@ -1088,8 +1113,10 @@ public class PageController {
applicationOutRecordPById.setDepartmentheadTime(DateUtil.TimeStampToDateTime(Long.valueOf(applicationOutRecordPById.getDepartmentheadTime())));
applicationOutRecordPById.setDepositoryManagerTime(DateUtil.TimeStampToDateTime(Long.valueOf(applicationOutRecordPById.getDepositoryManagerTime())));
applicationOutRecordPById.setPrice(applicationOutRecordPById.getPrice() / 100);
if(applicationOutRecordPById.getPlaceId()!=null) {
Place placeById = placeService.findPlaceById(applicationOutRecordPById.getPlaceId());
applicationOutRecordPById.setPCode(placeById.getCode());
}
mv.addObject("record", applicationOutRecordPById);
} else {
throw new MyException("缺少必要参数!");
@ -1403,7 +1430,56 @@ public class PageController {
@GetMapping("/scanQrCode")
public String scanQrCode(){
return "pages/uniApp/scanQrCodePlus?callback='/index'";
return "pages/scanQrCode/ScanQrCode";
}
// 获取扫描结果并跳转到入库
@GetMapping("/application_in_scanQrCode")
public ModelAndView applicationInScanQrCode(HttpServletRequest request){
ModelAndView mv = new ModelAndView();
UserByPort userByPort = (UserByPort) request.getAttribute("userToken");
String scanQrCodeValue = redisTemplate.opsForValue().get("scanQrCodeValue"+userByPort.getNumber()).toString();
redisTemplate.delete("scanQrCodeValue"+userByPort.getNumber());
JSONObject jsonObject = JSONObject.parseObject(scanQrCodeValue);
JSONObject depository = (JSONObject) jsonObject.get("depository");
JSONObject place = (JSONObject) jsonObject.get("place");
JSONArray materialList = (JSONArray) jsonObject.get("materialList");
if(depository == null && place == null){
// 如果库位与仓库都未选中
}else if(depository != null && place == null){
// 如果选中仓库未选中库位
mv.addObject("depository",depository);
}else if(place != null && depository == null){
// 如果选中库位未选中仓库
mv.addObject("place",place);
}
mv.addObject("materialList",materialList);
mv.setViewName("pages/application/application-in_scanQrCode");
return mv;
}
// 获取扫描结果并跳转到出库
@GetMapping("/application_Out_scanQrCode")
public ModelAndView applicationOutScanQrCode(HttpServletRequest request){
ModelAndView mv = new ModelAndView();
UserByPort userByPort = (UserByPort) request.getAttribute("userToken");
String scanQrCodeValue = redisTemplate.opsForValue().get("scanQrCodeValue"+userByPort.getNumber()).toString();
redisTemplate.delete("scanQrCodeValue"+userByPort.getNumber());
JSONObject jsonObject = JSONObject.parseObject(scanQrCodeValue);
JSONObject depository = (JSONObject) jsonObject.get("depository");
JSONObject place = (JSONObject) jsonObject.get("place");
JSONArray materialList = (JSONArray) jsonObject.get("materialList");
if(depository == null && place == null){
// 如果库位与仓库都未选中
}else if(depository != null && place == null){
// 如果选中仓库未选中库位
mv.addObject("depository",depository);
}else if(place != null && depository == null){
// 如果选中库位未选中仓库
mv.addObject("place",place);
}
mv.addObject("materialList",materialList);
mv.setViewName("pages/application/application-out_scanQrCode");
return mv;
}
}

27
src/main/java/com/dreamchaser/depository_manage/controller/PlaceController.java

@ -216,6 +216,7 @@ public class PlaceController {
return CrudUtil.postHandle(placeService.UpdatePlace(update),1);
}
// 根据物料编号获取库位
@PostMapping("/findPlaceByMid")
public RestResponse findPlaceByMid(@RequestBody Map<String,Object> map, HttpServletRequest request){
UserByPort userToken= (UserByPort) request.getAttribute("userToken");
@ -225,7 +226,31 @@ public class PlaceController {
for (int i = 0; i < depositoryByAdminorg.size(); i++) {
Depository depository = depositoryByAdminorg.get(i);
List<PlaceP> placeByMidAndDid = placeService.findPlaceByMidAndDid(mid, depository.getId());
placeList.addAll(placeByMidAndDid);
for (int j = 0; j < placeByMidAndDid.size(); j++) {
int index = placeList.indexOf(placeByMidAndDid.get(j));
if(index == -1){
placeList.add(placeByMidAndDid.get(j));
}
}
}
return new RestResponse(placeList);
}
// 根据物料编码以及仓库编号获取具体库位
@PostMapping("/findPlaceByMcodeAndDid")
public RestResponse findPlaceByMcodeAndDid(@RequestBody Map<String,Object> map,HttpServletRequest request){
List<MaterialP> inventory = materialService.findInventory(map);
List<PlaceP> placeList = new ArrayList<>();
if(inventory.size() > 0){ // 如果有当前物料
for (int i = 0; i < inventory.size(); i++) {
MaterialP materialP = inventory.get(i);
List<PlaceP> placeByMidAndDid = placeService.findPlaceByMidAndDid(materialP.getId(), ObjectFormatUtil.toInteger(map.get("depositoryId")));
for (int j = 0; j < placeByMidAndDid.size(); j++) {
int index = placeList.indexOf(placeByMidAndDid.get(j));
if(index == -1){
placeList.add(placeByMidAndDid.get(j));
}
}
}
}
return new RestResponse(placeList);
}

7
src/main/java/com/dreamchaser/depository_manage/entity/ApplicationOutRecord.java

@ -110,4 +110,11 @@ public class ApplicationOutRecord {
*/
private Integer placeId;
/**
* 订单状态
*/
private Integer pass;
}

43
src/main/java/com/dreamchaser/depository_manage/entity/ApplicationOutRecordMin.java

@ -1,4 +1,47 @@
package com.dreamchaser.depository_manage.entity;
import lombok.Data;
/**
* 出库子订单
*/
@Data
public class ApplicationOutRecordMin {
/**
* id
*/
private Integer id;
/**
* 物料id
*/
private Integer mid;
/**
* 仓库id
*/
private Integer depositoryId;
/**
* 对应库位id
*/
private Integer placeId;
/**
* 数量
*/
private Integer quantity;
/**
* 出库单号
*/
private String code;
/**
* 审核人编号
*/
private Integer checkId;
/**
* 主订单编号
*/
private Integer parentId;
}

7
src/main/java/com/dreamchaser/depository_manage/mapper/DepositoryMapper.java

@ -149,4 +149,11 @@ public interface DepositoryMapper {
* @return
*/
List<Depository> findDepositoryByAdminorgAndParent(Map<String,Object> map);
/**
* 根据仓库编码获取仓库
* @param depositoryCode
* @return
*/
Depository findDepositoryByCode(String depositoryCode);
}

10
src/main/java/com/dreamchaser/depository_manage/mapper/DepositoryMapper.xml

@ -64,6 +64,16 @@
or d.adminorg = ''
</select>
<!-- 根据仓库编码获取仓库-->
<select id="findDepositoryByCode" resultMap="depositoryMap" parameterType="string">
SELECT
<include refid="allColumns" />
FROM depository d WHERE 1 = 1 and d.state != 3
<if test="depositoryCode != null and depositoryCode !=''">
and d.code = #{depositoryCode}
</if>
</select>
<select id="findDepositoryByAdminorgAndParent" resultMap="depositoryMap" parameterType="map">
SELECT
<include refid="allColumns" />

21
src/main/java/com/dreamchaser/depository_manage/mapper/DepositoryRecordMapper.java

@ -285,4 +285,25 @@ public interface DepositoryRecordMapper {
ApplicationOutRecord findApplicationOutByCode(String code);
/**
* 插入一条出库子订单
* @param map
* @return
*/
Integer insertApplicationOutRecordMin(Map<String,Object> map);
/**
* 根据id获取出库子订单
* @param id
* @return
*/
ApplicationOutRecordMin findApplicationOutMinById(Integer id);
/**
* 根据主表获取所有子表
* @param parentId
* @return
*/
List<ApplicationOutRecordMin> findApplicationOutRecordMinByParent(Integer parentId);
}

52
src/main/java/com/dreamchaser/depository_manage/mapper/DepositoryRecordMapper.xml

@ -90,9 +90,23 @@
<result column="transferId" property="transferId" jdbcType="INTEGER" />
<result column="mcode" property="mcode" jdbcType="VARCHAR" />
<result column="placeId" property="placeId" jdbcType="INTEGER" />
<result column="pass" property="pass" jdbcType="INTEGER" />
</resultMap>
<!-- 出库子订单-->
<resultMap id="applicationOutRecordMin" type="com.dreamchaser.depository_manage.entity.ApplicationOutRecordMin">
<id property="id" column="aorid" jdbcType="INTEGER"/>
<result column="mid" property="mid" jdbcType="INTEGER" />
<result column="depositoryId" property="depositoryId" jdbcType="INTEGER" />
<result column="placeId" property="placeId" jdbcType="INTEGER" />
<result column="quantity" property="quantity" jdbcType="INTEGER" />
<result column="checkId" property="checkId" jdbcType="INTEGER" />
<result column="parentId" property="parentId" jdbcType="INTEGER" />
<result column="code" property="code" jdbcType="VARCHAR" />
</resultMap>
<!-- 表查询字段 -->
<sql id="simpleColumns">
dr.id, dr.type, dr.applicant_id, dr.apply_remark, dr.apply_time ,dr.oldId
@ -124,7 +138,11 @@
<sql id="ApplicationOutRecordInfo">
aorid,mid,mname,depositoryId,dname,applicantId,applicantTime,applyRemark,aorcode,aorpirce,aorquantity,departmenthead,departmentheadPass,departmentHeadTime,departmentheadMessage,
depositoryManager,depositoryManagerPass,depositoryManagerTime,depositoryManagerMessage,aorstate,istransfer,transferId,mcode,placeId
depositoryManager,depositoryManagerPass,depositoryManagerTime,depositoryManagerMessage,aorstate,istransfer,transferId,mcode,placeId,pass
</sql>
<sql id="ApplicationOutRecordMinInfo">
aorm.id,aorm.mid,aorm.depositoryId,aorm.placeId,aorm.quantity,aorm.code,aorm.checkId,aorm.parentId
</sql>
<!-- 查询所有数据行数 -->
<select id="findCount" resultType="integer">
@ -630,6 +648,38 @@
)
</insert>
<!-- 插入一条出库子订单-->
<insert id="insertApplicationOutRecordMin" parameterType="map" useGeneratedKeys="true" keyProperty="id">
insert into application_out_record_min (id,mid,quantity,code,depositoryId,placeId,checkId,parentId)
values(
#{id},
#{mid},
#{quantity},
#{code},
#{depositoryId},
#{placeId},
#{checkId},
#{parentId}
)
</insert>
<!-- 查找子订单-->
<select id="findApplicationOutMinById" parameterType="int" resultMap="applicationOutRecordMin">
select
<include refid="ApplicationOutRecordMinInfo" />
from application_out_record_min as aorm
where 1 = 1
and aorm.id = #{id}
</select>
<select id="findApplicationOutRecordMinByParent" parameterType="int" resultMap="applicationOutRecordMin">
select
<include refid="ApplicationOutRecordMinInfo" />
from application_out_record_min as aorm
where 1 = 1
and aorm.parentId = #{parentId}
</select>
<!-- 插入数据 -->
<insert id="insertDepositoryRecord" parameterType="map" useGeneratedKeys="true" keyProperty="id">

2
src/main/java/com/dreamchaser/depository_manage/mapper/MaterialMapper.xml

@ -350,7 +350,7 @@
<if test="depositoryCode != null and depositoryCode !=''">
depositoryCode = #{depositoryCode},
</if>
<if test="numberOfTemporary != null and numberOfTemporary != ''">
<if test="numberOfTemporary != null">
number_of_temporary = #{numberOfTemporary},
</if>
<if test="texture != null and texture != ''">

5
src/main/java/com/dreamchaser/depository_manage/pojo/ApplicationOutRecordP.java

@ -143,4 +143,9 @@ public class ApplicationOutRecordP {
* 对应库位编码
*/
private String pCode;
/**
* 订单状态
*/
private Integer pass;
}

3
src/main/java/com/dreamchaser/depository_manage/pojo/MaterialP.java

@ -127,4 +127,7 @@ public class MaterialP {
this.depositoryId = material.getDepositoryId(); // 仓库id
this.placeCode = material.getPlaceCode(); // 库位编码
}
public MaterialP() {
}
}

24
src/main/java/com/dreamchaser/depository_manage/service/DepositoryRecordService.java

@ -1,8 +1,6 @@
package com.dreamchaser.depository_manage.service;
import com.dreamchaser.depository_manage.entity.ApplicationInRecord;
import com.dreamchaser.depository_manage.entity.ApplicationOutRecord;
import com.dreamchaser.depository_manage.entity.DepositoryRecord;
import com.dreamchaser.depository_manage.entity.*;
import com.dreamchaser.depository_manage.pojo.*;
import java.util.List;
@ -32,7 +30,7 @@ public interface DepositoryRecordService {
* @param map 仓库调度信息
* @return 受影响的行数
*/
Integer transferApply(Map<String,Object> map);
Integer transferApply(Map<String,Object> map,UserByPort userByPort);
/**
@ -256,7 +254,7 @@ public interface DepositoryRecordService {
* @param map
* @return
*/
Integer insertApplicationOutRecord(Map<String,Object> map);
Integer insertApplicationOutRecord(Map<String,Object> map, UserByPort userToken);
/**
@ -299,4 +297,20 @@ public interface DepositoryRecordService {
* @return
*/
Integer deleteApplicaionInPlace(Map<String,Object> map);
/**
* 插入一条出库子订单
* @param map
* @return
*/
Integer insertApplicationOutMin(Map<String,Object> map);
/**
* 根据主表获取所有子表
* @param id
* @return
*/
List<ApplicationOutRecordMin> findApplicationOutRecordMinByParent(Integer id);
}

7
src/main/java/com/dreamchaser/depository_manage/service/DepositoryService.java

@ -147,4 +147,11 @@ public interface DepositoryService {
*/
List<Depository> findDepositoryByAdminorg(String adminorg);
/**
* 根据仓库编码获取仓库
* @param code
* @return
*/
Depository findDepositoryByCode(String code);
}

3
src/main/java/com/dreamchaser/depository_manage/service/PlaceService.java

@ -109,4 +109,7 @@ public interface PlaceService {
*/
Integer addMaterialOnPlace(Map<String,Object> map);
}

87
src/main/java/com/dreamchaser/depository_manage/service/impl/DepositoryRecordServiceImpl.java

@ -96,7 +96,7 @@ public class DepositoryRecordServiceImpl implements DepositoryRecordService {
temp.put("dcode", depositoryRecordById.getCode());
// 获取当前仓库库存
Double Inventory = depositoryMapper.getToDayInventoryByDName(temp);
String code = createCode(depositoryRecordById.getDname(), "InOrderNumber");//构造单号
String code = createCode(depositoryRecordById.getDname(), "InOrderNumber","in","");//构造单号
Double quantity = Double.parseDouble((String) map.get("quantity"));
Double price = Double.parseDouble((String) map.get("price"));
Integer mid = ObjectFormatUtil.toInteger(map.get("mid"));
@ -123,6 +123,7 @@ public class DepositoryRecordServiceImpl implements DepositoryRecordService {
if (materialByCondition.size() > 0) { // 如果当前存在
Material mt = materialByCondition.get(0);
map.put("oldPrice",mt.getPrice());
map.put("mid",mt.getId());
mt.setAmounts(mt.getAmounts() + amounts);
mt.setQuantity((int) (mt.getQuantity() + quantity));
mt.setPrice(avgPrice);
@ -146,6 +147,8 @@ public class DepositoryRecordServiceImpl implements DepositoryRecordService {
return depositoryRecordMapper.insertApplicationInRecord(map);
}
/**
* 插入一条出库记录
*
@ -153,9 +156,9 @@ public class DepositoryRecordServiceImpl implements DepositoryRecordService {
* @return
*/
@Override
public Integer insertApplicationOutRecord(Map<String, Object> map) {
public Integer insertApplicationOutRecord(Map<String, Object> map,UserByPort userToken) {
String placeId = (String) map.get("placeId");
if("".equals(placeId)){
if("".equals(placeId) || "0".equals(placeId)){
map.put("placeId",0);
}
Double quantity = Double.parseDouble((String) map.get("quantity"));
@ -166,8 +169,6 @@ public class DepositoryRecordServiceImpl implements DepositoryRecordService {
Material materialById = materialMapper.findMaterialById(mid);
int amounts = (int) ((materialById.getPrice() / 100) * quantity * 100);
map.put("price", amounts);
String simpleTime = DateUtil.getSimpleTime(new Date());
map.put("depositoryId", materialById.getDepositoryId());
map.put("state", "待部门负责人审核");
map.put("istransfer", 2);
Map<String, Object> update = new HashMap<>();
@ -179,7 +180,8 @@ public class DepositoryRecordServiceImpl implements DepositoryRecordService {
update.put("numberOfTemporary", numberOfTemporary + quantity);
materialMapper.updateMaterial(update);
Depository depositoryRecordById = depositoryMapper.findDepositoryRecordById(materialById.getDepositoryId());
String code = createCode(depositoryRecordById.getDname(), "outOrderNumber");
Administration company = PageController.getCompany(userToken.getMaindeparment());
String code = createCode(depositoryRecordById.getDname(), "outOrderNumber","out",company.getName());
map.put("code", code);
return depositoryRecordMapper.insertApplicationOutRecord(map);
}
@ -339,6 +341,26 @@ public class DepositoryRecordServiceImpl implements DepositoryRecordService {
}
/**
* 插入一条出库子订单
* @param map
* @return
*/
@Override
public Integer insertApplicationOutMin(Map<String, Object> map) {
return depositoryRecordMapper.insertApplicationOutRecordMin(map);
}
/**
* 根据主表获取所有子表
* @param id
* @return
*/
@Override
public List<ApplicationOutRecordMin> findApplicationOutRecordMinByParent(Integer id) {
return depositoryRecordMapper.findApplicationOutRecordMinByParent(id);
}
/**
* 转移申请
*
@ -347,7 +369,7 @@ public class DepositoryRecordServiceImpl implements DepositoryRecordService {
*/
@Override
@Transactional
public Integer transferApply(Map<String, Object> map) {
public Integer transferApply(Map<String, Object> map,UserByPort userByPort) {
Integer mid = ObjectFormatUtil.toInteger(map.get("mid"));
Double quantity = Double.parseDouble((String) map.get("quantity"));
Material material = materialMapper.findMaterialById(mid);
@ -374,7 +396,8 @@ public class DepositoryRecordServiceImpl implements DepositoryRecordService {
TransferRecord transferRecordByCondition = transferRecordMapper.findTransferRecordByCondition(map).get(0);
map.put("transferId", transferRecordByCondition.getId());
Depository depositoryRecordById = depositoryMapper.findDepositoryRecordById(material.getDepositoryId());
map.put("code", createCode(depositoryRecordById.getDname(), "outOrderNumber"));
Administration company = PageController.getCompany(userByPort.getMaindeparment());
map.put("code", createCode(depositoryRecordById.getDname(), "outOrderNumber","out",company.getName()));
String placeId = (String) map.get("placeId");
if("".equals(placeId)){
map.put("placeId",0);
@ -393,7 +416,7 @@ public class DepositoryRecordServiceImpl implements DepositoryRecordService {
@Transactional
public Integer review(Map<String, Object> map, Integer userid) {
ApplicationOutRecordP record = depositoryRecordMapper.findApplicationOutRecordPById(ObjectFormatUtil.toInteger(map.get("id")));
Object id = map.get("id");
Object id = map.get("id"); // 主订单编号
map.remove("id");
if (map.containsKey("departmentheadPass")) {
String simpleTime = DateUtil.getSimpleTime(new Date());
@ -401,14 +424,16 @@ public class DepositoryRecordServiceImpl implements DepositoryRecordService {
map.put("departmenthead", userid);
Integer departmentheadPass = (Integer) map.get("departmentheadPass");
if (departmentheadPass == 1) {
map.put("state", "待仓库管理员审核");
String depositoryManager = "";
List<Integer> userIdByDidList = roleService.findUserIdByDid(record.getDepositoryId());
for (int i = 0; i < userIdByDidList.size(); i++) {
UserByPort userByPort = PageController.FindUserById(userIdByDidList.get(i));
depositoryManager += userByPort.getId().toString() + ",";
}
map.put("depositoryManager", depositoryManager);
map.put("state", "待仓储中心负责人审核");
// 获取仓储中心详情
Administration company = PageController.getCompany(361);
// 获取仓储中心负责人
List<UserByPort> departmentHeadByUser = PortConfig.findDepartmentHeadByUser(company);
StringBuilder depositoryManager = new StringBuilder();
for (int i = 0; i < departmentHeadByUser.size(); i++) {
depositoryManager.append(departmentHeadByUser.get(i).getId() + ",");
}
map.put("depositoryManager", depositoryManager.toString());
} else {
map.put("state", "部门负责人审核未通过");
}
@ -418,11 +443,16 @@ public class DepositoryRecordServiceImpl implements DepositoryRecordService {
map.put("depositoryManagerTime", DateUtil.DateTimeToTimeStamp(simpleTime));
map.put("depositoryManager", userid);
map.put("depositoryId", record.getDepositoryId());
map.put("mid", record.getMid());
Material material = materialMapper.findMaterialById(record.getMid());
// 获取主单下的子单
List<ApplicationOutRecordMin> applicationOutRecordMinByParent = depositoryRecordMapper.findApplicationOutRecordMinByParent(record.getId());
for (int i = 0; i < applicationOutRecordMinByParent.size(); i++) {
}
// map.put("mid", record.getMid());
// Material material = materialMapper.findMaterialById(record.getMid());
Integer depositoryManagerPass = (Integer) map.get("depositoryManagerPass");
if (depositoryManagerPass == 1) {
boolean flag = true;
/*boolean flag = true;
Integer istransfer = record.getIstransfer();
Integer placeId = record.getPlaceId();
if(istransfer == 1){
@ -480,15 +510,16 @@ public class DepositoryRecordServiceImpl implements DepositoryRecordService {
map.put("state", "未出库");
map.put("depositoryManagerMessage", "当前仓位库存量不足");
Map<String, Object> update = new HashMap<>();
update.put("id", material.getId());
// update.put("id", material.getId());
update.put("numberOfTemporary", 0);
materialMapper.updateMaterial(update);
depositoryRecordMapper.updateApplicationOutRecord(map);
return -1;
}
map.put("state", "已出库");
*/
map.put("state", "出库中");
} else {
map.put("state", "仓库管理员审核未通过");
map.put("state", "仓储中心负责人审核未通过");
}
}
map.put("id",id);
@ -1163,9 +1194,9 @@ public class DepositoryRecordServiceImpl implements DepositoryRecordService {
* @param depositoryName
* @return
*/
private String createCode(String depositoryName, String key) {
private String createCode(String depositoryName, String key,String type,String mainDeparmentName) {
RLock lock = redissonClient.getLock(key);
// 单号(公司简称+仓库简称+年月日+数字(位数设置>=9))
// 入库单号(公司简称+仓库简称+年月日+数字(位数设置>=9))
String code = "GK";
String nowTime = DateUtil.getNowTime();
depositoryName = WordUtil.getPinYinHeadChar(depositoryName);
@ -1179,7 +1210,13 @@ public class DepositoryRecordServiceImpl implements DepositoryRecordService {
redisTemplate.boundValueOps(key).set(String.valueOf(newNumber), DateUtil.getSecondsNextEarlyMorning(), TimeUnit.SECONDS);
lock.unlock();
orderNumber = String.format("%09d", ObjectFormatUtil.toInteger(orderNumber));
if("in".equals(type)){
code = code + depositoryName + nowTime + orderNumber;
}
else if("out".equals(type)){
mainDeparmentName = WordUtil.getPinYinHeadChar(mainDeparmentName);
code = code + mainDeparmentName + nowTime + orderNumber;
}
return code;
}

10
src/main/java/com/dreamchaser/depository_manage/service/impl/DepositoryServiceImpl.java

@ -370,6 +370,16 @@ public class DepositoryServiceImpl implements DepositoryService {
return depositoryByAdminorg;
}
/**
* 根据仓库编码获取仓库
* @param code
* @return
*/
@Override
public Depository findDepositoryByCode(String code) {
return depositoryMapper.findDepositoryByCode(code);
}
//判断是否有子类
public boolean isChildForDepository(Integer parentId){
boolean flag = false;

2
src/main/resources/static/js/VueQrcodeReader.umd.min.js

File diff suppressed because one or more lines are too long

15
src/main/resources/static/js/ZXing.js

File diff suppressed because one or more lines are too long

10100
src/main/resources/static/js/jsQR.js

File diff suppressed because it is too large

12551
src/main/resources/static/js/library.min.js

File diff suppressed because one or more lines are too long

5
src/main/resources/static/js/respond.min.js

@ -0,0 +1,5 @@
/*! Respond.js v1.4.2: min/max-width media query polyfill * Copyright 2013 Scott Jehl
* Licensed under https://github.com/scottjehl/Respond/blob/master/LICENSE-MIT
* */
!function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='&shy;<style media="'+a+'"> #mq-test-1 { width: 42px; }</style>',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){u(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))};if(c.ajax=f,c.queue=d,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,maxw:/\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var g,h,i,j=a.document,k=j.documentElement,l=[],m=[],n=[],o={},p=30,q=j.getElementsByTagName("head")[0]||k,r=j.getElementsByTagName("base")[0],s=q.getElementsByTagName("link"),t=function(){var a,b=j.createElement("div"),c=j.body,d=k.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=j.createElement("body"),c.style.background="none"),k.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&k.insertBefore(c,k.firstChild),a=b.offsetWidth,f?k.removeChild(c):c.removeChild(b),k.style.fontSize=d,e&&(c.style.fontSize=e),a=i=parseFloat(a)},u=function(b){var c="clientWidth",d=k[c],e="CSS1Compat"===j.compatMode&&d||j.body[c]||d,f={},o=s[s.length-1],r=(new Date).getTime();if(b&&g&&p>r-g)return a.clearTimeout(h),h=a.setTimeout(u,p),void 0;g=r;for(var v in l)if(l.hasOwnProperty(v)){var w=l[v],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?i||t():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?i||t():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(m[w.rules]))}for(var C in n)n.hasOwnProperty(C)&&n[C]&&n[C].parentNode===q&&q.removeChild(n[C]);n.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=j.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,q.insertBefore(E,o.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(j.createTextNode(F)),n.push(E)}},v=function(a,b,d){var e=a.replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var g=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},h=!f&&d;b.length&&(b+="/"),h&&(f=1);for(var i=0;f>i;i++){var j,k,n,o;h?(j=d,m.push(g(a))):(j=e[i].match(c.regex.findStyles)&&RegExp.$1,m.push(RegExp.$2&&g(RegExp.$2))),n=j.split(","),o=n.length;for(var p=0;o>p;p++)k=n[p],l.push({media:k.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:m.length-1,hasquery:k.indexOf("(")>-1,minw:k.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:k.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},w=function(){if(d.length){var b=d.shift();f(b.href,function(c){v(c,b.href,b.media),o[b.href]=!0,a.setTimeout(function(){w()},0)})}},x=function(){for(var b=0;b<s.length;b++){var c=s[b],e=c.href,f=c.media,g=c.rel&&"stylesheet"===c.rel.toLowerCase();e&&g&&!o[e]&&(c.styleSheet&&c.styleSheet.rawCssText?(v(c.styleSheet.rawCssText,e,f),o[e]=!0):(!/^([a-zA-Z:]*\/\/)/.test(e)&&!r||e.replace(RegExp.$1,"").split("/")[0]===a.location.host)&&("//"===e.substring(0,2)&&(e=a.location.protocol+e),d.push({href:e,media:f})))}w()};x(),c.update=x,c.getEmValue=t,a.addEventListener?a.addEventListener("resize",b,!1):a.attachEvent&&a.attachEvent("onresize",b)}}(this);

2
src/main/resources/static/js/vue/common/permission.js

@ -1,6 +1,6 @@
/// null = 未请求,1 = 已允许,0 = 拒绝|受限, 2 = 系统未开启
var isIOS
var isIOS;
function album() {
var result = 0;

25
src/main/resources/static/js/vue/router.js

@ -0,0 +1,25 @@
const Home = httpVueLoader('static/vuePage/index.vue');
var Header = httpVueLoader('static/vuePage/scanCode.vue');
Vue.component('my-header', Header);
const Foo = {
template: '<div>foo</div>'
};
const Bar = {
template: '<div>bar</div>'
};
const routes = [{
path: '/',
component: Home,
children: [{
path: '/foo',
component: Foo
},
{
path: '/bar',
component: Bar
},
]
}, ];
const router = new VueRouter({
routes // (缩写) 相当于 routes: routes
})

3146
src/main/resources/static/js/vue/vue-router.js

File diff suppressed because it is too large

6
src/main/resources/static/js/vue/vue-router.min.js

File diff suppressed because one or more lines are too long

307
src/main/resources/static/vuePage/index.vue

@ -0,0 +1,307 @@
<template>
<div class="test">
<div class="fixBox">
<div class="iconBox"
@click="() => {
this.$router.history.go(-1);
}">
<i class="iconfont icon-fanhuitubiao"></i>
</div>
<div class="videoBox">
<div class="outVideo" v-if="isAnimation">
<video
autoPlay
ref="outVideo"
webkit-playsinline
x5-video-player-type="h5"
x5-video-player-fullscreen="true"
x-webkit-airplay="true"
playsinline
v-if="!trueFlag"
id="myVideo"
></video>
</div>
<div class="codebg" v-if="!trueFlag">
<div class="line"></div>
</div>
<canvas
id="qr-canvas"
style="width:6rem;height:6rem;"
ref="canvas"
></canvas>
</div>
</div>
</div>
</template>
<script>
import jsQR from "jsqr";
export default {
data() {
return {
photoBase: "",
trueFlag: false,
isAnimation: true
};
},
mounted() {
this.outvideo = this.$refs.outVideo;
this.cvsele = this.$refs.canvas;
this.canvas = this.cvsele.getContext("2d");
this.video = document.createElement("video");
this.$nextTick(() => {
this.getVideo();
});
},
methods: {
getVideo() {
let self = this;
try {
navigator.getUserMedia =
navigator.mediaDevices.getUserMedia ||
navigator.mediaDevices.webkitGetUserMedia ||
navigator.mediaDevices.mozGetUserMedia;
self.URL =
window.URL || window.webkitURL || window.mozURL || window.msURL;
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
//console.log(navigator.mediaDevices.getUserMedia);
navigator.mediaDevices
.getUserMedia({
video: {facingMode: {exact: "environment"}}
// video: { facingMode: "environment" }
})
.then(stream => {
this.outvideo.srcObject = stream;
this.video.srcObject = stream;
this.video.setAttribute("playsinline", true);
this.video.setAttribute("webkit-playsinline", true);
this.video.addEventListener("loadedmetadata", () => {
this.$refs.outVideo.play();
this.video.play();
this.sweep();
});
setTimeout(() => {
this.$refs.outVideo.play();
this.video.play();
}, 150);
})
.catch(function (err) {
console.log(err);
alert("请允许网站使用您的摄像头权限");
self.$router.history.go(-1);
});
} else if (navigator.getUserMedia) {
navigator
.getUserMedia({
video: true
})
.then(stream => {
this.outvideo.srcObject = stream;
this.video.srcObject = stream;
this.video.setAttribute("playsinline", true);
this.video.setAttribute("webkit-playsinline", true);
this.video.addEventListener("loadedmetadata", () => {
this.$refs.outVideo.play();
this.video.play();
this.sweep();
});
setTimeout(() => {
this.$refs.outVideo.play();
this.video.play();
}, 150);
})
.catch(function (err) {
alert(err);
});
}
} catch (err) {
console.error(err);
}
},
sweep() {
if (this.video.readyState === this.video.HAVE_ENOUGH_DATA) {
const {videoWidth, videoHeight} = this.video;
this.cvsele.width = videoWidth;
this.cvsele.height = videoHeight;
this.canvas.drawImage(this.video, 0, 0, videoWidth, videoHeight);
try {
const img = this.canvas.getImageData(0, 0, videoWidth, videoHeight);
this.imgurl = img;
const obj = jsQR(img.data, img.width, img.height, {
inversionAttempts: "dontInvert"
});
console.log(obj);
if (obj) {
const loc = obj.location;
this.draw(loc.topLeftCorner, loc.topRightCorner);
this.draw(loc.topRightCorner, loc.bottomRightCorner);
this.draw(loc.bottomRightCorner, loc.bottomLeftCorner);
this.draw(loc.bottomLeftCorner, loc.topLeftCorner);
if (obj.data) {
console.info("识别结果:", obj.data);
this.isAnimation = false;
}
} else {
// console.error("");
}
} catch (err) {
// console.error("", err);
}
}
if (this.isAnimation) {
this.timer = requestAnimationFrame(() => {
this.sweep();
});
}
},
draw(begin, end) {
this.canvas.beginPath();
this.canvas.moveTo(begin.x, begin.y);
this.canvas.lineTo(end.x, end.y);
this.canvas.lineWidth = 3;
this.canvas.strokeStyle = "red";
this.canvas.stroke();
},
},
};
</script>
<style lang="scss" scoped>
.test {
width: 100vw;
height: 100vh;
overflow: hidden;
}
.biginSearch {
outline: none;
border: none;
width: 3.15rem;
height: 0.8rem;
background: var(--themeColorzc);
border-radius: 0.1rem;
color: #fff;
font-weight: 700;
margin-top: 0.3rem;
font-size: 0.3rem;
}
.fixBox {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
// background: rgba(47, 47, 47, 0.81);
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.videoBox {
// border: 2px solid rgba(247, 241, 241, 0.81);
// width: 6rem;
// height: 6rem;
// overflow: hidden;
width: 100%;
height: 100%;
position: relative;
background-color: black;
.outVideo {
width: 100vw;
height: 100vh;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
z-index: 999;
background-color: black;
video {
width: 100%;
height: 100%;
object-fit: fill;
}
}
}
canvas {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.codebg {
position: absolute;
width: 6rem;
height: 6rem;
margin: 0px auto;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
z-index: 999;
/*此处为了居中*/
// background: url(img/ewm1.jpg) center top no-repeat;
/*二维码*/
}
.line {
position: absolute;
left: 0px;
z-index: 2;
height: 3px;
width: 6rem;
/* background: url(img/share/dapai.png) no-repeat; */
/*上下扫的线*/
background-color: var(--themeColorzc);
opacity: 0.5;
/*动画效果*/
animation: myScan 1s infinite alternate;
-webkit-animation: myScan 1s infinite alternate;
}
@keyframes myScan {
from {
top: 0px;
}
to {
top: 300px;
}
}
@font-face {
font-family: "iconfont"; /* Project id 2570754 */
src: url("//at.alicdn.com/t/font_2570754_w4gqnoegfag.woff2?t=1629957776725") format("woff2"),
url("//at.alicdn.com/t/font_2570754_w4gqnoegfag.woff?t=1629957776725") format("woff"),
url("//at.alicdn.com/t/font_2570754_w4gqnoegfag.ttf?t=1629957776725") format("truetype");
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-fanhuitubiao:before {
font-size: 0.48rem;
color: #fff;
content: "\e65c";
}
.iconBox {
position: absolute;
top: 0.3rem;
left: 0.3rem;
}
</style>

166
src/main/resources/static/vuePage/scanCode.vue

@ -1,144 +1,68 @@
<template>
<view class="content">
<view class="text-area">
<text>{{code}}</text>
<text class="title">{{result}}</text>
</view>
<view v-if="select_view == 'credible_view'" class="open_view">
<button type="primary">受信地址</button>
</view>
<div>
<p class="error">{{ error }}</p><!--错误信息-->
<view v-if="select_view == 'open_view'" class="open_view">
<button type="primary">不受信地址</button>
</view>
</view>
<p class="decode-result">扫描结果: <b>{{ result }}</b></p><!--扫描结果-->
<qrcode-stream @decode="onDecode" @init="onInit" />
</div>
</template>
<script>
import helper from "@/common/helper.js";
export default{
data() {
return {
domain:"www.zunkr.com",
code: '默认的内容',//
result: '',
select_view:"no",
model:"pda",
callbackurl:''
}
},
onLoad:function(option){
var that = this;
if(!option.code){
this.result = "扫码内容为空";
}
if(option.model){
this.model = option.model;
}
this.callbackurl = decodeURIComponent(option.callbackurl);//
const code = decodeURIComponent(option.code);
// code = "https://www.baidu.com?51b6d2c0-1964-11ea-a286-00163e0dfa3d";
this.code = code;
//
switch (typeof(code)){
case 'number':
this.result = code+"number 类型";
break;
case 'string':
this.result = code+"string 类型";
if(helper.IsURL(code)){
//
//cnpm install --save vue-qrcode-reader
//
var domain = helper.AnalysisURL(code)[2]
console.log(domain)
console.log(that.domain)
console.log(that.model)
if(domain === that.domain){
//
if (that.model == 'pda'){
//
var param = code.split("?");
var uuid = param[1];
this.result = domain+"为可控域名\r\nuuid为"+uuid;
if(that.callbackurl){
uni.redirectTo({
url:that.callbackurl+'?item='+uuid
})
}
}else if(that.model == 'browser'){
this.result = domain+"可信域验证通过";
this.select_view = "credible_view"
}
}else{
//
console.log(that.model)
if (that.model == 'pda'){
uni.showToast({
title:"PDA模式权限验证失败"
})
this.result = '模式权限验证失败';
this.select_view = "no"
}else if(that.model == 'browser'){
this.result = domain+"不属于内部域名可以第二webview打开";
this.select_view = "open_view"
}
//
import { QrcodeStream } from 'static/lib/vue-qrcode-reader';
}
export default {
}else{
this.result = code+"外部数据禁止使用";
}
//
name:"scanCode",
components: { QrcodeStream },
break;
case 'boolean':
this.result = code+"boolean 类型";
break;
case 'array':
this.result = code+"array 类型";
break;
default:
this.result = code+"default 类型";
break;
data () {
return {
result: '',//
error: '',//
}
console.log('App Load')
},
onShow: function() {
var that = this;
console.log('App Show')
},
methods:{
back(){
console.log("回去");
uni.navigateBack({
delta:1
})
methods: {
onDecode (result) {
alert(result);
this.result = result
},
open_view(){
console.log(encodeURI(this.code));
uni.navigateTo({
url: "/pages/webviews/openview?url="+ encodeURI(this.code) ,
animationType: 'pop-in',
animationDuration: 200,
success: res => {},
fail: () => {},
complete: () => {}
});
async onInit (promise) {
try {
await promise
} catch (error) {
if (error.name === 'NotAllowedError') {
this.error = "ERROR: 您需要授予相机访问权限"
} else if (error.name === 'NotFoundError') {
this.error = "ERROR: 这个设备上没有摄像头"
} else if (error.name === 'NotSupportedError') {
this.error = "ERROR: 所需的安全上下文(HTTPS、本地主机)"
} else if (error.name === 'NotReadableError') {
this.error = "ERROR: 相机被占用"
} else if (error.name === 'OverconstrainedError') {
this.error = "ERROR: 安装摄像头不合适"
} else if (error.name === 'StreamApiNotSupportedError') {
this.error = "ERROR: 此浏览器不支持流API"
}
}
}
}
}
</script>
<style>
.scan-result {
min-height: 50upx;
line-height: 50upx;
<style scoped>
.error {
font-weight: bold;
color: red;
}
</style>

23
src/main/resources/templates/index.html

@ -21,7 +21,14 @@
<!--[if lt IE 9]>
<script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
<script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<!-- vue相关-->
<script src="../static/js/vue/vue.js"></script>
<script src="../static/js/vue/vue.min.js"></script>
<script src="../static/js/vue/vue-router.js"></script>
<script src="../static/lib/http-vue-loader/src/httpVueLoader.js"></script>
<style id="layuimini-bg-color">
</style>
</head>
@ -136,14 +143,14 @@
<script src="/static/lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
<script src="/static/js/lay-config.js?v=2.0.0" charset="utf-8"></script>
<script>
<script>
layui.use(['jquery', 'layer', 'miniAdmin','miniTongji'], function () {
var $ = layui.jquery,
layer = layui.layer,
miniAdmin = layui.miniAdmin,
miniTongji = layui.miniTongji;
var uid = $("#uid").text()
var uid = $("#uid").text();
var options = {
clearUrl: "/static/api/clear.json", // 缓存清理接口
urlHashLocation: true, // 是否打开hash定位
@ -159,7 +166,17 @@
$("#scan").on("click",function () {
layer.open({
type: 2,
title: '扫码',
skin: 'layui-layer-rim',
maxmin: true,
shadeClose: true, //点击遮罩关闭层
area: ['100%', '100%'],
move : '.layui-layer-title',
fixed:false,
content: '/scanQrCode'
})
});

1
src/main/resources/templates/pages/application/application-in.html

@ -186,7 +186,6 @@
success: function (data) {
layer.close(this.layerIndex);
if (data.status >= 300) {
console.log(data)
var d = data.data;
if(d === ""){
layer.msg(data.statusInfo.detail);

25
src/main/resources/templates/pages/application/application-in_back.html

@ -11,6 +11,21 @@
<link rel="stylesheet" href="/static/js/lay-module/step-lay/step.css" media="all">
</head>
<body>
<style>
.inputdiv{
display:flex;background-color: #fff;height: 38px;line-height: 38px;border: 1px solid rgb(238, 238, 238);
}
.layui-form-label{
padding: 9px 0px;
text-align: left;
}
.layui-input-block{
margin-left: 80px;
}
</style>
<div class="layuimini-container">
<div class="layuimini-main">
<div class="layui-fluid">
@ -23,15 +38,19 @@
<form class="layui-form" style="margin: 0 auto;max-width: 460px;padding-top: 40px;">
<div class="layui-form-item">
<label class="layui-form-label">物料名称:</label>
<div class="layui-input-inline">
<div class="layui-input-block" style="margin: 0px;">
<div class="inputdiv">
<input type="text" th:value="${materialById.getMname()}" placeholder="请选择物料" class="layui-input"
id="openSonByMaterial"
id="openSonByMaterial" style="border-style: none"
lay-verify="required"/>
<i class="layui-icon layui-icon-search" style="display: inline" id="selectMaterial"></i>
</div>
<input type="text" th:value="${materialById.getId()}" name="mid" class="layui-input" id="mid"
style="display: none" lay-verify="required" />
</div>
<i class="layui-icon layui-icon-search" style="display: inline" id="selectMaterial"></i>
</div>
<div class="layui-form-item">
<label class="layui-form-label">物料编码:</label>
<div class="layui-input-block">

634
src/main/resources/templates/pages/application/application-in_scanQrCode.html

@ -0,0 +1,634 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<title>分步表单</title>
<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, maximum-scale=1">
<link rel="stylesheet" href="/static/lib/layui-v2.6.3/css/layui.css" media="all">
<link rel="stylesheet" href="/static/css/public.css" media="all">
<link rel="stylesheet" href="/static/js/lay-module/step-lay/step.css" media="all">
</head>
<body>
<style>
.inputdiv {
display: flex;
background-color: #fff;
height: 38px;
line-height: 38px;
border: 1px solid rgb(238, 238, 238);
}
.layui-form-label {
padding: 9px 0px;
text-align: left;
}
.layui-input-block {
margin-left: 80px;
}
</style>
<div class="layuimini-container">
<div class="layuimini-main">
<div class="layui-fluid">
<!-- 入库申请提交-->
<div class="layui-carousel" id="stepForm" lay-filter="stepForm" style="margin: 0 auto; ">
<input th:value="${materialList}" style="display:none;" id="scanValue_materialList">
<input th:value="${depository}" style="display: none" id="scanValue_depositoryId">
<input th:value="${place}" style="display: none" id="scanValue_placeId">
<div carousel-item style="overflow: inherit">
<div>
<form class="layui-form" style="margin: 0 auto;max-width: 460px;padding-top: 40px;">
<div class="layui-card" id="cardParent">
<!-- 提交按钮-->
<div class="layui-form-item" id="btn_sub">
<div class="layui-input-block" style="bottom: 15px;">
<button id="submitForm" class="layui-btn" lay-submit lay-filter="formStep"
style="margin-left: 15%">
&emsp;提交&emsp;
</button>
</div>
</div>
</div>
</form>
</div>
<!-- 下一步-->
<div>
<form class="layui-form" style="margin: 0 auto;max-width: 460px;padding-top: 40px;">
<div style="text-align: center;margin-top: 90px;">
<i class="layui-icon layui-circle"
style="color: white;font-size:30px;font-weight:bold;background: #52C41A;padding: 20px;line-height: 80px;">&#xe605;</i>
<div style="font-size: 24px;color: #333;font-weight: 500;margin-top: 30px;">
提交成功
</div>
<div style="text-align: center;margin-top: 50px;">
<button class="layui-btn next">再填写一次</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="/static/lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
<script src="/static/js/lay-config.js?v=1.0.4" charset="utf-8"></script>
<script>
// 用于添加标签
function addItem(obj) {
}
// 用于删除标签
function deleteItem(obj) {
}
// 用于编码查询
function selectCode(obj) {
}
// 用于点击搜索按钮
function selectMaterial(obj) {
}
// 用于物料名称查询
function selectMaterialByName(obj) {
}
// 用于加载仓库菜单
function openDepositoryTree(obj) {
}
// 用于页面初始化时的卡片构造
function initForm(num, obj) {
}
// 用于暂存卡片个数
var params = [];
// 用于卡片编号
var NewIdNumber = 0;
layui.use(['form', 'step', 'flow'], function () {
var $ = layui.$,
form = layui.form,
flow = layui.flow,
step = layui.step;
let scanValue = {};
// 页面初始化
$(function () {
let depository = $("#scanValue_depositoryId").val();
let place = $("#scanValue_placeId").val();
let materialList = $("#scanValue_materialList").val();
materialList = JSON.parse(materialList);
if (depository !== undefined && depository !== null && depository !== "") {
// 如果扫描到仓库
depository = JSON.parse(depository);
scanValue.depository = depository;
}
if (place !== undefined && place !== null && place !== "") {
// 如果扫描到库位
place = JSON.parse(place);
scanValue.place = place;
}
if (materialList.length > 0) {
for (let i = 0; i < materialList.length; i++) {
initForm(i, materialList[i]);
}
} else {
var material = {};
material.mname = '';
material.mid = '';
material.code = '';
initForm(0, material);
}
});
//用于页面初始化时的卡片构造
initForm = function (num, obj) {
var parent = $("#cardParent");
// 获取待添加父类
NewIdNumber = num;
if (num === 0) { // 如果是第一个
NewIdNumber = "";
}
var depositoryItem = `
<div class="layui-form-item">
<label class="layui-form-label">仓库:</label>
<div class="layui-input-block">
<input type="text" placeholder="请选择仓库" class="layui-input"
id="openSonByDepository" readonly onclick="openDepositoryTree(this)"
lay-verify="required"/>
<input type="text" name=` + "depositoryId" + NewIdNumber + ` class="layui-input" id="depositoryId"
style="display: none" lay-verify="required"/>
<input type="text" name=` + "placeId" + NewIdNumber + ` class="layui-input" id="placeId" value="0"
style="display: none" lay-verify="required"/>
</div>
</div>
`;
if (scanValue.depository !== undefined && scanValue.depository !== null && scanValue.depository !== "") {
let depository = scanValue.depository;
// 如果扫描了仓库
depositoryItem = `<div class="layui-form-item">
<label class="layui-form-label">仓库:</label>
<div class="layui-input-block">
<input type="text" placeholder="请选择仓库" class="layui-input" value=` + depository.dname + `
id="openSonByDepository" readonly onclick="openDepositoryTree(this)"
lay-verify="required"/>
<input type="text" name=` + "depositoryId" + NewIdNumber + ` class="layui-input" id="depositoryId" value=` + depository.did + `
style="display: none" lay-verify="required"/>
<input type="text" name=` + "placeId" + NewIdNumber + ` class="layui-input" id="placeId" value="0"
style="display: none" lay-verify="required"/>
</div>
</div>`;
}
if (scanValue.place !== undefined && scanValue.place !== null && scanValue.place !== "") {
// 如果扫描了库位
let place = scanValue.place;
depositoryItem = `<div class="layui-form-item">
<label class="layui-form-label">仓库:</label>
<div class="layui-input-block">
<input type="text" placeholder="请选择仓库" class="layui-input"
id="openSonByDepository" readonly onclick="openDepositoryTree(this)" value=` + place.dname + "-" + place.code + `
lay-verify="required"/>
<input type="text" name=` + "depositoryId" + NewIdNumber + ` class="layui-input" id="depositoryId" value=` + place.depositoryId + `
style="display: none" lay-verify="required"/>
<input type="text" name=` + "placeId" + NewIdNumber + ` class="layui-input" id="placeId" value=` + place.pid + `
style="display: none" lay-verify="required"/>
</div>
</div>`;
}
var firstItem =
// 前半部分
` <div class="layui-card-body" style="padding-right: 0px" id=` + "cardItem" + NewIdNumber + `>
<hr>
<i class="layui-icon layui-icon-subtraction" style="display: inline" onclick="deleteItem(this)"></i>
<div class="layui-form-item">
<label class="layui-form-label">物料名称</label>
<div class="layui-input-block">
<div class="inputdiv">
<input type="text" placeholder="请选择物料" class="layui-input" style="border-style: none"
id="openSonByMaterial" lay-verify="required" value="${obj.mname}" onblur="selectMaterialByName(this)"/>
<i class="layui-icon layui-icon-search" style="display: inline" id="selectMaterial" onclick="selectMaterial(this)"></i>
</div>
<input type="text" name=` + "mid" + NewIdNumber + ` class="layui-input" id="mid" value="${obj.mid}"
style="display: none" lay-verify="required" />
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">物料编码:</label>
<div class="layui-input-block">
<input id="code" name=` + "code" + NewIdNumber + ` type="text" placeholder="请填写入物料编码" onblur="selectCode(this)"
class="layui-input" lay-verify="required" value="${obj.code}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">物料单价:</label>
<div class="layui-input-block">
<input name=` + "price" + NewIdNumber + ` type="number" placeholder="请填写入物料单价" value=""
class="layui-input" lay-verify="number">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">物料数量:</label>
<div class="layui-input-block">
<input name=` + "quantity" + NewIdNumber + ` type="number" placeholder="请填写入物料数量" value=""
class="layui-input" lay-verify="number">
</div>
</div>`;
var lastItem = `<div class="layui-form-item">
<label class="layui-form-label">备注说明:</label>
<div class="layui-input-block">
<textarea name=` + "applyRemark" + NewIdNumber + ` placeholder="请填写相关原因及申请原因" value=""
class="layui-textarea"></textarea>
</div>
</div>
<i class="layui-icon layui-icon-addition" style="display: inline" onclick="addItem(this)"></i>
</div>`;
// 获取当前高度
var height = parseInt(($("#stepForm").css('height')).split("px")[0]);
if (NewIdNumber !== "") {
params.push(NewIdNumber)
}
$("#stepForm").css("height", height + 475 + 'px');
var materialItem = firstItem + depositoryItem + lastItem; // 最终
$("#btn_sub").prepend(materialItem)
};
// 用于分步表单加载
step.render({
elem: '#stepForm',
filter: 'stepForm',
width: '100%', //设置容器宽度
height: '600px',
stepItems: [{
title: '填写信息'
}, {
title: '提交成功'
}]
});
// 用于提交操作
form.on('submit(formStep)', function (data) {
data = data.field;
data.type = 1;
data.params = params;
$.ajax({
url: "/depositoryRecord/applicationIn",
type: 'post',
dataType: 'json',
contentType: "application/json;charset=utf-8",
data: JSON.stringify(data),
beforeSend: function () {
this.layerIndex = layer.load(0, {shade: [0.5, '#393D49']});
},
success: function (data) {
layer.close(this.layerIndex);
if (data.status >= 300) {
console.log(data)
var d = data.data;
if (d === "") {
layer.msg(data.statusInfo.detail);
} else {
var err = d["err"];
var success = d["success"];
var errMsg = "";
for (let i = 0; i < err.length; i++) {
errMsg += "物料编码: "
errMsg += err[i]["code"];
}
errMsg += "添加失败,请选择新仓库或库位";
layer.msg(errMsg, {
icon: 5,
time: 1000
}, function () {
step.next('#stepForm');
});
}
} else {
layer.msg("申请提交成功", {
icon: 6,//成功的表情
time: 500 //1秒关闭(如果不配置,默认是3秒)
}, function () {
step.next('#stepForm');
});
}
},
complete: function () {
layer.close(this.layerIndex);
}
});
return false;
});
form.on('submit(formStep2)', function (data) {
step.next('#stepForm');
return false;
});
$('.pre').click(function () {
step.pre('#stepForm');
});
$('.next').click(function () {
step.next('#stepForm');
});
// 实现卡片添加
addItem = function (obj) {
// 获取父元素id
var parentId = obj.parentNode.id;
NewIdNumber = NewIdNumber + 1;
// 物料名称栏目
var depositoryItem = ` <div class="layui-form-item">
<label class="layui-form-label">仓库:</label>
<div class="layui-input-block">
<input type="text" placeholder="请选择仓库" class="layui-input"
id="openSonByDepository" readonly onclick="openDepositoryTree(this)"
lay-verify="required"/>
<input type="text" name=` + "depositoryId" + NewIdNumber + ` class="layui-input" id="depositoryId"
style="display: none" lay-verify="required"/>
<input type="text" name=` + "placeId" + NewIdNumber + ` class="layui-input" id="placeId"
style="display: none" lay-verify="required"/>
</div>
</div>
`;
if (scanValue.depository !== undefined && scanValue.depository !== null && scanValue.depository !== "") {
let depository = scanValue.depository;
// 如果扫描了仓库
depositoryItem = `<div class="layui-form-item">
<label class="layui-form-label">仓库:</label>
<div class="layui-input-block">
<input type="text" placeholder="请选择仓库" class="layui-input" value=` + depository.dname + `
id="openSonByDepository" readonly onclick="openDepositoryTree(this)"
lay-verify="required"/>
<input type="text" name=` + "depositoryId" + NewIdNumber + ` class="layui-input" id="depositoryId" value=` + depository.did + `
style="display: none" lay-verify="required"/>
<input type="text" name=` + "placeId" + NewIdNumber + ` class="layui-input" id="placeId" value="0"
style="display: none" lay-verify="required"/>
</div>
</div>`;
}
if (scanValue.place !== undefined && scanValue.place !== null && scanValue.place !== "") {
// 如果扫描了库位
let place = scanValue.place;
depositoryItem = `<div class="layui-form-item">
<label class="layui-form-label">仓库:</label>
<div class="layui-input-block">
<input type="text" placeholder="请选择仓库" class="layui-input"
id="openSonByDepository" readonly onclick="openDepositoryTree(this)" value=` + place.dname + "-" + place.code + `
lay-verify="required"/>
<input type="text" name=` + "depositoryId" + NewIdNumber + ` class="layui-input" id="depositoryId" value=` + place.depositoryId + `
style="display: none" lay-verify="required"/>
<input type="text" name=` + "placeId" + NewIdNumber + ` class="layui-input" id="placeId" value=` + place.pid + `
style="display: none" lay-verify="required"/>
</div>
</div>`;
}
var firstItem =
`
<div class="layui-card-body" style="padding-right: 0px" id=` + "cardItem" + NewIdNumber + `>
<hr>
<i class="layui-icon layui-icon-subtraction" style="display: inline" onclick="deleteItem(this)"></i>
<div class="layui-form-item">
<label class="layui-form-label">物料名称</label>
<div class="layui-input-block">
<div class="inputdiv">
<input type="text" placeholder="请选择物料" class="layui-input" style="border-style: none"
id="openSonByMaterial" lay-verify="required" onblur="selectMaterialByName(this)"/>
<i class="layui-icon layui-icon-search" style="display: inline" id="selectMaterial" onclick="selectMaterial(this)"></i>
</div>
<input type="text" name=` + "mid" + NewIdNumber + ` class="layui-input" id="mid"
style="display: none" lay-verify="required" />
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">物料编码:</label>
<div class="layui-input-block">
<input id="code" name=` + "code" + NewIdNumber + ` type="text" placeholder="请填写入物料编码" value="" onblur="selectCode(this)"
class="layui-input" lay-verify="required">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">物料单价:</label>
<div class="layui-input-block">
<input name=` + "price" + NewIdNumber + ` type="number" placeholder="请填写入物料单价" value=""
class="layui-input" lay-verify="number">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">物料数量:</label>
<div class="layui-input-block">
<input name=` + "quantity" + NewIdNumber + ` type="number" placeholder="请填写入物料数量" value=""
class="layui-input" lay-verify="number">
</div>
</div>`;
var lastItem = `<div class="layui-form-item">
<label class="layui-form-label">备注说明:</label>
<div class="layui-input-block">
<textarea name=` + "applyRemark" + NewIdNumber + ` placeholder="请填写相关原因及申请原因" value=""
class="layui-textarea"></textarea>
</div>
</div>
<i class="layui-icon layui-icon-addition" style="display: inline" onclick="addItem(this)"></i>
</div>`;
// 获取当前高度
var height = parseInt(($("#stepForm").css('height')).split("px")[0]);
params.push(NewIdNumber)
$("#stepForm").css("height", height + 475 + 'px');
var materialItem = firstItem + depositoryItem + lastItem;
$("#" + parentId).after(materialItem);
};
// 实现卡片删除
deleteItem = function (obj) {
// 获取父节点
var parent = obj.parentNode;
var parentId = parent.id;
parentId = parseInt(parentId.split("cardItem")[1]);
// 获取祖父节点
var reparent = parent.parentNode;
var height = parseInt(($("#stepForm").css('height')).split("px")[0]);
$("#stepForm").css("height", height - 475 + 'px');
params = remove(params, parentId);
reparent.removeChild(parent);
};
//删除数组中指定元素
function remove(arr, item) {
var result = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] === item) {
continue;
}
result.push(arr[i]);
}
return result;
}
// 用于实现通过编码查询物料
selectCode = function (obj) {
// 输入code
var code = obj.value;
// 获取对应元素
var parent = obj.parentNode.parentNode.parentNode;
var children = parent.childNodes[5];
var materialItem = children.childNodes[3].childNodes[1].childNodes;
var materialName = materialItem[1];
var materialId = materialName.parentNode.parentNode.childNodes[3];
var req = {};
req.code = code;
req.type = "in";
$.ajax({
url: "/material/findMatrialByCode",
type: "get",
dataType: 'json',
data: req,
contentType: "application/json;charset=utf-8",
success: function (d) {
var d = d.data;
if (d == null) {
layer.msg("没有该编码,请确认是否输入正确");
materialName.value = "";
materialId.value = "";
obj.value = "";
} else {
materialName.value = d.mname;
materialId.value = d.id;
}
}
});
};
// 用于实现点击搜索按钮
selectMaterial = function (obj) {
var parent = obj.parentNode.parentNode.parentNode.parentNode;
var parentId = parent.id;
var codeChildren = parent.childNodes[7];
var materialChildren = parent.childNodes[5];
var codeItem = codeChildren.childNodes[3].childNodes;
var codeValue = codeItem[1];
var materialItem = materialChildren.childNodes[3].childNodes[1].childNodes;
var materialName = materialItem[1];
var materialId = materialName.parentNode.parentNode.childNodes[3];
var mname = materialName.value;
layer.open({
type: 2,
title: '弹窗内容',
skin: 'layui-layer-rim',
maxmin: true,
shadeClose: true, //点击遮罩关闭层
area: ['70%', '70%'],
content: '/selectMaterialByCard?mname=' + mname + '&type=1&clickObj=' + parentId,
move: '.layui-layer-title',
fixed: false,
end: function () {
var mid = materialId.value;
$.ajax({
url: "/material/findMatrialById?mid=" + mid,
type: "get",
dataType: 'json',
contentType: "application/json;charset=utf-8",
success: function (d) {
var material = d.data.materialById;
var code = material.code;
if (code === undefined) {
code = "";
}
codeValue.value = code;
}
});
}
});
};
//用于实现物料名称搜索
selectMaterialByName = function (obj) {
// 输入code
var data = obj.value;
// 获取对应元素
var parent = obj.parentNode.parentNode.parentNode.parentNode;
var materialChildren = parent.childNodes[5];
var codeChildren = parent.childNodes[7];
var codeItem = codeChildren.childNodes[3].childNodes;
var codeValue = codeItem[1];
var materialItem = materialChildren.childNodes[3].childNodes[1].childNodes;
var materialName = materialItem[1];
var materialId = materialName.parentNode.parentNode.childNodes[3];
var req = {};
req.mname = data;
$.ajax({
url: "/material/findMaterialByCondition",
type: "post",
dataType: 'json',
data: JSON.stringify(req),
contentType: "application/json;charset=utf-8",
success: function (d) {
if (d.count > 1) {
layer.msg("请点击右侧搜索确定物品");
materialId.value = "";
codeValue.value = "";
return false;
} else if (d.count === 0) {
layer.msg("没有该物品,请确认输入是否正确");
materialId.value = "";
codeValue.value = "";
materialName.value = "";
return false;
} else {
var material = d.data[0];
materialName.value = material.mname;
materialId.value = material.id;
codeValue.value = material.code;
}
}
});
};
// 用于打开仓库树形菜单
openDepositoryTree = function (obj) {
var parent = obj.parentNode.parentNode.parentNode;
var parentId = parent.id;
layer.open({
type: 2,
title: '弹窗内容',
skin: 'layui-layer-rim',
maxmin: true,
shadeClose: true, //点击遮罩关闭层
area: ['70%', '70%'],
move: '.layui-layer-title',
fixed: false,
content: '/selectDepositoryByCard?type=1&clickObj=' + parentId,
});
}
})
</script>
</body>
</html>

91
src/main/resources/templates/pages/application/application-out.html

@ -56,16 +56,10 @@
class="layui-input" lay-verify="required">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">所处库位:</label>
<div class="layui-input-block">
<select name="placeId" id="place"></select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">物料数量:</label>
<div class="layui-input-block">
<input name="quantity" type="number" placeholder="请填写入物料数量" value=""
<input name="quantity" type="number" placeholder="请填写入物料数量" value="" onblur="MaterialQuantityIsTrue(this)" id="quantity"
class="layui-input" lay-verify="number" required>
</div>
</div>
@ -129,6 +123,8 @@
function selectMaterial(obj){}
// 用于物料名称查询
function selectMaterialByName(obj){}
// 用于判断当前物料数量是否合适
function MaterialQuantityIsTrue(){}
// 用于暂存卡片个数
var params = [];
// 用于卡片编号
@ -222,21 +218,15 @@
<div class="layui-form-item">
<label class="layui-form-label">物料编码:</label>
<div class="layui-input-block">
<input id="code" name=`+"code"+NewIdNumber+` type="text" placeholder="请填写入物料编码" value="" onblur="selectCode(this)"
<input id=`+"code"+NewIdNumber+` name=`+"code"+NewIdNumber+` type="text" placeholder="请填写入物料编码" value="" onblur="selectCode(this)"
class="layui-input" lay-verify="required">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">所处库位:</label>
<div class="layui-input-block">
<select name=`+"placeId"+NewIdNumber +` id="place"></select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">物料数量:</label>
<div class="layui-input-block">
<input name=`+"quantity"+NewIdNumber+` type="number" placeholder="请填写入物料数量" value=""
class="layui-input" lay-verify="number">
<input name=`+"quantity"+NewIdNumber+` type="number" placeholder="请填写入物料数量" value="" onblur="MaterialQuantityIsTrue(this)"
id=`+"quantity"+NewIdNumber+` class="layui-input" lay-verify="number">
</div>
</div>
<div class="layui-form-item">
@ -251,7 +241,7 @@
// 获取当前高度
var height = parseInt(($("#stepForm").css('height')).split("px")[0]);
params.push(NewIdNumber)
$("#stepForm").css("height",height+430 +'px');
$("#stepForm").css("height",height+350 +'px');
$("#"+parentId).after(materialItem);
};
@ -261,11 +251,10 @@
var parent = obj.parentNode;
var parentId = parent.id;
parentId = parseInt(parentId.split("cardItem")[1]);
console.log(parentId);
// 获取祖父节点
var reparent = parent.parentNode;
var height = parseInt(($("#stepForm").css('height')).split("px")[0]);
$("#stepForm").css("height",height-430 +'px');
$("#stepForm").css("height",height-350 +'px');
params = remove(params,parentId);
reparent.removeChild(parent);
};
@ -287,6 +276,7 @@
var code = obj.value;
// 获取对应元素
var parent = obj.parentNode.parentNode.parentNode;
var objId = parent.id.split("cardItem")[1];
var children = parent.childNodes[5];
var materialItem = children.childNodes[3].childNodes[1].childNodes;
var materialName = materialItem[1];
@ -307,27 +297,12 @@
materialName.value = "";
materialId.value = "";
obj.value = "";
$('#place').empty();
$('#place'+objId).empty();
}else{
req.mid = d.id;
$.ajax({
url: "/place/findPlaceByMid",
type: "post",
dataType: 'json',
data:JSON.stringify(req),
contentType: "application/json;charset=utf-8",
success:function (res) {
$('#place').empty();
$.each(res.data, function (index, item) {
$('#place').append(new Option(item.depositoryName+"-"+item.code, item.id));//往下拉菜单里添加元素
});
form.render();
materialName.value = d.mname;
materialId.value = d.id;
}
});
}
}
});
};
@ -363,16 +338,11 @@
contentType: "application/json;charset=utf-8",
success: function (d) {
var material = d.data.materialById;
var placeList = d.data.placeList;
var code = material.code;
if(code === undefined){
code = "";
}
codeValue.value = code;
$('#place').empty();
$.each(placeList, function (index, item) {
$('#place').append(new Option(item.depositoryName+"-"+item.code, item.id));//往下拉菜单里添加元素
});
form.render();
}
});
@ -420,13 +390,50 @@
materialName.value = material.mname;
materialId.value = material.id;
codeValue.value = material.code;
}
}
});
};
//用于判断当前物料数量是否合适
MaterialQuantityIsTrue = function (obj) {
var id = obj.id.split("quantity")[1];
var mcode = $("#code"+id).val(); // 获取到当前输入的物料编码
if(mcode === "" || mcode ===undefined || mcode === null){
layer.msg("请输入物料的正确编码!");
$("#quantity"+id).val("")
}else{
var req = {};
req.code = mcode;
req.quantity = $("#quantity"+id).val();
$.ajax({
url:"/material/MaterialQuantityIsTrue",
type:"post",
data:JSON.stringify(req),
dataType: 'json',
contentType: "application/json;charset=utf-8",
success:function (res) {
var flag = res.data;
if(!flag){ // 如果当前数目不合适
layer.msg("当前物料数量不足");
$("#quantity"+id).val("");
// 获取对应元素
var parent = obj.parentNode.parentNode.parentNode;
var children = parent.childNodes[5];
var codeChildren = parent.childNodes[7];
var materialItem = children.childNodes[3].childNodes[1].childNodes;
var materialName = materialItem[1];
var materialId = materialName.parentNode.parentNode.childNodes[3];
var codeItem = codeChildren.childNodes[3].childNodes;
var codeValue = codeItem[1];
materialName.value = "";
materialId.value = "";
codeValue.value = "";
}
}
});
}
}
})

40
src/main/resources/templates/pages/application/application-out_back.html

@ -38,6 +38,12 @@
class="layui-input" lay-verify="required">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">所处库位:</label>
<div class="layui-input-block">
<select name="placeId" id="place"></select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">物料数量:</label>
<div class="layui-input-block">
@ -94,6 +100,24 @@
var $ = layui.$,
form = layui.form,
step = layui.step;
var temp = {};
temp.mid = $("#mid").val();
$.ajax({
url: "/place/findPlaceByMid",
type: "post",
dataType: 'json',
data:JSON.stringify(temp),
contentType: "application/json;charset=utf-8",
success:function (res) {
$('#place').empty();
$.each(res.data, function (index, item) {
$('#place').append(new Option(item.depositoryName + "-" + item.code, item.id));//往下拉菜单里添加元素
});
form.render();
}
});
$("#code").blur(function () {
var code = $(this).val();
var req = {};
@ -112,8 +136,24 @@
$("#openSonByMaterial").val("");
$("#mid").val("");
}else{
req.mid = d.id;
$.ajax({
url: "/place/findPlaceByMid",
type: "post",
dataType: 'json',
data:JSON.stringify(req),
contentType: "application/json;charset=utf-8",
success:function (res) {
$('#place').empty();
$.each(res.data, function (index, item) {
$('#place').append(new Option(item.depositoryName+"-"+item.code, item.id));//往下拉菜单里添加元素
});
$("#openSonByMaterial").val(d.mname);
$("#mid").val(d.id);
form.render();
}
});
}
}
});

243
src/main/resources/templates/pages/application/application-out_scanQrCode.html

@ -29,58 +29,17 @@
<div class="layui-fluid">
<!-- 出库申请-->
<div class="layui-carousel" id="stepForm" lay-filter="stepForm" style="margin: 0 auto;">
<input th:value="${materialList}" style="display:none;" id="scanValue_materialList">
<input th:value="${depository}" style="display: none" id="scanValue_depositoryId">
<input th:value="${place}" style="display: none" id="scanValue_placeId">
<div carousel-item style="overflow: inherit">
<div>
<form class="layui-form" style="margin: 0 auto;max-width: 460px;padding-top: 40px;">
<div class="layui-card" id="cardParent">
<div class="layui-card-body" id="cardItem1">
<hr>
<i class="layui-icon layui-icon-subtraction" style="display: inline" onclick="deleteItem(this)"></i>
<div class="layui-form-item">
<label class="layui-form-label">物料名称:</label>
<div class="layui-input-block">
<div class="inputdiv">
<input type="text" placeholder="请选择物料" class="layui-input" style="border-style: none"
id="openSonByMaterial" onblur="selectMaterialByName(this)"
lay-verify="required"/>
<i class="layui-icon layui-icon-search" style="display: inline" id="selectMaterial" onclick="selectMaterial(this)"></i>
</div>
<input type="text" name="mid" class="layui-input" id="mid"
style="display: none" lay-verify="required"/>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">物料编码:</label>
<div class="layui-input-block">
<input id="code" name="code" type="text" placeholder="请填写入物料编码" value="" onblur="selectCode(this)"
class="layui-input" lay-verify="required">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">所处库位:</label>
<div class="layui-input-block">
<select name="placeId" id="place"></select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">物料数量:</label>
<div class="layui-input-block">
<input name="quantity" type="number" placeholder="请填写入物料数量" value=""
class="layui-input" lay-verify="number" required>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">备注说明:</label>
<div class="layui-input-block">
<textarea name="applyRemark" placeholder="请填写相关原因及申请原因" value=""
class="layui-textarea"></textarea>
</div>
</div>
<i class="layui-icon layui-icon-addition" style="display: inline" onclick="addItem(this)"></i>
</div>
<!-- 提交按钮-->
<div class="layui-form-item">
<div class="layui-form-item" id="btn_sub">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="formStep" style="margin-bottom: 30px;margin-left: 15%">
&emsp;提交申请&emsp;
@ -131,6 +90,8 @@
function selectMaterialByName(obj){}
// 用于暂存卡片个数
var params = [];
// 用于页面初始化时的卡片构造
function initForm(num,obj) {}
// 用于卡片编号
var NewIdNumber = 1;
layui.use(['form', 'step', 'layer', 'jquery'], function () {
@ -149,6 +110,195 @@
title: '提交成功'
}]
});
let scanValue = {}; // 用于暂存扫描得到的结果
let materialOnPlaceList = []; // 用于保存当前物料所处的库位
let materialIsExist = ''; // 用于判断当前物料是否存在
// 页面初始化
$(function () {
let depository = $("#scanValue_depositoryId").val();
let place = $("#scanValue_placeId").val();
let materialList = $("#scanValue_materialList").val();
materialList = JSON.parse(materialList);
if(depository !== undefined && depository !== null && depository !== ""){
// 如果扫描到仓库
depository = JSON.parse(depository);
scanValue.depository = depository;
}
if(place !== undefined && place !== null && place !== ""){
// 如果扫描到库位
place = JSON.parse(place);
scanValue.place = place;
}
for (let i = 0; i < materialList.length; i++) {
initForm(i,materialList[i]);
}
});
// 用于获取当前物料所处的库位
function getPlaceByMaterial(material){
var req = {};
req.code = material.code;
req.type = "out";
$.ajax({
url: "/material/findMatrialByCode",
type: "get",
dataType: 'json',
data:(req),
contentType: "application/json;charset=utf-8",
success: function (d) {
var d = d.data;
if(d == null){
materialIsExist = false;
}else{
req.mid = d.id;
$.ajax({
url: "/place/findPlaceByMid",
type: "post",
dataType: 'json',
data:JSON.stringify(req),
contentType: "application/json;charset=utf-8",
success:function (res) {
materialOnPlaceList = res.data;
materialIsExist = true;
}
});
}
}
})
}
//用于页面初始化时的卡片构造
initForm = function(num,obj){
var parent = $("#cardParent");
// 获取待添加父类
NewIdNumber = num;
var isPlace = false;
if(num === 0){ // 如果是第一个
NewIdNumber = "";
}
let depositoryItem = `
<div class="layui-form-item">
<label class="layui-form-label">所处库位:</label>
<div class="layui-input-block">
<select name=`+"placeId"+NewIdNumber +` id=`+"place"+NewIdNumber+`></select>
</div>
</div>
`;
var firstItem = `
<div class="layui-card-body" id=`+"cardItem"+NewIdNumber+`>
<hr>
<i class="layui-icon layui-icon-subtraction" style="display: inline" onclick="deleteItem(this)"></i>
<div class="layui-form-item">
<label class="layui-form-label">物料名称</label>
<div class="layui-input-block">
<div class="inputdiv">
<input type="text" placeholder="请选择物料" class="layui-input" style="border-style: none" value="${obj.mname}"
id="openSonByMaterial" lay-verify="required" onblur="selectMaterialByName(this)"/>
<i class="layui-icon layui-icon-search" style="display: inline" id="selectMaterial" onclick="selectMaterial(this)"></i>
</div>
<input type="text" name=`+"mid"+NewIdNumber+` class="layui-input" id="mid" value="${obj.mid}"
style="display: none" lay-verify="required" />
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">物料编码:</label>
<div class="layui-input-block">
<input id="code" name=`+"code"+NewIdNumber+` type="text" placeholder="请填写入物料编码" value="${obj.code}" onblur="selectCode(this)"
class="layui-input" lay-verify="required">
</div>
</div>`;
var lastItem = `<div class="layui-form-item">
<label class="layui-form-label">物料数量:</label>
<div class="layui-input-block">
<input name=`+"quantity"+NewIdNumber+` type="number" placeholder="请填写入物料数量" value=""
class="layui-input" lay-verify="number">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">备注说明:</label>
<div class="layui-input-block">
<textarea name=`+"applyRemark"+NewIdNumber+` placeholder="请填写相关原因及申请原因" value=""
class="layui-textarea"></textarea>
</div>
</div>
<i class="layui-icon layui-icon-addition" style="display: inline" onclick="addItem(this)"></i>
</div>`;
if(scanValue.depository !== undefined && scanValue.depository !== null && scanValue.depository !== ""){
// 如果扫描了仓库
var depository = scanValue.depository;
var req = {};
req.depositoryId = depository.did;
req.code = obj.code;
$.ajax({
url: "/place/findPlaceByMcodeAndDid",
type: "post",
dataType: 'json',
data:JSON.stringify(req),
contentType: "application/json;charset=utf-8",
success: function (d) {
if(d.data.length === 0){
initDeleteCard(NewIdNumber)
}else {
$('#place' + NewIdNumber).empty();
$.each(d.data, function (index, item) {
$('#place' + NewIdNumber).append(new Option(item.depositoryName + "-" + item.code, item.did));//往下拉菜单里添加元素
});
form.render();
}
}
})
}
if(scanValue.place !== undefined && scanValue.place !== null && scanValue.place !== ""){
// 如果扫描了库位
var place = scanValue.place;
var midlist = place.midList;
if(midlist.indexOf(obj.mid) !== -1){ // 如果当前库位存在该物料
isPlace = true;
}
}
// 获取当前高度
var height = parseInt(($("#stepForm").css('height')).split("px")[0]);
if (NewIdNumber !== "") {
params.push(NewIdNumber)
}
$("#stepForm").css("height",height+475 +'px');
var materialItem = firstItem + depositoryItem + lastItem;
$("#btn_sub").prepend(materialItem);
if(isPlace) {
// 如果当前库位存在
$('#place' + NewIdNumber).empty();
$('#place' + NewIdNumber).append(new Option(place.dname + "-" + place.code, place.pid));//往下拉菜单里添加元素
form.render();
}
};
// 初始化时删除卡片
initDeleteCard = function(NewIdNumber){
// 待删除结点
var delItem = $("#cardItem"+NewIdNumber)[0];
var parentId = 0;
if(NewIdNumber !== ""){
parentId = parseInt(NewIdNumber);
}
// 获取祖父节点
// console.log(delItem)
var reparent = delItem.parentNode;
var height = parseInt(($("#stepForm").css('height')).split("px")[0]);
$("#stepForm").css("height",height-430 +'px');
params = remove(params,parentId);
reparent.removeChild(delItem);
};
// 提交
form.on('submit(formStep)', function (data) {
@ -261,7 +411,6 @@
var parent = obj.parentNode;
var parentId = parent.id;
parentId = parseInt(parentId.split("cardItem")[1]);
console.log(parentId);
// 获取祖父节点
var reparent = parent.parentNode;
var height = parseInt(($("#stepForm").css('height')).split("px")[0]);

2
src/main/resources/templates/pages/application/application-review.html

@ -114,7 +114,7 @@
<div class="layui-form" style="margin: 0 auto;max-width: 900px;padding-top: 40px;">
<div class="layui-form-item">
<label class="layui-form-label">验收备注:</label>
<label class="layui-form-label">审核备注:</label>
<div class="layui-input-block">
<textarea id="depositoryManagerMessageF" name="depositoryManagerMessage" placeholder="请填写相关原因及申请原因" value="" class="layui-textarea"></textarea>
</div>

4
src/main/resources/templates/pages/depository/table-stock.html

@ -263,13 +263,13 @@
}else if(obj.event === 'applicationOut'){
// 出库申请
var index = layer.open({
title: '库申请',
title: '库申请',
type: 2,
shade: 0.2,
maxmin: true,
shadeClose: true,
area: ['100%', '100%'],
content: '/application_out_back?mid='+data.id
content: '/application_out_back?code='+data.code+"&depositoryCode="+data.depositoryCode
});
$(window).on("resize", function () {
layer.full(index);

333
src/main/resources/templates/pages/scanQrCode/ScanQrCode.html

@ -0,0 +1,333 @@
<!DOCTYPE html>
<html xmlns:th="http://www.w3.org/1999/xhtml">
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<title>扫码</title>
<link rel="stylesheet" href="/static/lib/layui-v2.6.3/css/layui.css" media="all">
<link rel="stylesheet" href="/static/css/layuimini.css?v=2.0.4.2" media="all">
<link rel="stylesheet" href="/static/css/themes/default.css" media="all">
<link rel="stylesheet" href="/static/lib/font-awesome-4.7.0/css/font-awesome.min.css" media="all">
<!--[if lt IE 9]>
<script src="/static/js/html5.min.js"></script>
<script src="/static/js/respond.min.js"></script>
<![endif]-->
<!-- vue相关-->
<script src="../static/js/vue/vue.js"></script>
<script src="../static/js/vue/vue-router.js"></script>
<script src="../static/lib/http-vue-loader/src/httpVueLoader.js"></script>
<script src="../static/js/VueQrcodeReader.umd.min.js"></script>
<style>
.validation-success,
.validation-failure,
.validation-pending {
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, .8);
text-align: center;
font-weight: bold;
font-size: 1.4rem;
padding: 10px;
display: flex;
flex-flow: column nowrap;
justify-content: center;
}
.validation-success {
color: green;
}
.validation-failure {
color: red;
}
</style>
</head>
<body>
<div id="app">
<qrcode-stream :camera="camera" @decode="onDecode" @init="onInit" :track="paintBoundingBox">
<div v-if="validationPending" class="validation-pending">
Long validation in progress...
</div>
</qrcode-stream>
</div>
<script src="/static/lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
<script>
Vue.use(httpVueLoader);
var vue = new Vue({
data() {
return {
isValid: undefined,
camera: 'auto',
result: '',
error: '',
materialList: [],
depository: null,
place: null
}
},
computed: {
validationPending() {
return this.isValid === undefined
&& this.camera === 'off'
},
},
methods: {
onDecode(result) {
let params = {}; // 用于暂存扫描结果
this.result = result;
let parse = JSON.parse(result);
vue.turnCameraOff(); // 暂停扫描
if (parse.did !== undefined) {
// 如果扫描的是仓库二维码
this.depository = parse;// 将扫描结果保存到vue中
params.depository = this.depository;
params.place = this.place;
params.materialList = this.materialList;
if (this.materialList.length > 0) {
// 如果有物料
this.temporaryScanValue(params); // 将数据暂存至redis中
this.chooseInOrOut(); // 弹出选择框
} else {
// 如果没有
layer.confirm("暂未选择物料,是否继续扫描", {
btn:["继续","取消"]
},function () { // 继续
vue.turnCameraOn(); // 继续扫描
layer.close(layer.index); // 关闭弹窗
},function () { // 取消
vue.temporaryScanValue(params); // 将数据暂存
vue.chooseInOrOut(); // 弹出选择框
})
}
}
else if (parse.pid !== undefined) {
// 如果扫描的是库位二维码
this.place = parse; // 将扫描结果保存到vue中
params.depository = this.depository;
params.place = this.place;
params.materialList = this.materialList;
if (this.materialList.length > 0) {
// 如果有物料
this.temporaryScanValue(params); // 将数据暂存至redis中
this.chooseInOrOut(); // 弹出选择框
} else {
// 如果没有
layer.confirm("当前并未扫描物料,是否继续扫描",
{btn:["继续","取消"]},
function () { // 继续扫描
vue.turnCameraOn(); // 继续扫描
layer.close(layer.index); // 关闭弹窗
},
function () {
vue.temporaryScanValue(params); // 将数据暂存
vue.chooseInOrOut(); // 弹出选择框
}
)
}
}
else if (parse.mid !== undefined) {
// 如果扫描的是物料二维码
this.materialList.push(parse);
layer.confirm("是否继续扫描",
{
btn: ["继续", "取消"]
},
function () { // 继续扫描物料
vue.turnCameraOn(); // 继续扫描
layer.close(layer.index); // 关闭弹窗
},
function () {
// 不扫描物料
params.materialList = vue.materialList;
params.depository = vue.depository;
params.place = vue.place;
vue.temporaryScanValue(params); // 将物料暂存
if (vue.depository !== '' || vue.place !== '') {
// 如果已经扫描了仓库或库位
// 弹出选择框
vue.chooseInOrOut();
}
else {
// 如果没有扫描仓库或库位
layer.confirm("暂未扫描仓库,是否继续该操作",
{
btn: ["继续", "取消"]
},
function () {// 继续
// 弹出选择框
vue.chooseInOrOut();
},
function () { // 取消当前操作
vue.turnCameraOn(); // 继续扫描
layer.close(layer.index); // 关闭弹窗
}
)
}
}
)
}
},
/*layer.confirm("请选择入库|出库",{
btn:["入库","出库"]},
function () {
layer.open({
type: 2,
title: '入库',
skin: 'layui-layer-rim',
maxmin: true,
shadeClose: true, //点击遮罩关闭层
area: ['100%', '100%'],
move : '.layui-layer-title',
fixed:false,
content: '/application_in_back?mid='+material.mid,
})
},function () {
let req = {};
req.code = material.code;
req.type = "out";
layui.$.ajax({
url: "/material/findMatrialByCode",
type: "get",
dataType: 'json',
data:(req),
contentType: "application/json;charset=utf-8",
success: function (d) {
var d = d.data;
if(d !== null){
if(d == null) {
layer.msg("没有该编码,请确认是否输入正确");
}else{
layer.open({
type: 2,
title: '出库',
skin: 'layui-layer-rim',
maxmin: true,
shadeClose: true, //点击遮罩关闭层
area: ['100%', '100%'],
move : '.layui-layer-title',
fixed:false,
content: '/application_out_back?code='+d.code+"&depositoryCode="+d.depositoryCode,
})
}
}
}
})
}
)*/
async onInit(promise) {
try {
await promise.then(this.resetValidationState)
} catch (error) {
if (error.name === 'NotAllowedError') {
this.error = "ERROR: you need to grant camera access permission"
} else if (error.name === 'NotFoundError') {
this.error = "ERROR: no camera on this device"
} else if (error.name === 'NotSupportedError') {
this.error = "ERROR: secure context required (HTTPS, localhost)"
} else if (error.name === 'NotReadableError') {
this.error = "ERROR: is the camera already in use?"
} else if (error.name === 'OverconstrainedError') {
this.error = "ERROR: installed cameras are not suitable"
} else if (error.name === 'StreamApiNotSupportedError') {
this.error = "ERROR: Stream API is not supported in this browser"
} else if (error.name === 'InsecureContextError') {
this.error = 'ERROR: Camera access is only permitted in secure context. Use HTTPS or localhost rather than HTTP.';
} else {
this.error = `ERROR: Camera error (${error.name})`
}
console.log(this.error)
}
}
,
resetValidationState() {
this.isValid = undefined
}
,
// 绘制二维码跟踪框
paintBoundingBox(detectedCodes, ctx) {
for (const detectedCode of detectedCodes) {
const {boundingBox: {x, y, width, height}} = detectedCode;
ctx.lineWidth = 2;
ctx.strokeStyle = '#007bff';
ctx.strokeRect(x, y, width, height)
}
}
,
// 打开相机
turnCameraOn() {
this.camera = 'auto'
}
,
// 关闭相机
turnCameraOff() {
this.camera = 'off'
},
// 将扫描到的数据暂存到redis
temporaryScanValue(params) {
layui.$.ajax({
url: "/material/temporaryValue",
type: 'post',
dataType: 'json',
contentType: "application/json;charset=utf-8",
data: JSON.stringify(params)
});
},
// 弹出入库|出库选择框
chooseInOrOut(){
layer.confirm("请选择入库|出库", {
btn: ["入库"]
},
function () { // 选择入库
layer.open({
type: 2,
title: '入库',
skin: 'layui-layer-rim',
maxmin: true,
shadeClose: true, //点击遮罩关闭层
area: ['100%', '100%'],
move: '.layui-layer-title',
fixed: false,
content: '/application_in_scanQrCode',
end:function () {
var index = parent.layer.getFrameIndex(window.name);
parent.layer.close(index);
}
})
},
function () { // 选择出库
layui.$.ajax({ // 判断当前物料是否存在库存
url:"/material/IsMaterialExist",
type:"get",
dataType: 'json',
contentType: "application/json;charset=utf-8",
success:function (d) {
layer.open({
type: 2,
title: '出库',
skin: 'layui-layer-rim',
maxmin: true,
shadeClose: true, //点击遮罩关闭层
area: ['100%', '100%'],
move: '.layui-layer-title',
fixed: false,
content: '/application_Out_scanQrCode',
end:function () {
var index = parent.layer.getFrameIndex(window.name);
parent.layer.close(index);
}
})
}
});
})
}
}
}).$mount('#app')
</script>
</body>
</html>

150
src/main/resources/templates/pages/scanQrCode/scanQrCode2.html

@ -0,0 +1,150 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="author" content="ZXing for JS">
<title>ZXing TypeScript | Decoding from camera stream</title>
<!-- <link rel="stylesheet" rel="preload" as="style" onload="this.rel='stylesheet';this.onload=null" href="https://fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic">-->
<!-- <link rel="stylesheet" rel="preload" as="style" onload="this.rel='stylesheet';this.onload=null" href="https://unpkg.com/normalize.css@8.0.0/normalize.css">-->
<!-- <link rel="stylesheet" rel="preload" as="style" onload="this.rel='stylesheet';this.onload=null" href="https://unpkg.com/milligram@1.3.0/dist/milligram.min.css">-->
</head>
<body>
<main class="wrapper" style="padding-top:2em">
<section class="container" id="demo-content">
<div>
<a class="button" id="startButton">扫描</a>
<a class="button" id="resetButton">重置</a>
</div>
<div>
<video id="video" width="300" height="200" style="border: 1px solid gray"></video>
</div>
<div id="sourceSelectPanel" style="display:none">
<label for="sourceSelect">选择摄像头: </label>
<select id="sourceSelect" style="max-width:400px">
</select>
</div>
<div style="display: table">
<label for="decoding-style"> 扫描次数:</label>
<select id="decoding-style" size="1">
<option value="once">扫描一次</option>
<option value="continuously">持续扫描</option>
</select>
</div>
<label>结果:</label>
<pre><code id="result"></code></pre>
</section>
</main>
<script type="text/javascript" src="https://unpkg.com/@zxing/library@latest"></script>
<script type="text/javascript">
function decodeOnce(codeReader, selectedDeviceId) {
codeReader.decodeFromInputVideoDevice(selectedDeviceId, 'video').then((result) => {
console.log(result);
document.getElementById('result').textContent = result.text
}).catch((err) => {
console.error(err);
document.getElementById('result').textContent = err
})
}
function decodeContinuously(codeReader, selectedDeviceId) {
codeReader.decodeFromInputVideoDeviceContinuously(selectedDeviceId, 'video', (result, err) => {
if (result) {
// properly decoded qr code
console.log('Found QR code!', result);
document.getElementById('result').textContent = result.text
}
if (err) {
if (err instanceof ZXing.NotFoundException) {
console.log('No QR code found.')
}
if (err instanceof ZXing.ChecksumException) {
console.log('A code was found, but it\'s read value was not valid.')
}
if (err instanceof ZXing.FormatException) {
console.log('A code was found, but it was in a invalid format.')
}
}
})
}
window.addEventListener('load', function () {
let selectedDeviceId;
const codeReader = new ZXing.BrowserQRCodeReader();
console.log('ZXing 初始化');
codeReader.getVideoInputDevices()
.then((videoInputDevices) => {
const sourceSelect = document.getElementById('sourceSelect')
// selectedDeviceId = videoInputDevices[0].deviceId;
if (videoInputDevices.length >= 1) {
videoInputDevices.forEach((element) => {
const sourceOption = document.createElement('option');
console.log(element.label);
if(element.label.includes("front")){
sourceOption.text = "前置摄像头";
sourceOption.value = element.deviceId;
}else if (element.label.includes("back")){
sourceOption.text = "后置摄像头";
sourceOption.selected=true;
sourceOption.value = element.deviceId;
selectedDeviceId = element.deviceId;
}
sourceSelect.appendChild(sourceOption)
});
sourceSelect.onchange = () => {
selectedDeviceId = sourceSelect.value;
};
const sourceSelectPanel = document.getElementById('sourceSelectPanel')
sourceSelectPanel.style.display = 'block'
}
document.getElementById('startButton').addEventListener('click', () => {
const decodingStyle = document.getElementById('decoding-style').value;
if (decodingStyle === "once") {
// 如果只扫描一次
decodeOnce(codeReader, selectedDeviceId);
} else {
// 扫描多次
decodeContinuously(codeReader, selectedDeviceId);
}
console.log(`Started decode from camera with id ${selectedDeviceId}`)
});
document.getElementById('resetButton').addEventListener('click', () => {
codeReader.reset();
document.getElementById('result').textContent = '';
console.log('Reset.')
})
})
.catch((err) => {
console.error(err)
})
})
</script>
</body>
</html>

10
target/classes/com/dreamchaser/depository_manage/mapper/DepositoryMapper.xml

@ -64,6 +64,16 @@
or d.adminorg = ''
</select>
<!-- 根据仓库编码获取仓库-->
<select id="findDepositoryByCode" resultMap="depositoryMap" parameterType="string">
SELECT
<include refid="allColumns" />
FROM depository d WHERE 1 = 1 and d.state != 3
<if test="depositoryCode != null and depositoryCode !=''">
and d.code = #{depositoryCode}
</if>
</select>
<select id="findDepositoryByAdminorgAndParent" resultMap="depositoryMap" parameterType="map">
SELECT
<include refid="allColumns" />

52
target/classes/com/dreamchaser/depository_manage/mapper/DepositoryRecordMapper.xml

@ -90,9 +90,23 @@
<result column="transferId" property="transferId" jdbcType="INTEGER" />
<result column="mcode" property="mcode" jdbcType="VARCHAR" />
<result column="placeId" property="placeId" jdbcType="INTEGER" />
<result column="pass" property="pass" jdbcType="INTEGER" />
</resultMap>
<!-- 出库子订单-->
<resultMap id="applicationOutRecordMin" type="com.dreamchaser.depository_manage.entity.ApplicationOutRecordMin">
<id property="id" column="aorid" jdbcType="INTEGER"/>
<result column="mid" property="mid" jdbcType="INTEGER" />
<result column="depositoryId" property="depositoryId" jdbcType="INTEGER" />
<result column="placeId" property="placeId" jdbcType="INTEGER" />
<result column="quantity" property="quantity" jdbcType="INTEGER" />
<result column="checkId" property="checkId" jdbcType="INTEGER" />
<result column="parentId" property="parentId" jdbcType="INTEGER" />
<result column="code" property="code" jdbcType="VARCHAR" />
</resultMap>
<!-- 表查询字段 -->
<sql id="simpleColumns">
dr.id, dr.type, dr.applicant_id, dr.apply_remark, dr.apply_time ,dr.oldId
@ -124,7 +138,11 @@
<sql id="ApplicationOutRecordInfo">
aorid,mid,mname,depositoryId,dname,applicantId,applicantTime,applyRemark,aorcode,aorpirce,aorquantity,departmenthead,departmentheadPass,departmentHeadTime,departmentheadMessage,
depositoryManager,depositoryManagerPass,depositoryManagerTime,depositoryManagerMessage,aorstate,istransfer,transferId,mcode,placeId
depositoryManager,depositoryManagerPass,depositoryManagerTime,depositoryManagerMessage,aorstate,istransfer,transferId,mcode,placeId,pass
</sql>
<sql id="ApplicationOutRecordMinInfo">
aorm.id,aorm.mid,aorm.depositoryId,aorm.placeId,aorm.quantity,aorm.code,aorm.checkId,aorm.parentId
</sql>
<!-- 查询所有数据行数 -->
<select id="findCount" resultType="integer">
@ -630,6 +648,38 @@
)
</insert>
<!-- 插入一条出库子订单-->
<insert id="insertApplicationOutRecordMin" parameterType="map" useGeneratedKeys="true" keyProperty="id">
insert into application_out_record_min (id,mid,quantity,code,depositoryId,placeId,checkId,parentId)
values(
#{id},
#{mid},
#{quantity},
#{code},
#{depositoryId},
#{placeId},
#{checkId},
#{parentId}
)
</insert>
<!-- 查找子订单-->
<select id="findApplicationOutMinById" parameterType="int" resultMap="applicationOutRecordMin">
select
<include refid="ApplicationOutRecordMinInfo" />
from application_out_record_min as aorm
where 1 = 1
and aorm.id = #{id}
</select>
<select id="findApplicationOutRecordMinByParent" parameterType="int" resultMap="applicationOutRecordMin">
select
<include refid="ApplicationOutRecordMinInfo" />
from application_out_record_min as aorm
where 1 = 1
and aorm.parentId = #{parentId}
</select>
<!-- 插入数据 -->
<insert id="insertDepositoryRecord" parameterType="map" useGeneratedKeys="true" keyProperty="id">

2
target/classes/com/dreamchaser/depository_manage/mapper/MaterialMapper.xml

@ -350,7 +350,7 @@
<if test="depositoryCode != null and depositoryCode !=''">
depositoryCode = #{depositoryCode},
</if>
<if test="numberOfTemporary != null and numberOfTemporary != ''">
<if test="numberOfTemporary != null">
number_of_temporary = #{numberOfTemporary},
</if>
<if test="texture != null and texture != ''">

BIN
target/classes/static/images/cam.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 625 B

BIN
target/classes/static/images/vid.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

2
target/classes/static/js/VueQrcodeReader.umd.min.js

File diff suppressed because one or more lines are too long

15
target/classes/static/js/ZXing.js

File diff suppressed because one or more lines are too long

1
target/classes/static/js/html5.min.js

@ -0,0 +1 @@
(function(e,t){function n(e,t){var n=e.createElement("p"),i=e.getElementsByTagName("head")[0]||e.documentElement;return n.innerHTML="x<style>"+t+"</style>",i.insertBefore(n.lastChild,i.firstChild)}function i(){var e=m.elements;return"string"==typeof e?e.split(" "):e}function r(e){var t={},n=e.createElement,r=e.createDocumentFragment,o=r();e.createElement=function(e){m.shivMethods||n(e);var i;return i=t[e]?t[e].cloneNode():g.test(e)?(t[e]=n(e)).cloneNode():n(e),i.canHaveChildren&&!f.test(e)?o.appendChild(i):i},e.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+i().join().replace(/\w+/g,function(e){return t[e]=n(e),o.createElement(e),'c("'+e+'")'})+");return n}")(m,o)}function o(e){var t;return e.documentShived?e:(m.shivCSS&&!d&&(t=!!n(e,"article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio{display:none}canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden]{display:none}audio[controls]{display:inline-block;*display:inline;*zoom:1}mark{background:#FF0;color:#000}")),h||(t=!r(e)),t&&(e.documentShived=t),e)}function a(e){for(var t,n=e.getElementsByTagName("*"),r=n.length,o=RegExp("^(?:"+i().join("|")+")$","i"),a=[];r--;)t=n[r],o.test(t.nodeName)&&a.push(t.applyElement(s(t)));return a}function s(e){for(var t,n=e.attributes,i=n.length,r=e.ownerDocument.createElement(b+":"+e.nodeName);i--;)t=n[i],t.specified&&r.setAttribute(t.nodeName,t.nodeValue);return r.style.cssText=e.style.cssText,r}function l(e){for(var t,n=e.split("{"),r=n.length,o=RegExp("(^|[\\s,>+~])("+i().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),a="$1"+b+"\\:$2";r--;)t=n[r]=n[r].split("}"),t[t.length-1]=t[t.length-1].replace(o,a),n[r]=t.join("}");return n.join("{")}function c(e){for(var t=e.length;t--;)e[t].removeNode()}function u(e){var t,i,r=e.namespaces,o=e.parentWindow;return!y||e.printShived?e:(r[b]===void 0&&r.add(b),o.attachEvent("onbeforeprint",function(){for(var r,o,s,c=e.styleSheets,u=[],d=c.length,h=Array(d);d--;)h[d]=c[d];for(;s=h.pop();)if(!s.disabled&&v.test(s.media)){for(r=s.imports,d=0,o=r.length;o>d;d++)h.push(r[d]);try{u.push(s.cssText)}catch(p){}}u=l(u.reverse().join("")),i=a(e),t=n(e,u)}),o.attachEvent("onafterprint",function(){c(i),t.removeNode(!0)}),e.printShived=!0,e)}var d,h,p=e.html5||{},f=/^<|^(?:button|form|map|select|textarea|object|iframe)$/i,g=/^<|^(?:a|b|button|code|div|fieldset|form|h1|h2|h3|h4|h5|h6|i|iframe|img|input|label|li|link|ol|option|p|param|q|script|select|span|strong|style|table|tbody|td|textarea|tfoot|th|thead|tr|ul)$/i;(function(){var n=t.createElement("a");n.innerHTML="<xyz></xyz>",d="hidden"in n,d&&"function"==typeof injectElementWithStyles&&injectElementWithStyles("#modernizr{}",function(t){t.hidden=!0,d="none"==(e.getComputedStyle?getComputedStyle(t,null):t.currentStyle).display}),h=1==n.childNodes.length||function(){try{t.createElement("a")}catch(e){return!0}var n=t.createDocumentFragment();return n.cloneNode===void 0||n.createDocumentFragment===void 0||n.createElement===void 0}()})();var m={elements:p.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:p.shivCSS!==!1,shivMethods:p.shivMethods!==!1,type:"default",shivDocument:o};e.html5=m,o(t);var v=/^$|\b(?:all|print)\b/,b="html5shiv",y=!h&&function(){var n=t.documentElement;return t.namespaces!==void 0&&t.parentWindow!==void 0&&n.applyElement!==void 0&&n.removeNode!==void 0&&e.attachEvent!==void 0}();m.type+=" print",m.shivPrint=u,u(t)})(this,document);

10100
target/classes/static/js/jsQR.js

File diff suppressed because it is too large

12551
target/classes/static/js/library.min.js

File diff suppressed because one or more lines are too long

5
target/classes/static/js/respond.min.js

@ -0,0 +1,5 @@
/*! Respond.js v1.4.2: min/max-width media query polyfill * Copyright 2013 Scott Jehl
* Licensed under https://github.com/scottjehl/Respond/blob/master/LICENSE-MIT
* */
!function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='&shy;<style media="'+a+'"> #mq-test-1 { width: 42px; }</style>',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){u(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))};if(c.ajax=f,c.queue=d,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,maxw:/\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var g,h,i,j=a.document,k=j.documentElement,l=[],m=[],n=[],o={},p=30,q=j.getElementsByTagName("head")[0]||k,r=j.getElementsByTagName("base")[0],s=q.getElementsByTagName("link"),t=function(){var a,b=j.createElement("div"),c=j.body,d=k.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=j.createElement("body"),c.style.background="none"),k.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&k.insertBefore(c,k.firstChild),a=b.offsetWidth,f?k.removeChild(c):c.removeChild(b),k.style.fontSize=d,e&&(c.style.fontSize=e),a=i=parseFloat(a)},u=function(b){var c="clientWidth",d=k[c],e="CSS1Compat"===j.compatMode&&d||j.body[c]||d,f={},o=s[s.length-1],r=(new Date).getTime();if(b&&g&&p>r-g)return a.clearTimeout(h),h=a.setTimeout(u,p),void 0;g=r;for(var v in l)if(l.hasOwnProperty(v)){var w=l[v],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?i||t():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?i||t():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(m[w.rules]))}for(var C in n)n.hasOwnProperty(C)&&n[C]&&n[C].parentNode===q&&q.removeChild(n[C]);n.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=j.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,q.insertBefore(E,o.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(j.createTextNode(F)),n.push(E)}},v=function(a,b,d){var e=a.replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var g=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},h=!f&&d;b.length&&(b+="/"),h&&(f=1);for(var i=0;f>i;i++){var j,k,n,o;h?(j=d,m.push(g(a))):(j=e[i].match(c.regex.findStyles)&&RegExp.$1,m.push(RegExp.$2&&g(RegExp.$2))),n=j.split(","),o=n.length;for(var p=0;o>p;p++)k=n[p],l.push({media:k.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:m.length-1,hasquery:k.indexOf("(")>-1,minw:k.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:k.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},w=function(){if(d.length){var b=d.shift();f(b.href,function(c){v(c,b.href,b.media),o[b.href]=!0,a.setTimeout(function(){w()},0)})}},x=function(){for(var b=0;b<s.length;b++){var c=s[b],e=c.href,f=c.media,g=c.rel&&"stylesheet"===c.rel.toLowerCase();e&&g&&!o[e]&&(c.styleSheet&&c.styleSheet.rawCssText?(v(c.styleSheet.rawCssText,e,f),o[e]=!0):(!/^([a-zA-Z:]*\/\/)/.test(e)&&!r||e.replace(RegExp.$1,"").split("/")[0]===a.location.host)&&("//"===e.substring(0,2)&&(e=a.location.protocol+e),d.push({href:e,media:f})))}w()};x(),c.update=x,c.getEmValue=t,a.addEventListener?a.addEventListener("resize",b,!1):a.attachEvent&&a.attachEvent("onresize",b)}}(this);

84
target/classes/static/js/scan/ga.js

@ -0,0 +1,84 @@
(function(){var E;var g=window,n=document,p=function(a){var b=g._gaUserPrefs;if(b&&b.ioo&&b.ioo()||a&&!0===g["ga-disable-"+a])return!0;try{var c=g.external;if(c&&c._gaUserPrefs&&"oo"==c._gaUserPrefs)return!0}catch(f){}a=[];b=n.cookie.split(";");c=/^\s*AMP_TOKEN=\s*(.*?)\s*$/;for(var d=0;d<b.length;d++){var e=b[d].match(c);e&&a.push(e[1])}for(b=0;b<a.length;b++)if("$OPT_OUT"==decodeURIComponent(a[b]))return!0;return!1};var q=function(a){return encodeURIComponent?encodeURIComponent(a).replace(/\(/g,"%28").replace(/\)/g,"%29"):a},r=/^(www\.)?google(\.com?)?(\.[a-z]{2})?$/,u=/(^|\.)doubleclick\.net$/i;function Aa(a,b){switch(b){case 0:return""+a;case 1:return 1*a;case 2:return!!a;case 3:return 1E3*a}return a}function Ba(a){return"function"==typeof a}function Ca(a){return void 0!=a&&-1<(a.constructor+"").indexOf("String")}function F(a,b){return void 0==a||"-"==a&&!b||""==a}function Da(a){if(!a||""==a)return"";for(;a&&-1<" \n\r\t".indexOf(a.charAt(0));)a=a.substring(1);for(;a&&-1<" \n\r\t".indexOf(a.charAt(a.length-1));)a=a.substring(0,a.length-1);return a}
function Ea(){return Math.round(2147483647*Math.random())}function Fa(){}function G(a,b){if(encodeURIComponent instanceof Function)return b?encodeURI(a):encodeURIComponent(a);H(68);return escape(a)}function I(a){a=a.split("+").join(" ");if(decodeURIComponent instanceof Function)try{return decodeURIComponent(a)}catch(b){H(17)}else H(68);return unescape(a)}var Ga=function(a,b,c,d){a.addEventListener?a.addEventListener(b,c,!!d):a.attachEvent&&a.attachEvent("on"+b,c)};
function Ia(a,b){if(a){var c=J.createElement("script");c.type="text/javascript";c.async=!0;c.src=a;c.id=b;a=J.getElementsByTagName("script")[0];a.parentNode.insertBefore(c,a);return c}}function K(a){return a&&0<a.length?a[0]:""}function L(a){var b=a?a.length:0;return 0<b?a[b-1]:""}var nf=function(){this.prefix="ga.";this.values={}};nf.prototype.set=function(a,b){this.values[this.prefix+a]=b};nf.prototype.get=function(a){return this.values[this.prefix+a]};
nf.prototype.contains=function(a){return void 0!==this.get(a)};function Ka(a){0==a.indexOf("www.")&&(a=a.substring(4));return a.toLowerCase()}
function La(a,b){var c={url:a,protocol:"http",host:"",path:"",R:new nf,anchor:""};if(!a)return c;var d=a.indexOf("://");0<=d&&(c.protocol=a.substring(0,d),a=a.substring(d+3));d=a.search("/|\\?|#");if(0<=d)c.host=a.substring(0,d).toLowerCase(),a=a.substring(d);else return c.host=a.toLowerCase(),c;d=a.indexOf("#");0<=d&&(c.anchor=a.substring(d+1),a=a.substring(0,d));d=a.indexOf("?");0<=d&&(Na(c.R,a.substring(d+1)),a=a.substring(0,d));c.anchor&&b&&Na(c.R,c.anchor);a&&"/"==a.charAt(0)&&(a=a.substring(1));
c.path=a;return c}
function Oa(a,b){function c(a){var b=(a.hostname||"").split(":")[0].toLowerCase(),c=(a.protocol||"").toLowerCase();c=1*a.port||("http:"==c?80:"https:"==c?443:"");a=a.pathname||"";0==a.indexOf("/")||(a="/"+a);return[b,""+c,a]}b=b||J.createElement("a");b.href=J.location.href;var d=(b.protocol||"").toLowerCase(),e=c(b),f=b.search||"",Be=d+"//"+e[0]+(e[1]?":"+e[1]:"");0==a.indexOf("//")?a=d+a:0==a.indexOf("/")?a=Be+a:a&&0!=a.indexOf("?")?0>a.split("/")[0].indexOf(":")&&(a=Be+e[2].substring(0,e[2].lastIndexOf("/"))+
"/"+a):a=Be+e[2]+(a||f);b.href=a;d=c(b);return{protocol:(b.protocol||"").toLowerCase(),host:d[0],port:d[1],path:d[2],query:b.search||"",url:a||""}}function Na(a,b){function c(b,c){a.contains(b)||a.set(b,[]);a.get(b).push(c)}b=Da(b).split("&");for(var d=0;d<b.length;d++)if(b[d]){var e=b[d].indexOf("=");0>e?c(b[d],"1"):c(b[d].substring(0,e),b[d].substring(e+1))}}
function Pa(a,b){return F(a)||"["==a.charAt(0)&&"]"==a.charAt(a.length-1)?"-":a.indexOf(J.domain+(b&&"/"!=b?b:""))==(0==a.indexOf("http://")?7:0==a.indexOf("https://")?8:0)?"0":a};var Qa=0;function Ra(a,b,c){1<=Qa||1<=100*Math.random()||ld()||(a=["utmt=error","utmerr="+a,"utmwv=5.7.2","utmn="+Ea(),"utmsp=1"],b&&a.push("api="+b),c&&a.push("msg="+G(c.substring(0,100))),M.w&&a.push("aip=1"),Sa(a.join("&")),Qa++)};var Ta=0,Ua={};function N(a){return Va("x"+Ta++,a)}function Va(a,b){Ua[a]=!!b;return a}
var Wa=N(),Xa=Va("anonymizeIp"),Ya=N(),$a=N(),ab=N(),bb=N(),O=N(),P=N(),cb=N(),db=N(),eb=N(),fb=N(),gb=N(),hb=N(),ib=N(),jb=N(),kb=N(),lb=N(),nb=N(),ob=N(),pb=N(),qb=N(),rb=N(),sb=N(),tb=N(),ub=N(),vb=N(),wb=N(),xb=N(),yb=N(),zb=N(),Ab=N(),Bb=N(),Cb=N(),Db=N(),Eb=N(),Fb=N(!0),Gb=Va("currencyCode"),v=Va("storeGac"),Hb=Va("page"),Ib=Va("title"),Jb=N(),Kb=N(),Lb=N(),Mb=N(),Nb=N(),Ob=N(),Pb=N(),Qb=N(),Rb=N(),Q=N(!0),Sb=N(!0),Tb=N(!0),Ub=N(!0),Vb=N(!0),Wb=N(!0),Zb=N(!0),$b=N(!0),ac=N(!0),bc=N(!0),cc=N(!0),
R=N(!0),dc=N(!0),ec=N(!0),fc=N(!0),gc=N(!0),hc=N(!0),ic=N(!0),jc=N(!0),S=N(!0),kc=N(!0),lc=N(!0),mc=N(!0),nc=N(!0),oc=N(!0),pc=N(!0),qc=N(!0),rc=Va("campaignParams"),sc=N(),tc=Va("hitCallback"),uc=N();N();var vc=N(),wc=N(),xc=N(),yc=N(),zc=N(),Ac=N(),Bc=N(),Cc=N(),Dc=N(),Ec=N(),Fc=N(),Gc=N(),Hc=N(),Ic=N();N();
var Mc=N(),Nc=N(),Yb=N(),Jc=N(),Kc=N(),Lc=Va("utmtCookieName"),Cd=Va("displayFeatures"),Oc=N(),of=Va("gtmid"),Oe=Va("uaName"),Pe=Va("uaDomain"),Qe=Va("uaPath"),pf=Va("linkid"),w=N(),x=N(),y=N(),z=N();var Re=function(){function a(a,c,d){T(qf.prototype,a,c,d)}a("_createTracker",qf.prototype.hb,55);a("_getTracker",qf.prototype.oa,0);a("_getTrackerByName",qf.prototype.u,51);a("_getTrackers",qf.prototype.pa,130);a("_anonymizeIp",qf.prototype.aa,16);a("_forceSSL",qf.prototype.la,125);a("_getPlugin",Pc,120)},Se=function(){function a(a,c,d){T(U.prototype,a,c,d)}Qc("_getName",$a,58);Qc("_getAccount",Wa,64);Qc("_visitCode",Q,54);Qc("_getClientInfo",ib,53,1);Qc("_getDetectTitle",lb,56,1);Qc("_getDetectFlash",
jb,65,1);Qc("_getLocalGifPath",wb,57);Qc("_getServiceMode",xb,59);V("_setClientInfo",ib,66,2);V("_setAccount",Wa,3);V("_setNamespace",Ya,48);V("_setAllowLinker",fb,11,2);V("_setDetectFlash",jb,61,2);V("_setDetectTitle",lb,62,2);V("_setLocalGifPath",wb,46,0);V("_setLocalServerMode",xb,92,void 0,0);V("_setRemoteServerMode",xb,63,void 0,1);V("_setLocalRemoteServerMode",xb,47,void 0,2);V("_setSampleRate",vb,45,1);V("_setCampaignTrack",kb,36,2);V("_setAllowAnchor",gb,7,2);V("_setCampNameKey",ob,41);V("_setCampContentKey",
tb,38);V("_setCampIdKey",nb,39);V("_setCampMediumKey",rb,40);V("_setCampNOKey",ub,42);V("_setCampSourceKey",qb,43);V("_setCampTermKey",sb,44);V("_setCampCIdKey",pb,37);V("_setCookiePath",P,9,0);V("_setMaxCustomVariables",yb,0,1);V("_setVisitorCookieTimeout",cb,28,1);V("_setSessionCookieTimeout",db,26,1);V("_setCampaignCookieTimeout",eb,29,1);V("_setReferrerOverride",Jb,49);V("_setSiteSpeedSampleRate",Dc,132);V("_storeGac",v,143);a("_trackPageview",U.prototype.Fa,1);a("_trackEvent",U.prototype.F,4);
a("_trackPageLoadTime",U.prototype.Ea,100);a("_trackSocial",U.prototype.Ga,104);a("_trackTrans",U.prototype.Ia,18);a("_sendXEvent",U.prototype.ib,78);a("_createEventTracker",U.prototype.ia,74);a("_getVersion",U.prototype.qa,60);a("_setDomainName",U.prototype.B,6);a("_setAllowHash",U.prototype.va,8);a("_getLinkerUrl",U.prototype.na,52);a("_link",U.prototype.link,101);a("_linkByPost",U.prototype.ua,102);a("_setTrans",U.prototype.za,20);a("_addTrans",U.prototype.$,21);a("_addItem",U.prototype.Y,19);
a("_clearTrans",U.prototype.ea,105);a("_setTransactionDelim",U.prototype.Aa,82);a("_setCustomVar",U.prototype.wa,10);a("_deleteCustomVar",U.prototype.ka,35);a("_getVisitorCustomVar",U.prototype.ra,50);a("_setXKey",U.prototype.Ca,83);a("_setXValue",U.prototype.Da,84);a("_getXKey",U.prototype.sa,76);a("_getXValue",U.prototype.ta,77);a("_clearXKey",U.prototype.fa,72);a("_clearXValue",U.prototype.ga,73);a("_createXObj",U.prototype.ja,75);a("_addIgnoredOrganic",U.prototype.W,15);a("_clearIgnoredOrganic",
U.prototype.ba,97);a("_addIgnoredRef",U.prototype.X,31);a("_clearIgnoredRef",U.prototype.ca,32);a("_addOrganic",U.prototype.Z,14);a("_clearOrganic",U.prototype.da,70);a("_cookiePathCopy",U.prototype.ha,30);a("_get",U.prototype.ma,106);a("_set",U.prototype.xa,107);a("_addEventListener",U.prototype.addEventListener,108);a("_removeEventListener",U.prototype.removeEventListener,109);a("_addDevId",U.prototype.V);a("_getPlugin",Pc,122);a("_setPageGroup",U.prototype.ya,126);a("_trackTiming",U.prototype.Ha,
124);a("_initData",U.prototype.initData,2);a("_setVar",U.prototype.Ba,22);V("_setSessionTimeout",db,27,3);V("_setCookieTimeout",eb,25,3);V("_setCookiePersistence",cb,24,1);a("_setAutoTrackOutbound",Fa,79);a("_setTrackOutboundSubdomains",Fa,81);a("_setHrefExamineLimit",Fa,80)};function Pc(a){var b=this.plugins_;if(b)return b.get(a)}
var T=function(a,b,c,d){a[b]=function(){try{return void 0!=d&&H(d),c.apply(this,arguments)}catch(e){throw Ra("exc",b,e&&e.name),e;}}},Qc=function(a,b,c,d){U.prototype[a]=function(){try{return H(c),Aa(this.a.get(b),d)}catch(e){throw Ra("exc",a,e&&e.name),e;}}},V=function(a,b,c,d,e){U.prototype[a]=function(f){try{H(c),void 0==e?this.a.set(b,Aa(f,d)):this.a.set(b,e)}catch(Be){throw Ra("exc",a,Be&&Be.name),Be;}}},Te=function(a,b){return{type:b,target:a,stopPropagation:function(){throw"aborted";}}};var Rc=new RegExp(/(^|\.)doubleclick\.net$/i),Sc=function(a,b){return Rc.test(J.location.hostname)?!0:"/"!==b?!1:0!=a.indexOf("www.google.")&&0!=a.indexOf(".google.")&&0!=a.indexOf("google.")||-1<a.indexOf("google.org")?!1:!0},Tc=function(a){var b=a.get(bb),c=a.c(P,"/");Sc(b,c)&&a.stopPropagation()};var Zc=function(){var a={},b={},c=new Uc;this.g=function(a,b){c.add(a,b)};var d=new Uc;this.v=function(a,b){d.add(a,b)};var e=!1,f=!1,Be=!0;this.T=function(){e=!0};this.j=function(a){this.load();this.set(sc,a,!0);a=new Vc(this);e=!1;d.cb(this);e=!0;b={};this.store();a.Ja()};this.load=function(){e&&(e=!1,this.Ka(),Wc(this),f||(f=!0,c.cb(this),Xc(this),Wc(this)),e=!0)};this.store=function(){e&&(f?(e=!1,Xc(this),e=!0):this.load())};this.get=function(c){Ua[c]&&this.load();return void 0!==b[c]?b[c]:a[c]};
this.set=function(c,d,e){Ua[c]&&this.load();e?b[c]=d:a[c]=d;Ua[c]&&this.store()};this.Za=function(b){a[b]=this.b(b,0)+1};this.b=function(a,b){a=this.get(a);return void 0==a||""===a?b:1*a};this.c=function(a,b){a=this.get(a);return void 0==a?b:a+""};this.Ka=function(){if(Be){var b=this.c(bb,""),c=this.c(P,"/");Sc(b,c)||(a[O]=a[hb]&&""!=b?Yc(b):1,Be=!1)}}};Zc.prototype.stopPropagation=function(){throw"aborted";};
var Vc=function(a){var b=this;this.fb=0;var c=a.get(tc);this.Ua=function(){0<b.fb&&c&&(b.fb--,b.fb||c())};this.Ja=function(){!b.fb&&c&&setTimeout(c,10)};a.set(uc,b,!0)};function $c(a,b){b=b||[];for(var c=0;c<b.length;c++){var d=b[c];if(""+a==d||0==d.indexOf(a+"."))return d}return"-"}
var bd=function(a,b,c){c=c?"":a.c(O,"1");b=b.split(".");if(6!==b.length||ad(b[0],c))return!1;c=1*b[1];var d=1*b[2],e=1*b[3],f=1*b[4];b=1*b[5];if(!(0<=c&&0<d&&0<e&&0<f&&0<=b))return!1;a.set(Q,c);a.set(Vb,d);a.set(Wb,e);a.set(Zb,f);a.set($b,b);return!0},cd=function(a){var b=a.get(Q),c=a.get(Vb),d=a.get(Wb),e=a.get(Zb),f=a.b($b,1);return[a.b(O,1),void 0!=b?b:"-",c||"-",d||"-",e||"-",f].join(".")},dd=function(a){return[a.b(O,1),a.b(cc,0),a.b(R,1),a.b(dc,0)].join(".")},ed=function(a,b,c){c=c?"":a.c(O,
"1");var d=b.split(".");if(4!==d.length||ad(d[0],c))d=null;a.set(cc,d?1*d[1]:0);a.set(R,d?1*d[2]:10);a.set(dc,d?1*d[3]:a.get(ab));return null!=d||!ad(b,c)},fd=function(a,b){var c=G(a.c(Tb,"")),d=[],e=a.get(Fb);if(!b&&e){for(b=0;b<e.length;b++){var f=e[b];f&&1==f.scope&&d.push(b+"="+G(f.name)+"="+G(f.value)+"=1")}0<d.length&&(c+="|"+d.join("^"))}return c?a.b(O,1)+"."+c:null},gd=function(a,b,c){c=c?"":a.c(O,"1");b=b.split(".");if(2>b.length||ad(b[0],c))return!1;b=b.slice(1).join(".").split("|");0<b.length&&
a.set(Tb,I(b[0]));if(1>=b.length)return!0;b=b[1].split(-1==b[1].indexOf(",")?"^":",");for(c=0;c<b.length;c++){var d=b[c].split("=");if(4==d.length){var e={};e.name=I(d[1]);e.value=I(d[2]);e.scope=1;a.get(Fb)[d[0]]=e}}return!0},hd=function(a,b){return(b=Ue(a,b))?[a.b(O,1),a.b(ec,0),a.b(fc,1),a.b(gc,1),b].join("."):""},Ue=function(a){function b(b,e){F(a.get(b))||(b=a.c(b,""),b=b.split(" ").join("%20"),b=b.split("+").join("%20"),c.push(e+"="+b))}var c=[];b(ic,"utmcid");b(nc,"utmcsr");b(S,"utmgclid");
b(kc,"utmgclsrc");b(lc,"utmdclid");b(mc,"utmdsid");b(jc,"utmccn");b(oc,"utmcmd");b(pc,"utmctr");b(qc,"utmcct");return c.join("|")},id=function(a,b,c){c=c?"":a.c(O,"1");b=b.split(".");if(5>b.length||ad(b[0],c))return a.set(ec,void 0),a.set(fc,void 0),a.set(gc,void 0),a.set(ic,void 0),a.set(jc,void 0),a.set(nc,void 0),a.set(oc,void 0),a.set(pc,void 0),a.set(qc,void 0),a.set(S,void 0),a.set(kc,void 0),a.set(lc,void 0),a.set(mc,void 0),!1;a.set(ec,1*b[1]);a.set(fc,1*b[2]);a.set(gc,1*b[3]);Ve(a,b.slice(4).join("."));
return!0},Ve=function(a,b){function c(a){return(a=b.match(a+"=(.*?)(?:\\|utm|$)"))&&2==a.length?a[1]:void 0}function d(b,c){c?(c=e?I(c):c.split("%20").join(" "),a.set(b,c)):a.set(b,void 0)}-1==b.indexOf("=")&&(b=I(b));var e="2"==c("utmcvr");d(ic,c("utmcid"));d(jc,c("utmccn"));d(nc,c("utmcsr"));d(oc,c("utmcmd"));d(pc,c("utmctr"));d(qc,c("utmcct"));d(S,c("utmgclid"));d(kc,c("utmgclsrc"));d(lc,c("utmdclid"));d(mc,c("utmdsid"))},ad=function(a,b){return b?a!=b:!/^\d+$/.test(a)};var Uc=function(){this.filters=[]};Uc.prototype.add=function(a,b){this.filters.push({name:a,s:b})};Uc.prototype.cb=function(a){try{for(var b=0;b<this.filters.length;b++)this.filters[b].s.call(W,a)}catch(c){}};function jd(a){100!=a.get(vb)&&a.get(Q)%1E4>=100*a.get(vb)&&a.stopPropagation()}function kd(a){ld(a.get(Wa))&&a.stopPropagation()}function md(a){"file:"==J.location.protocol&&a.stopPropagation()}function Ge(a){He()&&a.stopPropagation()}
function nd(a){a.get(Ib)||a.set(Ib,J.title,!0);a.get(Hb)||a.set(Hb,J.location.pathname+J.location.search,!0)}function lf(a){a.get(Wa)&&"UA-XXXXX-X"!=a.get(Wa)||a.stopPropagation()};var od=new function(){var a=[];this.set=function(b){a[b]=!0};this.encode=function(){for(var b=[],c=0;c<a.length;c++)a[c]&&(b[Math.floor(c/6)]^=1<<c%6);for(c=0;c<b.length;c++)b[c]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".charAt(b[c]||0);return b.join("")+"~"}};function H(a){od.set(a)};var W=window,J=document,ld=function(a){var b=W._gaUserPrefs;if(b&&b.ioo&&b.ioo()||a&&!0===W["ga-disable-"+a])return!0;try{var c=W.external;if(c&&c._gaUserPrefs&&"oo"==c._gaUserPrefs)return!0}catch(d){}return!1},He=function(){return W.navigator&&"preview"==W.navigator.loadPurpose},We=function(a,b){setTimeout(a,b)},pd=function(a){var b=[],c=J.cookie.split(";");a=new RegExp("^\\s*"+a+"=\\s*(.*?)\\s*$");for(var d=0;d<c.length;d++){var e=c[d].match(a);e&&b.push(e[1])}return b},X=function(a,b,c,d,e,f){e=
ld(e)?!1:Sc(d,c)?!1:He()?!1:!0;e&&((b=mf(b))&&2E3<b.length&&(b=b.substring(0,2E3),H(69)),a=a+"="+b+"; path="+c+"; ",f&&(a+="expires="+(new Date((new Date).getTime()+f)).toGMTString()+"; "),d&&(a+="domain="+d+";"),J.cookie=a)},mf=function(a){if(!a)return a;var b=a.indexOf(";");-1!=b&&(a=a.substring(0,b),H(141));if(!(0<=W.navigator.userAgent.indexOf("Firefox")))return a;a=a.replace(/\n|\r/g," ");b=0;for(var c=a.length;b<c;++b){var d=a.charCodeAt(b)&255;if(10==d||13==d)a=a.substring(0,b)+"?"+a.substring(b+
1)}return a};var A,B=/^.*Version\/?(\d+)[^\d].*$/i;var qd,rd,sd=function(){if(!qd){var a={},b=W.navigator,c=W.screen;a.jb=c?c.width+"x"+c.height:"-";a.P=c?c.colorDepth+"-bit":"-";a.language=(b&&(b.language||b.browserLanguage)||"-").toLowerCase();a.javaEnabled=b&&b.javaEnabled()?1:0;a.characterSet=J.characterSet||J.charset||"-";try{var d=J.documentElement,e=J.body,f=e&&e.clientWidth&&e.clientHeight;b=[];d&&d.clientWidth&&d.clientHeight&&("CSS1Compat"===J.compatMode||!f)?b=[d.clientWidth,d.clientHeight]:f&&(b=[e.clientWidth,e.clientHeight]);var Be=
0>=b[0]||0>=b[1]?"":b.join("x");a.Wa=Be}catch(k){H(135)}qd=a}},td=function(){sd();var a=qd,b=W.navigator;a=b.appName+b.version+a.language+b.platform+b.userAgent+a.javaEnabled+a.jb+a.P+(J.cookie?J.cookie:"")+(J.referrer?J.referrer:"");b=a.length;for(var c=W.history.length;0<c;)a+=c--^b++;return Yc(a)},ud=function(a){sd();var b=qd;a.set(Lb,b.jb);a.set(Mb,b.P);a.set(Pb,b.language);a.set(Qb,b.characterSet);a.set(Nb,b.javaEnabled);a.set(Rb,b.Wa);if(a.get(ib)&&a.get(jb)){if(!(b=rd)){var c,d;var e="ShockwaveFlash";
if((b=(b=W.navigator)?b.plugins:void 0)&&0<b.length)for(c=0;c<b.length&&!d;c++)e=b[c],-1<e.name.indexOf("Shockwave Flash")&&(d=e.description.split("Shockwave Flash ")[1]);else{e=e+"."+e;try{c=new ActiveXObject(e+".7"),d=c.GetVariable("$version")}catch(f){}if(!d)try{c=new ActiveXObject(e+".6"),d="WIN 6,0,21,0",c.AllowScriptAccess="always",d=c.GetVariable("$version")}catch(f){}if(!d)try{c=new ActiveXObject(e),d=c.GetVariable("$version")}catch(f){}d&&(d=d.split(" ")[1].split(","),d=d[0]+"."+d[1]+" r"+
d[2])}b=d?d:"-"}rd=b;a.set(Ob,rd)}else a.set(Ob,"-")};var vd=function(a){if(Ba(a))this.s=a;else{var b=a[0],c=b.lastIndexOf(":"),d=b.lastIndexOf(".");this.h=this.i=this.l="";-1==c&&-1==d?this.h=b:-1==c&&-1!=d?(this.i=b.substring(0,d),this.h=b.substring(d+1)):-1!=c&&-1==d?(this.l=b.substring(0,c),this.h=b.substring(c+1)):c>d?(this.i=b.substring(0,d),this.l=b.substring(d+1,c),this.h=b.substring(c+1)):(this.i=b.substring(0,d),this.h=b.substring(d+1));this.Xa=a.slice(1);this.Ma=!this.l&&"_require"==this.h;this.J=!this.i&&!this.l&&"_provide"==this.h}},Y=function(){T(Y.prototype,
"push",Y.prototype.push,5);T(Y.prototype,"_getPlugin",Pc,121);T(Y.prototype,"_createAsyncTracker",Y.prototype.Sa,33);T(Y.prototype,"_getAsyncTracker",Y.prototype.Ta,34);this.I=new nf;this.eb=[]};E=Y.prototype;E.Na=function(a,b,c){var d=this.I.get(a);if(!Ba(d))return!1;b.plugins_=b.plugins_||new nf;b.plugins_.set(a,new d(b,c||{}));return!0};E.push=function(a){var b=Z.Va.apply(this,arguments);b=Z.eb.concat(b);for(Z.eb=[];0<b.length&&!Z.O(b[0])&&!(b.shift(),0<Z.eb.length););Z.eb=Z.eb.concat(b);return 0};
E.Va=function(a){for(var b=[],c=0;c<arguments.length;c++)try{var d=new vd(arguments[c]);d.J?this.O(d):b.push(d)}catch(e){}return b};
E.O=function(a){try{if(a.s)a.s.apply(W);else if(a.J)this.I.set(a.Xa[0],a.Xa[1]);else{var b="_gat"==a.i?M:"_gaq"==a.i?Z:M.u(a.i);if(a.Ma){if(!this.Na(a.Xa[0],b,a.Xa[2])){if(!a.Pa){var c=Oa(""+a.Xa[1]);var d=c.protocol,e=J.location.protocol;var f;if(f="https:"==d||d==e?!0:"http:"!=d?!1:"http:"==e)a:{var Be=Oa(J.location.href);if(!(c.query||0<=c.url.indexOf("?")||0<=c.path.indexOf("://")||c.host==Be.host&&c.port==Be.port)){var k="http:"==c.protocol?80:443,Ja=M.S;for(b=0;b<Ja.length;b++)if(c.host==Ja[b][0]&&
(c.port||k)==(Ja[b][1]||k)&&0==c.path.indexOf(Ja[b][2])){f=!0;break a}}f=!1}f&&!ld()&&(a.Pa=Ia(c.url))}return!0}}else a.l&&(b=b.plugins_.get(a.l)),b[a.h].apply(b,a.Xa)}}catch(t){}};E.Sa=function(a,b){return M.hb(a,b||"")};E.Ta=function(a){return M.u(a)};var yd=function(){function a(a,b,c,d){void 0==f[a]&&(f[a]={});void 0==f[a][b]&&(f[a][b]=[]);f[a][b][c]=d}function b(a,b,c){if(void 0!=f[a]&&void 0!=f[a][b])return f[a][b][c]}function c(a,b){if(void 0!=f[a]&&void 0!=f[a][b]){f[a][b]=void 0;b=!0;var c;for(c=0;c<Be.length;c++)if(void 0!=f[a][Be[c]]){b=!1;break}b&&(f[a]=void 0)}}function d(a){var b="",c=!1,d;for(d=0;d<Be.length;d++){var e=a[Be[d]];if(void 0!=e){c&&(b+=Be[d]);var f=e,Ja=[];for(e=0;e<f.length;e++)if(void 0!=f[e]){c="";1!=e&&void 0==f[e-
1]&&(c+=e.toString()+"!");var fa,Ke=f[e],Le="";for(fa=0;fa<Ke.length;fa++){var Me=Ke.charAt(fa);var m=k[Me];Le+=void 0!=m?m:Me}c+=Le;Ja.push(c)}b+="("+Ja.join("*")+")";c=!1}else c=!0}return b}var e=this,f=[],Be=["k","v"],k={"'":"'0",")":"'1","*":"'2","!":"'3"};e.Ra=function(a){return void 0!=f[a]};e.A=function(){for(var a="",b=0;b<f.length;b++)void 0!=f[b]&&(a+=b.toString()+d(f[b]));return a};e.Qa=function(a){if(void 0==a)return e.A();for(var b=a.A(),c=0;c<f.length;c++)void 0==f[c]||a.Ra(c)||(b+=
c.toString()+d(f[c]));return b};e.f=function(b,c,d){if(!wd(d))return!1;a(b,"k",c,d);return!0};e.o=function(b,c,d){if(!xd(d))return!1;a(b,"v",c,d.toString());return!0};e.getKey=function(a,c){return b(a,"k",c)};e.N=function(a,c){return b(a,"v",c)};e.L=function(a){c(a,"k")};e.M=function(a){c(a,"v")};T(e,"_setKey",e.f,89);T(e,"_setValue",e.o,90);T(e,"_getKey",e.getKey,87);T(e,"_getValue",e.N,88);T(e,"_clearKey",e.L,85);T(e,"_clearValue",e.M,86)};function wd(a){return"string"==typeof a}
function xd(a){return!("number"==typeof a||void 0!=Number&&a instanceof Number)||Math.round(a)!=a||isNaN(a)||Infinity==a?!1:!0};var zd=function(a){var b=W.gaGlobal;a&&!b&&(W.gaGlobal=b={});return b},Ad=function(){var a=zd(!0).hid;null==a&&(a=Ea(),zd(!0).hid=a);return a},Dd=function(a){a.set(Kb,Ad());var b=zd();if(b&&b.dh==a.get(O)){var c=b.sid;c&&(a.get(ac)?H(112):H(132),a.set(Zb,c),a.get(Sb)&&a.set(Wb,c));b=b.vid;a.get(Sb)&&b&&(b=b.split("."),a.set(Q,1*b[0]),a.set(Vb,1*b[1]))}};var Ed,Fd=function(a,b,c,d){var e=a.c(bb,""),f=a.c(P,"/");d=void 0!=d?d:a.b(cb,0);a=a.c(Wa,"");X(b,c,f,e,a,d)},Xc=function(a){var b=a.c(bb,""),c=a.c(P,"/"),d=a.c(Wa,"");X("__utma",cd(a),c,b,d,a.get(cb));X("__utmb",dd(a),c,b,d,a.get(db));X("__utmc",""+a.b(O,1),c,b,d);var e=hd(a,!0);e?X("__utmz",e,c,b,d,a.get(eb)):X("__utmz","",c,b,"",-1);(e=fd(a,!1))?X("__utmv",e,c,b,d,a.get(cb)):X("__utmv","",c,b,"",-1);if(1==a.get(v)&&(e=a.get(w))){var f=a.get(x);b=a.c(bb,"");c=a.c(P,"/");d=a.c(Wa,"");var Be=a.b(y,
0);a=Math.min(a.b(cb,7776E6),a.b(eb,7776E6),7776E6);a=Math.min(a,1E3*Be+a-(new Date).getTime());if(!f||"aw.ds"==f)if(f=["1",Be+"",q(e)].join("."),0<a&&(e="_gac_"+q(d),!(p(d)||u.test(J.location.hostname)||"/"==c&&r.test(b))&&((d=f)&&1200<d.length&&(d=d.substring(0,1200)),c=e+"="+d+"; path="+c+"; ",a&&(c+="expires="+(new Date((new Date).getTime()+a)).toGMTString()+"; "),b&&"none"!==b&&(c+="domain="+b+";"),b=J.cookie,J.cookie=c,b==J.cookie)))for(b=[],c=J.cookie.split(";"),a=new RegExp("^\\s*"+e+"=\\s*(.*?)\\s*$"),
d=0;d<c.length;d++)(e=c[d].match(a))&&b.push(e[1])}},Wc=function(a){var b=a.b(O,1);if(!bd(a,$c(b,pd("__utma"))))return a.set(Ub,!0),!1;var c=!ed(a,$c(b,pd("__utmb")));a.set(bc,c);id(a,$c(b,pd("__utmz")));gd(a,$c(b,pd("__utmv")));if(1==a.get(v)){b=a.get(w);var d=a.get(x);if(!b||d&&"aw.ds"!=d){if(J){b=[];d=J.cookie.split(";");for(var e=/^\s*_gac_(UA-\d+-\d+)=\s*(.+?)\s*$/,f=0;f<d.length;f++){var Be=d[f].match(e);Be&&b.push({Oa:Be[1],value:Be[2]})}d={};if(b&&b.length)for(e=0;e<b.length;e++)f=b[e].value.split("."),
"1"==f[0]&&3==f.length&&f[1]&&(d[b[e].Oa]||(d[b[e].Oa]=[]),d[b[e].Oa].push({timestamp:f[1],kb:f[2]}));b=d}else b={};(b=b[a.get(Wa)])&&0<b.length&&(b=b[0],a.set(y,b.timestamp),a.set(w,b.kb),a.set(x,void 0))}}Ed=!c;return!0},Gd=function(a){Ed||0<pd("__utmb").length||(X("__utmd","1",a.c(P,"/"),a.c(bb,""),a.c(Wa,""),1E4),0==pd("__utmd").length&&a.stopPropagation())};var h=0,Jd=function(a){void 0==a.get(Q)?Hd(a):a.get(Ub)&&!a.get(Mc)?Hd(a):a.get(bc)&&Id(a)},Kd=function(a){a.get(hc)&&!a.get(ac)&&(Id(a),a.set(fc,a.get($b)))},Hd=function(a){h++;1<h&&H(137);var b=a.get(ab);a.set(Sb,!0);a.set(Q,Ea()^td(a)&2147483647);a.set(Tb,"");a.set(Vb,b);a.set(Wb,b);a.set(Zb,b);a.set($b,1);a.set(ac,!0);a.set(cc,0);a.set(R,10);a.set(dc,b);a.set(Fb,[]);a.set(Ub,!1);a.set(bc,!1)},Id=function(a){h++;1<h&&H(137);a.set(Wb,a.get(Zb));a.set(Zb,a.get(ab));a.Za($b);a.set(ac,!0);a.set(cc,
0);a.set(R,10);a.set(dc,a.get(ab));a.set(bc,!1)};var Ld="daum:q eniro:search_word naver:query pchome:q images.google:q google:q yahoo:p yahoo:q msn:q bing:q aol:query aol:q lycos:q lycos:query ask:q cnn:query virgilio:qs baidu:wd baidu:word alice:qs yandex:text najdi:q seznam:q rakuten:qt biglobe:q goo.ne:MT search.smt.docomo:MT onet:qt onet:q kvasir:q terra:query rambler:query conduit:q babylon:q search-results:q avg:q comcast:q incredimail:q startsiden:q go.mail.ru:q centrum.cz:q 360.cn:q sogou:query tut.by:query globo:q ukr:q so.com:q haosou.com:q auone:q".split(" "),
Sd=function(a){if(a.get(kb)&&!a.get(Mc)){var b=!F(a.get(ic))||!F(a.get(nc))||!F(a.get(S))||!F(a.get(lc));for(var c={},d=0;d<Md.length;d++){var e=Md[d];c[e]=a.get(e)}(d=a.get(rc))?(H(149),e=new nf,Na(e,d),d=e):d=La(J.location.href,a.get(gb)).R;if("1"!=L(d.get(a.get(ub)))||!b)if(d=Xe(a,d)||Qd(a),d||b||!a.get(ac)||(Pd(a,void 0,"(direct)",void 0,void 0,void 0,"(direct)","(none)",void 0,void 0),d=!0),d&&(a.set(hc,Rd(a,c)),b="(direct)"==a.get(nc)&&"(direct)"==a.get(jc)&&"(none)"==a.get(oc),a.get(hc)||a.get(ac)&&
!b))a.set(ec,a.get(ab)),a.set(fc,a.get($b)),a.Za(gc)}},Xe=function(a,b){function c(c,d){d=d||"-";return(c=L(b.get(a.get(c))))&&"-"!=c?I(c):d}var d=L(b.get(a.get(nb)))||"-",e=L(b.get(a.get(qb)))||"-",f=L(b.get(a.get(pb)))||"-",Be=L(b.get("gclsrc"))||"-",k=L(b.get("dclid"))||"-";"-"!=f&&a.set(w,f);"-"!=Be&&a.set(x,Be);var Ja=c(ob,"(not set)"),t=c(rb,"(not set)"),Za=c(sb),Ma=c(tb);if(F(d)&&F(f)&&F(k)&&F(e))return!1;var mb=!F(f)&&!F(Be);mb=F(e)&&(!F(k)||mb);var Xb=F(Za);if(mb||Xb){var Bd=Nd(a);Bd=La(Bd,
!0);(Bd=Od(a,Bd))&&!F(Bd[1]&&!Bd[2])&&(mb&&(e=Bd[0]),Xb&&(Za=Bd[1]))}Pd(a,d,e,f,Be,k,Ja,t,Za,Ma);return!0},Qd=function(a){var b=Nd(a),c=La(b,!0);(b=!(void 0!=b&&null!=b&&""!=b&&"0"!=b&&"-"!=b&&0<=b.indexOf("://")))||(b=c&&-1<c.host.indexOf("google")&&c.R.contains("q")&&"cse"==c.path);if(b)return!1;if((b=Od(a,c))&&!b[2])return Pd(a,void 0,b[0],void 0,void 0,void 0,"(organic)","organic",b[1],void 0),!0;if(b||!a.get(ac))return!1;a:{b=a.get(Bb);for(var d=Ka(c.host),e=0;e<b.length;++e)if(-1<d.indexOf(b[e])){a=
!1;break a}Pd(a,void 0,d,void 0,void 0,void 0,"(referral)","referral",void 0,"/"+c.path);a=!0}return a},Od=function(a,b){for(var c=a.get(zb),d=0;d<c.length;++d){var e=c[d].split(":");if(-1<b.host.indexOf(e[0].toLowerCase())){var f=b.R.get(e[1]);if(f&&(f=K(f),!f&&-1<b.host.indexOf("google.")&&(f="(not provided)"),!e[3]||-1<b.url.indexOf(e[3]))){f||H(151);a:{b=f;a=a.get(Ab);b=I(b).toLowerCase();for(c=0;c<a.length;++c)if(b==a[c]){a=!0;break a}a=!1}return[e[2]||e[0],f,a]}}}return null},Pd=function(a,
b,c,d,e,f,Be,k,Ja,t){a.set(ic,b);a.set(nc,c);a.set(S,d);a.set(kc,e);a.set(lc,f);a.set(jc,Be);a.set(oc,k);a.set(pc,Ja);a.set(qc,t)},Md=[jc,ic,S,lc,nc,oc,pc,qc],Rd=function(a,b){function c(a){a=(""+a).split("+").join("%20");return a=a.split(" ").join("%20")}function d(c){var d=""+(a.get(c)||"");c=""+(b[c]||"");return 0<d.length&&d==c}if(d(S)||d(lc))return H(131),!1;for(var e=0;e<Md.length;e++){var f=Md[e],Be=b[f]||"-";f=a.get(f)||"-";if(c(Be)!=c(f))return!0}return!1},Td=new RegExp(/^https?:\/\/(www\.)?google(\.com?)?(\.[a-z]{2}t?)?\/?$/i),
jf=/^https?:\/\/(r\.)?search\.yahoo\.com?(\.jp)?\/?[^?]*$/i,rf=/^https?:\/\/(www\.)?bing\.com\/?$/i,Nd=function(a){a=Pa(a.get(Jb),a.get(P));try{if(Td.test(a))return H(136),a+"?q=";if(jf.test(a))return H(150),a+"?p=(not provided)";if(rf.test(a))return a+"?q=(not provided)"}catch(b){H(145)}return a};var Ud,Vd,Wd=function(a){Ud=a.c(S,"");Vd=a.c(kc,"")},Xd=function(a){var b=a.c(S,""),c=a.c(kc,"");b!=Ud&&(-1<c.indexOf("ds")?a.set(mc,void 0):!F(Ud)&&-1<Vd.indexOf("ds")&&a.set(mc,Ud))};var Zd=function(a){Yd(a,J.location.href)?(a.set(Mc,!0),H(12)):a.set(Mc,!1)},Yd=function(a,b){if(!a.get(fb))return!1;var c=La(b,a.get(gb));b=K(c.R.get("__utma"));var d=K(c.R.get("__utmb")),e=K(c.R.get("__utmc")),f=K(c.R.get("__utmx")),Be=K(c.R.get("__utmz")),k=K(c.R.get("__utmv"));c=K(c.R.get("__utmk"));if(Yc(""+b+d+e+f+Be+k)!=c){b=I(b);d=I(d);e=I(e);f=I(f);e=$d(b+d+e+f,Be,k,c);if(!e)return!1;Be=e[0];k=e[1]}if(!bd(a,b,!0))return!1;ed(a,d,!0);id(a,Be,!0);gd(a,k,!0);ae(a,f,!0);return!0},ce=function(a,
b,c){var d=cd(a)||"-";var e=dd(a)||"-",f=""+a.b(O,1)||"-",Be=be(a)||"-",k=hd(a,!1)||"-";a=fd(a,!1)||"-";var Ja=Yc(""+d+e+f+Be+k+a),t=[];t.push("__utma="+d);t.push("__utmb="+e);t.push("__utmc="+f);t.push("__utmx="+Be);t.push("__utmz="+k);t.push("__utmv="+a);t.push("__utmk="+Ja);d=t.join("&");if(!d)return b;e=b.indexOf("#");if(c)return 0>e?b+"#"+d:b+"&"+d;c="";0<e&&(c=b.substring(e),b=b.substring(0,e));return 0>b.indexOf("?")?b+"?"+d+c:b+"&"+d+c},$d=function(a,b,c,d){for(var e=0;3>e;e++){for(var f=
0;3>f;f++){if(d==Yc(a+b+c))return H(127),[b,c];var Be=b.replace(/ /g,"%20"),k=c.replace(/ /g,"%20");if(d==Yc(a+Be+k))return H(128),[Be,k];Be=Be.replace(/\+/g,"%20");k=k.replace(/\+/g,"%20");if(d==Yc(a+Be+k))return H(129),[Be,k];try{var Ja=b.match("utmctr=(.*?)(?:\\|utm|$)");if(Ja&&2==Ja.length&&(Be=b.replace(Ja[1],G(I(Ja[1]))),d==Yc(a+Be+c)))return H(139),[Be,c]}catch(t){}b=I(b)}c=I(c)}};var de="|",fe=function(a,b,c,d,e,f,Be,k,Ja){var t=ee(a,b);t||(t={},a.get(Cb).push(t));t.id_=b;t.affiliation_=c;t.total_=d;t.tax_=e;t.shipping_=f;t.city_=Be;t.state_=k;t.country_=Ja;t.items_=t.items_||[];return t},ge=function(a,b,c,d,e,f,Be){a=ee(a,b)||fe(a,b,"",0,0,0,"","","");a:{if(a&&a.items_){var k=a.items_;for(var Ja=0;Ja<k.length;Ja++)if(k[Ja].sku_==c){k=k[Ja];break a}}k=null}Ja=k||{};Ja.transId_=b;Ja.sku_=c;Ja.name_=d;Ja.category_=e;Ja.price_=f;Ja.quantity_=Be;k||a.items_.push(Ja);return Ja},
ee=function(a,b){a=a.get(Cb);for(var c=0;c<a.length;c++)if(a[c].id_==b)return a[c];return null};var he,ie=function(a){if(!he){var b=J.location.hash;var c=W.name,d=/^#?gaso=([^&]*)/;if(c=(b=(b=b&&b.match(d)||c&&c.match(d))?b[1]:K(pd("GASO")))&&b.match(/^(?:!([-0-9a-z.]{1,40})!)?([-.\w]{10,1200})$/i))Fd(a,"GASO",""+b,0),M._gasoDomain=a.get(bb),M._gasoCPath=a.get(P),a=c[1],Ia("https://www.google.com/analytics/web/inpage/pub/inpage.js?"+(a?"prefix="+a+"&":"")+Ea(),"_gasojs");he=!0}};var ae=function(a,b,c){c&&(b=I(b));c=a.b(O,1);b=b.split(".");2>b.length||!/^\d+$/.test(b[0])||(b[0]=""+c,Fd(a,"__utmx",b.join("."),void 0))},be=function(a,b){a=$c(a.get(O),pd("__utmx"));"-"==a&&(a="");return b?G(a):a},Ye=function(a){try{var b=La(J.location.href,!1),c=decodeURIComponent(L(b.R.get("utm_referrer")))||"";c&&a.set(Jb,c);var d=decodeURIComponent(K(b.R.get("utm_expid")))||"";d&&(d=d.split(".")[0],a.set(Oc,""+d))}catch(e){H(146)}},l=function(a){var b=W.gaData&&W.gaData.expId;b&&a.set(Oc,
""+b)};var ke=function(a,b){var c=Math.min(a.b(Dc,0),100);if(a.b(Q,0)%100>=c)return!1;c=Ze()||$e();if(void 0==c)return!1;var d=c[0];if(void 0==d||Infinity==d||isNaN(d))return!1;0<d?af(c)?b(je(c)):b(je(c.slice(0,1))):Ga(W,"load",function(){ke(a,b)},!1);return!0},me=function(a,b,c,d){var e=new yd;e.f(14,90,b.substring(0,500));e.f(14,91,a.substring(0,150));e.f(14,92,""+le(c));void 0!=d&&e.f(14,93,d.substring(0,500));e.o(14,90,c);return e},af=function(a){for(var b=1;b<a.length;b++)if(isNaN(a[b])||Infinity==
a[b]||0>a[b])return!1;return!0},le=function(a){return isNaN(a)||0>a?0:5E3>a?10*Math.floor(a/10):5E4>a?100*Math.floor(a/100):41E5>a?1E3*Math.floor(a/1E3):41E5},je=function(a){for(var b=new yd,c=0;c<a.length;c++)b.f(14,c+1,""+le(a[c])),b.o(14,c+1,a[c]);return b},Ze=function(){var a=W.performance||W.webkitPerformance;if(a=a&&a.timing){var b=a.navigationStart;if(0==b)H(133);else return[a.loadEventStart-b,a.domainLookupEnd-a.domainLookupStart,a.connectEnd-a.connectStart,a.responseStart-a.requestStart,
a.responseEnd-a.responseStart,a.fetchStart-b,a.domInteractive-b,a.domContentLoadedEventStart-b]}},$e=function(){if(W.top==W){var a=W.external,b=a&&a.onloadT;a&&!a.isValidLoadTime&&(b=void 0);2147483648<b&&(b=void 0);0<b&&a.setPageReadyTime();if(void 0!=b)return[b]}};var cf=function(a){if(a.get(Sb))try{a:{var b=pd(a.get(Oe)||"_ga");if(b&&!(1>b.length)){for(var c=[],d=0;d<b.length;d++){var e=b[d].split("."),f=e.shift();if(("GA1"==f||"1"==f)&&1<e.length){var Be=e.shift().split("-");1==Be.length&&(Be[1]="1");Be[0]*=1;Be[1]*=1;var k={Ya:Be,$a:e.join(".")}}else k=void 0;k&&c.push(k)}if(1==c.length){var Ja=c[0].$a;break a}if(0!=c.length){var t=a.get(Pe)||a.get(bb);c=bf(c,(0==t.indexOf(".")?t.substr(1):t).split(".").length,0);if(1==c.length){Ja=c[0].$a;break a}var Za=
a.get(Qe)||a.get(P);(b=Za)?(1<b.length&&"/"==b.charAt(b.length-1)&&(b=b.substr(0,b.length-1)),0!=b.indexOf("/")&&(b="/"+b),Za=b):Za="/";c=bf(c,"/"==Za?1:Za.split("/").length,1);Ja=c[0].$a;break a}}Ja=void 0}if(Ja){var Ma=(""+Ja).split(".");2==Ma.length&&/[0-9.]/.test(Ma)&&(H(114),a.set(Q,Ma[0]),a.set(Vb,Ma[1]),a.set(Sb,!1))}}catch(mb){H(115)}},bf=function(a,b,c){for(var d=[],e=[],f=128,Be=0;Be<a.length;Be++){var k=a[Be];k.Ya[c]==b?d.push(k):k.Ya[c]==f?e.push(k):k.Ya[c]<f&&(e=[k],f=k.Ya[c])}return 0<
d.length?d:e};var kf=/^gtm\d+$/,hf=function(a){var b=!!a.b(Cd,1);if(b)if(H(140),"page"!=a.get(sc))a.set(Kc,"",!0);else if(b=a.c(Lc,""),b||(b=(b=a.c($a,""))&&"~0"!=b?kf.test(b)?"__utmt_"+G(a.c(Wa,"")):"__utmt_"+G(b):"__utmt"),0<pd(b).length)a.set(Kc,"",!0);else if(X(b,"1",a.c(P,"/"),a.c(bb,""),a.c(Wa,""),6E5),0<pd(b).length){a.set(Kc,Ea(),!0);a.set(Yb,1,!0);if(void 0!==W.__ga4__)b=W.__ga4__;else{if(void 0===A){var c=W.navigator.userAgent;if(c){b=c;try{b=decodeURIComponent(c)}catch(d){}if(c=!(0<=b.indexOf("Chrome"))&&
!(0<=b.indexOf("CriOS"))&&(0<=b.indexOf("Safari/")||0<=b.indexOf("Safari,")))b=B.exec(b),c=11<=(b?Number(b[1]):-1);A=c}else A=!1}b=A}b?(a.set(z,C(a),!0),a.set(Jc,"https://ssl.google-analytics.com/j/__utm.gif",!0)):a.set(Jc,Ne()+"/r/__utm.gif?",!0)}},C=function(a){a=aa(a);return{gb:"t=dc&_r=3&"+a,google:"t=sr&slf_rd=1&_r=4&"+a,count:0}},aa=function(a){function b(a,b){c.push(a+"="+G(b))}var c=[];b("v","1");b("_v","5.7.2");b("tid",a.get(Wa));b("cid",a.get(Q)+"."+a.get(Vb));b("jid",a.get(Kc));b("aip",
"1");return c.join("&")+"&z="+Ea()};var U=function(a,b,c){function d(a){return function(b){if((b=b.get(Nc)[a])&&b.length)for(var c=Te(e,a),d=0;d<b.length;d++)b[d].call(e,c)}}var e=this;this.a=new Zc;this.get=function(a){return this.a.get(a)};this.set=function(a,b,c){this.a.set(a,b,c)};this.set(Wa,b||"UA-XXXXX-X");this.set($a,a||"");this.set(Ya,c||"");this.set(ab,Math.round((new Date).getTime()/1E3));this.set(P,"/");this.set(cb,63072E6);this.set(eb,15768E6);this.set(db,18E5);this.set(fb,!1);this.set(yb,50);this.set(gb,!1);this.set(hb,
!0);this.set(ib,!0);this.set(jb,!0);this.set(kb,!0);this.set(lb,!0);this.set(ob,"utm_campaign");this.set(nb,"utm_id");this.set(pb,"gclid");this.set(qb,"utm_source");this.set(rb,"utm_medium");this.set(sb,"utm_term");this.set(tb,"utm_content");this.set(ub,"utm_nooverride");this.set(vb,100);this.set(Dc,1);this.set(Ec,!1);this.set(wb,"/__utm.gif");this.set(xb,1);this.set(Cb,[]);this.set(Fb,[]);this.set(zb,Ld.slice(0));this.set(Ab,[]);this.set(Bb,[]);this.B("auto");this.set(Jb,J.referrer);this.set(v,!0);
this.set(y,Math.round((new Date).getTime()/1E3));Ye(this.a);this.set(Nc,{hit:[],load:[]});this.a.g("0",Zd);this.a.g("1",Wd);this.a.g("2",Jd);this.a.g("3",cf);this.a.g("4",Sd);this.a.g("5",Xd);this.a.g("6",Kd);this.a.g("7",d("load"));this.a.g("8",ie);this.a.v("A",kd);this.a.v("B",md);this.a.v("C",Ge);this.a.v("D",Jd);this.a.v("E",jd);this.a.v("F",Tc);this.a.v("G",ne);this.a.v("H",lf);this.a.v("I",Gd);this.a.v("J",nd);this.a.v("K",ud);this.a.v("L",Dd);this.a.v("M",l);this.a.v("N",hf);this.a.v("O",d("hit"));
this.a.v("P",oe);this.a.v("Q",pe);0===this.get(ab)&&H(111);this.a.T();this.H=void 0};E=U.prototype;E.m=function(){var a=this.get(Db);a||(a=new yd,this.set(Db,a));return a};E.La=function(a){for(var b in a){var c=a[b];a.hasOwnProperty(b)&&this.set(b,c,!0)}};E.K=function(a){if(this.get(Ec))return!1;var b=this,c=ke(this.a,function(c){b.set(Hb,a,!0);b.ib(c)});this.set(Ec,c);return c};
E.Fa=function(a){a&&Ca(a)?(H(13),this.set(Hb,a,!0)):"object"===typeof a&&null!==a&&this.La(a);this.H=a=this.get(Hb);this.a.j("page");this.K(a)};E.F=function(a,b,c,d,e){if(""==a||!wd(a)||""==b||!wd(b)||void 0!=c&&!wd(c)||void 0!=d&&!xd(d))return!1;this.set(wc,a,!0);this.set(xc,b,!0);this.set(yc,c,!0);this.set(zc,d,!0);this.set(vc,!!e,!0);this.a.j("event");return!0};
E.Ha=function(a,b,c,d,e){var f=this.a.b(Dc,0);1*e===e&&(f=e);if(this.a.b(Q,0)%100>=f)return!1;c=1*(""+c);if(""==a||!wd(a)||""==b||!wd(b)||!xd(c)||isNaN(c)||0>c||0>f||100<f||void 0!=d&&(""==d||!wd(d)))return!1;this.ib(me(a,b,c,d));return!0};E.Ga=function(a,b,c,d){if(!a||!b)return!1;this.set(Ac,a,!0);this.set(Bc,b,!0);this.set(Cc,c||J.location.href,!0);d&&this.set(Hb,d,!0);this.a.j("social");return!0};E.Ea=function(){this.set(Dc,10);this.K(this.H)};E.Ia=function(){this.a.j("trans")};
E.ib=function(a){this.set(Eb,a,!0);this.a.j("event")};E.ia=function(a){this.initData();var b=this;return{_trackEvent:function(c,d,e){H(91);b.F(a,c,d,e)}}};E.ma=function(a){return this.get(a)};E.xa=function(a,b){if(a)if(Ca(a))this.set(a,b);else if("object"==typeof a)for(var c in a)a.hasOwnProperty(c)&&this.set(c,a[c])};E.addEventListener=function(a,b){(a=this.get(Nc)[a])&&a.push(b)};E.removeEventListener=function(a,b){a=this.get(Nc)[a];for(var c=0;a&&c<a.length;c++)if(a[c]==b){a.splice(c,1);break}};
E.qa=function(){return"5.7.2"};E.B=function(a){this.get(hb);a="auto"==a?Ka(J.domain):a&&"-"!=a&&"none"!=a?a.toLowerCase():"";this.set(bb,a)};E.va=function(a){this.set(hb,!!a)};E.na=function(a,b){return ce(this.a,a,b)};E.link=function(a,b){this.a.get(fb)&&a&&(J.location.href=ce(this.a,a,b))};E.ua=function(a,b){this.a.get(fb)&&a&&a.action&&(a.action=ce(this.a,a.action,b))};
E.za=function(){this.initData();var a=this.a,b=J.getElementById?J.getElementById("utmtrans"):J.utmform&&J.utmform.utmtrans?J.utmform.utmtrans:null;if(b&&b.value){a.set(Cb,[]);b=b.value.split("UTM:");for(var c=0;c<b.length;c++){b[c]=Da(b[c]);for(var d=b[c].split(de),e=0;e<d.length;e++)d[e]=Da(d[e]);"T"==d[0]?fe(a,d[1],d[2],d[3],d[4],d[5],d[6],d[7],d[8]):"I"==d[0]&&ge(a,d[1],d[2],d[3],d[4],d[5],d[6])}}};E.$=function(a,b,c,d,e,f,Be,k){return fe(this.a,a,b,c,d,e,f,Be,k)};
E.Y=function(a,b,c,d,e,f){return ge(this.a,a,b,c,d,e,f)};E.Aa=function(a){de=a||"|"};E.ea=function(){this.set(Cb,[])};E.wa=function(a,b,c,d){var e=this.a;if(0>=a||a>e.get(yb))a=!1;else if(!b||!c||128<b.length+c.length)a=!1;else{1!=d&&2!=d&&(d=3);var f={};f.name=b;f.value=c;f.scope=d;e.get(Fb)[a]=f;a=!0}a&&this.a.store();return a};E.ka=function(a){this.a.get(Fb)[a]=void 0;this.a.store()};E.ra=function(a){return(a=this.a.get(Fb)[a])&&1==a.scope?a.value:void 0};
E.Ca=function(a,b,c){12==a&&1==b?this.set(pf,c):this.m().f(a,b,c)};E.Da=function(a,b,c){this.m().o(a,b,c)};E.sa=function(a,b){return this.m().getKey(a,b)};E.ta=function(a,b){return this.m().N(a,b)};E.fa=function(a){this.m().L(a)};E.ga=function(a){this.m().M(a)};E.ja=function(){return new yd};E.W=function(a){a&&this.get(Ab).push(a.toLowerCase())};E.ba=function(){this.set(Ab,[])};E.X=function(a){a&&this.get(Bb).push(a.toLowerCase())};E.ca=function(){this.set(Bb,[])};
E.Z=function(a,b,c,d,e){if(a&&b){a=[a,b.toLowerCase()].join(":");if(d||e)a=[a,d,e].join(":");d=this.get(zb);d.splice(c?0:d.length,0,a)}};E.da=function(){this.set(zb,[])};E.ha=function(a){this.a.load();var b=this.get(P),c=be(this.a);this.set(P,a);this.a.store();ae(this.a,c);this.set(P,b)};E.ya=function(a,b){if(0<a&&5>=a&&Ca(b)&&""!=b){var c=this.get(Fc)||[];c[a]=b;this.set(Fc,c)}};E.V=function(a){a=""+a;if(a.match(/^[A-Za-z0-9]{1,5}$/)){var b=this.get(Ic)||[];b.push(a);this.set(Ic,b)}};
E.initData=function(){this.a.load()};E.Ba=function(a){a&&""!=a&&(this.set(Tb,a),this.a.j("var"))};var ne=function(a){"trans"!==a.get(sc)&&500<=a.b(cc,0)&&a.stopPropagation();if("event"===a.get(sc)){var b=(new Date).getTime(),c=a.b(dc,0),d=a.b(Zb,0);c=Math.floor((b-(c!=d?c:1E3*c))/1E3);0<c&&(a.set(dc,b),a.set(R,Math.min(10,a.b(R,0)+c)));0>=a.b(R,0)&&a.stopPropagation()}},pe=function(a){"event"===a.get(sc)&&a.set(R,Math.max(0,a.b(R,10)-1))};var qe=function(){var a=[];this.add=function(b,c,d){d&&(c=G(""+c));a.push(b+"="+c)};this.toString=function(){return a.join("&")}},re=function(a,b){(b||2!=a.get(xb))&&a.Za(cc)},se=function(a,b){b.add("utmwv","5.7.2");b.add("utms",a.get(cc));b.add("utmn",Ea());var c=J.location.hostname;F(c)||b.add("utmhn",c,!0);a=a.get(vb);100!=a&&b.add("utmsp",a,!0)},te=function(a,b){b.add("utmht",(new Date).getTime());b.add("utmac",Da(a.get(Wa)));a.get(Oc)&&b.add("utmxkey",a.get(Oc),!0);a.get(vc)&&b.add("utmni",1);
a.get(of)&&b.add("utmgtm",a.get(of),!0);var c=a.get(Ic);c&&0<c.length&&b.add("utmdid",c.join("."));ff(a,b);!1!==a.get(Xa)&&(a.get(Xa)||M.w)&&b.add("aip",1);void 0!==a.get(Kc)&&b.add("utmjid",a.c(Kc,""),!0);a.b(Yb,0)&&b.add("utmredir",a.b(Yb,0),!0);M.bb||(M.bb=a.get(Wa));(1<M.ab()||M.bb!=a.get(Wa))&&b.add("utmmt",1);b.add("utmu",od.encode())},ue=function(a,b){a=a.get(Fc)||[];for(var c=[],d=1;d<a.length;d++)a[d]&&c.push(d+":"+G(a[d].replace(/%/g,"%25").replace(/:/g,"%3A").replace(/,/g,"%2C")));c.length&&
b.add("utmpg",c.join(","))},ff=function(a,b){function c(a,b){b&&d.push(a+"="+b+";")}var d=[];c("__utma",cd(a));c("__utmz",hd(a,!1));c("__utmv",fd(a,!0));c("__utmx",be(a));b.add("utmcc",d.join("+"),!0)},ve=function(a,b){a.get(ib)&&(b.add("utmcs",a.get(Qb),!0),b.add("utmsr",a.get(Lb)),a.get(Rb)&&b.add("utmvp",a.get(Rb)),b.add("utmsc",a.get(Mb)),b.add("utmul",a.get(Pb)),b.add("utmje",a.get(Nb)),b.add("utmfl",a.get(Ob),!0))},we=function(a,b){a.get(lb)&&a.get(Ib)&&b.add("utmdt",a.get(Ib),!0);b.add("utmhid",
a.get(Kb));b.add("utmr",Pa(a.get(Jb),a.get(P)),!0);b.add("utmp",G(a.get(Hb),!0),!0)},xe=function(a,b){for(var c=a.get(Db),d=a.get(Eb),e=a.get(Fb)||[],f=0;f<e.length;f++){var Be=e[f];Be&&(c||(c=new yd),c.f(8,f,Be.name),c.f(9,f,Be.value),3!=Be.scope&&c.f(11,f,""+Be.scope))}F(a.get(wc))||F(a.get(xc),!0)||(c||(c=new yd),c.f(5,1,a.get(wc)),c.f(5,2,a.get(xc)),e=a.get(yc),void 0!=e&&c.f(5,3,e),e=a.get(zc),void 0!=e&&c.o(5,1,e));F(a.get(pf))||(c||(c=new yd),c.f(12,1,a.get(pf)));c?b.add("utme",c.Qa(d),!0):
d&&b.add("utme",d.A(),!0)},ye=function(a,b,c){var d=new qe;re(a,c);se(a,d);d.add("utmt","tran");d.add("utmtid",b.id_,!0);d.add("utmtst",b.affiliation_,!0);d.add("utmtto",b.total_,!0);d.add("utmttx",b.tax_,!0);d.add("utmtsp",b.shipping_,!0);d.add("utmtci",b.city_,!0);d.add("utmtrg",b.state_,!0);d.add("utmtco",b.country_,!0);xe(a,d);ve(a,d);we(a,d);(b=a.get(Gb))&&d.add("utmcu",b,!0);c||(ue(a,d),te(a,d));return d.toString()},ze=function(a,b,c){var d=new qe;re(a,c);se(a,d);d.add("utmt","item");d.add("utmtid",
b.transId_,!0);d.add("utmipc",b.sku_,!0);d.add("utmipn",b.name_,!0);d.add("utmiva",b.category_,!0);d.add("utmipr",b.price_,!0);d.add("utmiqt",b.quantity_,!0);xe(a,d);ve(a,d);we(a,d);(b=a.get(Gb))&&d.add("utmcu",b,!0);c||(ue(a,d),te(a,d));return d.toString()},Ae=function(a,b){var c=a.get(sc);if("page"==c)c=new qe,re(a,b),se(a,c),xe(a,c),ve(a,c),we(a,c),b||(ue(a,c),te(a,c)),a=[c.toString()];else if("event"==c)c=new qe,re(a,b),se(a,c),c.add("utmt","event"),xe(a,c),ve(a,c),we(a,c),b||(ue(a,c),te(a,c)),
a=[c.toString()];else if("var"==c)c=new qe,re(a,b),se(a,c),c.add("utmt","var"),!b&&te(a,c),a=[c.toString()];else if("trans"==c){c=[];for(var d=a.get(Cb),e=0;e<d.length;++e){c.push(ye(a,d[e],b));for(var f=d[e].items_,Be=0;Be<f.length;++Be)c.push(ze(a,f[Be],b))}a=c}else"social"==c?b?a=[]:(c=new qe,re(a,b),se(a,c),c.add("utmt","social"),c.add("utmsn",a.get(Ac),!0),c.add("utmsa",a.get(Bc),!0),c.add("utmsid",a.get(Cc),!0),xe(a,c),ve(a,c),we(a,c),ue(a,c),te(a,c),a=[c.toString()]):"feedback"==c?b?a=[]:(c=
new qe,re(a,b),se(a,c),c.add("utmt","feedback"),c.add("utmfbid",a.get(Gc),!0),c.add("utmfbpr",a.get(Hc),!0),xe(a,c),ve(a,c),we(a,c),ue(a,c),te(a,c),a=[c.toString()]):a=[];return a},oe=function(a){var b=a.get(xb),c=a.get(uc),d=c&&c.Ua,e=0,f=a.get(z);if(0==b||2==b){var Be=a.get(wb)+"?";var k=Ae(a,!0);for(var Ja=0,t=k.length;Ja<t;Ja++)Sa(k[Ja],d,Be,!0),e++}if(1==b||2==b)for(k=Ae(a),a=a.c(Jc,""),Ja=0,t=k.length;Ja<t;Ja++)try{if(f){var Za=k[Ja];b=(b=d)||Fa;df("",b,a+"?"+Za,f)}else Sa(k[Ja],d,a);e++}catch(Ma){Ma&&
Ra(Ma.name,void 0,Ma.message)}c&&(c.fb=e)};var Ne=function(){return"https:"==J.location.protocol||M.G?"https://ssl.google-analytics.com":"http://www.google-analytics.com"},Ce=function(a){this.name="len";this.message=a+"-8192"},De=function(a){this.name="ff2post";this.message=a+"-2036"},Sa=function(a,b,c,d){b=b||Fa;if(d||2036>=a.length)gf(a,b,c);else if(8192>=a.length){if(0<=W.navigator.userAgent.indexOf("Firefox")&&![].reduce)throw new De(a.length);df(a,b)||ef(a,b)||Ee(a,b)||b()}else throw new Ce(a.length);},gf=function(a,b,c){c=c||Ne()+"/__utm.gif?";
var d=new Image(1,1);d.src=c+a;d.onload=function(){d.onload=null;d.onerror=null;b()};d.onerror=function(){d.onload=null;d.onerror=null;b()}},ef=function(a,b){if(0!=Ne().indexOf(J.location.protocol))return!1;var c=W.XDomainRequest;if(!c)return!1;c=new c;c.open("POST",Ne()+"/p/__utm.gif");c.onerror=function(){b()};c.onload=b;c.send(a);return!0},df=function(a,b,c,d){var e=W.XMLHttpRequest;if(!e)return!1;var f=new e;if(!("withCredentials"in f))return!1;f.open("POST",c||Ne()+"/p/__utm.gif",!0);f.withCredentials=
!0;f.setRequestHeader("Content-Type","text/plain");f.onreadystatechange=function(){if(4==f.readyState){if(d)try{var a=f.responseText;if(1>a.length||"1"!=a.charAt(0))Ra("xhr","ver",a),b();else if(3<d.count++)Ra("xhr","tmr",""+d.count),b();else if(1==a.length)b();else{var c=a.charAt(1);if("d"==c){var e=d.gb;a=(a=b)||Fa;df("",a,"https://stats.g.doubleclick.net/j/collect?"+e,d)}else if("g"==c){var t="https://www.google.%/ads/ga-audiences?".replace("%","com");gf(d.google,b,t);var Za=a.substring(2);if(Za)if(/^[a-z.]{1,6}$/.test(Za)){var Ma=
"https://www.google.%/ads/ga-audiences?".replace("%",Za);gf(d.google,Fa,Ma)}else Ra("tld","bcc",Za)}else Ra("xhr","brc",c),b()}}catch(mb){b()}else b();f=null}};f.send(a);return!0},Ee=function(a,b){if(!J.body)return We(function(){Ee(a,b)},100),!0;a=encodeURIComponent(a);try{var c=J.createElement('<iframe name="'+a+'"></iframe>')}catch(e){c=J.createElement("iframe"),c.name=a}c.height="0";c.width="0";c.style.display="none";c.style.visibility="hidden";var d=Ne()+"/u/post_iframe.html";Ga(W,"beforeunload",
function(){c.src="";c.parentNode&&c.parentNode.removeChild(c)});setTimeout(b,1E3);J.body.appendChild(c);c.src=d;return!0};var qf=function(){this.G=this.w=!1;0==Ea()%1E4&&(H(142),this.G=!0);this.C={};this.D=[];this.U=0;this.S=[["www.google-analytics.com","","/plugins/"]];this._gasoCPath=this._gasoDomain=this.bb=void 0;Re();Se()};E=qf.prototype;E.oa=function(a,b){return this.hb(a,void 0,b)};E.hb=function(a,b,c){b&&H(23);c&&H(67);void 0==b&&(b="~"+M.U++);a=new U(b,a,c);M.C[b]=a;M.D.push(a);return a};E.u=function(a){a=a||"";return M.C[a]||M.hb(void 0,a)};E.pa=function(){return M.D.slice(0)};E.ab=function(){return M.D.length};
E.aa=function(){this.w=!0};E.la=function(){this.G=!0};var Fe=function(a){if("prerender"==J.visibilityState)return!1;a();return!0};var M=new qf;var D=W._gat;D&&Ba(D._getTracker)?M=D:W._gat=M;var Z=new Y;(function(a){if(!Fe(a)){H(123);var b=!1,c=function(){if(!b&&Fe(a)){b=!0;var d=J,e=c;d.removeEventListener?d.removeEventListener("visibilitychange",e,!1):d.detachEvent&&d.detachEvent("onvisibilitychange",e)}};Ga(J,"visibilitychange",c)}})(function(){var a=W._gaq,b=!1;if(a&&Ba(a.push)&&(b="[object Array]"==Object.prototype.toString.call(Object(a)),!b)){Z=a;return}W._gaq=Z;b&&Z.push.apply(Z,a)});function Yc(a){var b=1,c;if(a)for(b=0,c=a.length-1;0<=c;c--){var d=a.charCodeAt(c);b=(b<<6&268435455)+d+(d<<14);d=b&266338304;b=0!=d?b^d>>21:b}return b};}).call(this);

1
target/classes/static/js/scan/llqrcode.js

File diff suppressed because one or more lines are too long

0
target/classes/static/js/scan/plusone.js

240
target/classes/static/js/scan/webqr.js

@ -0,0 +1,240 @@
// QRCODE reader Copyright 2011 Lazar Laszlo
// http://www.webqr.com
var gCtx = null;
var gCanvas = null;
var c=0;
var stype=0;
var gUM=false;
var webkit=false;
var moz=false;
var v=null;
var imghtml='<div id="qrfile"><canvas id="out-canvas" width="320" height="240"></canvas>'+
'<div id="imghelp">drag and drop a QRCode here'+
'<br>or select a file'+
'<input type="file" onchange="handleFiles(this.files)"/>'+
'</div>'+
'</div>';
var vidhtml = '<video id="v" autoplay></video>';
function dragenter(e) {
e.stopPropagation();
e.preventDefault();
}
function dragover(e) {
e.stopPropagation();
e.preventDefault();
}
function drop(e) {
e.stopPropagation();
e.preventDefault();
var dt = e.dataTransfer;
var files = dt.files;
if(files.length>0)
{
handleFiles(files);
}
else
if(dt.getData('URL'))
{
qrcode.decode(dt.getData('URL'));
}
}
function handleFiles(f)
{
var o=[];
for(var i =0;i<f.length;i++)
{
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
gCtx.clearRect(0, 0, gCanvas.width, gCanvas.height);
qrcode.decode(e.target.result);
};
})(f[i]);
reader.readAsDataURL(f[i]);
}
}
function initCanvas(w,h)
{
gCanvas = document.getElementById("qr-canvas");
gCanvas.style.width = w + "px";
gCanvas.style.height = h + "px";
gCanvas.width = w;
gCanvas.height = h;
gCtx = gCanvas.getContext("2d");
gCtx.clearRect(0, 0, w, h);
}
function captureToCanvas() {
if(stype!=1)
return;
if(gUM)
{
try{
gCtx.drawImage(v,0,0);
try{
qrcode.decode();
}
catch(e){
console.log(e);
setTimeout(captureToCanvas, 500);
};
}
catch(e){
console.log(e);
setTimeout(captureToCanvas, 500);
};
}
}
function htmlEntities(str) {
return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
function read(a)
{
var html="<br>";
if(a.indexOf("http://") === 0 || a.indexOf("https://") === 0)
html+="<a target='_blank' href='"+a+"'>"+a+"</a><br>";
html+="<b>"+htmlEntities(a)+"</b><br><br>";
document.getElementById("result").innerHTML=html;
}
function isCanvasSupported(){
var elem = document.createElement('canvas');
return !!(elem.getContext && elem.getContext('2d'));
}
function success(stream)
{
v.srcObject = stream;
v.play();
gUM=true;
setTimeout(captureToCanvas, 500);
}
function error(error)
{
gUM=false;
return;
}
function load()
{
if(isCanvasSupported() && window.File && window.FileReader)
{
initCanvas(800, 600);
qrcode.callback = read;
document.getElementById("mainbody").style.display="inline";
setwebcam();
}
else
{
document.getElementById("mainbody").style.display="inline";
document.getElementById("mainbody").innerHTML='<p id="mp1">QR code scanner for HTML5 capable browsers</p><br>'+
'<br><p id="mp2">sorry your browser is not supported</p><br><br>'+
'<p id="mp1">try <a href="http://www.mozilla.com/firefox"><img src="firefox.png"/></a> or <a href="http://chrome.google.com"><img src="chrome_logo.gif"/></a> or <a href="http://www.opera.com"><img src="Opera-logo.png"/></a></p>';
}
}
function setwebcam()
{
var options = true;
if(navigator.mediaDevices && navigator.mediaDevices.enumerateDevices)
{
try{
navigator.mediaDevices.enumerateDevices()
.then(function(devices) {
devices.forEach(function(device) {
if (device.kind === 'videoinput') {
if(device.label.toLowerCase().search("back") >-1)
options={'deviceId': {'exact':device.deviceId}, 'facingMode':'environment'} ;
}
console.log(device.kind + ": " + device.label +" id = " + device.deviceId);
});
setwebcam2(options);
});
}
catch(e)
{
console.log(e);
}
}
else{
console.log("no navigator.mediaDevices.enumerateDevices" );
setwebcam2(options);
}
}
function setwebcam2(options)
{
console.log(options);
document.getElementById("result").innerHTML="- scanning -";
if(stype==1)
{
setTimeout(captureToCanvas, 500);
return;
}
var n=navigator;
document.getElementById("outdiv").innerHTML = vidhtml;
v=document.getElementById("v");
if(n.mediaDevices.getUserMedia)
{
n.mediaDevices.getUserMedia({video: options, audio: false}).
then(function(stream){
success(stream);
}).catch(function(error){
error(error)
});
}
else
if(n.getUserMedia)
{
webkit=true;
n.getUserMedia({video: options, audio: false}, success, error);
}
else
if(n.webkitGetUserMedia)
{
webkit=true;
n.webkitGetUserMedia({video:options, audio: false}, success, error);
}
document.getElementById("qrimg").style.opacity=0.2;
document.getElementById("webcamimg").style.opacity=1.0;
stype=1;
setTimeout(captureToCanvas, 500);
}
function setimg()
{
document.getElementById("result").innerHTML="";
if(stype==2)
return;
document.getElementById("outdiv").innerHTML = imghtml;
//document.getElementById("qrimg").src="qrimg.png";
//document.getElementById("webcamimg").src="webcam2.png";
document.getElementById("qrimg").style.opacity=1.0;
document.getElementById("webcamimg").style.opacity=0.2;
var qrfile = document.getElementById("qrfile");
qrfile.addEventListener("dragenter", dragenter, false);
qrfile.addEventListener("dragover", dragover, false);
qrfile.addEventListener("drop", drop, false);
stype=2;
}

0
target/classes/static/vue/common/helper.js → target/classes/static/js/vue/common/helper.js

2
target/classes/static/vue/common/permission.js → target/classes/static/js/vue/common/permission.js

@ -1,6 +1,6 @@
/// null = 未请求,1 = 已允许,0 = 拒绝|受限, 2 = 系统未开启
var isIOS
var isIOS;
function album() {
var result = 0;

25
target/classes/static/js/vue/router.js

@ -0,0 +1,25 @@
const Home = httpVueLoader('static/vuePage/index.vue');
var Header = httpVueLoader('static/vuePage/scanCode.vue');
Vue.component('my-header', Header);
const Foo = {
template: '<div>foo</div>'
};
const Bar = {
template: '<div>bar</div>'
};
const routes = [{
path: '/',
component: Home,
children: [{
path: '/foo',
component: Foo
},
{
path: '/bar',
component: Bar
},
]
}, ];
const router = new VueRouter({
routes // (缩写) 相当于 routes: routes
})

3146
target/classes/static/js/vue/vue-router.js

File diff suppressed because it is too large

6
target/classes/static/js/vue/vue-router.min.js

File diff suppressed because one or more lines are too long

11944
target/classes/static/js/vue/vue.js

File diff suppressed because it is too large

6
target/classes/static/js/vue/vue.min.js

File diff suppressed because one or more lines are too long

40
target/classes/static/lib/http-vue-loader/.gitignore

@ -0,0 +1,40 @@
# Logs
logs
*.log
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules
jspm_packages
# Optional npm cache directory
.npm
# Optional REPL history
.node_repl_history
# Temporary directory
tmp

40
target/classes/static/lib/http-vue-loader/.npmignore

@ -0,0 +1,40 @@
# Logs
logs
*.log
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules
jspm_packages
# Optional npm cache directory
.npm
# Optional REPL history
.node_repl_history
# Temporary directory
tmp

316
target/classes/static/lib/http-vue-loader/README.md

@ -0,0 +1,316 @@
### :tada: **http-vue-loader** evolved into [**vue3-sfc-loader**](https://github.com/FranckFreiburger/vue3-sfc-loader) that supports Vue2 and Vue3 :tada:
### (see the [announcement](https://github.com/FranckFreiburger/http-vue-loader/issues/127))
# http-vue-loader
Load .vue files directly from your html/js. No node.js environment, no build step.
## examples
`my-component.vue`
```vue
<template>
<div class="hello">Hello {{who}}</div>
</template>
<script>
module.exports = {
data: function() {
return {
who: 'world'
}
}
}
</script>
<style>
.hello {
background-color: #ffe;
}
</style>
```
`index.html`
```html
<!doctype html>
<html lang="en">
<head>
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/http-vue-loader"></script>
</head>
<body>
<div id="my-app">
<my-component></my-component>
</div>
<script type="text/javascript">
new Vue({
el: '#my-app',
components: {
'my-component': httpVueLoader('my-component.vue')
}
});
</script>
</body>
</html>
```
## More examples
using `httpVueLoader()`
```html
...
<script type="text/javascript">
new Vue({
components: {
'my-component': httpVueLoader('my-component.vue')
},
...
```
or, using `httpVueLoader.register()`
```html
...
<script type="text/javascript">
httpVueLoader.register(Vue, 'my-component.vue');
new Vue({
components: [
'my-component'
]
},
...
```
or, using `httpVueLoader` as a plugin
```html
...
<script type="text/javascript">
Vue.use(httpVueLoader);
new Vue({
components: {
'my-component': 'url:my-component.vue'
},
...
```
or, using an array
```
new Vue({
components: [
'url:my-component.vue'
]
},
...
```
## Features
* `<template>`, `<script>` and `<style>` support the `src` attribute.
* `<style scoped>` is supported.
* `module.exports` may be a promise.
* Support of relative urls in `<template>` and `<style>` sections.
* Support custom CSS, HTML and scripting languages, eg. `<script lang="coffee">` (see VueLoader.langProcessor).
## Browser Support
![Chrome](https://raw.github.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/src/safari/safari_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/src/opera/opera_48x48.png) | ![Edge](https://raw.github.com/alrra/browser-logos/master/src/edge/edge_48x48.png) | ![IE](https://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Internet_Explorer_10_logo.svg/48px-Internet_Explorer_10_logo.svg.png) |
--- | --- | --- | --- | --- | --- |
Latest ✔ | Latest ✔ | ? | ? | Latest ✔ | 9+ ✔ |
## Requirements
* [Vue.js 2](https://vuejs.org/) ([compiler and runtime](https://vuejs.org/v2/guide/installation.html#Explanation-of-Different-Builds))
* [es6-promise](https://github.com/stefanpenner/es6-promise) (optional, except for IE, Chrome < 33, FireFox < 29, [...](http://caniuse.com/#search=promise) )
* webserver (optional)...
Since some browsers do not allow XMLHttpRequest to access local files (Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https),
you can start a small express server to run this example.
Run the following commands to start a basic web server:
```
npm install express
node -e "require('express')().use(require('express').static(__dirname, {index:'index.html'})).listen(8181)"
```
## API
##### httpVueLoader(`url`)
`url`: any url to a .vue file
##### httpVueLoader.register(`vue`, `url`)
`vue`: a Vue instance
`url`: any url to a .vue file
##### httpVueLoader.httpRequest(`url`)
This is the default httpLoader.
Use axios instead of the default http loader:
```Javascript
httpVueLoader.httpRequest = function(url) {
return axios.get(url)
.then(function(res) {
return res.data;
})
.catch(function(err) {
return Promise.reject(err.status);
});
}
```
##### httpVueLoader.langProcessor
This is an object that contains language processors related to the `lang` attribute of the `<script>` section.
The language is a simple function that accepts a script source as argument and returns a javascript script source.
Example - CoffeeScript:
```JavaScript
<script src="http://coffeescript.org/v1/browser-compiler/coffee-script.js"></script>
<script src="httpVueLoader.js"></script>
<script>
httpVueLoader.langProcessor.coffee = function(scriptText) {
return window.CoffeeScript.compile(scriptText, {bare: true});
}
</script>
```
Then, in you `.vue` file:
```CoffeeScript
...
<script lang="coffee">
module.exports =
components: {}
data: ->
{}
computed: {}
methods: {}
</script>
...
```
Example - Stylus:
```JavaScript
<script src="//stylus-lang.com/try/stylus.min.js"></script>
<script src="httpVueLoader.js"></script>
<script>
httpVueLoader.langProcessor.stylus = function(stylusText) {
return new Promise(function(resolve, reject) {
stylus.render(stylusText.trim(), {}, function(err, css) {
if (err) reject(err);
resolve(css);
});
})
}
</script>
```
```stylus
...
<style lang="stylus">
border-radius()
-webkit-border-radius: arguments
-moz-border-radius: arguments
border-radius: arguments
form input
padding: 5px
border: 1px solid
border-radius: 5px
</style>
...
```
Sass (SCSS) example. Since `sass.compile()` is asynchronous, a promise needs to be returned:
```JavaScript
<script src="sass.js"></script>
<script src="httpVueLoader.js"></script>
<script>
httpVueLoader.langProcessor.scss = function (scssText) {
return new Promise(function(resolve, reject) {
sass.compile(scssText, function (result) {
if ( result.status === 0 )
resolve(result.text)
else
reject(result)
});
});
}
// ....
```
```scss
...
<style lang="scss">
$font-stack: Helvetica, sans-serif;
$primary-color: #333;
body {
font: 100% $font-stack;
color: $primary-color;
}
</style>
```
## How it works
1. http request the vue file
1. load the vue file in a document fragment
1. process each section (template, script and style)
1. return a promise to Vue.js (async components)
1. then Vue.js compiles and cache the component
## Notes
The aim of http-vue-loader is to quickly test .vue components without any compilation step.
However, for production, I recommend to use [webpack module bundler](https://webpack.github.io/docs/) with [vue-loader](https://github.com/vuejs/vue-loader),
[webpack-simple](https://github.com/vuejs-templates/webpack-simple) is a good minimalist webpack config you should look at.
BTW, see also [why Vue.js doesn't support templateURL](https://vuejs.org/2015/10/28/why-no-template-url/).
## Caveat
Due to the lack of suitable API in Google Chrome and Internet Explorer, syntax errors in the `<script>` section are only reported on FireFox.
## Credits
[Franck Freiburger](https://www.franck-freiburger.com)

24
target/classes/static/lib/http-vue-loader/package.json

@ -0,0 +1,24 @@
{
"name": "http-vue-loader",
"version": "1.4.2",
"description": "Load .vue files directly from your html/js. No node.js environment, no build step.",
"main": "./src/httpVueLoader.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/FranckFreiburger/http-vue-loader.git"
},
"keywords": [
"http",
"vue",
"loader"
],
"author": "Franck Freiburger",
"license": "MIT",
"bugs": {
"url": "https://github.com/FranckFreiburger/http-vue-loader/issues"
},
"homepage": "https://github.com/FranckFreiburger/http-vue-loader#readme"
}

478
target/classes/static/lib/http-vue-loader/src/httpVueLoader.js

@ -0,0 +1,478 @@
(function umd(root,factory){
if(typeof module==='object' && typeof exports === 'object' )
module.exports=factory()
else if(typeof define==='function' && define.amd)
define([],factory)
else
root.httpVueLoader=factory()
})(this,function factory() {
'use strict';
var scopeIndex = 0;
StyleContext.prototype = {
withBase: function(callback) {
var tmpBaseElt;
if ( this.component.baseURI ) {
// firefox and chrome need the <base> to be set while inserting or modifying <style> in a document.
tmpBaseElt = document.createElement('base');
tmpBaseElt.href = this.component.baseURI;
var headElt = this.component.getHead();
headElt.insertBefore(tmpBaseElt, headElt.firstChild);
}
callback.call(this);
if ( tmpBaseElt )
this.component.getHead().removeChild(tmpBaseElt);
},
scopeStyles: function(styleElt, scopeName) {
function process() {
var sheet = styleElt.sheet;
var rules = sheet.cssRules;
for ( var i = 0; i < rules.length; ++i ) {
var rule = rules[i];
if ( rule.type !== 1 )
continue;
var scopedSelectors = [];
rule.selectorText.split(/\s*,\s*/).forEach(function(sel) {
scopedSelectors.push(scopeName+' '+sel);
var segments = sel.match(/([^ :]+)(.+)?/);
scopedSelectors.push(segments[1] + scopeName + (segments[2]||''));
});
var scopedRule = scopedSelectors.join(',') + rule.cssText.substr(rule.selectorText.length);
sheet.deleteRule(i);
sheet.insertRule(scopedRule, i);
}
}
try {
// firefox may fail sheet.cssRules with InvalidAccessError
process();
} catch (ex) {
if ( ex instanceof DOMException && ex.code === DOMException.INVALID_ACCESS_ERR ) {
styleElt.sheet.disabled = true;
styleElt.addEventListener('load', function onStyleLoaded() {
styleElt.removeEventListener('load', onStyleLoaded);
// firefox need this timeout otherwise we have to use document.importNode(style, true)
setTimeout(function() {
process();
styleElt.sheet.disabled = false;
});
});
return;
}
throw ex;
}
},
compile: function() {
var hasTemplate = this.template !== null;
var scoped = this.elt.hasAttribute('scoped');
if ( scoped ) {
// no template, no scopable style needed
if ( !hasTemplate )
return;
// firefox does not tolerate this attribute
this.elt.removeAttribute('scoped');
}
this.withBase(function() {
this.component.getHead().appendChild(this.elt);
});
if ( scoped )
this.scopeStyles(this.elt, '['+this.component.getScopeId()+']');
return Promise.resolve();
},
getContent: function() {
return this.elt.textContent;
},
setContent: function(content) {
this.withBase(function() {
this.elt.textContent = content;
});
}
};
function StyleContext(component, elt) {
this.component = component;
this.elt = elt;
}
ScriptContext.prototype = {
getContent: function() {
return this.elt.textContent;
},
setContent: function(content) {
this.elt.textContent = content;
},
compile: function(module) {
var childModuleRequire = function(childURL) {
return httpVueLoader.require(resolveURL(this.component.baseURI, childURL));
}.bind(this);
var childLoader = function(childURL, childName) {
return httpVueLoader(resolveURL(this.component.baseURI, childURL), childName);
}.bind(this);
try {
Function('exports', 'require', 'httpVueLoader', 'module', this.getContent()).call(this.module.exports, this.module.exports, childModuleRequire, childLoader, this.module);
} catch(ex) {
if ( !('lineNumber' in ex) ) {
return Promise.reject(ex);
}
var vueFileData = responseText.replace(/\r?\n/g, '\n');
var lineNumber = vueFileData.substr(0, vueFileData.indexOf(script)).split('\n').length + ex.lineNumber - 1;
throw new (ex.constructor)(ex.message, url, lineNumber);
}
return Promise.resolve(this.module.exports)
.then(httpVueLoader.scriptExportsHandler.bind(this))
.then(function(exports) {
this.module.exports = exports;
}.bind(this));
}
};
function ScriptContext(component, elt) {
this.component = component;
this.elt = elt;
this.module = { exports:{} };
}
TemplateContext.prototype = {
getContent: function() {
return this.elt.innerHTML;
},
setContent: function(content) {
this.elt.innerHTML = content;
},
getRootElt: function() {
var tplElt = this.elt.content || this.elt;
if ( 'firstElementChild' in tplElt )
return tplElt.firstElementChild;
for ( tplElt = tplElt.firstChild; tplElt !== null; tplElt = tplElt.nextSibling )
if ( tplElt.nodeType === Node.ELEMENT_NODE )
return tplElt;
return null;
},
compile: function() {
return Promise.resolve();
}
};
function TemplateContext(component, elt) {
this.component = component;
this.elt = elt;
}
Component.prototype = {
getHead: function() {
return document.head || document.getElementsByTagName('head')[0];
},
getScopeId: function() {
if ( this._scopeId === '' ) {
this._scopeId = 'data-s-' + (scopeIndex++).toString(36);
this.template.getRootElt().setAttribute(this._scopeId, '');
}
return this._scopeId;
},
load: function(componentURL) {
return httpVueLoader.httpRequest(componentURL)
.then(function(responseText) {
this.baseURI = componentURL.substr(0, componentURL.lastIndexOf('/')+1);
var doc = document.implementation.createHTMLDocument('');
// IE requires the <base> to come with <style>
doc.body.innerHTML = (this.baseURI ? '<base href="'+this.baseURI+'">' : '') + responseText;
for ( var it = doc.body.firstChild; it; it = it.nextSibling ) {
switch ( it.nodeName ) {
case 'TEMPLATE':
this.template = new TemplateContext(this, it);
break;
case 'SCRIPT':
this.script = new ScriptContext(this, it);
break;
case 'STYLE':
this.styles.push(new StyleContext(this, it));
break;
}
}
return this;
}.bind(this));
},
_normalizeSection: function(eltCx) {
var p;
if ( eltCx === null || !eltCx.elt.hasAttribute('src') ) {
p = Promise.resolve(null);
} else {
p = httpVueLoader.httpRequest(eltCx.elt.getAttribute('src'))
.then(function(content) {
eltCx.elt.removeAttribute('src');
return content;
});
}
return p
.then(function(content) {
if ( eltCx !== null && eltCx.elt.hasAttribute('lang') ) {
var lang = eltCx.elt.getAttribute('lang');
eltCx.elt.removeAttribute('lang');
return httpVueLoader.langProcessor[lang.toLowerCase()].call(this, content === null ? eltCx.getContent() : content);
}
return content;
}.bind(this))
.then(function(content) {
if ( content !== null )
eltCx.setContent(content);
});
},
normalize: function() {
return Promise.all(Array.prototype.concat(
this._normalizeSection(this.template),
this._normalizeSection(this.script),
this.styles.map(this._normalizeSection)
))
.then(function() {
return this;
}.bind(this));
},
compile: function() {
return Promise.all(Array.prototype.concat(
this.template && this.template.compile(),
this.script && this.script.compile(),
this.styles.map(function(style) { return style.compile(); })
))
.then(function() {
return this;
}.bind(this));
}
};
function Component(name) {
this.name = name;
this.template = null;
this.script = null;
this.styles = [];
this._scopeId = '';
}
function identity(value) {
return value;
}
function parseComponentURL(url) {
var comp = url.match(/(.*?)([^/]+?)\/?(\.vue)?(\?.*|#.*|$)/);
return {
name: comp[2],
url: comp[1] + comp[2] + (comp[3] === undefined ? '/index.vue' : comp[3]) + comp[4]
};
}
function resolveURL(baseURL, url) {
if (url.substr(0, 2) === './' || url.substr(0, 3) === '../') {
return baseURL + url;
}
return url;
}
httpVueLoader.load = function(url, name) {
return function() {
return new Component(name).load(url)
.then(function(component) {
return component.normalize();
})
.then(function(component) {
return component.compile();
})
.then(function(component) {
var exports = component.script !== null ? component.script.module.exports : {};
if ( component.template !== null )
exports.template = component.template.getContent();
if ( exports.name === undefined )
if ( component.name !== undefined )
exports.name = component.name;
exports._baseURI = component.baseURI;
return exports;
});
};
};
httpVueLoader.register = function(Vue, url) {
var comp = parseComponentURL(url);
Vue.component(comp.name, httpVueLoader.load(comp.url));
};
httpVueLoader.install = function(Vue) {
Vue.mixin({
beforeCreate: function () {
var components = this.$options.components;
for ( var componentName in components ) {
if ( typeof(components[componentName]) === 'string' && components[componentName].substr(0, 4) === 'url:' ) {
var comp = parseComponentURL(components[componentName].substr(4));
var componentURL = ('_baseURI' in this.$options) ? resolveURL(this.$options._baseURI, comp.url) : comp.url;
if ( isNaN(componentName) )
components[componentName] = httpVueLoader.load(componentURL, componentName);
else
components[componentName] = Vue.component(comp.name, httpVueLoader.load(componentURL, comp.name));
}
}
}
});
};
httpVueLoader.require = function(moduleName) {
return window[moduleName];
};
httpVueLoader.httpRequest = function(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'text';
xhr.onreadystatechange = function() {
if ( xhr.readyState === 4 ) {
if ( xhr.status >= 200 && xhr.status < 300 )
resolve(xhr.responseText);
else
reject(xhr.status);
}
};
xhr.send(null);
});
};
httpVueLoader.langProcessor = {
html: identity,
js: identity,
css: identity
};
httpVueLoader.scriptExportsHandler = identity;
function httpVueLoader(url, name) {
var comp = parseComponentURL(url);
return httpVueLoader.load(comp.url, name);
}
return httpVueLoader;
});

3
target/classes/static/lib/vue-qrcode-reader/.browserslistrc

@ -0,0 +1,3 @@
> 1%
last 2 versions
ie >= 10

18
target/classes/static/lib/vue-qrcode-reader/.editorconfig

@ -0,0 +1,18 @@
root = true
[*]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
end_of_line = lf
insert_final_newline = true
[docs/rules/linebreak-style.md]
end_of_line = disabled
[{docs/rules/{indent.md,no-mixed-spaces-and-tabs.md}]
indent_style = disabled
indent_size = disabled
[docs/rules/no-trailing-spaces.md]
trim_trailing_whitespace = false

25
target/classes/static/lib/vue-qrcode-reader/.eslintrc.js

@ -0,0 +1,25 @@
module.exports = {
root: true,
env: {
node: true
},
extends: ["plugin:vue/essential", "eslint:recommended", "@vue/prettier"],
parserOptions: {
parser: "babel-eslint"
},
rules: {
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off"
},
overrides: [
{
files: [
"**/__tests__/*.{j,t}s?(x)",
"**/tests/unit/**/*.spec.{j,t}s?(x)"
],
env: {
mocha: true
}
}
]
};

28
target/classes/static/lib/vue-qrcode-reader/.github/ISSUE_TEMPLATE/bug_report.md

@ -0,0 +1,28 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is. Can you reproduce this issue with [one of the demos](https://gruhn.github.io/vue-qrcode-reader/demos/DecodeAll.html)?
**To Reproduce**
Please provide a link to a minimal reproduction of the bug. For example on jsFiddle, CodePen, etc. Please don't attach a ZIP file with your entire code base. I know this is additional effort but if it takes too much time to reproduce your issue you'll likely won't get help at all.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]

19
target/classes/static/lib/vue-qrcode-reader/.github/ISSUE_TEMPLATE/wrong_camera.md

@ -0,0 +1,19 @@
---
name: Wrong camera selected
about:
title: ''
labels: ''
assignees: ''
---
If your device defaults to the wrong camera, please [open this demo](https://gruhn.github.io/vue-qrcode-reader/select-camera-demo.html).
You should see a list of all cameras installed on your device.
Copy the list and mark the camera that was picked by default and the camera that should actually be picked.
For example like this:
```
FaceTime HD Camera (Built-in) [DEFAULT]
A different Camera [PREFERRED]
Another different Camera
```

BIN
target/classes/static/lib/vue-qrcode-reader/.github/browserstack-logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
target/classes/static/lib/vue-qrcode-reader/.github/screenshot1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

BIN
target/classes/static/lib/vue-qrcode-reader/.github/screenshot2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
target/classes/static/lib/vue-qrcode-reader/.github/screenshot3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 KiB

BIN
target/classes/static/lib/vue-qrcode-reader/.github/travis-logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

33
target/classes/static/lib/vue-qrcode-reader/.github/workflows/main.yml

@ -0,0 +1,33 @@
name: Release
on:
push:
branches:
- master
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v1
with:
node-version: 16
- name: Install & Build
run: |
npm ci
npm run build
npm run build:docs
- name: Deploy Docs
uses: JamesIves/github-pages-deploy-action@4.1.4
with:
branch: gh-pages
folder: docs/.vuepress/dist
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-release

26
target/classes/static/lib/vue-qrcode-reader/.gitignore

@ -0,0 +1,26 @@
.DS_Store
node_modules
/dist
/docs/.vuepress/dist
/tests/e2e/videos/
/tests/e2e/screenshots/
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

4
target/classes/static/lib/vue-qrcode-reader/.releaserc.yml

@ -0,0 +1,4 @@
branches:
- name: master
- name: beta
prerelease: true

23
target/classes/static/lib/vue-qrcode-reader/CONTRIBUTING.md

@ -0,0 +1,23 @@
Your contributions are welcome.
Don't hesitate to open an issue if you have trouble.
### Setup Dev Environment
Clone the repository and run
```
npm install
```
We use a locally served version of the [demo page](https://gruhn.github.io/vue-qrcode-reader/demos/DecodeAll.html) during development.
To get that started run
```
npm run dev
```
### Commit Messages
The version number of releases is automatically determined form commit messages.
This only works if we follow [Angular Commit Message Conventions](https://github.com/semantic-release/semantic-release#commit-message-format).

183
target/classes/static/lib/vue-qrcode-reader/README.md

@ -0,0 +1,183 @@
<p align="center">
<img src="https://gruhn.github.io/vue-qrcode-reader/logo.png" alt="Logo" width="240" height="240" style="max-width: 100%;">
<br>
<br>
<a href="https://vuejs.org/">
<img src="https://img.shields.io/badge/vue-2.x-brightgreen.svg" alt="for Vue.js 2">
</a>
<a href="https://www.npmjs.com/package/vue-qrcode-reader">
<img src="https://img.shields.io/npm/dm/vue-qrcode-reader.svg" alt="npm monthly downloads">
</a>
<br>
<img src="https://img.shields.io/badge/Maintained%3F-yes-green.svg" alt="is maintained? yes">
<a href="http://opensource.org/licenses/MIT">
<img src="https://img.shields.io/github/license/Naereen/StrapDown.js.svg" alt="licence: MIT">
</a>
<a href="https://github.com/Naereen/badges">
<img src="https://img.shields.io/badge/badges-awesome-green.svg" alt="badges = awesome">
</a>
<br>
<a href="https://github.com/semantic-release/semantic-release">
<img src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg" alt="uses semantic release">
</a>
<a href="https://github.com/prettier/prettier">
<img src="https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square" alt="code style: prettier">
</a>
<br>
<a href="https://bundlephobia.com/result?p=vue-qrcode-reader">
<img src="https://badgen.net/bundlephobia/minzip/vue-qrcode-reader" alt="size minified + gzipped">
</a>
<a href="https://www.npmjs.com/package/vue-qrcode-reader">
<img src="https://img.shields.io/npm/v/vue-qrcode-reader.svg" alt="npm current version">
</a>
<br>
<a href="https://github.com/vuejs/awesome-vue">
<img src="https://awesome.re/mentioned-badge.svg" alt="Mentioned in Awesome Vue">
</a>
<br>
<br>
<a href="https://gruhn.github.io/vue-qrcode-reader/demos/DecodeAll.html">live demos</a> |
<a href="https://gruhn.github.io/vue-qrcode-reader/api/QrcodeStream.html">api reference</a>
</p>
A set of Vue.js components, allowing you to detect and decode QR codes, without leaving the browser.
- :movie_camera: `QrcodeStream` accesses the device camera and continuously scans incoming frames.
- :put_litter_in_its_place: `QrcodeDropZone` renders to an empty region where you can drag-and-drop images to be decoded.
- :open_file_folder: `QrcodeCapture` is a classic file upload field, instantly scanning all files you select.
All components are responsive. Beyond that, close to zero styling. Make them fit your layout. Usage is simple and straight forward:
```html
<qrcode-stream @decode="onDecode"></qrcode-stream>
```
```js
methods: {
onDecode (decodedString) {
// ...
}
}
```
### Screenshots
<p align="center">
<img src="https://raw.githubusercontent.com/gruhn/vue-qrcode-reader/master/.github/screenshot1.png" height="500" alt="Screenshot 1">
<img src="https://raw.githubusercontent.com/gruhn/vue-qrcode-reader/master/.github/screenshot2.png" height="500" alt="Screenshot 2">
<img src="https://raw.githubusercontent.com/gruhn/vue-qrcode-reader/master/.github/screenshot3.png" height="500" alt="Screenshot 3">
</p>
# Installation :package:
## With NPM
Run
```bash
npm install vue-qrcode-reader
```
You can import the components independantly
```javascript
import { QrcodeStream, QrcodeDropZone, QrcodeCapture } from 'vue-qrcode-reader'
const MyComponent = {
components: {
QrcodeStream,
QrcodeDropZone,
QrcodeCapture
},
// ...
))
```
or register all of them globally right away
```javascript
import Vue from "vue";
import VueQrcodeReader from "vue-qrcode-reader";
Vue.use(VueQrcodeReader);
```
## Without NPM
Include the following JS file:
https://unpkg.com/vue-qrcode-reader/dist/VueQrcodeReader.umd.min.js
Make sure to include it after Vue:
```html
<script src="./vue.js"></script>
<script src="./VueQrcodeReader.umd.min.js"></script>
```
All components are automatically registered globally.
Use kebab-case to reference them in your templates:
```html
<qrcode-stream></qrcode-stream>
<qrcode-drop-zone></qrcode-drop-zone>
<qrcode-capture></qrcode-capture>
```
# Troubleshooting :zap:
### The wrong camera is picked by default. Can I set it explicitly?
Modern devices sometimes have multiple rear cameras.
Not all are optimal for scanning QR codes.
For example wide angle, infrared and virtual cameras.
With the current web API it's hard to pick the right camera automatically.
It's technically possible to let the user make that decision.
For example by displaying list of installed cameras and letting the user select the right one.
However, this is a user experience trade-off.
Native QR code reader applications don't face this trade-off.
That's why we want to find a different solution.
Please create a GitHub issue from the [wrong camera selected](https://github.com/gruhn/vue-qrcode-reader/issues/new?assignees=&labels=&template=wrong_camera.md&title=) template and follow the instructions in the text.
#### I don't see the camera when using `QrcodeStream`.
- Check if it works on the demo page. Especially the [Decode All](https://gruhn.github.io/vue-qrcode-reader/demos/DecodeAll.html) demo, since it renders error messages. If you see errors, consult the docs to understand their meaning.
- The demo works but it doesn't work in my project: Listen for the `init` event to investigate errors.
- The demo doesn't work: Carefully review the Browser Support section above. Maybe your device is just not supported.
#### I'm running a dev server on localhost. How to test on my mobile device without HTTPS?
- If your setup is Desktop Chrome + Android Chrome, use [Remote Debugging](https://developers.google.com/web/tools/chrome-devtools/remote-debugging/) which allows your Android device to [access your local server as localhost](https://developers.google.com/web/tools/chrome-devtools/remote-debugging/local-server).
- Otherwise use a reverse proxy like [ngrok](https://ngrok.com/) or [serveo](https://serveo.net/) to temporarily make your local server publicly available with HTTPS.
- There are also loads of serverless/static hosting services that have HTTPS enabled by default and where you can deploy your web app for free (e.g. *GitHub Pages*, *GitLab Pages*, *Google Firebase*, *Netlify*, *Heroku*, *ZEIT Now*, ...)
#### Some of my QR codes are not being detected.
- Make sure, there is some white border around the QR code.
- Color inverted QR codes are not supported (dark background, light foreground).
- [Model 1 QR codes](https://en.wikipedia.org/wiki/QR_code#Model_1) are also not supported.
# Thanks :pray:
<a href="https://browserstack.com">
<img height="38" src="https://raw.githubusercontent.com/gruhn/vue-qrcode-reader/master/.github/browserstack-logo.png" alt="BrowserStack Logo">
</a>

3
target/classes/static/lib/vue-qrcode-reader/babel.config.js

@ -0,0 +1,3 @@
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"]
};

54
target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/DemoWrapper.vue

@ -0,0 +1,54 @@
<template>
<component :is="currentDemo" />
</template>
<script>
import CustomTracking from './demos/CustomTracking.vue'
import DecodeAll from './demos/DecodeAll.vue'
import SwitchCamera from './demos/SwitchCamera.vue'
import DragDrop from './demos/DragDrop.vue'
import Upload from './demos/Upload.vue'
import Fullscreen from './demos/Fullscreen.vue'
import LoadingIndicator from './demos/LoadingIndicator.vue'
import Torch from './demos/Torch.vue'
import Validate from './demos/Validate.vue'
import ScanSameQrcodeMoreThanOnce from './demos/ScanSameQrcodeMoreThanOnce.vue'
export default {
components: {
DecodeAll,
CustomTracking,
SwitchCamera,
DragDrop,
Upload,
Fullscreen,
LoadingIndicator,
Torch,
Validate,
ScanSameQrcodeMoreThanOnce
},
props: {
component: String
},
data () {
return {
currentDemo: null
}
},
mounted () {
this.currentDemo = this.component
}
}
</script>
<style>
.decode-result {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

92
target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/demos/CustomTracking.vue

@ -0,0 +1,92 @@
<template>
<div>
<p>
Track function:
<select v-model="selected">
<option v-for="option in options" :key="option.text" :value="option">
{{ option.text }}
</option>
</select>
</p>
<qrcode-stream :key="_uid" :track="selected.value" @init="logErrors" />
</div>
</template>
<script>
import { QrcodeStream } from '../../../../src'
export default {
components: { QrcodeStream },
data () {
const options = [
{ text: "nothing (default)", value: undefined },
{ text: "outline", value: this.paintOutline },
{ text: "centered text", value: this.paintCenterText },
{ text: "bounding box", value: this.paintBoundingBox },
]
const selected = options[1]
return { selected, options }
},
methods: {
paintOutline (detectedCodes, ctx) {
for (const detectedCode of detectedCodes) {
const [ firstPoint, ...otherPoints ] = detectedCode.cornerPoints
ctx.strokeStyle = "red";
ctx.beginPath();
ctx.moveTo(firstPoint.x, firstPoint.y);
for (const { x, y } of otherPoints) {
ctx.lineTo(x, y);
}
ctx.lineTo(firstPoint.x, firstPoint.y);
ctx.closePath();
ctx.stroke();
}
},
paintBoundingBox (detectedCodes, ctx) {
for (const detectedCode of detectedCodes) {
const { boundingBox: { x, y, width, height } } = detectedCode
ctx.lineWidth = 2
ctx.strokeStyle = '#007bff'
ctx.strokeRect(x, y, width, height)
}
},
paintCenterText (detectedCodes, ctx) {
for (const detectedCode of detectedCodes) {
const { boundingBox, rawValue } = detectedCode
const centerX = boundingBox.x + boundingBox.width/ 2
const centerY = boundingBox.y + boundingBox.height/ 2
const fontSize = Math.max(12, 50 * boundingBox.width/ctx.canvas.width)
console.log(boundingBox.width, ctx.canvas.width)
ctx.font = `bold ${fontSize}px sans-serif`
ctx.textAlign = "center"
ctx.lineWidth = 3
ctx.strokeStyle = '#35495e'
ctx.strokeText(detectedCode.rawValue, centerX, centerY)
ctx.fillStyle = '#5cb984'
ctx.fillText(rawValue, centerX, centerY)
}
},
logErrors (promise) {
promise.catch(console.error)
}
}
}
</script>

62
target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/demos/DecodeAll.vue

@ -0,0 +1,62 @@
<template>
<div>
<p class="error">{{ error }}</p>
<p class="decode-result">Last result: <b>{{ result }}</b></p>
<qrcode-stream @decode="onDecode" @init="onInit" />
</div>
</template>
<script>
import { QrcodeStream } from '../../../../src'
export default {
components: { QrcodeStream },
data () {
return {
result: '',
error: ''
}
},
methods: {
onDecode (result) {
this.result = result
},
async onInit (promise) {
try {
await promise
} catch (error) {
if (error.name === 'NotAllowedError') {
this.error = "ERROR: you need to grant camera access permission"
} else if (error.name === 'NotFoundError') {
this.error = "ERROR: no camera on this device"
} else if (error.name === 'NotSupportedError') {
this.error = "ERROR: secure context required (HTTPS, localhost)"
} else if (error.name === 'NotReadableError') {
this.error = "ERROR: is the camera already in use?"
} else if (error.name === 'OverconstrainedError') {
this.error = "ERROR: installed cameras are not suitable"
} else if (error.name === 'StreamApiNotSupportedError') {
this.error = "ERROR: Stream API is not supported in this browser"
} else if (error.name === 'InsecureContextError') {
this.error = 'ERROR: Camera access is only permitted in secure context. Use HTTPS or localhost rather than HTTP.';
} else {
this.error = `ERROR: Camera error (${error.name})`;
}
}
}
}
}
</script>
<style scoped>
.error {
font-weight: bold;
color: red;
}
</style>

80
target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/demos/DragDrop.vue

@ -0,0 +1,80 @@
<template>
<div>
<p class="decode-result">Last result: <b>{{ result }}</b></p>
<p v-if="error !== null" class="drop-error">
{{ error }}
</p>
<qrcode-drop-zone @detect="onDetect" @dragover="onDragOver" @init="logErrors">
<div class="drop-area" :class="{ 'dragover': dragover }">
DROP SOME IMAGES HERE
</div>
</qrcode-drop-zone>
</div>
</template>
<script>
import { QrcodeDropZone } from '../../../../src'
export default {
components: { QrcodeDropZone },
data () {
return {
result: null,
error: null,
dragover: false
}
},
methods: {
async onDetect (promise) {
try {
const { content } = await promise
this.result = content
this.error = null
} catch (error) {
if (error.name === 'DropImageFetchError') {
this.error = 'Sorry, you can\'t load cross-origin images :/'
} else if (error.name === 'DropImageDecodeError') {
this.error = 'Ok, that\'s not an image. That can\'t be decoded.'
} else {
this.error = 'Ups, what kind of error is this?! ' + error.message
}
}
},
logErrors (promise) {
promise.catch(console.error)
},
onDragOver (isDraggingOver) {
this.dragover = isDraggingOver
}
}
}
</script>
<style>
.drop-area {
height: 300px;
color: #fff;
text-align: center;
font-weight: bold;
padding: 10px;
background-color: rgba(0,0,0,.5);
}
.dragover {
background-color: rgba(0,0,0,.8);
}
.drop-error {
color: red;
font-weight: bold;
}
</style>

115
target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/demos/Fullscreen.vue

@ -0,0 +1,115 @@
<template>
<div :class="{ 'fullscreen': fullscreen }" ref="wrapper" @fullscreenchange="onFullscreenChange">
<qrcode-stream @init="logErrors">
<button @click="fullscreen = !fullscreen" class="fullscreen-button">
<img :src="$withBase(fullscreenIcon)" alt="toggle fullscreen" />
</button>
</qrcode-stream>
</div>
</template>
<script>
import { QrcodeStream } from '../../../../src'
// NOTE: calling `requestFullscreen` might prompt the user with another
// permission dialog. You already asked for camera access permission so this is
// a rather invasive move.
//
// Even without calling `requestFullscreen` the entire viewport is covered
// by the camera stream. So consider skipping `requestFullscreen` in your
// implementation.
export default {
components: { QrcodeStream },
data () {
return {
fullscreen: false
}
},
computed: {
fullscreenIcon() {
if (this.fullscreen) {
return "/fullscreen-exit.svg"
} else {
return "/fullscreen.svg"
}
}
},
watch: {
fullscreen(enterFullscreen) {
if (enterFullscreen) {
this.requestFullscreen()
} else {
this.exitFullscreen()
}
}
},
methods: {
onFullscreenChange(event) {
// This becomes important when the user doesn't use the button to exit
// fullscreen but hits ESC on desktop, pushes a physical back button on
// mobile etc.
this.fullscreen = document.fullscreenElement !== null
},
requestFullscreen() {
const elem = this.$refs.wrapper
if (elem.requestFullscreen) {
elem.requestFullscreen();
} else if (elem.mozRequestFullScreen) { /* Firefox */
elem.mozRequestFullScreen();
} else if (elem.webkitRequestFullscreen) { /* Chrome, Safari and Opera */
elem.webkitRequestFullscreen();
} else if (elem.msRequestFullscreen) { /* IE/Edge */
elem.msRequestFullscreen();
}
},
exitFullscreen() {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.mozCancelFullScreen) { /* Firefox */
document.mozCancelFullScreen();
} else if (document.webkitExitFullscreen) { /* Chrome, Safari and Opera */
document.webkitExitFullscreen();
} else if (document.msExitFullscreen) { /* IE/Edge */
document.msExitFullscreen();
}
},
logErrors (promise) {
promise.catch(console.error)
}
}
}
</script>
<style scoped>
.fullscreen {
position: fixed;
z-index: 1000;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
.fullscreen-button {
background-color: white;
position: absolute;
bottom: 0;
right: 0;
margin: 1rem;
}
.fullscreen-button img {
width: 2rem;
}
</style>

61
target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/demos/LoadingIndicator.vue

@ -0,0 +1,61 @@
<template>
<div>
<button @click="reload">Destroy And Re-Create Component</button>
<qrcode-stream @init="onInit" v-if="!destroyed">
<div class="loading-indicator" v-if="loading">
Loading...
</div>
</qrcode-stream>
</div>
</template>
<script>
import { QrcodeStream } from '../../../../src'
export default {
components: { QrcodeStream },
data () {
return {
loading: false,
destroyed: false
}
},
methods: {
async onInit (promise) {
this.loading = true
try {
await promise
} catch (error) {
console.error(error)
} finally {
this.loading = false
}
},
async reload () {
this.destroyed = true
await this.$nextTick()
this.destroyed = false
}
}
}
</script>
<style scoped>
button {
margin-bottom: 20px;
}
.loading-indicator {
font-weight: bold;
font-size: 2rem;
text-align: center;
}
</style>

78
target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/demos/ScanSameQrcodeMoreThanOnce.vue

@ -0,0 +1,78 @@
<template>
<div>
<p class="decode-result">Last result: <b>{{ result }}</b></p>
<qrcode-stream :camera="camera" @decode="onDecode" @init="onInit">
<div v-show="showScanConfirmation" class="scan-confirmation">
<img :src="$withBase('/checkmark.svg')" alt="Checkmark" width="128px" />
</div>
</qrcode-stream>
</div>
</template>
<script>
import { QrcodeStream } from '../../../../src'
export default {
components: { QrcodeStream },
data () {
return {
camera: 'auto',
result: null,
showScanConfirmation: false
}
},
methods: {
async onInit (promise) {
try {
await promise
} catch (e) {
console.error(e)
} finally {
this.showScanConfirmation = this.camera === "off"
}
},
async onDecode (content) {
this.result = content
this.pause()
await this.timeout(500)
this.unpause()
},
unpause () {
this.camera = 'auto'
},
pause () {
this.camera = 'off'
},
timeout (ms) {
return new Promise(resolve => {
window.setTimeout(resolve, ms)
})
}
}
}
</script>
<style scoped>
.scan-confirmation {
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, .8);
display: flex;
flex-flow: row nowrap;
justify-content: center;
}
</style>

82
target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/demos/SwitchCamera.vue

@ -0,0 +1,82 @@
<template>
<div>
<p class="error" v-if="noFrontCamera">
You don't seem to have a front camera on your device
</p>
<p class="error" v-if="noRearCamera">
You don't seem to have a rear camera on your device
</p>
<qrcode-stream :camera="camera" @init="onInit">
<button @click="switchCamera">
<img :src="$withBase('/camera-switch.svg')" alt="switch camera">
</button>
</qrcode-stream>
</div>
</template>
<script>
import { QrcodeStream } from '../../../../src'
export default {
components: { QrcodeStream },
data () {
return {
camera: 'rear',
noRearCamera: false,
noFrontCamera: false
}
},
methods: {
switchCamera () {
switch (this.camera) {
case 'front':
this.camera = 'rear'
break
case 'rear':
this.camera = 'front'
break
}
},
async onInit (promise) {
try {
await promise
} catch (error) {
const triedFrontCamera = this.camera === 'front'
const triedRearCamera = this.camera === 'rear'
const cameraMissingError = error.name === 'OverconstrainedError'
if (triedRearCamera && cameraMissingError) {
this.noRearCamera = true
}
if (triedFrontCamera && cameraMissingError) {
this.noFrontCamera = true
}
console.error(error)
}
}
}
}
</script>
<style scoped>
button {
position: absolute;
left: 10px;
top: 10px;
}
.error {
color: red;
font-weight: bold;
}
</style>

64
target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/demos/Torch.vue

@ -0,0 +1,64 @@
<template>
<div>
<p v-if="torchNotSupported" class="error">
Torch not supported for active camera
</p>
<qrcode-stream :torch="torchActive" @init="onInit">
<button @click="torchActive = !torchActive" :disabled="torchNotSupported">
<img :src="$withBase(icon)" alt="toggle torch">
</button>
</qrcode-stream>
</div>
</template>
<script>
import { QrcodeStream } from '../../../../src'
export default {
components: { QrcodeStream },
data () {
return {
torchActive: false,
torchNotSupported: false
}
},
computed: {
icon() {
if (this.torchActive)
return '/flash-off.svg'
else
return '/flash-on.svg'
}
},
methods: {
async onInit (promise) {
try {
const { capabilities } = await promise
console.log(capabilities);
this.torchNotSupported = !capabilities.torch
} catch (error) {
console.error(error)
}
}
}
}
</script>
<style scoped>
button {
position: absolute;
left: 10px;
top: 10px;
}
.error {
color: red;
font-weight: bold;
}
</style>

47
target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/demos/Upload.vue

@ -0,0 +1,47 @@
<template>
<div>
<p>
Capture:
<select v-model="selected">
<option v-for="option in options" :key="option.text" :value="option">
{{ option.text }}
</option>
</select>
</p>
<hr/>
<p class="decode-result">Last result: <b>{{ result }}</b></p>
<qrcode-capture @decode="onDecode" :capture="selected.value" />
</div>
</template>
<script>
import { QrcodeCapture } from '../../../../src'
export default {
components: { QrcodeCapture },
data () {
const options = [
{ text: "rear camera (default)", value: "environment" },
{ text: "front camera", value: "user" },
{ text: "force file dialog", value: false },
]
return {
result: '',
options,
selected: options[0]
}
},
methods: {
onDecode (result) {
this.result = result
}
}
}
</script>

118
target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/components/demos/Validate.vue

@ -0,0 +1,118 @@
<template>
<div>
<p class="decode-result">Last result: <b>{{ result }}</b></p>
<qrcode-stream :camera="camera" @decode="onDecode" @init="onInit">
<div v-if="validationSuccess" class="validation-success">
This is a URL
</div>
<div v-if="validationFailure" class="validation-failure">
This is NOT a URL!
</div>
<div v-if="validationPending" class="validation-pending">
Long validation in progress...
</div>
</qrcode-stream>
</div>
</template>
<script>
import { QrcodeStream } from '../../../../src'
export default {
components: { QrcodeStream },
data () {
return {
isValid: undefined,
camera: 'auto',
result: null,
}
},
computed: {
validationPending () {
return this.isValid === undefined
&& this.camera === 'off'
},
validationSuccess () {
return this.isValid === true
},
validationFailure () {
return this.isValid === false
}
},
methods: {
onInit (promise) {
promise
.catch(console.error)
.then(this.resetValidationState)
},
resetValidationState () {
this.isValid = undefined
},
async onDecode (content) {
this.result = content
this.turnCameraOff()
// pretend it's taking really long
await this.timeout(3000)
this.isValid = content.startsWith('http')
// some more delay, so users have time to read the message
await this.timeout(2000)
this.turnCameraOn()
},
turnCameraOn () {
this.camera = 'auto'
},
turnCameraOff () {
this.camera = 'off'
},
timeout (ms) {
return new Promise(resolve => {
window.setTimeout(resolve, ms)
})
}
}
}
</script>
<style scoped>
.validation-success,
.validation-failure,
.validation-pending {
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, .8);
text-align: center;
font-weight: bold;
font-size: 1.4rem;
padding: 10px;
display: flex;
flex-flow: column nowrap;
justify-content: center;
}
.validation-success {
color: green;
}
.validation-failure {
color: red;
}
</style>

41
target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/config.js

@ -0,0 +1,41 @@
module.exports = {
title: 'Vue Qrcode Reader',
description: 'A set of Vue.js components for detecting and decoding QR codes.',
base: '/vue-qrcode-reader/',
extraWatchFiles: [
'../src/'
],
themeConfig: {
repo: 'gruhn/vue-qrcode-reader',
sidebar: {
'/demos/': [
'Simple',
'DecodeAll',
'CustomTracking',
'LoadingIndicator',
'ScanSameQrcodeMoreThanOnce',
'Validate',
'SwitchCamera',
'Fullscreen',
'Torch',
'DragDrop',
'Upload'
],
'/api/': [
'QrcodeStream',
'QrcodeDropZone',
'QrcodeCapture'
],
},
nav: [
{ text: 'Live Demos', link: '/demos/CustomTracking' },
{ text: 'API Reference', link: '/api/QrcodeStream' }
]
}
}

1
target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/public/camera-switch.svg

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M15,15.5V13H9V15.5L5.5,12L9,8.5V11H15V8.5L18.5,12M20,4H16.83L15,2H9L7.17,4H4A2,2 0 0,0 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V6C22,4.89 21.1,4 20,4Z" /></svg>

After

Width:  |  Height:  |  Size: 445 B

1
target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/public/checkmark.svg

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M12 2C6.5 2 2 6.5 2 12S6.5 22 12 22 22 17.5 22 12 17.5 2 12 2M12 20C7.59 20 4 16.41 4 12S7.59 4 12 4 20 7.59 20 12 16.41 20 12 20M16.59 7.58L10 14.17L7.41 11.59L6 13L10 17L18 9L16.59 7.58Z" fill="#3eaf7c" /></svg>

After

Width:  |  Height:  |  Size: 499 B

102
target/classes/static/lib/vue-qrcode-reader/docs/.vuepress/public/debug-memory-leak.html

@ -0,0 +1,102 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<video id="video" autoplay muted playsinline></video>
</body>
<script type="module">
import BarcodeDetector from "https://cdn.skypack.dev/barcode-detector@0.5.0";
const adaptOldFormat = detectedCodes => {
if (detectedCodes.length > 0) {
const [ firstCode ] = detectedCodes;
const [
topLeftCorner,
topRightCorner,
bottomRightCorner,
bottomLeftCorner
] = firstCode.cornerPoints
return {
content: firstCode.rawValue,
location: {
topLeftCorner,
topRightCorner,
bottomRightCorner,
bottomLeftCorner,
// not supported by native API:
topLeftFinderPattern: {},
topRightFinderPattern: {},
bottomLeftFinderPattern: {}
},
imageData: null
}
} else {
return {
content: null,
location: null,
imageData: null
}
}
}
export const keepScanning = (videoElement, options) => {
const barcodeDetector = new BarcodeDetector({ formats: ["qr_code"] });
const { detectHandler, locateHandler, minDelay } = options;
const processFrame = state => async timeNow => {
if (videoElement.readyState > 1) {
console.log("scan")
const { lastScanned, contentBefore, locationBefore } = state
if (timeNow - lastScanned >= minDelay) {
const detectedCodes = await barcodeDetector.detect(videoElement);
const { content, location, imageData } = adaptOldFormat(detectedCodes)
if (content !== null && content !== contentBefore) {
detectHandler({ content, location, imageData });
}
if (location !== null || locationBefore !== null) {
locateHandler(detectedCodes);
}
window.requestAnimationFrame(processFrame({
lastScanned: timeNow,
contentBefore: content ?? contentBefore,
locationBefore: location
}))
} else {
window.requestAnimationFrame(processFrame(state))
}
}
};
processFrame({
contentBefore: null,
locationBefore: null,
lastScanned: performance.now()
})();
};
(async () => {
const videoEl = document.querySelector('#video')
const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: false })
videoEl.srcObject = stream
videoEl.addEventListener("loadeddata", () => {
keepScanning(videoEl, { minDelay: 40, detectHandler: console.log, locateHandler: console.log })
})
})()
</script>
</html>

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save