@@ -0,0 +1,3 @@ | |||
NODE_ENV='development' | |||
VUE_APP_SERVER_URL=https://localhost:8080 | |||
TEST='88999' |
@@ -0,0 +1,2 @@ | |||
NODE_ENV='production' | |||
VUE_APP_SERVER_URL=https://127.0.0.1 |
@@ -0,0 +1,2 @@ | |||
NODE_ENV='test' | |||
VUE_APP_SERVER_URL=http://10.12.96.114:8082/ |
@@ -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 |
@@ -0,0 +1,12 @@ | |||
module.exports = { | |||
presets: ["@vue/cli-plugin-babel/preset"], | |||
plugins: [ | |||
[ | |||
"component", | |||
{ | |||
libraryName: "mint-ui", | |||
style: true | |||
} | |||
] | |||
] | |||
}; |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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" | |||
} | |||
} |
@@ -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": "我是前台小酷,有什么可以帮您?" | |||
} | |||
} | |||
] | |||
} |
@@ -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> |
@@ -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> |
@@ -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; | |||
} | |||
}; |
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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: "访客" | |||
} | |||
}; |
@@ -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); | |||
} | |||
); | |||
} | |||
}; |
@@ -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; |
@@ -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; |
@@ -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; |
@@ -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; |
@@ -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; |
@@ -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; |
@@ -0,0 +1,5 @@ | |||
// 引入各种函数,便于做成npm包 | |||
// indexedDB 部分 | |||
import MetaHelp from "./nf-meta/help.js"; | |||
export { MetaHelp }; |
@@ -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; | |||
} | |||
} |
@@ -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; |
@@ -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; |
@@ -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 | |||
}; |
@@ -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; |
@@ -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; |
@@ -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; |
@@ -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; |
@@ -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); | |||
} | |||
} |
@@ -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]; | |||
} | |||
}; |
@@ -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; |
@@ -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; |
@@ -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); | |||
} | |||
}); | |||
} |
@@ -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); | |||
} | |||
}); | |||
} |
@@ -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); | |||
} | |||
}); | |||
} |
@@ -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); | |||
} | |||
}); | |||
} |
@@ -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); | |||
} | |||
}); | |||
} |
@@ -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); | |||
} | |||
}); | |||
} |
@@ -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); | |||
} | |||
}); | |||
} |
@@ -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); | |||
} | |||
}); | |||
} |
@@ -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; |
@@ -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; |
@@ -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; | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} |
@@ -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; |
@@ -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]; | |||
} | |||
}; |
@@ -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; | |||
} |
@@ -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); | |||
}); | |||
}); | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} |
@@ -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 // 组件里获取对象仓库,方便实现增删改查 | |||
}; |
@@ -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 | |||
}; | |||
}; |
@@ -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); | |||
} | |||
}; | |||
}); | |||
} | |||
}; |
@@ -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 | |||
}); |
@@ -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(); | |||
}; |
@@ -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 }; |
@@ -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; |
@@ -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 | |||
}); | |||
}; |
@@ -0,0 +1,5 @@ | |||
import AxiosRequest from "./axios"; | |||
import config from "@/config"; | |||
const request = new AxiosRequest(config.baseUrl, config.isDebuggable); | |||
export default request; |
@@ -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; |
@@ -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; |
@@ -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; |
@@ -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......"); |
@@ -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; |
@@ -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; | |||
} |
@@ -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; | |||
} | |||
}; |