yk пре 2 година
комит
ff047eed17
100 измењених фајлова са 43357 додато и 0 уклоњено
  1. +3
    -0
      .env.dev
  2. +2
    -0
      .env.prod
  3. +2
    -0
      .env.test
  4. +30
    -0
      .gitignore
  5. +0
    -0
      README.md
  6. +12
    -0
      babel.config.js
  7. +96
    -0
      nginx.conf
  8. +31756
    -0
      package-lock.json
  9. +60
    -0
      package.json
  10. +192
    -0
      public/config.json
  11. BIN
      public/favicon.ico
  12. +45
    -0
      public/index.html
  13. +432
    -0
      src/App.vue
  14. +452
    -0
      src/api/cloudia-sdk-v1.4.1.js
  15. BIN
      src/assets/back.png
  16. +3593
    -0
      src/assets/bootstrap.min.js
  17. BIN
      src/assets/close.png
  18. BIN
      src/assets/erji.png
  19. BIN
      src/assets/home.png
  20. BIN
      src/assets/ic_back.png
  21. BIN
      src/assets/ic_photo_error.png
  22. BIN
      src/assets/ic_photo_loading.png
  23. BIN
      src/assets/loading2.gif
  24. BIN
      src/assets/logo-digimeta.png
  25. BIN
      src/assets/logo.png
  26. BIN
      src/assets/logo_new.png
  27. BIN
      src/assets/logo_wh.png
  28. +125
    -0
      src/components/Alert.vue
  29. +685
    -0
      src/components/DemoView.vue
  30. +98
    -0
      src/components/DialogMeetingAppointOK.vue
  31. +94
    -0
      src/components/DialogMeetingCancelOK.vue
  32. +69
    -0
      src/components/DialogMeetingRoom.vue
  33. +68
    -0
      src/components/DialogMeetingTopic.vue
  34. +82
    -0
      src/components/DialogMeetingTopicDefine.vue
  35. +89
    -0
      src/components/DialogVisitorAppointOK.vue
  36. +85
    -0
      src/components/DialogVisitorRegisterOK.vue
  37. +398
    -0
      src/components/JsonView.vue
  38. +193
    -0
      src/components/SwiperView.vue
  39. +29
    -0
      src/config/index.js
  40. +21
    -0
      src/db/dbHelp.js
  41. +88
    -0
      src/db/dbRouter.js
  42. +54
    -0
      src/db/mssql.js
  43. +10
    -0
      src/db/sql.js
  44. +70
    -0
      src/main.js
  45. +274
    -0
      src/mixins/mixin.js
  46. +95
    -0
      src/mixins/socket.js
  47. +5
    -0
      src/packages/meta.js
  48. +87
    -0
      src/packages/nf-meta/help.js
  49. +138
    -0
      src/packages/nf-meta/loadmeta-json.js
  50. +209
    -0
      src/packages/nf-meta/loadmeta-sql.js
  51. +100
    -0
      src/packages/nf-meta/savemeta-db.js
  52. +114
    -0
      src/packages/nf-ws-indexeddb/_toIndex.js
  53. +19
    -0
      src/packages/nf-ws-indexeddb/_toObject.js
  54. +26
    -0
      src/packages/nf-ws-indexeddb/begin-init.js
  55. +32
    -0
      src/packages/nf-ws-indexeddb/begin-tran.js
  56. +270
    -0
      src/packages/nf-ws-indexeddb/help.js
  57. +146
    -0
      src/packages/nf-ws-indexeddb/install.js
  58. +106
    -0
      src/packages/nf-ws-indexeddb/list-all.js
  59. +60
    -0
      src/packages/nf-ws-indexeddb/list-index.js
  60. +124
    -0
      src/packages/nf-ws-indexeddb/list-pager.js
  61. +37
    -0
      src/packages/nf-ws-indexeddb/model-add.js
  62. +35
    -0
      src/packages/nf-ws-indexeddb/model-count.js
  63. +34
    -0
      src/packages/nf-ws-indexeddb/model-delete.js
  64. +36
    -0
      src/packages/nf-ws-indexeddb/model-get.js
  65. +45
    -0
      src/packages/nf-ws-indexeddb/model-put.js
  66. +56
    -0
      src/packages/nf-ws-indexeddb/model-set.js
  67. +31
    -0
      src/packages/nf-ws-indexeddb/store-clear.js
  68. +34
    -0
      src/packages/nf-ws-websql/_pager-info.js
  69. +81
    -0
      src/packages/nf-ws-websql/_where-query.js
  70. +52
    -0
      src/packages/nf-ws-websql/data-add.js
  71. +30
    -0
      src/packages/nf-ws-websql/data-delete.js
  72. +31
    -0
      src/packages/nf-ws-websql/data-deleteflag.js
  73. +30
    -0
      src/packages/nf-ws-websql/data-get.js
  74. +55
    -0
      src/packages/nf-ws-websql/data-set.js
  75. +49
    -0
      src/packages/nf-ws-websql/data-update.js
  76. +27
    -0
      src/packages/nf-ws-websql/db-delete.js
  77. +211
    -0
      src/packages/nf-ws-websql/help.js
  78. +150
    -0
      src/packages/nf-ws-websql/install.js
  79. +50
    -0
      src/packages/nf-ws-websql/list-all.js
  80. +33
    -0
      src/packages/nf-ws-websql/list-count.js
  81. +53
    -0
      src/packages/nf-ws-websql/list-pager.js
  82. +39
    -0
      src/packages/nf-ws-websql/table-create.js
  83. +27
    -0
      src/packages/nf-ws-websql/table-delete.js
  84. +31
    -0
      src/packages/storage.js
  85. +127
    -0
      src/packages/vue-localstore/index.js
  86. +415
    -0
      src/plugins/db.js
  87. +10
    -0
      src/plugins/lazyload.js
  88. +16
    -0
      src/plugins/mintui.js
  89. +149
    -0
      src/plugins/socket.js
  90. +135
    -0
      src/requests/axios.js
  91. +41
    -0
      src/requests/request-cors.js
  92. +5
    -0
      src/requests/request.js
  93. +87
    -0
      src/router/dbRouter.js
  94. +72
    -0
      src/router/index.js
  95. +42
    -0
      src/router/socketSrv.js
  96. +28
    -0
      src/server/dbHandle.js
  97. +56
    -0
      src/store/index.js
  98. +6
    -0
      src/styles/bootstrap.min.css
  99. +24
    -0
      src/styles/dimens.scss
  100. +149
    -0
      src/utils/common.js

+ 3
- 0
.env.dev Прегледај датотеку

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

+ 2
- 0
.env.prod Прегледај датотеку

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

+ 2
- 0
.env.test Прегледај датотеку

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

+ 30
- 0
.gitignore Прегледај датотеку

@@ -0,0 +1,30 @@
.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?

.es*
.browserslistrc
.docker*
.npmrc
.prettierrc
.stylelintrc


+ 12
- 0
babel.config.js Прегледај датотеку

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

+ 96
- 0
nginx.conf Прегледај датотеку

@@ -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;
}
}
}

+ 31756
- 0
package-lock.json
Разлика између датотеке није приказан због своје велике величине
Прегледај датотеку


+ 60
- 0
package.json Прегледај датотеку

@@ -0,0 +1,60 @@
{
"name": "wh-aiman",
"version": "0.0.2",
"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",
"less-loader": "^11.1.0",
"lodash": "^4.17.21",
"mint-ui": "^2.2.13",
"moment": "^2.29.4",
"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",
"vuex": "^3.6.2"
},
"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",
"lodash-webpack-plugin": "^0.11.6",
"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.9.0"
}
}

+ 192
- 0
public/config.json Прегледај датотеку

@@ -0,0 +1,192 @@
{
"ttsControlEnable": true,
"chatEnable": false,
"showMsg": false,
"autoOpenDoor": true,
"ableHandleLight": true,
"debug": false,
"detectedFaceEnable": false,
"handleUrl": "http://192.168.1.146:8080/",
"text_match": {
"工区": "公区",
"奥比": "奥北",
"回忆": "会议",
"宝贝": "报备",
"卡门": "开门",
"看门": "开门",
"看看": "开门",
"早下": "找下",
"可燃": "客人",
"克然": "客人",
"早一下": "找一下"
},
"clothes": {
"SweetGirl": [
"suit_blue",
"suit_red",
"waistcoat_blue"
],
"BusinessGirl": [
"suit_green",
"waistcoat_black"
]
},
"characters": [
"SweetGirl",
"BusinessGirl"
],
"zhaohu": [
"你好",
"您好",
"小酷",
"小酷小酷",
"你好小酷",
"hello"
],
"breakReqs": [
"停",
"闭嘴",
"住嘴",
"stop",
"shut up"
],
"helpReqs": [
"我找",
"我来",
"在嘛",
"这里是",
"来找",
"送快递",
"送外卖",
"卢总",
"王总"
],
"serverDb": "http://192.168.1.254:13000",
"nuoDiSrvUrl": "http://39.105.85.176:48080/nuodi",
"nuoDiAppId": "759a993c",
"nuoDiSecret": "3946401cbcc24a90b208",
"serverUrl": "https://ai.lecooai.com",
"notifyTodayUrl": "/v1/notifyToday",

"returnAdPage": 30000,
"judgeDetectedNoPerson": 5000,
"judgeNoPerson": 15000,

"normal": [
],
"greeting": [
"您好",
"嗨",
"Hi",
"Hello"
],
"progressMap": {
"dhys":"会议室模式",
"fkbb": "访客预约",
"fkdj": "访客登记",
"moshengren": "陌生人"
},
"lights": [
"会议",
"门口",
"公区",
"会客",
"大门"
],
"meetings": [
"会议",
"开会",
"约会",
"定会",
"约个会",
"预约",
"预定",
"会议预定"
],
"visits": [
"访客","访客报备","访客预约","客人","客人到访","报备"
],
"visitors":["我找","在么","在吗","外卖","登记","送快递","面试","找", "见", "访","预约", "来找", "找一下","找下", "客人", "有约", "预约"],
"forwards": ["对","好","ok","可以","是","嗯","行","需要","要"],
"opposites": ["不","否","no"],
"meetingTopics": ["例会", "事项讨论", "访客接待","面试", "自定义"],
"lights_match": {
"会议": 0,
"会议室": 0,
"展厅": 1,
"门口": 1,
"工区": 2,
"办公区": 2,
"会客室": 3,
"会客": 3,
"东屋": 3,
"大门": 4
},

"workLights": [
{
"deviceId": "21",
"channel": "2"
},{
"deviceId": "21",
"channel": "4"
},{
"deviceId": "21",
"channel": "1"
},{
"deviceId": "21",
"channel": "3"
}
],

"lightsObj":[
{
"deviceId": "20",
"channel": "2"
},{
"deviceId": "20",
"channel": "1"
}],

"devMappings": [
{
"robotCode": "864972045000291",
"title": "阳光恒昌",
"deviceId": "ROBOT_PAD1",
"openDoorUrl": "http://192.168.1.253:9091",
"officeCode": "6123731313956274818",
"defaultPhones": "13488821068,15001249652",
"asks": {
"mgr": "",
"emp": "",
"emp2": "",
"keyVisitor": "欢迎来到阳光恒昌,请进。",
"keyVisitor2": "",
"visitor": "好久不见,您先在会议室稍坐,已通知到我的同事",
"visitor2": "",
"courier": "快递外卖人员暂不可进入本公司,请您在门外联系相关人员。",
"blackRole": "你是黑名单人员,不允许进入本公司,请赶快离开!",
"default": "我是前台小酷,有什么可以帮您?"
}
},{
"robotCode": "864972045000846",
"title": "缔智元",
"deviceId": "ROBOT_PAD2",
"openDoorUrl": "/srv/api/passDoor?deviceId=VGATE1",
"officeCode": "3969026645953309806",
"defaultPhones": "18910801519,19306342044",
"asks": {
"mgr": "",
"emp": "",
"emp2": "",
"keyVisitor": "欢迎来到缔智元,请进。",
"keyVisitor2": "",
"visitor": "好久不见,您先在会议室稍坐,已通知到我的同事",
"visitor2": "",
"courier": "快递外卖人员暂不可进入本公司,请您在门外联系相关人员。",
"blackRole": "你是黑名单人员,不允许进入本公司,请赶快离开!",
"default": "我是前台小酷,有什么可以帮您?"
}
}
]
}

BIN
public/favicon.ico Прегледај датотеку

Before After

+ 45
- 0
public/index.html Прегледај датотеку

@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="pragma" content="no-cache" />
<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">
<style>
body {
height: 100% !important;
background-color: transparent !important;
}
.dg-main-content {
max-width: 300px !important;
}
.other {
color: red;
}
.dg-content{
text-align: center;
}
.dg-content-body {
border-bottom: none !important;
padding: 15px 0 !important;
}
.el-message-box {
width: 92vw !important;
}
</style>
<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>
<script scr="@/assets/bootstrap.min.js"></script>


</html>

+ 432
- 0
src/App.vue Прегледај датотеку

@@ -0,0 +1,432 @@
<template>
<div id="app" class="no-scrollbar" style="width: 100%;">
<!-- <div
v-show="(this.ws && this.ws.readyState == 1) || !this.ws"
style="position: absolute;background: orangered;width: 2vw;height: 2vh;right: 0"
></div>-->
<div v-if="debug" class="record-wrapper" style="position: absolute;top: 0;z-index: 999;">
<div class="msg msg-right" style="display: contents;">
<div
:key="this.consoleList.index"
class="message-wrapper-right"
style="width:90%;display: flex;background-color: rgba(220,220,220,0.7) !important;border-radius: 2px !important;"
>
<div class="message" style="font-size: 5px !important;text-align: left !important;">
{{ this.consoleList && this.consoleList.time ? this.consoleList.time + ":" : "" }}:{{
(this.consoleList ? this.consoleList.message : "") +
"(pg:" +
this.lastProgress +
";sleep:" +
this.sleep +
";speak:" +
this.isSpeaking +
";state:" +
this.stateVal +
";npl:" +
this.lastNplText +
";tts:" +
this.lastTtsText +
";q:" +
this.lastQText +
";locked:" +
this.execLocked +
";qHandle:" +
this.qHandleType +
")" +
this.otherLog +
JSON.stringify(this.lastPerson) +
this.reqResult +
"noDetectedFace:" +
this.noDetectedFace() +
"noPersonHere:" +
this.noPersonHere()
}}
</div>
<button class="btn" style="position: absolute;top:12vh;" @click="sendMsg(1)">
TEST
</button>
</div>
</div>
</div>
<navigation>
<router-view :style="content"> </router-view>
</navigation>
</div>
</template>

<script>
import Cloudia from "./api/cloudia-sdk-v1.4.1";
import { handleFaceType } from "./utils/handleTts";
import moment from "moment";
import { mapMutations, mapState } from "vuex";
var initTimer2 = 0;

export default {
name: "App",
data() {
return {
isRouterAlive: true,
interactive: "",
content: "",
retryLoadClientType: 0,
lastDetectTs: 0,
lastPersonTs: 0,
lastPerson: {},
sockData: {},
lastNplText: "",
lastTtsText: "",
lastMsDetectTs: 0,
lastMsNlpTimes: 0,
lastDetectObj: {},
lastQText: "",
lastQTs: 0,
execLocked: "",
qHandleType: "",
reqResult: "",
otherLog: "",
otherLog2: "",
sleep: false,
isSpeaking: false,
cameraMode: "level",
jsHandleStateEnabled: false,
jsPlayTtsEnabled: true,
stateVal: "",
ws: null,
times: 0,
timeoutObj: null,
serverTimeoutObj: null,
timeout: 10000,
qData: {},
nlpData: {},
rMsg: {},
heartCheck: {
reset: this.reset,
start: this.start
},
consoleList: {},
debug: this.$cmdList.debug,
connectTimer: null,
strangerDetectTimes: 0
};
},
computed: {
...mapState({
lastProgress: "lastReq",
padInfo: "pad",
lPerson: "lastPerson",
localDev: "localDevInfo",
debugFlag: "debug"
})
},
watch: {
padInfo: {
handler: function(val, oldVal) {
let that = this;
if (val && that.$cmdList.detectedFaceEnable) {
that.wsInit();
}
},
deep: true
}
},
mounted() {
window._ = _;
window.globalVue = this.$children[0];
window.timer = undefined;
window.intimer = undefined;
window.socketTimer = undefined;
window.closeTimer = undefined;
window.Cloudia = Cloudia;
},
destroyed() {
// console.log("=========app destroyed====");
},
methods: {
...mapMutations([
"setLastPerson",
"setLastReq",
"setProgressPerson",
"setLocalDevInfo",
"setRobotMsg",
"setWs"
]),
reset: function() {
this.timeoutObj && clearTimeout(this.timeoutObj);
this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
return this;
},
start: function() {
let self = this;
this.timeoutObj = setTimeout(function() {
self.ws.send("ping");
self.serverTimeoutObj = setTimeout(function() {
self.ws.close();
}, self.timeout);
}, this.timeout);
},
consoleLog(text) {
let ts = new Date().getTime();
this.consoleList = {
index: ts,
message: text,
time: moment(ts).format("mm:ss.SSS")
};
},
setProgressCode(key) {
this.setLastReq(key);
},
sendMsg(type) {
var that = this;
that.setLastReq("dhys");
},

returnAdPage() {
// this.sleep = true;
this.sleep = false;
this.setLastReq("");
this.isSpeaking = false;
this.meetingDateStr = "";
this.meetingTitle = "";
// this.lastMsNlpTimes = 0;
// this.lastMsDetectTs = 0;
this.strangerDetectTimes = 0;
this.msgList = [
{
from: 2,
message: "您好,我是小酷。"
}
];
window.Cloudia && window.Cloudia.setClothes("suit_blue");
},
leaveAdPage() {
this.sleep = false;
// window.Cloudia && window.Cloudia.setClothes("suit_blue");
},
wsInit() {
var that = this;
if (this.padInfo && this.padInfo.ipAddr) {
// let wsUrl = "ws://127.0.0.1:9090";
let wsUrl = "ws://" + this.padInfo.ipAddr + ":9090";
//先判断浏览器是否支持WebSocket
if (typeof WebSocket === "undefined") {
that.$alert("您的浏览器不支持socket");
} else {
// 判断 WebSocket是否已经建立连接,避免重复连接
// this.ws && this.ws.close();
// 新增一个websocket实例,并且建立连接
this.ws = new WebSocket(wsUrl);
// 连接成功后的回调函数
this.ws.onopen = this.handleWsOpen;
// 收到服务器数据后的回调函数
this.ws.onmessage = this.handleWsMessage;
// 连接关闭后的回调函数
this.ws.onclose = this.handleReconnectWs;
// 报错时的回调函数(网络断开,网络不稳定, 用户电脑休眠)
this.ws.onerror = this.handleReconnectWs;

this.setWs(this.ws);
}
} else {
that.handleReconnectWs();
}
},
// ws建立连接
handleWsOpen() {
this.consoleLog("websocket已连接,初始化成功");
this.heartCheck.reset().start();
},
// ws拿到服务器(后端接口)或者客户端(心跳监测或者自测)发送的数据
handleWsMessage(msg) {
this.heartCheck.reset().start();
// 拿到的数据
let result = msg.data;
let that = this;
if (result == "tong") {
return;
}

that.lastDetectTs = new Date().getTime();
that.sockData = JSON.parse(result);
that.consoleLog(JSON.stringify(that.sockData));
if (!that.isSpeaking && (that.lastProgress == "" || that.lastProgress == "moshengren")) {
that.handleDetectedFace(that.sockData);
}
},

// 重连ws
handleReconnectWs() {
this.connectTimer && clearTimeout(this.connectTimer);
let that = this;
that.consoleLog("socket断开链接");
that.times++;
this.connectTimer = setTimeout(() => {
if (that.ws) {
that.consoleLog("重连" + that.times + "次", that.ws.readyState);
// 接已经关闭,或者打开连接失败
if (that.ws.readyState === 3) {
that.wsInit();
}
} else {
that.consoleLog("重连" + that.times + "次");
that.wsInit();
}
}, 3000);
},
handleDetectedFace(obj) {
let that = this;
let str = "";
if (obj && (obj.id == undefined || obj.id == -1)) {
//识别到脸,不是系统里的合法人脸

// let currentTs = new Date().getTime();
// that.lastDetectTs = currentTs; //识别到脸的时间戳
// that.lastMsDetectTs = that.lastMsDetectTs == 0 ? currentTs : that.lastMsDetectTs; //陌生人识别时间戳
that.leaveAdPage();

//陌生人识别3秒,只提示一次
if (that.strangerDetectTimes > 5) {
// that.$alert("moshengren");
// that.strangerDetectTimes = 0;
that.lastDetectObj = obj;
that.lastPerson = {};
that.setLastPerson({});
// that.lastMsDetectTs = 0;
str += handleFaceType(that, obj);
that.sleep = false;
that.rMsg = { text: str, ts: new Date().getTime() };
that.setRobotMsg(that.rMsg);
// that.lastMsNlpTimes++;
} else {
that.strangerDetectTimes++;
}
} else if (obj && (obj.id.length > 6 || obj.id > 0)) {
that.strangerDetectTimes = 0;
//识别到认识的人
// that.lastMsDetectTs = 0;
let currentTs = new Date().getTime();
that.lastDetectTs = currentTs;
that.lastDetectObj = obj;
//识别到人
/*if (obj.name != "") {
if (that.lastProgress == "moshengren") {
// that.setLastReq("");
}
}*/
/*if (that.lastProgress == "moshengren") {
return;
}*/

if (that.lastDetectObj.id === that.lastPerson.id) {
that.lastPerson.name = that.lastDetectObj.name;
that.lastPerson.tag = that.lastDetectObj.tag;
}
//1分钟识别到同一人只执行一次
if (
(obj.id == that.lastPerson.id && (currentTs - that.lastPersonTs >= 60000 || that.sleep)) ||
obj.id != that.lastPerson.id
) {
// that.lastMsNlpTimes = 0;
that.lastPerson = obj;
that.setLastPerson(obj);
that.lastPersonTs = currentTs;
str += handleFaceType(that, obj);
that.rMsg = { text: str, ts: new Date().getTime() };
if (that.lastProgress == "") {
that.setRobotMsg(that.rMsg);
}
that.sleep = false;
that.addMsgList(2, str);
} else {
that.consoleLog("repeat person:" + obj.id);
}
}
},
noDetectedFace() {
let currentTs = new Date().getTime();
if (currentTs - this.lastDetectTs > this.$cmdList.judgeDetectedNoPerson) {
//5秒内没识别
return true;
}
return false;
},
noPersonHere() {
let currentTs = new Date().getTime();
if (currentTs - this.lastQTs > this.$cmdList.judgeNoPerson) {
//15秒钟不说话
return this.noDetectedFace();
}
return false;
},
setIsSpeaking(speak) {
this.isSpeaking = speak;
}
}
};
</script>

<style lang="scss">
* {
margin: 0;
padding: 0;
}

html,
body {
width: 100%;
height: 100%;
overflow-x: hidden;
overflow-y: hidden;
}

.record-wrapper {
margin: 4px;
padding: 4px;
width: 90vw;
}

#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>

+ 452
- 0
src/api/cloudia-sdk-v1.4.1.js Прегледај датотеку

@@ -0,0 +1,452 @@
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 && 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 && 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 && 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 && 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 && 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 && 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 && ue.cloudminds) {
ue.cloudminds.hue(
"updatecharacterrotation",
rotationP + "#$*&@" + rotationY + "#$*&@" + rotationR + "#$*&@" + persistence
);
return true;
}
return false;
},
/**
* 播放动画
* @param name 动画名称
* @param status 动画状态
*/
playMotion(name, status = "") {
if (ue && 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 && 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 && ue.cloudminds) {
ue.cloudminds.hue("setMapBgColor", color);
return true;
}
return false;
},
/**
* @param wall 背景墙资源名称
*/
setBgWallResource(wall) {
if (ue && 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 && 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 && ue.cloudminds) {
ue.cloudminds.hue("setJsHandleStateEnabled", enable.toString());
return true;
}
return false;
},
/**
* 获取deviceId,调用成功之后会在onCmdReceived中收到deviceId的命令
* @deprecated 请改用getRobotInfoConfig("RobotId")方法
*/
getDeviceId() {
if (ue && ue.cloudminds) {
ue.cloudminds.hue("getdeviceid");
return true;
}
return false;
},
getRobotInfoConfig(key) {
if (ue && 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 && ue.cloudminds) {
return ue.cloudminds.hueget("getappconfig");
}
return new Promise(function() {
return "";
});
},
getCharacter() {
if (ue && 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 && 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 && 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 && 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 && ue.cloudminds) {
ue.cloudminds.hue("setAsrWakeUpEnable", enable.toString());
return true;
}
return false;
},
stopPlayTts(playOK = false) {
if (ue && 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 && 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 && 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 && ue.cloudminds) {
ue.cloudminds.hue("enterImmerseMode", immerse.toString());
return true;
}
return false;
},
startVideoTalk() {
if (ue && ue.cloudminds) {
ue.cloudminds.hue("starttalk");
return true;
}
return false;
},
stopVideoTalk() {
if (ue && 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 && 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 && ue.cloudminds) {
ue.cloudminds.hue("setvolume", vol.toString());
return true;
}
return false;
},
getVolume() {
if (ue && ue.cloudminds) {
return ue.cloudminds.hueget("getcurvolume");
}
return new Promise(function() {
return "11";
});
},
downloadFiles(tag, urls) {
if (ue && 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 && ue.cloudminds) {
ue.cloudminds.hue("setcharacterscale", scaleLevel + "#$*&@" + persistence);
return true;
}
},
restartH5() {
if (ue && ue.cloudminds) {
ue.cloudminds.hue("reopenbrowser");
}
},
setState(state) {
if (this.isEmpty(state)) {
console.warn("Invalid call:setState");
return false;
}
if (ue && ue.cloudminds) {
ue.cloudminds.hue("setState", state);
return true;
}
return false;
}
};

BIN
src/assets/back.png Прегледај датотеку

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

+ 3593
- 0
src/assets/bootstrap.min.js
Разлика између датотеке није приказан због своје велике величине
Прегледај датотеку


BIN
src/assets/close.png Прегледај датотеку

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

BIN
src/assets/erji.png Прегледај датотеку

Before After
Width: 200  |  Height: 200  |  Size: 3.1 KiB

BIN
src/assets/home.png Прегледај датотеку

Before After
Width: 200  |  Height: 200  |  Size: 2.9 KiB

BIN
src/assets/ic_back.png Прегледај датотеку

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

BIN
src/assets/ic_photo_error.png Прегледај датотеку

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

BIN
src/assets/ic_photo_loading.png Прегледај датотеку

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

BIN
src/assets/loading2.gif Прегледај датотеку

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

BIN
src/assets/logo-digimeta.png Прегледај датотеку

Before After
Width: 770  |  Height: 324  |  Size: 42 KiB

BIN
src/assets/logo.png Прегледај датотеку

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

BIN
src/assets/logo_new.png Прегледај датотеку

Before After
Width: 990  |  Height: 1154  |  Size: 23 KiB

BIN
src/assets/logo_wh.png Прегледај датотеку

Before After
Width: 2242  |  Height: 572  |  Size: 50 KiB

+ 125
- 0
src/components/Alert.vue Прегледај датотеку

@@ -0,0 +1,125 @@
<template>
<transition name="fade">
<div v-show="show" class="alert-box-wrapper">
<div class="alert-box">
<div class="alert-box-header">
<div class="alert-box-title">{{ title }}</div>
<div class="alert-box-headerbtn" @click="handleAction('close')">X</div>
</div>
<div class="alert-box-content">
<div class="alert-box-container">{{ message }}</div>
</div>
<div class="alert-box-btns">
<button class="cancel-btn" @click="handleAction('cancel')">{{ cancelText }}</button>
<button class="confirm-btn" @click="handleAction('confirm')">{{ confirmText }}</button>
</div>
</div>
</div>
</transition>
</template>

<script>
export default {
name: "Alert",
data() {
return {
title: "标题",
message: "这是一段提示内容",
show: false,
callback: null,
cancelText: "取消",
confirmText: "确定"
};
},
methods: {
handleAction(action) {
this.callback(action);
this.destroyVm();
},
destroyVm() {
// 销毁
this.show = false;
setTimeout(() => {
this.$destroy(true);
this.$el && this.$el.parentNode.removeChild(this.$el);
}, 500);
}
}
};
</script>

<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}

.alert-box-wrapper {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.5);
.alert-box {
display: inline-block;
width: 92vw;
padding-bottom: 10px;
background-color: #fff;
border-radius: 4px;
border: 1px solid #303133;
font-size: 16px;
text-align: left;
overflow: hidden;
.alert-box-header {
position: relative;
padding: 15px;
padding-bottom: 10px;
.alert-box-title {
color: #303133;
}
.alert-box-headerbtn {
position: absolute;
top: 15px;
right: 15px;
cursor: pointer;
color: #909399;
}
}
.alert-box-content {
padding: 10px 15px;
color: #606266;
font-size: 14px;
}
.alert-box-btns {
padding: 5px 15px 0;
text-align: right;
.cancel-btn {
padding: 5px 15px;
background: #fff;
border: 1px solid #dcdfe6;
border-radius: 4px;
outline: none;
cursor: pointer;
}
.confirm-btn {
margin-left: 6px;
padding: 5px 15px;
color: #fff;
background-color: #409eff;
border: 1px solid #409eff;
border-radius: 4px;
outline: none;
cursor: pointer;
}
}
}
}
</style>

+ 685
- 0
src/components/DemoView.vue Прегледај датотеку

@@ -0,0 +1,685 @@
<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 v-if="false" :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 v-if="false" :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 v-if="false" :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 v-if="false" :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 v-if="false" :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 v-if="false" :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 v-if="false" :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 v-if="false" :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 v-if="false" :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
v-if="false"
: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 v-if="false" :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 v-if="false" :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 v-if="false" :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 v-if="false" :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
v-if="false"
: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 v-if="false" :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 v-if="false" :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 v-if="false" :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 v-if="false" :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 v-if="false" :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 v-if="false" :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 v-if="false" :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 v-if="false" 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;

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 = window.Cloudia.showToast(this.toast);
this.allInterfaces["interfaceShowToast"] = result ? 1 : 2;
},
interfaceShowLongToast() {
let result = window.Cloudia.showLongToast(this.longToast);
this.allInterfaces["interfaceShowLongToast"] = result ? 1 : 2;
},
interfacePlayTts() {
let result = window.Cloudia.playTts(this.tts);
if (result) {
this.iPlayTts = true;
timer && window.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 = window.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 = window.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 = window.Cloudia.updateCharacterRotation(rotation[0], rotation[1], rotation[2], rotation[3]);
this.allInterfaces["interfaceUpdateCharacterRotation"] = result ? 1 : 2;
},
interfaceUpdateWallLocation() {
let result = window.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 = window.Cloudia.playMotion(params[0], params[1]);
} else {
result = window.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 = window.Cloudia.setBgWallColor(r + ", " + g + ", " + b);
this.allInterfaces["interfaceSetBgWallColor"] = result ? 1 : 2;
},
interfaceSetBgWallRes() {
let result = window.Cloudia.setBgWallResource(this.wallRes);
this.allInterfaces["interfaceSetBgWallRes"] = result ? 1 : 2;
},
interfaceGetDeviceId() {
let that = this;
this.iGetRobotConfig = true;
return window.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 window.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 = window.Cloudia.setCharacter(this.character);
this.allClothes = cloudiaConfig.allClothes;
this.clothes = this.allClothes[0];
this.allInterfaces["interfaceSetCharacter"] = result ? 1 : 2;
return result;
},
interfaceSetClothes() {
let result = window.Cloudia.setClothes(this.clothes);
this.allInterfaces["interfaceSetClothes"] = result ? 1 : 2;
},
interfacePostMediaEvent() {
let result = window.Cloudia.postMediaEvent(this.mediaEvent);
this.allInterfaces["interfacePostMediaEvent"] = result ? 1 : 2;
},
interfaceSetAsrWakeUpEnable() {
let result = window.Cloudia.setAsrWakeUpEnable(this.asrWakeUp);
if (result) {
this.iAsrWakeUp = true;
timer && window.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 = window.Cloudia.stopPlayTts(false);
this.allInterfaces["interfaceStopPlayTts"] = result ? 1 : 2;
},
interfaceEnterImmerseMode() {
let result = window.Cloudia.enterImmerseMode(this.immerseMode);
this.allInterfaces["interfaceEnterImmerseMode"] = result ? 1 : 2;
},
interfaceStartVideoTalk() {
let result = window.Cloudia.startVideoTalk();
this.allInterfaces["interfaceStartVideoTalk"] = result ? 1 : 2;
},
interfaceStopVideoTalk() {
let result = window.Cloudia.stopVideoTalk();
this.allInterfaces["interfaceStopVideoTalk"] = result ? 1 : 2;
},
interfaceSetVolume() {
let result = window.Cloudia.setVolume(this.setValueText);
this.allInterfaces["interfaceSetVolume"] = result ? 1 : 2;
},
interfaceGetVolume() {
this.iGetVolume = true;
return window.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 = window.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 = window.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事件中收到通知
window.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);
});
},

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(this.$cmdList.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 && window.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.2vh;
justify-content: left;
width: 30%;
text-align: left;
}

.input-text {
height: 2vh;
line-height: 2vh;
font-size: 1vh;
color: black;
text-align: left;
width: 20vw;
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>

+ 98
- 0
src/components/DialogMeetingAppointOK.vue Прегледај датотеку

@@ -0,0 +1,98 @@
<template>
<div v-if="showMeetingAppoint" class="root" @click="close($event)">
<div ref="content" class="content">
<div class="appoint-info">预约成功</div>
<div class="oppoint-time-div">
<div class="appoint-info">您已完成会议预约</div>
<div class="appoint-info">主题:{{ topic }}</div>
<div class="appoint-info">会议室:{{ meetingRoom }}</div>
<div v-for="(time, index) in timeList" :key="index" class="appoint-time-item">
{{ time }}
</div>
</div>
<div class="appoint-info">{{ timeCount }}秒后自动关闭</div>
</div>
</div>
</template>
<script>
import { mapMutations } from "vuex";

export default {
props: ["showMeetingAppoint", "topic", "meetingRoom", "times"],
data() {
return {
timeList: [],
timeCount: 3
};
},
mounted() {},
methods: {
...mapMutations(["setLastAction"]),
close(ev) {
if (this.$refs.content && !this.$refs.content.contains(ev.target)) {
this.$emit("showMeetingAppointResult");
}
},
quit() {
this.$emit("showMeetingAppointResult");
}
},
watch: {
times(newVal, oldVal) {
//console.log(newVal)
//console.log(JSON.stringify(newVal))
this.timeList = newVal;
},
showMeetingAppoint(newVal, oldVal) {
if (newVal) {
this.setLastAction("meetingOk");
let self = this;
var timeId = setInterval(function() {
self.timeCount -= 1;
if (self.timeCount == 0) {
clearInterval(timeId);
self.quit();
}
}, 1000);
}
}
}
};
</script>
<style lang="scss" scoped>
.root {
position: fixed;
top: 0;
left: 0;
background: transparent;
width: 100vw;
height: 100vh;
z-index: 2;
}
.content {
position: absolute;
left: 5%;
top: 20%;
/*transform: translate(-50%, -50%);*/
z-index: 10;
width: 90%;
padding: 10px;
border-radius: 5px;
overflow: hidden;
background: white;
}
.appoint-info {
padding: 10px;
color: black;
font-size: 16px;
text-align: center;
}
.appoint-time-item {
padding: 3px;
color: black;
font-size: 16px;
text-align: center;
}
.oppoint-time-div {
}
</style>

+ 94
- 0
src/components/DialogMeetingCancelOK.vue Прегледај датотеку

@@ -0,0 +1,94 @@
<template>
<div v-if="showMeetingCancel" class="root" @click="close($event)">
<div ref="content" class="content">
<div class="appoint-info">已取消预约</div>
<div class="oppoint-time-div">
<div class="appoint-info">会议预约详情</div>
<div class="appoint-info">主题:{{ order.meetingTitle }}</div>
<div class="appoint-info">会议室:{{ order.roomName }}</div>
<div class="appoint-info">{{ order.orderDate }},{{ order.orderTime }}至{{ order.endTime }}</div>
</div>
<div class="appoint-info">{{ timeCount }}秒后自动关闭</div>
</div>
</div>
</template>
<script>
import { mapMutations } from "vuex";

export default {
props: ["showMeetingCancel", "order"],
data() {
return {
timeList: [],
timeCount: 3,
curOrder: {}
};
},
watch: {
order(newVal, oldVal) {
//console.log(newVal)
//console.log(JSON.stringify(newVal))
this.setLastAction("meetingCancel");
this.curOrder = newVal;
let self = this;
var timeId = setInterval(function() {
self.timeCount -= 1;
if (self.timeCount == 0) {
clearInterval(timeId);
self.quit();
self.timeCount = 3;
}
}, 1000);
}
},
mounted() {},
methods: {
...mapMutations(["setLastAction"]),
close(ev) {
if (this.$refs.content && !this.$refs.content.contains(ev.target)) {
this.$emit("showMeetingCancelResult");
}
},
quit() {
this.$emit("showMeetingCancelResult");
}
}
};
</script>
<style lang="scss" scoped>
.root {
position: fixed;
top: 0;
left: 0;
background: #efefef;
width: 100vw;
height: 100vh;
z-index: 2;
}
.content {
position: absolute;
left: 5%;
top: 30%;
/*transform: translate(-50%, -50%);*/
z-index: 10;
width: 90%;
padding: 10px;
border-radius: 5px;
overflow: hidden;
background: white;
}
.appoint-info {
padding: 10px;
color: black;
font-size: 16px;
text-align: center;
}
.appoint-time-item {
padding: 3px;
color: black;
font-size: 16px;
text-align: center;
}
.oppoint-time-div {
}
</style>

+ 69
- 0
src/components/DialogMeetingRoom.vue Прегледај датотеку

@@ -0,0 +1,69 @@
<template>
<div v-if="showMeetingRoom" class="root" @click="close($event)">
<div class="content" ref="content" :styles="{top: contentTop + 'px', left: 0}">
<div v-for="(room, index) in rooms"
class="room-item"
:key="index"
@click="selectRoom(room)">
{{room.name}}
</div>
</div>
</div>
</template>
<script>
export default {
props: ["rooms", "top", "showMeetingRoom"],
data(){
return{
contentTop: 0,
}
},
created() {
this.contentTop = this.top
console.log();
},
methods: {
close(ev) {
if(this.$refs.content && !this.$refs.content.contains(ev.target)){
let data = {room:null}
this.$emit("showRooms", data);
}
},
selectRoom(room){
let data = {room:room}
this.$emit("showRooms", data);
}
},
watch: {
top(newVal, oldVal) {
console.log('-----' + newVal);
this.popupTop = newVal
},
},
}
</script>
<style lang="scss" scoped>
.root{
position: fixed;
top: 0;
left: 0;
background: transparent;
width: 100vw;
height: 100vh;
z-index: 2;
}
.content{
position: absolute;
/*transform: translate(-50%, -50%);*/
z-index: 10;
left: 0;
top: 40%;
width: 100%;
border-radius: 5px;
overflow: hidden;
}
.room-item{
padding: 10px;
background: white;
}
</style>

+ 68
- 0
src/components/DialogMeetingTopic.vue Прегледај датотеку

@@ -0,0 +1,68 @@
<template>
<div v-if="showMeetingTopic" class="root" @click="close($event)">
<div class="content" ref="content">
<div v-for="(topic, index) in topics"
class="topic-item"
:key="index"
@click="selectTopic(topic)">
{{topic}}
</div>
</div>
</div>
</template>
<script>
export default {
props: ["topics", "top", "showMeetingTopic"],
data(){
return{
contentTop: 0,
}
},
created() {
this.contentTop = this.top
console.log();
},
methods: {
close(ev) {
if(this.$refs.content && !this.$refs.content.contains(ev.target)){
let data = {topic: null}
this.$emit("showTopics", data);
}
},
selectTopic(topic){
let data = {topic: topic}
this.$emit("showTopics", data);
}
},
watch: {
top(newVal, oldVal) {
console.log('-----' + newVal);
this.contentTop = newVal
},
},
}
</script>
<style lang="scss" scoped>
.root{
position: fixed;
top: 0;
left: 0;
background: transparent;
width: 100vw;
height: 100vh;
z-index: 2;
}
.content{
position: absolute;
left: 0;
top: 40%;
z-index: 10;
width: 100%;
border-radius: 5px;
overflow: hidden;
}
.topic-item{
padding: 10px;
background: white;
}
</style>

+ 82
- 0
src/components/DialogMeetingTopicDefine.vue Прегледај датотеку

@@ -0,0 +1,82 @@
<template>
<div v-if="showMeetingTopicDefine" class="root" @click="close($event)">
<div ref="content" class="content">
<div class="meeting-topic">会议主题</div>
<input v-model="topic" class="topic_input" type="text" placeholder="请输入会议主题" />
<div class="confirm-div">
<div class="meeting-topic-confirm" @click="confirm">确定</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: ["showMeetingTopicDefine"],
data() {
return {
topic: ""
};
},
methods: {
close(ev) {
if (this.$refs.content && !this.$refs.content.contains(ev.target)) {
this.$emit("showTopicsDefine", null);
}
},
confirm() {
console.log(this.topic);
this.$emit("showTopicsDefine", this.topic);
}
}
};
</script>
<style lang="scss" scoped>
.root {
position: fixed;
top: 0;
left: 0;
background: transparent;
width: 100vw;
height: 100vh;
z-index: 2;
}
.content {
position: absolute;
left: 5%;
top: 40%;
/*transform: translate(-50%, -50%);*/
z-index: 10;
width: 90%;
padding: 10px;
border-radius: 5px;
overflow: hidden;
background: white;
}
.meeting-topic {
padding: 10px;
color: black;
font-size: 18px;
text-align: center;
}
.topic_input {
padding: 10px;
margin-top: 10px;
}
.confirm-div {
display: flex;
flex-direction: row;
justify-content: center;
margin-top: 20px;
}
.meeting-topic-confirm {
padding-left: 50px;
padding-right: 50px;
padding-top: 10px;
padding-bottom: 10px;
color: white;
font-size: 16px;
font-weight: bold;
border-radius: 10px;
background: #1ca7f5;
}
</style>

+ 89
- 0
src/components/DialogVisitorAppointOK.vue Прегледај датотеку

@@ -0,0 +1,89 @@
<template>
<div v-if="showVisitorAppoint" class="root" @click="close($event)">
<div ref="content" class="content">
<div class="appoint-info">预约成功!</div>
<div class="appoint-time-div">
<div class="appoint-info">预约访客名称:{{ visitorName }}</div>
<div class="appoint-info">预约人:{{ appointName }}</div>
<div class="appoint-info">访客到达后联系手机号:{{ appointPhone }}</div>
</div>
<div class="appoint-tip">客人到访登记后会请客人在休息区等您,同时为您发送提醒短信。</div>
<div class="appoint-info">{{ timeCount }}秒后自动关闭</div>
</div>
</div>
</template>
<script>
import { mapMutations } from "vuex";

export default {
props: ["showVisitorAppoint", "visitorName", "appointName", "appointPhone"],
data() {
return {
timeCount: 3
};
},
mounted() {},
methods: {
...mapMutations(["setLastAction"]),
close(ev) {
if (this.$refs.content && !this.$refs.content.contains(ev.target)) {
this.$emit("showVisitorAppointResult");
}
},
quit() {
this.$emit("showVisitorAppointResult");
}
},
watch: {
showVisitorAppoint(newVal, oldVal) {
if (newVal) {
let self = this;
this.setLastAction("visitorAppoint");
var timeId = setInterval(function() {
self.timeCount -= 1;
if (self.timeCount == 0) {
clearInterval(timeId);
self.quit();
self.timeCount = 3;
}
}, 1000);
}
}
}
};
</script>
<style lang="scss" scoped>
.root {
position: fixed;
top: 0;
left: 0;
background: #00efefef;
width: 100vw;
height: 100vh;
z-index: 2;
}
.content {
position: absolute;
left: 5%;
top: 30%;
/*transform: translate(-50%, -50%);*/
z-index: 10;
width: 90%;
padding: 10px;
border-radius: 5px;
overflow: hidden;
background: white;
}
.appoint-info {
padding: 10px;
color: black;
font-size: 16px;
text-align: center;
}
.appoint-tip {
padding: 10px;
color: #efefef;
font-size: 16px;
text-align: center;
}
</style>

+ 85
- 0
src/components/DialogVisitorRegisterOK.vue Прегледај датотеку

@@ -0,0 +1,85 @@
<template>
<div v-if="showVisitorRegister" class="root" @click="close($event)">
<div ref="content" class="content">
<div class="register-info">已完成登记</div>
<div class="register-time-div">
<div class="register-info">到访客人:{{ visitorName }}</div>
</div>
<div class="register-info">{{ timeCount }}秒后自动关闭</div>
</div>
</div>
</template>
<script>
import { mapMutations } from "vuex";
export default {
props: ["showVisitorRegister", "visitorName"],
data() {
return {
timeCount: 3
};
},
mounted() {},
methods: {
...mapMutations(["setLastAction"]),
close(ev) {
if (this.$refs.content && !this.$refs.content.contains(ev.target)) {
this.$emit("showVisitorRegisterResult");
}
},
quit() {
this.$emit("showVisitorRegisterResult");
}
},
watch: {
showVisitorRegister(newVal, oldVal) {
if (newVal) {
this.setLastAction("visitorReg");
let self = this;
var timeId = setInterval(function() {
self.timeCount -= 1;
if (self.timeCount == 0) {
clearInterval(timeId);
self.quit();
self.timeCount = 3;
}
}, 1000);
}
}
}
};
</script>
<style lang="scss" scoped>
.root {
position: fixed;
top: 0;
left: 0;
background: #00efefef;
width: 100vw;
height: 100vh;
z-index: 2;
}
.content {
position: absolute;
left: 5%;
top: 30%;
/*transform: translate(-50%, -50%);*/
z-index: 10;
width: 90%;
padding: 10px;
border-radius: 5px;
overflow: hidden;
background: white;
}
.register-info {
padding: 10px;
color: black;
font-size: 16px;
text-align: center;
}
.register-tip {
padding: 10px;
color: #efefef;
font-size: 16px;
text-align: center;
}
</style>

+ 398
- 0
src/components/JsonView.vue Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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 && window.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 && window.clearTimeout(timer);
timer = setTimeout(function() {
//要确认changePointActiveIndex是不是还是目前的activeIndex,是的话计时后执行,不是的话不执行
if (changePointActiveIndex === swiper.activeIndex) {
swiper.slideNext();
}
}, 5000);
} else {
timer && window.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>

+ 29
- 0
src/config/index.js Прегледај датотеку

@@ -0,0 +1,29 @@
export default {
/**
* @description 是否输出调试信息
*/
isDebuggable: process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test",

/**
* @description api请求基础路径
*/
baseUrl: process.env.VUE_APP_SERVER_URL,

appTitle: "缔智园数字人",
userType: {
mgr: 0,
emp: 1,
keyVisitor: 2,
courier: 3,
blackRole: 4,
visitor: 5
},
userTypeCn: {
0: "高管",
1: "员工",
2: "VIP客户",
3: "快递员",
4: "黑名单",
5: "访客"
}
};

+ 21
- 0
src/db/dbHelp.js Прегледај датотеку

@@ -0,0 +1,21 @@
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);
}
);
}
};

+ 88
- 0
src/db/dbRouter.js Прегледај датотеку

@@ -0,0 +1,88 @@
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;

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

// 接口:用户管理分页接口查询
router.get("/getlist", (req, res) => {
const params = req.body;
console.log(params);
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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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;

+ 70
- 0
src/main.js Прегледај датотеку

@@ -0,0 +1,70 @@
import Vue from "vue";
import App from "@/App.vue";
import router from "@/router";

import _ from "lodash";

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;

import "./assets/bootstrap.min.js";

/*import socket from "./mixins/socket";
Vue.prototype.sock = socket;*/

import Alert from "./components/Alert";
Vue.use(Alert);

import store from "./store";
function bindData() {
if (count == 1) {
app = new Vue({
router,
store,
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;
Vue.prototype._ = _;
bindData();
}
});

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;
};
export default Vue;

+ 274
- 0
src/mixins/mixin.js Прегледај датотеку

@@ -0,0 +1,274 @@
import { handleNlp } from "../utils/handleNlp";
import { handleQEvent } from "../utils/handleQ";
import { containObjByCode } from "../utils/common";
import { mapMutations, mapState } from "vuex";
import Cloudia from "../api/cloudia-sdk-v1.4.1";
const FormData = require("form-data");

/**
* 通用的方法和一些与业务无关的工具方法
*
*/
const mixin = {
data() {
return {
playerOptions: {},
devCode: "",
picUrl: "",
picVisible: false,
videoVisible: false,
jsPlayTtsEnabled: true,
jsHandleStateEnabled: false
};
},
computed: {
...mapState({
debugFlag: "debug"
})
},
methods: {
...mapMutations(["setLastPerson", "setProgressPerson", "setLocalDevInfo", "setPad", "setDebug"]),
jsonpRequest(url) {
return new Promise((resolve, reject) => {
const callbackName = "jsonpCallback"; // 回调函数名

// 创建一个 script 元素
const script = document.createElement("script");
script.src = url + (url.indexOf("?") === -1 ? "?" : "&") + "callback=" + callbackName;
document.body.appendChild(script);

// 设置回调函数
window[callbackName] = (data) => {
delete window[callbackName];
document.body.removeChild(script);
resolve(data);
};

// 请求失败处理
script.onerror = (error) => {
delete window[callbackName];
document.body.removeChild(script);
reject(error);
};
});
},
cloudiaInit() {
let that = this;
try {
if (Cloudia && Cloudia.init) {
Cloudia.init(
function(cmd, params) {
switch (cmd) {
case "onBind":
that.character = params.currentCharacter;
that.allClothes = window.cloudiaConfig.allClothes;
break;
case "setState":
if ("GREET" == params.state) {
that.tabIndex = 0;
that.$parent.$data.sleep = false;
// that.isSpeaking = false;
}
that.$parent.$data.stateVal = params.state;
break;
case "event":
that.cloudiaEvents[params["name"]] = params["info"]["status"];
break;
case "nlp":
handleNlp(that, params);
break;
case "event":
//人脸处理不通过达闼
if ("faceDetected" == params.name) {
}
break;
case "q":
handleQEvent(that, params);
break;
default:
break;
}
},
{
jsHandleTts: that.jsPlayTtsEnabled,
jsHandleState: that.jsHandleStateEnabled,
cameraMode: that.cameraMode
}
);
Cloudia.setWalkGreetingEnable(false);
Cloudia.setAsrWakeUpEnable(true);
}
} catch (e) {
that.$parent.consoleLog(e.message);
}
},
mixinMethod() {
let that = this;
if (!(that.localDev && that.$pad)) {
that.cloudiaInit();
that.$nextTick(function() {
Cloudia.getRobotInfoConfig("RobotId").then(function(ReturnValue) {
let RobotId = ReturnValue.ReturnValue;
// let RobotId = "864972045000846";
that.devCode = RobotId;
//绑定本设备相关信息
that.localDevInfo = containObjByCode(that.$cmdList["devMappings"], that.devCode);
that.setLocalDevInfo(that.localDevInfo);
that.$axios.get("/srv/api/device/getPadExt?deviceId=" + RobotId).then((res) => {
if (res.data) {
that.$pad = res.data.data;
console.log(JSON.stringify(that.$pad));
that.setPad(that.$pad);
that.otherLog2 = "padInfo:" + JSON.stringify(that.$pad);
}
});
});
that.updLocation();
});
}
},
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);
}
},
playPic(src) {
if (src) {
this.videoVisible = false;
this.tabIndex = 5;
this.picUrl = src;
this.picVisible = true;

var that = this;
setTimeout(function() {
that.picVisible = false;
}, 5000);
}
},

enterImmerseMode(mode) {
Cloudia.enterImmerseMode(mode);
},

queryNlp() {
let that = this;
this.$axios.get(this.$cmdList.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.setDebug(!this.debugFlag);
this.showMsg = !this.showMsg;
this.$parent.$data.debug = !this.$parent.$data.debug;
}
},
homeEvent() {
// this.$parent.$data.ws.send("pic1");
this.jsonpRequest(this.$cmdList.handleUrl + "pic1")
.then((data) => {})
.catch((error) => {});
},
companyEvent() {
let that = this;

this.jsonpRequest(this.$cmdList.handleUrl + "pic2")
.then((data) => {})
.catch((error) => {});

this.jsonpRequest(this.$cmdList.handleUrl + "name=play")
.then((data) => {})
.catch((error) => {});

this.jsonpRequest(this.$cmdList.handleUrl + "speed=0.13")
.then((data) => {})
.catch((error) => {});

if (that.$parent.$data.isSpeaking) {
that.$parent.setIsSpeaking(false);
window.Cloudia.stopPlayTts();
that.jsonpRequest(this.$cmdList.handleUrl + "name=stop")
.then((data) => {})
.catch((error) => {});
} else {
setTimeout(function() {
that.addMsgList(
2,
"协合新能源集团创立于二零零六年,自创立之初便致力于风电项目的建设,并在二零零六年成功投产了首个风电项目、、位于辽宁昌图的五十兆瓦风电场。随后的二零零七年,集团于香港联交所上市,成为中国内地和香港市场上首家风电上市企业。二零零八年,集团初步形成了纵向一体化风电产业链,包括制造、开发、建设和营运等环节、在二零零九年集团进入发展的快车道,并与多家国内外大型发电企业建立战略合作关系,权益装机容量首次超过五百兆瓦。在二零一零年,集团发展达到了阶段高峰,年度净利润达到四点二七亿港币,累计投资的风电项目数量达到二十七个,共计装机容量达到一千七百一十兆瓦,并与国际金融公司IFC实现合作。随后,在二零一一年,集团积极实施向南发展和向太阳能发展的战略,成功并网了首个光伏电站。二零一二年,首个海外光伏项目、美国纽约分布式光伏项目也投产、、经过多年实践,集团资产结构和资产质量持续优化,并于二零一六年成功发行了国内首单非金融企业绿色债券。在二零一七年,集团获得了国际信用评级机构的BB评级,并发布了智慧能源解决方案POWER加。二零一八年,权益装机容量突破了二百万千瓦。二零一九年,集团首个平价项目当年开工、当年投产,这展示了我们已迈入平价时代。二零二零年,尽管受到疫情影响,集团仍始终坚持项目的建设,并取得了资产结构和质量的极大提升,实现持续滚动发展。二零二一年,集团实现了年投产容量百万千瓦,并创造了二百兆瓦电站工程最短工期记录。在二零二二年,开发指标创下了历史新高,基地项目申报实现零的突破,连续实现年投产容量超过百万千瓦,并在MSCI的ESG评级中获评为A级、、协合新能源集团从成立伊始就以发展绿色能源为己任,追求可持续发展,而历经多年的努力和拼搏,已初步建立了一条完整的绿色发展产业链,未来也将围绕用清洁能源创造更好未来的核心价值观,促进企业与社会的可持续发展。"
);
}, 800);
}
},
updLocation() {
window.Cloudia.setBgWallResource("Landscape");
// window.Cloudia.updateCharacterLocation(-500, 0, 450);
},

_clearCache() {
localStorage.clear();
},

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

+ 95
- 0
src/mixins/socket.js Прегледај датотеку

@@ -0,0 +1,95 @@
let isConnect = false;
const socket = {
components: {},

websock: null,
times: 0,
timeout: 10000,
timeoutObj: null,
serverTimeoutObj: null,
heartCheck: {
reset: function() {
console.log(this);
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
return this;
},
start: function() {
var self = this;
this.timeoutObj = setTimeout(function() {
//这里发送一个心跳,后端收到后,返回一个心跳消息,
//onmessage拿到返回的心跳就说明连接正常
self.websock.send("ping");
self.serverTimeoutObj = setTimeout(function() {
//如果超过一定时间还没重置,说明后端主动断开了
self.websock.close(); //如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
}, self.timeout);
}, this.timeout);
}
},

initWebSocket() {
try {
// const path = Config.padSocketUrl; // 后台给的websocket的ip地址
console.log("---==-=-=-=-=");
// if (this.$pad && this.$pad.ipAddr) {
const path = "ws://192.168.33.251:9090"; // 后台给的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;
/*} else {
this.reConnect();
}*/
} catch (e) {
this.reConnect();
console.log(e);
}
},
reConnect() {
if (isConnect) {
this.consoleLog("重连成功!");
return;
} //如果已经连上就不在重连了
window.socketTimer && window.clearTimeout(window.socketTimer);
let that = this;
window.socketTimer = setTimeout(function() {
// 延迟5秒重连 避免过多次过频繁请求重连
that.initWebSocket();
that.times++;
}, 5000);
},
// 连接建立成功的信号
websocketOnOpen() {
console.log(22);
isConnect = true;
this.times = 0;
this.heartCheck.reset().start();
},
// 连接建立失败重连
websocketOnError() {
// 如果报错的话,在这里就可以重新初始化websocket,这就是断线重连
this.websock = null;
isConnect = false; //连接断开修改标识
this.reConnect(); //连接错误 需要重连
},

// 数据发送
websocketSend(Data) {
if (typeof Data == "object") {
Data = JSON.stringify(Data);
}
this.otherLog = "send to serv:" + Data;
if (this.socket && this.socket.readyState === 1) {
this.websock.send(Data); // Data变量就是你想对后台说些啥,根据后端给你的接口文档传值进行交互
}
},
// 关闭的信号
websocketClose() {
this.websock = null;
isConnect = false; //连接断开修改标识
this.reConnect(); //服务器主动断开的情况下,需要重连
}
};
export default socket;

+ 5
- 0
src/packages/meta.js Прегледај датотеку

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

export { MetaHelp };

+ 87
- 0
src/packages/nf-meta/help.js Прегледај датотеку

@@ -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;
}
}

+ 138
- 0
src/packages/nf-meta/loadmeta-json.js Прегледај датотеку

@@ -0,0 +1,138 @@
// 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;

+ 209
- 0
src/packages/nf-meta/loadmeta-sql.js Прегледај датотеку

@@ -0,0 +1,209 @@
/**
* 从 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 Прегледај датотеку

@@ -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]).onsuccess = (event) => {
// 添加一条meta
count -= 1;
if (count === 0) {
resolve(event.target.result);
}
};
} else {
// 修改
store.put(meta[key]).onsuccess = (event) => {
// 修改一条meta
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
};

+ 114
- 0
src/packages/nf-ws-indexeddb/_toIndex.js Прегледај датотеку

@@ -0,0 +1,114 @@
/**
* 一般查询方式的字典
*/
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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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;

+ 270
- 0
src/packages/nf-ws-indexeddb/help.js Прегледај датотеку

@@ -0,0 +1,270 @@
// 加载操作函数
// 对象仓库的操作
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);
}
}

+ 146
- 0
src/packages/nf-ws-indexeddb/install.js Прегледај датотеку

@@ -0,0 +1,146 @@
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];
}
};

+ 106
- 0
src/packages/nf-ws-indexeddb/list-all.js Прегледај датотеку

@@ -0,0 +1,106 @@
/**
* 不分页获取数据,可以查询
* @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 Прегледај датотеку

@@ -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;

+ 124
- 0
src/packages/nf-ws-indexeddb/list-pager.js Прегледај датотеку

@@ -0,0 +1,124 @@
/**
* 获取分页列表数据
* @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);
}
});
}

+ 37
- 0
src/packages/nf-ws-indexeddb/model-add.js Прегледај датотеку

@@ -0,0 +1,37 @@
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 Прегледај датотеку

@@ -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);
}
});
}

+ 34
- 0
src/packages/nf-ws-indexeddb/model-delete.js Прегледај датотеку

@@ -0,0 +1,34 @@
/**
* 删除对象
* @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 Прегледај датотеку

@@ -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);
}
});
}

+ 45
- 0
src/packages/nf-ws-indexeddb/model-put.js Прегледај датотеку

@@ -0,0 +1,45 @@
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);
}
});
}

+ 56
- 0
src/packages/nf-ws-indexeddb/model-set.js Прегледај датотеку

@@ -0,0 +1,56 @@
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);
}
});
}

+ 31
- 0
src/packages/nf-ws-indexeddb/store-clear.js Прегледај датотеку

@@ -0,0 +1,31 @@
/**
* 清空仓库 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().onsuccess = (event) => {
// 删除store
// 成功后的回调
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 Прегледај датотеку

@@ -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;

+ 81
- 0
src/packages/nf-ws-websql/_where-query.js Прегледај датотеку

@@ -0,0 +1,81 @@
/**
* 内部函数,根据查询条件,拼接查询用的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;

+ 52
- 0
src/packages/nf-ws-websql/data-add.js Прегледај датотеку

@@ -0,0 +1,52 @@
/**
* 实现添加数据的功能。拼接 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;
}

+ 30
- 0
src/packages/nf-ws-websql/data-delete.js Прегледај датотеку

@@ -0,0 +1,30 @@
/**
* 实现删除数据的功能。物理删除,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;
}

+ 31
- 0
src/packages/nf-ws-websql/data-deleteflag.js Прегледај датотеку

@@ -0,0 +1,31 @@
/**
* 实现删除数据的功能。逻辑删除,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;
}

+ 30
- 0
src/packages/nf-ws-websql/data-get.js Прегледај датотеку

@@ -0,0 +1,30 @@
/**
* 依据主键字段,获取记录
* @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;
}

+ 55
- 0
src/packages/nf-ws-websql/data-set.js Прегледај датотеку

@@ -0,0 +1,55 @@
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;
}

+ 49
- 0
src/packages/nf-ws-websql/data-update.js Прегледај датотеку

@@ -0,0 +1,49 @@
/**
* 实现修改数据的功能。拼接 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;
}

+ 27
- 0
src/packages/nf-ws-websql/db-delete.js Прегледај датотеку

@@ -0,0 +1,27 @@
/**
* 删除数据库
* @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;
}

+ 211
- 0
src/packages/nf-ws-websql/help.js Прегледај датотеку

@@ -0,0 +1,211 @@
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;

+ 150
- 0
src/packages/nf-ws-websql/install.js Прегледај датотеку

@@ -0,0 +1,150 @@
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];
}
};

+ 50
- 0
src/packages/nf-ws-websql/list-all.js Прегледај датотеку

@@ -0,0 +1,50 @@
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;
}

+ 33
- 0
src/packages/nf-ws-websql/list-count.js Прегледај датотеку

@@ -0,0 +1,33 @@
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);
});
});
}

+ 53
- 0
src/packages/nf-ws-websql/list-pager.js Прегледај датотеку

@@ -0,0 +1,53 @@
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;
}

+ 39
- 0
src/packages/nf-ws-websql/table-create.js Прегледај датотеку

@@ -0,0 +1,39 @@
/**
* 实现删除数据的功能。逻辑删除,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;
}

+ 27
- 0
src/packages/nf-ws-websql/table-delete.js Прегледај датотеку

@@ -0,0 +1,27 @@
/**
* 实现删除数据的功能。逻辑删除,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 Прегледај датотеку

@@ -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 // 组件里获取对象仓库,方便实现增删改查
};

+ 127
- 0
src/packages/vue-localstore/index.js Прегледај датотеку

@@ -0,0 +1,127 @@
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
};
};

+ 415
- 0
src/plugins/db.js Прегледај датотеку

@@ -0,0 +1,415 @@
// 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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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; //如果已经连上就不在重连了
window.socketTimer && window.clearTimeout(window.socketTimer);
window.socketTimer = 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() {
window.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 };

+ 135
- 0
src/requests/axios.js Прегледај датотеку

@@ -0,0 +1,135 @@
import axios from "axios";
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) {
window.Cloudia.showToast(`http code: ${status}`);
}
} else if (status !== 200) {
if (this.isDebuggable) {
window.Cloudia.showToast(`http code: ${status}`);
} else {
console.error(`http error, code: ${status}`);
window.Cloudia.showToast("请检查网络连接是否正常,稍后重试!");
}
}

if (data.resultInfo && data.resultInfo.resultCode !== "200") {
window.Cloudia.showToast(
`request error: ${data.resultInfo.resultMsg} (${data.resultInfo.resultCode})`
);
}
return data;
},
(error) => {
window.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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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;

+ 72
- 0
src/router/index.js Прегледај датотеку

@@ -0,0 +1,72 @@
import Vue from "vue";
import VueRouter from "vue-router";
import ApiDemo from "../views/ApiDemo";
import meetingAppoint from "../views/MeetingAppoint";
import meetingReserve from "../views/MeetingReserve";

const meetingCancel = (r) => require.ensure([], () => r(require("../views/MeetingCancel")), "meetingCancel");
const visitorAppoint = (r) => require.ensure([], () => r(require("../views/VisitorAppoint")), "visitorAppoint");
const visitorRegister = (r) => require.ensure([], () => r(require("../views/VisitorRegister")), "visitorRegister");
const visitor = (r) => require.ensure([], () => r(require("../views/Visitor")), "visitor");

Vue.use(VueRouter);

const routes = [
{
path: "/",
name: "apiDemo",
component: ApiDemo
},
{
path: "/meetingReserve",
name: "meetingReserve",
component: meetingReserve
},
{
path: "/meetingAppoint",
name: "meetingAppoint",
component: meetingAppoint
},
{
path: "/meetingCancel",
name: "meetingCancel",
component: meetingCancel
},
{
path: "/visitorAppoint",
name: "visitorAppoint",
component: visitorAppoint
},
{
path: "/visitorRegister",
name: "visitorRegister",
component: visitorRegister
},
{
path: "/visitor",
name: "visitor",
component: visitor
}
];

const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
/*
router.beforeEach((to, from, next) => {
if (to.path == "/") {
if (to.fullPath.indexOf("_r") > -1) {
next();
} else {
if (to.fullPath.indexOf("?") > -1) {
next(to.fullPath + "&_r=" + Math.random());
} else {
next(to.fullPath + "?_r=" + Math.random());
}
}
}
});*/

export default router;

+ 42
- 0
src/router/socketSrv.js Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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......");

+ 56
- 0
src/store/index.js Прегледај датотеку

@@ -0,0 +1,56 @@
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

const store = new Vuex.Store({
state() {
return {
// 就是公共的数据,所有的组件都可以直接使用
count: 100,
lastReq: "",
lastPerson: {},
progressPerson: {},
localDevInfo: {},
handleType: "",
pad: {},
robotMsg: {},
lastAction: "",
ws: {},
debug: false
};
},
mutations: {
setHandleType(state, handleType) {
state.handleType = handleType;
},
setLastReq(state, lastReq) {
state.lastReq = lastReq;
},
setLastPerson(state, lastPerson) {
state.lastPerson = lastPerson;
},
setProgressPerson(state, progressPerson) {
state.progressPerson = progressPerson;
},
setLocalDevInfo(state, localDevInfo) {
state.localDevInfo = localDevInfo;
},
setPad(state, pad) {
state.pad = pad;
},
setRobotMsg(state, msg) {
state.robotMsg = msg;
},
setLastAction(state, action) {
state.lastAction = action;
},
setWs(state, ws) {
state.ws = ws;
},
setDebug(state, debug) {
state.debug = debug;
}
}
});
export default store;

+ 6
- 0
src/styles/bootstrap.min.css
Разлика између датотеке није приказан због своје велике величине
Прегледај датотеку


+ 24
- 0
src/styles/dimens.scss Прегледај датотеку

@@ -0,0 +1,24 @@
$base-width: 540;
$base-height: 960;

$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;
}

+ 149
- 0
src/utils/common.js Прегледај датотеку

@@ -0,0 +1,149 @@
import Config from "../config";
import { genTimeText } from "./handleTtsFun";

export const getTimeState2 = () => {
let timeNow = new Date();
let hours = timeNow.getHours();
// 设置默认文字
let text = "";
if (hours > 18 && hours <= 24) {
text = "挺晚了,您今天辛苦了!";
}
// 返回当前时间段对应的状态
return text;
};

export const genResp = (tag) => {
let result = [];
if (genTimeText() != "") {
result.push(genTimeText());
}
if (getTimeState2() != "") {
result.push(getTimeState2());
}
if (!(tag == Config.userType.courier || tag == Config.userType.blackRole)) {
return result;
}
return [];
};

export const nameShort = (name) => {
let str = "";
if (/^[a-zA-Z]+$/.test(name)) {
str = name;
} else {
str += name !== "" ? name.substr(0, 1) : "";
}
return str;
};

export const getRandomOne = (array) => {
let randNum = Math.floor(Math.random() * array.length);
let str = array[randNum];
return str;
};

export const getSevenDays = (weekNum) => {
let oneDay = 24 * 3600 * 1000;
let oneWeek = 7 * oneDay;
let base = Date.parse(new Date()) + oneWeek * weekNum; // 转换为时间戳
let date = new Date(base);
let weekDay = date.getDay(); //本周第几天

let timeData = {};
let days = [];
for (let i = 0; i < 7; i++) {
let time = base - (weekDay - i) * oneDay;
let now = new Date(time);
let day = {};
day.year = now.getFullYear();
day.month = now.getMonth() + 1;
day.monthDay = now.getDate(); //本月多少号
day.dateStr = day.year + "-" + day.month + "-" + day.monthDay;
day.en = getDayEn(now.getDay());
days.push(day);
if (weekDay - i == 0) {
timeData.selectDay = day;
}
}
timeData.days = days;
return timeData;
};

function getDayEn(day) {
if (day == 0) {
return "SUN";
} else if (day == 1) {
return "MON";
} else if (day == 2) {
return "TUE";
} else if (day == 3) {
return "WED";
} else if (day == 4) {
return "THU";
} else if (day == 5) {
return "FRI";
} else if (day == 6) {
return "SAT";
}
return "";
}

export const containStr = (array, text) => {
for (var i = 0; i < array.length; i++) {
if (text.indexOf(array[i]) > -1) {
return text.indexOf(array[i]);
}
}
return -1;
};

export const containStrStr = (array, text) => {
for (var i = 0; i < array.length; i++) {
if (text.indexOf(array[i]) > -1) {
return array[i];
}
}
return -1;
};

export const containObjByCode = (array, code) => {
for (var i = 0; i < array.length; i++) {
if (array[i]["robotCode"] === code) {
return array[i];
}
}
return null;
};
export const containStrIndex = (array, text) => {
for (var i = 0; i < array.length; i++) {
if (text.indexOf(array[i]) > -1) {
return i;
}
}
return -1;
};

export const arrayComm = (array) => {
array.sort();
let ary = [];
let index = 0;
if (array.length > 1) {
for (let i = 0; i < array.length; i++) {
let tmp = array[i].split("-");
let temp = { start: tmp[0] };
for (let j = i + 1; j < array.length; j++) {
let tmp2 = array[j].split("-");
if ((tmp[1] = tmp2[0])) {
temp.end = tmp2[1];
} else {
ary[index++] = [temp.start + "-" + temp.end];
i = j;
}
}
}
return ary;
} else {
return array;
}
};

Неке датотеке нису приказане због велике количине промена

Loading…
Откажи
Сачувај