Browse Source

init

main
yk 2 years ago
parent
commit
7453d26a7e
100 changed files with 7884 additions and 0 deletions
  1. +3
    -0
      . eslintignore
  2. +9
    -0
      .browserslistrc
  3. +2
    -0
      .dockerignore
  4. +2
    -0
      .env.dev
  5. +2
    -0
      .env.prod
  6. +2
    -0
      .env.test
  7. +23
    -0
      .eslintrc.js
  8. +23
    -0
      .gitignore
  9. +5
    -0
      .npmrc
  10. +10
    -0
      .prettierrc
  11. +7
    -0
      .stylelintrc
  12. +12
    -0
      babel.config.js
  13. +96
    -0
      nginx.conf
  14. +60
    -0
      package.json
  15. +515
    -0
      public/config.json
  16. BIN
      public/favicon.ico
  17. +85
    -0
      public/global.js
  18. +20
    -0
      public/index.html
  19. +106
    -0
      src/App.vue
  20. +451
    -0
      src/api/cloudia-sdk-v1.4.1.js
  21. BIN
      src/assets/ad_images.zip
  22. BIN
      src/assets/ads/10.jpg
  23. BIN
      src/assets/ads/1234567890.mp4
  24. BIN
      src/assets/ads/17.jpg
  25. BIN
      src/assets/ads/2.jpg
  26. BIN
      src/assets/ads/img_1.png
  27. BIN
      src/assets/back.png
  28. BIN
      src/assets/close.png
  29. BIN
      src/assets/ic_back.png
  30. BIN
      src/assets/ic_photo_error.png
  31. BIN
      src/assets/ic_photo_loading.png
  32. BIN
      src/assets/loading2.gif
  33. BIN
      src/assets/logo.png
  34. BIN
      src/assets/qrcode.png
  35. +684
    -0
      src/components/DemoView.vue
  36. +398
    -0
      src/components/JsonView.vue
  37. +193
    -0
      src/components/SwiperView.vue
  38. +74
    -0
      src/components/VideoView.vue
  39. +68
    -0
      src/config/cmdDict.js
  40. +80
    -0
      src/config/index.js
  41. +19
    -0
      src/db/dbHelp.js
  42. +90
    -0
      src/db/dbRouter.js
  43. +54
    -0
      src/db/mssql.js
  44. +10
    -0
      src/db/sql.js
  45. +44
    -0
      src/main.js
  46. +284
    -0
      src/mixins/mixin.js
  47. +321
    -0
      src/mixins/mixin_demo.js
  48. +156
    -0
      src/mixins/mixin_socket.js
  49. +7
    -0
      src/packages/meta.js
  50. +87
    -0
      src/packages/nf-meta/help.js
  51. +135
    -0
      src/packages/nf-meta/loadmeta-json.js
  52. +206
    -0
      src/packages/nf-meta/loadmeta-sql.js
  53. +100
    -0
      src/packages/nf-meta/savemeta-db.js
  54. +116
    -0
      src/packages/nf-ws-indexeddb/_toIndex.js
  55. +19
    -0
      src/packages/nf-ws-indexeddb/_toObject.js
  56. +26
    -0
      src/packages/nf-ws-indexeddb/begin-init.js
  57. +32
    -0
      src/packages/nf-ws-indexeddb/begin-tran.js
  58. +266
    -0
      src/packages/nf-ws-indexeddb/help.js
  59. +149
    -0
      src/packages/nf-ws-indexeddb/install.js
  60. +101
    -0
      src/packages/nf-ws-indexeddb/list-all.js
  61. +60
    -0
      src/packages/nf-ws-indexeddb/list-index.js
  62. +120
    -0
      src/packages/nf-ws-indexeddb/list-pager.js
  63. +36
    -0
      src/packages/nf-ws-indexeddb/model-add.js
  64. +35
    -0
      src/packages/nf-ws-indexeddb/model-count.js
  65. +33
    -0
      src/packages/nf-ws-indexeddb/model-delete.js
  66. +36
    -0
      src/packages/nf-ws-indexeddb/model-get.js
  67. +43
    -0
      src/packages/nf-ws-indexeddb/model-put.js
  68. +53
    -0
      src/packages/nf-ws-indexeddb/model-set.js
  69. +30
    -0
      src/packages/nf-ws-indexeddb/store-clear.js
  70. +34
    -0
      src/packages/nf-ws-websql/_pager-info.js
  71. +82
    -0
      src/packages/nf-ws-websql/_where-query.js
  72. +53
    -0
      src/packages/nf-ws-websql/data-add.js
  73. +31
    -0
      src/packages/nf-ws-websql/data-delete.js
  74. +32
    -0
      src/packages/nf-ws-websql/data-deleteflag.js
  75. +31
    -0
      src/packages/nf-ws-websql/data-get.js
  76. +54
    -0
      src/packages/nf-ws-websql/data-set.js
  77. +50
    -0
      src/packages/nf-ws-websql/data-update.js
  78. +28
    -0
      src/packages/nf-ws-websql/db-delete.js
  79. +203
    -0
      src/packages/nf-ws-websql/help.js
  80. +152
    -0
      src/packages/nf-ws-websql/install.js
  81. +48
    -0
      src/packages/nf-ws-websql/list-all.js
  82. +31
    -0
      src/packages/nf-ws-websql/list-count.js
  83. +51
    -0
      src/packages/nf-ws-websql/list-pager.js
  84. +40
    -0
      src/packages/nf-ws-websql/table-create.js
  85. +28
    -0
      src/packages/nf-ws-websql/table-delete.js
  86. +31
    -0
      src/packages/storage.js
  87. +126
    -0
      src/packages/vue-localstore/index.js
  88. +452
    -0
      src/plugins/db.js
  89. +10
    -0
      src/plugins/lazyload.js
  90. +16
    -0
      src/plugins/mintui.js
  91. +149
    -0
      src/plugins/socket.js
  92. +134
    -0
      src/requests/axios.js
  93. +41
    -0
      src/requests/request-cors.js
  94. +5
    -0
      src/requests/request.js
  95. +87
    -0
      src/router/dbRouter.js
  96. +21
    -0
      src/router/index.js
  97. +42
    -0
      src/router/socketSrv.js
  98. +28
    -0
      src/server/dbHandle.js
  99. +24
    -0
      src/styles/dimens.scss
  100. +172
    -0
      src/utils/genTtsText.js

+ 3
- 0
. eslintignore View File

@@ -0,0 +1,3 @@
.vscode
node_modules
dist

+ 9
- 0
.browserslistrc View File

@@ -0,0 +1,9 @@
# Browsers that we support
> 1%
last 2 versions
not dead
# Node.js that we support
node >= 8.11.0

+ 2
- 0
.dockerignore View File

@@ -0,0 +1,2 @@
**/node_modules
**/dist

+ 2
- 0
.env.dev View File

@@ -0,0 +1,2 @@
NODE_ENV='development'
VUE_APP_SERVER_URL=https://localhost:8080

+ 2
- 0
.env.prod View File

@@ -0,0 +1,2 @@
NODE_ENV='production'
VUE_APP_SERVER_URL=https://127.0.0.1

+ 2
- 0
.env.test View File

@@ -0,0 +1,2 @@
NODE_ENV='test'
VUE_APP_SERVER_URL=http://10.12.96.114:8082/

+ 23
- 0
.eslintrc.js View File

@@ -0,0 +1,23 @@
module.exports = {
root: true,
env: {
node: true
},
extends: [
// "eslint:recommended",
"plugin:vue/base",
"plugin:vue/essential",
"plugin:vue/strongly-recommended",
"plugin:vue/recommended",
"@vue/prettier",
"prettier/babel"
],
parserOptions: {
parser: "babel-eslint"
},
rules: {
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off"
}
};

+ 23
- 0
.gitignore View File

@@ -0,0 +1,23 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
!.vscode/launch.json
!.vscode/settings.json
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

+ 5
- 0
.npmrc View File

@@ -0,0 +1,5 @@
# For fix low severity vulnerability of package yargs-parser
# registry=https://registry.npmjs.org
# For speeding up jenkins compile process
registry=https://registry.npm.taobao.org

+ 10
- 0
.prettierrc View File

@@ -0,0 +1,10 @@
{
"eslintIntegration": true,
"formatOnSave": false,
"tabWidth": 4,
"printWidth": 120,
"arrowParens": "always"
}

+ 7
- 0
.stylelintrc View File

@@ -0,0 +1,7 @@
{
"rules": {
"selector-pseudo-element-no-unknown": [true, {
"ignorePseudoElements": ["-webkit-media-controls-enclosure"]
}]
}
}

+ 12
- 0
babel.config.js View File

@@ -0,0 +1,12 @@
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"],
plugins: [
[
"component",
{
libraryName: "mint-ui",
style: true
}
]
]
};

+ 96
- 0
nginx.conf View File

@@ -0,0 +1,96 @@
user www-data;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr($http_x_real_ip) - $remote_user [$time_local] '
'$ssl_protocol/$ssl_cipher '
'"$http_host($http_true_client_ip:$upstream_addr) $request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" "$http_x_forwarded_for"'
'\n';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
gzip on;
gzip_static on;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
gzip_proxied expired no-cache no-store private auth;
gzip_comp_level 1;
gzip_min_length 10k;
gzip_types
text/plain
text/css
text/js
text/javascript
text/html
text/xml
text/x-component
application/javascript
application/x-javascript
application/json
application/xhtml+xml
application/xml
application/rss+xml
application/x-font-ttf
application/vnd.ms-fontobject
font/truetype
font/opentype
image/svg+xml svg svgz;
map $http_accept $webp_suffix {
default "";
"~*webp" ".webp";
}
map $msie $cache_control {
"1" "private";
}
map $msie $vary_header {
default "Accept";
"1" "";
}
server {
listen 8888 ssl http2;
listen [::]:8888 ssl http2;
server_name test.cloudminds.com;
ssl_certificate /etc/nginx/cert/214971167760195.pem;
ssl_certificate_key /etc/nginx/cert/214971167760195.key;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
root /srv/www/cloudia-fe-mall;
index index.html;
try_files $uri $uri/ /index.html;
}
location ~* .(jpe?g|png|gif|svg)$ {
root /srv/www/cloudia-fe-mall;
add_header Vary $vary_header;
add_header Cache-Control $cache_control;
try_files $uri$webp_suffix $uri =404;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}

+ 60
- 0
package.json View File

@@ -0,0 +1,60 @@
{
"name": "aobei-aiman",
"version": "1.0.0",
"info": "奥北数字人",
"private": true,
"scripts": {
"serve": "vue-cli-service serve --open",
"build": "vue-cli-service build --modern --mode development",
"build:test": "vue-cli-service build --modern --mode test",
"build:prod": "vue-cli-service build --modern --mode production",
"lint": "vue-cli-service lint --no-fix",
"lint:fix": "vue-cli-service lint",
"analyze": "cross-env ANALYZER=true npm run build:prod && webpack-bundle-analyzer --port 8123 dist/stats.json"
},
"dependencies": {
"axios": "^0.19.2",
"core-js": "^3.6.4",
"element-ui": "^2.15.10",
"js-md5": "^0.7.3",
"jsencrypt": "^3.2.1",
"lodash": "^4.17.15",
"mint-ui": "^2.2.13",
"moment": "^2.29.4",
"video.js": "^7.20.3",
"videojs-flash": "^2.2.1",
"vue": "^2.6.11",
"vue-grid-layout": "^2.3.7",
"vue-lazyload": "^1.3.3",
"vue-navigation": "^1.1.4",
"vue-router": "^3.1.6"
},
"devDependencies": {
"@amap/amap-jsapi-loader": "0.0.1",
"@vue/cli-plugin-babel": "~4.3.0",
"@vue/cli-plugin-eslint": "~4.3.0",
"@vue/cli-plugin-router": "~4.3.0",
"@vue/cli-plugin-vuex": "~4.3.0",
"@vue/cli-service": "~4.3.0",
"@vue/eslint-config-prettier": "^6.0.0",
"babel-eslint": "^10.1.0",
"babel-plugin-component": "^1.1.1",
"babel-plugin-lodash": "^3.3.4",
"compression-webpack-plugin": "^3.1.0",
"copy-webpack-plugin": "^6.0.2",
"cross-env": "^7.0.2",
"eslint": "^6.7.2",
"eslint-plugin-prettier": "^3.1.1",
"eslint-plugin-vue": "^6.2.2",
"imagemin-mozjpeg": "^8.0.0",
"imagemin-webp-webpack-plugin": "^3.3.1",
"imagemin-webpack-plugin": "^2.4.2",
"jquery": "^3.6.1",
"prettier": "^1.19.1",
"sass": "^1.26.3",
"sass-loader": "^8.0.2",
"vue-awesome-swiper": "^3.1.3",
"vue-template-compiler": "^2.6.11",
"webpack-bundle-analyzer": "^3.7.0"
}
}

+ 515
- 0
public/config.json View File

@@ -0,0 +1,515 @@
{
"ttsControlEnable": true,
"qp": {
"type": 1,
"equip_no": "2",
"set_no": "2",
"value": "AlarmCenter.ScreensAddin.ScreensCommand",
"name": "全屏",
"info": "已为您打开全屏",
"top": 0
},
"fhsy": {
"type": 1,
"equip_no": "2",
"set_no": "1701",
"value": "AlarmCenter.ScreensAddin.ScreensCommand",
"name": "首页",
"info": "已返回首页",
"top": 0
},

"af_open": {
"type": 3,
"path": "/api/real/Security/setup_SecurityOpenPage",
"data": {
"page_no": "2",
"mes": "打开安防态势"
},
"msg": "已为您打开安防态势"
},

"af_camera_open":{
"type": 3,
"path": "/api/real/Security/setup_CameraService",
"data": {
"page_no": "2",
"mes": "园区监控",
"equip_no":2,
"value":1,
"set_no": ""
},
"msg": "已为您打开园区监控"
},


"ny_open": {
"type": 3,
"path": "/api/real/Comprehensive/setup_EnergyOpenPage",
"data": {
"page_no": "5",
"mes": "打开能源态势"
},
"msg": "已为您打开能源态势"
},
"xf_open": {
"type": 3,
"path": "/api/real/Comprehensive/setup_FireControlOpenPage",
"data": {
"page_no": "6",
"mes": "打开消防态势"
},
"msg": "已为您打开消防态势"
},
"zhh_open": {
"type": 3,
"path": "/api/real/Comprehensive/setup_ComprehensiveOpenPage",
"data": {
"page_no": "1",
"mes": "打开综合态势"
},
"msg": "已为您打开综合态势"

},

"zhh_company_open": {
"type": 3,
"path": "/api/real/Comprehensive/setup_CompanyInfo",
"data": {
"page_no": 1,
"mes": "打开公司介绍",
"companyFlag":1,
"companyName":""
},
"msg": "#[companyInfo]"

},

"ry_open": {
"type": 3,
"mes": "打开人员态势",
"path": "/api/real/Person/post_PersonOpenPage",
"data": {
"page_no": "3",
"mes": "打开人员态势"
},
"msg": "",
"after_exec": "ry_sj"
},
"qqbj_open": {
"type": 3,
"path": "/api/real/Comprehensive/setup_GlobalOpenPage",
"data": {
"page_no": "7",
"page_action":"1",
"mes": "打开全球业务布局"
},
"msg": "已为您打开全球业务布局"
},
"cnbj_open": {
"type": 3,
"path": "/api/real/Comprehensive/setup_ChinaOpenPage",
"data": {
"page_no": "8",
"page_action":"1",
"mes": "打开中国业务布局"
},
"msg": "已为您打开中国业务布局"
},
"ab_open": {
"type": 3,
"mes": "打开奥北科技园",
"path": "/api/real/Comprehensive/setup_ScienceParkOpenPage",
"data": {
"page_no": "9",
"page_action": "1",
"mes": "打开奥北科技园"
},
"msg": "已为您打开奥北科技园"
},
"ry_sj": {
"type": 3,
"path": "/api/real/Person/post_PeopleValue",
"data": {
"page_no": "3",
"mes": "人员所有信息"
},
"msg": "现在为您展示的是人员态势,当前20楼内总人数#[peopleCount]人,通过首层大堂闸机通行人数#[passCount]人,其中人脸识别#[faceCount]人,刷卡识别#[cardCount]人。"
},
"ry_sb": {
"type": 3,
"path": "/api/real/Person/post_EquipCount",
"data": {
"page_no": "3",
"mes": "设备状态统计"
},
"msg": "当前设备在线#[onLineEquip]台,设备离线#[offLineEquip]台;在线率#[onLineROL]"
},
"ry_zlry": {
"type": 3,
"mes": "今日在楼人员统计",
"path": "/api/real/Person/post_PeopleCount",
"data": {
"page_no": "3",
"mes": "今日在楼人员统计"
},
"msg": "当前20楼内总人数#[peopleCount]人"
},
"ry_sbzt": {
"type": 3,
"mes": "设备状态统计",
"path": "/api/real/Person/post_EquipCount",
"data": {
"page_no": "3",
"mes": "设备状态统计"
},
"msg": ""
},
"ry_rycr": {
"type": 3,
"mes": "人员出入统计",
"path": "/api/real/Person/post_PeopleCountStatistics",
"data": {
"page_no": "3",
"mes": "人员出入统计"
},
"msg": "当前20楼内通过首层大堂闸机通行进入#[enterPeopleCount]人,离开#[leavPeopleCount]人。"
},
"ry_dkzj": {
"type": 3,
"mes": "打开闸机",
"path": "/api/real/Person/post_PersonPassRecord",
"data": {
"page_no": "3",
"equip_no": "2",
"set_no": "",
"value": "1",
"mes": "打开闸机"
},
"setNoMapping": {
"一号通道": 674,
"二号通道": 673,
"三号通道": 672,
"四号通道": 671,
"五号通道": 670,
"一号闸机": 674,
"二号闸机": 673,
"三号闸机": 672,
"四号闸机": 671,
"五号闸机": 670
},
"msg": "已为您打开闸机"
},
"tc_open": {
"type": 3,
"mes": "打开停车态势",
"path": "/api/real/Person/post_PersonOpenPage",
"data": {
"page_no": "4",
"mes": "打开停车态势"
},
"msg": "",
"after_exec": "tc_sj"
},
"tc_zccl": {
"type": 3,
"mes": "注册车辆统计",
"path": "/api/real/Park/post_RegisterCarCount",
"data": {
"page_no": "4",
"mes": "注册车辆统计"
},
"msg": "园区目前注册车辆数是#[registerCarCount]辆"

},
"tc_sj": {
"type": 3,
"mes": "停车所有信息",
"path": "/api/real/Park/post_CarValue",
"data": {
"page_no": "4",
"mes": "停车所有信息"
},
"msg": "现在为您展示的是停车态势,当前园区总车位数量是#[allParkCount],剩余车位数量是#[leveParkCount];注册车辆数是#[registerCarCount]辆;本日车辆进入数是#[enterCarCount],离开车辆数是#[leavCarCount]。"

},
"tc_dqcw": {
"type": 3,
"mes": "当前车位统计",
"path": "/api/real/Park/post_ParkCount",
"data": {
"page_no": "4",
"mes": "当前车位统计"
},
"msg": "园区目前总车位数量是#[allParkCount],剩余车位数量是#[leveParkCount]"
},
"tc_crtj": {
"type": 3,
"mes": "车辆出入统计",
"path": "/api/real/Park/post_CarCount",
"data": {
"page_no": "4",
"mes": "车辆出入统计"
},
"msg": "园区当日车辆进入数是#[enterCarCount],离开车辆数是#[leavCarCount]"
},
"tc_jk": {
"type": 3,
"path": "/api/real/Park/post_OpenPark",
"data": {
"page_no": "4",
"page_action":"1",
"mes": ""
},
"msg": "好的"
},
"tc_sbzt": {
"type": 3,
"mes": "设备状态统计",
"path": "/api/real/Park/post_EquipCount",
"data": {
"page_no": "4",
"mes": "设备状态统计"
},
"msg": ""
},


"company_close": {
"type": 3,
"path": "api/real/Comprehensive/setup_CompanyInfo",
"data": {
"page_no": "4",
"mes": "打开/关闭公司介绍",
"companyFlag":0,
"companyName":""
},
"msg": "关闭成功"
},

"companys": [
"翰博尔",
"华瑞",
"山石网科",
"索为",
"中创腾瑞",
"卓建国际",
"道有道",
"毫末",
"先河环保",
"恒泰证券",
"来酷",
"数据堂",
"随锐",
"臻和"
],
"companys_match": {
"翰博尔":0,
"翰博":0,
"汉博尔":0,
"汉伯尔":0,
"华瑞": 1,
"华瑞网研": 1,
"山石网科": 2,
"索为": 3,
"所谓": 3,
"中创腾瑞": 4,
"卓建国际": 5,
"着建国际": 5,
"道有道": 6,
"道友到": 6,
"毫末": 7,
"好没": 7,
"先河环保": 8,
"恒泰证券": 9,
"来酷": 10,
"数据堂": 11,
"随锐科技": 12,
"随锐": 12,
"谁瑞": 12,
"水位": 12,
"谁为": 12,
"真和": 13,
"真核": 13
},
"companys_q": [
"翰博尔",
"翰博",
"汉博尔",
"汉伯尔",
"华瑞",
"华瑞网研",
"山石网科",
"索为",
"所谓",
"中创腾瑞",
"卓建国际",
"着建国际",
"道有道",
"道友到",
"毫末",
"好没",
"先河环保",
"恒泰证券",
"来酷",
"数据堂",
"随锐科技",
"随锐",
"谁瑞",
"水瑞",
"水位",
"谁为",
"真和",
"真核"
],
"doors": [
"一号通道",
"二号通道",
"三号通道",
"四号通道",
"五号通道",
"一号闸机",
"二号闸机",
"三号闸机",
"四号闸机",
"五号闸机"
],

"parks": [
"地上出入口",
"B1停车场",
"B2停车场"
],
"parksMapping": {
"地上出入口": 0,
"地上停车场": 0,
"B1停车场": 1,
"be停车场": 1,
"b1停车场": 1,
"负1停车场": 1,
"负一停车场": 1,
"附一停车场": 1,
"B2停车场": 2,
"b2停车场": 2,
"br停车场": 2
},

"hbh": {
"type": 2,
"forward_answer": [
"好",
"好的",
"行",
"可以",
"好吧"
],
"positive_answer": [
"不好",
"不可以",
"不行"
],
"forward_text": "京信局的展台设计以北斗七星为灵感,展台分为三大区域,城市数据建设展示区、应用场景展示区、北京数字经济展示区。请问您想了解哪个区域呢?",
"positive_text": "好吧,您先自己随便逛逛,有需要再叫我"
},
"shoudaoduanxi": {
"type": 2,
"forward_answer": [
"是",
"是的",
"收到",
"已收到",
"收到了"
],
"positive_answer": [
"否",
"没",
"没收到",
"我没收到",
"还没收到",
"没有",
"没有收到",
"未收到"
],
"forward_text": "您收到短信的手机号后四位是多少?",
"positive_text": "额,抱歉,请您自行联系将要拜访的人员。",
"req": "duanxin"
},
"duanxin": {
"type": 2,
"forward_text": "已匹配到您的拜访记录,将为您打开闸机,请通行!",
"forward_motion": "showRightHandBottom",
"positive_text": "抱歉,未匹配到您的邀约记录,请您联系将要拜访的人员。",
"positive_motion": "bow",
"callback": 1
},
"clothes": {
"SweetGirl": [
"suit_blue",
"suit_red",
"waistcoat_blue"
],
"BusinessGirl": [
"suit_green",
"waistcoat_black"
]
},
"characters": [
"SweetGirl",
"BusinessGirl"
],
"zhaohu": [
"你好",
"您好",
"小酷",
"小酷小酷",
"你好小酷",
"hello"
],
"breakReqs": [
"停",
"闭嘴",
"住嘴",
"stop",
"shut up"
],
"helpReqs": [
"我找",
"我来",
"在嘛",
"这里是",
"来找",
"送快递",
"送外卖",
"卢总",
"王总"
],
"asks": {
"mgr": "",
"emp": "您已打卡成功",
"emp2": "",
"keyVisitor": "欢迎来到来酷智联,卢总已在办公室等您。",
"keyVisitor2": "",
"visitor": "好久不见,您先在会议室稍坐会,已通知到我的同事",
"visitor2": "",
"courier": "根据大厦防疫规定,快递外卖人员不可进入大厦,请您在大厦外联系相关人员。",
"blackRole": "你是黑名单人员,不允许进入本公司,请赶快离开!",
"default": "请问您是员工还是访客?"
},
"normal": [
"很高兴为您服务",
"您今天状态真好",
"您今天心情挺好的吧",
"问问我喜欢什么吧",
"近来挺顺利的吧",
"天渐凉,早晚记得多穿点"
],
"handleTtsTexts": [
"jdyl",
"zdyl",
"cqqd",
"xxym",
"tsym",
"sjym",
"szym"
]
}

BIN
public/favicon.ico View File

Before After

+ 85
- 0
public/global.js View File

@@ -0,0 +1,85 @@
const Glod = {
qp: {
type: 1,
equip_no: "2",
set_no: "2",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "打开全屏"
},
fhsy: {
type: 1,
equip_no: "2",
set_no: "1701",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "返回首页"
},
zhts: {
type: 1,
equip_no: "2",
set_no: "103",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "打开综合态势"
},
afts: {
type: 1,
equip_no: "2",
set_no: "104",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "打开安防态势"
},
ryts: {
type: 1,
equip_no: "2",
set_no: "105",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "打开人员态势"
},
tcts: {
type: 1,
equip_no: "2",
set_no: "106",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "打开停车态势"
},
nyts: {
type: 1,
equip_no: "2",
set_no: "107",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "打开能源态势"
},
xfts: {
type: 1,
equip_no: "2",
set_no: "108",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "打开消防态势"
},
xmdsxt: {
type: 1,
equip_no: "1005",
set_no: "2",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "打开西门东侧摄像头"
},
hys1bsxt: {
type: 1,
equip_no: "1005",
set_no: "3",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "打开一号会议室北侧摄像头"
},
dtmxsxt: {
type: 1,
equip_no: "1005",
set_no: "4",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "打开大堂门口西侧摄像头"
},
hbh: {
type: 2,
forward_text:
"京信局的展台设计以北斗七星为灵感,展台分为三大区域,城市数据建设展示区、应用场景展示区、北京数字经济展示区。",
positive_text: "好吧,您请自便"
}
};

+ 20
- 0
public/index.html View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="x-dns-prefetch-control" content="on" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

+ 106
- 0
src/App.vue View File

@@ -0,0 +1,106 @@
<template>
<div id="app" class="no-scrollbar" style="width: 100%;">
<navigation>
<router-view :style="content"></router-view>
</navigation>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
isRouterAlive: true,
chatData: [],
weatherData: null,
interactive: "",
content: "",
retryLoadClientType: 0
};
},
mounted() {
window._ = _;
Date.prototype.Format = function(fmt) {
var o = {
"M+": this.getMonth() + 1, // 月份
"d+": this.getDate(), // 日
"h+": this.getHours(), // 小时
"m+": this.getMinutes(), // 分
"s+": this.getSeconds(), // 秒
"q+": Math.floor((this.getMonth() + 3) / 3), // 季度
S: this.getMilliseconds() // 毫秒
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt))
fmt = fmt.replace(
RegExp.$1,
RegExp.$1.length === 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length)
);
return fmt;
};
}
};
</script>
<style lang="scss">
* {
margin: 0;
padding: 0;
}
html,
body {
width: 100%;
height: 100%;
overflow-x: hidden;
overflow-y: hidden;
}
#app {
width: 100%;
height: 100%;
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
// 隐藏滚轮
.no-scrollbar {
-ms-overflow-style: none;
overflow: -moz-scrollbars-none;
/*background-color: black;*/
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.no-scrollbar::-webkit-scrollbar {
width: 0 !important;
}
img {
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
}
img[lazy="loading"] {
background-color: white;
}
.single-line-text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: block !important;
text-align: left;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
}
</style>

+ 451
- 0
src/api/cloudia-sdk-v1.4.1.js View File

@@ -0,0 +1,451 @@
export default {
/**
* 初始化SDK 传入onReceiveCmd, 用于接收nlp, a, reload等命令
* @param onReceiveCmd
* @param config
*/
init(
onReceiveCmd,
config = {
jsHandleTts: false,
jsHandleState: false
}
) {
window.sendCmd = function(cmd, params) {
if (cmd === "onBind") {
ue.cloudminds.hue("onstart", JSON.stringify(config));
console.info("onStart event sent");
window.cloudiaConfig = params;
if (params && params.SweetGirlClothes) {
cloudiaConfig.girls = new Map();
cloudiaConfig.sweetGirlClothes = params.SweetGirlClothes.replace(" ", "").split(",");
cloudiaConfig.girls.set("SweetGirl", cloudiaConfig.sweetGirlClothes);
cloudiaConfig.allClothes = cloudiaConfig.girls.get("SweetGirl");
if (params.BusinessGirlClothes) {
cloudiaConfig.businessGirlClothes = params.BusinessGirlClothes.replace(" ", "").split(",");
cloudiaConfig.girls.set("BusinessGirl", cloudiaConfig.businessGirlClothes);
}
if (params.AncientGirlClothes) {
cloudiaConfig.ancientGirlClothes = params.AncientGirlClothes.replace(" ", "").split(",");
cloudiaConfig.girls.set("AncientGirl", cloudiaConfig.ancientGirlClothes);
}
}
}
return onReceiveCmd(cmd, params);
};
},
reloadClothes() {
if (cloudiaConfig && cloudiaConfig.SweetGirlClothes) {
cloudiaConfig.allClothes = cloudiaConfig.girls.get(cloudiaConfig.currentCharacter);
}
},
isNotValidNum(value) {
return !/(^[\-0-9][0-9]*(.[0-9]+)?)$/.test(value);
},
isEmpty(obj) {
return typeof obj === "undefined" || obj == null || obj === "";
},
/**
* 显示toast
* @param msg toast内容
*/
showToast(msg) {
if (ue.cloudminds) {
if (this.isEmpty(msg)) {
console.warn("Invalid call:showToast");
return false;
}
ue.cloudminds.hue("showtoast", msg);
return true;
}
return false;
},
/**
* 显示长toast
* @param msg toast内容
*/
showLongToast(msg) {
if (ue.cloudminds) {
if (this.isEmpty(msg)) {
console.warn("Invalid call:showLongToast");
return false;
}
ue.cloudminds.hue("showlongtoast", msg);
return true;
}
return false;
},
/**
* 语音播报
* @param text 播报的内容
*/
playTts(text) {
if (ue.cloudminds) {
if (this.isEmpty(text)) {
console.warn("Invalid call:playTts");
return false;
}
ue.cloudminds.hue("playtts", text);
return true;
}
return false;
},
/**
* 修改浏览器位置
* @param left 浏览器距离屏幕左边的位置
* @param top 浏览器距离屏幕上边的位置
* @param right 浏览器距离屏幕右边的位置
* @param bottom 浏览器距离屏幕下边的位置
*/
updateBrowserLocation(left, top, right, bottom) {
if (
this.isNotValidNum(left) ||
this.isNotValidNum(top) ||
this.isNotValidNum(right) ||
this.isNotValidNum(bottom)
) {
console.error("updateBrowserLocation 数据不合法");
return false;
}
if (ue.cloudminds) {
// 蓝图端用的是","分隔方案
ue.cloudminds.hue("updatebrowserlocation", left + ", " + top + ", " + right + ", " + bottom);
return true;
}
return false;
},
/**
* 修改虚拟人物位置
* @param locationX X坐标值
* @param locationY Y坐标值
* @param locationZ Z坐标值
* @param persistence 是否持久化保存
*/
updateCharacterLocation(locationX, locationY, locationZ, persistence = false) {
if (this.isNotValidNum(locationX) || this.isNotValidNum(locationY) || this.isNotValidNum(locationZ)) {
console.error("updateCharacterLocation 数据不合法");
return false;
}
if (ue.cloudminds) {
ue.cloudminds.hue(
"updatecharacterlocation",
locationX + "#$*&@" + locationY + "#$*&@" + locationZ + "#$*&@" + persistence
);
return true;
}
return false;
},
/**
* 修改虚拟人物旋转角度
* @param rotationP P坐标值
* @param rotationY Y坐标值
* @param rotationR R坐标值
* @param persistence 是否持久化保存
*/
updateCharacterRotation(rotationP, rotationY, rotationR, persistence = false) {
if (this.isNotValidNum(rotationP) || this.isNotValidNum(rotationY) || this.isNotValidNum(rotationR)) {
console.error("updateCharacterRotation 数据不合法");
return false;
}
if (ue.cloudminds) {
ue.cloudminds.hue(
"updatecharacterrotation",
rotationP + "#$*&@" + rotationY + "#$*&@" + rotationR + "#$*&@" + persistence
);
return true;
}
return false;
},
/**
* 播放动画
* @param name 动画名称
* @param status 动画状态
*/
playMotion(name, status = "") {
if (ue.cloudminds) {
if (this.isEmpty(name)) {
console.warn("Invalid call:playMotion");
return false;
}
if (status.length === 0) {
ue.cloudminds.hue("playmotion", name);
} else {
ue.cloudminds.hue("playmotion", name + "#$*&@" + status);
}
return true;
}
return false;
},
/**
* 设置表情
* @param exp 表情名称
* @param value 值
*/
setExpression(exp, value) {
if (ue.cloudminds) {
if (this.isEmpty(value) || this.isEmpty(exp)) {
console.warn("Invalid call:setExpression");
return false;
}
ue.cloudminds.hue("setexpression", exp + "#$*&@" + value);
return true;
}
return false;
},
/**
* @param color 背景墙颜色
*/
setBgWallColor(color) {
if (ue.cloudminds) {
ue.cloudminds.hue("setMapBgColor", color);
return true;
}
return false;
},
/**
* @param wall 背景墙资源名称
*/
setBgWallResource(wall) {
if (ue.cloudminds) {
ue.cloudminds.hue("setMapBgResource", wall);
return true;
}
return false;
},
/**
* 设置是否由js接管tts播报,接管之后,app将不负责播报,转而由js负责调用palytts进行播报
* @param enable
*/
setJsPlayTtsEnabled(enable) {
if (this.isEmpty(enable)) {
console.warn("Invalid call:setJsPlayTtsEnabled");
return false;
}
if (ue.cloudminds) {
ue.cloudminds.hue("setjsplayttsenabled", enable.toString());
}
return true;
},
/**
* 设置是否由js接管state,接管之后,app将不切换state
* @param enable
*/
setJsHandleStateEnabled(enable) {
if (this.isEmpty(enable)) {
console.warn("Invalid call:setJsHandleStateEnabled");
return false;
}
if (ue.cloudminds) {
ue.cloudminds.hue("setJsHandleStateEnabled", enable.toString());
return true;
}
return false;
},
/**
* 获取deviceId,调用成功之后会在onCmdReceived中收到deviceId的命令
* @deprecated 请改用getRobotInfoConfig("RobotId")方法
*/
getDeviceId() {
if (ue.cloudminds) {
ue.cloudminds.hue("getdeviceid");
return true;
}
return false;
},
getRobotInfoConfig(key) {
if (ue.cloudminds) {
if (this.isEmpty(key)) {
console.warn("Invalid call:getRobotInfoConfig");
return false;
}
return ue.cloudminds.hueget("getrobotinfoconfig", key);
}
return new Promise(function() {
return "";
});
},
getGreetingMsg() {
return this.getAppConfig();
},
getAppConfig() {
if (ue.cloudminds) {
return ue.cloudminds.hueget("getappconfig");
}
return new Promise(function() {
return "";
});
},
getCharacter() {
if (ue.cloudminds) {
return ue.cloudminds.hueget("getcharacterinfo");
}
return new Promise(function() {
return "";
});
},
setCharacter(cname) {
if (this.isEmpty(cname)) {
console.warn("Invalid call:setCharacter");
return false;
}
if (ue.cloudminds) {
ue.cloudminds.hue("setcharacter", cname);
if (cloudiaConfig) {
cloudiaConfig.currentCharacter = cname;
}
this.reloadClothes();
return true;
}
return false;
},
setClothes(name) {
if (cloudiaConfig && cloudiaConfig.allClothes && !cloudiaConfig.allClothes.indexOf(name) < 0) {
console.warn("Invalid call:setClothes:" + name);
return false;
}
if (ue.cloudminds) {
ue.cloudminds.hue("setClothes", name);
return true;
}
return false;
},
postMediaEvent(event) {
if (this.isEmpty(event)) {
console.warn("Invalid call:postMediaEvent");
return false;
}
if (ue.cloudminds) {
ue.cloudminds.hue("postmediaevent", event);
return true;
}
return false;
},
setAsrWakeUpEnable(enable) {
if (this.isEmpty(enable)) {
console.warn("Invalid call:setAsrWakeUpEnable");
return false;
}
if (ue.cloudminds) {
ue.cloudminds.hue("setAsrWakeUpEnable", enable.toString());
return true;
}
return false;
},
stopPlayTts(playOK = false) {
if (ue.cloudminds) {
ue.cloudminds.hue("stopTts", playOK.toString());
return true;
}
return false;
},
setWalkGreetingEnable(enable) {
if (this.isEmpty(enable)) {
console.warn("Invalid call:setWalkGreetEnable");
return false;
}
if (ue.cloudminds) {
ue.cloudminds.hue("walkGreetEnable", enable.toString());
return true;
}
return false;
},
setWallLocation(location) {
if (this.isEmpty(location)) {
console.warn("Invalid call:setWallLocation");
return false;
}
if (ue.cloudminds) {
ue.cloudminds.hue("setbgwalllocation", location);
return true;
}
return false;
},
enterImmerseMode(immerse) {
if (this.isEmpty(immerse)) {
console.warn("Invalid call:enterImmerseMode");
return false;
}
if (ue.cloudminds) {
ue.cloudminds.hue("enterImmerseMode", immerse.toString());
return true;
}
return false;
},
startVideoTalk() {
if (ue.cloudminds) {
ue.cloudminds.hue("starttalk");
return true;
}
return false;
},
stopVideoTalk() {
if (ue.cloudminds) {
ue.cloudminds.hue("endtalk");
return true;
}
return false;
},
textTriggerNlp(text) {
if (this.isEmpty(text)) {
console.warn("Invalid call:textTriggerNlp");
return false;
}
if (ue.cloudminds) {
ue.cloudminds.hue("texttriggernlp", text);
return true;
}
return false;
},
setVolume(vol) {
if (this.isNotValidNum(vol)) {
console.warn("Invalid call:setVolume:" + vol);
return false;
}
if (ue.cloudminds) {
ue.cloudminds.hue("setvolume", vol.toString());
return true;
}
return false;
},
getVolume() {
if (ue.cloudminds) {
return ue.cloudminds.hueget("getcurvolume");
}
return new Promise(function() {
return "11";
});
},
downloadFiles(tag, urls) {
if (ue.cloudminds) {
ue.cloudminds.hue("downloadfiles", tag + "#$*&@" + urls);
return true;
}
return false;
},
updateCharacterScaleLevel(scaleLevel, persistence = false) {
if (this.isNotValidNum(scaleLevel)) {
console.warn("Invalid call:setVolume:" + persistence);
return false;
}
if (ue.cloudminds) {
ue.cloudminds.hue("setcharacterscale", scaleLevel + "#$*&@" + persistence);
return true;
}
},
restartH5() {
if (ue.cloudminds) {
ue.cloudminds.hue("reopenbrowser");
}
},
setState(state) {
if (this.isEmpty(state)) {
console.warn("Invalid call:setState");
return false;
}
if (ue.cloudminds) {
ue.cloudminds.hue("setState", state);
return true;
}
return false;
}
};

BIN
src/assets/ad_images.zip View File


BIN
src/assets/ads/10.jpg View File

Before After
Width: 5400  |  Height: 9600  |  Size: 4.9 MiB

BIN
src/assets/ads/1234567890.mp4 View File


BIN
src/assets/ads/17.jpg View File

Before After
Width: 5400  |  Height: 9600  |  Size: 5.3 MiB

BIN
src/assets/ads/2.jpg View File

Before After
Width: 5400  |  Height: 9600  |  Size: 3.7 MiB

BIN
src/assets/ads/img_1.png View File

Before After
Width: 930  |  Height: 1653  |  Size: 1.4 MiB

BIN
src/assets/back.png View File

Before After
Width: 40  |  Height: 40  |  Size: 1.3 KiB

BIN
src/assets/close.png View File

Before After
Width: 30  |  Height: 30  |  Size: 695 B

BIN
src/assets/ic_back.png View File

Before After
Width: 33  |  Height: 58  |  Size: 682 B

BIN
src/assets/ic_photo_error.png View File

Before After
Width: 160  |  Height: 141  |  Size: 6.3 KiB

BIN
src/assets/ic_photo_loading.png View File

Before After
Width: 140  |  Height: 140  |  Size: 4.7 KiB

BIN
src/assets/loading2.gif View File

Before After
Width: 800  |  Height: 800  |  Size: 88 KiB

BIN
src/assets/logo.png View File

Before After
Width: 4471  |  Height: 908  |  Size: 77 KiB

BIN
src/assets/qrcode.png View File

Before After
Width: 400  |  Height: 400  |  Size: 2.2 KiB

+ 684
- 0
src/components/DemoView.vue View File

@@ -0,0 +1,684 @@
<template>
<div :v-model="testing">
<div class="api-layout m-button">
<input
type="button"
value="一键自测"
class="input-text input-button"
style="margin: 0; width: 100%; text-align: center;"
@click="testAllInterface(toast)"
/>
</div>
<div :class="getValidClass(allInterfaces['interfaceShowToast'])">
<input v-model="toast" type="text" class="input-text" />
<input
type="button"
value="showToast"
class="input-text input-button m-button"
@click="interfaceShowToast()"
/>
</div>
<div :class="getValidClass(allInterfaces['interfaceShowLongToast'])">
<input v-model="longToast" type="text" class="input-text" />
<input
type="button"
value="longToast"
class="input-text input-button m-button"
@click="interfaceShowLongToast()"
/>
</div>
<div :class="iPlayTts ? 'api-layout' : getValidClass(allInterfaces['interfacePlayTts'])">
<input v-model="tts" type="text" class="input-text" />
<input type="button" value="playTts" class="input-text input-button" @click="interfacePlayTts()" />
</div>
<div :class="getValidClass(allInterfaces['interfaceUpdateBrowserLocation'])">
<input v-model="bOffset" type="text" class="input-text" />
<input
type="button"
value="browser"
class="input-text input-button"
@click="interfaceUpdateBrowserLocation()"
/>
</div>
<div :class="getValidClass(allInterfaces['interfaceUpdateCharacterLocation'])">
<input v-model="cLocation" type="text" class="input-text" />
<input
type="button"
value="location"
class="input-text input-button m-button"
@click="interfaceUpdateCharacterLocation()"
/>
</div>
<div :class="getValidClass(allInterfaces['interfaceUpdateCharacterRotation'])">
<input v-model="cRotation" type="text" class="input-text" />
<input
type="button"
value="rotation"
class="input-text input-button"
@click="interfaceUpdateCharacterRotation()"
/>
</div>
<div :class="getValidClass(allInterfaces['interfaceUpdateWallLocation'])">
<input v-model="bgLocation" type="text" class="input-text" />
<input
type="button"
value="WallLocation"
class="input-text input-button m-button"
@click="interfaceUpdateWallLocation()"
/>
</div>
<div :class="getValidClass(allInterfaces['interfacePlayMotion'])">
<label class="input-text select_wrapper">
<select v-model="motion" class="input-text selection">
<option>idle</option>
<option>nod</option>
<option>shakeHead</option>
<option>bow</option>
<option>handWave</option>
<option>showLeftHand</option>
<option>showLeftHandTop</option>
<option>showLeftHandBottom</option>
<option>showRightHand</option>
<option>showRightHandTop</option>
<option>showRightHandBottom</option>
<option>showBothHandBottom</option>
</select>
</label>
<input
type="button"
value="playMotion"
class="input-text input-button m-button"
@click="interfacePlayMotion()"
/>
</div>
<div :class="getValidClass(allInterfaces['interfaceSetBgWallColor']) + ' input-color-layout'">
<div class="input-text">
<span class="input-color-text">{{ wall }}</span>
</div>
<input
id="color"
type="color"
name="color"
value="#00f4ff"
class="input-text input-color-button m-button"
@change="interfaceSetBgWallColor()"
/>
</div>
<div :class="getValidClass(allInterfaces['interfaceSetBgWallRes'])">
<label class="input-text select_wrapper">
<select v-model="wallRes" class="input-text selection">
<option>3DRoom</option>
<option>SolidColor</option>
<option>Landscape</option>
</select>
</label>
<input
type="button"
value="setMapRes"
class="input-text input-button m-button"
@click="interfaceSetBgWallRes()"
/>
</div>
<div :class="iGetRobotConfig ? 'api-layout' : getValidClass(allInterfaces['interfaceGetDeviceId'])">
<input v-model="deviceId" type="text" class="input-text" />
<input type="button" value="DeviceId" class="input-text input-button" @click="interfaceGetDeviceId()" />
</div>
<div :class="iAppConfig ? 'api-layout' : getValidClass(allInterfaces['interfaceGetAppConfig'])">
<input v-model="appConfig" type="text" class="input-text" />
<input type="button" value="AppConfig" class="input-text input-button" @click="interfaceGetAppConfig()" />
</div>
<div :class="getValidClass(allInterfaces['interfaceSetCharacter'])">
<label class="input-text select_wrapper">
<select v-model="character" class="input-text selection">
<option>SweetGirl</option>
<option>BusinessGirl</option>
<option>AncientGirl</option>
</select>
</label>
<input
type="button"
value="setCharacter"
class="input-text input-button m-button"
@click="interfaceSetCharacter()"
/>
</div>
<div :class="getValidClass(allInterfaces['interfaceSetClothes'])">
<label class="input-text select_wrapper">
<select v-model="clothes" class="input-text selection">
<option v-for="c in allClothes" :key="c">{{ c }}</option>
</select>
</label>
<input
type="button"
value="setClothes"
class="input-text input-button m-button"
@click="interfaceSetClothes()"
/>
</div>
<div :class="getValidClass(allInterfaces['interfacePostMediaEvent'])">
<label class="input-text select_wrapper">
<select v-model="mediaEvent" class="input-text selection">
<option>playing</option>
<option>pause</option>
<option>ended</option>
</select>
</label>
<input
type="button"
value="postMediaEvent"
class="input-text input-button m-button"
@click="interfacePostMediaEvent()"
/>
</div>
<div :class="iAsrWakeUp ? 'api-layout' : getValidClass(allInterfaces['interfaceSetAsrWakeUpEnable'])">
<input v-model="asrWakeUp" type="text" class="input-text" />
<input
type="button"
value="Asr Wake Up"
class="input-text input-button"
@click="interfaceSetAsrWakeUpEnable()"
/>
</div>
<div :class="getValidClass(allInterfaces['interfaceStopPlayTts'])">
<input disabled type="text" class="input-text" />
<input
type="button"
value="StopPlayTts"
class="input-text input-button m-button"
@click="interfaceStopPlayTts()"
/>
</div>
<div :class="getValidClass(allInterfaces['interfaceEnterImmerseMode'])">
<input v-model="immerseMode" type="text" class="input-text" />
<input
type="button"
value="immerseMode"
class="input-text input-button m-button"
@click="interfaceEnterImmerseMode()"
/>
</div>
<div :class="getValidClass(allInterfaces['interfaceStartVideoTalk'])">
<input
type="button"
value="StartVideoTalk"
class="input-text"
style="width: 61vw;"
@click="interfaceStartVideoTalk()"
/>
<input
type="button"
value="StopVideoTalk"
class="input-text input-button m-button"
@click="interfaceStopVideoTalk()"
/>
</div>
<div :class="getValidClass(allInterfaces['interfaceSetVolume'])">
<input v-model="setValueText" type="text" class="input-text" />
<input type="button" value="setVolume" class="input-text input-button" @click="interfaceSetVolume()" />
</div>
<div :class="iGetVolume ? 'api-layout' : getValidClass(allInterfaces['interfaceGetVolume'])">
<input v-model="getValueText" type="text" class="input-text" />
<input type="button" value="getVolume" class="input-text input-button" @click="interfaceGetVolume()" />
</div>
<div :class="getValidClass(allInterfaces['interfaceDownloadFiles'])">
<input disabled type="text" class="input-text" />
<input
type="button"
value="downloadFiles"
class="input-text input-button m-button"
@click="interfaceDownloadFiles()"
/>
</div>
<div :class="getValidClass(allInterfaces['interfaceTextTriggerNlp'])">
<input v-model="ttsText" type="text" class="input-text" />
<input
type="button"
value="TriggerNlp"
class="input-text input-button m-button"
@click="interfaceTextTriggerNlp()"
/>
</div>
<div class="api-layout">
<input disabled type="text" class="input-text" />
<input type="button" value="LoadAd" class="input-text input-button" @click="loadAd()" />
</div>
<div class="api-layout">
<p>cloudminds</p>
</div>
</div>
</template>
<script>
var timer;
import Cloudia from "../api/cloudia-sdk-v1.4.1";
export default {
name: "DemoView",
components: {},
data() {
return {
toast: "A Toast",
longToast: "A Long Toast",
tts: "1234567890",
bOffset: "0, 0, 0, 0",
cLocation: "-378.8,-0.7,448.3,false",
cRotation: "0,179.5,0,false",
motion: "bow",
wall: "Change BG Color",
wallRes: "3DRoom",
exp: "smile, 1",
mediaEvent: "playing",
asrWakeUp: true,
walkGreetEnable: true,
cameraMode: "level",
bgLocation: "1400,0,0",
setValueText: 12,
getValueText: 0,
ttsText: "成都天气",
deviceId: 0,
testing: true,
iPlayTts: true,
iAsrWakeUp: true,
iGetRobotConfig: true,
iAppConfig: true,
iGetVolume: true,
allInterfaces: new Map(),
cloudiaEvents: new Map(),
appConfig: "",
character: "SweetGirl",
allClothes: [],
clothes: "suit_blue",
immerseMode: false,
asrEnabled: true
};
},
computed: {},
watch: {},
mounted() {
let that = this;
if (that.$parent.tabIndex == 1) {
let getAllInterfaces = (obj) =>
Object.getOwnPropertyNames(obj).filter((item) => {
if (typeof obj[item] === "function" && item.startsWith("interface")) {
that.allInterfaces.set(item, 0);
console.info(item);
return item;
}
});
getAllInterfaces(this);
}
},
methods: {
getValidClass(cond) {
if (cond === undefined || cond === 0) {
return "api-layout interface-init";
} else if (cond === 1) {
return "api-layout interface-success";
} else {
return "api-layout interface-fail";
}
},
interfaceShowToast() {
let result = Cloudia.showToast(this.toast);
this.allInterfaces["interfaceShowToast"] = result ? 1 : 2;
},
interfaceShowLongToast() {
let result = Cloudia.showLongToast(this.longToast);
this.allInterfaces["interfaceShowLongToast"] = result ? 1 : 2;
},
interfacePlayTts() {
let result = Cloudia.playTts(this.tts);
if (result) {
this.iPlayTts = true;
timer && clearTimeout(timer);
timer = setTimeout(() => {
this.iPlayTts = false;
this.allInterfaces["interfacePlayTts"] = this.cloudiaEvents["ttsPlay"] === 10 ? 1 : 2;
}, 1500);
} else {
this.allInterfaces["interfacePlayTts"] = 2;
}
},
interfaceUpdateBrowserLocation() {
this.bOffset = this.bOffset.replace(/ /g, "");
let offset = this.bOffset.split(",");
let result = Cloudia.updateBrowserLocation(offset[0], offset[1], offset[2], offset[3]);
this.allInterfaces["interfaceUpdateBrowserLocation"] = result ? 1 : 2;
},
interfaceUpdateCharacterLocation() {
this.cLocation = this.cLocation.replace(/ /g, "");
let location = this.cLocation.split(",");
let result = Cloudia.updateCharacterLocation(location[0], location[1], location[2], location[3]);
this.allInterfaces["interfaceUpdateCharacterLocation"] = result ? 1 : 2;
},
interfaceUpdateCharacterRotation() {
this.cRotation = this.cRotation.replace(/ /g, "");
let rotation = this.cRotation.split(",");
let result = Cloudia.updateCharacterRotation(rotation[0], rotation[1], rotation[2], rotation[3]);
this.allInterfaces["interfaceUpdateCharacterRotation"] = result ? 1 : 2;
},
interfaceUpdateWallLocation() {
let result = Cloudia.setWallLocation(this.bgLocation);
this.allInterfaces["interfaceUpdateWallLocation"] = result ? 1 : 2;
},
interfacePlayMotion() {
this.motion = this.motion.replace(/ /g, "");
let params = this.motion.split(",");
let result;
if (params.length === 2) {
result = Cloudia.playMotion(params[0], params[1]);
} else {
result = Cloudia.playMotion(params[0]);
}
this.allInterfaces["interfacePlayMotion"] = result ? 1 : 2;
},
interfaceSetBgWallColor() {
//通过使用 getElementById() 来访问 <color> 元素
let colorEl = document.getElementById("color");
console.info("selected color:" + colorEl.value);
let color = colorEl.value.replace("#", "");
let r = parseInt(color.substring(0, 2), 16) / 255;
let g = parseInt(color.substring(2, 4), 16) / 255;
let b = parseInt(color.substring(4, 6), 16) / 255;
// console.info("Selected color: rgb(" + r + ", " + g + ", " + b + ")");
let result = Cloudia.setBgWallColor(r + ", " + g + ", " + b);
this.allInterfaces["interfaceSetBgWallColor"] = result ? 1 : 2;
},
interfaceSetBgWallRes() {
let result = Cloudia.setBgWallResource(this.wallRes);
this.allInterfaces["interfaceSetBgWallRes"] = result ? 1 : 2;
},
interfaceGetDeviceId() {
let that = this;
this.iGetRobotConfig = true;
return Cloudia.getRobotInfoConfig("RobotId").then(function(ReturnValue) {
if (ReturnValue !== undefined && ReturnValue.ReturnValue !== undefined) {
that.deviceId = ReturnValue.ReturnValue;
}
that.allInterfaces["interfaceGetDeviceId"] = that.deviceId.length > 0 ? 1 : 2;
that.iGetRobotConfig = false;
});
},
interfaceGetAppConfig() {
let that = this;
this.iAppConfig = true;
return Cloudia.getAppConfig().then(function(ReturnValue) {
if (ReturnValue !== undefined && ReturnValue.ReturnValue !== undefined) {
that.appConfig = ReturnValue.ReturnValue;
}
that.allInterfaces["interfaceGetAppConfig"] = that.appConfig.length > 0 ? 1 : 2;
that.iAppConfig = false;
});
},
interfaceSetCharacter() {
let result = Cloudia.setCharacter(this.character);
this.allClothes = cloudiaConfig.allClothes;
this.clothes = this.allClothes[0];
this.allInterfaces["interfaceSetCharacter"] = result ? 1 : 2;
return result;
},
interfaceSetClothes() {
let result = Cloudia.setClothes(this.clothes);
this.allInterfaces["interfaceSetClothes"] = result ? 1 : 2;
},
interfacePostMediaEvent() {
let result = Cloudia.postMediaEvent(this.mediaEvent);
this.allInterfaces["interfacePostMediaEvent"] = result ? 1 : 2;
},
interfaceSetAsrWakeUpEnable() {
let result = Cloudia.setAsrWakeUpEnable(this.asrWakeUp);
if (result) {
this.iAsrWakeUp = true;
timer && clearTimeout(timer);
timer = setTimeout(() => {
if (this.cloudiaEvents["asrWakeUp"] === this.asrWakeUp ? 10 : 20) {
this.allInterfaces["interfaceSetAsrWakeUpEnable"] = 1;
} else {
this.allInterfaces["interfaceSetAsrWakeUpEnable"] = 2;
}
this.iAsrWakeUp = false;
}, 1000);
} else {
this.allInterfaces["interfaceSetAsrWakeUpEnable"] = 2;
}
},
interfaceStopPlayTts() {
let result = Cloudia.stopPlayTts(false);
this.allInterfaces["interfaceStopPlayTts"] = result ? 1 : 2;
},
interfaceEnterImmerseMode() {
let result = Cloudia.enterImmerseMode(this.immerseMode);
this.allInterfaces["interfaceEnterImmerseMode"] = result ? 1 : 2;
},
interfaceStartVideoTalk() {
let result = Cloudia.startVideoTalk();
this.allInterfaces["interfaceStartVideoTalk"] = result ? 1 : 2;
},
interfaceStopVideoTalk() {
let result = Cloudia.stopVideoTalk();
this.allInterfaces["interfaceStopVideoTalk"] = result ? 1 : 2;
},
interfaceSetVolume() {
let result = Cloudia.setVolume(this.setValueText);
this.allInterfaces["interfaceSetVolume"] = result ? 1 : 2;
},
interfaceGetVolume() {
this.iGetVolume = true;
return Cloudia.getVolume().then((ReturnValue) => {
if (ReturnValue !== undefined && ReturnValue.ReturnValue !== undefined) {
this.getValueText = ReturnValue.ReturnValue;
console.info("========:" + this.getValueText + ", " + this.setValueText);
this.allInterfaces["interfaceGetVolume"] =
this.getValueText.toString() === this.setValueText.toString() ? 1 : 2;
} else {
this.allInterfaces["interfaceGetVolume"] = 2;
}
this.iGetVolume = false;
});
},
interfaceDownloadFiles() {
let result = Cloudia.downloadFiles(
"test",
JSON.stringify([
{
name: "04070c61b7d40b5a90b98640645493cb.jpeg",
url: "https://127.0.0.1"
},
{
name: "112350h4wcwa94c9ch3oth.jpg",
url: "https://127.0.0.1"
}
])
);
this.allInterfaces["interfaceDownloadFiles"] = result ? 1 : 2;
},
interfaceTextTriggerNlp() {
let result = Cloudia.textTriggerNlp(this.ttsText);
this.allInterfaces["interfaceTextTriggerNlp"] = result ? 1 : 2;
},
getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min; //不含最大值,含最小值
},
loadAd() {
// TODO !!!!不同的环境需要切换不同的baseUrl!!!!
let baseUrl = "https://127.0.0.1";
let timestamp = new Date().getTime();
// TODO 填写你自己的appId
let appId = Config.appId;
let nonceStr = this.getRandomInt(1000, 9999);
// TODO 填写你自己的appSecret
let appSecret = Config.appSecret;
let sign = md5("appId" + appId + "timestamp" + timestamp + "nonceStr" + nonceStr + appSecret);
// console.info("appId:" + appId);
// console.info("appSecret:" + appSecret);
// console.info("sign:" + sign);
const headers = {
"Content-Type": "application/json",
appId: appId,
timestamp: timestamp,
nonceStr: nonceStr,
sign: sign
};
let url = "/crss-robot/ads/robotapi/v1/adSpace/get?pageCode=home&robotCode=" + this.deviceId;
fetch(baseUrl + url, { headers })
.then(async (response) => {
const data = await response.json();
if (!response.ok) {
// get error message from body or default to response statusText
const error = (data && data.message) || response.statusText;
return Promise.reject(error);
}
console.info("load ad data success:" + JSON.stringify(data));
if (data.code === 0 && data.data && data.data.adList) {
// 拼接完整URL
data.data.adList.map((e) => {
e.url = baseUrl + e.url;
});
let adData = JSON.stringify(data.data.adList);
// 下载广告数据,下载成功之后会在event事件中收到通知
Cloudia.downloadFiles("home", adData);
console.info("ad data:" + adData);
} else {
console.warn("ad data is empty");
}
})
.catch((error) => {
console.error("load ad data error:" + error);
});
},
interFun() {
var ii = "qp";
this.handleCustomize(ii);
},
insertNlp() {
this.addMsgList(2, "测试一下,测试一下");
if (this.nplList.length > 10) {
this.nplList.splice(10, this.nplList.length - 10);
}
this.nplList = [
{ question_id: new Date().getTime(), question_text: "test test", answer: "answer....." },
...this.nplList
];
this.$axios
.post(Config.serverDb + "/api/db/save", {
id: new Date().getTime(),
text: "test test",
answer: "answer....."
})
.then((res) => {
console.log(res);
});
},
testAllInterface() {
let i = 0;
for (let [key, value] of this.allInterfaces) {
timer && clearTimeout(timer);
timer = setTimeout(() => {
this.testing = true;
try {
this[key]();
} catch (e) {
this.allInterfaces[key] = 2;
console.error("interface exec failed:" + key + ", " + value + "----" + e);
}
this.testing = false;
}, ++i * 1000);
}
}
}
};
</script>
<style>
.log {
height: 100%;
text-align: left;
overflow-y: scroll;
margin-right: 0;
padding-right: 0;
}
.cmd {
margin-left: 2vw;
color: #803300;
font-size: 4vh;
display: inline-block;
}
.api-layout {
margin-bottom: 0.5vh;
justify-content: left;
width: 100%;
text-align: left;
}
.input-text {
height: 6vh;
line-height: 6vh;
font-size: 3vh;
color: black;
text-align: left;
width: 60vw;
background-color: rgba(255, 255, 255, 0.4);
border: none;
padding-left: 1vw;
}
.select_wrapper {
padding: 0;
background-color: transparent;
}
.selection {
padding: 0;
width: 61vw;
background-color: rgba(255, 255, 255, 0.4);
}
.input-button {
width: 34vw;
margin-left: 2vw;
}
.m-button {
background-color: rgba(59, 140, 207, 0.5);
}
.input-color-layout {
display: -webkit-box;
}
.input-color-text {
font: 400 3vh Arial;
text-align: left;
display: contents;
}
.input-color-button {
padding: 0;
margin-left: 2vw;
width: 34vw;
display: flex;
}
.floats {
position: absolute;
right: 1vw;
width: 48vw;
text-align: right;
}
.interface-init {
background-color: transparent;
}
.interface-success {
background-color: #57b73b;
}
.interface-fail {
background-color: #803300;
}
</style>

+ 398
- 0
src/components/JsonView.vue View File

@@ -0,0 +1,398 @@
<template>
<div v-if="visible" :class="['json-view-container', theme, `deep-${currentDeep}`]">
<div
:class="['json-view', length ? 'closeable' : '']"
:style="{ fontSize: fontSize + 'px', lineHeight: lineHeight + 'px' }"
>
<!--icon-style-square-->
<span v-if="length && iconStyle === 'square'" class="angle" @click="toggleClose">
<svg
v-if="innerclosed"
:fill="iconColors[0]"
width="1em"
height="1em"
viewBox="0 0 1792 1792"
style="vertical-align: middle; color: rgb(42, 161, 152); height: 1em; width: 1em;"
>
<path
d="M1344 800v64q0 14-9 23t-23 9h-352v352q0 14-9 23t-23 9h-64q-14 0-23-9t-9-23v-352h-352q-14 0-23-9t-9-23v-64q0-14 9-23t23-9h352v-352q0-14 9-23t23-9h64q14 0 23 9t9 23v352h352q14 0 23 9t9 23zm128 448v-832q0-66-47-113t-113-47h-832q-66 0-113 47t-47 113v832q0 66 47 113t113 47h832q66 0 113-47t47-113zm128-832v832q0 119-84.5 203.5t-203.5 84.5h-832q-119 0-203.5-84.5t-84.5-203.5v-832q0-119 84.5-203.5t203.5-84.5h832q119 0 203.5 84.5t84.5 203.5z"
></path>
</svg>
<svg
v-if="!innerclosed"
:fill="iconColors[1]"
width="1em"
height="1em"
viewBox="0 0 1792 1792"
style="vertical-align: middle; color: rgb(88, 110, 117); height: 1em; width: 1em;"
>
<path
d="M1344 800v64q0 14-9 23t-23 9h-832q-14 0-23-9t-9-23v-64q0-14 9-23t23-9h832q14 0 23 9t9 23zm128 448v-832q0-66-47-113t-113-47h-832q-66 0-113 47t-47 113v832q0 66 47 113t113 47h832q66 0 113-47t47-113zm128-832v832q0 119-84.5 203.5t-203.5 84.5h-832q-119 0-203.5-84.5t-84.5-203.5v-832q0-119 84.5-203.5t203.5-84.5h832q119 0 203.5 84.5t84.5 203.5z"
></path>
</svg>
</span>
<!--icon-style-circle-->
<span v-if="length && iconStyle === 'circle'" class="angle" @click="toggleClose">
<svg
v-if="!innerclosed"
viewBox="0 0 24 24"
:fill="iconColors[0]"
preserveAspectRatio="xMidYMid meet"
style="vertical-align: middle; color: rgb(1, 160, 228); height: 1em; width: 1em;"
>
<path
d="M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M7,13H17V11H7"
></path>
</svg>
<svg
v-if="innerclosed"
viewBox="0 0 24 24"
:fill="iconColors[1]"
preserveAspectRatio="xMidYMid meet"
style="vertical-align: middle; color: rgb(161, 106, 148); height: 1em; width: 1em;"
>
<path
d="M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M13,7H11V11H7V13H11V17H13V13H17V11H13V7Z"
></path>
</svg>
</span>
<!--icon-style-triangle-->
<span v-if="length && iconStyle === 'triangle'" class="angle" @click="toggleClose">
<svg
v-if="!innerclosed"
viewBox="0 0 15 15"
:fill="iconColors[0]"
style="vertical-align: top; color: #3c4047; height: 1em; width: 1em; padding-left: 2px;"
>
<path d="M0 5l6 6 6-6z"></path>
</svg>
<svg
v-if="innerclosed"
viewBox="0 0 15 15"
:fill="iconColors[1]"
style="vertical-align: top; color: #3c4047; height: 1em; width: 1em; padding-left: 2px;"
>
<path d="M0 14l6-6-6-6z"></path>
</svg>
</span>
<div class="content-wrap">
<p :class="['first-line', length > 0 ? 'pointer' : '']" @click="toggleClose">
<span v-if="jsonKey" class="json-key">"{{ jsonKey }}": </span>
<span v-if="length"
>{{ prefix }}{{ innerclosed ? "..." + subfix : "" }}
<span class="json-note">{{ innerclosed ? length + " items" : "" }}</span>
</span>
<span v-if="!length">{{ `${isArray ? "[]" : "{}"}${isLast ? "" : ","}` }}</span>
</p>
<div v-if="!innerclosed && length" class="json-body">
<template v-for="(item, index) in items">
<json-view
v-if="item.isJSON"
:key="index"
:closed="isClose()"
:data="item.value"
:json-key="item.key"
:current-deep="templateDeep + 1"
:deep="deep"
:icon-style="iconStyle"
:theme="theme"
:font-size="fontSize"
:line-height="lineHeight"
:icon-color="iconColors"
:is-last="index === items.length - 1"
:has-siblings="item.hasSiblings"
/>
<p v-else :key="index" class="json-item">
<span class="json-key">{{ isArray ? "" : '"' + item.key + '":' }}</span>
<span :class="['json-value', getDataType(item.value)]">
{{
`${getDataType(item.value) === "string" ? '"' : ""}${formatValue(item.value)}${
getDataType(item.value) === "string" ? '"' : ""
}${index === items.length - 1 ? "" : ","}`
}}
</span>
</p>
</template>
<span v-if="!innerclosed" class="base-line"></span>
</div>
<p v-if="!innerclosed" class="last-line">
<span>{{ subfix }}</span>
</p>
</div>
</div>
</div>
</template>
<script>
export default {
name: "JsonView",
props: {
data: {
// 传入的json数据
type: [Object, Array],
required: true
},
jsonKey: {
// json的key值,用于第二层及二层以上的组件的key值
type: String,
default: ""
},
closed: {
// 是否折叠
type: Boolean,
default: false
},
isLast: {
//是否是最后一行
type: Boolean,
default: true
},
fontSize: {
//字体大小
type: Number,
default: 14
},
lineHeight: {
//行高
type: Number,
default: 24
},
deep: {
// 展开深度
type: Number,
default: 3
},
currentDeep: {
// 当前为递归的第几层
type: Number,
default: 1
},
iconStyle: {
// 折叠icon样式
type: String,
default: "square"
},
iconColor: {
//icon颜色
type: Array,
default() {
return [];
}
},
theme: {
// 主题
type: String,
default: ""
},
hasSiblings: {
// 是否有兄弟节点
type: Boolean,
default: true
}
},
data() {
return {
innerclosed: this.closed,
templateDeep: this.currentDeep,
visible: false
};
},
computed: {
isArray() {
return this.getDataType(this.data) === "array";
},
length() {
return this.isArray ? this.data.length : Object.keys(this.data).length;
},
subfix() {
const data = this.data;
if (this.isEmptyArrayOrObject(data)) {
// 如果是空数组或空对象
return "";
} else {
return (this.isArray ? "]" : "}") + (this.isLast ? "" : ",");
}
},
prefix() {
return this.isArray ? "[" : "{";
},
items() {
const json = this.data;
if (this.isArray) {
return json.map((item) => {
const isJSON = this.isObjectOrArray(item);
return {
value: item,
isJSON,
key: ""
};
});
}
return Object.keys(json).map((key) => {
const item = json[key];
const isJSON = this.isObjectOrArray(item);
return {
value: item,
isJSON,
key
};
});
},
iconColors() {
const { theme, iconColor } = this;
if (iconColor.length === 2) {
return iconColor;
} else {
if (theme === "one-dark") {
return ["#747983", "#747983"];
} else if (theme === "vs-code") {
return ["#c6c6c6", "#c6c6c6"];
} else {
return ["#747983", "#747983"];
}
}
}
},
watch: {
closed() {
this.innerclosed = this.closed;
}
},
mounted() {
setTimeout(() => {
this.visible = true;
}, 0);
},
methods: {
formatValue(data) {
if (data && data._isBigNumber) {
return data.toString(10);
}
return data;
},
getDataType(data) {
return data && data._isBigNumber
? "number"
: Object.prototype.toString
.call(data)
.slice(8, -1)
.toLowerCase();
},
isObjectOrArray(source) {
return ["array", "object"].includes(this.getDataType(source));
},
toggleClose() {
if (this.length === 0) {
return;
}
if (this.innerclosed) {
this.innerclosed = false;
} else {
this.innerclosed = true;
}
},
isClose() {
return this.templateDeep + 1 > this.deep;
},
isEmptyArrayOrObject(data) {
// 空数组或者空对象
return [{}, []].map((item) => JSON.stringify(item)).includes(JSON.stringify(data));
}
}
};
</script>
<style scoped lang="scss">
.json-view-container {
background-color: transparent;
&.deep-1 {
// overflow: auto;
padding-right: 10px;
}
.json-view {
position: relative;
display: block;
width: 100%;
height: 100%;
white-space: nowrap;
padding-left: 2rem;
box-sizing: border-box;
cursor: default;
.json-note {
color: #909399;
font-size: 12px;
font-style: italic;
}
.json-key {
color: #8c6325;
}
.json-value {
display: inline-block;
color: #57b73b;
word-break: break-all;
white-space: normal;
&.number {
color: #2d8cf0;
}
&.string {
color: #57b73b;
}
&.boolean {
color: #eb3324;
}
&.null {
color: #eb3324;
}
}
.json-item {
margin: 0;
padding-left: 2rem;
display: flex;
}
.first-line {
padding: 0;
margin: 0;
&.pointer {
cursor: pointer !important;
}
}
.json-body {
position: relative;
padding: 0;
margin: 0;
.base-line {
position: absolute;
height: 100%;
border-left: 1px dashed #bbb;
top: 0;
left: 2px;
&:hover {
}
}
}
.last-line {
padding: 0;
margin: 0;
}
.angle {
position: absolute;
display: block;
cursor: pointer;
float: left;
width: 20px;
text-align: center;
/*left: ~"calc(2rem - 18px)";*/
left: 12px;
}
}
}
</style>

+ 193
- 0
src/components/SwiperView.vue View File

@@ -0,0 +1,193 @@
<template>
<div class="recommendPage">
<swiper v-if="initOrNot" ref="videoSwiper" :options="swiperOption">
<swiper-slide v-for="(item, index) in mediaNews" :key="index">
<video
v-if="item.type === 1"
controls
muted="muted"
autoplay="autoplay"
class="multimedia"
style="width: 100%;object-fit: cover"
@ended="endVideo(index)"
>
<source :src="item.url" type="video/mp4" />
</video>
<img v-else :src="item.url" class="multimedia" style="width: 100%;object-fit: cover" />
</swiper-slide>
</swiper>
</div>
</template>
<script>
import { swiper, swiperSlide } from "vue-awesome-swiper";
import "swiper/dist/css/swiper.css";
var timer;
export default {
name: "SwiperView",
components: {
swiper,
swiperSlide
},
data() {
const files = require.context("@/assets/ads", true).keys();
let ads = [];
console.log(ads);
for (let url in files) {
let temp = {};
console.log("../assets/ads/" + files[url]);
temp.url = require("../assets/ads/" + files[url].substr(2));
temp.type = 0;
if (files[url].endsWith("mp4")) {
temp.type = 1;
}
ads.push(temp);
}
return {
swiperOption: {
speed: 1000,
loop: false,
observer: true,
observeParents: true,
autoplayDisableOnInteraction: false,
allowTouchMove: false,
pagination: {
el: ".swiper-pagination",
clickable: true
},
on: {
slideChangeTransitionEnd: () => {
this.slideChangeTransitionEndHandle();
},
slideChangeTransitionStart: () => {
this.slideChangeTransitionStartHandle();
},
//控制第一个slide切换
init: () => {
this.initHandle();
}
}
},
initOrNot: false,
mediaLastIndex: 0,
mediaNews: ads
};
},
computed: {
swiper() {
return this.$refs.videoSwiper.swiper;
}
},
watch: {
mediaNews: {
handler(newName, oldName) {
if (newName.length > 0) {
this.initOrNot = false;
this.$nextTick(() => {
this.initOrNot = true;
});
}
},
immediate: true,
deep: true
}
},
mounted() {},
methods: {
initHandle() {
let that = this;
timer && clearTimeout(timer);
timer = setTimeout(function() {
let swiper = that.$refs.videoSwiper.swiper;
that.mediaNewsImgHandle(swiper);
}, 200);
},
mediaNewsImgHandle(swiper) {
//刚切换到的activeIndex
let changePointActiveIndex = swiper.activeIndex;
if (swiper.activeIndex < this.mediaNews.length - 1) {
timer && clearTimeout(timer);
timer = setTimeout(function() {
//要确认changePointActiveIndex是不是还是目前的activeIndex,是的话计时后执行,不是的话不执行
if (changePointActiveIndex === swiper.activeIndex) {
swiper.slideNext();
}
}, 5000);
} else {
timer && clearTimeout(timer);
timer = setTimeout(function() {
if (changePointActiveIndex === swiper.activeIndex) {
swiper.slideTo(0, 0);
}
}, 5000);
}
},
slideChangeTransitionStartHandle() {
let swiper = this.$refs.videoSwiper.swiper;
if (this.mediaNews[this.mediaLastIndex].type === 1) {
document.getElementsByClassName("multimedia")[this.mediaLastIndex].currentTime = 0;
}
},
slideChangeTransitionEndHandle() {
console.log("end..");
let that = this;
let swiper = that.$refs.videoSwiper.swiper;
if (this.mediaNews[swiper.activeIndex].type === 0) {
this.mediaNewsImgHandle(swiper);
} else {
if (this.mediaLastIndex.type === 1) {
document.getElementsByClassName("multimedia")[this.mediaLastIndex].pause();
}
document.getElementsByClassName("multimedia")[swiper.activeIndex].removeAttribute("muted");
document.getElementsByClassName("multimedia")[swiper.activeIndex].play();
// this.playVideo(this.mediaNews[swiper.activeIndex].url);
}
this.mediaLastIndex = swiper.activeIndex;
},
endVideo(index) {
let swiper = this.$refs.videoSwiper.swiper;
if (index === swiper.activeIndex) {
if (swiper.activeIndex < this.mediaNews.length - 1) {
swiper.slideNext();
if (this.mediaNews[swiper.activeIndex].type === 1) {
document.getElementsByClassName("multimedia")[swiper.activeIndex].removeAttribute("muted");
document.getElementsByClassName("multimedia")[swiper.activeIndex].play();
// this.playVideo(this.mediaNews[swiper.activeIndex].url);
}
} else {
swiper.slideTo(0, 0);
if (this.mediaNews[swiper.activeIndex].type === 1) {
document.getElementsByClassName("multimedia")[swiper.activeIndex].removeAttribute("muted");
document.getElementsByClassName("multimedia")[swiper.activeIndex].play();
// this.playVideo(this.mediaNews[swiper.activeIndex].url);
}
}
}
}
}
};
</script>
<style>
.recommendPage .swiper-container {
position: relative;
width: 100%;
height: 1920px;
background: transparent;
}
.recommendPage .swiper-container .swiper-slide {
width: 100%;
//line-height: 1920px;
background: transparent;
color: #000;
font-size: 16px;
text-align: center;
}
swiper-slide img {
object-fit: contain;
}
</style>

+ 74
- 0
src/components/VideoView.vue View File

@@ -0,0 +1,74 @@
<template>
<div class="video-js-comp">
<video ref="videoPlayer" class="video-js vjs-fluid" controls />
</div>
</template>
<script>
import videojs from "video.js";
import "videojs-flash";
import "video.js/dist/video-js.css";
import CN from "video.js/dist/lang/zh-CN.json";
videojs.addLanguage("zh-CN", CN);
export default {
name: "VideoPlayer",
props: {
options: {
type: Object,
default() {
return {};
}
},
dispose: {
type: Boolean,
required: true
}
},
data() {
return {
player: null
};
},
watch: {
dispose(newVal) {
if (!newVal && this.player) {
this.player.dispose();
}
}
},
mounted() {
this.player = videojs(this.$refs.videoPlayer, this.options);
this.videoPlayer = this.$refs.videoPlayer;
console.log(this.player);
console.log(this.videoPlayer);
// 播放结束
var that = this;
this.videoPlayer.addEventListener("ended", (e) => {
// 重置状态
// this.videoVisiable = false;
that.$parent.setVideoVisible(false);
that.$parent.setTabindex(0);
that.$parent.enterImmerseMode(false);
});
}
};
</script>
<style lang="scss" scoped>
.video-js-comp {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
}
video {
display: block;
min-height: 100%;
min-width: 100%;
position: absolute !important;
top: 50% !important;
left: 50% !important;
transform: translate(-50%, -50%);
}
video:focus {
outline: none;
}
</style>

+ 68
- 0
src/config/cmdDict.js View File

@@ -0,0 +1,68 @@
export default {
qp: {
equip_no: "2",
set_no: "2",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "打开全屏"
},
fhsy: {
equip_no: "2",
set_no: "1701",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "返回首页"
},
zhts: {
equip_no: "2",
set_no: "103",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "打开综合态势"
},
afts: {
equip_no: "2",
set_no: "104",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "打开安防态势"
},
ryts: {
equip_no: "2",
set_no: "105",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "打开人员态势"
},
tcts: {
equip_no: "2",
set_no: "106",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "打开停车态势"
},
nyts: {
equip_no: "2",
set_no: "107",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "打开能源态势"
},
xfts: {
equip_no: "2",
set_no: "108",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "打开消防态势"
},
xmdsxt: {
equip_no: "1005",
set_no: "2",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "打开西门东侧摄像头"
},
hys1bsxt: {
equip_no: "1005",
set_no: "3",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "打开一号会议室北侧摄像头"
},
dtmxsxt: {
equip_no: "1005",
set_no: "4",
value: "AlarmCenter.ScreensAddin.ScreensCommand",
info: "打开大堂门口西侧摄像头"
}
};

+ 80
- 0
src/config/index.js View File

@@ -0,0 +1,80 @@
export default {
appId: "xxxxx",
appSecret: "xxxxxxx",
/**
* @description 是否输出调试信息
*/
isDebuggable: process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test",
/**
* @description api请求基础路径
*/
baseUrl: process.env.VUE_APP_SERVER_URL,
/**
* CMS URL
*/
mediaApi: "http://127.0.0.1",
/**
* @description shop type
*/
shopType: Object.freeze({
SHOP_DETAIL: 1,
SHOP_MAP: 2,
SHOP_LIST_ALL: 3,
SHOP_LIST_FOOD: 4,
SHOP_LIST_PLAY: 5,
SHOP_LIST_CLOTH: 6,
SHOP_LIST_KID: 7,
SHOP_LIST_ON_SALE: 8,
SHOP_LIST_ON_SERVICE: 9,
SHOP_LIST_ON_BEAUTY: 10
}),
isPortrait: true,
storageKey: Object.freeze({
KEY_SHOP_DATA: "preloadShopData"
}),
listItemType: Object.freeze({
SHOP: 0,
CHAT: 1
}),
appTitle: "奥北科技园",
username: "adminadmin",
userpwd: "admin.123",
// serverHj1: "http://192.168.1.254:8089",
getKeyUrl: "http://tx.lecooai.com:47880/api/server/getkey_pc",
serverHj: "http://dev.lecooai.com:47880",
// serverHj: "http://192.168.1.254:8089",
// serverHj: "http://39.105.85.176:63089",
mouseServerAb: "http://39.105.85.176:63091",
// serverDb: "http://39.105.85.176:63300",
serverDb: "http://192.168.1.254:13000",
padSocketUrl: "ws://192.168.124.4:9090",
// padSocketUrl: "ws://192.168.10.65:8666",
serverUrl: "http://192.168.10.65",
openDoorUrl: "http://39.105.85.176:63330",
serverPot: "/hj",
userType: {
mgr: 0,
emp: 1,
keyVisitor: 2,
courier: 3,
blackRole: 4,
visitor: 5
},
userTypeCn: {
0: "高管",
1: "员工",
2: "VIP客户",
3: "快递",
4: "黑名单",
5: "访客"
},
debug: true,
faceDetectEnable: false,
detectSleep: 6000,
speakSleep: 60000,
returnAdPage: 30000,
currentScene: "lecoo1218"
};

+ 19
- 0
src/db/dbHelp.js View File

@@ -0,0 +1,19 @@
var connection = require('./sql.js')

module.exports = {
query: (callback) => {
connection.query("select * from cmd order by created_at desc limit 20", function (error, results, fields) {
console.log(results)
callback(results);
})
},

add : (obj, callback) => {

connection.query('insert into cmd (question_id, question_text, answer) value (?, ?, ?)', [obj.id, obj.text, obj.answer], function (error, results) {
console.log(results)
callback(results);
})
}

}

+ 90
- 0
src/db/dbRouter.js View File

@@ -0,0 +1,90 @@
const { add, query } = require("../db/dbHelp");
const express = require("express");
const router = express.Router();
import Cloudia from "../api/cloudia-sdk-v1.4.1";

// 连接数据库
const jsonWrite = function(res, ret) {
if (typeof ret === "undefined") {
res.json({
code: "1",
msg: "操作失败"
});
} else {
res.json(ret);
}
};

// 接口:增加信息sql,编辑修改信息sql1
router.post("/save", (req, res) => {
const params = req.body;

add(params, (result) => {
jsonWrite(res, result);
});
});

// 接口:用户管理分页接口查询
router.get("/getlist", (req, res) => {
const params = req.body;
console.log(params);
alert(JSON.stringify(Cloudia));
alert("okokokok");
query((result) => {
jsonWrite(res, result);
});
});

const db = require("../db/mssql"); //注意改路径

router.get("/ms/detailMD", (req, res) => {
console.log(db.sql);
//根据时间查询的模板

var count = 0;
var commonResult = [];
db.sql(
"SELECT PassType,count(1) as Count FROM HJ_PersonRecognition WHERE DateDiff(dd,DetectTime,getdate())=0 group by PassType order by PassType",
function(err, result) {
if (err) {
console.log(err);
return;
}
commonResult.push(...result.recordset);
count++;
if (count >= 3) {
res.send(commonResult);
}
}
);
db.sql(
"select '0' as Reserve1, count(1) as cnt from HJ_PersonRecognition as person where person.Reserve1 = '0' and DATEDIFF(DAY, person.DetectTime, GETDATE()) = 0 union select '1' as Reserve1, count(1) as cnt from HJ_PersonRecognition as person where person.Reserve1 = '1' and DATEDIFF(DAY, person.DetectTime, GETDATE()) = 0",
function(err, result) {
if (err) {
console.log(err);
return;
}
commonResult.push(...result.recordset);
count++;
if (count >= 3) {
res.send(commonResult);
}
}
);
db.sql(
"SELECT '0' as online, count(1) as num FROM HJ_EquipInfo WHERE Status = 1 and EquipTypeID = 3 union SELECT '1' as online, count(1) as num FROM HJ_EquipInfo WHERE (Status = 0 or Status = 2) and EquipTypeID = 3",
function(err, result) {
if (err) {
console.log(err);
return;
}
commonResult.push(...result.recordset);
count++;
if (count >= 3) {
res.send(commonResult);
}
}
);
});

module.exports = router;

+ 54
- 0
src/db/mssql.js View File

@@ -0,0 +1,54 @@
/*
mssql模块简单封装
*/
const mssql = require("mssql");
const db = {};
const config = {
user: "sa",
password: "123456", //改成你自己的
server: "192.168.1.254", //改成你自己的
database: "Yifangzhongxin", //改成你自己的
port: 1433, //改成你自己的
options: {
encrypt: false // Use this if you're on Windows Azure
},
pool: {
min: 0,
max: 10,
idleTimeoutMillis: 3000
}
};

//执行sql,返回数据.
db.sql = function(sql, callBack) {
const connection = new mssql.ConnectionPool(config, function(err) {
if (err) {
console.log(err);
return;
}
const ps = new mssql.PreparedStatement(connection);
ps.prepare(sql, function(err) {
if (err) {
console.log(err);
return;
}
ps.execute("", function(err, result) {
if (err) {
console.log(err);
return;
}

ps.unprepare(function(err) {
if (err) {
console.log(err);
callback(err, null);
return;
}
callBack(err, result);
});
});
});
});
};

module.exports = db;

+ 10
- 0
src/db/sql.js View File

@@ -0,0 +1,10 @@
var mysql = require("mysql");
// 连接数据库
var connection = mysql.createConnection({
host: "39.105.85.176",
user: "root",
password: "Lecooai@2021",
database: "vue"
});

module.exports = connection;

+ 44
- 0
src/main.js View File

@@ -0,0 +1,44 @@
import Vue from "vue";
import App from "@/App.vue";
import router from "@/router";
import _ from "lodash/core";
Vue.prototype._ = _;
import "@/plugins/lazyload";
import "@/plugins/mintui";
import Navigation from "vue-navigation";
Vue.use(Navigation, { router });
import Axios from "axios";
Vue.prototype.$axios = Axios;
import ElementUI from "element-ui"; //element-ui的全部组件
import "element-ui/lib/theme-chalk/index.css"; //element-ui的css
Vue.use(ElementUI); //使用elementUI
Vue.config.productionTip = false;
import jquery from "jquery";
Vue.prototype.$ = jquery;
let app = null;
let count = 0;
function bindData() {
if (count == 1) {
app = new Vue({
router,
render: (h) => h(App)
}).$mount("#app");
global.vm = app;
}
}
Axios.get("./config.json").then((res) => {
if (res.data) {
count += 1;
Vue.prototype.$cmdList = res.data;
bindData();
}
});
export default Vue;

+ 284
- 0
src/mixins/mixin.js View File

@@ -0,0 +1,284 @@
import Config from "../config";
import Cloudia from "../api/cloudia-sdk-v1.4.1";
import { genPreRemoteReq, genRyts } from "../utils/genTtsText";
import moment from "moment";

let timer;
/**
* 通用的方法和一些与业务无关的工具方法
*
*/
const mixin = {
data() {
return {
msg444: "hello"
};
},
methods: {
mixinMethod() {
console.log(this.$cmdList);
console.log(this.stateVal);
console.log(this.msgList);
// this.returnAdPage();
console.log(this.msg444 + ",这是mixin混入方法");
},
setVideoVisible(visible) {
this.videoVisible = visible;
},
setTabindex(tabIndex) {
this.tabIndex = tabIndex;
},
playVideo(src) {
if (src) {
this.picVisible = false;
this.tabIndex = 5;
this.playerOptions = {
muted: false,
language: "zh-CN",
playbackRates: [0.5, 1.0, 1.5, 2.0],
autoplay: true,
controls: false,
sources: [
{
type: "video/mp4",
src: src
}
]
};
this.videoVisible = true;
this.enterImmerseMode(true);
} else {
}
},
playPic(src) {
if (src) {
this.videoVisible = false;
this.tabIndex = 5;
this.picUrl = src;
this.picVisible = true;
}
},
setProgressCode(key) {
this.lastReq = key;
},
sendMsg(type) {
// Cloudia.textTriggerNlp("人员态势");
/*let obj = this.$cmdList["zhh_company_open"];
obj.data.companyName = "道有道";
console.log(obj);*/

/*if (this.rotationY > 360) {
this.rotationY = 0.0;
} else {
this.rotationY += 0.2;
}
Cloudia.updateCharacterRotation(0.0, this.rotationY, 0.0);*/
let obj = this.$cmdList["ry_open"];
// obj.data.companyName = "道有道";
var that = this;
genPreRemoteReq(
obj,
(result) => {
that.consoleLog("success=====1");
console.log("success=====1");
// that.consoleLog(JSON.stringify(result));

var results = obj.msg.match(/#\[\w*]/g);
console.log(results);
obj.showMsg = obj.msg;
if (!obj.after_exec) {
for (var i in results) {
var temp = results[i];
var iTemp = temp.replace("#[", "");
iTemp = iTemp.replace("]", "");

obj.showMsg = obj.showMsg.replace(temp, result.HttpData.data[iTemp]);
}
console.log(obj);
that.addMsgList(2, obj.showMsg);
} else {
console.log(that.$cmdList[obj.after_exec]);

let cobj = that.$cmdList[obj.after_exec];
genPreRemoteReq(
cobj,
(result) => {
var results = cobj.msg.match(/#\[\w*]/g);
cobj.showMsg = cobj.msg;
for (var i in results) {
var temp = results[i];
var iTemp = temp.replace("#[", "");
iTemp = iTemp.replace("]", "");

cobj.showMsg = cobj.showMsg.replace(temp, result.HttpData.data[iTemp]);
}
that.addMsgList(2, cobj.showMsg);
},
(err) => {
console.log(err);
}
);
}
},
(res) => {
console.log("error=======");
that.consoleLog("error=====1");
that.consoleLog(res);
// that.consoleLog(JSON.stringify(res));
console.log(res);
}
);

/*opendoor(
(res) => {},
(err) => {}
);*/

let a = "0";
let b = 0;
/*alert(this._.isEqual(a, "" + b));
alert(this._.isEqual("" + b, a));
alert(a == b);*/
this.consoleLog("skudhfishdifosijdknfknsdf");
/*for (var i = 0; i < this.msgList.length; i++) {
if (this.msgList[i].from == type) {
this.msgList.splice(i, 1);
}
}
let text =
"奥北科技园由北京奥北兴华科贸中心有限公司投资开发,园区定位为“高端生态商务花园” 。项目总建筑面积约10.4万平方米,按照“中心绿化带串联起多个建筑”的规划构思,项目整体分为东、西、两个区域,东区为2栋甲级写字楼,西区为24栋小型花园式商务独栋办公楼 。";
this.addMsgList(2, text);*/
},

fhsy(callback) {
var obj = this.$cmdList["fhsy"];
genPreRemoteReq(
obj,
(res) => {
// that.addMsgList(2, obj.info);
callback(res);
},
(res) => {
Cloudia.showLongToast(JSON.stringify(res));
}
);
},
returnAdPage() {
/*this.tabIndex = 4;
// this.tabIndex = 0;
this.sleep = true;
this.isSpeaking = false;
this.lastReq = "";
this.msgList = [
{
from: 2,
message: "您好,我是小酷。"
}
];*/
Cloudia.setClothes("suit_blue");
},
leaveAdPage() {
this.tabIndex = 0;
// this.tabIndex = 0;
this.sleep = false;
Cloudia.setClothes("suit_blue");
},

enterImmerseMode(mode) {
Cloudia.enterImmerseMode(mode);
},
showQrCode() {
this.imgQrcode = true;
timer && clearTimeout(timer);
timer = setTimeout(function() {
Cloudia.playMotion("showRightHandTop");
}, 1500);
},

queryNlp() {
let that = this;
this.$axios.get(Config.serverDb + "/api/db/getlist", {}).then((res) => {
that.nplList = res.data;
});
},
changeCharacter() {
var characters = this.$cmdList["characters"];
if (this.characterInd >= characters.length - 1) {
this.characterInd = 0;
} else {
this.characterInd++;
}
Cloudia.setCharacter(characters[this.characterInd]);
this.character = characters[this.characterInd];
this.clothesInd = 0;
var clothes = this.$cmdList["clothes"][this.character];
Cloudia.setClothes(clothes[this.clothesInd]);
},
changeCloth() {
var clothes = this.$cmdList["clothes"][this.character];
if (this.clothesInd >= clothes.length - 1) {
this.clothesInd = 0;
} else {
this.clothesInd++;
}
Cloudia.setClothes(clothes[this.clothesInd]);
},
scrollMsgToBottom() {
this.tabIndex = 0;
let that = this;
this.$nextTick(() => {
let middle = that.$refs["middle"];
if (middle) middle.scrollTop = middle.scrollHeight;
});
},
clickEvent() {
this.clickNum++;
if (this.clickNum >= 20) {
this.close();
this.clickNum = 0;
// alert(this.clickNum);
}
if (this.clickNum >= 15) {
this.debug = !this.debug;
this.showMsg = !this.showMsg;
}
},

_clearCache() {
localStorage.clear();
},
hiddenDebug() {
this.debug = false;
},
containStr(array, text) {
for (var i = 0; i < array.length; i++) {
if (text.indexOf(array[i]) > -1) {
return array[i];
}
}
return null;
},

keysToArray(obj) {
var array = [];
for (var key in obj) {
array.push(key);
}
return array;
},

consoleLog(text) {
let ts = new Date().getTime();
this.consoleList = {
index: ts,
message: text,
time: moment(ts).format("mm:ss.SSS")
};
},

close() {
Cloudia.restartH5();
}
}
};
export default mixin;

+ 321
- 0
src/mixins/mixin_demo.js View File

@@ -0,0 +1,321 @@
import Cloudia from "../api/cloudia-sdk-v1.4.1";
import Config from "../config";
import md5 from "js-md5";
var timer;

const mixin_demo = {
data() {
return {
toast: "A Toast",
longToast: "A Long Toast",
tts: "1234567890",
bOffset: "0, 0, 0, 0",
cLocation: "-378.8,-0.7,448.3,false",
cRotation: "0,179.5,0,false",
motion: "bow",
wall: "Change BG Color",
wallRes: "3DRoom",
exp: "smile, 1",
mediaEvent: "playing",
asrWakeUp: true,
walkGreetEnable: true,
cameraMode: "level",
bgLocation: "1400,0,0",
setValueText: 12,
getValueText: 0,
ttsText: "成都天气",
testing: true,
iPlayTts: true,
iAsrWakeUp: true,
iGetRobotConfig: true,
iAppConfig: true,
iGetVolume: true,
allInterfaces: new Map(),
cloudiaEvents: new Map()
};
},
methods: {
getValidClass(cond) {
if (cond === undefined || cond === 0) {
return "api-layout interface-init";
} else if (cond === 1) {
return "api-layout interface-success";
} else {
return "api-layout interface-fail";
}
},
interfaceShowToast() {
let result = Cloudia.showToast(this.toast);
this.allInterfaces["interfaceShowToast"] = result ? 1 : 2;
},
interfaceShowLongToast() {
let result = Cloudia.showLongToast(this.longToast);
this.allInterfaces["interfaceShowLongToast"] = result ? 1 : 2;
},
interfacePlayTts() {
let result = Cloudia.playTts(this.tts);
if (result) {
this.iPlayTts = true;
timer && clearTimeout(timer);
timer = setTimeout(() => {
this.iPlayTts = false;
this.allInterfaces["interfacePlayTts"] = this.cloudiaEvents["ttsPlay"] === 10 ? 1 : 2;
}, 1500);
} else {
this.allInterfaces["interfacePlayTts"] = 2;
}
},
interfaceUpdateBrowserLocation() {
this.bOffset = this.bOffset.replace(/ /g, "");
let offset = this.bOffset.split(",");
let result = Cloudia.updateBrowserLocation(offset[0], offset[1], offset[2], offset[3]);
this.allInterfaces["interfaceUpdateBrowserLocation"] = result ? 1 : 2;
},
interfaceUpdateCharacterLocation() {
this.cLocation = this.cLocation.replace(/ /g, "");
let location = this.cLocation.split(",");
let result = Cloudia.updateCharacterLocation(location[0], location[1], location[2], location[3]);
this.allInterfaces["interfaceUpdateCharacterLocation"] = result ? 1 : 2;
},
interfaceUpdateCharacterRotation() {
this.cRotation = this.cRotation.replace(/ /g, "");
let rotation = this.cRotation.split(",");
let result = Cloudia.updateCharacterRotation(rotation[0], rotation[1], rotation[2], rotation[3]);
this.allInterfaces["interfaceUpdateCharacterRotation"] = result ? 1 : 2;
},
interfaceUpdateWallLocation() {
let result = Cloudia.setWallLocation(this.bgLocation);
this.allInterfaces["interfaceUpdateWallLocation"] = result ? 1 : 2;
},
interfacePlayMotion() {
this.motion = this.motion.replace(/ /g, "");
let params = this.motion.split(",");
let result;
if (params.length === 2) {
result = Cloudia.playMotion(params[0], params[1]);
} else {
result = Cloudia.playMotion(params[0]);
}
this.allInterfaces["interfacePlayMotion"] = result ? 1 : 2;
},
interfaceSetBgWallColor() {
//通过使用 getElementById() 来访问 <color> 元素
let colorEl = document.getElementById("color");
console.info("selected color:" + colorEl.value);
let color = colorEl.value.replace("#", "");
let r = parseInt(color.substring(0, 2), 16) / 255;
let g = parseInt(color.substring(2, 4), 16) / 255;
let b = parseInt(color.substring(4, 6), 16) / 255;
// console.info("Selected color: rgb(" + r + ", " + g + ", " + b + ")");
let result = Cloudia.setBgWallColor(r + ", " + g + ", " + b);
this.allInterfaces["interfaceSetBgWallColor"] = result ? 1 : 2;
},
interfaceSetBgWallRes() {
let result = Cloudia.setBgWallResource(this.wallRes);
this.allInterfaces["interfaceSetBgWallRes"] = result ? 1 : 2;
},
interfaceGetDeviceId() {
let that = this;
this.iGetRobotConfig = true;
return Cloudia.getRobotInfoConfig("RobotId").then(function(ReturnValue) {
if (ReturnValue !== undefined && ReturnValue.ReturnValue !== undefined) {
that.deviceId = ReturnValue.ReturnValue;
}
that.allInterfaces["interfaceGetDeviceId"] = that.deviceId.length > 0 ? 1 : 2;
that.iGetRobotConfig = false;
});
},
interfaceGetAppConfig() {
let that = this;
this.iAppConfig = true;
return Cloudia.getAppConfig().then(function(ReturnValue) {
if (ReturnValue !== undefined && ReturnValue.ReturnValue !== undefined) {
that.appConfig = ReturnValue.ReturnValue;
}
that.allInterfaces["interfaceGetAppConfig"] = that.appConfig.length > 0 ? 1 : 2;
that.iAppConfig = false;
});
},
interfaceSetCharacter() {
let result = Cloudia.setCharacter(this.character);
this.allClothes = cloudiaConfig.allClothes;
this.clothes = this.allClothes[0];
this.allInterfaces["interfaceSetCharacter"] = result ? 1 : 2;
return result;
},
interfaceSetClothes() {
let result = Cloudia.setClothes(this.clothes);
this.allInterfaces["interfaceSetClothes"] = result ? 1 : 2;
},
interfacePostMediaEvent() {
let result = Cloudia.postMediaEvent(this.mediaEvent);
this.allInterfaces["interfacePostMediaEvent"] = result ? 1 : 2;
},
interfaceSetAsrWakeUpEnable() {
let result = Cloudia.setAsrWakeUpEnable(this.asrWakeUp);
if (result) {
this.iAsrWakeUp = true;
timer && clearTimeout(timer);
timer = setTimeout(() => {
if (this.cloudiaEvents["asrWakeUp"] === this.asrWakeUp ? 10 : 20) {
this.allInterfaces["interfaceSetAsrWakeUpEnable"] = 1;
} else {
this.allInterfaces["interfaceSetAsrWakeUpEnable"] = 2;
}
this.iAsrWakeUp = false;
}, 1000);
} else {
this.allInterfaces["interfaceSetAsrWakeUpEnable"] = 2;
}
},
interfaceStopPlayTts() {
let result = Cloudia.stopPlayTts(false);
this.allInterfaces["interfaceStopPlayTts"] = result ? 1 : 2;
},
interfaceEnterImmerseMode() {
let result = Cloudia.enterImmerseMode(this.immerseMode);
this.allInterfaces["interfaceEnterImmerseMode"] = result ? 1 : 2;
},
interfaceStartVideoTalk() {
let result = Cloudia.startVideoTalk();
this.allInterfaces["interfaceStartVideoTalk"] = result ? 1 : 2;
},
interfaceStopVideoTalk() {
let result = Cloudia.stopVideoTalk();
this.allInterfaces["interfaceStopVideoTalk"] = result ? 1 : 2;
},
interfaceSetVolume() {
let result = Cloudia.setVolume(this.setValueText);
this.allInterfaces["interfaceSetVolume"] = result ? 1 : 2;
},
interfaceGetVolume() {
this.iGetVolume = true;
return Cloudia.getVolume().then((ReturnValue) => {
if (ReturnValue !== undefined && ReturnValue.ReturnValue !== undefined) {
this.getValueText = ReturnValue.ReturnValue;
console.info("========:" + this.getValueText + ", " + this.setValueText);
this.allInterfaces["interfaceGetVolume"] =
this.getValueText.toString() === this.setValueText.toString() ? 1 : 2;
} else {
this.allInterfaces["interfaceGetVolume"] = 2;
}
this.iGetVolume = false;
});
},
interfaceDownloadFiles() {
let result = Cloudia.downloadFiles(
"test",
JSON.stringify([
{
name: "04070c61b7d40b5a90b98640645493cb.jpeg",
url: "https://127.0.0.1"
},
{
name: "112350h4wcwa94c9ch3oth.jpg",
url: "https://127.0.0.1"
}
])
);
this.allInterfaces["interfaceDownloadFiles"] = result ? 1 : 2;
},
interfaceTextTriggerNlp() {
let result = Cloudia.textTriggerNlp(this.ttsText);
this.allInterfaces["interfaceTextTriggerNlp"] = result ? 1 : 2;
},
loadAd() {
// TODO !!!!不同的环境需要切换不同的baseUrl!!!!
let baseUrl = "https://127.0.0.1";
let timestamp = new Date().getTime();
// TODO 填写你自己的appId
let appId = Config.appId;
let nonceStr = this.getRandomInt(1000, 9999);
// TODO 填写你自己的appSecret
let appSecret = Config.appSecret;
let sign = md5("appId" + appId + "timestamp" + timestamp + "nonceStr" + nonceStr + appSecret);
// console.info("appId:" + appId);
// console.info("appSecret:" + appSecret);
// console.info("sign:" + sign);
const headers = {
"Content-Type": "application/json",
appId: appId,
timestamp: timestamp,
nonceStr: nonceStr,
sign: sign
};
let url = "/crss-robot/ads/robotapi/v1/adSpace/get?pageCode=home&robotCode=" + this.deviceId;
fetch(baseUrl + url, { headers })
.then(async (response) => {
const data = await response.json();
if (!response.ok) {
// get error message from body or default to response statusText
const error = (data && data.message) || response.statusText;
return Promise.reject(error);
}
console.info("load ad data success:" + JSON.stringify(data));
if (data.code === 0 && data.data && data.data.adList) {
// 拼接完整URL
data.data.adList.map((e) => {
e.url = baseUrl + e.url;
});
let adData = JSON.stringify(data.data.adList);
// 下载广告数据,下载成功之后会在event事件中收到通知
Cloudia.downloadFiles("home", adData);
console.info("ad data:" + adData);
} else {
console.warn("ad data is empty");
}
})
.catch((error) => {
console.error("load ad data error:" + error);
});
},
interFun() {
var ii = "qp";
this.handleCustomize(ii);
},

insertNlp() {
this.addMsgList(2, "测试一下,测试一下");
if (this.nplList.length > 10) {
this.nplList.splice(10, this.nplList.length - 10);
}
this.nplList = [
{ question_id: new Date().getTime(), question_text: "test test", answer: "answer....." },
...this.nplList
];

this.$axios
.post(Config.serverDb + "/api/db/save", {
id: new Date().getTime(),
text: "test test",
answer: "answer....."
})
.then((res) => {
console.log(res);
});
},
queryNlp() {
let that = this;
this.$axios.get(Config.serverDb + "/api/db/getlist", {}).then((res) => {
that.nplList = res.data;
});
},
testAllInterface() {
let i = 0;
for (let [key, value] of this.allInterfaces) {
timer && clearTimeout(timer);
timer = setTimeout(() => {
this.testing = true;
try {
this[key]();
} catch (e) {
this.allInterfaces[key] = 2;
console.error("interface exec failed:" + key + ", " + value + "----" + e);
}
this.testing = false;
}, ++i * 1000);
}
}
}
};
export default mixin_demo;

+ 156
- 0
src/mixins/mixin_socket.js View File

@@ -0,0 +1,156 @@
import JsonView from "../components/JsonView";
import videoPlayer from "../components/VideoView";
import { Switch } from "mint-ui";
import { swiper, swiperSlide } from "vue-awesome-swiper";
import Config from "../config";
import { handleFaceType } from "../utils/handleTts";
let rec; //断线重连后,延迟5秒重新创建WebSocket连接 rec用来存储延迟请求的代码
let isConnect = false;
const mixin_socket = {
components: {
JsonView,
videoPlayer,
swt: Switch,
swiper,
swiperSlide
},
data() {
return {
webData: null,
lastDetectTs: 0,
lastPerson: {},
lastPersonId: 0,
lastDetectObj: {},
lastPersonTs: 0
};
},
computed: {},
mounted() {
if (Config.faceDetectEnable) {
this.initWebSocket();
}
},

destroyed() {
this.websock && this.websock.close();
localStorage.clear();
},

methods: {
initWebSocket() {
const path = Config.padSocketUrl; // 后台给的websocket的ip地址
this.websock = new WebSocket(path);
this.websock.onmessage = this.websocketOnMessage;
this.websock.onopen = this.websocketOnOpen;
this.websock.onerror = this.websocketOnError;
this.websock.onclose = this.websocketClose;
},
reConnect() {
this.consoleLog("尝试重新连接");
if (isConnect) return; //如果已经连上就不在重连了
rec && clearTimeout(rec);
let that = this;
rec = setTimeout(function() {
// 延迟5秒重连 避免过多次过频繁请求重连
that.initWebSocket();
}, 5000);
},
// 连接建立成功的信号
websocketOnOpen() {
this.consoleLog("初始化成功"); // 连接成功后就可以在这里写一些回调函数了
},
// 连接建立失败重连
websocketOnError() {
// 如果报错的话,在这里就可以重新初始化websocket,这就是断线重连
// this.initWebSocket()
this.consoleLog("WebSocket连接发生错误");
isConnect = false; //连接断开修改标识
this.reConnect(); //连接错误 需要重连
},
// 数据接收
websocketOnMessage(e) {
let that = this;
let obj = e.data;
if (typeof obj != "object") {
obj = JSON.parse(obj);
}
that.consoleLog(
"id=" +
(obj.id.length > 7 ? obj.id.substr(7) : obj.id) +
",name=" +
obj.name +
",tag=" +
obj.tag +
",gender=" +
obj.gender
);
// console.log(e.data);
//非说话的状态下,用户说完话两秒后
let currentTs = new Date().getTime();
if (!that.execLocked && !that.isSpeaking && that.lastReq == "" && currentTs - that.lastQTs > 2000) {
that.handleDetectedFace(obj);
}
},
// 数据发送
websocketSend(Data) {
if (typeof Data == "object") {
Data = JSON.stringify(Data);
}
this.consoleLog("send to serv:" + Data);
this.websock.send(Data); // Data变量就是你想对后台说些啥,根据后端给你的接口文档传值进行交互
},
// 关闭的信号
websocketClose() {
this.consoleLog("断开连接,重试连接");
isConnect = false; //连接断开修改标识
this.reConnect(); //服务器主动断开的情况下,需要重连
},
handleDetectedFace(obj) {
let that = this;
let currentTs = new Date().getTime();
let str = "";

if (obj && obj.id == -1) {
//识别到脸
that.lastDetectTs = currentTs;
that.leaveAdPage();
setTimeout(function() {
that.playMotion("showLeftHand");
}, 600);

return;
} else if (obj && obj.id > 0) {
//识别到人
if (that.lastReq == "moshengren") {
that.lastReq = "";
}
that.lastDetectTs = currentTs;
that.lastDetectObj = obj;
if (that.lastDetectObj.id === that.lastPerson.id) {
that.lastPerson.name = that.lastDetectObj.name;
that.lastPerson.tag = that.lastDetectObj.tag;
}
if (
(obj.id == that.lastPersonId && (currentTs - that.lastPersonTs >= 15000 || that.sleep)) ||
obj.id != that.lastPersonId
) {
that.lastPersonId = obj.id;
that.lastPerson = obj;
str += handleFaceType(that, obj);
that.lastPersonTs = currentTs;
that.sleep = false;
that.tabIndex = 0;
that.addMsgList(2, str);
}
}
},
noDetectedFace() {
let currentTs = new Date().getTime();
if (currentTs - this.lastDetectTs > 5000) {
return true;
}
return false;
}
}
};
export default mixin_socket;

+ 7
- 0
src/packages/meta.js View File

@@ -0,0 +1,7 @@
// 引入各种函数,便于做成npm包
// indexedDB 部分
import MetaHelp from './nf-meta/help.js'

export {
MetaHelp
}

+ 87
- 0
src/packages/nf-meta/help.js View File

@@ -0,0 +1,87 @@
import { reactive } from 'vue'

// 从json文件加载meta
import loadMetaFormJson from './loadmeta-json.js'

// 从 webSQL加载meta
import loadMetaFormSQL from './loadmeta-sql.js'

// 把meta存入 indexedDB
import { saveMetaAll, loadMeta } from './savemeta-db.js'

/**
* meta的help
* * 从 json 加载 meta,存入 indexedDB
* * 从 webSQL 加载 meta,存入 indexedDB
* * 从 indexedDB 加载 meta,
* * 把 meta 存入状态
*/
export default class MetaHelp {
constructor (url) {
this.jsonUrl = url, // json 的路径,axios 加载用
this.sqlHelp = null, // 访问 webSQL
this.dbHelp = null, // 访问 indexedDB
this.meta = reactive({
menu: {},
module: {},
service: {}
})
}

/**
* 从 indexedDB 里面加载 meta
* @returns
*/
async loadMetaFromDB() {
return await loadMeta(this.dbHelp)
}

/**
* 把 meta 存入 state
* @param {*} state 状态
* @param {*} meta 要存入的 meta。menu:数组;module:对象;service:对象
*/
toState(state, meta) {
// 存入菜单,需要去重
meta.menu.forEach(_menu => {
if (state.menu.findIndex((m) => m.id === _menu.id) < 0) {
state.menu.push(_menu)
}
})
// 存入模块
Object.assign(state.module, meta.module)
// 存入服务
Object.assign(state.service, meta.service)
}

/**
* 从 webSQL 加载 meta,然后存入 indexedDB,并且返回 meta
* @param {*} moduleId
*/
async sqlToDB(moduleId = null) {
console.log('MetaHelp 的 sqlToDB', this)
const meta = await loadMetaFormSQL(this.sqlHelp)
console.log('MetaHelp 的 SQL 读取出来的 meta ', meta)

// 遍历,添加到 indexedDB
saveMetaAll(this.dbHelp, meta)

return meta
}

/**
* 从 json 加载 meta,然后存入 indexedDB,并且返回 meta
* @param {*} moduleId 模块ID
* @returns
*/
async loagMetaFromJson(moduleId = null) {
console.log('MetaHelp 的 sqlToDB', this)
const meta = await loadMetaFormJson(this.jsonUrl)
console.log('MetaHelp 的 从json加载的meta:', meta)

// 遍历,添加到 indexedDB
saveMetaAll(this.dbHelp, meta)
return meta
}
}

+ 135
- 0
src/packages/nf-meta/loadmeta-json.js View File

@@ -0,0 +1,135 @@

// axios
import axios from 'axios'

/**
* 加载 json 文件 整理成 meta 的格式,返回
*/

/**
* 01 获取 json文件 的目录,因为json文件比较多,还希望实现热更新,所以做了个加载目录。
* * 应该加个随机数,便于即使更新。
* * 因为有缓存,所以不用怕过多访问的问题。
*/
const _loadFileDirectory = (jsonURL) => {
return new Promise((resolve, reject) => {
const _url = `${jsonURL}/dir.json?v=1`
axios.get(_url).then((res) => {
// console.log('dir -- 目录:', res)
resolve(res.data)
}).catch((res) => {
reject(res)
})
})
}

/**
* 整理加载的json,转成meta格式
*/
const _format = (res) => {
const meta = {
service: {},
module: {},
menu: res[0].data.menu
}

// 遍历meta,进行分类
res.forEach((re, index) => {
if (index === 0) return // 第一个是菜单,
const model = re.data
if (typeof model.actions !== 'undefined') {
// 后端API
meta.service[model.moduleId] = model
} else {
// 模块的 meta
if (typeof meta.module[model.moduleId] === 'undefined') {
meta.module[model.moduleId] = {
moduleId: model.moduleId
}
}

// 开始判断
if (typeof model.btnOrder === 'object') {
// 按钮
meta.module[model.moduleId].button = model
} else if (typeof model.quickFind === 'object') {
// 查询
meta.module[model.moduleId].find = model
} else if (typeof model.idName === 'string') {
// 列表
meta.module[model.moduleId].grid = model
} else if (typeof model.formId !== 'undefined') {
// 表单
if (typeof meta.module[model.moduleId].forms === 'undefined') {
meta.module[model.moduleId].forms = {}
}
meta.module[model.moduleId].forms[model.formId] = model
}
}
})
return meta
}

/**
* axios 读取json文件,然后返回
* @param {*} josnDir 前端模块meta 的文件夹
* @param {*} serviveDir 后端服务meta 的文件夹
* @param {*} jsonURL 项目meta的url
* @returns
*/
const _loadMeta = (josnDir, serviveDir, jsonURL) => {
return new Promise((resolve, reject) => {
const actionName = ['button', 'find', 'grid']
// 加载json的 请求的 数组,交给 Promise.all 使用
const getMetaAxios = []
// 加入导航菜单
const _url = `${jsonURL}/menu.json`
getMetaAxios.push(axios.get(_url))

// 前端meta 请求 加入数组
for (const key in josnDir) {
const meta = josnDir[key] // 模块需要的表单
// 添加按钮、列表、查询
actionName.forEach(action => {
const _url = `${jsonURL}module/${key}/${action}.json`
getMetaAxios.push(axios.get(_url))
})
// 添加表单
meta.forEach(form => {
const _url = `${jsonURL}module/${key}/${form}.json`
getMetaAxios.push(axios.get(_url))
})
}

// 后端API的meta 请求,也加入数组
serviveDir.forEach(api => {
const _url = `${jsonURL}service/${api}.json`
getMetaAxios.push(axios.get(_url))
})

// 一起发起所有json文件的请求
Promise.all(getMetaAxios).then((res) => {
// console.log('data:', res)
if (res[0].status === 200) { // statusText
// json 数据 转换成 meta 格式
const meta = _format(res)
console.log('----json--处理好后的--meta:--', meta)
// 返回 meta
resolve(meta)
}
})
})
}

/**
* 加载josn文件,整理后变成meta格式
* @param {string} jsonURL 项目meta的url
* @returns 整理好的meta
*/
const loadMetaFormJson = async (jsonURL) => {
// 获取json的文件目录,便于 axios 加载
const dir = await _loadFileDirectory(jsonURL)
return await _loadMeta(dir.jsonDir, dir.serviceDir, jsonURL)
}

export default loadMetaFormJson

+ 206
- 0
src/packages/nf-meta/loadmeta-sql.js View File

@@ -0,0 +1,206 @@
/**
* 从 SQL 里面加载数据,整理成 meta 的格式
*/

/**
* 把 webSQL 里的【菜单】数据变成 meta 的格式
*/
const _getMenuMetaBySQL = (data) => {
const menu = []
data.forEach(m => {
menu.push({
id: m.moduleId,
componentKind: m.componentKind,
icon: m.icon,
moduleLevel: m.moduleLevel,
parentId: m.parentId,
title: m.title
})
})
return menu
}

/**
* 把 webSQL 里的【按钮】数据变成 meta 的格式
*/
const _getButtonMetaBySQL = (data) => {
const meta = {
moduleId: data.moduleId,
btnOrder: [],
itemMeta: {}
}
data.forEach(btn => {
meta.btnOrder.push(btn.buttonId)
meta.itemMeta[btn.buttonId] = btn
})
return meta
}

/**
* 把 webSQL 里的【列表】数据变成 meta 的格式
*/
const _getGridMetaBySQL = (grid, item) => {
const meta = grid[0]
meta.colOrder = meta.colOrder.split(',')
meta.itemMeta = {}
// meta.quickFind = meta.quickFind
item.forEach(ctl => {
// meta.colOrder.push(ctl.columnId)
meta.itemMeta[ctl.columnId] = ctl
})
return meta
}

/**
* 把 webSQL 里的【查询】数据变成 meta 的格式
*/
const _getFindMetaBySQL = (find, item) => {
const meta = find[0]
meta.allFind = meta.allFind.split(',')
meta.quickFind = meta.quickFind.split(',')
meta.itemMeta = {}
item.forEach(ctl => {
// meta.quickFind.push(ctl.columnId)
// meta.allFind.push(ctl.columnId)
meta.itemMeta[ctl.columnId] = ctl
})
return meta
}

/**
* 把 webSQL 里的【表单】数据变成 meta 的格式
* * form 数组,包含多个 formId
*/
const _getFormMetaBySQL = (forms, items) => {
const meta = {}
forms.forEach(fm => {
meta[fm.formId] = fm
meta[fm.formId].colOrder = meta[fm.formId].colOrder.split(',')
meta[fm.formId].itemMeta = {}
items.filter(a => a.formId === fm.formId).forEach(ctl => {
meta[fm.formId].itemMeta[ctl.columnId] = ctl
})
})
return meta
}

/**
* 把 webSQL 里的【actions】数据变成 meta 的格式
*/
const _getActionMetaBySQL = (data) => {
const actions = {}
data.forEach(action => {
actions[action.actionId] = {
actionName: action.actionName,
kind: action.kind,
model: action.modelId
}
})
return actions
}

/**
* 把 webSQL 里的【models】数据变成 meta 的格式
*/
const _getModelMetaBySQL = (data) => {
const models = {}
data.forEach(model => {
models[model.actionId] = {
tableName: model.tableName,
idKey: model.idKey,
cols: model.cols,
pager: {
orderBy: { roleId: false },
pagerIndex: 1,
pagerSize: model.pagerSize,
pagerTotal: 100
},
query: {}
}
})
return models
}

/**
* 开发模式:从 webSQL 读取数据,转换成meta 的格式
* * 菜单meta、模块meta、service的meta
* * 从 SQL 加载数据,转换格式,返回。
*/
const loadMetaFormSQL = async (sqlHelp) => {
console.log('------webSQL 的 sqlHelp', sqlHelp)

const tables = sqlHelp._tables

// 存放 SQL 里面的 meta
const meta = {}
// 获取所有数据库里的 meta 数据
for (const key in tables) {
const tt = tables[key]
const tmp = await tt.list()
meta[key] = Array.from(tmp)
}
console.log('------controller 的 meta', meta)

// 返回的 meta
const reMeta = {
menu: _getMenuMetaBySQL(meta.nf_module), // 记录菜单
module: {}, // 模块
service: {} // service
}

const _tmp = (name, modId) => {
return meta[name].filter((a) => a.moduleId === modId)
}

// 遍历菜单,变成 meta 的格式
for (let i = 0; i < meta.nf_module.length; i++) {
const modId = meta.nf_module[i].moduleId
const __moduleMeta = { // 记录模块的meta
moduleId: modId,
pager: {},
button: {},
grid: {},
find: {},
forms: {}
}
// 分页
// __moduleMeta.pager = this._getButtonMetaBySQL(meta[151].filter((a) => a.moduleId === modId))
// 列表
__moduleMeta.grid = _getGridMetaBySQL(_tmp('v_module_grid', modId), _tmp('v_module_grid_item', modId))
// 按钮
__moduleMeta.button = _getButtonMetaBySQL(_tmp('v_module_button', modId))
// 查询
__moduleMeta.find = _getFindMetaBySQL(_tmp('v_module_find', modId), _tmp('v_module_find_item', modId))
// 表单
__moduleMeta.forms = _getFormMetaBySQL(_tmp('v_module_form', modId), _tmp('v_module_form_item', modId))

// 记录
reMeta.module[modId] = __moduleMeta
}

// 遍历service,整理后端api
for (let i = 0; i < meta.v_service.length; i++) {
const service = meta.v_service[i]
const serviceId = service.serviceId
// 记录service
const serviceMeta = {
moduleId: serviceId,
moduleName: service.serviceName,
actions: {},
models: {}
}
const _tmp = (id) => {
return meta[id].filter((a) => a.serviceId === serviceId)
}
serviceMeta.actions = _getActionMetaBySQL(_tmp('v_service_action', serviceId))
serviceMeta.models = _getModelMetaBySQL(_tmp('v_service_model', serviceId))

reMeta.service[serviceId] = serviceMeta
}

// 返回整理好的 meta
return reMeta
}

export default loadMetaFormSQL

+ 100
- 0
src/packages/nf-meta/savemeta-db.js View File

@@ -0,0 +1,100 @@
/**
* saveMeta:把 meta 的一个属性 存入 indexedDB 的一个对象仓库
* saveMetaAll:把 meta 存入 indexedDB
* loadMeta:从 indexedDB 加载meta
*/

/**
* json、webSQL 的 meta,存入 indexedDB
* @param {help} help 访问 indexedDB 的 help
* @param {string} storeName 仓库名称
* @param {object} meta 要存入的对象,对象集合
* @returns 仅通知
*/
const saveMeta = (help, storeName, meta) => {
const idName = { // 主键名称的字典
menuMeta: 'id',
moduleMeta: 'moduleId',
serviceMeta: 'moduleId'
}

return new Promise((resolve, reject) => {
let count = 0
help.beginInit(storeName).then((store) => {
count += Object.keys(meta).length
if (count === 0) {
resolve(null)
}
for (const key in meta) {
// 先判断有没有,没有add;有了put
store.get(meta[key][idName[storeName]])
.onsuccess = (event) => {
// console.log('====== 要添加的key:', storeName + '_' + meta[key][idName[storeName]])
// console.log('====== 获取的 结果:', event.target.result)
if (typeof event.target.result === 'undefined') {
// 添加
store.add(meta[key]) // 添加一条meta
.onsuccess = (event) => {
count -= 1
if (count === 0) {
resolve(event.target.result)
}
}
} else {
// 修改
store.put(meta[key]) // 修改一条meta
.onsuccess = (event) => {
count -= 1
if (count === 0) {
resolve(event.target.result)
}
}
}
}
}
})
})
}

/**
* 把 meta 存入 indexedDB
* @param {*} help indexedDB 的 help
* @param {*} meta 要存入的 meta
*/
const saveMetaAll = async (help, meta) => {
await saveMeta(help, 'serviceMeta', meta.service)
await saveMeta(help, 'moduleMeta', meta.module)
await saveMeta(help, 'menuMeta', meta.menu)
}

/**
* 从 indexedDB 里面加载 meta,并且返回
* @param {*} help indexedDB 的 help
* @returns
*/
const loadMeta = async (help) => {
const state = {
menu: [],
module: {},
service: {}
}
state.menu = await help.getModel('menuMeta')
const _module = await help.getModel('moduleMeta')
const _service = await help.getModel('serviceMeta')

for (const key in _module) {
const m = _module[key]
state.module[m.moduleId] = m
}
for (const key in _service) {
const s = _service[key]
state.service[s.moduleId] = s
}
return state
}

export {
saveMetaAll, // 存入 meta
saveMeta, // 存入一个属性
loadMeta // 加载 meta
}

+ 116
- 0
src/packages/nf-ws-indexeddb/_toIndex.js View File

@@ -0,0 +1,116 @@

/**
* 一般查询方式的字典
*/
const _find = {
401: (colValue, key) => colValue === key, // =
403: (colValue, key) => colValue.includes(key), // 包含
405: (colValue, key) => colValue.indexOf(key) === 0, // 起始于
406: (colValue, key) => colValue.indexOf(key) + key.length === colValue.length, // 结束于
413: (colValue, key) => colValue > key, // >
414: (colValue, key) => colValue >= key, // >=
415: (colValue, key) => colValue < key, // <
416: (colValue, key) => colValue <= key, // <=
417: (colValue, key) => key[0] <= colValue && colValue <= key[1], // between
418: (colValue, key) => key[0] < colValue && colValue <= key[1], // a < x <= b
419: (colValue, key) => key[0] <= colValue && colValue < key[1], // a <= x < b
420: (colValue, key) => key[0] < colValue && colValue < key[1] // a < x < b

}

/**
* IDBKeyRange 的字典
*/
const _dicRange = {
401: (_value) => IDBKeyRange.only(_value), // =
// 403: (_value) => IDBKeyRange.only(_value),
// 405: (_value) => IDBKeyRange.only(_value),
// 406: (_value) => IDBKeyRange.only(_value),
413: (_value) => IDBKeyRange.lowerBound(_value, true), // >
414: (_value) => IDBKeyRange.lowerBound(_value), // >=
415: (_value) => IDBKeyRange.upperBound(_value, true), // <
416: (_value) => IDBKeyRange.upperBound(_value), // <=
417: (_value) => IDBKeyRange.bound(_value[0], _value[1]), // between
418: (_value) => IDBKeyRange.bound(_value[0], _value[1], true, false), // a < x <= b
419: (_value) => IDBKeyRange.bound(_value[0], _value[1], false, true), // a <= x < b
420: (_value) => IDBKeyRange.bound(_value[0], _value[1], true, true) // a < x < b
}

// 索引的排序方式,正序、倒序
// const _description = page.description || 'prev' // 默认倒序

/**
* 遍历查询条件,找到对应的字段,做判断,有一个不符合就返回 false
* @param {*} other 查询条件
* @param {*} model 要核对的对象
* @returns 是否符合
*/
const _check = (other, model) => {
let re = true
for (const key in other) {
const colValue = model[key] // 被查询的内容
const kind = other[key][0] // 查询方式
const _key = other[key][1] // 查询条件的值
const _re = _find[kind](colValue, _key) // 验证
if (!_re) re = false
}
return re
}

/**
* 处理索引和其他查询
* @param {*} indexNames 对象仓库已经设置的索引
* @param {*} query 查询条件
* @returns IDBKeyRange、其他查询条件、查询方式、回调查询
*/
const _toIndex = (indexNames, query) => {
const re = {
range: null,
other: {},
find: (other, model) => _check(other, model), // 查询非索引字段
callback: () => {} // 回调查询,可以自定义查询方式
}

// 匹配到的索引字段
let indexName = ''

// 查询条件字段和索引字段,匹配一下,只匹配第一个索引字段
for (let i = 0; i < indexNames.length; i++) {
// 索引字段名称
const _indexName = indexNames[i]

if (typeof query[_indexName] !== 'undefined') {
// 查询方式
const _kind = query[_indexName][0]
// 查询的值
const _value = query[_indexName][1]
// 查询条件里包含索引,记录,后面的就不管了。
// 匹配查询方式
re.range = _dicRange[_kind * 1](_value)
// 没有的话,说明无法利用索引
if (typeof re.range === 'undefined') {
re.range = null
} else {
indexName = _indexName
}
}

if (indexName !== '') {
// 退出循环
i = indexNames.length
}
}

// 把其他的查询字段放在 other 里面
for (const key in query) {
const _query = query[key]
if (indexName !== key) {
// 记录到其他查询条件里面
re.other[key] = _query
}
}

return re
}

export default _toIndex

+ 19
- 0
src/packages/nf-ws-indexeddb/_toObject.js View File

@@ -0,0 +1,19 @@
import { unref, isReactive, toRaw } from 'vue'

// 内部函数,如果是proxy,那么获取原型,否则会报错。
const _vueToObject = (obj) => {
/*
// 处理 ref
let _object = unref(obj)
// 处理 reactive
if (isReactive(_object)) {
// 如果是 vue 的 reactive 类型,那么获取原型,否则会报错
_object = toRaw(_object)
}
*/
const tmp = unref(obj)
const _object = isReactive(tmp) ? toRaw(tmp): tmp
return _object
}

export default _vueToObject

+ 26
- 0
src/packages/nf-ws-indexeddb/begin-init.js View File

@@ -0,0 +1,26 @@
/**
* 初始化数据的时候使用的一个事务。
* * help._db 必然可用,不用判断。
*/
const beginInit = (help, storeName) => {
return new Promise((resolve, reject) => {
//
const tranRequest = help._db.transaction(storeName, 'readwrite')
const store = tranRequest.objectStore(storeName) // 获取store

tranRequest.onerror = (event) => {
console.log('读写事务出错:', event.target.error)
// eslint-disable-next-line prefer-promise-reject-errors
reject('读写事务出错:' + event.target.error)
// tranRequest.abort() // 大概是回滚的意思。
}

tranRequest.oncomplete = (event) => {
// console.log('初始化数据事务完毕:', window.performance.now(), help._dataState)
// help._dataState = 'done'
}
resolve(store)
})
}

export default beginInit

+ 32
- 0
src/packages/nf-ws-indexeddb/begin-tran.js View File

@@ -0,0 +1,32 @@
/**
* 开启一个读写的事务。需要判断 help._db 是否可用
* @param {*} help indexedDB 的 help
* @param {Array} storeName 字符串的数组,对象仓库的名称
* @param {string} type readwrite:读写事务;readonly:只读事务;versionchange:允许执行任何操作,包括删除和创建对象存储和索引。
* @returns 读写事务
*/
const beginTran = (help, storeName, type = 'readwrite') => {
return new Promise((resolve, reject) => {
const _tran = () => {
const tranRequest = help._db.transaction(storeName, type)
tranRequest.onerror = (event) => {
const err = `${type} 事务出错:${event.target.error}`
console.log(err)
reject(err)
}
resolve(tranRequest)
tranRequest.oncomplete = (event) => {
// console.log('beginReadonly 事务完毕:', window.performance.now())
}
}

if (help._db) {
_tran() // 执行事务
} else {
// 注册一个回调事件
help._regCallback.push(() => _tran())
}
})
}

export default beginTran

+ 266
- 0
src/packages/nf-ws-indexeddb/help.js View File

@@ -0,0 +1,266 @@
// 加载操作函数
// 对象仓库的操作
import _clearStore from './store-clear.js' // 清空仓库里的全部对象

// model 的添加、修改、设置、获取、删除
import _addModel from './model-add.js' // 添加一个对象
import _putModel from './model-put.js' // 修改一个对象
import _setModel from './model-set.js' // 修改一个对象
import _getModel from './model-get.js' // 获取一个对象,或者全部(不能查询)
import _delModel from './model-delete.js' // 删除一个对象
import _getCount from './model-count.js' // 获取仓库里的数量

// 对象的查询
import _listAll from './list-index.js' // 获取仓库里符合条件的对象,可以查询。
import _listPager from './list-pager.js' // 分页获取对象,可以查询

// 初始化和事务
import _beginInit from './begin-init.js' // 初始化时用的事务
import _beginTran from './begin-tran.js' // 事务

/**
* indexedDB 的 help,基础功能的封装
* * 打开数据库,建立对象仓库,获取连接对象,实现增删改查
* * info 的结构:
* * * dbFlag: '' // 数据库标识,区别不同的数据库
* * * dbConfig: { // 连接数据库
* * * * dbName: '数据库名称',
* * * * ver: '数据库版本',
* * * },
* * * stores: {
* * * * storeName: { // 对象仓库名称
* * * * * id: 'id', // 主键名称
* * * * * index: { // 可以不设置索引
* * * * * * name: ture, // key:索引名称;value:是否可以重复
* * * * * }
* * * * }
* * * },
* * * init: (help) => {} // 完全准备好之后的回调函数
*/
export default class IndexedDBHelp {
constructor (info) {
this.myIndexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB
if (!this.myIndexedDB) {
console.log('您的浏览器不支持 IndexedDB')
return
}
// 数据库名称和版本号
this._info = {
dbName: info.dbConfig.dbName,
ver: info.dbConfig.ver
}
// 记录连接数据库的对象, IDBDatabase 类型,因为open是异步操作,所以不能立即获得。
this._db = null

// 记录仓库状态。new:新库或者版本升级后;old:有对象仓库了。
this._storeState = 'pending'

/**
* 注册回调事件。
* * 如果组件读写 indexedDB 的时还没有准备好的话,
* * 可以来注册一个事件,等准备好了之后回调。
*/
this._regCallback = []

// 打开数据库,异步操作,大概需要几毫秒的时间。
this.dbRequest = this.myIndexedDB.open(this._info.dbName, this._info.ver)

// 第一次,或者版本升级时执行,根据配置信息建立表
this.dbRequest.onupgradeneeded = (event) => {
this._storeState = 'new'
const db = event.target.result

for (const key in info.stores) {
const store = info.stores[key]
if (db.objectStoreNames.contains(key)) {
// 已经有仓库,验证一下是否需要删除原来的仓库
if (store.isClear) {
// 删除原对象仓库,没有保存数据
db.deleteObjectStore(key)
// 建立新对象仓库
const objectStore = db.createObjectStore(key, { keyPath: store.id })
// 建立索引
for (const key2 in store.index) {
const unique = store.index[key2]
objectStore.createIndex(key2, key2, { unique: unique })
}
}
} else {
// 没有对象仓库,建立
const objectStore = db.createObjectStore(key, { keyPath: store.id }) /* 自动创建主键 autoIncrement: true */
// 建立索引
for (const key2 in store.index) {
const unique = store.index[key2]
objectStore.createIndex(key2, key2, { unique: unique })
}
}
}
}

// 数据库打开成功,记录连接对象
this.dbRequest.onsuccess = async (event) => {
this._db = event.target.result // dbRequest.result
// console.log('【1】成功打开数据库 onsuccess --- ', this._db)
// 修改状态
if (this._storeState === 'pending') {
this._storeState = 'old'
}
// 调用初始化的回调
if (typeof info.init === 'function') {
await info.init(this)
}
// 调用组件注册的回调
this._regCallback.forEach(fn => {
if (typeof fn === 'function') {
fn()
}
})
}

// 处理出错信息
this.dbRequest.onerror = (event) => {
// 出错
console.log('打开数据库出错:', event.target.error)
}
}

// versionchange 全能事务

// 初始化时批量添加对象的事务
beginInit (storeName) {
return _beginInit(this, storeName)
}

// 读写的事务
beginWrite (storeName) {
return _beginTran(this, storeName, 'readwrite')
}

// 只读的事务
beginReadonly (storeName) {
return _beginTran(this, storeName, 'readonly')
}

/**
* 删掉整个库
*/
deleteDB () {
// 定义一个 Promise 的实例
const objectPromise = new Promise((resolve, reject) => {
// 删掉整个数据库
const request = this.myIndexedDB.deleteDatabase(this._info.dbName)
request.onsuccess = (event) => { // 没有触发
console.log('删掉整个数据库成功!', event)
resolve(event)
}
request.onblocked = (event) => { // 这个会被触发
console.log('删除数据库的 blocked:', event)
// Close connections here
resolve(event)
}
request.onerror = (event) => {
console.log('删除数据库的 error:', event)
}
})
return objectPromise
}

/**
* 清空一个对象仓库的全部对象
* @param {string} storeName 对象仓库名称
* @param {IDBTransaction} tran 事务,可以为 null
* @returns
*/
clearStore (storeName, tran = null) {
return _clearStore(this, storeName, tran)
}

/**
* 添加一个对象
* @param {string} storeName 对象仓库名称
* @param {object} model 要添加的对象
* @param {IDBTransaction} tran 事务,可以为 null
* @returns
*/
addModel (storeName, model, tran = null) {
return _addModel(this, storeName, model, tran)
}

/**
* 修改一个对象
* @param {string} storeName 对象仓库名称
* @param {object} model 要修改的对象
* @param {number} id 对象主键ID
* @param {IDBTransaction} tran 事务,可以为 null
* @returns
*/
putModel (storeName, model, id = null, tran = null) {
return _putModel(this, storeName, model, id, tran)
}

/**
* 添加或者修改一个对象
* @param {string} storeName 对象仓库名称
* @param {object} model 要添加或者修改的对象
* @param {number} id 对象主键ID,判断有无的依据
* @param {IDBTransaction} tran 事务,可以为 null
* @returns
*/
setModel (storeName, model, id = null, tran = null) {
return _setModel(this, storeName, model, id, tran)
}

/**
* 删除一个对象
* @param {string} storeName 对象仓库名称
* @param {object} id id 或者 model 要删除的对象
* @param {IDBTransaction} tran 事务,可以为 null
* @returns
*/
delModel (storeName, id, tran = null) {
return _delModel(this, storeName, id, tran)
}

/**
* 获取一个对象,或者仓库的全部对象
* @param {string} storeName 对象仓库名称
* @param {number} id null:获取仓库的全部对象;其他:对象ID值
* @param {IDBTransaction} tran 事务,可以为 null
* @returns
*/
getModel (storeName, id = null, tran = null) {
return _getModel(this, storeName, id, tran)
}

/**
* 获取对象仓库里全部对象的数量
* @param {string} storeName 对象仓库名称
* @param {IDBTransaction} tran 事务,可以为 null
* @returns
*/
getCount (storeName, tran = null) {
return _getCount(this, storeName, tran )
}

/**
* 获取一个仓库的全部对象
* @param {string} storeName 对象仓库名称
* @param {object} query 查询条件
* @param {IDBTransaction} tran 事务,可以为 null
* @returns
*/
getList (storeName, query = {}, tran = null) {
return _listAll(this, storeName, query, tran)
}

/**
* 获取一个仓库的全部对象
* @param {string} storeName 对象仓库名称
* @param {object} query 查询条件
* @param {IDBTransaction} tran 事务,可以为 null
* @returns
*/
listPager (storeName, query = {}, tran = null) {
return _listPager(this, storeName, query, tran)
}
}

+ 149
- 0
src/packages/nf-ws-indexeddb/install.js View File

@@ -0,0 +1,149 @@
import { reactive } from 'vue'
// 引入 indexedDB 的help
import IndexedDB from './help.js'

/**
* 对 indexedDB 的 help 进行初始化
*/
export default {
_indexedDBFlag: Symbol('nf-indexedDB-help'),
_help: {}, // 访问数据库的实例
_stores: {}, // 存放对象,实现 foo.addModel(obj)的功能
/**
* 根据参数创建一个数据库的实例,初始化数据库
* * 删表、建表、添加默认数据
* @param {*} info 参数
* @returns
* * dbFlag: '数据库标识,区分多个数据库',
* * dbConfig: { // 连接数据库
* * * dbName: 'vite2-blog',
* * * ver: 1.0
* * },
* * init: () => {}, // 初始化完成后的回调函数
* * stores: {
* * * storeName: { // 对象仓库名
* * * * id: 'id', // 主键名称
* * * * index: {
* * * * * name: ture, // 索引:是否可以重复
* * * * },
* * * * isDeleteOldTable: false, // 是否删除之前的对象仓库
* * * }
* * }
*/
createHelp (info) {
const indexedDBFlag = typeof info.dbFlag === 'undefined' ?
this._indexedDBFlag : info.dbFlag
// 连接数据库,获得实例。
const help = new IndexedDB(info)
const __stores = {}
// 存入静态对象,以便于支持保存多个不同的实例。
this._help[indexedDBFlag] = help // help
this._stores[indexedDBFlag] = __stores // 仓库变对象

help._stores = __stores // 挂到 help 上面

// 把仓库变成对象的形式,避免写字符串的仓库名称
for (const key in info.stores) {
__stores[key] = {
add: (obj, tran = null) => help.addModel(key, obj, tran),
get: (id = null, tran = null) => help.getModel(key, id, tran),
count: (tran = null) => help.getCount(key, tran),
put: (obj, tran = null) => {
let _id = obj
if (typeof obj === 'object') {
_id = obj[info.stores[key].id]
}
return help.putModel(key, obj, _id, tran)
},
set: (obj, tran = null) => {
let _id = obj
if (typeof obj === 'object') {
_id = obj[info.stores[key].id]
}
return help.setModel(key, obj, _id, tran)
},
del: (obj, tran = null) => {
let _id = obj
if (typeof obj === 'object') {
_id = obj[info.stores[key].id]
}
return help.delModel(key, _id, tran)
},
list: (query = {}, tran = null) => help.getList(key, query, tran),
begin: () => help.beginWrite(key),
beginWrite: () => help.beginWrite(key),
beginReadonly: () => help.beginReadonly(key),
// 给model 加上增删改查的函数
createModel: (model) => {
class MyModel {
constructor (_model) {
for (const key in _model) {
this[key] = _model[key]
}
}
/**
* 添加对象
* @param {*} tran 事务,可以为 null
* @returns
*/
add(tran = null) {
return help.addModel(key, this, tran)
}
/**
* 保存对象,无则添加、有则修改
* @param {*} tran 事务,可以为 null
* @returns
*/
save(tran = null) {
const _id = this[info.stores[key].id]
return help.setModel(key, this, _id, tran)
}
/**
* 加载对象,获取对象
* @param {*} tran 事务,可以为 null
*/
load(tran = null) {
return new Promise((resolve, reject) => {
// 套个娃
const _id = this[info.stores[key].id]
help.getModel(key, _id, tran).then((res) => {
Object.assign(this, res)
resolve(res)
})
})
}
/**
* 删除对象
* @param {*} tran 事务,可以为 null
* @returns
*/
del(tran = null) {
const _id = this[info.stores[key].id]
return help.delModel(key, _id, tran)
}
}
const re = new MyModel(model)
return reactive(re)
}
}
}

return help
},

// 获取静态对象里的数据库实例
useDBHelp (_dbFlag) {
const flag = typeof _dbFlag === 'undefined' ?
this._indexedDBFlag : _dbFlag

return this._help[flag]
},
useStores (_dbFlag) {
const flag = typeof _dbFlag === 'undefined' ?
this._indexedDBFlag : _dbFlag
return this._stores[flag]
}
}

+ 101
- 0
src/packages/nf-ws-indexeddb/list-all.js View File

@@ -0,0 +1,101 @@

/**
* 不分页获取数据,可以查询
* @param { dbHelp } help 访问数据库的实例
* @param { Object } storeName 对象仓库
* @param { Object } findInfo 查询条件
* @param { Object } pager 排序字段
* @returns 添加记录的ID
* * findInfo 结构(查询条件):
* * * { colName: [401, 11] } 字段名称,查询方式,查询关键字
* * pager 结构:
* * * orderBy: { id: false } // 排序字段:字段名,false表示倒序。
*/
const getList = (help, storeName, findInfo = {}, pager = {}) => {
const _start = page.start || 0
const _count = page.count || 0
const _end = _start + _count
const _description = pager.description || 'prev' // 默认倒序

// 查询条件,按照主键或者索引查询
let keyRange = null
if (typeof findInfo.indexName !== 'undefined') {
if (typeof findInfo.indexKind !== 'undefined') {
const id = findInfo.indexValue
const dicRange = {
'=': IDBKeyRange.only(id),
'>': IDBKeyRange.lowerBound(id, true),
'>=': IDBKeyRange.lowerBound(id),
'<': IDBKeyRange.upperBound(id, true),
'<=': IDBKeyRange.upperBound(id)
}
const betweenInfo = findInfo.betweenInfo
switch (findInfo.indexKind) {
case '=':
case '>':
case '>=':
case '<':
case '<=':
keyRange = dicRange[findInfo.indexKind]
break
case 'between':
keyRange = IDBKeyRange.bound(betweenInfo.v1, betweenInfo.v2, betweenInfo.v1isClose, betweenInfo.v2isClose)
break
}
}
}
console.log('findObject - keyRange', keyRange)
return new Promise((resolve, reject) => {
const _getList = (__tran) => {
const store = tranRequest.objectStore(storeName)
let cursorRequest
// 打开游标
cursorRequest = store.openCursor(keyRange, _description)

// 使用游标查询对象并且返回
cursorRequest.onsuccess = (event) => {
const cursor = event.target.result
if (cursor) {
if (_end === 0 || (cursorIndex >= _start && cursorIndex < _end)) {
// 判断钩子函数
if (typeof findInfo.where === 'function') {
if (findInfo.where(cursor.value, cursorIndex)) {
dataList.push(cursor.value)
cursorIndex++
}
} else { // 没有设置查询条件
dataList.push(cursor.value)
cursorIndex++
}
}
cursor.continue()
}
// tranRequest.commit()
}

tranRequest.oncomplete = (event) => {
if (config.debug) {
console.log('findObjectByIndex - dataList', dataList)
}
resolve(dataList)
}
tranRequest.onerror = (event) => {
console.log('findObjectByIndex - onerror', event)
reject(event)
}
}
// 判断数据库是否打开
if (tranRequest === null) {
// 自己开一个事务
help.beginReadonly([storeName]).then((tran) => {
_getList(tran)
tran.commit() // 可以快点提交事务,好吧其实也没快。
})
} else {
_getList(tranRequest)
}
})
}

export default getList

+ 60
- 0
src/packages/nf-ws-indexeddb/list-index.js View File

@@ -0,0 +1,60 @@

import _toIndex from './_toIndex.js'

/**
* 用索引查询数据
* @param { IndexedDBHelp } help 访问数据库的实例
* @param { string } storeName 仓库名称(表名)
* @param { Object } query 查询条件
* * query: {
* * * keyName1: [401, xxx], // 第一个是索引,
* * * keyName2: [402, xxx] // 后面的不算索引
* * }
* @param { IDBTransaction } tranRequest 如果使用事务的话,需要传递开启事务时创建的连接对象
* @returns 要获取的对象
*/
const getList = (help, storeName, query = {}, tranRequest = null) => {
return new Promise((resolve, reject) => {
// 定义个函数,便于调用
const _getList = (__tran) => {
const store = __tran.objectStore(storeName)
// 分析查询条件,设置索引和其他条件
const { range, other, find } = _toIndex(store.indexNames, query)

const keys = Object.keys(query)
// 设置索引的查询条件
// 打开对象仓库或者索引 ? 不用索引,直接用对象仓库 : 使用索引
const dbRequest = range === null ? store : store.index(keys[0])
// // 直接开游标 : // 带条件的开游标
const cursor = range === null ? dbRequest.openCursor() : dbRequest.openCursor(range)

const arr = [] // 返回的记录集
let i = 0
cursor.onsuccess = (event) => { // 打开成功
const res = event.target.result
console.log('游标:' + i++, res)
if (res) {
// 判断其他查询条件
if (find(other, res.value)) {
arr.push(res.value)
}
res.continue() // 继续下一个
} else {
// 没有了
resolve(arr) // 返回对象
}
}
}
// 判断数据库是否打开
if (tranRequest === null) {
// 自己开一个事务
help.beginReadonly([storeName]).then((tran) => {
_getList(tran)
// tran.commit() // 可以快点提交事务,好吧其实也没快。
})
} else {
_getList(tranRequest)
}
})
}
export default getList

+ 120
- 0
src/packages/nf-ws-indexeddb/list-pager.js View File

@@ -0,0 +1,120 @@
/**
* 获取分页列表数据
* @param { IndexedDBHelp } help 访问数据库的实例
* @param { string } storeName 仓库名称(表名)
* @param { Object } model 对象(数据记录)
* @param { IDBTransaction } tranRequest 如果使用事务的话,需要传递开启事务时创建的连接对象
* @returns 添加记录的ID
* * meta 结构:
* * * storeName: '', 对象仓库名
* * info 结构:
* * * find: {
* * * * indexName: 'groupId',
* * * * indexKind: '=', // '>','>=','<','<=','between',
* * * },
* * * pager: {
* * * * start:开始,
* * * * count:数量,
* * * * description:'next'
* * * * indexValue: 1,
* * * * betweenInfo: {
* * * * * v1:1,
* * * * * v2:2,
* * * * * v1isClose:true,
* * * * * v2isClose:true,
* * * * },
* * * * where:(object) => {
* * * * * reutrn true/false
* * * * }
* * * }
*/
export default function pager (help, storeName, info, tranRequest = null) {
const _start = info.pager.start || 0
const _count = info.pager.count || 0
const _end = _start + _count
const _description = info.pager.description || 'prev' // 默认倒序

// 查询条件,按照主键或者索引查询
let keyRange = null
if (typeof info.find.indexName !== 'undefined') {
if (typeof info.find.indexKind !== 'undefined') {
const id = info.find.indexValue
const dicRange = {
'=': IDBKeyRange.only(id),
'>': IDBKeyRange.lowerBound(id, true),
'>=': IDBKeyRange.lowerBound(id),
'<': IDBKeyRange.upperBound(id, true),
'<=': IDBKeyRange.upperBound(id)
}
const betweenInfo = info.find.betweenInfo || '=='
switch (findInfo.indexKind) {
case '=':
case '>':
case '>=':
case '<':
case '<=':
keyRange = dicRange[findInfo.indexKind]
break
case 'between':
keyRange = IDBKeyRange.bound(betweenInfo.v1, betweenInfo.v2, betweenInfo.v1isClose, betweenInfo.v2isClose)
break
}
}
}
console.log('pager - keyRange', keyRange)

// 定义一个 Promise 的实例
return new Promise((resolve, reject) => {
const dataList = []
// 定义个函数,便于调用
const _pager = (__tran) => {
let cursorIndex = 0
const store = __tran.objectStore(storeName)
let cursorRequest
// 判断是否索引查询
if (typeof findInfo.indexName === 'undefined') {
cursorRequest = store.openCursor(keyRange, _description)
} else {
cursorRequest = store
.index(info.find.indexName)
.openCursor(keyRange, _description)
}

cursorRequest.onsuccess = (event) => {
const cursor = event.target.result
if (cursor) {
if (_end === 0 || (cursorIndex >= _start && cursorIndex < _end)) {
// 判断钩子函数
if (typeof findInfo.where === 'function') {
if (findInfo.where(cursor.value, cursorIndex)) {
dataList.push(cursor.value)
cursorIndex++
}
} else { // 没有设置查询条件
dataList.push(cursor.value)
cursorIndex++
}
}
cursor.continue()
}
// __tran.commit()
}

__tran.oncomplete = (event) => {
if (config.debug) {
console.log('oncomplete - pager - dataList', dataList)
}
resolve(dataList)
}
}
if (tranRequest === null) {
help.beginReadonly([storeName]).then((tran) => {
// 自己开一个事务
_pager(tran)
})
} else {
// 使用传递过来的事务
_pager(tranRequest)
}
})
}

+ 36
- 0
src/packages/nf-ws-indexeddb/model-add.js View File

@@ -0,0 +1,36 @@
import _vueToObject from './_toObject.js'

/**
* 添加对象
* @param { IndexedDBHelp } help 访问数据库的实例
* @param { string } storeName 仓库名称(表名)
* @param { Object } model 对象(数据记录)
* @param { IDBTransaction } tranRequest 如果使用事务的话,需要传递开启事务时创建的连接对象
* @returns 新对象的ID
*/
export default function addModel (help, storeName, model, tranRequest = null) {
console.log('添加对象的 this', this)
// 取对象的原型,便于保存 reactive
const _model = _vueToObject(model)
// 定义一个 Promise 的实例
return new Promise((resolve, reject) => {
// 定义个函数,便于调用
const _add = (__tran) => {
__tran
.objectStore(storeName) // 获取store
.add(_model) // 添加对象
.onsuccess = (event) => { // 成功后的回调
resolve(event.target.result) // 返回对象的ID
}
}
if (tranRequest === null) {
help.beginWrite([storeName]).then((tran) => {
// 自己开一个事务
_add(tran)
})
} else {
// 使用传递过来的事务
_add(tranRequest)
}
})
}

+ 35
- 0
src/packages/nf-ws-indexeddb/model-count.js View File

@@ -0,0 +1,35 @@

/**
* 获取对象
* @param { IndexedDBHelp } help 访问数据库的实例
* @param { string } storeName 仓库名称(表名)
* @param { IDBTransaction } tran 如果使用事务的话,需要传递开启事务时创建的连接对象
* @returns 要获取的对象
*/
export default function getCount (help, storeName, tran = null) {
return new Promise((resolve, reject) => {
// 定义个函数,便于调用
const _getCount = (__tran) => {
const store = __tran.objectStore(storeName)
// console.log('对象仓库--', store)
// 判断是获取一个,还是获取全部
const dbRequest = store.count()
// console.log('dbRequest--', dbRequest)

dbRequest.onsuccess = (event) => { // 成功后的回调
// console.log('-- 得到数据 --:', window.performance.now())
resolve(event.target.result) // 返回对象
}
}
// 判断数据库是否打开
if (tran === null) {
// 自己开一个事务
help.beginReadonly([storeName]).then((tran) => {
_getCount(tran)
tran.commit() // 可以快点提交事务,好吧其实也没快。
})
} else {
_getCount(tran)
}
})
}

+ 33
- 0
src/packages/nf-ws-indexeddb/model-delete.js View File

@@ -0,0 +1,33 @@
/**
* 删除对象
* @param { IndexedDBHelp } help 访问数据库的实例
* @param { string } storeName 仓库名称(表名)
* @param { string } id 对象的ID
* @param { IDBTransaction } tranRequest 如果使用事务的话,需要传递开启事务时创建的连接对象
* @returns 添加记录的ID
* * meta 结构:
* * * tableName: '', 表名
* * * idKey: 'id', 主键字段名称
*/
export default function deleteData (help, storeName, id, tranRequest = null) {
// 定义一个 Promise 的实例
return new Promise((resolve, reject) => {
// 定义个函数,便于调用
const _delete = (__tran) => {
__tran
.objectStore(storeName) // 获取store
.delete(id) // 删除一个对象
.onsuccess = (event) => { // 成功后的回调
resolve(event.target.result)
}
}
// 判断是否有事务
if (tranRequest === null) {
help.beginWrite([storeName]).then((tran) => {
_delete(tran)
})
} else {
_delete(tranRequest)
}
})
}

+ 36
- 0
src/packages/nf-ws-indexeddb/model-get.js View File

@@ -0,0 +1,36 @@

/**
* 获取对象
* @param { IndexedDBHelp } help 访问数据库的实例
* @param { string } storeName 仓库名称(表名)
* @param { Object } id 对象(提供id)
* @param { IDBTransaction } tranRequest 如果使用事务的话,需要传递开启事务时创建的连接对象
* @returns 要获取的对象
*/
export default function getModel (help, storeName, id = null, tranRequest = null) {
return new Promise((resolve, reject) => {
// 定义个函数,便于调用
const _getModel = (__tran) => {
const store = __tran.objectStore(storeName)
// console.log('对象仓库--', store)
// 判断是获取一个,还是获取全部
const dbRequest = id === null ? store.getAll() : store.get(id)
// console.log('dbRequest--', dbRequest)

dbRequest.onsuccess = (event) => { // 成功后的回调
// console.log('-- 得到数据 --:', window.performance.now())
resolve(event.target.result) // 返回对象
}
}
// 判断数据库是否打开
if (tranRequest === null) {
// 自己开一个事务
help.beginReadonly([storeName]).then((tran) => {
_getModel(tran)
tran.commit() // 可以快点提交事务,好吧其实也没快。
})
} else {
_getModel(tranRequest)
}
})
}

+ 43
- 0
src/packages/nf-ws-indexeddb/model-put.js View File

@@ -0,0 +1,43 @@
import _vueToObject from './_toObject.js'

/**
* 修改对象,先依据ID获取对象,然后把model的属性叠加上去,最后put新对象
* @param { IndexedDBHelp } help 访问数据库的实例
* @param { string } storeName 仓库名称(表名)
* @param { Object } model 对象(数据记录)
* @param { string } id 对象的ID
* @param { IDBTransaction } tranRequest 如果使用事务的话,需要传递开启事务时创建的连接对象
* @returns 添加记录的ID
*/
export default function updateData (help, storeName, model, id, tranRequest = null) {
const _model = _vueToObject(model)
// 定义一个 Promise 的实例
return new Promise((resolve, reject) => {
// 定义个函数,便于调用
const _update = (__tran) => {
// 先获取对象,然后修改对象,最后存回去
const store = __tran.objectStore(storeName) // 获取store
store.get(id) // 获取对象
.onsuccess = (event) => { // 成功后的回调
// 从仓库里提取对象,把修改值合并到对象里面。
const newObject = {}
Object.assign(newObject, event.target.result, _model)
// 修改数据
store.put(newObject) // 修改对象
.onsuccess = (event) => { // 成功后的回调
resolve(event.target.result)
}
}
}
// 判断是否自带事务
if (tranRequest === null) {
help.beginWrite([storeName]).then((tran) => {
// 自己开一个事务
_update(tran)
})
} else {
// 使用传递过来的事务
_update(tranRequest)
}
})
}

+ 53
- 0
src/packages/nf-ws-indexeddb/model-set.js View File

@@ -0,0 +1,53 @@
import _vueToObject from './_toObject.js'

/**
* 添加或者修改对象,先依据ID判断是否有对象,无则添,有则改
* @param { IndexedDBHelp } help 访问数据库的实例
* @param { string } storeName 仓库名称(表名)
* @param { Object } model 对象(数据记录)
* @param { string } id 对象的ID
* @param { IDBTransaction } tranRequest 如果使用事务的话,需要传递开启事务时创建的连接对象
* @returns 添加记录的ID
*/
export default function setData (help, storeName, model, id, tranRequest = null) {
const _model = _vueToObject(model)
// 定义一个 Promise 的实例
return new Promise((resolve, reject) => {
// 定义个函数,便于调用
const _set = (__tran) => {
// 先获取对象,然后修改对象,最后存回去
const store = __tran.objectStore(storeName) // 获取store
store.get(id) // 获取对象
.onsuccess = (event) => { // 成功后的回调
// 从仓库里提取对象,把修改值合并到对象里面。
const res = event.target.result
if (typeof res === 'undefined') {
// 没有对象添加
store.add(_model) // 添加对象
.onsuccess = (event) => { // 成功后的回调
resolve(event.target.result) // 返回对象的ID
}
} else {
// 修改
const newObject = {}
Object.assign(newObject, event.target.result, _model)
// 修改数据
store.put(newObject) // 修改对象
.onsuccess = (event) => { // 成功后的回调
resolve(event.target.result)
}
}
}
}
// 判断是否自带事务
if (tranRequest === null) {
help.beginWrite([storeName]).then((tran) => {
// 自己开一个事务
_set(tran)
})
} else {
// 使用传递过来的事务
_set(tranRequest)
}
})
}

+ 30
- 0
src/packages/nf-ws-indexeddb/store-clear.js View File

@@ -0,0 +1,30 @@
/**
* 清空仓库 store 里的对象
* @param { IndexedDBHelp } help 访问数据库的实例
* @param { string } storeName 仓库名称(表名)
* @param { IDBTransaction } tranRequest 如果使用事务的话,需要传递开启事务时创建的连接对象
* @returns
*/
export default function deleteStore (help, storeName, tranRequest = null) {
// 定义一个 Promise 的实例
return new Promise((resolve, reject) => {
// 定义个函数,便于调用
const _clearStore = (__tran) => {
__tran
.objectStore(storeName) // 获取store
.clear() // 删除store
.onsuccess = (event) => { // 成功后的回调
resolve(event) // 返回对象的ID
}
}
if (tranRequest === null) {
help.beginWrite([storeName]).then((tran) => {
// 自己开一个事务
_clearStore(tran)
})
} else {
// 使用传递过来的事务
_clearStore(tranRequest)
}
})
}

+ 34
- 0
src/packages/nf-ws-websql/_pager-info.js View File

@@ -0,0 +1,34 @@
/**
* 内部函数,根据分页信息,设置 分页信息和排序字段
* @param { object } pager 分页和排序
* @returns order by 和 limit
*/
const _getPager = (pager) => {
const re = {
orderBy: '', // 分页,可以不设置
limit: '' // 排序,可以不设置
}
// 设置分页 order by 和 limit
if (typeof pager !== 'undefined') {
if (typeof pager.pagerIndex !== 'undefined') {
// 用 limit 实现分页
const _pageSize = pager.pagerSize || 10
const index = _pageSize * (pager.pagerIndex - 1)
re.limit = ` limit ${index}, ${_pageSize} `
}
if (typeof pager.orderBy === 'object') {
// 设置排序字段和方式
const arr = []
for (const key in pager.orderBy) {
const col = key
const isAsc = pager.orderBy[key] ? ' asc ' : ' desc '
arr.push(col + ' ' + isAsc)
}
re.orderBy = ` order by ${arr.join(',')}`
}
}

return re
}

export default _getPager

+ 82
- 0
src/packages/nf-ws-websql/_where-query.js View File

@@ -0,0 +1,82 @@
/**
* 内部函数,根据查询条件,拼接查询用的SQL语句,where 后面的部分。
* @param {object} query 查询条件
* @returns where 后面的查询语句
*/
const _getWhereQuery = (query) => {
// 查询条件
const findKind = {
// 字符串
401: ' {col} = ? ',
402: ' {col} <> ? ',
403: ' {col} like ? ',
404: ' {col} not like ? ',
405: ' {col} like ? ', // 起始于
406: ' {col} like ? ', // 结束于
// 数字
411: ' {col} = ? ',
412: ' {col} <> ? ',
413: ' {col} > ? ',
414: ' {col} >= ? ',
415: ' {col} < ? ',
416: ' {col} <= ? ',
417: ' {col} between ? and ? ',
// 日期
421: ' {col} = ? ',
422: ' {col} <> ? ',
423: ' {col} > ? ',
424: ' {col} >= ? ',
425: ' {col} < ? ',
426: ' {col} <= ? ',
427: ' {col} between ? and ? ',
// 范围
441: ' {col} in (?)'
}
const _whereCol = [] // 查询字段
const _whereValue = [] // 查询参数
// 设置查询条件
for (const key in query) {
const val = query[key]
if (val[1] === '' || val[1] === null) continue
_whereCol.push(findKind[val[0]].replace('{col}', key))
switch (val[0]) {
case 403: // like
case 404: // not like
_whereValue.push('%' + val[1] + '%')
break
case 405: // like a%
_whereValue.push(val[1] + '%')
break
case 406: // like %a
_whereValue.push('%' + val[1])
break
case 417: // between 数字
case 427: // between 日期
_whereValue.push(...val[1])
break
case 441: // in
_whereCol[_whereCol.length - 1] =
_whereCol[_whereCol.length - 1]
.replace('?', val[1].map(a => '?').join(','))
_whereValue.push(...val[1])
break
default:
_whereValue.push(val[1])
break
}
}

const re = {
whereQuery: '',
whereValue: []
}
// 如果没有查询添加,设置 1=1 占位
if (_whereCol.length > 0) {
re.whereQuery = ` WHERE ${_whereCol.join(' and ')}`,
re.whereValue = _whereValue
}
return re

}

export default _getWhereQuery

+ 53
- 0
src/packages/nf-ws-websql/data-add.js View File

@@ -0,0 +1,53 @@

/**
* 实现添加数据的功能。拼接 insert 的 SQL语句
* @param { MySQLHelp } help 访问数据库的实例
* @param { Object } meta 表、字段
* @param { Object } model 数据
* @param { connection } cn 如果使用事务的话,需要传递开启事务时创建的连接对象
* @returns 添加记录的ID
* * meta 结构:
* * * tableName: '', 表名
* * * cols: { colName: '', ...}
* * model 结构:
* * * colName: value
*/
export default function addData (help, meta, model, cn = null) {
// 拼接添加用的SQL语句,
// 提交SQL语句
// console.log('addData,开始运行 :')
const myPromise = new Promise((resolve, reject) => {
// 记录字段名称
const colNames = []
// 记录字段对应的值
const colValues = []
// 记录字段对应的占位符合
const cols = []
// 变量对象,记录 key和 value
const colKeys = meta.cols || model
for (const key in colKeys) {
if (key.toLocaleLowerCase() === 'id') continue
colNames.push(key)
// 判断类型
if (typeof model[key] === 'object') {
colValues.push(JSON.stringify(model[key]))
} else {
colValues.push(model[key])
}
cols.push('?')
}

const sql = `INSERT INTO ${meta.tableName} ( ${colNames.join(',')} ) VALUES ( ${cols.join(',')} )`

// console.log('insertSQL:', sql)
help.query(sql, colValues, cn)
.then((res) => {
// 成功了,返回给调用者
resolve(res.insertId)
})
.catch((err) => {
reject(err)
})
})
return myPromise
}

+ 31
- 0
src/packages/nf-ws-websql/data-delete.js View File

@@ -0,0 +1,31 @@

/**
* 实现删除数据的功能。物理删除,delete from
* @param { MySQLHelp } help 访问数据库的实例
* @param { Object } meta 表、字段
* @param { number|string } id 主键字段值
* @param { connection } cn 如果使用事务的话,需要传递开启事务时创建的连接对象
* @returns 添加记录的ID
* * meta 结构:
* * * tableName: '', 表名
* * * idKey: 'id', 主键字段名称
*/
export default function deleteData (help, meta, id, cn = null) {
// 拼接添加用的SQL语句,
// 提交SQL语句
// console.log('deleteData,开始运行 :')
const myPromise = new Promise((resolve, reject) => {
const sql = `DELETE FROM ${meta.tableName} WHERE ${meta.idKey}=?`
console.log('sql-----delete:', sql, id)

help.query(sql, [id], cn)
.then((res) => {
// 成功了,返回给调用者
resolve(res.rowsAffected)
})
.catch((err) => {
reject(err)
})
})
return myPromise
}

+ 32
- 0
src/packages/nf-ws-websql/data-deleteflag.js View File

@@ -0,0 +1,32 @@

/**
* 实现删除数据的功能。逻辑删除,update set flag = 1
* @param { MySQLHelp } help 访问数据库的实例
* @param { Object } meta 表、字段
* @param { number|string } id 主键字段值
* @param { connection } cn 如果使用事务的话,需要传递开启事务时创建的连接对象
* @returns 添加记录的ID
* * meta 结构:
* * * tableName: '', 表名
* * * idKey: 'id', 主键字段名称
* * * delFlag: 'isDel', 逻辑删除,标记字段名称
*/
export default function deleteData (help, meta, id, cn = null) {
// 拼接添加用的SQL语句,
// 提交SQL语句
// console.log('deleteData,开始运行 :')
const myPromise = new Promise((resolve, reject) => {
const sql = `UPDATE ${meta.tableName} SET ${meta.delFlag} = 1 WHERE ${meta.idKey}=?`
// console.log('sql:', sql)

help.query(sql, [id], cn)
.then((res) => {
// 成功了,返回给调用者
resolve(res.rowsAffected)
})
.catch((err) => {
reject(err)
})
})
return myPromise
}

+ 31
- 0
src/packages/nf-ws-websql/data-get.js View File

@@ -0,0 +1,31 @@

/**
* 依据主键字段,获取记录
* @param { MySQLHelp } help 访问数据库的实例
* @param { Object } meta 表、字段
* @param { number|string } id 主键字段值
* @param { connection } cn 如果使用事务的话,需要传递开启事务时创建的连接对象
* @returns 添加记录的ID
* * meta 结构:
* * * tableName: '', 表名
* * * idKey: 'id', 主键字段名称
*/
export default function getData (help, meta, id, cn = null) {
// 拼接添加用的SQL语句,
// 提交SQL语句
// console.log('getData,开始运行 :')
const myPromise = new Promise((resolve, reject) => {
const sql = `SELECT * FROM ${meta.tableName} WHERE ${meta.idKey || 'id'}=?`
// console.log('SELECT -- sql:', sql, id)

help.query(sql, [id], cn)
.then((res) => {
// 成功了,返回给调用者
resolve(res.rows)
})
.catch((err) => {
reject(err)
})
})
return myPromise
}

+ 54
- 0
src/packages/nf-ws-websql/data-set.js View File

@@ -0,0 +1,54 @@
import add from './data-add'
import update from './data-update'

/**
* 实现添加/修改数据的功能。没有ID:添加,有ID:修改
* @param { MySQLHelp } help 访问数据库的实例
* @param { Object } meta 表、字段
* @param { Object } model 数据
* @param { number|string } id 主键字段值
* @param { connection } cn 如果使用事务的话,需要传递开启事务时创建的连接对象
* @returns 影响的行数
* * meta 结构:
* * * tableName: '', 表名
* * * idKey: 'id', 主键字段名称
* * model 结构:
* * * colName: value
*/
export default function updateData (help, meta, model, id, cn = null) {
// 拼接修改用的SQL语句,
// console.log('updateData,开始运行 :')
const myPromise = new Promise((resolve, reject) => {
// 记录字段名称
const colNames = []
// 记录字段对应的值
const colValues = []
// 变量对象,记录 key和 value
const colKeys = meta.cols || model
for (const key in colKeys) {
colNames.push(key + '=? ')
if (typeof model[key] === 'object') {
colValues.push(JSON.stringify(model[key], null, 2))
} else {
colValues.push(model[key])
}
}
// 加入查询条件
colValues.push(id)

const sql = `SELECT 1 FROM ${meta.tableName} WHERE ${meta.idKey || 'id'}=?`
// console.log('updateSQL:', sql)

help.query(sql, colValues, cn).then((res) => {
add(help, meta, model, id, cn).then((res1) => {
// 成功了,返回给调用者
resolve(res.rowsAffected)
})
}).catch((err) => {
reject(err)
})
})
return myPromise
}

+ 50
- 0
src/packages/nf-ws-websql/data-update.js View File

@@ -0,0 +1,50 @@

/**
* 实现修改数据的功能。拼接 update 的 SQL语句
* @param { MySQLHelp } help 访问数据库的实例
* @param { Object } meta 表、字段
* @param { Object } model 数据
* @param { number|string } id 主键字段值
* @param { connection } cn 如果使用事务的话,需要传递开启事务时创建的连接对象
* @returns 影响的行数
* * meta 结构:
* * * tableName: '', 表名
* * * idKey: 'id', 主键字段名称
* * model 结构:
* * * colName: value
*/
export default function updateData (help, meta, model, id, cn = null) {
// 拼接修改用的SQL语句,
// console.log('updateData,开始运行 :')
const myPromise = new Promise((resolve, reject) => {
// 记录字段名称
const colNames = []
// 记录字段对应的值
const colValues = []
// 变量对象,记录 key和 value
const colKeys = meta.cols || model
for (const key in colKeys) {
colNames.push(key + '=? ')
if (typeof model[key] === 'object') {
colValues.push(JSON.stringify(model[key], null, 2))
} else {
colValues.push(model[key])
}
}
// 加入查询条件
colValues.push(id)

const sql = `UPDATE ${meta.tableName} SET ${colNames.join(',')} WHERE ${meta.idKey}=?`
// console.log('updateSQL:', sql)

help.query(sql, colValues, cn)
.then((res) => {
// 成功了,返回给调用者
resolve(res.rowsAffected)
})
.catch((err) => {
reject(err)
})
})
return myPromise
}

+ 28
- 0
src/packages/nf-ws-websql/db-delete.js View File

@@ -0,0 +1,28 @@

/**
* 删除数据库
* @param { MySQLHelp } help 访问数据库的实例
* @param { string } dbName 数据库名称
* @param { connection } cn 如果使用事务的话,需要传递开启事务时创建的连接对象
* @returns 添加记录的ID
* * meta 结构:
* * * tableName: '', 表名
* * * idKey: 'id', 主键字段名称
* * * delFlag: 'isDel', 逻辑删除,标记字段名称
*/
export default function deleteTable (help, dbName, cn = null) {
const myPromise = new Promise((resolve, reject) => {
const sql = `DROP database ${dbName} `
// console.log('sql:', sql)
help.query(sql, [], cn)
.then((res) => {
// 成功了,返回给调用者
resolve(res)
})
.catch((err) => {
console.log('deleteDataBase-sql:', sql, err)
reject(err)
})
})
return myPromise
}

+ 203
- 0
src/packages/nf-ws-websql/help.js View File

@@ -0,0 +1,203 @@

import _addModel from './data-add.js' // 添加一个对象
import _updateModel from './data-update.js' // 修改一个对象
import _getModel from './data-get.js' // 获取一个对象
import _deleteModel from './data-delete.js' // 删除一个对象

import _listAll from './list-all.js' // 获取仓库里全部对象
import _listCount from './list-count.js' // 统计对象数量
import _listPager from './list-pager.js' // 分页获取对象

/**
* 基于 promise 封装 webSQL 的基本操作
* * 创建数据库连接
* * 提交SQL给数据库执行,得到返回结果
* * 共用函数
* * info 结构:
* * * dbName: 'test', // 数据库名称
* * * ver: '1', // 版本,很重要
* * * size: '2', // 大小,自动 * 1024 * 1024
* * * description: '数据库描述'
*/
export default class MySQLHelp {
constructor (info) {
if (!window.openDatabase) {
console.log('您的浏览器不支持 webSQL')
return
}
// 数据库连接信息
this._info = {
dbName: info.dbName,
ver: info.ver,
size: info.size,
description: info.infodescription
}
// 打开数据库
this.db = window.openDatabase(
this._info.dbName,
this._info.ver,
this._info.description,
this._info.size * 1024 * 1024)
// console.log('\n db', this.db.version)
}

/**
* 运行 SQL 语句,带参数,返回执行结果
* @param { string } sql SQL语句
* @param { array } param 参数
* @param { object } tran 参数
* @returns promise
*/
query (sql, param = [], tran = null) {
const promise1 = new Promise((resolve, reject) => {
const _query = (tran) => {
tran.executeSql(sql, param,
(tx, results) => { resolve(results) },
(tx, err) => {
console.log('query - sql:', sql, param, tx, err)
reject(err)
return true // 回滚
}
)
}
if (tran === null) {
this.begin().then((_tran) => {
_query(_tran)
})
} else {
_query(tran)
}
})
return promise1
}

/**
* 开启一个事务,Promise 的方式
* @returns Promise 形式
*/
begin () {
const myPromise = new Promise((resolve, reject) => {
// 开启一个事务。
// console.log('★ 开启事务,promise 模式')
this.db.transaction(
(tran) => { resolve(tran) },
(tx, err) => { reject(err) }
)
})
return myPromise
}

/**
* 提交一个事务
* @param { connection } tran 开启事务时创建的连接对象
* @returns 提交事务
*/
commit (tran) {
const myPromise = new Promise((resolve, reject) => {
// 提交事务
tran.commit((err) => {
if (err) {
console.log('事务提交失败', err)
reject(err)
} else {
resolve()
}
})
})
return myPromise
}

/**
* 关闭数据库
* @param { connection } tran 开启事务时创建的连接对象
*/
close (tran = null) {
if (tran !== null) {
// 归还连接对象。console.log('--close: tran', tran.threadId)
tran.release()
// console.log('\n[MySQL 事务,已经关闭数据库:] \n')
} else {
// 关闭连接
this.db.end((err) => {
if (err) {
console.error('关闭连接发生错误:', err)
} else {
// console.log('\n[MySQL 已经关闭数据库:]\n')
}
})
}
}

/**
* 添加一条记录
* @param {string} meta 表名
* @param {object} model 要添加的记录
* @param {*} tran 事务,可以为null
* @returns
*/
addModel (meta, model, tran = null) {
return _addModel(this, meta, model, tran)
}

/**
* 修改一条记录
* @param {string} meta 表名
* @param {object} model 要添加的记录
* @param {*} tran 事务,可以为null
* @returns
*/
updateModel (meta, model, tran = null) {
return _updateModel(this, meta, model, tran)
}

/**
* 删除一条记录
* @param {string} tableName 表名
* @param {object} model 要添加的记录
* @param {*} tran 事务,可以为null
* @returns
*/
delModel (meta, model, tran = null) {
return _deleteModel(this, meta, model, tran)
}

/**
* 获取一条记录
* @param {string} tableName 表名
* @param {object} model 要添加的记录
* @param {*} tran 事务,可以为null
* @returns
*/
getModel (meta, model, tran = null) {
return _getModel(this, meta, model, tran)
}

/**
* 获取全部记录,可以查询
* @param {string} tableName 表名
* @param {object} model 要添加的记录
* @param {*} tran 事务,可以为null
* @returns
*/
listAll (meta, query, pager = {}, tran = null) {
return _listAll(this, meta, query, pager, tran)
}

/**
* 分页获取记录,可以查询
* @param {string} tableName 表名
* @param {object} model 要添加的记录
* @param {*} tran 事务,可以为null
* @returns
*/
async listPager (meta, query, pager, _count = 0, tran = null) {
const count = _count === 0 ? await _listCount(this, meta, query, tran) : _count
const list = await _listPager(this, meta, query, pager, tran)
return {
count,
list
}
}
}

MySQLHelp.prototype.add = _addModel

+ 152
- 0
src/packages/nf-ws-websql/install.js View File

@@ -0,0 +1,152 @@

import webSQL from './help.js'
// 维护
import createTable from './table-create.js'
import deleteTable from './table-delete.js'

export default {
_webSQLFlag: Symbol('nf-webSQL-help'),
_help: {}, // 访问数据库的实例
_tables: {}, // 把表变成对象

/**
* 根据参数创建一个数据库的实例,初始化数据库
* * 删表、建表、添加默认数据
* @param {*} info 参数
* @returns 安装一个Vue的插件
* * dbFlag: '数据库标识',
* * dbConfig: { // 连接数据库
* * * dbName: 'vite2-blog',
* * * ver: 1.0,
* * * remarks: '测试用的博客数据库',
* * * size: 2
* * },
* * init: () => {},
* * tables: {
* * * tableName: ['字段名称', '字段名称']
* * },
* * isDeleteOldTable: false, // 是否删除之前的表
*/
createHelp (info) {
let webSQLFlag = this._webSQLFlag
if (typeof info.dbFlag === 'string') {
webSQLFlag = Symbol.for(info.dbFlag)
} else if (typeof info.dbFlag === 'symbol') {
webSQLFlag = info.dbFlag
}
const init = info.init
// const tables = this._tables
// 连接数据库
// eslint-disable-next-line new-cap
const help = new webSQL(info.dbConfig)

// 遍历配置,设置表的操作。
// 按照表(对象)的配置信息,设置操作实例
help.begin().then((cn) => {
for (const key in info.tables) {
const tableName = key
const cols = Object.keys(info.tables[key])
// 判断要不要删除表
if (info.isDeleteOldTable) {
// 删除表
deleteTable(help, tableName, cn)
}
// 建立表
createTable(help, tableName, cols, cn)
}
})

this._help[webSQLFlag] = help
const newTable = {}
help._tables = newTable
this._tables[webSQLFlag] = newTable
// 把表变成对象
for (const key in info.tables) {
const meta = {
tableName: key,
cols: info.tables[key]
}
newTable[meta.tableName] = {
add: (model, cn = null) => help.addModel(meta, model, cn),
get: (id = null, cn = null) => help.getModel(meta, id, cn),
put: (model, cn = null) => {
let _id = model
if (typeof model === 'object') {
_id = model[info.stores[key].id]
}
return help.updateModel(meta, model, _id, cn)
},
del: (model, cn = null) => {
let _id = model
if (typeof model === 'object') {
_id = model[info.stores[key].id]
}
return help.delModel(meta, _id, cn)
},
list: (query = {}, isDesc = false, cn = null) => {
const pager = {
orderBy: {}
}
pager.orderBy[Object.keys(meta.cols)[0]] = isDesc
return help.listAll(meta, query, pager, cn)
},
pager: (query = {}, _pager = null, _count = 0, cn = null) => {
const pager = {
pagerIndex: 1,
pagerSize: 5,
pagerTotal: 100,
orderBy: {}
}
pager.orderBy[Object.keys(meta.cols)[0]] = false

if (_pager !== null){
Object.assign(pager, _pager)
}
return help.listPager(meta, query, pager, _count, cn)
},
begin: () => help.begin()
}

}

if (typeof init === 'function') {
init(help, newTable)
}

return {
// 安装插件,不用 provide 注入了
install (app, options) {
// 注入状态,用 symbol 作为标记,避免重名
// app.provide(webSQLFlag, { help, tables })
// 调用初始化,给全局状态赋值
}
}
},

// 获取数据库的连接实例
useSQLHelp (_dbFlag) {
let flag = this._webSQLFlag
if (typeof _dbFlag === 'string') {
flag = Symbol.for(_dbFlag)
} else if (typeof _dbFlag === 'symbol') {
flag = _dbFlag
}
return this._help[flag]
},

/**
* 把表变成对象,可以直接用表.add/put/del/get等操作
* @param {*} _dbFlag
* @returns
*/
useTables (_dbFlag) {
let flag = this._webSQLFlag
if (typeof _dbFlag === 'string') {
flag = Symbol.for(_dbFlag)
} else if (typeof _dbFlag === 'symbol') {
flag = _dbFlag
}
return this._tables[flag]
}
}

+ 48
- 0
src/packages/nf-ws-websql/list-all.js View File

@@ -0,0 +1,48 @@
import _getWhereQuery from './_where-query.js'
import _getPager from './_pager-info.js'

/**
* 不分页获取数据,可以查询
* @param { MySQLHelp } help 访问数据库的实例
* @param { Object } meta 表、字段
* @param { Object } query 查询条件
* @param { Object } pager 排序字段
* @returns 添加记录的ID
* * meta 结构:
* * * tableName: '', 表名
* * * cols:{colName: '类型'}, 需要显示的字段
* * query 结构(查询条件):
* * * { colName: [401, 11] } 字段名称,查询方式,查询关键字
* * pager 结构:
* * * orderBy: { id: false } // 排序字段:字段名,false表示倒序。
*/
export default function listAll (help, meta, query, pager, cn = null) {
// console.log('开始获取全部记录 :')
const myPromise = new Promise((resolve, reject) => {
// 查询条件和查询参数
const { whereQuery, whereValue } = _getWhereQuery(query)
// 设置排序
const { orderBy } = _getPager(pager)

// 设置显示的字段
const showCol = Object.keys(meta.cols)
if (showCol.length === 0) { showCol.push('*') }

// 拼接查询语句
const sql = `SELECT ${showCol.join(',')} FROM ${meta.tableName} ${whereQuery} ${orderBy}`
// console.log('select-all-sql:', sql, whereValue)

help.query(sql, whereValue, cn)
.then((res) => {
// 添加成功
// console.log('分页获取记录:', res)
resolve(Array.from(res.rows))
})
.catch((err) => {
// 出错了
console.log('获取全部记录失败了:', err)
reject(err)
})
})
return myPromise
}

+ 31
- 0
src/packages/nf-ws-websql/list-count.js View File

@@ -0,0 +1,31 @@
import _getWhereQuery from './_where-query.js'
import _getPager from './_pager-info.js'

/**
* 分页获取数据,可以查询
* @param { MySQLHelp } help 访问数据库的实例
* @param { Object } meta 表、字段
* @param { Object } query 查询条件
* @returns 添加记录的ID
* * meta 结构:
* * * tableName: '', 表名
* * * cols:{colName: '类型'}, 需要显示的字段
* * query 结构(查询条件):
* * * { colName: [401, '查询关键字'] } 字段名称,查询方式,查询关键字
*/
export default function getCount (help, meta, query) {
return new Promise((resolve, reject) => {
// 查询条件和查询参数
const { whereQuery, whereValue } = _getWhereQuery(query)
// 统计总数
const sql = `SELECT count(1) as count FROM ${meta.tableName} ${whereQuery} `
console.log('count-sql:', sql, whereValue)
help.query(sql, whereValue).then((re) => {
resolve(re.rows[0].count)
}).catch((err) => {
// 出错了
console.log('统计总记录数失败了:', err)
reject(err)
})
})
}

+ 51
- 0
src/packages/nf-ws-websql/list-pager.js View File

@@ -0,0 +1,51 @@
import _getWhereQuery from './_where-query.js'
import _getPager from './_pager-info.js'

/**
* 分页获取数据,可以查询
* @param { MySQLHelp } help 访问数据库的实例
* @param { Object } meta 表、字段
* @param { Object } query 查询条件
* @param { Object } pager 数据
* @returns 添加记录的ID
* * meta 结构:
* * * tableName: '', 表名
* * * cols:{colName: '类型'}, 需要显示的字段
* * query 结构(查询条件):
* * * { colName: [401, 11] } 字段名称,查询方式,查询关键字
* * pager 结构:
* * * pageSize: 20 // 一页显示多少条记录
* * * orderBy: { id: false } // 排序字段:字段名,false表示倒序。
* * * pageTotal: 100 // 符合查询条件的总记录数
* * * pageIndex: 1 // 显示第几页的记录,从 1 开始
*/
export default function listPager (help, meta, query, pager) {
// console.log('开始分页 :')
const myPromise = new Promise((resolve, reject) => {
// 查询条件和查询参数
const { whereQuery, whereValue } = _getWhereQuery(query)
// 设置排序和分页
const { orderBy, limit } = _getPager(pager)

// 设置显示的字段
const showCol = Object.keys(meta.cols)
if (showCol.length === 0) { showCol.push('*') }

// 拼接查询语句
const sql = `SELECT ${showCol.join(',')} FROM ${meta.tableName} ${whereQuery} ${orderBy} ${limit}`
console.log('select-pager-sql:', sql, whereValue)

help.query(sql, whereValue)
.then((res) => {
// 添加成功
// console.log('分页获取记录:', res)
resolve(Array.from(res.rows))
})
.catch((err) => {
// 出错了
console.log('分页获取记录失败了:', err)
reject(err)
})
})
return myPromise
}

+ 40
- 0
src/packages/nf-ws-websql/table-create.js View File

@@ -0,0 +1,40 @@

/**
* 实现删除数据的功能。逻辑删除,update set flag = 1
* @param { MySQLHelp } help 访问数据库的实例
* @param { string } tableName 表名
* @param { array } cols 字段名集合,数组
* @param { connection } cn 如果使用事务的话,需要传递开启事务时创建的连接对象
* @returns 添加记录的ID
* * meta 结构:
* * * tableName: '', 表名
* * * idKey: 'id', 主键字段名称
* * * cols: {name: ''},
*/
export default function createTable (help, tableName, cols, cn = null) {
const myPromise = new Promise((resolve, reject) => {
// 记录字段名称,不设置类型了。
let _cols = []
if (typeof cols.length === 'number') {
_cols = cols
} else {
_cols = Object.keys(cols)
}
_cols = _cols.filter(key => key.toLowerCase() !== 'id')

const sql = `CREATE TABLE IF NOT EXISTS ${tableName} (id INTEGER PRIMARY KEY ASC, ${_cols.join(',')} )`
// console.log('createSQL:', sql)
// 调用事务,建立表
help.query(sql, [], cn)
.then((res) => {
resolve(res)
})
.catch((err) => {
console.log('createTable -sql:', sql, err)
const stack = new Error()
console.log('createTable -sql:', stack)
reject(err)
})
})
return myPromise
}

+ 28
- 0
src/packages/nf-ws-websql/table-delete.js View File

@@ -0,0 +1,28 @@

/**
* 实现删除数据的功能。逻辑删除,update set flag = 1
* @param { MySQLHelp } help 访问数据库的实例
* @param { string } tableName 表名
* @param { connection } cn 如果使用事务的话,需要传递开启事务时创建的连接对象
* @returns 添加记录的ID
* * meta 结构:
* * * tableName: '', 表名
* * * idKey: 'id', 主键字段名称
* * * delFlag: 'isDel', 逻辑删除,标记字段名称
*/
export default function deleteTable (help, tableName, cn = null) {
const myPromise = new Promise((resolve, reject) => {
const sql = `DROP TABLE ${tableName} `
// console.log('sql:', sql)
help.query(sql, [], cn)
.then((res) => {
// 成功了,返回给调用者
resolve(res)
})
.catch((err) => {
console.log('deleteTable - sql:', sql, err)
reject(err)
})
})
return myPromise
}

+ 31
- 0
src/packages/storage.js View File

@@ -0,0 +1,31 @@
// 引入各种函数,便于做成npm包
// indexedDB 部分
import dbHelp from './nf-ws-indexeddb/help.js'
import dbInstall from './nf-ws-indexeddb/install.js'

// webSQL 部分
import sqlHelp from './nf-ws-websql/help.js'
import sqlInstall from './nf-ws-websql/install.js'

// indexedDB 部分
const dbCreateHelp = (info) => dbInstall.createHelp(info)
const useDBHelp = (_dbFlag) => dbInstall.useDBHelp(_dbFlag)
const useStores = (_dbFlag) => dbInstall.useStores(_dbFlag)

// webSQL 部分
const sqlCreateHelp = (info) => sqlInstall.createHelp(info)
const useSQLHelp = (_dbFlag) => sqlInstall.useSQLHelp(_dbFlag)
const useTables = (_dbFlag) => sqlInstall.useTables(_dbFlag)

export {
// webSQL部分
sqlHelp,
sqlCreateHelp,
useSQLHelp,
useTables,
// indexedDB 部分
dbHelp, // indexedDB 的help
dbCreateHelp, // 创建help,初始化设置
useDBHelp, // 组件里获取 help
useStores // 组件里获取对象仓库,方便实现增删改查
}

+ 126
- 0
src/packages/vue-localstore/index.js View File

@@ -0,0 +1,126 @@

const manageStorage = (type) => {
// type --- local: localStorage;
// session:sessionStorage
if (typeof type === 'undefined' || type === '') { type = 'local' }
// 设置值
const setItem = (key, value) => {
let v = value
// 记录value的类型,默认是对象/数组
let valueType = typeof value
// 依据类型做序列化
switch (valueType) {
case 'object':
// 判断是不是日期类型
if (value === null) {
valueType = 'null'
v = 'null'
} else if (value instanceof Date) {
// 保存数据的时间戳
valueType = 'date'
v = value.valueOf()
} else {
// 对象、数组
v = JSON.stringify(value)
}
break
case 'function':
v = value.toString()
break
case 'undefined':
valueType = 'undefined'
v = 'undefined'
break
}
// 把数据、数据类型和时间戳,一起保存
const object = {
valueType: valueType,
time: new Date().valueOf(), // 时间戳,判断是否过期
value: v
}
v = JSON.stringify(object)
if (type === 'local') {
localStorage.setItem(key, v)
} else {
sessionStorage.setItem(key, v)
}
}
// 获取值
const getItem = (key) => {
let str = ''
// 判断存储方式
if (type === 'local') {
str = localStorage.getItem(key)
} else {
str = sessionStorage.getItem(key)
}
// 判断是否为空
if (typeof str === 'undefined' || str === null || str === '') {
return str
}
// 判断格式是否符合,没有太好的办法,暂时先这样。
if (str.indexOf('{"valueType":"') === -1) {
return ''
}
console.log('-----------------------------------------')
console.log('111存储的数据的类型:', typeof str)
console.log('111存储的数据:', str)
// 把存储的数据转换为对象
const object = JSON.parse(str)
// 取值
let value = object.value
// 判断存储之前的类型,做转换
switch (object.valueType) {
case 'object':// 对象和数组
value = JSON.parse(value)
break
case 'function': // 不做转换
// value = object.value
break
case 'date': // 日期的时间戳
value = new Date(value)
break
case 'number': // 数字
value = parseInt(value)
break
case 'null':
value = null
break
case 'undefined':
value = undefined
break
}
console.log('存储的数据的类型:')
console.log(object.valueType, typeof value)
console.log(object.valueType, Object.prototype.toString.call(value))
console.log('存储的数据:', value)
return value
}
// removeItem
const removeItem = (key) => {
if (type === 'local') {
localStorage.removeItem(key)
} else {
sessionStorage.removeItem(key)
}
}
// clear
const clear = (key) => {
if (type === 'local') {
localStorage.clear()
} else {
sessionStorage.clear()
}
}
return {
setItem,
getItem,
removeItem,
clear
}
}

+ 452
- 0
src/plugins/db.js View File

@@ -0,0 +1,452 @@
// indexedDB.js,浏览器本地数据库操作

export default {
// indexedDB兼容
indexedDB: window.indexedDB || window.webkitindexedDB || window.msIndexedDB || mozIndexedDB,
// 打开数据库
// 新对象储存空间newStore参数:newStore.name、newStore.key
// 新增对象存储空间要更改数据库版本
openDB: function (dbname, version, db, newStore, callback) {
var version = version;
var request = this.indexedDB.open(dbname, version);
request.onerror = function (event) {
console.log('IndexedDB数据库打开错误');
};
request.onsuccess = function (event) {
db = event.target.result;
if (callback && (typeof callback === 'function')) {
callback(db);
}
};
// onupgradeneeded,调用创建新的储存空间
request.onupgradeneeded = function (event) {
var db = event.target.result;
if (newStore) {
if (!db.objectStoreNames.contains(newStore.name)) {
var objectStore = db.createObjectStore(newStore.name, {
keyPath: newStore.key,
});
objectStore.createIndex('counter_index', 'counter', { unique: false });
objectStore.createIndex('barcode_index', 'barcode', { unique: false });
objectStore.createIndex('qty_index', 'qty', { unique: false });
objectStore.createIndex('counter_code', ['counter', 'barcode'], { unique: false });
}
}
};
},
// 删除数据库
deleteDB: function (dbname, callback) {
var deleteQuest = this.indexedDB.deleteDatabase(dbname);
deleteQuest.onerror = function () {
console.log('删除数据库出错');
};
deleteQuest.onsuccess = function () {
if (callback && (typeof callback === 'function')) {
callback();
}
}
},
// 关闭数据库
closeDB: function (dbname) {
dbname.close();
console.log('数据库已关闭');
},
// 更新旧值,针对输入数量
putData: function (db, storename, dataArr, callback) {
let mybarcode = "";
let QTY = "";
let key = "";
let counter = "";
let barcode = "";
let addtime = "";
dataArr.forEach(item => {
mybarcode = item.barcode;
QTY = item.qty;
barcode = item.barcode;
counter = item.counter;
key = item.counterCode;
addtime = item.addtime;

});
this.getdatabycursor(db, storename).then(arr => {
if (arr.length == 0) {
//console.log("添加")
var store = db.transaction(storename, 'readwrite').objectStore(storename),
request;
for (var i = 0, len = dataArr.length; i < len; i++) {
request = store.put(dataArr[i]);
request.onerror = function () {
console.error('PUT添加数据报错');
};
request.onsuccess = function (result) {
if (callback && (typeof callback === 'function')) {
callback();
}
};
}
}
else {
this.read(db, storename, counter, barcode).then(x => {
if (x) {
//console.log("最新的值是" + QTY)
this.updateDataByKey(db, storename, key, QTY, addtime).then(x => {
if (callback && (typeof callback === 'function')) {
callback();
}

});

}
else {
//console.log("再次添加")
var store = db.transaction(storename, 'readwrite').objectStore(storename),
request;
for (var i = 0, len = dataArr.length; i < len; i++) {
request = store.put(dataArr[i]);
request.onerror = function () {
console.error('PUT添加数据报错');
};
request.onsuccess = function (result) {
if (callback && (typeof callback === 'function')) {
callback();
}
};
}
}
})
}
})
},
// 更新旧值
putDatas: function (db, storename, dataArr, callback) {
let mybarcode = "";
let QTY = "";
let key = "";
let counter = "";
let barcode = "";
let addtime = "";
dataArr.forEach(item => {
mybarcode = item.barcode;
QTY = item.qty;
key = item.counterCode;
counter = item.counter;
barcode = item.barcode;
addtime = item.addtime;

});
this.getdatabycursor(db, storename).then(arr => {
if (arr.length == 0) {
//console.log("添加")
var store = db.transaction(storename, 'readwrite').objectStore(storename),
request;
for (var i = 0, len = dataArr.length; i < len; i++) {
request = store.add(dataArr[i]);
request.onerror = function () {
console.error('PUT添加数据报错');
};
request.onsuccess = function (result) {
if (callback && (typeof callback === 'function')) {
callback();
}
};
}
}
else {
this.read(db, storename, counter, barcode).then(x => {
if (x) {
this.updateDataByKeys(db, storename, key, addtime).then(x => {
this.getdata(db, storename).then(result => {
if (callback && (typeof callback === 'function')) {
callback();
}
});
});

}
else {
//console.log("再次添加")
//console.log("当前的值是"+barcode)
var store = db.transaction(storename, 'readwrite').objectStore(storename),
request;
for (var i = 0, len = dataArr.length; i < len; i++) {
request = store.add(dataArr[i]);
request.onerror = function () {
console.error('PUT添加数据报错');
};
request.onsuccess = function (result) {
if (callback && (typeof callback === 'function')) {
callback();
}
};
}

}
})
}
})
},
//根据key修改数量
updateDataByKey: function (db, storeName, value, QTY, addtime) {
var transaction = db.transaction(storeName, 'readwrite');
var store = transaction.objectStore(storeName);
var request = store.get(value);
return new Promise((resolve, reject) => {
request.onsuccess = function (e) {
var stocktable = e.target.result;
if (stocktable) {
stocktable.qty = QTY;
stocktable.addtime = addtime;
resolve(store.put(stocktable));
}
else {
reject(false);
}

};

})

},

updateDataBycode: function (db, storeName, value, QTY) {
var transaction = db.transaction(storeName, 'readwrite');
var store = transaction.objectStore(storeName);
var request = store.get(value);
return new Promise((resolve, reject) => {
request.onsuccess = function (e) {
var stocktable = e.target.result;
if (stocktable) {
stocktable.qty = QTY;

resolve(store.put(stocktable));
}
else {
reject(false);
}

};

})

},
//根据key修改数量
updateDataByKeys: function (db, storeName, value, addtime, callback) {
var transaction = db.transaction(storeName, 'readwrite');
var store = transaction.objectStore(storeName);
var request = store.get(value);

return new Promise((resolve, reject) => {
//console.log(addtime)
request.onsuccess = function (e) {
var stocktable = e.target.result;
if (stocktable) {
stocktable.qty = QTY ;
stocktable.addtime = addtime;
resolve(store.put(stocktable));
}
else {
reject(false);
}

};
})

},
// 删除数据
deleteData: function (db, storename, key, callback) {
var store = db.transaction(storename, 'readwrite').objectStore(storename);
store.delete(key);
if (callback && (typeof callback === 'function')) {
callback();
}

},
// 清空数据
clearData: function (db, storename, callback) {
var store = db.transaction(storename, 'readwrite').objectStore(storename);
store.clear();
if (callback && (typeof callback === 'function')) {
callback();
}
},
// 通过key获取数据
read: function (db, storeName, counter, barcode) {
var transaction = db.transaction(storeName);
var objectStore = transaction.objectStore(storeName);
var currentdata = [counter, barcode];
var indexs = objectStore.index('counter_code');
var request = indexs.openCursor(IDBKeyRange.only(currentdata));
return new Promise((resolve, reject) => {
request.onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
resolve(true);
}
else {
resolve(false);
}
}
})

},
// 通过barcode获取数据
reads: function (db, storeName, values) {
var transaction = db.transaction(storeName);
var objectStore = transaction.objectStore(storeName);
var indexs = objectStore.index('barcode_index');
var data = [];
var request = indexs.openCursor(IDBKeyRange.only(values));
return new Promise((resolve, reject) => {
request.onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
data.push(cursor.value);
// resolve(data);
cursor.continue();
}
else {
resolve(data)
}
};
})

},
//根据counter索引查询数据
getdatabyCounter: function (db, storeName, values) {
var transaction = db.transaction(storeName);
var store = transaction.objectStore(storeName);
var indexs = store.index('counter_index');
var datas = [];
var request = indexs.openCursor(IDBKeyRange.only(values))
return new Promise((resolve, reject) => {
request.onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
datas.push(cursor.value);
cursor.continue();
}
else {
resolve(datas)
}
}
})

},
//根据主键和索引查询
getAll: function (db, storeName, counter, barcode) {
var transaction = db.transaction(storeName);
var objectStore = transaction.objectStore(storeName);
var counterCode = [counter, barcode];
var indexs = objectStore.index('counter_code');
var request = indexs.openCursor(IDBKeyRange.only(counterCode));
var data = [];
return new Promise((resolve, reject) => {
request.onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
data.push(cursor.value);
//resolve(data);
cursor.continue();
}
else {
resolve(data)
}

}
})
},
//根据key查询数量是否存在
getqtyBykey: function (db, storeName, key) {
var transaction = db.transaction(storeName);
var objectStore = transaction.objectStore(storeName);
var request = objectStore.get(key);
request.onerror = function (event) {
console.log('事务失败');
};
return new Promise((resolve, reject) => {
request.onsuccess = function (event) {
if (request.result) {
//console.log(request.result.qty)
resolve(request.result);
} else {
resolve(false);
}
};
})

},
// //通过游标遍历数据
getdatabycursor: function (db, storename) {
var objectStore = db.transaction(storename).objectStore(storename);
var dataList = [];
var i = 0;
return new Promise((resolve, reject) => {
objectStore.openCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
dataList.push(cursor.value)
cursor.continue();
} else {
resolve(dataList);
}

};
})

},
//查询所有的柜台
getAllCounter: function (db, storename) {
var transaction = db.transaction(storename);
var store = transaction.objectStore(storename);
var indexs = store.index('counter_index');
var data = [];
return new Promise((resolve, reject) => {
indexs.openCursor().onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
// console.log(cursor.value.counter);
data.push(cursor.value.counter);
resolve(data);
cursor.continue();
}
}
})
},
getdata: function (db, storename) {
var objectStore = db.transaction(storename).objectStore(storename);
var data = [];
return new Promise((resolve, reject) => {
objectStore.openCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
data.push(cursor.value)

resolve(data)
}
else {
reject(false)
}

};
})
},
getqtybyqtyindex: function (db, storename) {
var transaction = db.transaction(storename);
var store = transaction.objectStore(storename);
var indexs = store.index('qty_index');
var sum = 0;
return new Promise((resolve, reject) => {
indexs.openCursor().onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
sum += cursor.value.qty
cursor.continue();
}
else {
resolve(sum)
}
}
})
}

}

+ 10
- 0
src/plugins/lazyload.js View File

@@ -0,0 +1,10 @@
import Vue from "vue";
import VueLazyload from "vue-lazyload";
// https://github.com/hilongjw/vue-lazyload
Vue.use(VueLazyload, {
preLoad: 1.3,
// loading: require("@/assets/ic_photo_loading.png"),
error: require("@/assets/ic_photo_error.png"),
attempt: 3
});

+ 16
- 0
src/plugins/mintui.js View File

@@ -0,0 +1,16 @@
import Vue from "vue";
import { Indicator } from "mint-ui";
// Mint UI 使用文档: https://mint-ui.github.io/docs/#/zh-cn2
Vue.component(Indicator);
// import isEmpty from "lodash/isEmpty";
Vue.prototype.showLoading = function(msg) {
// if (isEmpty(msg)) {
// msg = "加载中...";
// }
return Indicator.open(msg);
};
Vue.prototype.hideLoading = function() {
return Indicator.close();
};

+ 149
- 0
src/plugins/socket.js View File

@@ -0,0 +1,149 @@
var websock = null;
let rec; //断线重连后,延迟5秒重新创建WebSocket连接 rec用来存储延迟请求的代码
let isConnect = false; //连接标识 避免重复连接
let checkMsg = "heartbeat"; //心跳发送/返回的信息 服务器和客户端收到的信息内容如果如下 就识别为心跳信息 不要做业务处理

var globalCallback = function() {};

let createWebSocket = (url) => {
try {
initWebSocket(url); //初始化websocket连接
} catch (e) {
console.log("尝试创建连接失败");
reConnect(url); //如果无法连接上webSocket 那么重新连接!可能会因为服务器重新部署,或者短暂断网等导致无法创建连接
}
};

//定义重连函数
let reConnect = (url) => {
console.log("尝试重新连接");
if (isConnect) return; //如果已经连上就不在重连了
rec && clearTimeout(rec);
rec = setTimeout(function() {
// 延迟5秒重连 避免过多次过频繁请求重连
createWebSocket(url);
}, 5000);
};
//设置关闭连接
let closeWebSocket = () => {
webSocket.close();
};
//心跳设置
var heartCheck = {
timeout: 20000, //每段时间发送一次心跳包 这里设置为20s
timeoutObj: null, //延时发送消息对象(启动心跳新建这个对象,收到消息后重置对象)

start: function() {
this.timeoutObj = setTimeout(function() {
if (isConnect) websock.send(checkMsg);
}, this.timeout);
},

reset: function() {
clearTimeout(this.timeoutObj);
this.start();
}
};

// 初始化websocket
function initWebSocket(ws) {
// ws地址 -->这里是你的请求路径
websock = new WebSocket(ws);
websock.onmessage = function(e) {
websocketonmessage(e);
};
websock.onclose = function(e) {
websocketclose(e);
};
websock.onopen = function() {
websocketOpen();
// heartCheck.start();
};

// 连接发生错误的回调方法
websock.onerror = function() {
console.log("WebSocket连接发生错误");
isConnect = false; //连接断开修改标识
reConnect(ws); //连接错误 需要重连
};
return websock;
}

// 实际调用的方法
function sendSock(agentData, callback) {
globalCallback = callback;
// console.log(globalCallback)
if (websock.readyState === websock.OPEN) {
// 若是ws开启状态
websocketsend(agentData);
} else if (websock.readyState === websock.CONNECTING) {
// 若是 正在开启状态,则等待1s后重新调用
setTimeout(function() {
sendSock(agentData, callback);
}, 1000);
} else {
// 若未开启 ,则等待1s后重新调用
setTimeout(function() {
sendSock(agentData, callback);
}, 1000);
}
}

function getSock(callback) {
globalCallback = callback;
}
// 数据接收
function websocketonmessage(e) {
console.log(e.data);

let O_o = JSON.parse(decodeUnicode(e.data));

if (!O_o) {
heartCheck.reset();
} else {
if (O_o.msg == "open success") {
sessionStorage.setItem("wid", O_o.wid);
} else {
console.log(O_o);
globalCallback(O_o);
}
}

// globalCallback(JSON.parse(e.data))
function decodeUnicode(str) {
str = str.replace(/\\/g, "%");
//转换中文
str = unescape(str);
//将其他受影响的转换回原来
str = str.replace(/%/g, "\\");
//对网址的链接进行处理
str = str.replace(/\\/g, "");
return str;
}
}

// 数据发送
function websocketsend(agentData) {
console.log(JSON.stringify(agentData));
websock.send(JSON.stringify(agentData));
}

// 关闭
function websocketclose(e) {
console.log(e);
isConnect = false; //断开后修改标识
console.log("connection closed (" + e.code + ")");
let url = e.currentTarget.url;
reConnect(url);
}

// 创建 websocket 连接
function websocketOpen(e) {
isConnect = true;
console.log("连接成功");
}

// initWebSocket();

// 将方法暴露出去
export { initWebSocket, sendSock, getSock, createWebSocket, closeWebSocket };

+ 134
- 0
src/requests/axios.js View File

@@ -0,0 +1,134 @@
import axios from "axios";
import Cloudia from "../api/cloudia-sdk-v1.4.1";
import Vue from "vue";
let retry = 2;
let retryDelay = 1000;
class AxiosRequest {
constructor(baseUrl, isDebuggable) {
this.isDebuggable = isDebuggable;
this.instance = axios.create({
baseURL: baseUrl,
timeout: 10000, // 10s as default
withCredentials: true,
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
}
});
this.interceptors();
}
get(url, params) {
return this.request({
method: "get",
url: url,
params: params
});
}
post(url, params) {
return this.request({
method: "post",
url: url,
headers: {
"Content-Type": "application/json;charset=UTF-8"
},
data: params
});
}
postForm(url, params) {
return this.request({
method: "post",
url: url,
data: params,
transformRequest: [
function(data) {
let ret = "";
for (const it in data) {
ret += encodeURIComponent(it) + "=" + encodeURIComponent(data[it]) + "&";
}
return ret;
}
]
});
}
postFile(url, params) {
return this.request({
method: "post",
url: url,
headers: {
"Content-Type": "multipart/form-data"
},
data: params,
transformRequest: [
function(data) {
const formData = new FormData();
for (const item in data) {
formData.append(item, data[item]);
}
return formData;
}
]
});
}
request(options) {
return this.instance(options);
}
interceptors() {
let that = this;
this.instance.interceptors.response.use(
(res) => {
const { data, status } = res;
if (status > 200 && status < 400) {
if (this.isDebuggable) {
Cloudia.showToast(`http code: ${status}`);
}
} else if (status !== 200) {
if (this.isDebuggable) {
Cloudia.showToast(`http code: ${status}`);
} else {
console.error(`http error, code: ${status}`);
Cloudia.showToast("请检查网络连接是否正常,稍后重试!");
}
}
if (data.resultInfo && data.resultInfo.resultCode !== "200") {
Cloudia.showToast(`request error: ${data.resultInfo.resultMsg} (${data.resultInfo.resultCode})`);
}
return data;
},
(error) => {
Cloudia.showToast("请检查网络连接是否正常,稍后重试!");
console.error("网络加载失败");
var config = error.config;
config.__retryCount = config.__retryCount || 0;
if (config.__retryCount >= retry) {
console.error("网络请求重试结束:" + config.__retryCount);
Vue.prototype.hideLoading();
// Reject with the error
return Promise.reject(error);
}
// Increase the retry count
config.__retryCount += 1;
console.error("网络请求开始重试:" + config.__retryCount);
// Create new promise to handle exponential backoff
return new Promise(function(resolve) {
setTimeout(function() {
resolve();
}, retryDelay);
}).then(function() {
return that.request(config);
});
}
);
}
}
export default AxiosRequest;

+ 41
- 0
src/requests/request-cors.js View File

@@ -0,0 +1,41 @@
import request from "./request";
// https://{host-name}/api/apilist?api=Weather
// location - 城市
// startTime - 2019-05-09/2019-05-09 12:00
// endTime - 2019-05-12/2019-05-12 12:00
// lang - Optional, en/cn/jp
export const getWeatherDaily = (location, startTime, endTime, lang = "cn") => {
console.info(
"request corsapi/weather?api=Weather, params:location=" +
location +
", startTime=" +
startTime +
", endTime=" +
endTime +
", lang=" +
lang
);
return request.get("corsapi/weather?api=WeatherNow", {
location: location,
lang: lang
});
};
export const getWeatherWeekly = (location, startTime, endTime, lang = "cn") => {
console.info(
"request corsapi/weather?api=Weather, params:location=" +
location +
", startTime=" +
startTime +
", endTime=" +
endTime +
", lang=" +
lang
);
return request.get("corsapi/weather?api=Weather", {
location: location,
startTime: startTime,
endTime: endTime,
lang: lang
});
};

+ 5
- 0
src/requests/request.js View File

@@ -0,0 +1,5 @@
import AxiosRequest from "./axios";
import config from "@/config";
const request = new AxiosRequest(config.baseUrl, config.isDebuggable);
export default request;

+ 87
- 0
src/router/dbRouter.js View File

@@ -0,0 +1,87 @@
const { add, query } = require("../db/dbHelp");
const express = require("express");
const router = express.Router();

// 连接数据库
const jsonWrite = function(res, ret) {
if (typeof ret === "undefined") {
res.json({
code: "1",
msg: "操作失败"
});
} else {
res.json(ret);
}
};

// 接口:增加信息sql,编辑修改信息sql1
router.post("/save", (req, res) => {
const params = req.body;
console.log(params);
add(params, (result) => {
jsonWrite(res, result);
});
});

// 接口:用户管理分页接口查询
router.get("/getlist", (req, res) => {
const params = req.body;
console.log(params);
query((result) => {
jsonWrite(res, result);
});
});

const db = require("../db/mssql"); //注意改路径

router.get("/ms/detailMD", (req, res) => {
console.log(db.sql);
//根据时间查询的模板

var count = 0;
var commonResult = [];
db.sql(
"SELECT PassType,count(1) as Count FROM HJ_PersonRecognition WHERE DateDiff(dd,DetectTime,getdate())=0 group by PassType order by PassType",
function(err, result) {
if (err) {
console.log(err);
return;
}
commonResult.push(...result.recordset);
count++;
if (count >= 3) {
res.send(commonResult);
}
}
);
db.sql(
"select 0 as Reserve1, count(1) as cnt from HJ_PersonRecognition as person where person.Reserve1 = '0' and DATEDIFF(DAY, person.DetectTime, GETDATE()) = 0 union select 1 as Reserve1, count(1) as cnt from HJ_PersonRecognition as person where person.Reserve1 = '1' and DATEDIFF(DAY, person.DetectTime, GETDATE()) = 0",
function(err, result) {
if (err) {
console.log(err);
return;
}
commonResult.push(...result.recordset);
count++;
if (count >= 3) {
res.send(commonResult);
}
}
);
db.sql(
"SELECT 0 as online, count(1) as num FROM HJ_EquipInfo WHERE Status = 1 and EquipTypeID = 3 union SELECT 1 as online, count(1) as num FROM HJ_EquipInfo WHERE (Status = 0 or Status = 2) and EquipTypeID = 3",
function(err, result) {
if (err) {
console.log(err);
return;
}
commonResult.push(...result.recordset);
count++;
if (count >= 3) {
res.send(commonResult);
}
}
);
});

module.exports = router;

+ 21
- 0
src/router/index.js View File

@@ -0,0 +1,21 @@
import Vue from "vue";
import VueRouter from "vue-router";
import ApiDemo from "../views/ApiDemo";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "ApiDemo",
component: ApiDemo
}
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
export default router;

+ 42
- 0
src/router/socketSrv.js View File

@@ -0,0 +1,42 @@
const ws = require("nodejs-websocket");
console.log("开始建立连接...");

const socket = ws
.createServer(function(conn) {
let msg = { id: "211", times: 0, name: "王武", tag: "" };
let intval = setInterval(() => {
if (conn.readyState == 1) {
conn.sendText(JSON.stringify(msg));
} else {
clearInterval(intval);
}
}, 2000);

conn.on("text", function(str) {
/* console.log("message:" + str);
let msg = { data: { on: 1, face: "hhhh" } };
// let msg = "你好,这里是是日前端~";
// let msg = 'websocket处于正常状态'
setInterval(() => {
conn.sendText(JSON.stringify(msg));
}, 3000);*/
});
conn.on("connect", function(code) {
let msg = { data: { on: 1, face: "hhhh" } };
// let msg = "你好,这里是是日前端~";
// let msg = 'websocket处于正常状态'
setInterval(() => {
conn.sendText(JSON.stringify(msg));
}, 3000);
});
conn.on("close", function(code, reason) {
console.log("关闭连接");
});
conn.on("error", function(code, reason) {
console.log("异常关闭", code, reason);
});
})
.listen(8666);
console.log("WebSocket建立完毕");

module.exports = socket;

+ 28
- 0
src/server/dbHandle.js View File

@@ -0,0 +1,28 @@
// node 后端服务器
const dbRouter = require("../router/dbRouter");
const bodyParser = require("body-parser");
const express = require("express");
const app = express();
//采用设置所有均可访问的方法解决跨域问题
app.all("*", function(req, res, next) {
//设置允许跨域的域名,*代表允许任意域名跨域
res.header("Access-Control-Allow-Origin", "*");
//允许的header类型
res.header("Access-Control-Allow-Headers", "content-type");
//跨域允许的请求方式
res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS");
if (req.method.toLowerCase() == "options") res.send(200);
//让options尝试请求快速结束
else next();
});

// 以json格式返回出去
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

// 后端api路由
app.use("/api/db", dbRouter);

// 监听端口
app.listen(13000);
console.log("success listen at port:13000......");

+ 24
- 0
src/styles/dimens.scss View File

@@ -0,0 +1,24 @@
$base-width: 540;
$base-height: 976;
$border-radius: 4px;
@function vw($px) {
@return $px / $base-width * 100vw;
}
@function vh($px) {
@return $px / $base-height * 100vh;
}
@function vmax($px) {
@return $px / $base-height * 100vh;
}
@function vmin($px) {
@return $px / $base-width * 100vw;
}
@function rem($px) {
@return $px / $base-width * 100vw;
}

+ 172
- 0
src/utils/genTtsText.js View File

@@ -0,0 +1,172 @@
import Config from "../config";
import axios from "axios";
import { encrypt } from "./jsencrypt";

export const genRyts = (callback, err) => {
axios
.get(Config.serverDb + "/api/db/ms/detailMD", {})
.then((res3) => {
var result = res3.data;
var inNum = 0;
var outNum = 0;
var faceNum = 0;
var cardNum = 0;
var onlineNum = 0;
var offlineNum = 0;
for (var item in result) {
if (result[item]["online"] && result[item]["online"] == 0) {
onlineNum = result[item]["num"];
} else if (result[item]["online"] && result[item]["online"] == 1) {
offlineNum = result[item]["num"];
} else if (result[item]["Reserve1"] && result[item]["Reserve1"] == 0) {
inNum = result[item]["cnt"];
} else if (result[item]["Reserve1"] && result[item]["Reserve1"] == 1) {
outNum = result[item]["cnt"];
} else if (result[item]["PassType"] && result[item]["PassType"] == 0) {
cardNum = result[item]["Count"];
} else if (result[item]["PassType"] && result[item]["PassType"] == 1) {
faceNum = result[item]["Count"];
}
}

/* var str =
"现在为您展示的是人员态势,当前20楼内总人数" +
(inNum - outNum) +
"人,通过首层大堂闸机通行人数" +
(inNum + outNum) +
"人,其中人脸识别" +
faceNum +
"人,刷卡识别" +
cardNum +
"人。";*/
var str = "已为您打开人员态势";
//人脸识别面板机、门禁闸机" +
// onlineNum +
// "台在线,在线率100%。
callback(str);
})
.catch((res) => {
err(res);
});
};

export const genPreRemoteReq = (obj, callback, errCallback) => {
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
myHeaders.append("Cookie", "ASP.NET_SessionId=");

var raw = JSON.stringify({
username: "adminadmin",
userpwd:
"Og4mnsq5AsZc+RfESX8eC9QS2aa9vEDC8Tp7c8S2ZY+d/BuNeEMoFc5Y9ycMhwWQ/gMsAWPsRaGgAvUt09WzOkdWYzlImrZrLfqa4/B26m7TtAigun5tNHCbpEb/ojjlGNmH4tQbszPwMfV6QFgYj6gAecVPYZQXOt7hdjEHdSQ=",
verificationCode: 2222
});

var requestOptions = {
method: "POST",
headers: myHeaders,
body: raw,
redirect: "follow"
};

// fetch("http://192.168.1.254:8089/api/server/getkey_pc", requestOptions)
fetch("/getKey", requestOptions)
.then((response) => response.text())
.then((res1) => {
console.log(res1);
res1 = JSON.parse(res1);
console.log(res1);
let resData = res1.HttpData.data;
var myHeaders = new Headers();
myHeaders.append("Authorization", resData.appkey + "-" + resData.infokey);
myHeaders.append("Referer", Config.serverHj);
myHeaders.append("Content-Type", "application/json");
myHeaders.append("Cookie", "ASP.NET_SessionId=");

var raw = JSON.stringify({
data: obj.data
});

var requestOptions = {
method: "POST",
headers: myHeaders,
body: raw,
redirect: "follow"
};

// fetch(Config.serverPot + obj.path + "?_r=" + Math.random(), requestOptions)
fetch("/hj" + obj.path + "?_r=" + Math.random(), requestOptions)
// fetch("http://192.168.1.254:8088" + obj.path + "?_r=" + Math.random(), requestOptions)
.then((response) => response.text())
.then((result) => {
console.log(result);

result = JSON.parse(result);
console.log(result);
callback(result);
})
.catch((error) => {
console.log("error", error);
errCallback(error);
});
})
.catch((error) => console.log("error", error));

/*axios
.post("http://192.168.1.254:8089/api/server/getkey_pc", {
// .post("/getKey", {
username: Config.username,
userpwd: encrypt(Config.userpwd),
verificationCode: "2222"
})
.then((res1) => {
let resData = res1.data.HttpData.data;
var myHeaders = new Headers();
myHeaders.append("Authorization", resData.appkey + "-" + resData.infokey);
myHeaders.append("Referer", Config.serverHj);
myHeaders.append("Content-Type", "application/json");
myHeaders.append("Cookie", "ASP.NET_SessionId=");

var raw = JSON.stringify({
data: obj.data
});

var requestOptions = {
method: "POST",
headers: myHeaders,
body: raw,
redirect: "follow"
};

// fetch(Config.serverPot + obj.path + "?_r=" + Math.random(), requestOptions)
fetch("http://192.168.1.254:8088" + obj.path + "?_r=" + Math.random(), requestOptions)
.then((response) => response.text())
.then((result) => {
console.log(result);

result = JSON.parse(result);
console.log(result);
callback(result);
})
.catch((error) => {
console.log("error", error);
errCallback(error);
});
})
.catch((res) => {
errCallback(res);
});*/
};

export const genRemoteReq = (resData, obj, callback, errCallback) => {
axios
.post(Config.serverHj + "/api/real/setup_service", obj, {
headers: { Authorization: resData.appkey + "-" + resData.infokey }
})
.then(() => {
callback();
})
.catch((res) => {
errCallback(res);
});
};

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

Loading…
Cancel
Save