diff --git a/.hbuilderx/launch.json b/.hbuilderx/launch.json index c9abd4b..4bbcf3c 100644 --- a/.hbuilderx/launch.json +++ b/.hbuilderx/launch.json @@ -2,10 +2,23 @@ // launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数 "version": "0.0", "configurations": [{ - "type": "uniCloud", - "default": { - "launchtype": "local" - } - } + "app-plus" : + { + "launchtype" : "local" + }, + "default" : + { + "launchtype" : "local" + }, + "h5" : + { + "launchtype" : "local" + }, + "mp-weixin" : + { + "launchtype" : "local" + }, + "type" : "uniCloud" + } ] } diff --git a/api/index.js b/api/index.js new file mode 100644 index 0000000..cd3bcfc --- /dev/null +++ b/api/index.js @@ -0,0 +1,22 @@ +import { + http, + uploadOne, + uploadImage +} from '@/api/request/index.js'; +import { + url_config +} from '@/config/index.js' +const api = { + send(opts = {}){ + const {url, method='GET',data={},auth = 'auth',loading = false} = opts + return http(loading)(url,method,data,auth); + }, + sendOne(url, method='GET',data={},loading = false,auth = 'auth'){ + return http(loading)(url,method,data,auth); + }, + uploadPath: () => (url_config + "/oss/upload"), + uploadFile: (path, msg) => uploadImage("/oss/upload", path, msg), + uploadOne: (msg) => uploadOne("/oss/upload", msg), + + homeInfo: (data, show = false, loadingText) => http(show, loadingText)(`/ums/api/v1/home/pageInfo`, 'GET', data), +} \ No newline at end of file diff --git a/api/request/error.js b/api/request/error.js new file mode 100644 index 0000000..94a1bc2 --- /dev/null +++ b/api/request/error.js @@ -0,0 +1,21 @@ + +export default function checkError(code, res) { + let result = null + switch (code) { + case 401: + case 202: + let text = '' + if (res) { + text = res && res.data ? res.data.message : '请重新登录' + } + break; + default: + uni.showToast({ + icon: 'none', + title: res.data ? res.data.message ? res.data.message : res.data.error ? res.data.error : + '请求失败' : '请求失败' + }) + break; + } + return result; +} diff --git a/api/request/index.js b/api/request/index.js new file mode 100644 index 0000000..a18f9e7 --- /dev/null +++ b/api/request/index.js @@ -0,0 +1,77 @@ +import urlConfig from '@/config/index.js' +import checkError from "./error.js" +import { uploadOne, uploadImage} from "./upload.js" + +const { + url_config +} = urlConfig; + +export { + uploadOne, + uploadImage +} + +export default { + request: http(), + // 带加载框的请求 + _request: http(true) +} + +function isUrl(url) { + return /^((https|http|ftp|rtsp|mms)?:\/\/)[^\s]+/.test(url) +} + +export function http(showLoading, loadingText="正在加载中") { + return function(url, method = 'GET', data = {}, type = 'form') { + let realData = data; + let realUrl = url + var header = {}; + if (type == 'json') { + header['Content-Type'] = 'application/json'; + } else if (type == 'form') { + header['Content-Type'] = 'application/x-www-form-urlencoded'; + } + return new Promise((resolve, reject) => { + if (showLoading) { + uni.showLoading({ + title: loadingText, + mask: true + }) + } + uni.request({ + url: isUrl(realUrl) ? realUrl : (url_config + realUrl), + method, + dataType: 'json', + header, + data: realData, + success: (res) => { + if (showLoading) { + uni.hideLoading(); + } + if (!(res.statusCode === 200)) { + checkError(res.statusCode, res); + reject(res) + return + } + if (res.data.code == 200) { + resolve(res.data); + } else { + checkError(res.data.code, res); + reject(res.data) + } + }, + fail(err) { + if (showLoading) { + uni.hideLoading(); + } + uni.showToast({ + icon: 'none', + title: err.errMsg + }) + checkError(-1, err); + reject(err) + } + }); + }) + } +} diff --git a/api/request/upload.js b/api/request/upload.js new file mode 100644 index 0000000..4b97269 --- /dev/null +++ b/api/request/upload.js @@ -0,0 +1,50 @@ + + +export function uploadOne(action, msg) { + let that = this; + return new Promise((resolve, reject) => { + uni.chooseImage({ + count: 1, + async success(res) { + if (res.tempFilePaths && res.tempFilePaths[0]) { + let file = res.tempFilePaths[0]; + let urls = await uploadImage(action, file, msg); + resolve(JSON.parse(urls)); + } else { + reject() + } + }, + fail(err) { + reject(err) + } + }) + }) +} + +export function uploadImage(action, path, msg = "上传中") { + uni.showLoading({ + title: msg + }) + return new Promise((resolve, reject) => { + uni.uploadFile({ + url: url_config + action, + filePath: path, + fileType: "image", + dataType: 'json', + name: 'file', + header: {}, + success: (uploadFileRes) => { + uni.hideLoading(); + resolve(uploadFileRes.data) + }, + fail: (err) => { + uni.hideLoading(); + uni.showToast({ + icon: 'none', + title: '上传失败' + }) + reject(err) + } + }); + }) +} diff --git a/assets/style/common.scss b/assets/style/common.scss index 4c53fde..07660f7 100644 --- a/assets/style/common.scss +++ b/assets/style/common.scss @@ -1,13 +1,14 @@ page { - background-color: #FFF8F8; + // background-color: #FFF8F8; + background-color: #F1F1F1; // min-height: 100%; height: 100%; font-size: 28rpx; - line-height: 1.5; // + line-height: 1.2; // color: #000; } - page>.tabpage{ + page .tabpage{ // 怪异盒模型 -webkit-overflow-scrolling: touch; box-sizing: border-box; @@ -21,17 +22,17 @@ page { margin-bottom: 0; /* #endif */ // 触发BFC - overflow-x: hidden; - overflow-y: scroll; + // overflow-x: hidden; + // overflow-y: scroll; min-height: 100%; } - page>.page{ + page .page{ // 怪异盒模型 -webkit-overflow-scrolling: touch; box-sizing: border-box; // 触发BFC - overflow-x: hidden; - overflow-y: scroll; + // overflow-x: hidden; + // overflow-y: scroll; min-height: 100%; } diff --git a/components/Cell/Cell.vue b/components/Cell/Cell.vue new file mode 100644 index 0000000..d694da2 --- /dev/null +++ b/components/Cell/Cell.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/components/CellBox/CellBox.vue b/components/CellBox/CellBox.vue new file mode 100644 index 0000000..50a4f6b --- /dev/null +++ b/components/CellBox/CellBox.vue @@ -0,0 +1,22 @@ + + + + + diff --git a/components/niu-tree/anim.vue b/components/niu-tree/anim.vue new file mode 100644 index 0000000..ed8b41e --- /dev/null +++ b/components/niu-tree/anim.vue @@ -0,0 +1,55 @@ + + + + + diff --git a/components/niu-tree/niu-tree.vue b/components/niu-tree/niu-tree.vue new file mode 100644 index 0000000..16c595b --- /dev/null +++ b/components/niu-tree/niu-tree.vue @@ -0,0 +1,105 @@ + + + + + diff --git a/main.js b/main.js index 3d79b7f..fd5cf19 100644 --- a/main.js +++ b/main.js @@ -1,6 +1,6 @@ import Vue from 'vue' import niuUI from '@/uni_modules/niu-ui' -import mock from '@/mock' +// import mock from '@/mock'. import App from './App' Vue.config.productionTip = false @@ -8,7 +8,7 @@ Vue.config.productionTip = false App.mpType = 'app' Vue.use(niuUI) -Vue.use(mock) +// Vue.use(mock) const app = new Vue({ ...App diff --git a/manifest.json b/manifest.json index ff1371c..70b620e 100644 --- a/manifest.json +++ b/manifest.json @@ -8,7 +8,7 @@ /* 5+App特有相关 */ "app-plus" : { "usingComponents" : true, - "nvueStyleCompiler" : "uni-app", + "nvueStyleCompiler" : "uni-app", "compilerVersion" : 3, "splashscreen" : { "alwaysShowBeforeRender" : true, @@ -43,7 +43,9 @@ /* ios打包配置 */ "ios" : {}, /* SDK配置 */ - "sdkConfigs" : {} + "sdkConfigs" : { + "ad" : {} + } } }, /* 快应用特有相关 */ @@ -65,7 +67,12 @@ "mp-toutiao" : { "usingComponents" : true }, - "uniStatistics": { - "enable": false + "h5" : { + "devServer" : { + "disableHostCheck" : true + } + }, + "uniStatistics" : { + "enable" : false } } diff --git a/mixins/mescroll-ui/mixin.js b/mixins/mescroll-ui/mixin.js deleted file mode 100644 index eca4169..0000000 --- a/mixins/mescroll-ui/mixin.js +++ /dev/null @@ -1,86 +0,0 @@ -const allConfig = {}; -const allFunc = {}; -/** - * 自动下拉刷新 - */ -allConfig.common = { - downOption: { - auto: true, - use: true - }, - upOption: { - page: { - size: 10 // 每页数据的数量,默认10 - }, - auto: false, - toTop: { - src: 'https://shidaizhu.oss-cn-shenzhen.aliyuncs.com/app_static/images/backtop.png', - bottom: "20%", - duration: 300, - zIndex: 9990, - right: 50, - safearea: false, - width: 96, - radius: "50%", - left: null - }, - empty: { - use: true, - // icon: require('@/static/zichan_empty.png'), - tip: '暂无数据', - // btnText: '发布项目需求', - fixed: false, - top: '40%', - zIndex: 9 - }, - mescroll: null, - noMoreSize: 5, - textNoMore: '-- 暂无更多数据 --' - }, // 上拉加载的常用配置 -}; - -allFunc.common = { - computed:{ - $mTop(){ - return this.$n.state.$Top - }, - }, - onPageScroll(e) { - // if(e.scrollTop<=40){ - // this.mescroll.lockDownScroll( false ) - // } - // if(e.scrollTop>40){ - // this.mescroll.lockDownScroll( true ) - // } - }, - mounted(){ - - }, - methods: { - mescrollInit(mescroll) { - this.mescroll = mescroll; - }, - // mescroll组件初始化的回调,可获取到mescroll对象 - downCallback(mescroll) { - this.mescroll.resetUpScroll(false) - }, - upCallback(mescroll) { - - }, - } -} - -export default function(name,func="common") { - const config = allConfig[name] ? allConfig[name] : {} - const myFunc = allFunc[func] ? allFunc[func] : {} - return { - data() { - return { - downOption: {}, // 下拉刷新的配置 - upOption: {}, // 上拉加载的常用配置 - ...config, - } - }, - ...myFunc - } -} \ No newline at end of file diff --git a/mock/index - 副本.js b/mock/index - 副本.js new file mode 100644 index 0000000..f521012 --- /dev/null +++ b/mock/index - 副本.js @@ -0,0 +1,46 @@ +/** + * Mock数据 + */ + + +this.$u.api.queryElectricityInfoReport + + +export default { + +} + +const oldRequest = uni.request; + +const opts = { + url: '', + data: '', + header: {}, + method: '', + timeout: '', + dataType: '', + responseType: '', + sslVerify: '', + withCredentials: '', + firstIpv4: '', + success: '', + fail: '', + complete: '', +} + +uni.request = async (opts) => { + console.log(1231); + const data = await oldRequest({ + url: "https://baidu.com", + method: "GET" + }) + let [error, res] = data; + console.log(error); + console.log(res); +} + +export default { + install(Vue, opts) { + + } +} diff --git a/mock/index.js b/mock/index.js index 63dfe58..34c3007 100644 --- a/mock/index.js +++ b/mock/index.js @@ -1,38 +1,17 @@ -/** - * Mock数据 - */ - -const oldRequest = uni.request; - -const opts = { - url: '', - data: '', - header: {}, - method: '', - timeout: '', - dataType: '', - responseType: '', - sslVerify: '', - withCredentials: '', - firstIpv4: '', - success: '', - fail: '', - complete: '', -} - -uni.request = async (opts) => { - console.log(1231); - const data = await oldRequest({ - url: "https://baidu.com", - method: "GET" - }) - let [error, res] = data; - console.log(error); - console.log(res); +import http from './util'; +import * as mockData from './mock'; +const home = { + aa: "haha" } -export default { - install(Vue, opts) { +const api = { + home: ()=> http({res: mockData['home'], isSuccess:true}) +}; +export default{ + install(Vue,opts){ + if(Vue.prototype.$n){ + Vue.prototype.$n.api = Object.assign(Vue.prototype.$n.api, api) + } } } diff --git a/mock/mock - 副本.js b/mock/mock - 副本.js new file mode 100644 index 0000000..ad2bfc5 --- /dev/null +++ b/mock/mock - 副本.js @@ -0,0 +1,46 @@ +/** + * Mock数据 + */ + + +// this.$u.api.queryElectricityInfoReport + + +export default { + +} + +const oldRequest = uni.request; + +const opts = { + url: '', + data: '', + header: {}, + method: '', + timeout: '', + dataType: '', + responseType: '', + sslVerify: '', + withCredentials: '', + firstIpv4: '', + success: '', + fail: '', + complete: '', +} + +uni.request = async (opts) => { + console.log(1231); + const data = await oldRequest({ + url: "https://baidu.com", + method: "GET" + }) + let [error, res] = data; + console.log(error); + console.log(res); +} + +export default { + install(Vue, opts) { + + } +} diff --git a/mock/mock.js b/mock/mock.js new file mode 100644 index 0000000..a11fc6d --- /dev/null +++ b/mock/mock.js @@ -0,0 +1,3 @@ +export const home = { + aa: "sadsa" +} \ No newline at end of file diff --git a/mock/util.js b/mock/util.js new file mode 100644 index 0000000..8d5aadc --- /dev/null +++ b/mock/util.js @@ -0,0 +1,35 @@ +const defaultOpts = { + message: "", + res: {}, + err: false, + get isSuccess() { + return !![0,1][~~(Math.random()*2)] + }, + get duration() { + return ~~(Math.random()*3000+500) + } +} + +export default function http(opts) { + let realOpts = {} + Object.keys(defaultOpts).forEach(v => { + if (opts&&opts[v] != undefined) { + realOpts[v] = opts[v] + } else { + realOpts[v] = defaultOpts[v] + } + }) + console.log('请等待'+realOpts.duration/1000+'s') + return new Promise((resolve, reject) => { + setTimeout(() => { + if(realOpts.err){ + reject(new Error("diy message")); + } + if(realOpts.isSuccess){ + resolve({code: 1, message:realOpts.message, data: realOpts.res}) + }else{ + reject({code: 0,message:realOpts.message, data: realOpts.res}) + } + }, realOpts.duration) + }) +} diff --git a/pages.json b/pages.json index 6e30810..18c2f3e 100644 --- a/pages.json +++ b/pages.json @@ -7,10 +7,31 @@ "navigationBarTitleText": "uni-app" } } - ,{ - "path" : "pages/about/about", + ,{ + "path" : "pages/Sub/Tabs/Tabs", "style" : { + "navigationStyle": "custom", + "navigationBarTitleText": "", + "enablePullDownRefresh": false + } + + } + ,{ + "path" : "pages/Sub/Socket/Socket", + "style" : + { + "navigationStyle": "custom", + "navigationBarTitleText": "", + "enablePullDownRefresh": false + } + + } + ,{ + "path" : "pages/Sub/Pro/SelectTime/SelectTime", + "style" : + { + "navigationStyle": "custom", "navigationBarTitleText": "", "enablePullDownRefresh": false } diff --git a/pages/Sub/Pro/SelectTime/SelectTime.vue b/pages/Sub/Pro/SelectTime/SelectTime.vue new file mode 100644 index 0000000..1183a6d --- /dev/null +++ b/pages/Sub/Pro/SelectTime/SelectTime.vue @@ -0,0 +1,22 @@ + + + + + diff --git a/pages/Sub/Pro/SelectTime/TimeSelect.vue b/pages/Sub/Pro/SelectTime/TimeSelect.vue new file mode 100644 index 0000000..05d6d5d --- /dev/null +++ b/pages/Sub/Pro/SelectTime/TimeSelect.vue @@ -0,0 +1,549 @@ + + + + + + diff --git a/pages/Sub/Pro/SelectTime/TimeType.vue b/pages/Sub/Pro/SelectTime/TimeType.vue new file mode 100644 index 0000000..bcb0254 --- /dev/null +++ b/pages/Sub/Pro/SelectTime/TimeType.vue @@ -0,0 +1,74 @@ + + + + + diff --git a/pages/Sub/Pro/SelectTime/day.vue b/pages/Sub/Pro/SelectTime/day.vue new file mode 100644 index 0000000..8304f13 --- /dev/null +++ b/pages/Sub/Pro/SelectTime/day.vue @@ -0,0 +1,222 @@ + + + + + diff --git a/pages/Sub/Pro/SelectTime/util.js b/pages/Sub/Pro/SelectTime/util.js new file mode 100644 index 0000000..cc6700b --- /dev/null +++ b/pages/Sub/Pro/SelectTime/util.js @@ -0,0 +1,111 @@ +export function bigerZero(num){ + if(num===undefined){ + return 0 + } + return num<0?0:num +} + +export function buildYearData(year, long) { + let minYear = long[0]; + let maxYear = long[1]; + + if (minYear > maxYear) { + console.log("区间错误"); + return + } + let len = maxYear - minYear + let yearList = createArray(len + 1, year + minYear) + return yearList; +} + +export function buildHourData(){ + return createArray(24); +} + +export function buildMinuteData(){ + return createArray(60); +} + +export function buildSecondData(){ + return createArray(60); +} + +export function buildMonthData(year) { + return createArray(12, 1); +} + +export function buildDayData(year, month) { + let is31Day = [1, 3, 5, 7, 8, 10, 12].indexOf(month) != -1 + let leapYear = isLeapYear(year); + if (month !== 2) { + return createArray(is31Day ? 31 : 30, 1); + } else if (leapYear && month === 2) { + return createArray(29, 1); + } else if (!leapYear && month === 2) { + return createArray(28, 1); + } + return [] +} + + +function createArray(length, num = 0) { + return [...Array(length)].map((v, i) => (num + i)) +} + +/** + * 是否是闰年 + * @param {Object} year 年份 + */ +function isLeapYear(year) { + if (year % 100 != 0 && year % 4 == 0 || year % 400 == 0) { + return true + } + return false +} + + export function dateTimeFormat(date, fmt = 'yyyy-MM-dd HH:mm:ss') { + if (!date) { + return '' + } + if (typeof date === 'string') { + date = date.replace('T', ' ').replace('Z', ''); + date = new Date(date.replace(/-/g, '/')) + } + if (typeof date === 'number') { + date = new Date(date) + } + var o = { + 'M+': date.getMonth() + 1, + 'd+': date.getDate(), + 'h+': date.getHours() % 12 === 0 ? 12 : date.getHours() % 12, + 'H+': date.getHours(), + 'm+': date.getMinutes(), + 's+': date.getSeconds(), + 'q+': Math.floor((date.getMonth() + 3) / 3), + 'S': date.getMilliseconds() + } + var week = { + '0': '\u65e5', + '1': '\u4e00', + '2': '\u4e8c', + '3': '\u4e09', + '4': '\u56db', + '5': '\u4e94', + '6': '\u516d' + } + if (/(y+)/.test(fmt)) { + fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)) + } + if (/(E+)/.test(fmt)) { + fmt = fmt.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? '\u661f\u671f' : '\u5468') : + '') + + week[date.getDay() + '']) + } + 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 + } \ No newline at end of file diff --git a/pages/Sub/Socket/Socket.scss b/pages/Sub/Socket/Socket.scss new file mode 100644 index 0000000..2d4b09d --- /dev/null +++ b/pages/Sub/Socket/Socket.scss @@ -0,0 +1,124 @@ +.input-box{ + display: flex; + align-items: center; + margin: 20rpx; + .input{ + flex: 1; + background-color: white; + border-top-left-radius: 10rpx; + border-bottom-left-radius: 10rpx; + height: 70rpx; + line-height: 70rpx; + padding: 0 20rpx; + } + .button{ + height: 70rpx; + line-height: 70rpx; + color: white; + font-size: 28rpx; + padding: 0 20rpx; + background-color: #31AB45; + &:last-child{ + border-top-right-radius: 10rpx; + border-bottom-right-radius: 10rpx; + } + &.success{ + background-color: #f29100; + } + &.del{ + background-color: #dd6161; + } + } + } + .talkbox{ + .msg{ + text-align: center; + margin-bottom: 10rpx; + .text{ + background-color: #c8c9cc; + color: white; + display: inline-block; + line-height: 1; + padding: 8rpx 15rpx; + border-radius: 6rpx; + font-size: 24rpx; + } + } + .other{ + .talk__info{ + margin-right: 10rpx; + } + .talk__content{ + display: flex; + justify-content: flex-start; + .text{ + background-color: #39B54A; + &::before{ + right: 100%; + border-top: 10rpx solid transparent; + border-bottom: 10rpx solid transparent; + border-left: 10rpx solid transparent; + border-right: 10rpx solid #39B54A; + } + } + .error{ + margin-left: 10rpx; + } + } + } + .my{ + .talk__info{ + margin-left: 20rpx; + } + .talk__content{ + display: flex; + justify-content: flex-end; + .text{ + background-color: #3277FF; + &::before{ + left: 100%; + border-top: 10rpx solid transparent; + border-bottom: 10rpx solid transparent; + border-right: 10rpx solid transparent; + border-left: 10rpx solid #3277FF; + } + } + .error{ + margin-right: 10rpx; + } + } + } + .talk{ + display: flex; + align-items: flex-start; + margin: 0 10rpx 10rpx 10rpx; + .talk__content{ + flex: 1; + width: 0; + margin-left: 15rpx; + display: flex; + align-items: center; + .text{ + display: inline-block; + border-radius: 8rpx; + color: white; + line-height: 1.3; + padding: 10rpx; + position: relative; + word-break: break-all; + &::before{ + content: " "; + display: block; + position: absolute; + } + } + .error{ + width: 20rpx; + height: 20rpx; + background-color: #dd6161; + border-radius: 50%; + } + } + } + } + \ No newline at end of file diff --git a/pages/Sub/Socket/Socket.vue b/pages/Sub/Socket/Socket.vue new file mode 100644 index 0000000..127b59b --- /dev/null +++ b/pages/Sub/Socket/Socket.vue @@ -0,0 +1,129 @@ + + + + + diff --git a/pages/Sub/Socket/events.js b/pages/Sub/Socket/events.js new file mode 100644 index 0000000..bfe7ec0 --- /dev/null +++ b/pages/Sub/Socket/events.js @@ -0,0 +1,497 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; + +var R = typeof Reflect === 'object' ? Reflect : null +var ReflectApply = R && typeof R.apply === 'function' + ? R.apply + : function ReflectApply(target, receiver, args) { + return Function.prototype.apply.call(target, receiver, args); + } + +var ReflectOwnKeys +if (R && typeof R.ownKeys === 'function') { + ReflectOwnKeys = R.ownKeys +} else if (Object.getOwnPropertySymbols) { + ReflectOwnKeys = function ReflectOwnKeys(target) { + return Object.getOwnPropertyNames(target) + .concat(Object.getOwnPropertySymbols(target)); + }; +} else { + ReflectOwnKeys = function ReflectOwnKeys(target) { + return Object.getOwnPropertyNames(target); + }; +} + +function ProcessEmitWarning(warning) { + if (console && console.warn) console.warn(warning); +} + +var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) { + return value !== value; +} + +function EventEmitter() { + EventEmitter.init.call(this); +} +module.exports = EventEmitter; +module.exports.once = once; + +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; + +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._eventsCount = 0; +EventEmitter.prototype._maxListeners = undefined; + +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +var defaultMaxListeners = 10; + +function checkListener(listener) { + if (typeof listener !== 'function') { + throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener); + } +} + +Object.defineProperty(EventEmitter, 'defaultMaxListeners', { + enumerable: true, + get: function() { + return defaultMaxListeners; + }, + set: function(arg) { + if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) { + throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.'); + } + defaultMaxListeners = arg; + } +}); + +EventEmitter.init = function() { + + if (this._events === undefined || + this._events === Object.getPrototypeOf(this)._events) { + this._events = Object.create(null); + this._eventsCount = 0; + } + + this._maxListeners = this._maxListeners || undefined; +}; + +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { + if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) { + throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.'); + } + this._maxListeners = n; + return this; +}; + +function _getMaxListeners(that) { + if (that._maxListeners === undefined) + return EventEmitter.defaultMaxListeners; + return that._maxListeners; +} + +EventEmitter.prototype.getMaxListeners = function getMaxListeners() { + return _getMaxListeners(this); +}; + +EventEmitter.prototype.emit = function emit(type) { + var args = []; + for (var i = 1; i < arguments.length; i++) args.push(arguments[i]); + var doError = (type === 'error'); + + var events = this._events; + if (events !== undefined) + doError = (doError && events.error === undefined); + else if (!doError) + return false; + + // If there is no 'error' event listener then throw. + if (doError) { + var er; + if (args.length > 0) + er = args[0]; + if (er instanceof Error) { + // Note: The comments on the `throw` lines are intentional, they show + // up in Node's output if this results in an unhandled exception. + throw er; // Unhandled 'error' event + } + // At least give some kind of context to the user + var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : '')); + err.context = er; + throw err; // Unhandled 'error' event + } + + var handler = events[type]; + + if (handler === undefined) + return false; + + if (typeof handler === 'function') { + ReflectApply(handler, this, args); + } else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + ReflectApply(listeners[i], this, args); + } + + return true; +}; + +function _addListener(target, type, listener, prepend) { + var m; + var events; + var existing; + + checkListener(listener); + + events = target._events; + if (events === undefined) { + events = target._events = Object.create(null); + target._eventsCount = 0; + } else { + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (events.newListener !== undefined) { + target.emit('newListener', type, + listener.listener ? listener.listener : listener); + + // Re-assign `events` because a newListener handler could have caused the + // this._events to be assigned to a new object + events = target._events; + } + existing = events[type]; + } + + if (existing === undefined) { + // Optimize the case of one listener. Don't need the extra array object. + existing = events[type] = listener; + ++target._eventsCount; + } else { + if (typeof existing === 'function') { + // Adding the second element, need to change to array. + existing = events[type] = + prepend ? [listener, existing] : [existing, listener]; + // If we've already got an array, just append. + } else if (prepend) { + existing.unshift(listener); + } else { + existing.push(listener); + } + + // Check for listener leak + m = _getMaxListeners(target); + if (m > 0 && existing.length > m && !existing.warned) { + existing.warned = true; + // No error code for this since it is a Warning + // eslint-disable-next-line no-restricted-syntax + var w = new Error('Possible EventEmitter memory leak detected. ' + + existing.length + ' ' + String(type) + ' listeners ' + + 'added. Use emitter.setMaxListeners() to ' + + 'increase limit'); + w.name = 'MaxListenersExceededWarning'; + w.emitter = target; + w.type = type; + w.count = existing.length; + ProcessEmitWarning(w); + } + } + + return target; +} + +EventEmitter.prototype.addListener = function addListener(type, listener) { + return _addListener(this, type, listener, false); +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.prependListener = + function prependListener(type, listener) { + return _addListener(this, type, listener, true); + }; + +function onceWrapper() { + if (!this.fired) { + this.target.removeListener(this.type, this.wrapFn); + this.fired = true; + if (arguments.length === 0) + return this.listener.call(this.target); + return this.listener.apply(this.target, arguments); + } +} + +function _onceWrap(target, type, listener) { + var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener }; + var wrapped = onceWrapper.bind(state); + wrapped.listener = listener; + state.wrapFn = wrapped; + return wrapped; +} + +EventEmitter.prototype.once = function once(type, listener) { + checkListener(listener); + this.on(type, _onceWrap(this, type, listener)); + return this; +}; + +EventEmitter.prototype.prependOnceListener = + function prependOnceListener(type, listener) { + checkListener(listener); + this.prependListener(type, _onceWrap(this, type, listener)); + return this; + }; + +// Emits a 'removeListener' event if and only if the listener was removed. +EventEmitter.prototype.removeListener = + function removeListener(type, listener) { + var list, events, position, i, originalListener; + + checkListener(listener); + + events = this._events; + if (events === undefined) + return this; + + list = events[type]; + if (list === undefined) + return this; + + if (list === listener || list.listener === listener) { + if (--this._eventsCount === 0) + this._events = Object.create(null); + else { + delete events[type]; + if (events.removeListener) + this.emit('removeListener', type, list.listener || listener); + } + } else if (typeof list !== 'function') { + position = -1; + + for (i = list.length - 1; i >= 0; i--) { + if (list[i] === listener || list[i].listener === listener) { + originalListener = list[i].listener; + position = i; + break; + } + } + + if (position < 0) + return this; + + if (position === 0) + list.shift(); + else { + spliceOne(list, position); + } + + if (list.length === 1) + events[type] = list[0]; + + if (events.removeListener !== undefined) + this.emit('removeListener', type, originalListener || listener); + } + + return this; + }; + +EventEmitter.prototype.off = EventEmitter.prototype.removeListener; + +EventEmitter.prototype.removeAllListeners = + function removeAllListeners(type) { + var listeners, events, i; + + events = this._events; + if (events === undefined) + return this; + + // not listening for removeListener, no need to emit + if (events.removeListener === undefined) { + if (arguments.length === 0) { + this._events = Object.create(null); + this._eventsCount = 0; + } else if (events[type] !== undefined) { + if (--this._eventsCount === 0) + this._events = Object.create(null); + else + delete events[type]; + } + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + var keys = Object.keys(events); + var key; + for (i = 0; i < keys.length; ++i) { + key = keys[i]; + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = Object.create(null); + this._eventsCount = 0; + return this; + } + + listeners = events[type]; + + if (typeof listeners === 'function') { + this.removeListener(type, listeners); + } else if (listeners !== undefined) { + // LIFO order + for (i = listeners.length - 1; i >= 0; i--) { + this.removeListener(type, listeners[i]); + } + } + + return this; + }; + +function _listeners(target, type, unwrap) { + var events = target._events; + + if (events === undefined) + return []; + + var evlistener = events[type]; + if (evlistener === undefined) + return []; + + if (typeof evlistener === 'function') + return unwrap ? [evlistener.listener || evlistener] : [evlistener]; + + return unwrap ? + unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); +} + +EventEmitter.prototype.listeners = function listeners(type) { + return _listeners(this, type, true); +}; + +EventEmitter.prototype.rawListeners = function rawListeners(type) { + return _listeners(this, type, false); +}; + +EventEmitter.listenerCount = function(emitter, type) { + if (typeof emitter.listenerCount === 'function') { + return emitter.listenerCount(type); + } else { + return listenerCount.call(emitter, type); + } +}; + +EventEmitter.prototype.listenerCount = listenerCount; +function listenerCount(type) { + var events = this._events; + + if (events !== undefined) { + var evlistener = events[type]; + + if (typeof evlistener === 'function') { + return 1; + } else if (evlistener !== undefined) { + return evlistener.length; + } + } + + return 0; +} + +EventEmitter.prototype.eventNames = function eventNames() { + return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : []; +}; + +function arrayClone(arr, n) { + var copy = new Array(n); + for (var i = 0; i < n; ++i) + copy[i] = arr[i]; + return copy; +} + +function spliceOne(list, index) { + for (; index + 1 < list.length; index++) + list[index] = list[index + 1]; + list.pop(); +} + +function unwrapListeners(arr) { + var ret = new Array(arr.length); + for (var i = 0; i < ret.length; ++i) { + ret[i] = arr[i].listener || arr[i]; + } + return ret; +} + +function once(emitter, name) { + return new Promise(function (resolve, reject) { + function errorListener(err) { + emitter.removeListener(name, resolver); + reject(err); + } + + function resolver() { + if (typeof emitter.removeListener === 'function') { + emitter.removeListener('error', errorListener); + } + resolve([].slice.call(arguments)); + }; + + eventTargetAgnosticAddListener(emitter, name, resolver, { once: true }); + if (name !== 'error') { + addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true }); + } + }); +} + +function addErrorHandlerIfEventEmitter(emitter, handler, flags) { + if (typeof emitter.on === 'function') { + eventTargetAgnosticAddListener(emitter, 'error', handler, flags); + } +} + +function eventTargetAgnosticAddListener(emitter, name, listener, flags) { + if (typeof emitter.on === 'function') { + if (flags.once) { + emitter.once(name, listener); + } else { + emitter.on(name, listener); + } + } else if (typeof emitter.addEventListener === 'function') { + // EventTarget does not have `error` event semantics like Node + // EventEmitters, we do not listen for `error` events here. + emitter.addEventListener(name, function wrapListener(arg) { + // IE does not have builtin `{ once: true }` support so we + // have to do it manually. + if (flags.once) { + emitter.removeEventListener(name, wrapListener); + } + listener(arg); + }); + } else { + throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter); + } +} \ No newline at end of file diff --git a/pages/Sub/Socket/socket - 副本.js b/pages/Sub/Socket/socket - 副本.js new file mode 100644 index 0000000..53cb1cf --- /dev/null +++ b/pages/Sub/Socket/socket - 副本.js @@ -0,0 +1,162 @@ +import EventEmitter from "./events.js" + +export class Msg{ + data = "" // 数据载体 + ev = "" // 事件类型 + _success = 0 // 是否发送成功 + constructor(ev, data, _success) { + this.ev = ev; + this.data = data; + this._success = _success; + } +} + +Msg.create = function(ev, data, _success){ + return new Msg(ev, data, _success) +} + +class Sc { + #isConnected = false; + #isConnecting = false; + // #url = "ws://82.157.123.54:9010/ajaxchattest" + #url = "ws://127.0.0.1:8888" + #instance = null + #event = null + #isClose = false + #time = 0 // 重连的次数 + #maxTime = 10 // 能够重连的次数 + #timerID = -1 // 心跳检测 + // WILL: 是否需要检测心跳检测没回应的次数断开连接 + #heartTimes = 0 // 心跳检测次数 + constructor() { + this.#event = new EventEmitter() + } + get event(){ + return this.#event; + } + close(){ + if(!this.#isConnected) return + if(!this.#instance) return + this.#isClose = true + this.#instance.close() + } + /** + * 心跳检测 + */ + heartTime(){ + if(!this.#isConnected) return + if(!this.#instance) return + if(this.#timerID!=-1) return + this.send({ping: new Date().getTime()}) + this.#timerID = setInterval(()=>{ + this.send({ping: new Date().getTime()}) + },5000) + } + clearHeartTime(){ + clearInterval(this.#timerID) + this.#timerID = -1 + } + send(data){ + return new Promise((resolve,reject)=>{ + const that = this; + if(this.#isConnected){ + const encryptData = encodeURIComponent(JSON.stringify(data)); + this.#instance.send({ + data: encryptData, + success(){ + resolve() + }, + fail() { + that.#event.emit('onMessage',{...data, _success: 2}) + // reject() + resolve() + } + }); + }else{ + that.#event.emit('onMessage',{...data, _success: 2}) + // reject() + resolve() + } + }) + } + initConnect(opts = {}, isReConnect) { + if(typeof opts === "boolean"){ + isReConnect = opts + opts = {} + } + if(this.#isConnecting&&!isReConnect) return + if (this.#isConnected) return + this.#isConnecting = true + this.#instance = uni.connectSocket({ + url: this.#url, + header: opts.header || {}, + complete: () => {} + }); + const onError = (errMsg)=>{ + // console.log(errMsg); + } + const onMessage = (data)=>{ + // console.log(data); + } + const onOpen = async ()=>{ + + } + const onClose = ()=>{ + + } + this.#event.on('onMessage', onMessage) + this.#event.on('onError', onError) + this.#event.on('onOpen', onOpen) + this.#event.on('onClose', onClose) + this.#instance.onOpen(async ()=>{ + this.#isConnected = true + this.#isConnecting = false + this.#time = 0 + this.#event.emit('#msg', "客户端已连接") + this.#event.emit('onOpen', isReConnect) + // this.heartTime() + if(isReConnect){ + this.send({"reconnect": true}) + } + }) + this.#instance.onClose(()=>{ + this.#isConnected = false + this.#isConnecting = false + this.#instance = null + // this.clearHeartTime() + this.#event.off("onClose", onClose) + this.#event.off("onError", onError) + this.#event.off("onOpen", onOpen) + this.#event.off("onMessage", onMessage) + if(!this.#isClose){ + this.#time++ + if(this.#time<=this.#maxTime){ + this.#isConnecting = true + setTimeout(()=>{ + this.#event.emit('#msg', `第${this.#time}次重连`) + // 重连 + this.initConnect(opts, true) + },2000) + }else{ + this.#event.emit('#msg', "客户端已离线,请重试") + this.#event.emit('onClose') + } + }else{ + this.isClose = false + this.#event.emit('#msg', "客户端已离线") + this.#event.emit('onClose') + } + }) + this.#instance.onError((errMsg)=>{ + this.#event.emit('onError', errMsg) + }) + this.#instance.onMessage((data)=>{ + // let rData = JSON.parse(decodeURIComponent(data.data).slice(0,-66)); + let rData = JSON.parse(decodeURIComponent(data.data)); + if(rData.hasOwnProperty("ping")) return + this.#event.emit('onMessage',rData) + }) + } +} + +export default new Sc() diff --git a/pages/Sub/Socket/socket.js b/pages/Sub/Socket/socket.js new file mode 100644 index 0000000..4028aa8 --- /dev/null +++ b/pages/Sub/Socket/socket.js @@ -0,0 +1,170 @@ +import EventEmitter from "./events.js" + +export class Msg{ + data = "" // 数据载体 + ev = "" // 事件类型 + _success = 0 // 是否发送成功 + constructor(ev, data, _success) { + this.ev = ev; + this.data = data; + this._success = _success; + } +} + +Msg.create = function(ev, data, _success){ + return new Msg(ev, data, _success) +} +Msg.clone = function(data, _success){ + return new Msg(data.ev, data.data, _success!=undefined ? _success : data._success) +} +class Sc { + #isConnected = false; + #isConnecting = false; + // #url = "ws://82.157.123.54:9010/ajaxchattest" + #url = "ws://127.0.0.1:8888" + #instance = null + #event = null + #isClose = false + #time = 0 // 重连的次数 + #maxTime = 10 // 能够重连的次数 + #timerID = -1 // 心跳检测 + // WILL: 是否需要检测心跳检测没回应的次数断开连接 + #heartTimes = 0 // 心跳检测次数 + constructor() { + this.#event = new EventEmitter() + } + get event(){ + return this.#event; + } + close(){ + if(!this.#isConnected) return + if(!this.#instance) return + this.#isClose = true + this.#instance.close() + } + /** + * 心跳检测 + */ + heartTime(){ + if(!this.#isConnected) return + if(!this.#instance) return + if(this.#timerID!=-1) return + this.send({ping: new Date().getTime()}, true) + this.#timerID = setInterval(()=>{ + this.send({ping: new Date().getTime()}, true) + },5000) + } + clearHeartTime(){ + clearInterval(this.#timerID) + this.#timerID = -1 + } + send(data, isPing){ + return new Promise((resolve,reject)=>{ + const that = this; + if(!data instanceof Msg || isPing) { + console.error("载体不是msg实例") + return + } + if(this.#isConnected){ + const encryptData = encodeURIComponent(JSON.stringify(data)); + this.#instance.send({ + data: encryptData, + success(){ + resolve() + }, + fail() { + that.#event.emit('onMessage',Msg.clone(data,2)) + // reject() + resolve() + } + }); + }else{ + that.#event.emit('onMessage',Msg.clone(data,2)) + // reject() + resolve() + } + }) + } + initConnect(opts = {}, isReConnect) { + if(typeof opts === "boolean"){ + isReConnect = opts + opts = {} + } + if(this.#isConnecting&&!isReConnect) return + if (this.#isConnected) return + this.#isConnecting = true + this.#instance = uni.connectSocket({ + url: this.#url, + header: opts.header || {}, + complete: () => {} + }); + const onError = (errMsg)=>{ + // console.log(errMsg); + } + const onMessage = (data)=>{ + // console.log(data); + } + const onOpen = async ()=>{ + + } + const onClose = ()=>{ + + } + this.#event.on('onMessage', onMessage) + this.#event.on('onError', onError) + this.#event.on('onOpen', onOpen) + this.#event.on('onClose', onClose) + this.#instance.onOpen(async ()=>{ + this.#isConnected = true + this.#isConnecting = false + this.#time = 0 + this.#event.emit('onMessage', Msg.create("msg","客户端已连接",1)) + this.#event.emit('onOpen', isReConnect) + // this.heartTime() + if(isReConnect){ + this.send(Msg.create("reconnect",true,1)) + } + }) + this.#instance.onClose(()=>{ + this.#isConnected = false + this.#isConnecting = false + this.#instance = null + // this.clearHeartTime() + this.#event.off("onClose", onClose) + this.#event.off("onError", onError) + this.#event.off("onOpen", onOpen) + this.#event.off("onMessage", onMessage) + if(!this.#isClose){ + this.#time++ + if(this.#time<=this.#maxTime){ + this.#isConnecting = true + setTimeout(()=>{ + this.#event.emit('onMessage', Msg.create("msg",`第${this.#time}次重连`,1)) + // 重连 + this.initConnect(opts, true) + },2000) + }else{ + this.#event.emit('onMessage', Msg.create("msg","客户端已离线,请重试",1)) + this.#event.emit('onClose') + } + }else{ + this.isClose = false + this.#event.emit('onMessage', Msg.create("msg","客户端已离线",1)) + this.#event.emit('onClose') + } + }) + this.#instance.onError((errMsg)=>{ + this.#event.emit('onError', errMsg) + }) + this.#instance.onMessage((data)=>{ + // let rData = JSON.parse(decodeURIComponent(data.data).slice(0,-66)); + let rData = JSON.parse(decodeURIComponent(data.data)); + console.log(`原始数据:`,rData); + if(rData.hasOwnProperty("ping")) return + rData._success = rData._success == 0 ? 1 : rData._success + this.#event.emit('onMessage',rData) + }) + } +} + +export default new Sc() diff --git a/pages/Sub/Tabs/Tabs.vue b/pages/Sub/Tabs/Tabs.vue new file mode 100644 index 0000000..8254285 --- /dev/null +++ b/pages/Sub/Tabs/Tabs.vue @@ -0,0 +1,81 @@ + + + + + diff --git a/pages/Sub/Tabs/cell.vue b/pages/Sub/Tabs/cell.vue new file mode 100644 index 0000000..ba93352 --- /dev/null +++ b/pages/Sub/Tabs/cell.vue @@ -0,0 +1,241 @@ +