diff --git a/.env b/.env
new file mode 100644
index 0000000..486391d
--- /dev/null
+++ b/.env
@@ -0,0 +1,27 @@
+# 版本号
+SHOPRO_VERSION = v1.8.3
+
+# 后端接口 - 正式环境(通过 process.env.NODE_ENV 非 development)
+SHOPRO_BASE_URL = http://localhost:48080
+
+# 后端接口 - 测试环境(通过 process.env.NODE_ENV = development)
+SHOPRO_DEV_BASE_URL = http://127.0.0.1:48080
+### SHOPRO_DEV_BASE_URL = https://peiwan.mfzt.site
+
+# 后端接口前缀(一般不建议调整)
+SHOPRO_API_PATH = /app-api
+
+# 后端 websocket 接口前缀
+SHOPRO_WEBSOCKET_PATH = /infra/ws
+
+# 开发环境运行端口
+SHOPRO_DEV_PORT = 3000
+
+# 客户端静态资源地址 空=默认使用服务端指定的CDN资源地址前缀 | local=本地 | http(s)://xxx.xxx=自定义静态资源地址前缀
+SHOPRO_STATIC_URL = https://file.sheepjs.com
+
+# 是否开启直播 1 开启直播 | 0 关闭直播 (小程序官方后台未审核开通直播权限时请勿开启)
+SHOPRO_MPLIVE_ON = 0
+
+# 租户ID 默认 1
+SHOPRO_TENANT_ID = 1
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..43dda18
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,11 @@
+unpackage/*
+node_modules/*
+.idea/*
+deploy.sh
+.hbuilderx/
+.vscode/
+**/.DS_Store
+yarn.lock
+package-lock.json
+*.keystore
+pnpm-lock.yaml
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..7384df0
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,6 @@
+/unpackage/*
+/node_modules/**
+/uni_modules/**
+/public/*
+**/*.svg
+**/*.sh
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..fe0a3f9
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,10 @@
+{
+ "printWidth": 100,
+ "semi": true,
+ "vueIndentScriptAndStyle": true,
+ "singleQuote": true,
+ "trailingComma": "all",
+ "proseWrap": "never",
+ "htmlWhitespaceSensitivity": "strict",
+ "endOfLine": "auto"
+}
diff --git a/App.vue b/App.vue
new file mode 100644
index 0000000..1c143ef
--- /dev/null
+++ b/App.vue
@@ -0,0 +1,129 @@
+
+
+
diff --git a/androidPrivacy.json b/androidPrivacy.json
new file mode 100644
index 0000000..0d726ca
--- /dev/null
+++ b/androidPrivacy.json
@@ -0,0 +1,3 @@
+{
+ "prompt" : "template"
+}
diff --git a/components/custom-back-to-top/custom-back-to-top.vue b/components/custom-back-to-top/custom-back-to-top.vue
new file mode 100644
index 0000000..37bc253
--- /dev/null
+++ b/components/custom-back-to-top/custom-back-to-top.vue
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/htz-image-upload/htz-image-upload.vue b/components/htz-image-upload/htz-image-upload.vue
new file mode 100644
index 0000000..897499a
--- /dev/null
+++ b/components/htz-image-upload/htz-image-upload.vue
@@ -0,0 +1,831 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ×
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/qrcode-modal/qrcode-modal.vue b/components/qrcode-modal/qrcode-modal.vue
new file mode 100644
index 0000000..a94dc44
--- /dev/null
+++ b/components/qrcode-modal/qrcode-modal.vue
@@ -0,0 +1,121 @@
+
+
+
+
+ 长按二维码 关注公众号
+ 用于接收消息提醒
+ 点击验证
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/components/search-modal/search-modal.vue b/components/search-modal/search-modal.vue
new file mode 100644
index 0000000..bc5c1ba
--- /dev/null
+++ b/components/search-modal/search-modal.vue
@@ -0,0 +1,356 @@
+
+
+
+ 筛选
+
+ 年龄
+
+ {{age.text}}
+
+
+
+ 性别
+
+ {{sex.text}}
+
+
+
+ 是否同城(会员特权)
+
+ {{city.text}}
+
+
+
+ 城市(会员特权)
+
+ 全部
+ {{query.city}}
+ 切换城市
+
+
+
+ 确定
+
+
+
+
+
+
+
+
+
diff --git a/components/thorui/tui-actionsheet/tui-actionsheet.vue b/components/thorui/tui-actionsheet/tui-actionsheet.vue
new file mode 100644
index 0000000..84901ea
--- /dev/null
+++ b/components/thorui/tui-actionsheet/tui-actionsheet.vue
@@ -0,0 +1,201 @@
+
+
+
+
+ {{tips}}
+
+
+
+ {{item.text}}
+
+
+ 取消
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/components/thorui/tui-badge/tui-badge.vue b/components/thorui/tui-badge/tui-badge.vue
new file mode 100644
index 0000000..d361637
--- /dev/null
+++ b/components/thorui/tui-badge/tui-badge.vue
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/components/thorui/tui-bottom-popup/tui-bottom-popup.vue b/components/thorui/tui-bottom-popup/tui-bottom-popup.vue
new file mode 100644
index 0000000..c06e4ed
--- /dev/null
+++ b/components/thorui/tui-bottom-popup/tui-bottom-popup.vue
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/components/thorui/tui-bubble-popup/tui-bubble-popup.vue b/components/thorui/tui-bubble-popup/tui-bubble-popup.vue
new file mode 100644
index 0000000..dbb3cea
--- /dev/null
+++ b/components/thorui/tui-bubble-popup/tui-bubble-popup.vue
@@ -0,0 +1,204 @@
+
+
+
+
+
+
+
+
+
diff --git a/components/thorui/tui-circular-progress/tui-circular-progress.vue b/components/thorui/tui-circular-progress/tui-circular-progress.vue
new file mode 100644
index 0000000..2fc86a4
--- /dev/null
+++ b/components/thorui/tui-circular-progress/tui-circular-progress.vue
@@ -0,0 +1,309 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/components/thorui/tui-icon/tui-icon.js b/components/thorui/tui-icon/tui-icon.js
new file mode 100644
index 0000000..0304802
--- /dev/null
+++ b/components/thorui/tui-icon/tui-icon.js
@@ -0,0 +1,3 @@
+export default {
+
+}
diff --git a/components/thorui/tui-icon/tui-icon.vue b/components/thorui/tui-icon/tui-icon.vue
new file mode 100644
index 0000000..665c71a
--- /dev/null
+++ b/components/thorui/tui-icon/tui-icon.vue
@@ -0,0 +1,82 @@
+
+ {{ icons[name] || '' }}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/components/thorui/tui-modal/tui-modal.vue b/components/thorui/tui-modal/tui-modal.vue
new file mode 100644
index 0000000..b6e2898
--- /dev/null
+++ b/components/thorui/tui-modal/tui-modal.vue
@@ -0,0 +1,338 @@
+
+
+
+
+ {{ title }}
+ {{ content }}
+
+
+ {{ item.text || '确定' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/components/thorui/tui-navigation-bar/tui-navigation-bar.vue b/components/thorui/tui-navigation-bar/tui-navigation-bar.vue
new file mode 100644
index 0000000..7db07ea
--- /dev/null
+++ b/components/thorui/tui-navigation-bar/tui-navigation-bar.vue
@@ -0,0 +1,258 @@
+
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/components/thorui/tui-numberbox/tui-numberbox.vue b/components/thorui/tui-numberbox/tui-numberbox.vue
new file mode 100644
index 0000000..2fb6e7e
--- /dev/null
+++ b/components/thorui/tui-numberbox/tui-numberbox.vue
@@ -0,0 +1,248 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/thorui/tui-sticky/tui-sticky.vue b/components/thorui/tui-sticky/tui-sticky.vue
new file mode 100644
index 0000000..050047f
--- /dev/null
+++ b/components/thorui/tui-sticky/tui-sticky.vue
@@ -0,0 +1,166 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/components/thorui/tui-tabbar/tui-tabbar.vue b/components/thorui/tui-tabbar/tui-tabbar.vue
new file mode 100644
index 0000000..e03aab7
--- /dev/null
+++ b/components/thorui/tui-tabbar/tui-tabbar.vue
@@ -0,0 +1,287 @@
+
+
+
+
+
+
+
+
+ {{ item.isDot ? '' : item.num }}
+
+
+ {{ item.text }}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/components/thorui/tui-tabs/tui-tabs.vue b/components/thorui/tui-tabs/tui-tabs.vue
new file mode 100644
index 0000000..b734d7d
--- /dev/null
+++ b/components/thorui/tui-tabs/tui-tabs.vue
@@ -0,0 +1,346 @@
+
+
+
+
+ {{ item[field] }} ({{item[badgeField]}})
+
+ {{ item.isDot ? '' : item[badgeField] }}
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..2269a69
--- /dev/null
+++ b/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jsconfig.json b/jsconfig.json
new file mode 100644
index 0000000..b1968ee
--- /dev/null
+++ b/jsconfig.json
@@ -0,0 +1,9 @@
+{
+ "compilerOptions": {
+ "jsx": "preserve",
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["./*"]
+ }
+ }
+}
diff --git a/main.js b/main.js
new file mode 100644
index 0000000..3d6411c
--- /dev/null
+++ b/main.js
@@ -0,0 +1,21 @@
+import App from './App';
+
+// 引入 uView UI
+import uView from './uni_modules/vk-uview-ui';
+
+import { createSSRApp } from 'vue';
+import { setupPinia } from './sheep/store';
+
+
+export function createApp() {
+
+ const app = createSSRApp(App);
+
+ app.use(uView);
+
+ setupPinia(app);
+
+ return {
+ app,
+ };
+}
diff --git a/manifest.json b/manifest.json
new file mode 100644
index 0000000..28f1440
--- /dev/null
+++ b/manifest.json
@@ -0,0 +1,239 @@
+{
+ "name": "晚趣语音",
+ "appid": "__UNI__458F814",
+ "description": "基于 uni-app + Vue3 技术驱动的在线商城系统,内含诸多功能与丰富的活动,期待您的使用和反馈。",
+ "versionName": "2.1.0",
+ "versionCode": 183,
+ "transformPx": false,
+ "app-plus": {
+ "usingComponents": true,
+ "nvueCompiler": "uni-app",
+ "nvueStyleCompiler": "uni-app",
+ "compilerVersion": 3,
+ "nvueLaunchMode": "fast",
+ "splashscreen": {
+ "alwaysShowBeforeRender": true,
+ "waiting": true,
+ "autoclose": true,
+ "delay": 0
+ },
+ "safearea": {
+ "bottom": {
+ "offset": "none"
+ }
+ },
+ "modules": {
+ "Payment": {},
+ "Share": {},
+ "VideoPlayer": {},
+ "OAuth": {}
+ },
+ "distribute": {
+ "android": {
+ "permissions": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""
+ ],
+ "minSdkVersion": 21,
+ "schemes": "shopro"
+ },
+ "ios": {
+ "urlschemewhitelist": [
+ "baidumap",
+ "iosamap"
+ ],
+ "dSYMs": false,
+ "privacyDescription": {
+ "NSPhotoLibraryUsageDescription": "需要同意访问您的相册选取图片才能完善该条目",
+ "NSPhotoLibraryAddUsageDescription": "需要同意访问您的相册才能保存该图片",
+ "NSCameraUsageDescription": "需要同意访问您的摄像头拍摄照片才能完善该条目",
+ "NSUserTrackingUsageDescription": "开启追踪并不会获取您在其它站点的隐私信息,该行为仅用于标识设备,保障服务安全和提升浏览体验"
+ },
+ "urltypes": "shopro",
+ "capabilities": {
+ "entitlements": {
+ "com.apple.developer.associated-domains": [
+ "applinks:shopro.sheepjs.com"
+ ]
+ }
+ },
+ "idfa": true
+ },
+ "sdkConfigs": {
+ "speech": {
+ "ifly": {}
+ },
+ "ad": {},
+ "oauth": {
+ "apple": {},
+ "weixin": {
+ "appid": "wxae7a0c156da9383b",
+ "UniversalLinks": "https://shopro.sheepjs.com/uni-universallinks/__UNI__082C0BA/"
+ }
+ },
+ "payment": {
+ "weixin": {
+ "__platform__": [
+ "ios",
+ "android"
+ ],
+ "appid": "wxae7a0c156da9383b",
+ "UniversalLinks": "https://shopro.sheepjs.com/uni-universallinks/__UNI__082C0BA/"
+ },
+ "alipay": {
+ "__platform__": [
+ "ios",
+ "android"
+ ]
+ }
+ },
+ "share": {
+ "weixin": {
+ "appid": "wxae7a0c156da9383b",
+ "UniversalLinks": "https://shopro.sheepjs.com/uni-universallinks/__UNI__082C0BA/"
+ }
+ }
+ },
+ "orientation": [
+ "portrait-primary"
+ ],
+ "splashscreen": {
+ "androidStyle": "common",
+ "iosStyle": "common",
+ "useOriginalMsgbox": true
+ },
+ "icons": {
+ "android": {
+ "hdpi": "unpackage/res/icons/72x72.png",
+ "xhdpi": "unpackage/res/icons/96x96.png",
+ "xxhdpi": "unpackage/res/icons/144x144.png",
+ "xxxhdpi": "unpackage/res/icons/192x192.png"
+ },
+ "ios": {
+ "appstore": "unpackage/res/icons/1024x1024.png",
+ "ipad": {
+ "app": "unpackage/res/icons/76x76.png",
+ "app@2x": "unpackage/res/icons/152x152.png",
+ "notification": "unpackage/res/icons/20x20.png",
+ "notification@2x": "unpackage/res/icons/40x40.png",
+ "proapp@2x": "unpackage/res/icons/167x167.png",
+ "settings": "unpackage/res/icons/29x29.png",
+ "settings@2x": "unpackage/res/icons/58x58.png",
+ "spotlight": "unpackage/res/icons/40x40.png",
+ "spotlight@2x": "unpackage/res/icons/80x80.png"
+ },
+ "iphone": {
+ "app@2x": "unpackage/res/icons/120x120.png",
+ "app@3x": "unpackage/res/icons/180x180.png",
+ "notification@2x": "unpackage/res/icons/40x40.png",
+ "notification@3x": "unpackage/res/icons/60x60.png",
+ "settings@2x": "unpackage/res/icons/58x58.png",
+ "settings@3x": "unpackage/res/icons/87x87.png",
+ "spotlight@2x": "unpackage/res/icons/80x80.png",
+ "spotlight@3x": "unpackage/res/icons/120x120.png"
+ }
+ }
+ }
+ }
+ },
+ "quickapp": {},
+ "quickapp-native": {
+ "icon": "/static/logo.png",
+ "package": "com.example.demo",
+ "features": [
+ {
+ "name": "system.clipboard"
+ }
+ ]
+ },
+ "quickapp-webview": {
+ "icon": "/static/logo.png",
+ "package": "com.example.demo",
+ "minPlatformVersion": 1070,
+ "versionName": "1.0.0",
+ "versionCode": 100
+ },
+ "mp-weixin": {
+ "appid": "wx2708b75e03e8440a",
+ "setting": {
+ "urlCheck": false,
+ "minified": true,
+ "postcss": true
+ },
+ "optimization": {
+ "subPackages": true
+ },
+ "plugins": {},
+ "lazyCodeLoading": "requiredComponents",
+ "usingComponents": {},
+ "permission": {},
+ "requiredPrivateInfos": [
+ "chooseAddress"
+ ]
+ },
+ "mp-alipay": {
+ "usingComponents": true
+ },
+ "mp-baidu": {
+ "usingComponents": true
+ },
+ "mp-toutiao": {
+ "usingComponents": true
+ },
+ "mp-jd": {
+ "usingComponents": true
+ },
+ "h5": {
+ "template": "index.html",
+ "router": {
+ "mode": "hash",
+ "base": "./"
+ },
+ "sdkConfigs": {
+ "maps": {}
+ },
+ "async": {
+ "timeout": 20000
+ },
+ "title": "晚趣语音",
+ "optimization": {
+ "treeShaking": {
+ "enable": true
+ }
+ }
+ },
+ "vueVersion": "3",
+ "_spaceID": "192b4892-5452-4e1d-9f09-eee1ece40639",
+ "locale": "zh-Hans",
+ "fallbackLocale": "zh-Hans"
+}
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..b158175
--- /dev/null
+++ b/package.json
@@ -0,0 +1,103 @@
+{
+ "id": "shopro",
+ "name": "shopro",
+ "displayName": "晚趣语音",
+ "version": "2.2.0",
+ "description": "晚趣语音,一套代码,同时发行到iOS、Android、H5、微信小程序多个平台,请使用手机扫码快速体验强大功能",
+ "scripts": {
+ "prettier": "prettier --write \"{pages,sheep}/**/*.{js,json,tsx,css,less,scss,vue,html,md}\""
+ },
+ "repository": "https://github.com/sheepjs/shop.git",
+ "keywords": [
+ "商城",
+ "B2C",
+ "商城模板"
+ ],
+ "author": "",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/sheepjs/shop/issues"
+ },
+ "homepage": "https://github.com/dcloudio/hello-uniapp#readme",
+ "dcloudext": {
+ "category": [
+ "前端页面模板",
+ "uni-app前端项目模板"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": ""
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "u",
+ "aliyun": "u"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "u"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "u",
+ "百度": "u",
+ "字节跳动": "u",
+ "QQ": "u",
+ "京东": "u"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ },
+ "Vue": {
+ "vue2": "u",
+ "vue3": "y"
+ }
+ }
+ }
+ },
+ "dependencies": {
+ "dayjs": "^1.11.7",
+ "lodash": "^4.17.21",
+ "lodash-es": "^4.17.21",
+ "luch-request": "^3.0.8",
+ "pinia": "^2.0.33",
+ "pinia-plugin-persist-uni": "^1.2.0",
+ "weixin-js-sdk": "^1.6.0"
+ },
+ "devDependencies": {
+ "prettier": "^2.8.7",
+ "vconsole": "^3.15.0"
+ }
+}
diff --git a/pages.json b/pages.json
new file mode 100644
index 0000000..cd8ad0e
--- /dev/null
+++ b/pages.json
@@ -0,0 +1,625 @@
+{
+ "easycom": {
+ "autoscan": true,
+ "custom": {
+ "^s-(.*)": "@/sheep/components/s-$1/s-$1.vue",
+ "^su-(.*)": "@/sheep/ui/su-$1/su-$1.vue"
+ }
+ },
+ "pages": [
+ {
+ "path": "pages/tabbar/index",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "pages/index/login",
+ "style": {
+ "navigationBarTitleText": "登录"
+ }
+ }
+ ],
+ "subPackages": [
+ {
+ "root": "pages/trend",
+ "pages": [
+ {
+ "path": "city/list",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "detail/index",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "my/list",
+ "style": {
+ "navigationStyle": "custom"
+ },
+ "meta": {
+ "auth": true
+ }
+ }
+ ]
+ },
+ {
+ "root": "pages/reward",
+ "pages": [
+ {
+ "path": "list",
+ "style": {
+ "navigationStyle": "custom"
+ },
+ "meta": {
+ "auth": true
+ }
+ }
+ ]
+ },
+ {
+ "root": "pages/worker",
+ "pages": [
+ {
+ "path": "levelList/index",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "workerList/index",
+ "style": {
+ "navigationStyle": "custom"
+ },
+ "meta": {
+ "auth": true
+ }
+ },
+ {
+ "path": "workerList/set",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "blind/index",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ }
+ ]
+ },
+ {
+ "root": "pages/clerk",
+ "pages": [
+ {
+ "path": "apply/index",
+ "style": {
+ "navigationStyle": "custom"
+ },
+ "meta": {
+ "auth": true
+ }
+ },
+ {
+ "path": "fans/list",
+ "style": {
+ "navigationStyle": "custom"
+ },
+ "meta": {
+ "auth": true
+ }
+ },
+ {
+ "path": "apply/edit",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "detail/index",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ }
+ ]
+ },
+ {
+ "root": "pages/goods",
+ "pages": [
+ {
+ "path": "comment/worker/add",
+ "style": {
+ "navigationBarTitleText": "评价店员"
+ },
+ "meta": {
+ "auth": true
+ }
+ }
+ ]
+ },
+ {
+ "root": "pages/order",
+ "pages": [
+ {
+ "path": "worker/confirm",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "blind/confirm",
+ "style": {
+ "navigationStyle": "custom"
+ },
+ "meta": {
+ "auth": true
+ }
+ },
+ {
+ "path": "worker/aftersale/apply",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "my/aftersale/apply",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "worker/aftersale/list",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "blind/detail",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "worker/detail",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "my/detail",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "worker/list",
+ "style": {
+ "navigationStyle": "custom"
+ },
+ "meta": {
+ "auth": true
+ }
+ },
+ {
+ "path": "blind/list",
+ "style": {
+ "navigationStyle": "custom"
+ },
+ "meta": {
+ "auth": true
+ }
+ },
+ {
+ "path": "my/list",
+ "style": {
+ "navigationStyle": "custom"
+ },
+ "meta": {
+ "auth": true
+ }
+ },
+ {
+ "path": "receive/index",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "my/index",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ }
+ ]
+ },
+ {
+ "root": "pages/user",
+ "pages": [{
+ "path": "info",
+ "style": {
+ "navigationBarTitleText": "我的信息"
+ },
+ "meta": {
+ "auth": true,
+ "sync": true,
+ "title": "用户信息",
+ "group": "用户中心"
+ }
+ },
+ {
+ "path": "vip",
+ "style": {
+ "navigationStyle": "custom"
+ },
+ "meta": {
+ "auth": true
+ }
+ },
+ {
+ "path": "detail/index",
+ "style": {
+ "navigationStyle": "custom"
+ },
+ "meta": {
+ "auth": true
+ }
+ },
+ {
+ "path": "wallet/money",
+ "style": {
+ "navigationBarTitleText": "我的余额"
+ },
+ "meta": {
+ "auth": true,
+ "sync": true,
+ "title": "用户余额",
+ "group": "用户中心"
+ }
+ },
+ {
+ "path": "wallet/score",
+ "style": {
+ "navigationBarTitleText": "我的积分"
+ },
+ "meta": {
+ "auth": true,
+ "sync": true,
+ "title": "用户积分",
+ "group": "用户中心"
+ }
+ }
+ ]
+ },
+ {
+ "root": "pages/commission",
+ "pages": [{
+ "path": "index",
+ "style": {
+ "navigationBarTitleText": "分销"
+ },
+ "meta": {
+ "auth": true,
+ "sync": true,
+ "title": "分销中心",
+ "group": "分销商城"
+ }
+ },
+ {
+ "path": "wallet",
+ "style": {
+ "navigationBarTitleText": "我的佣金"
+ },
+ "meta": {
+ "auth": true,
+ "sync": true,
+ "title": "用户佣金",
+ "group": "分销中心"
+ }
+ },
+ {
+ "path": "order",
+ "style": {
+ "navigationBarTitleText": "分销订单"
+ },
+ "meta": {
+ "auth": true,
+ "sync": true,
+ "title": "分销订单",
+ "group": "分销商城"
+ }
+ },
+ {
+ "path": "team",
+ "style": {
+ "navigationBarTitleText": "我的团队"
+ },
+ "meta": {
+ "auth": true,
+ "sync": true,
+ "title": "我的团队",
+ "group": "分销商城"
+ }
+ }, {
+ "path": "promoter",
+ "style": {
+ "navigationBarTitleText": "推广人排行榜"
+ },
+ "meta": {
+ "auth": true,
+ "sync": true,
+ "title": "推广人排行榜",
+ "group": "分销商城"
+ }
+ }, {
+ "path": "commission-ranking",
+ "style": {
+ "navigationBarTitleText": "佣金排行榜"
+ },
+ "meta": {
+ "auth": true,
+ "sync": true,
+ "title": "佣金排行榜",
+ "group": "分销商城"
+ }
+ }, {
+ "path": "withdraw",
+ "style": {
+ "navigationBarTitleText": "申请提现"
+ },
+ "meta": {
+ "auth": true,
+ "sync": true,
+ "title": "申请提现",
+ "group": "分销商城"
+ }
+ }
+ ]
+ },
+ {
+ "root": "pages/app",
+ "pages": [{
+ "path": "sign",
+ "style": {
+ "navigationBarTitleText": "签到中心"
+ },
+ "meta": {
+ "auth": true,
+ "sync": true,
+ "title": "签到中心",
+ "group": "应用"
+ }
+ }]
+ },
+ {
+ "root": "pages/public",
+ "pages": [{
+ "path": "setting",
+ "style": {
+ "navigationBarTitleText": "系统设置"
+ },
+ "meta": {
+ "auth": true,
+ "sync": true,
+ "title": "系统设置",
+ "group": "通用"
+ }
+ },
+ {
+ "path": "richtext",
+ "style": {
+ "navigationBarTitleText": "富文本"
+ },
+ "meta": {
+ "sync": true,
+ "title": "富文本",
+ "group": "通用"
+ }
+ },
+ {
+ "path": "faq",
+ "style": {
+ "navigationBarTitleText": "常见问题"
+ },
+ "meta": {
+ "sync": true,
+ "title": "常见问题",
+ "group": "通用"
+ }
+ },
+ {
+ "path": "error",
+ "style": {
+ "navigationBarTitleText": "错误页面"
+ }
+ },
+ {
+ "path": "webview",
+ "style": {
+ "navigationBarTitleText": ""
+ }
+ }
+ ]
+ },
+ {
+ "root": "pages/coupon",
+ "pages": [{
+ "path": "list",
+ "style": {
+ "navigationBarTitleText": "领券中心"
+ },
+ "meta": {
+ "auth": true,
+ "sync": true,
+ "title": "领券中心",
+ "group": "优惠券"
+ }
+ },
+ {
+ "path": "detail",
+ "style": {
+ "navigationBarTitleText": "优惠券"
+ },
+ "meta": {
+ "auth": false,
+ "sync": true,
+ "title": "优惠券详情",
+ "group": "优惠券"
+ }
+ }
+ ]
+ },
+ {
+ "root": "pages/chat",
+ "pages": [{
+ "path": "index",
+ "style": {
+ "navigationBarTitleText": "客服"
+ },
+ "meta": {
+ "auth": true,
+ "sync": true,
+ "title": "客服",
+ "group": "客服"
+ }
+ }]
+ },
+ {
+ "root": "pages/im",
+ "pages": [{
+ "path": "index",
+ "style": {
+ "navigationBarTitleText": "聊天"
+ },
+ "meta": {
+ "auth": true,
+ "sync": true,
+ "title": "聊天",
+ "group": "聊天"
+ }
+ }]
+ },
+ {
+ "root": "pages/point",
+ "pages": [
+ {
+ "path": "recharge",
+ "style": {
+ "navigationBarTitleText": "充值积分"
+ },
+ "meta": {
+ "auth": true,
+ "sync": true,
+ "title": "充值积分",
+ "group": "支付"
+ }
+ },
+ {
+ "path": "recharge-log",
+ "style": {
+ "navigationBarTitleText": "充值记录"
+ },
+ "meta": {
+ "auth": true,
+ "sync": true,
+ "title": "充值记录",
+ "group": "支付"
+ }
+ },
+ {
+ "path": "result",
+ "style": {
+ "navigationBarTitleText": "支付结果"
+ },
+ "meta": {
+ "auth": true,
+ "sync": true,
+ "title": "支付结果",
+ "group": "支付"
+ }
+ }
+ ]
+ },
+ {
+ "root": "pages/pay",
+ "pages": [{
+ "path": "index",
+ "style": {
+ "navigationBarTitleText": "收银台"
+ }
+ },
+ {
+ "path": "result",
+ "style": {
+ "navigationBarTitleText": "支付结果"
+ }
+ },
+ {
+ "path": "worker/index",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "point/index",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "vip/index",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "reward/index",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "worker/result",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "recharge",
+ "style": {
+ "navigationBarTitleText": "充值余额"
+ },
+ "meta": {
+ "auth": true,
+ "sync": true,
+ "title": "充值余额",
+ "group": "支付"
+ }
+ },
+ {
+ "path": "recharge-log",
+ "style": {
+ "navigationBarTitleText": "充值记录"
+ },
+ "meta": {
+ "auth": true,
+ "sync": true,
+ "title": "充值记录",
+ "group": "支付"
+ }
+ }
+ ]
+ }
+ ],
+ "globalStyle": {
+ "navigationBarTextStyle": "black",
+ "navigationBarTitleText": "晚趣语音",
+ "navigationBarBackgroundColor": "#FFFFFF",
+ "backgroundColor": "#FFFFFF",
+ "navigationStyle": "custom"
+ }
+}
diff --git a/pages/app/sign.vue b/pages/app/sign.vue
new file mode 100644
index 0000000..7a4702c
--- /dev/null
+++ b/pages/app/sign.vue
@@ -0,0 +1,451 @@
+
+
+
+
+
+
+
+
+
+ 签到日历
+
+ 已连续签到 {{ state.signInfo.continuousDay }} 天
+
+
+
+
+
+ 第{{ item.day }}天
+
+
+
+
+ + {{ item.point }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 签到说明
+ 1、已累计签到{{state.signInfo.totalDay}}天
+
+ 2、据说连续签到第 {{ state.maxDay }} 天可获得超额积分,一定要坚持签到哦~~~
+
+
+
+
+
+
+
+
+
+
+ {{ state.signResult.point }} 积分
+ {{ state.signResult.experience }} 经验
+
+
+ 已连续打卡 {{ state.signResult.day }} 天
+
+
+
+ 签到成功
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/chat/components/goods.vue b/pages/chat/components/goods.vue
new file mode 100644
index 0000000..eabdd21
--- /dev/null
+++ b/pages/chat/components/goods.vue
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/pages/chat/components/messageInput.vue b/pages/chat/components/messageInput.vue
new file mode 100644
index 0000000..1714ac5
--- /dev/null
+++ b/pages/chat/components/messageInput.vue
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/chat/components/messageList.vue b/pages/chat/components/messageList.vue
new file mode 100644
index 0000000..d08fd83
--- /dev/null
+++ b/pages/chat/components/messageList.vue
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 有新消息
+
+
+
+
+
diff --git a/pages/chat/components/messageListItem.vue b/pages/chat/components/messageListItem.vue
new file mode 100644
index 0000000..3379539
--- /dev/null
+++ b/pages/chat/components/messageListItem.vue
@@ -0,0 +1,304 @@
+
+
+
+
+
+
+
+ {{ formatDate(message.createTime) }}
+
+
+
+ {{ message.content }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/chat/components/order.vue b/pages/chat/components/order.vue
new file mode 100644
index 0000000..3a68172
--- /dev/null
+++ b/pages/chat/components/order.vue
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
+
+ 共 {{ orderData.productCount }} 件商品,总金额:
+
+ ¥{{ fen2yuan(orderData.payPrice) }}
+
+
+
+
+
+
+
+
+
diff --git a/pages/chat/components/select-popup.vue b/pages/chat/components/select-popup.vue
new file mode 100644
index 0000000..60711af
--- /dev/null
+++ b/pages/chat/components/select-popup.vue
@@ -0,0 +1,151 @@
+
+
+
+
+
+
+
+
+
diff --git a/pages/chat/components/toolsPopup.vue b/pages/chat/components/toolsPopup.vue
new file mode 100644
index 0000000..d446197
--- /dev/null
+++ b/pages/chat/components/toolsPopup.vue
@@ -0,0 +1,166 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 图片
+
+
+
+
+ 订单
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/chat/index.vue b/pages/chat/index.vue
new file mode 100644
index 0000000..5b20a61
--- /dev/null
+++ b/pages/chat/index.vue
@@ -0,0 +1,187 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/chat/util/constants.js b/pages/chat/util/constants.js
new file mode 100644
index 0000000..bdf5cb3
--- /dev/null
+++ b/pages/chat/util/constants.js
@@ -0,0 +1,21 @@
+export const KeFuMessageContentTypeEnum = {
+ TEXT: 1, // 文本消息
+ IMAGE: 2, // 图片消息
+ VOICE: 3, // 语音消息
+ VIDEO: 4, // 视频消息
+ SYSTEM: 5, // 系统消息
+ // ========== 商城特殊消息 ==========
+ PRODUCT: 10,// 商品消息
+ ORDER: 11,// 订单消息"
+};
+export const UserTypeEnum = {
+ MEMBER: 1, // 会员 面向 c 端,普通用户
+ ADMIN: 2, // 管理员 面向 b 端,管理后台
+};
+// Promotion 的 WebSocket 消息类型枚举类
+export const WebSocketMessageTypeConstants = {
+ KEFU_MESSAGE_TYPE: 'kefu_message_type', // 客服消息类型
+ IM_MESSAGE_READ: 'im_message_read_status_change', // IM消息已读
+ IM_MESSAGE_NEWS: 'im_message_news', // IM新消息
+ KEFU_MESSAGE_ADMIN_READ: 'kefu_message_read_status_change' // 客服消息管理员已读
+}
diff --git a/pages/chat/util/emoji.js b/pages/chat/util/emoji.js
new file mode 100644
index 0000000..83e6e84
--- /dev/null
+++ b/pages/chat/util/emoji.js
@@ -0,0 +1,58 @@
+export const emojiList = [
+ { name: '[笑掉牙]', file: 'xiaodiaoya.png' },
+ { name: '[可爱]', file: 'keai.png' },
+ { name: '[冷酷]', file: 'lengku.png' },
+ { name: '[闭嘴]', file: 'bizui.png' },
+ { name: '[生气]', file: 'shengqi.png' },
+ { name: '[惊恐]', file: 'jingkong.png' },
+ { name: '[瞌睡]', file: 'keshui.png' },
+ { name: '[大笑]', file: 'daxiao.png' },
+ { name: '[爱心]', file: 'aixin.png' },
+ { name: '[坏笑]', file: 'huaixiao.png' },
+ { name: '[飞吻]', file: 'feiwen.png' },
+ { name: '[疑问]', file: 'yiwen.png' },
+ { name: '[开心]', file: 'kaixin.png' },
+ { name: '[发呆]', file: 'fadai.png' },
+ { name: '[流泪]', file: 'liulei.png' },
+ { name: '[汗颜]', file: 'hanyan.png' },
+ { name: '[惊悚]', file: 'jingshu.png' },
+ { name: '[困~]', file: 'kun.png' },
+ { name: '[心碎]', file: 'xinsui.png' },
+ { name: '[天使]', file: 'tianshi.png' },
+ { name: '[晕]', file: 'yun.png' },
+ { name: '[啊]', file: 'a.png' },
+ { name: '[愤怒]', file: 'fennu.png' },
+ { name: '[睡着]', file: 'shuizhuo.png' },
+ { name: '[面无表情]', file: 'mianwubiaoqing.png' },
+ { name: '[难过]', file: 'nanguo.png' },
+ { name: '[犯困]', file: 'fankun.png' },
+ { name: '[好吃]', file: 'haochi.png' },
+ { name: '[呕吐]', file: 'outu.png' },
+ { name: '[龇牙]', file: 'ziya.png' },
+ { name: '[懵比]', file: 'mengbi.png' },
+ { name: '[白眼]', file: 'baiyan.png' },
+ { name: '[饿死]', file: 'esi.png' },
+ { name: '[凶]', file: 'xiong.png' },
+ { name: '[感冒]', file: 'ganmao.png' },
+ { name: '[流汗]', file: 'liuhan.png' },
+ { name: '[笑哭]', file: 'xiaoku.png' },
+ { name: '[流口水]', file: 'liukoushui.png' },
+ { name: '[尴尬]', file: 'ganga.png' },
+ { name: '[惊讶]', file: 'jingya.png' },
+ { name: '[大惊]', file: 'dajing.png' },
+ { name: '[不好意思]', file: 'buhaoyisi.png' },
+ { name: '[大闹]', file: 'danao.png' },
+ { name: '[不可思议]', file: 'bukesiyi.png' },
+ { name: '[爱你]', file: 'aini.png' },
+ { name: '[红心]', file: 'hongxin.png' },
+ { name: '[点赞]', file: 'dianzan.png' },
+ { name: '[恶魔]', file: 'emo.png' },
+];
+
+export let emojiPage = {};
+emojiList.forEach((item, index) => {
+ if (!emojiPage[Math.floor(index / 30) + 1]) {
+ emojiPage[Math.floor(index / 30) + 1] = [];
+ }
+ emojiPage[Math.floor(index / 30) + 1].push(item);
+});
diff --git a/pages/clerk/apply/components/formAvatar.vue b/pages/clerk/apply/components/formAvatar.vue
new file mode 100644
index 0000000..73b8f4a
--- /dev/null
+++ b/pages/clerk/apply/components/formAvatar.vue
@@ -0,0 +1,183 @@
+
+
+
+ 上传头像
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/apply/components/formCity.vue b/pages/clerk/apply/components/formCity.vue
new file mode 100644
index 0000000..b101a8a
--- /dev/null
+++ b/pages/clerk/apply/components/formCity.vue
@@ -0,0 +1,69 @@
+
+
+
+ 所在城市
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/apply/components/formImage.vue b/pages/clerk/apply/components/formImage.vue
new file mode 100644
index 0000000..ad63575
--- /dev/null
+++ b/pages/clerk/apply/components/formImage.vue
@@ -0,0 +1,73 @@
+
+
+
+ 上传图片
+ {{imgList.length}}/{{number}}
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/apply/components/formSex.vue b/pages/clerk/apply/components/formSex.vue
new file mode 100644
index 0000000..00ddbdc
--- /dev/null
+++ b/pages/clerk/apply/components/formSex.vue
@@ -0,0 +1,90 @@
+
+
+ 性别
+
+ {{item.name}}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/apply/components/formVoice.vue b/pages/clerk/apply/components/formVoice.vue
new file mode 100644
index 0000000..1422d8c
--- /dev/null
+++ b/pages/clerk/apply/components/formVoice.vue
@@ -0,0 +1,255 @@
+
+
+
+ 录音
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 停止播放
+ 播放录音
+
+
+
+
+
+
+ 重录
+
+
+
+
+
+
+
+
+ 停止播放
+ 播放录音
+
+
+
+
+
+ 上传录音文件
+
+
+
+ 重录
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/apply/edit.vue b/pages/clerk/apply/edit.vue
new file mode 100644
index 0000000..4d017c4
--- /dev/null
+++ b/pages/clerk/apply/edit.vue
@@ -0,0 +1,213 @@
+
+
+
+
+
+
+
+
+
+
+ 昵称
+
+
+
+
+ 年龄
+
+
+
+ 微信
+
+
+
+ 手机号
+
+
+
+ 相关经验
+
+
+
+ 自我介绍
+
+
+
+ 所在城市
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 提交申请
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/apply/index.vue b/pages/clerk/apply/index.vue
new file mode 100644
index 0000000..ff88263
--- /dev/null
+++ b/pages/clerk/apply/index.vue
@@ -0,0 +1,307 @@
+
+
+
+
+
+
+
+ 获取实时审核结果
+ 立即订阅
+
+
+
+
+
+
+
+
+
+ 昵称
+
+
+
+
+ 年龄
+
+
+
+ 微信
+
+
+
+ 手机号
+
+
+
+ 自我介绍
+
+
+
+ 所在城市
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 我已阅读并接受
+ 《达人申请协议》
+
+
+
+ 提交申请
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/detail/components/detail-navbar.vue b/pages/clerk/detail/components/detail-navbar.vue
new file mode 100644
index 0000000..f4b7e2f
--- /dev/null
+++ b/pages/clerk/detail/components/detail-navbar.vue
@@ -0,0 +1,225 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.label }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/detail/components/gameBox.vue b/pages/clerk/detail/components/gameBox.vue
new file mode 100644
index 0000000..7930cef
--- /dev/null
+++ b/pages/clerk/detail/components/gameBox.vue
@@ -0,0 +1,150 @@
+
+
+
+
+
+ 服务类型
+
+
+ {{option.name}}
+
+
+
+
+
+
+ 选项
+
+
+ {{option.name}}
+
+
+
+
+
+
+ 选项
+
+
+ {{option.name}}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/detail/components/giftList.vue b/pages/clerk/detail/components/giftList.vue
new file mode 100644
index 0000000..63eefff
--- /dev/null
+++ b/pages/clerk/detail/components/giftList.vue
@@ -0,0 +1,316 @@
+
+
+
+
+ 选择礼物
+
+
+ 取消
+
+
+
+
+
+
+
+ 特效
+ ·{{item.tag}}
+
+
+ {{item.tag}}
+
+
+ {{item.name}}
+ {{ fen2yuan(item.money) }} 钻石
+
+
+
+
+
+
+
+
+
+
+ {{gift.name}}
+ {{ fen2yuan(gift.money) }} 钻石
+
+ 取消
+ 确定
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/detail/components/giftPopup.vue b/pages/clerk/detail/components/giftPopup.vue
new file mode 100644
index 0000000..397d7f0
--- /dev/null
+++ b/pages/clerk/detail/components/giftPopup.vue
@@ -0,0 +1,444 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 服务类型
+
+
+
+ 赠礼
+
+
+
+
+
+
+ 打赏金额
+
+
+
+
+
+
+
+
+ 赠送礼物
+
+
+ 已选【{{gift.name}}】
+ 点击选择礼物
+
+
+
+
+
+
+ 礼物数量
+
+
+
+
+
+
+
+
+
+ 心动留言
+
+
+
+
+
+
+
+
+ 您的微信号
+
+
+
+
+
+
+
+
+
+
+
+
+ 立即赠送
+
+
+
+
+
+ 总价:
+ {{ fen2yuan(gift.money*form.count) }}
+ 钻石
+
+
+ 立即赠送
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/detail/components/layout.vue b/pages/clerk/detail/components/layout.vue
new file mode 100644
index 0000000..f552d28
--- /dev/null
+++ b/pages/clerk/detail/components/layout.vue
@@ -0,0 +1,263 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 立即下单
+ 赠礼
+
+
+ 立即下单
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/clerk/detail/components/navBar.vue b/pages/clerk/detail/components/navBar.vue
new file mode 100644
index 0000000..8504cbe
--- /dev/null
+++ b/pages/clerk/detail/components/navBar.vue
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/detail/components/orderPopup.vue b/pages/clerk/detail/components/orderPopup.vue
new file mode 100644
index 0000000..a50c285
--- /dev/null
+++ b/pages/clerk/detail/components/orderPopup.vue
@@ -0,0 +1,282 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 购买数量
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 总价:
+ {{ fen2yuan(game.price*order.num) }}
+ 钻石
+
+
+ 立即下单
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/detail/components/photoBox.vue b/pages/clerk/detail/components/photoBox.vue
new file mode 100644
index 0000000..7d575ed
--- /dev/null
+++ b/pages/clerk/detail/components/photoBox.vue
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/detail/components/postList.vue b/pages/clerk/detail/components/postList.vue
new file mode 100644
index 0000000..7c1bca8
--- /dev/null
+++ b/pages/clerk/detail/components/postList.vue
@@ -0,0 +1,342 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.city}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/detail/components/priceList.vue b/pages/clerk/detail/components/priceList.vue
new file mode 100644
index 0000000..284ef71
--- /dev/null
+++ b/pages/clerk/detail/components/priceList.vue
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/detail/components/radioBox.vue b/pages/clerk/detail/components/radioBox.vue
new file mode 100644
index 0000000..da299ce
--- /dev/null
+++ b/pages/clerk/detail/components/radioBox.vue
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+ {{option.name}}
+
+
+ {{option.number}}
+ 钻石
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/detail/components/rateList.vue b/pages/clerk/detail/components/rateList.vue
new file mode 100644
index 0000000..648d122
--- /dev/null
+++ b/pages/clerk/detail/components/rateList.vue
@@ -0,0 +1,125 @@
+
+
+
+
+
+
+
+ {{item.userNickname}}
+
+
+ {{item.createTimeStr}}
+
+
+
+
+ {{clerk.nickname}}
+ 服务类型:{{item.skuName}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/detail/components/starList.vue b/pages/clerk/detail/components/starList.vue
new file mode 100644
index 0000000..32ff751
--- /dev/null
+++ b/pages/clerk/detail/components/starList.vue
@@ -0,0 +1,310 @@
+
+
+
+
+ 礼物墙
+ (已点亮:{{starNum}}/{{total}})
+
+
+
+
+
+
+
+ 特效
+ ·{{item.tag}}
+
+
+ {{item.tag}}
+
+
+ {{item.name}}
+ x {{item.playNum}}
+ 点亮
+ 赠送
+ 已下架
+
+
+
+
+
+
+
+
+
+
+ {{gift.name}}
+ {{ fen2yuan(gift.money) }} 钻石
+
+ 取消
+ 点亮
+ 赠送
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/detail/components/stickyBox.vue b/pages/clerk/detail/components/stickyBox.vue
new file mode 100644
index 0000000..089eda2
--- /dev/null
+++ b/pages/clerk/detail/components/stickyBox.vue
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/detail/components/table-bd.vue b/pages/clerk/detail/components/table-bd.vue
new file mode 100644
index 0000000..8819269
--- /dev/null
+++ b/pages/clerk/detail/components/table-bd.vue
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
diff --git a/pages/clerk/detail/components/table-td.vue b/pages/clerk/detail/components/table-td.vue
new file mode 100644
index 0000000..13c6ea3
--- /dev/null
+++ b/pages/clerk/detail/components/table-td.vue
@@ -0,0 +1,305 @@
+
+
+
+
+
+
+
+
+
diff --git a/pages/clerk/detail/components/table-tr.vue b/pages/clerk/detail/components/table-tr.vue
new file mode 100644
index 0000000..2b12c95
--- /dev/null
+++ b/pages/clerk/detail/components/table-tr.vue
@@ -0,0 +1,208 @@
+
+
+
+
+
+
+
+
+
diff --git a/pages/clerk/detail/components/tableList.vue b/pages/clerk/detail/components/tableList.vue
new file mode 100644
index 0000000..50ddbde
--- /dev/null
+++ b/pages/clerk/detail/components/tableList.vue
@@ -0,0 +1,98 @@
+
+
+
+
+
+ 服务项目
+ 价格
+
+
+
+
+ {{tb.name}}
+
+
+
+
+
+ {{tb2.name}}
+
+
+
+
+
+
+ {{ fen2yuan(tb2.price) }}
+
+
+
+
+
+
+
+
+
+ {{tb2.name}}
+
+
+
+ {{tb3.name}}
+
+
+
+
+
+
+
+
+
+
+
+ {{ fen2yuan(tb3.price) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/detail/components/userBox.vue b/pages/clerk/detail/components/userBox.vue
new file mode 100644
index 0000000..3e6ce6f
--- /dev/null
+++ b/pages/clerk/detail/components/userBox.vue
@@ -0,0 +1,270 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{clerk.nickname}}
+
+
+ {{clerkLevel.name}}
+
+
+ 可接单
+ 休息中
+
+
+
+
+
+
+
+
+
+ {{clerk.age}}
+
+
+ {{clerk.intro}}
+
+
+
+
+
+
+
+
+ {{categoryName}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/detail/components/voicePlay.vue b/pages/clerk/detail/components/voicePlay.vue
new file mode 100644
index 0000000..4eee5b7
--- /dev/null
+++ b/pages/clerk/detail/components/voicePlay.vue
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{sec}}"
+
+
+
+
diff --git a/pages/clerk/detail/index.vue b/pages/clerk/detail/index.vue
new file mode 100644
index 0000000..3f63706
--- /dev/null
+++ b/pages/clerk/detail/index.vue
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/fans/components/layout.vue b/pages/clerk/fans/components/layout.vue
new file mode 100644
index 0000000..f0bb9d9
--- /dev/null
+++ b/pages/clerk/fans/components/layout.vue
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/clerk/fans/components/orderList.vue b/pages/clerk/fans/components/orderList.vue
new file mode 100644
index 0000000..adc3a4f
--- /dev/null
+++ b/pages/clerk/fans/components/orderList.vue
@@ -0,0 +1,212 @@
+
+
+
+
+
+
+
+
+
+ {{item.nickname}}
+
+
+ 在线
+
+
+
+ 休息中
+
+
+ {{item.city}}
+
+
+ 女
+ 男
+ {{item.age}}岁
+
+
+ {{item.fansNum}}人收藏
+
+
+
+
+ {{item.intro}}
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/clerk/fans/list.vue b/pages/clerk/fans/list.vue
new file mode 100644
index 0000000..6825d61
--- /dev/null
+++ b/pages/clerk/fans/list.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/commission/commission-ranking.vue b/pages/commission/commission-ranking.vue
new file mode 100644
index 0000000..d8dd4ab
--- /dev/null
+++ b/pages/commission/commission-ranking.vue
@@ -0,0 +1,249 @@
+
+
+
+
+
+
+
+
+ {{ item }}
+
+
+
+
+
+
+
+
+ {{ index + 1 }}
+
+
+
+
+
+ {{ item.nickname }}
+
+ ¥{{ fen2yuan(item.brokeragePrice) }}
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/commission/components/account-info.vue b/pages/commission/components/account-info.vue
new file mode 100644
index 0000000..d904b8d
--- /dev/null
+++ b/pages/commission/components/account-info.vue
@@ -0,0 +1,125 @@
+
+
+
+
+
+
+
+
+
+ 当前佣金(元)
+
+ {{ state.showMoney ? fen2yuan(state.summary.brokeragePrice || 0) : '***' }}
+
+
+
+ 昨天的佣金(元)
+
+ {{ state.showMoney ? fen2yuan(state.summary.yesterdayPrice || 0) : '***' }}
+
+
+
+ 累计已提(元)
+
+ {{ state.showMoney ? fen2yuan(state.summary.withdrawPrice || 0) : '***' }}
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/commission/components/account-type-select.vue b/pages/commission/components/account-type-select.vue
new file mode 100644
index 0000000..c5ee5c0
--- /dev/null
+++ b/pages/commission/components/account-type-select.vue
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/commission/components/commission-auth.vue b/pages/commission/components/commission-auth.vue
new file mode 100644
index 0000000..9a484fa
--- /dev/null
+++ b/pages/commission/components/commission-auth.vue
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+ 抱歉!您没有分销权限
+ 该功能暂不可用
+
+
+
+
+
+
+
+
+
diff --git a/pages/commission/components/commission-info.vue b/pages/commission/components/commission-info.vue
new file mode 100644
index 0000000..948f380
--- /dev/null
+++ b/pages/commission/components/commission-info.vue
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+
+ {{ userInfo.nickname }}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/commission/components/commission-log.vue b/pages/commission/components/commission-log.vue
new file mode 100644
index 0000000..2c4b70c
--- /dev/null
+++ b/pages/commission/components/commission-log.vue
@@ -0,0 +1,181 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.title }} {{ fen2yuan(item.price) }} 元
+
+
+
+ {{ dayjs(item.createTime).fromNow() }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/commission/components/commission-menu.vue b/pages/commission/components/commission-menu.vue
new file mode 100644
index 0000000..988b9b7
--- /dev/null
+++ b/pages/commission/components/commission-menu.vue
@@ -0,0 +1,137 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/commission/goods.vue b/pages/commission/goods.vue
new file mode 100644
index 0000000..509cc04
--- /dev/null
+++ b/pages/commission/goods.vue
@@ -0,0 +1,156 @@
+
+
+
+
+
+
+
+ 预计佣金:计算中
+
+ 预计佣金:{{ fen2yuan(item.brokerageMinPrice) }}
+
+
+ 预计佣金:{{ fen2yuan(item.brokerageMinPrice) }} ~
+ {{ fen2yuan(item.brokerageMaxPrice) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/commission/index.vue b/pages/commission/index.vue
new file mode 100644
index 0000000..1b7ee06
--- /dev/null
+++ b/pages/commission/index.vue
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/commission/order.vue b/pages/commission/order.vue
new file mode 100644
index 0000000..54232a4
--- /dev/null
+++ b/pages/commission/order.vue
@@ -0,0 +1,328 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/commission/promoter.vue b/pages/commission/promoter.vue
new file mode 100644
index 0000000..b7d0a89
--- /dev/null
+++ b/pages/commission/promoter.vue
@@ -0,0 +1,297 @@
+
+
+
+
+
+
+
+
+
+ {{ index + 4 }}
+
+
+
+
+ {{item.nickname}}
+
+ {{ item.brokerageUserCount }}人
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/commission/team.vue b/pages/commission/team.vue
new file mode 100644
index 0000000..df1ac58
--- /dev/null
+++ b/pages/commission/team.vue
@@ -0,0 +1,585 @@
+
+
+
+
+
+
+
+
+ 一级({{ state.summary.firstBrokerageUserCount || 0 }})
+
+
+ 二级({{ state.summary.secondBrokerageUserCount || 0 }})
+
+
+
+
+
+
+
+
+
+
+
+ 团队排序
+
+
+
+
+ 团队排序
+
+
+
+ 团队排序
+
+
+
+ 金额排序
+
+
+
+ 金额排序
+
+
+
+ 金额排序
+
+
+
+ 订单排序
+
+
+
+ 订单排序
+
+
+
+ 订单排序
+
+
+
+
+
+
+
+
+
+
+ {{ item.nickname }}
+
+ 加入时间:
+ {{ sheep.$helper.timeFormat(item.brokerageTime, 'yyyy-mm-dd hh:MM:ss') }}
+
+
+
+
+
+ {{ item.brokerageUserCount || 0 }} 人
+
+
+ {{ item.orderCount || 0 }}单
+
+ {{ item.brokeragePrice || 0 }}元
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/commission/wallet.vue b/pages/commission/wallet.vue
new file mode 100644
index 0000000..bc69563
--- /dev/null
+++ b/pages/commission/wallet.vue
@@ -0,0 +1,533 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 转余额
+ 将您的佣金转为钻石继续消费
+
+ ¥
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.description }}
+
+ +{{ fen2yuan(item.price) }}
+ {{ fen2yuan(item.price) }}
+
+
+
+ {{
+ sheep.$helper.timeFormat(item.createTime, 'yyyy-mm-dd hh:MM:ss')
+ }}
+ 待结算
+ 已结算
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/commission/withdraw.vue b/pages/commission/withdraw.vue
new file mode 100644
index 0000000..e60309f
--- /dev/null
+++ b/pages/commission/withdraw.vue
@@ -0,0 +1,467 @@
+
+
+
+
+
+
+ 可提现金额(元)
+ {{ fen2yuan(state.brokerageInfo.brokeragePrice) }}
+
+
+
+
+
+
+ 提现至
+
+ 请选择提现方式
+ 钱包余额
+ 银行卡转账
+ 微信零钱
+ 支付宝账户
+
+
+
+
+ 提现金额
+
+ ¥
+
+
+
+
+ 提现账号
+
+
+
+
+
+
+ 收款码
+
+
+
+
+
+
+
+ 持卡人
+
+
+
+
+
+ 提现银行
+
+
+
+
+
+
+
+
+ 开户地址
+
+
+
+
+
+
+
+
+
+ 提现说明
+ 最低提现金额 {{ fen2yuan(state.minPrice) }} 元
+
+ 冻结佣金:¥{{ fen2yuan(state.brokerageInfo.frozenPrice) }}
+ (每笔佣金的冻结期为 {{ state.frozenDays }} 天,到期后可提现)
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/coupon/detail.vue b/pages/coupon/detail.vue
new file mode 100644
index 0000000..2fca525
--- /dev/null
+++ b/pages/coupon/detail.vue
@@ -0,0 +1,390 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ state.coupon.name }}
+
+ 满 {{ fen2yuan(state.coupon.usePrice) }} 元,
+ {{
+ state.coupon.discountType === 1
+ ? '减 ' + fen2yuan(state.coupon.discountPrice) + ' 元'
+ : '打 ' + state.coupon.discountPercent / 10.0 + ' 折'
+ }}
+
+
+
+ 有效期:领取后 {{ state.coupon.fixedEndTerm }} 天内可用
+
+
+ 有效期: {{ sheep.$helper.timeFormat(state.coupon.validStartTime, 'yyyy-mm-dd') }} 至
+ {{ sheep.$helper.timeFormat(state.coupon.validEndTime, 'yyyy-mm-dd') }}
+
+
+
+
+
+ 优惠券类型
+ {{ state.coupon.discountType === 1 ? '满减券' : '折扣券' }}
+
+
+
+
+ {{ state.coupon.description }}
+
+
+
+
+
+
+
+
+
+ 全场通用
+
+
+
+
+ {{ state.coupon.productScope === 2 ? '指定商品可用' : '指定分类可用' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/coupon/list.vue b/pages/coupon/list.vue
new file mode 100644
index 0000000..ec5ea45
--- /dev/null
+++ b/pages/coupon/list.vue
@@ -0,0 +1,222 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/goods/comment/add.vue b/pages/goods/comment/add.vue
new file mode 100644
index 0000000..bfbc800
--- /dev/null
+++ b/pages/goods/comment/add.vue
@@ -0,0 +1,190 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 商品质量
+
+
+
+ 服务态度
+
+
+
+
+
+
+ uploadSuccess(payload, index)"
+ />
+
+
+
+ toggleAnonymous(index, event)">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/goods/comment/worker/add.vue b/pages/goods/comment/worker/add.vue
new file mode 100644
index 0000000..0cf7976
--- /dev/null
+++ b/pages/goods/comment/worker/add.vue
@@ -0,0 +1,180 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 店员质量
+
+
+
+ 服务态度
+
+
+
+
+
+
+
+ uploadSuccess(payload, index)"
+ limit="9" mode="grid" :imageStyles="{ width: '168rpx', height: '168rpx' }" />
+
+
+
+ toggleAnonymous(index, event)">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/im/components/cardNotice.vue b/pages/im/components/cardNotice.vue
new file mode 100644
index 0000000..fe43f5f
--- /dev/null
+++ b/pages/im/components/cardNotice.vue
@@ -0,0 +1,41 @@
+
+
+
+
+ 投诉举报
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/im/components/cardSwiper.vue b/pages/im/components/cardSwiper.vue
new file mode 100644
index 0000000..7494020
--- /dev/null
+++ b/pages/im/components/cardSwiper.vue
@@ -0,0 +1,225 @@
+
+
+
+
+
+
+
+
+
+
+ 15开黑卡/局
+ LOL手游
+ 下单前聊一聊
+
+ 找TA开黑
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/im/components/chatBar.vue b/pages/im/components/chatBar.vue
new file mode 100644
index 0000000..97df5cb
--- /dev/null
+++ b/pages/im/components/chatBar.vue
@@ -0,0 +1,1452 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{btnText}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/im/components/layout.vue b/pages/im/components/layout.vue
new file mode 100644
index 0000000..5d29165
--- /dev/null
+++ b/pages/im/components/layout.vue
@@ -0,0 +1,336 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 有新消息
+
+
+
+
+
+
+
+
+
diff --git a/pages/im/components/navigationBar.vue b/pages/im/components/navigationBar.vue
new file mode 100644
index 0000000..cde82cb
--- /dev/null
+++ b/pages/im/components/navigationBar.vue
@@ -0,0 +1,194 @@
+
+
+
+
+
+
+ {{user.nickname}}
+
+
+
+
+
+
+
+
+ 会话重连中
+
+
+ 在线
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/im/components/viewItem.vue b/pages/im/components/viewItem.vue
new file mode 100644
index 0000000..830dc26
--- /dev/null
+++ b/pages/im/components/viewItem.vue
@@ -0,0 +1,385 @@
+
+
+
+
+ {{item.content}}
+
+
+
+
+ 温馨提示
+ {{item.content}}
+
+
+
+
+
+
+ {{showDayTime(item.createTime)}}
+
+
+
+
+
+
+
+ {{item.content}}
+
+
+ {{item.content}}
+
+
+
+
+
+
+ {{item.voiceSec}}”
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.content}}
+
+
+
+
+ {{item.content}}
+
+
+
+
+
+
+ {{item.voiceSec}}”
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/im/index - 副本.vue b/pages/im/index - 副本.vue
new file mode 100644
index 0000000..7390a29
--- /dev/null
+++ b/pages/im/index - 副本.vue
@@ -0,0 +1,204 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/im/index.vue b/pages/im/index.vue
new file mode 100644
index 0000000..ee4b170
--- /dev/null
+++ b/pages/im/index.vue
@@ -0,0 +1,194 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/im/util/emoji.js b/pages/im/util/emoji.js
new file mode 100644
index 0000000..fb04e14
--- /dev/null
+++ b/pages/im/util/emoji.js
@@ -0,0 +1,33 @@
+export default [
+ "😀", "😁", "😃", "😄", "😅", "😆", "😉", "😊", "😋", "😎", "😍",
+ "😘", "😗", "😙", "😚", "😇", "😐", "😑", "😶", "😏", "😣", "😥", "😮", "😯", "😪",
+ "😫", "😴", "😌", "😛", "😜", "😝", "😒", "😓", "😔", "😕", "😲", "😷", "😖", "😞", "😟",
+ "😤", "😢", "😭", "😦", "😧", "😨", "😬", "😰", "😱", "😳", "😵", "😡", "😠",
+ "👦", "👧", "👨", "👩", "👴", "👵", "👶", "👱", "👮", "👲", "👳", "👷", "👸", "💂", "🎅", "👰", "👼",
+ "💆", "💇", "🙍", "🙎", "🙅", "🙆", "💁", "🙋", "🙇", "🙌", "🙏", "👤", "👥", "🚶", "🏃", "👯",
+ "💃", "👫", "👬", "👭", "💏", "💑", "👪", "💪", "👈", "👉", "☝", "👆", "👇", "✌", "✋", "👌",
+ "👍", "👎", "✊", "👊", "👋", "👏", "👐", "✍", "👣", "👀", "👂", "👃", "👅", "👄", "💋", "👓",
+ "👔", "👙", "👛", "👜", "👝", "🎒", "💼", "👞", "👟", "👠", "👡", "👢", "👑",
+ "👒", "🎩", "🎓", "💄", "💅", "💍", "🌂", "📶", "📳", "📴", "♻", "🏧","🚮", "🚰", "♿", "🚹", "🚺",
+ "🚻", "🚼", "🚾", "⚠", "🚸", "⛔", "🚫", "🚳", "🚭", "🚯", "🚱", "🚷", "🔞", "💈",
+ "🙈", "🐒", "🐶", "🐕", "🐩", "🐺", "🐱","🐈", "🐯", "🐅", "🐆", "🐴", "🐎", "🐮", "🐂",
+ "🐃","🐄","🐷","🐖","🐗","🐽","🐏","🐑","🐐","🐪","🐫","🐘","🐭",
+ "🐁","🐀","🐹","🐰","🐇","🐻","🐨","🐼","🐾","🐔","🐓","🐣","🐤","🐥",
+ "🐦", "🐧", "🐸", "🐊","🐢", "🐍", "🐲", "🐉", "🐳", "🐋", "🐬", "🐟", "🐠", "🐡",
+ "🐙", "🐚", "🐌", "🐛", "🐜", "🐝", "🐞", "🦋", "💐", "🌸", "💮", "🌹", "🌺",
+ "🌻", "🌼", "🌷", "🌱", "🌲", "🌳", "🌴", "🌵", "🌾", "🌿", "🍀", "🍁", "🍂", "🍃",
+ "🌍","🌎","🌏","🌐","🌑","🌒","🌓","🌔","🌕","🌖","🌗","🌘","🌙","🌚",
+ "🌛","🌜","☀","🌝","🌞","⭐","🌟","🌠","☁","⛅","☔","⚡","❄","🔥","💧","🌊",
+ "🏀", "🏈", "🏉", "🎾", "🎱", "🎳", "⛳", "🎣", "🎽", "🎿",
+ "😈", "👿", "👹", "👺", "💀", "☠", "👻", "👽", "👾", "💣",
+ "🌋", "🗻", "🏠", "🏡", "🏢", "🏣", "🏤", "🏥", "🏦", "🏨",
+ "⛲", "🌁", "🌃", "🌆", "🌇", "🎠", "🎡", "🎢", "🚂",
+ "🚌", "🚍", "🚎", "🚏", "🚐", "🚑", "🚒", "🚓", "🚔", "🚕", "🚖", "🚗", "🚘",
+ "💌", "💎", "🔪", "💈", "🚪", "🚽", "🚿", "🛁", "⌛", "⏳", "⌚", "⏰", "🎈", "🎉",
+ "💤", "💢", "💬", "💭", "♨", "🌀", "🔔", "🔕", "✡", "✝", "🔯", "📛", "🔰", "🔱", "⭕", "✅",
+ "☑", "✔", "✖", "❌", "❎", "➕", "➖", "➗", "➰", "➿", "〽", "✳", "✴", "❇", "‼", "⁉", "❓", "❔", "❕", "❗",
+ "🕛", "🕧", "🕐", "🕜", "🕑", "🕝", "🕒", "🕞", "🕓", "🕟", "🕔", "🕠", "🕕", "🕡",
+ "🕖", "🕢", "🕗", "🕣", "🕘", "🕤", "🕙", "🕥", "🕚", "🕦", "⏱", "⏲", "🕰",
+ "💘", "❤", "💓", "💔", "💕", "💖", "💗", "💙", "💚", "💛", "💜", "💝", "💞", "💟❣",
+ "🍇", "🍈", "🍉", "🍊", "🍋", "🍌", "🍍", "🍎", "🍏", "🍐", "🍑", "🍒", "🍓",
+]
\ No newline at end of file
diff --git a/pages/index/cart.vue b/pages/index/cart.vue
new file mode 100644
index 0000000..633b567
--- /dev/null
+++ b/pages/index/cart.vue
@@ -0,0 +1,192 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/index/category.vue b/pages/index/category.vue
new file mode 100644
index 0000000..4c88f38
--- /dev/null
+++ b/pages/index/category.vue
@@ -0,0 +1,237 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/index/components/first-one.vue b/pages/index/components/first-one.vue
new file mode 100644
index 0000000..2decc86
--- /dev/null
+++ b/pages/index/components/first-one.vue
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/index/components/first-two.vue b/pages/index/components/first-two.vue
new file mode 100644
index 0000000..482931c
--- /dev/null
+++ b/pages/index/components/first-two.vue
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+ {{ item.title }}
+ ¥{{ fen2yuan(item.price) }}
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/index/components/second-one.vue b/pages/index/components/second-one.vue
new file mode 100644
index 0000000..86b7078
--- /dev/null
+++ b/pages/index/components/second-one.vue
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+ {{ props.data[activeMenu].name }}
+
+
+
+
+
+
+
+ {{ item.name }}
+
+
+
+
+
+
+
+
+
diff --git a/pages/index/index.vue b/pages/index/index.vue
new file mode 100644
index 0000000..c62c563
--- /dev/null
+++ b/pages/index/index.vue
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/index/login.vue b/pages/index/login.vue
new file mode 100644
index 0000000..e498870
--- /dev/null
+++ b/pages/index/login.vue
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
diff --git a/pages/index/page.vue b/pages/index/page.vue
new file mode 100644
index 0000000..b5d8ef3
--- /dev/null
+++ b/pages/index/page.vue
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/index/search.vue b/pages/index/search.vue
new file mode 100644
index 0000000..8497298
--- /dev/null
+++ b/pages/index/search.vue
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+
+
+ 搜索历史
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/index/user.vue b/pages/index/user.vue
new file mode 100644
index 0000000..705451a
--- /dev/null
+++ b/pages/index/user.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/addressSelection.vue b/pages/order/addressSelection.vue
new file mode 100644
index 0000000..2432d41
--- /dev/null
+++ b/pages/order/addressSelection.vue
@@ -0,0 +1,261 @@
+
+
+
+
+
+
+
+
+
+
+ {{ state.addressInfo.name }}
+ {{ state.addressInfo.mobile }}
+
+
+ [默认]
+ {{ state.addressInfo.areaName }} {{ state.addressInfo.detailAddress }}
+
+
+
+ 设置收货地址
+
+
+
+
+
+
+
+
+
+
+ {{ state.pickUpInfo.name }}
+ {{ state.pickUpInfo.phone }}
+
+ {{ state.pickUpInfo.areaName }}{{ ', ' + state.pickUpInfo.detailAddress }}
+
+
+
+ 选择自提门店
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/aftersale/apply.vue b/pages/order/aftersale/apply.vue
new file mode 100644
index 0000000..805ea94
--- /dev/null
+++ b/pages/order/aftersale/apply.vue
@@ -0,0 +1,351 @@
+
+
+
+
+
+
+
+
+
+
+
+ 售后类型
+
+
+
+
+
+
+
+
+ 退款金额
+
+ ¥{{ fen2yuan(state.item.payPrice) }}
+
+
+
+
+ 申请原因
+
+ {{ formData.applyReason }}
+ 请选择申请原因~
+
+
+
+
+
+
+ 相关描述
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 申请原因
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/aftersale/detail.vue b/pages/order/aftersale/detail.vue
new file mode 100644
index 0000000..6b7bfcc
--- /dev/null
+++ b/pages/order/aftersale/detail.vue
@@ -0,0 +1,379 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.title }}
+
+
+
+
+
+
+
+
+
+ {{ formatAfterSaleStatusDescription(state.info) }}
+
+
+ {{ sheep.$helper.timeFormat(state.info.updateTime, 'yyyy-mm-dd hh:MM:ss') }}
+
+
+
+
+
+
+
+ 退款总额
+ ¥{{ fen2yuan(state.info.refundPrice) }}
+
+
+
+
+
+
+
+
+
+ 服务单号:
+ {{ state.info.no }}
+
+
+
+ 申请时间:
+
+ {{ sheep.$helper.timeFormat(state.info.createTime, 'yyyy-mm-dd hh:MM:ss') }}
+
+
+
+ 售后类型:
+ {{ state.info.way === 10 ? '仅退款' : '退款退货' }}
+
+
+ 申请原因:
+ {{ state.info.applyReason }}
+
+
+ 相关描述:
+ {{ state.info.applyDescription }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/aftersale/list.vue b/pages/order/aftersale/list.vue
new file mode 100644
index 0000000..5ec22b4
--- /dev/null
+++ b/pages/order/aftersale/list.vue
@@ -0,0 +1,210 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ 服务单号:{{ order.no }}
+ {{ formatAfterSaleStatus(order) }}
+
+
+
+
+ {{ order.way === 10 ? '仅退款' : '退款退货' }}
+ {{ formatAfterSaleStatusDescription(order) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/aftersale/log-item.vue b/pages/order/aftersale/log-item.vue
new file mode 100644
index 0000000..01329df
--- /dev/null
+++ b/pages/order/aftersale/log-item.vue
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+ {{ item.content }}
+
+ {{ sheep.$helper.timeFormat(item.createTime, 'yyyy-mm-dd hh:MM:ss') }}
+
+
+
+
+
+
diff --git a/pages/order/aftersale/log.vue b/pages/order/aftersale/log.vue
new file mode 100644
index 0000000..a8df8a2
--- /dev/null
+++ b/pages/order/aftersale/log.vue
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/aftersale/return-delivery.vue b/pages/order/aftersale/return-delivery.vue
new file mode 100644
index 0000000..fa3ecec
--- /dev/null
+++ b/pages/order/aftersale/return-delivery.vue
@@ -0,0 +1,195 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/order/blind/components/layout.vue b/pages/order/blind/components/layout.vue
new file mode 100644
index 0000000..3a0e444
--- /dev/null
+++ b/pages/order/blind/components/layout.vue
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/blind/components/orderList.vue b/pages/order/blind/components/orderList.vue
new file mode 100644
index 0000000..5cc40ec
--- /dev/null
+++ b/pages/order/blind/components/orderList.vue
@@ -0,0 +1,248 @@
+
+
+
+
+
+ {{ order.no }}
+
+ {{order.statusStr}}
+
+
+
+
+
+
+
+
+ {{order.nickname}}
+ 订单时间:{{order.createTimeStr}}
+ 服务内容:{{item.spuName}} {{item.properties.map((property) => property.valueName).join(' ')}}×{{item.count}}
+ 性别要求:女生
+ 性别要求:男生
+
+ 微信:{{order.weixin}}
+
+
+
+
+
+ 剩余时间:
+
+ 已结束
+
+
+
+
+ 暂未接单
+
+ 备注:{{order.userRemark}}
+ 取消原因:{{order.cancelReason}}
+
+
+ {{order.brokeragePrice}}
+ /钻
+
+
+
+
+
+
+ 也被其它店员抢单
+ 查看详情
+ 取消接单
+ 取消订单
+ 邀请好友抢单
+ 邀请评价
+ 立即抢单
+ 结束服务
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/order/blind/components/tabBox.vue b/pages/order/blind/components/tabBox.vue
new file mode 100644
index 0000000..db9711d
--- /dev/null
+++ b/pages/order/blind/components/tabBox.vue
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/order/blind/confirm.vue b/pages/order/blind/confirm.vue
new file mode 100644
index 0000000..92e7541
--- /dev/null
+++ b/pages/order/blind/confirm.vue
@@ -0,0 +1,435 @@
+
+
+
+
+
+
+ 订单备注
+
+
+
+
+
+
+
+
+
+
+ 技能金额
+
+
+ ¥{{ fen2yuan(state.orderInfo.price.totalPrice) }}
+
+
+
+
+ 积分抵扣
+
+ {{ state.pointStatus ? '剩余积分' : '当前积分' }}
+
+
+ {{ state.pointStatus ? state.orderInfo.totalPoint - state.orderInfo.usePoint : (state.orderInfo.totalPoint || 0) }}
+
+
+
+
+
+
+
+ TA添加你的微信号
+
+
+
+
+
+
+ 优惠券
+
+
+ -¥{{ fen2yuan(state.orderInfo.price.couponPrice) }}
+
+
+ {{
+ state.couponInfo.length > 0 ? state.couponInfo.length + ' 张可用' : '暂无可用优惠券'
+ }}
+
+
+
+
+
+ 活动优惠
+
+
+
+ -¥{{ fen2yuan(state.orderInfo.price.discountPrice) }}
+
+
+
+
+
+ 会员优惠
+
+
+ -¥{{ fen2yuan(state.orderInfo.price.vipPrice) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/blind/detail.vue b/pages/order/blind/detail.vue
new file mode 100644
index 0000000..3368079
--- /dev/null
+++ b/pages/order/blind/detail.vue
@@ -0,0 +1,599 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ formatBlindOrderStatus(state.orderInfo) }}
+
+
+ {{ formatBlindOrderStatusDescription(state.orderInfo) }}
+
+
+
+
+
+
+
+ {{ state.orderInfo.receiverName }}
+
+ {{ state.orderInfo.receiverMobile }}
+
+
+ {{ state.orderInfo.receiverAreaName }} {{ state.orderInfo.receiverDetailAddress }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 订单编号:
+ {{ state.orderInfo.no }}
+
+
+
+
+ 下单时间:
+
+ {{ sheep.$helper.timeFormat(state.orderInfo.createTime, 'yyyy-mm-dd hh:MM:ss') }}
+
+
+
+ 支付时间:
+
+ {{ sheep.$helper.timeFormat(state.orderInfo.payTime, 'yyyy-mm-dd hh:MM:ss') }}
+
+
+
+ 支付方式:
+ {{ state.orderInfo.payChannelName || '-' }}
+
+
+
+
+
+
+
+ 订单总额
+
+ ¥{{ fen2yuan(state.orderInfo.totalPrice) }}
+
+
+
+ 优惠劵金额
+ -¥{{ fen2yuan(state.orderInfo.couponPrice) }}
+
+
+ 积分抵扣
+ -¥{{ fen2yuan(state.orderInfo.pointPrice) }}
+
+
+ 活动优惠
+ ¥{{ fen2yuan(state.orderInfo.discountPrice) }}
+
+
+ 会员优惠
+ -¥{{ fen2yuan(state.orderInfo.vipPrice) }}
+
+
+ 用户付款
+ ¥{{ fen2yuan(state.orderInfo.payPrice) }}
+
+
+ 佣金比例
+ {{state.orderInfo.brokeragePercent}}%
+
+
+ {{ state.orderInfo.status == '30' ? '结算佣金' : '可得佣金' }}
+ ¥{{ fen2yuan(state.orderInfo.brokeragePrice) }}
+
+
+ 已退款
+ ¥{{ fen2yuan(state.orderInfo.refundPrice) }}
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/blind/list.vue b/pages/order/blind/list.vue
new file mode 100644
index 0000000..03a1146
--- /dev/null
+++ b/pages/order/blind/list.vue
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/order/confirm.vue b/pages/order/confirm.vue
new file mode 100644
index 0000000..b18df4f
--- /dev/null
+++ b/pages/order/confirm.vue
@@ -0,0 +1,468 @@
+
+
+
+
+
+
+
+
+
+ 订单备注
+
+
+
+
+
+
+
+
+
+
+ 商品金额
+
+
+ ¥{{ fen2yuan(state.orderInfo.price.totalPrice) }}
+
+
+
+
+ 积分抵扣
+
+ {{ state.pointStatus ? '剩余积分' : '当前积分' }}
+
+
+ {{ state.pointStatus ? state.orderInfo.totalPoint - state.orderInfo.usePoint : (state.orderInfo.totalPoint || 0) }}
+
+
+
+
+
+
+
+
+ 运费
+
+
+ +¥{{ fen2yuan(state.orderInfo.price.deliveryPrice) }}
+
+ 免运费
+
+
+
+
+ 联系人
+
+
+
+
+
+ 联系电话
+
+
+
+
+
+
+ 优惠券
+
+
+ -¥{{ fen2yuan(state.orderInfo.price.couponPrice) }}
+
+
+ {{
+ state.couponInfo.length > 0 ? state.couponInfo.length + ' 张可用' : '暂无可用优惠券'
+ }}
+
+
+
+
+
+ 活动优惠
+
+
+
+ -¥{{ fen2yuan(state.orderInfo.price.discountPrice) }}
+
+
+
+
+
+ 会员优惠
+
+
+ -¥{{ fen2yuan(state.orderInfo.price.vipPrice) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/detail.vue b/pages/order/detail.vue
new file mode 100644
index 0000000..ed0119f
--- /dev/null
+++ b/pages/order/detail.vue
@@ -0,0 +1,655 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ formatOrderStatus(state.orderInfo) }}
+
+
+ {{ formatOrderStatusDescription(state.orderInfo) }}
+
+
+
+
+
+
+
+ {{ state.orderInfo.receiverName }}
+
+ {{ state.orderInfo.receiverMobile }}
+
+
+ {{ state.orderInfo.receiverAreaName }} {{ state.orderInfo.receiverDetailAddress }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 订单编号:
+ {{ state.orderInfo.no }}
+
+
+
+
+ 下单时间:
+
+ {{ sheep.$helper.timeFormat(state.orderInfo.createTime, 'yyyy-mm-dd hh:MM:ss') }}
+
+
+
+ 支付时间:
+
+ {{ sheep.$helper.timeFormat(state.orderInfo.payTime, 'yyyy-mm-dd hh:MM:ss') }}
+
+
+
+ 支付方式:
+ {{ state.orderInfo.payChannelName || '-' }}
+
+
+
+
+
+
+
+ 商品总额
+
+ ¥{{ fen2yuan(state.orderInfo.totalPrice) }}
+
+
+
+ 运费
+ ¥{{ fen2yuan(state.orderInfo.deliveryPrice) }}
+
+
+ 优惠劵金额
+ -¥{{ fen2yuan(state.orderInfo.couponPrice) }}
+
+
+ 积分抵扣
+ -¥{{ fen2yuan(state.orderInfo.pointPrice) }}
+
+
+ 活动优惠
+ ¥{{ fen2yuan(state.orderInfo.discountPrice) }}
+
+
+ 会员优惠
+ -¥{{ fen2yuan(state.orderInfo.vipPrice) }}
+
+
+ {{ state.orderInfo.payStatus ? '已付款' : '需付款' }}
+ ¥{{ fen2yuan(state.orderInfo.payPrice) }}
+
+
+ 已退款
+ ¥{{ fen2yuan(state.orderInfo.refundPrice) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/express/log.vue b/pages/order/express/log.vue
new file mode 100644
index 0000000..eb992a5
--- /dev/null
+++ b/pages/order/express/log.vue
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 快递单号:{{ state.info.logisticsNo }}
+ 快递公司:{{ state.info.logisticsName }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.content }}
+
+ {{ sheep.$helper.timeFormat(item.time, 'yyyy-mm-dd hh:MM:ss') }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/list.vue b/pages/order/list.vue
new file mode 100644
index 0000000..926ecfd
--- /dev/null
+++ b/pages/order/list.vue
@@ -0,0 +1,495 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 共 {{ order.productCount }} 件商品,总金额:
+ ¥{{ fen2yuan(order.payPrice) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/my/aftersale/apply.vue b/pages/order/my/aftersale/apply.vue
new file mode 100644
index 0000000..6d86283
--- /dev/null
+++ b/pages/order/my/aftersale/apply.vue
@@ -0,0 +1,333 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ 退回余额
+
+ ¥{{ fen2yuan(state.item.payPrice) }}
+
+
+
+
+
+
+
+ 取消原因
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 取消原因
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/my/aftersale/list.vue b/pages/order/my/aftersale/list.vue
new file mode 100644
index 0000000..9ed49bf
--- /dev/null
+++ b/pages/order/my/aftersale/list.vue
@@ -0,0 +1,184 @@
+
+
+
+
+
+
+
+
+ 服务单号:{{ order.no }}
+ {{ formatAfterSaleStatus(order) }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/my/components/layout.vue b/pages/order/my/components/layout.vue
new file mode 100644
index 0000000..8b493d8
--- /dev/null
+++ b/pages/order/my/components/layout.vue
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/my/components/orderList.vue b/pages/order/my/components/orderList.vue
new file mode 100644
index 0000000..f44058e
--- /dev/null
+++ b/pages/order/my/components/orderList.vue
@@ -0,0 +1,219 @@
+
+
+
+
+
+ {{ order.no }}
+
+ {{order.statusStr}}
+
+
+
+
+
+
+
+
+ {{item.nickname}}
+ 待接单..
+ 订单时间:{{order.createTimeStr}}
+ 服务内容:{{item.spuName}} {{item.properties.map((property) => property.valueName).join(' ')}}×{{item.count}}
+ 开始服务时间:{{order.deliveryTimeStr}}
+
+ 剩余时间:
+
+ 已结束
+
+
+
+
+ 暂未接单
+
+ 取消原因:{{order.cancelReason}}
+
+
+ {{order.payPrice}}
+ /钻
+
+
+
+
+
+
+ 查看详情
+ 取消订单
+ 取消订单
+ 再来一单
+ 评价
+ 继续支付
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/order/my/components/tabBox.vue b/pages/order/my/components/tabBox.vue
new file mode 100644
index 0000000..db9711d
--- /dev/null
+++ b/pages/order/my/components/tabBox.vue
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/order/my/confirm.vue b/pages/order/my/confirm.vue
new file mode 100644
index 0000000..2476e5d
--- /dev/null
+++ b/pages/order/my/confirm.vue
@@ -0,0 +1,426 @@
+
+
+
+
+
+
+ 订单备注
+
+
+
+
+
+
+
+
+
+
+ 商品金额
+
+
+ ¥{{ fen2yuan(state.orderInfo.price.totalPrice) }}
+
+
+
+
+ 积分抵扣
+
+ {{ state.pointStatus ? '剩余积分' : '当前积分' }}
+
+
+ {{ state.pointStatus ? state.orderInfo.totalPoint - state.orderInfo.usePoint : (state.orderInfo.totalPoint || 0) }}
+
+
+
+
+
+
+
+ 你的微信号
+
+
+
+
+
+
+ 优惠券
+
+
+ -¥{{ fen2yuan(state.orderInfo.price.couponPrice) }}
+
+
+ {{
+ state.couponInfo.length > 0 ? state.couponInfo.length + ' 张可用' : '暂无可用优惠券'
+ }}
+
+
+
+
+
+ 活动优惠
+
+
+
+ -¥{{ fen2yuan(state.orderInfo.price.discountPrice) }}
+
+
+
+
+
+ 会员优惠
+
+
+ -¥{{ fen2yuan(state.orderInfo.price.vipPrice) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/my/detail.vue b/pages/order/my/detail.vue
new file mode 100644
index 0000000..e03b0c4
--- /dev/null
+++ b/pages/order/my/detail.vue
@@ -0,0 +1,580 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ formatWorkerOrderStatus(state.orderInfo) }}
+
+
+ {{ formatMyOrderStatusDescription(state.orderInfo) }}
+
+
+
+
+
+
+
+ {{ state.orderInfo.receiverName }}
+
+ {{ state.orderInfo.receiverMobile }}
+
+
+ {{ state.orderInfo.receiverAreaName }} {{ state.orderInfo.receiverDetailAddress }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 订单编号:
+ {{ state.orderInfo.no }}
+
+
+
+
+ 下单时间:
+
+ {{ sheep.$helper.timeFormat(state.orderInfo.createTime, 'yyyy-mm-dd hh:MM:ss') }}
+
+
+
+ 支付时间:
+
+ {{ sheep.$helper.timeFormat(state.orderInfo.payTime, 'yyyy-mm-dd hh:MM:ss') }}
+
+
+
+ 支付方式:
+ {{ state.orderInfo.payChannelName || '-' }}
+
+
+
+
+
+
+
+ 订单总额
+
+ ¥{{ fen2yuan(state.orderInfo.totalPrice) }}
+
+
+
+ 优惠劵金额
+ -¥{{ fen2yuan(state.orderInfo.couponPrice) }}
+
+
+ 积分抵扣
+ -¥{{ fen2yuan(state.orderInfo.pointPrice) }}
+
+
+ 活动优惠
+ ¥{{ fen2yuan(state.orderInfo.discountPrice) }}
+
+
+ 会员优惠
+ -¥{{ fen2yuan(state.orderInfo.vipPrice) }}
+
+
+ {{ state.orderInfo.payStatus ? '实付款' : '需付款' }}
+ ¥{{ fen2yuan(state.orderInfo.payPrice) }}
+
+
+ 已退款
+ ¥{{ fen2yuan(state.orderInfo.refundPrice) }}
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/my/index.vue b/pages/order/my/index.vue
new file mode 100644
index 0000000..96befc2
--- /dev/null
+++ b/pages/order/my/index.vue
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/order/my/list - 副本.vue b/pages/order/my/list - 副本.vue
new file mode 100644
index 0000000..b7718c0
--- /dev/null
+++ b/pages/order/my/list - 副本.vue
@@ -0,0 +1,514 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 共 {{ order.productCount }} 件商品,总金额:
+ ¥{{ fen2yuan(order.payPrice) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/my/list.vue b/pages/order/my/list.vue
new file mode 100644
index 0000000..6e2bdbb
--- /dev/null
+++ b/pages/order/my/list.vue
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/order/pickUpVerify.vue b/pages/order/pickUpVerify.vue
new file mode 100644
index 0000000..1e8bb6e
--- /dev/null
+++ b/pages/order/pickUpVerify.vue
@@ -0,0 +1,261 @@
+
+
+
+
+ 核销信息
+
+
+
+
+
+
+
+
+ {{ orderInfo.pickUpVerifyCode }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 使用说明
+
+ 可将二维码出示给店员扫描或提供数字核销码
+
+
+
+
+ 自提地址信息
+
+ 查看位置
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/receive/components/layout.vue b/pages/order/receive/components/layout.vue
new file mode 100644
index 0000000..7944220
--- /dev/null
+++ b/pages/order/receive/components/layout.vue
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/receive/components/orderList.vue b/pages/order/receive/components/orderList.vue
new file mode 100644
index 0000000..5c21013
--- /dev/null
+++ b/pages/order/receive/components/orderList.vue
@@ -0,0 +1,163 @@
+
+
+
+
+
+ 123213123123
+
+ 待服务
+
+
+
+
+
+
+ 碎冰冰
+ 订单时间:2024-08-10
+ 服务内容:文字×1
+
+ 微信:rbtnet
+
+
+ 剩余时间:已结束
+ 取消原因:
+
+
+ 5.00
+ /钻
+
+
+
+
+
+
+ 结束服务
+ 取消接单
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/order/receive/components/tabBox.vue b/pages/order/receive/components/tabBox.vue
new file mode 100644
index 0000000..532c152
--- /dev/null
+++ b/pages/order/receive/components/tabBox.vue
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/order/receive/index.vue b/pages/order/receive/index.vue
new file mode 100644
index 0000000..be27386
--- /dev/null
+++ b/pages/order/receive/index.vue
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/order/worker/aftersale/apply.vue b/pages/order/worker/aftersale/apply.vue
new file mode 100644
index 0000000..4ebd868
--- /dev/null
+++ b/pages/order/worker/aftersale/apply.vue
@@ -0,0 +1,318 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ 退款金额
+
+ ¥{{ fen2yuan(state.item.payPrice) }}
+
+
+
+
+ 取消原因
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 申请原因
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/worker/aftersale/list.vue b/pages/order/worker/aftersale/list.vue
new file mode 100644
index 0000000..78f9d26
--- /dev/null
+++ b/pages/order/worker/aftersale/list.vue
@@ -0,0 +1,184 @@
+
+
+
+
+
+
+
+
+ 服务单号:{{ order.no }}
+ {{ formatAfterSaleStatus(order) }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/worker/components/layout.vue b/pages/order/worker/components/layout.vue
new file mode 100644
index 0000000..846bfd9
--- /dev/null
+++ b/pages/order/worker/components/layout.vue
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/worker/components/orderList.vue b/pages/order/worker/components/orderList.vue
new file mode 100644
index 0000000..ad1856f
--- /dev/null
+++ b/pages/order/worker/components/orderList.vue
@@ -0,0 +1,242 @@
+
+
+
+
+
+ {{ order.no }}
+
+ {{order.statusStr}}
+
+
+
+
+
+
+
+
+ {{order.nickname}}
+ 订单时间:{{order.createTimeStr}}
+ 服务内容:{{item.spuName}} {{item.properties.map((property) => property.valueName).join(' ')}}×{{item.count}}
+
+ 微信:{{order.weixin}}
+
+
+
+
+
+ 剩余时间:
+
+ 已结束
+
+
+
+
+ 暂未接单
+
+ 备注:{{order.userRemark}}
+ 取消原因:{{order.cancelReason}}
+
+
+ {{order.brokeragePrice}}
+ /钻
+
+
+
+
+
+
+ 查看详情
+ 取消接单
+ 取消订单
+ 再来一单
+ 评价
+ 继续支付
+ 开始接单
+ 结束服务
+ 邀请老板
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/order/worker/components/tabBox.vue b/pages/order/worker/components/tabBox.vue
new file mode 100644
index 0000000..db9711d
--- /dev/null
+++ b/pages/order/worker/components/tabBox.vue
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/order/worker/confirm.vue b/pages/order/worker/confirm.vue
new file mode 100644
index 0000000..bbd3809
--- /dev/null
+++ b/pages/order/worker/confirm.vue
@@ -0,0 +1,433 @@
+
+
+
+
+
+
+ 订单备注
+
+
+
+
+
+
+
+
+
+
+ 技能金额
+
+
+ ¥{{ fen2yuan(state.orderInfo.price.totalPrice) }}
+
+
+
+
+ 积分抵扣
+
+ {{ state.pointStatus ? '剩余积分' : '当前积分' }}
+
+
+ {{ state.pointStatus ? state.orderInfo.totalPoint - state.orderInfo.usePoint : (state.orderInfo.totalPoint || 0) }}
+
+
+
+
+
+
+
+ TA添加你的微信号
+
+
+
+
+
+
+ 优惠券
+
+
+ -¥{{ fen2yuan(state.orderInfo.price.couponPrice) }}
+
+
+ {{
+ state.couponInfo.length > 0 ? state.couponInfo.length + ' 张可用' : '暂无可用优惠券'
+ }}
+
+
+
+
+
+ 活动优惠
+
+
+
+ -¥{{ fen2yuan(state.orderInfo.price.discountPrice) }}
+
+
+
+
+
+ 会员优惠
+
+
+ -¥{{ fen2yuan(state.orderInfo.price.vipPrice) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/worker/detail.vue b/pages/order/worker/detail.vue
new file mode 100644
index 0000000..26316bf
--- /dev/null
+++ b/pages/order/worker/detail.vue
@@ -0,0 +1,593 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ formatWorkerOrderStatus(state.orderInfo) }}
+
+
+ {{ formatWorkerOrderStatusDescription(state.orderInfo) }}
+
+
+
+
+
+
+
+ {{ state.orderInfo.receiverName }}
+
+ {{ state.orderInfo.receiverMobile }}
+
+
+ {{ state.orderInfo.receiverAreaName }} {{ state.orderInfo.receiverDetailAddress }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 订单编号:
+ {{ state.orderInfo.no }}
+
+
+
+
+ 下单时间:
+
+ {{ sheep.$helper.timeFormat(state.orderInfo.createTime, 'yyyy-mm-dd hh:MM:ss') }}
+
+
+
+ 支付时间:
+
+ {{ sheep.$helper.timeFormat(state.orderInfo.payTime, 'yyyy-mm-dd hh:MM:ss') }}
+
+
+
+ 支付方式:
+ {{ state.orderInfo.payChannelName || '-' }}
+
+
+
+
+
+
+
+ 订单总额
+
+ ¥{{ fen2yuan(state.orderInfo.totalPrice) }}
+
+
+
+ 优惠劵金额
+ -¥{{ fen2yuan(state.orderInfo.couponPrice) }}
+
+
+ 积分抵扣
+ -¥{{ fen2yuan(state.orderInfo.pointPrice) }}
+
+
+ 活动优惠
+ ¥{{ fen2yuan(state.orderInfo.discountPrice) }}
+
+
+ 会员优惠
+ -¥{{ fen2yuan(state.orderInfo.vipPrice) }}
+
+
+ 用户付款
+ ¥{{ fen2yuan(state.orderInfo.payPrice) }}
+
+
+ 佣金比例
+ {{state.orderInfo.brokeragePercent}}%
+
+
+ {{ state.orderInfo.payStatus ? '结算佣金' : '可得佣金' }}
+ ¥{{ fen2yuan(state.orderInfo.brokeragePrice) }}
+
+
+ 已退款
+ ¥{{ fen2yuan(state.orderInfo.refundPrice) }}
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/order/worker/list.vue b/pages/order/worker/list.vue
new file mode 100644
index 0000000..27d5ece
--- /dev/null
+++ b/pages/order/worker/list.vue
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/pay/index.vue b/pages/pay/index.vue
new file mode 100644
index 0000000..ef8bfe1
--- /dev/null
+++ b/pages/pay/index.vue
@@ -0,0 +1,295 @@
+
+
+
+
+
+
+
+
+
+ 选择支付方式
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/pay/point/index.vue b/pages/pay/point/index.vue
new file mode 100644
index 0000000..830ac1e
--- /dev/null
+++ b/pages/pay/point/index.vue
@@ -0,0 +1,308 @@
+
+
+
+
+
+
+
+
+
+ 选择支付方式
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/pay/recharge-log.vue b/pages/pay/recharge-log.vue
new file mode 100644
index 0000000..5dd3e36
--- /dev/null
+++ b/pages/pay/recharge-log.vue
@@ -0,0 +1,167 @@
+
+
+
+
+
+
+
+ 充值钻石
+
+ {{ fen2yuan(item.payPrice) }} 钻
+ (赠送 {{ fen2yuan(item.bonusPrice) }} 钻)
+
+
+
+ 支付状态
+
+ {{ item.refundStatus === 10 ? '已退款' : '已支付' }}
+
+
+
+ 充值渠道
+ {{ item.payChannelName }}
+
+
+ 充值单号
+ {{ item.payOrderChannelOrderNo }}
+
+
+ 充值时间
+
+ {{ sheep.$helper.timeFormat(item.payTime, 'yyyy-mm-dd hh:MM:ss') }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/pay/recharge.vue b/pages/pay/recharge.vue
new file mode 100644
index 0000000..d63c640
--- /dev/null
+++ b/pages/pay/recharge.vue
@@ -0,0 +1,264 @@
+
+
+
+
+
+ 当前钻石(钻)
+ {{ fen2yuan(userWallet.balance) }}
+
+
+
+
+
+ 充值钻石
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/pay/result.vue b/pages/pay/result.vue
new file mode 100644
index 0000000..e4cc298
--- /dev/null
+++ b/pages/pay/result.vue
@@ -0,0 +1,318 @@
+
+
+
+
+
+
+
+
+ 支付成功
+ 支付失败
+ 该订单已关闭
+ 检测支付结果...
+
+ ¥{{ fen2yuan(state.orderInfo.price) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 获取实时发货信息与订单状态
+ 立即订阅
+
+
+
+
+
+
+
+
+
diff --git a/pages/pay/reward/index.vue b/pages/pay/reward/index.vue
new file mode 100644
index 0000000..3541dda
--- /dev/null
+++ b/pages/pay/reward/index.vue
@@ -0,0 +1,308 @@
+
+
+
+
+
+
+
+
+
+ 选择支付方式
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/pay/vip/index.vue b/pages/pay/vip/index.vue
new file mode 100644
index 0000000..bd47e5b
--- /dev/null
+++ b/pages/pay/vip/index.vue
@@ -0,0 +1,308 @@
+
+
+
+
+
+
+
+
+
+ 选择支付方式
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/pay/worker/index.vue b/pages/pay/worker/index.vue
new file mode 100644
index 0000000..db34839
--- /dev/null
+++ b/pages/pay/worker/index.vue
@@ -0,0 +1,308 @@
+
+
+
+
+
+
+
+
+
+ 选择支付方式
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/pay/worker/result.vue b/pages/pay/worker/result.vue
new file mode 100644
index 0000000..bd3fa33
--- /dev/null
+++ b/pages/pay/worker/result.vue
@@ -0,0 +1,310 @@
+
+
+
+
+
+
+
+
+ 支付成功
+ 支付失败
+ 该订单已关闭
+ 检测支付结果...
+
+ ¥{{ fen2yuan(state.orderInfo.price) }}
+
+
+
+
+
+
+
+
+
+
+
+
+ 获取实时接单信息与订单状态
+ 立即订阅
+
+
+
+
+
+
+
+
+
diff --git a/pages/point/recharge-log.vue b/pages/point/recharge-log.vue
new file mode 100644
index 0000000..3e44fb6
--- /dev/null
+++ b/pages/point/recharge-log.vue
@@ -0,0 +1,167 @@
+
+
+
+
+
+
+
+ 充值积分
+
+ {{ item.payPrice }} 积分
+ (赠送 {{ item.bonusPrice }} 积分)
+
+
+
+ 支付状态
+
+ {{ item.refundStatus === 10 ? '已退款' : '已支付' }}
+
+
+
+ 充值渠道
+ {{ item.payChannelName }}
+
+
+ 充值单号
+ {{ item.payOrderChannelOrderNo }}
+
+
+ 充值时间
+
+ {{ sheep.$helper.timeFormat(item.payTime, 'yyyy-mm-dd hh:MM:ss') }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/point/recharge.vue b/pages/point/recharge.vue
new file mode 100644
index 0000000..f919e83
--- /dev/null
+++ b/pages/point/recharge.vue
@@ -0,0 +1,264 @@
+
+
+
+
+
+ 当前积分(个)
+ {{ userInfo.point }}
+
+
+
+
+
+ 充值积分
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/point/result.vue b/pages/point/result.vue
new file mode 100644
index 0000000..d188e52
--- /dev/null
+++ b/pages/point/result.vue
@@ -0,0 +1,318 @@
+
+
+
+
+
+
+
+
+ 支付成功
+ 支付失败
+ 该订单已关闭
+ 检测支付结果...
+
+ ¥{{ fen2yuan(state.orderInfo.price) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 获取实时发货信息与订单状态
+ 立即订阅
+
+
+
+
+
+
+
+
+
diff --git a/pages/public/error.vue b/pages/public/error.vue
new file mode 100644
index 0000000..3c9097d
--- /dev/null
+++ b/pages/public/error.vue
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/public/faq.vue b/pages/public/faq.vue
new file mode 100644
index 0000000..ebfeaf8
--- /dev/null
+++ b/pages/public/faq.vue
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+ {{ item.content }}
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/public/richtext.vue b/pages/public/richtext.vue
new file mode 100644
index 0000000..e4a0921
--- /dev/null
+++ b/pages/public/richtext.vue
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/public/setting.vue b/pages/public/setting.vue
new file mode 100644
index 0000000..6a08ff9
--- /dev/null
+++ b/pages/public/setting.vue
@@ -0,0 +1,236 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/public/webview.vue b/pages/public/webview.vue
new file mode 100644
index 0000000..1327295
--- /dev/null
+++ b/pages/public/webview.vue
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/reward/components/layout.vue b/pages/reward/components/layout.vue
new file mode 100644
index 0000000..c5cab70
--- /dev/null
+++ b/pages/reward/components/layout.vue
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/reward/components/orderList.vue b/pages/reward/components/orderList.vue
new file mode 100644
index 0000000..126279a
--- /dev/null
+++ b/pages/reward/components/orderList.vue
@@ -0,0 +1,169 @@
+
+
+
+
+
+
+
+
+
+ {{order.nickname}}
+ 礼物名称:{{order.gift}}×{{order.count}}
+ 到账金额:{{order.money}}
+ 心动留言:{{order.msg}}
+
+ 微信:{{order.weixin}}
+
+
+
+
+ 订单时间:{{order.createTimeStr}}
+
+
+ {{order.payMoney}}
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/reward/list.vue b/pages/reward/list.vue
new file mode 100644
index 0000000..abc3de3
--- /dev/null
+++ b/pages/reward/list.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/actionSheet.vue b/pages/tabbar/components/home/actionSheet.vue
new file mode 100644
index 0000000..ba318d4
--- /dev/null
+++ b/pages/tabbar/components/home/actionSheet.vue
@@ -0,0 +1,220 @@
+
+
+
+
+ {{tips}}
+
+
+
+
+ {{item.text}}
+
+
+
+ 取消
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/cardList.vue b/pages/tabbar/components/home/cardList.vue
new file mode 100644
index 0000000..577bdc6
--- /dev/null
+++ b/pages/tabbar/components/home/cardList.vue
@@ -0,0 +1,448 @@
+
+
+
+
+
+ 获取未读消息提醒
+ 立即订阅
+
+
+
+
+
+
+
+
+
+
+ {{item.nickname}}
+
+
+ {{item.age}}
+
+
+
+ {{item.age}}
+
+
+
+
+
+ {{item.city}}
+
+ 未知
+
+
+
+
+ 已注册{{item.day}}天
+ 可交换名片
+
+
+
+
+
+
+
+
+
+
+
+ 密聊
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/categoryCard.vue b/pages/tabbar/components/home/categoryCard.vue
new file mode 100644
index 0000000..cf0e7af
--- /dev/null
+++ b/pages/tabbar/components/home/categoryCard.vue
@@ -0,0 +1,181 @@
+
+
+
+
+
+
+
+
+ 技能分类
+
+
+
+
+
+
+
+
+
+
+
+ {{item.name}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/categorySheet.vue b/pages/tabbar/components/home/categorySheet.vue
new file mode 100644
index 0000000..8b944b3
--- /dev/null
+++ b/pages/tabbar/components/home/categorySheet.vue
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/dazi.vue b/pages/tabbar/components/home/dazi.vue
new file mode 100644
index 0000000..ddfda62
--- /dev/null
+++ b/pages/tabbar/components/home/dazi.vue
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/friend.vue b/pages/tabbar/components/home/friend.vue
new file mode 100644
index 0000000..4764e54
--- /dev/null
+++ b/pages/tabbar/components/home/friend.vue
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/friend/imgBox.vue b/pages/tabbar/components/home/friend/imgBox.vue
new file mode 100644
index 0000000..e2076b5
--- /dev/null
+++ b/pages/tabbar/components/home/friend/imgBox.vue
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+ +{{imgList.length-3}}
+
+
+
+
+
+ 暂未上传相册
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/friend/rankBox.vue b/pages/tabbar/components/home/friend/rankBox.vue
new file mode 100644
index 0000000..d0cf316
--- /dev/null
+++ b/pages/tabbar/components/home/friend/rankBox.vue
@@ -0,0 +1,246 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{list[1].nickname}}
+ ???
+
+
+
+
+
+
+
+ {{list[0].nickname}}
+ ???
+
+
+
+
+
+
+
+ {{list[2].nickname}}
+ ???
+
+
+ 更新时间: {{updateTime}}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/friend/stickyBox.vue b/pages/tabbar/components/home/friend/stickyBox.vue
new file mode 100644
index 0000000..9b05d5d
--- /dev/null
+++ b/pages/tabbar/components/home/friend/stickyBox.vue
@@ -0,0 +1,109 @@
+
+
+
+
+
+
+
+ 更多用户
+
+
+
+ 筛选
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/friend/topBox.vue b/pages/tabbar/components/home/friend/topBox.vue
new file mode 100644
index 0000000..2237f41
--- /dev/null
+++ b/pages/tabbar/components/home/friend/topBox.vue
@@ -0,0 +1,260 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/friend/userCard.vue b/pages/tabbar/components/home/friend/userCard.vue
new file mode 100644
index 0000000..803ce69
--- /dev/null
+++ b/pages/tabbar/components/home/friend/userCard.vue
@@ -0,0 +1,210 @@
+
+
+
+
+
+
+
+ 新人推荐
+
+
+
+
+
+
+
+
+ {{item.nickname}}
+
+
+
+
+
+
+
+
+
+
+ 置顶用户
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.nickname}}
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/navBar - 副本.vue b/pages/tabbar/components/home/navBar - 副本.vue
new file mode 100644
index 0000000..3bbe7b9
--- /dev/null
+++ b/pages/tabbar/components/home/navBar - 副本.vue
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/navBar.vue b/pages/tabbar/components/home/navBar.vue
new file mode 100644
index 0000000..e4fd304
--- /dev/null
+++ b/pages/tabbar/components/home/navBar.vue
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+ {{item.name}}
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/noticeBar.vue b/pages/tabbar/components/home/noticeBar.vue
new file mode 100644
index 0000000..9cc4e9b
--- /dev/null
+++ b/pages/tabbar/components/home/noticeBar.vue
@@ -0,0 +1,112 @@
+
+
+
+
+ 最新消息
+
+
+
+ {{item}}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/peiwan.vue b/pages/tabbar/components/home/peiwan.vue
new file mode 100644
index 0000000..3cf0030
--- /dev/null
+++ b/pages/tabbar/components/home/peiwan.vue
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/rankBox.vue b/pages/tabbar/components/home/rankBox.vue
new file mode 100644
index 0000000..600faa8
--- /dev/null
+++ b/pages/tabbar/components/home/rankBox.vue
@@ -0,0 +1,198 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{list[1].nickname}}
+ ???
+
+
+
+
+
+
+
+ {{list[0].nickname}}
+ ???
+
+
+
+
+
+
+
+ {{list[2].nickname}}
+ ???
+
+
+ 更新时间: {{updateTime}}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/sexSheet.vue b/pages/tabbar/components/home/sexSheet.vue
new file mode 100644
index 0000000..87b2d28
--- /dev/null
+++ b/pages/tabbar/components/home/sexSheet.vue
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/stickyBox.vue b/pages/tabbar/components/home/stickyBox.vue
new file mode 100644
index 0000000..79d21f1
--- /dev/null
+++ b/pages/tabbar/components/home/stickyBox.vue
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+ 更多达人
+
+
+
+ {{searchTabs.categoryLabel}}
+
+
+
+ {{searchTabs.sexLabel}}
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/topBox.vue b/pages/tabbar/components/home/topBox.vue
new file mode 100644
index 0000000..8f6d628
--- /dev/null
+++ b/pages/tabbar/components/home/topBox.vue
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 随机下单
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/userCard.vue b/pages/tabbar/components/home/userCard.vue
new file mode 100644
index 0000000..bd6d0ab
--- /dev/null
+++ b/pages/tabbar/components/home/userCard.vue
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+
+ 新人推荐
+
+
+
+
+
+
+
+
+ {{item.nickname}}
+
+
+
+
+
+
+
+
+
+
+ 人气达人
+
+
+
+
+
+
+
+
+
+ {{item.nickname}}
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/userList.vue b/pages/tabbar/components/home/userList.vue
new file mode 100644
index 0000000..18019d6
--- /dev/null
+++ b/pages/tabbar/components/home/userList.vue
@@ -0,0 +1,379 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{item.nickname}}
+
+
+ {{item.age}}
+
+
+
+ {{item.age}}
+
+
+
+
+
+
+
+
+
+
+
+ {{item.clerkLevel.name}}
+
+
+
+
+
+ 在线
+
+
+
+ 离线
+
+
+
+
+
+ {{categoryName}}
+
+
+
+
+ {{item.intro}}
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/home/voicePlay.vue b/pages/tabbar/components/home/voicePlay.vue
new file mode 100644
index 0000000..fb95eec
--- /dev/null
+++ b/pages/tabbar/components/home/voicePlay.vue
@@ -0,0 +1,184 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{sec}}"
+
+
+
+
diff --git a/pages/tabbar/components/member/layout.vue b/pages/tabbar/components/member/layout.vue
new file mode 100644
index 0000000..d3bcce3
--- /dev/null
+++ b/pages/tabbar/components/member/layout.vue
@@ -0,0 +1,233 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item}}
+
+
+
+
+
+
+
+
+
diff --git a/pages/tabbar/components/member/navBar.vue b/pages/tabbar/components/member/navBar.vue
new file mode 100644
index 0000000..dafb8da
--- /dev/null
+++ b/pages/tabbar/components/member/navBar.vue
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{title}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/member/viewItem.vue b/pages/tabbar/components/member/viewItem.vue
new file mode 100644
index 0000000..87c81f5
--- /dev/null
+++ b/pages/tabbar/components/member/viewItem.vue
@@ -0,0 +1,216 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.nickname}}
+
+
+
+
+
+
+
+
+ 19:39
+
+
+
+ [已读]
+ 希望打个赏哦
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/message/friend.vue b/pages/tabbar/components/message/friend.vue
new file mode 100644
index 0000000..1337205
--- /dev/null
+++ b/pages/tabbar/components/message/friend.vue
@@ -0,0 +1,208 @@
+
+
+
+
+
+
+
+
+
+
+ {{item}}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/message/gameBox.vue b/pages/tabbar/components/message/gameBox.vue
new file mode 100644
index 0000000..a9e02d1
--- /dev/null
+++ b/pages/tabbar/components/message/gameBox.vue
@@ -0,0 +1,149 @@
+
+
+
+
+
+ 服务类型
+
+
+ {{option.name}}
+
+
+
+
+
+
+ 选项
+
+
+ {{option.name}}
+
+
+
+
+
+
+ 选项
+
+
+ {{option.name}}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/message/navBar.vue b/pages/tabbar/components/message/navBar.vue
new file mode 100644
index 0000000..85e02b3
--- /dev/null
+++ b/pages/tabbar/components/message/navBar.vue
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+ {{item.name}}
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/message/peiwan.vue b/pages/tabbar/components/message/peiwan.vue
new file mode 100644
index 0000000..0f6c54c
--- /dev/null
+++ b/pages/tabbar/components/message/peiwan.vue
@@ -0,0 +1,346 @@
+
+
+
+
+
+ 店员性别
+
+
+
+
+
+
+
+
+
+
+
+ 小姐姐
+
+
+
+
+
+
+
+
+
+
+ 小哥哥
+
+
+
+
+
+
+ 店员等级
+
+
+
+ {{option.name}}
+
+
+
+
+
+
+
+ 购买数量
+
+
+
+
+
+
+
+
+
+ 排除下单过的店员
+
+
+
+
+
+
+
+
+
+
+
+ 总价:
+ {{ fen2yuan(game.price*form.num) }}
+ 钻石
+
+
+ 立即下单
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/message/viewItem.vue b/pages/tabbar/components/message/viewItem.vue
new file mode 100644
index 0000000..ce8bd94
--- /dev/null
+++ b/pages/tabbar/components/message/viewItem.vue
@@ -0,0 +1,265 @@
+
+
+
+
+
+
+
+
+
+
+
+ 通知助手
+
+ 前天
+
+
+
+ 希望打个赏哦
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.nickname}}
+
+
+
+
+
+
+
+
+ {{item.time}}
+
+
+
+ 已读
+ {{item.lastMessageContent}}
+ [语音消息]
+ [图片消息]
+
+
+
+
+
+
+ {{item.unreadMessageCount}}
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/mine/bgBox.vue b/pages/tabbar/components/mine/bgBox.vue
new file mode 100644
index 0000000..acf464e
--- /dev/null
+++ b/pages/tabbar/components/mine/bgBox.vue
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/mine/layout.vue b/pages/tabbar/components/mine/layout.vue
new file mode 100644
index 0000000..80b8a00
--- /dev/null
+++ b/pages/tabbar/components/mine/layout.vue
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/tabbar/components/mine/mainBox.vue b/pages/tabbar/components/mine/mainBox.vue
new file mode 100644
index 0000000..d91404c
--- /dev/null
+++ b/pages/tabbar/components/mine/mainBox.vue
@@ -0,0 +1,502 @@
+
+
+
+
+
+
+
+ {{ userInfo?.nickname || nickname }}
+
+
+
+ ID: {{ userInfo?.id || 88888 }}
+
+
+
+
+
+ 钻石
+
+
+
+
+ 积分
+
+
+
+ 动态
+
+
+ 礼物
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 我的订单
+
+
+
+ 待付款
+ {{numData.orderCount['unpaidCount']}}
+
+
+
+
+ 待服务
+
+
+
+
+ 服务中
+
+
+
+
+ 已完成
+
+
+
+
+
+ 接单中心
+
+
+
+
+ 接单中心
+
+
+
+
+ 抢单中心
+
+
+
+
+ 达人资料
+
+
+
+
+ 打赏记录
+
+
+
+
+
+
+
+
+ 常用工具
+
+
+
+
+
+
+ 达人申请
+
+
+
+
+ 分销中心
+
+
+
+
+ 签到有礼
+
+
+
+
+ 收藏达人
+
+
+
+
+ 优惠券
+
+
+
+
+ 购买授权
+
+
+
+
+ 申请提现
+
+
+
+
+
+
+
+
+
+
+ 尔加科技版权所有
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/mine/navBar.vue b/pages/tabbar/components/mine/navBar.vue
new file mode 100644
index 0000000..93c98a2
--- /dev/null
+++ b/pages/tabbar/components/mine/navBar.vue
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{userInfo.nickname}}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/mine/vipCard.vue b/pages/tabbar/components/mine/vipCard.vue
new file mode 100644
index 0000000..4a17861
--- /dev/null
+++ b/pages/tabbar/components/mine/vipCard.vue
@@ -0,0 +1,109 @@
+
+
+
+
+ VIP会员中心
+
+
+
+
+ 查看特权
+
+
+
+ 立即开通
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/trend/clerk-popup.vue b/pages/tabbar/components/trend/clerk-popup.vue
new file mode 100644
index 0000000..41f15a3
--- /dev/null
+++ b/pages/tabbar/components/trend/clerk-popup.vue
@@ -0,0 +1,132 @@
+
+
+
+
+ 切换店员
+
+
+
+
+
+
+
+
+
+ {{item.nickname}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/trend/fb-popup.vue b/pages/tabbar/components/trend/fb-popup.vue
new file mode 100644
index 0000000..20640c4
--- /dev/null
+++ b/pages/tabbar/components/trend/fb-popup.vue
@@ -0,0 +1,313 @@
+
+
+
+
+
+
+
+
+
+ 发布动态
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 立即发布
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/tabbar/components/trend/formCity.vue b/pages/tabbar/components/trend/formCity.vue
new file mode 100644
index 0000000..58d3a0f
--- /dev/null
+++ b/pages/tabbar/components/trend/formCity.vue
@@ -0,0 +1,55 @@
+
+
+
+ 关联店员
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/trend/formImage.vue b/pages/tabbar/components/trend/formImage.vue
new file mode 100644
index 0000000..ebe341f
--- /dev/null
+++ b/pages/tabbar/components/trend/formImage.vue
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/trend/formVideo.vue b/pages/tabbar/components/trend/formVideo.vue
new file mode 100644
index 0000000..a74af80
--- /dev/null
+++ b/pages/tabbar/components/trend/formVideo.vue
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/trend/formVoice.vue b/pages/tabbar/components/trend/formVoice.vue
new file mode 100644
index 0000000..3028da4
--- /dev/null
+++ b/pages/tabbar/components/trend/formVoice.vue
@@ -0,0 +1,256 @@
+
+
+
+ 录音
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 停止播放
+ 播放录音
+
+
+
+
+
+
+ 重录
+
+
+
+
+
+
+
+
+ 停止播放
+ 播放录音
+
+
+
+
+
+ 上传录音文件
+
+
+
+ 重录
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/trend/imgBox.vue b/pages/tabbar/components/trend/imgBox.vue
new file mode 100644
index 0000000..060ed7c
--- /dev/null
+++ b/pages/tabbar/components/trend/imgBox.vue
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+ 观看视频解锁
+
+
+
+
+
+
+
+
+
+
+
+
+ +{{imgList.length-2}}
+
+
+
+
+
+ 观看视频解锁
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/trend/layout.vue b/pages/tabbar/components/trend/layout.vue
new file mode 100644
index 0000000..ee38589
--- /dev/null
+++ b/pages/tabbar/components/trend/layout.vue
@@ -0,0 +1,179 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 获取实时动态提醒
+ 立即订阅
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/tabbar/components/trend/navBar.vue b/pages/tabbar/components/trend/navBar.vue
new file mode 100644
index 0000000..5fbdf9c
--- /dev/null
+++ b/pages/tabbar/components/trend/navBar.vue
@@ -0,0 +1,131 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.name}}
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/trend/postList.vue b/pages/tabbar/components/trend/postList.vue
new file mode 100644
index 0000000..1b5fe42
--- /dev/null
+++ b/pages/tabbar/components/trend/postList.vue
@@ -0,0 +1,512 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.city}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/trend/userCard.vue b/pages/tabbar/components/trend/userCard.vue
new file mode 100644
index 0000000..d8f58e3
--- /dev/null
+++ b/pages/tabbar/components/trend/userCard.vue
@@ -0,0 +1,190 @@
+
+
+
+
+
+
+
+ 置顶用户
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.nickname}}
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/trend/videoBox.vue b/pages/tabbar/components/trend/videoBox.vue
new file mode 100644
index 0000000..10f336d
--- /dev/null
+++ b/pages/tabbar/components/trend/videoBox.vue
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/components/trend/voicePlay.vue b/pages/tabbar/components/trend/voicePlay.vue
new file mode 100644
index 0000000..6720241
--- /dev/null
+++ b/pages/tabbar/components/trend/voicePlay.vue
@@ -0,0 +1,184 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{sec}}"
+
+
+
+
diff --git a/pages/tabbar/home.vue b/pages/tabbar/home.vue
new file mode 100644
index 0000000..f237486
--- /dev/null
+++ b/pages/tabbar/home.vue
@@ -0,0 +1,244 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/index.vue b/pages/tabbar/index.vue
new file mode 100644
index 0000000..73b8995
--- /dev/null
+++ b/pages/tabbar/index.vue
@@ -0,0 +1,395 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{gift.username}}
+ 赠送
+ {{gift.nickname}}
+ {{gift.name}}
+ x{{gift.count}}
+
+
+ 关闭
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/tabbar/message.vue b/pages/tabbar/message.vue
new file mode 100644
index 0000000..0a63119
--- /dev/null
+++ b/pages/tabbar/message.vue
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/mine.vue b/pages/tabbar/mine.vue
new file mode 100644
index 0000000..ec77f11
--- /dev/null
+++ b/pages/tabbar/mine.vue
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/social.vue b/pages/tabbar/social.vue
new file mode 100644
index 0000000..69d947a
--- /dev/null
+++ b/pages/tabbar/social.vue
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/tabbar/trend.vue b/pages/tabbar/trend.vue
new file mode 100644
index 0000000..595bb2a
--- /dev/null
+++ b/pages/tabbar/trend.vue
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/trend/city/components/orderList.vue b/pages/trend/city/components/orderList.vue
new file mode 100644
index 0000000..23dec4f
--- /dev/null
+++ b/pages/trend/city/components/orderList.vue
@@ -0,0 +1,510 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.city}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/trend/city/list.vue b/pages/trend/city/list.vue
new file mode 100644
index 0000000..93009b7
--- /dev/null
+++ b/pages/trend/city/list.vue
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/trend/detail/components/card.vue b/pages/trend/detail/components/card.vue
new file mode 100644
index 0000000..9bff436
--- /dev/null
+++ b/pages/trend/detail/components/card.vue
@@ -0,0 +1,510 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.city}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/trend/detail/index.vue b/pages/trend/detail/index.vue
new file mode 100644
index 0000000..c8237bb
--- /dev/null
+++ b/pages/trend/detail/index.vue
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/trend/my/components/orderList.vue b/pages/trend/my/components/orderList.vue
new file mode 100644
index 0000000..d0e266b
--- /dev/null
+++ b/pages/trend/my/components/orderList.vue
@@ -0,0 +1,500 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.city}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/trend/my/list.vue b/pages/trend/my/list.vue
new file mode 100644
index 0000000..417b0b4
--- /dev/null
+++ b/pages/trend/my/list.vue
@@ -0,0 +1,143 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/user/address/edit.vue b/pages/user/address/edit.vue
new file mode 100644
index 0000000..b88ee07
--- /dev/null
+++ b/pages/user/address/edit.vue
@@ -0,0 +1,305 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 设为默认地址
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/user/address/list.vue b/pages/user/address/list.vue
new file mode 100644
index 0000000..58b6214
--- /dev/null
+++ b/pages/user/address/list.vue
@@ -0,0 +1,165 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/user/detail/components/detail-navbar.vue b/pages/user/detail/components/detail-navbar.vue
new file mode 100644
index 0000000..1723c51
--- /dev/null
+++ b/pages/user/detail/components/detail-navbar.vue
@@ -0,0 +1,221 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.label }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/user/detail/components/giftList.vue b/pages/user/detail/components/giftList.vue
new file mode 100644
index 0000000..63eefff
--- /dev/null
+++ b/pages/user/detail/components/giftList.vue
@@ -0,0 +1,316 @@
+
+
+
+
+ 选择礼物
+
+
+ 取消
+
+
+
+
+
+
+
+ 特效
+ ·{{item.tag}}
+
+
+ {{item.tag}}
+
+
+ {{item.name}}
+ {{ fen2yuan(item.money) }} 钻石
+
+
+
+
+
+
+
+
+
+
+ {{gift.name}}
+ {{ fen2yuan(gift.money) }} 钻石
+
+ 取消
+ 确定
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/user/detail/components/giftPopup.vue b/pages/user/detail/components/giftPopup.vue
new file mode 100644
index 0000000..8abb4d6
--- /dev/null
+++ b/pages/user/detail/components/giftPopup.vue
@@ -0,0 +1,445 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 赠送类型
+
+
+
+ 赠礼
+
+
+
+
+
+
+ 打赏金额
+
+
+
+
+
+
+
+
+ 赠送礼物
+
+
+ 已选【{{gift.name}}】
+ 点击选择礼物
+
+
+
+
+
+
+ 礼物数量
+
+
+
+
+
+
+
+
+
+ 心动留言
+
+
+
+
+
+
+
+
+ 您的微信号
+
+
+
+
+
+
+
+
+
+
+
+
+ 立即赠送
+
+
+
+
+
+ 总价:
+ {{ fen2yuan(gift.money*form.count) }}
+ 钻石
+
+
+ 立即赠送
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/user/detail/components/layout.vue b/pages/user/detail/components/layout.vue
new file mode 100644
index 0000000..0e1764e
--- /dev/null
+++ b/pages/user/detail/components/layout.vue
@@ -0,0 +1,286 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 赠礼
+ 密聊
+
+
+ 密聊
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/user/detail/components/navBar.vue b/pages/user/detail/components/navBar.vue
new file mode 100644
index 0000000..42ca85b
--- /dev/null
+++ b/pages/user/detail/components/navBar.vue
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/user/detail/components/photoBox.vue b/pages/user/detail/components/photoBox.vue
new file mode 100644
index 0000000..7d575ed
--- /dev/null
+++ b/pages/user/detail/components/photoBox.vue
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/user/detail/components/postList.vue b/pages/user/detail/components/postList.vue
new file mode 100644
index 0000000..5080775
--- /dev/null
+++ b/pages/user/detail/components/postList.vue
@@ -0,0 +1,362 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.city}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/user/detail/components/starList.vue b/pages/user/detail/components/starList.vue
new file mode 100644
index 0000000..32ff751
--- /dev/null
+++ b/pages/user/detail/components/starList.vue
@@ -0,0 +1,310 @@
+
+
+
+
+ 礼物墙
+ (已点亮:{{starNum}}/{{total}})
+
+
+
+
+
+
+
+ 特效
+ ·{{item.tag}}
+
+
+ {{item.tag}}
+
+
+ {{item.name}}
+ x {{item.playNum}}
+ 点亮
+ 赠送
+ 已下架
+
+
+
+
+
+
+
+
+
+
+ {{gift.name}}
+ {{ fen2yuan(gift.money) }} 钻石
+
+ 取消
+ 点亮
+ 赠送
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/user/detail/components/stickyBox.vue b/pages/user/detail/components/stickyBox.vue
new file mode 100644
index 0000000..7739659
--- /dev/null
+++ b/pages/user/detail/components/stickyBox.vue
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/user/detail/components/userBox.vue b/pages/user/detail/components/userBox.vue
new file mode 100644
index 0000000..3c8e75c
--- /dev/null
+++ b/pages/user/detail/components/userBox.vue
@@ -0,0 +1,308 @@
+
+
+
+
+
+
+
+
+
+
+ {{clerk.nickname}}
+
+
+ L1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{clerk.age}}
+ {{clerk.city}}
+
+ {{clerk.intro}}
+
+
+ 已注册{{clerk.day}}天
+ 可交换名片
+
+
+
+ {{categoryName}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/user/detail/index.vue b/pages/user/detail/index.vue
new file mode 100644
index 0000000..440f970
--- /dev/null
+++ b/pages/user/detail/index.vue
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/user/goods-collect.vue b/pages/user/goods-collect.vue
new file mode 100644
index 0000000..af5e64a
--- /dev/null
+++ b/pages/user/goods-collect.vue
@@ -0,0 +1,233 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/user/goods-log.vue b/pages/user/goods-log.vue
new file mode 100644
index 0000000..b52efe3
--- /dev/null
+++ b/pages/user/goods-log.vue
@@ -0,0 +1,308 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/user/goods_details_store/index.vue b/pages/user/goods_details_store/index.vue
new file mode 100644
index 0000000..07b6850
--- /dev/null
+++ b/pages/user/goods_details_store/index.vue
@@ -0,0 +1,275 @@
+
+
+
+
+
+
+
+
+ {{ item.name }}
+
+ {{ item.areaName }}{{ ', ' + item.detailAddress }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 距离{{ item.distance.toFixed(2) }}千米
+ 查看地图
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/user/info.vue b/pages/user/info.vue
new file mode 100644
index 0000000..3699790
--- /dev/null
+++ b/pages/user/info.vue
@@ -0,0 +1,475 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/user/vip.vue b/pages/user/vip.vue
new file mode 100644
index 0000000..ca0b0ba
--- /dev/null
+++ b/pages/user/vip.vue
@@ -0,0 +1,382 @@
+
+
+
+
+ VIP尊享会员
+
+
+ VIP会员({{showDayTime(userInfo.vipEndTime)}}到期)
+ 暂未激活VIP会员
+
+
+
+
+
+ {{item.num}}{{item.unit}}
+ ¥{{item.month}}/{{item.tip}}
+ ¥{{item.pay}}
+ 新人优惠
+
+
+
+
+ VIP特权
+
+
+
+
+
+
+
+ 每天3次发布动态无广告
+ 每天免费发布3次无广告增加曝光
+
+
+
+
+
+
+
+ 每天5次交换名片
+ 每天可以免费交换5次名片
+
+
+
+
+
+
+
+ 打招呼聊天免费
+ 打招呼聊天发送消息无限制
+
+
+
+
+
+
+
+ 每天3次首页置顶
+ 每天可以免费置顶3次
+
+
+
+
+
+
+
+ 可查看同城的用户
+ 离得近奔现的概率更高
+
+
+
+
+ 已开通
+
+
+
+ ¥{{pay.pay}} 立即购买
+ 每天不到¥{{pay.day}}
+
+
+
+
+
+
+
+ 已开通
+
+
+
+ ¥{{pay.pay}} 购买会员
+ 每天不到¥{{pay.day}}
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/user/wallet/money.vue b/pages/user/wallet/money.vue
new file mode 100644
index 0000000..b6c9d0d
--- /dev/null
+++ b/pages/user/wallet/money.vue
@@ -0,0 +1,379 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 总收入¥{{ fen2yuan(state.summary.totalIncome) }}
+ 总支出¥{{ fen2yuan(state.summary.totalExpense) }}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.title }}
+
+
+ +{{ fen2yuan(item.price) }}
+ {{ fen2yuan(item.price) }}
+
+
+
+ {{ sheep.$helper.timeFormat(state.createTime, 'yyyy-mm-dd hh:MM:ss') }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/user/wallet/score.vue b/pages/user/wallet/score.vue
new file mode 100644
index 0000000..f49866e
--- /dev/null
+++ b/pages/user/wallet/score.vue
@@ -0,0 +1,323 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.title }}{{ item.description ? ' - ' + item.description : '' }}
+ {{
+ sheep.$helper.timeFormat(item.createTime, 'yyyy-mm-dd hh:MM:ss')
+ }}
+
+ +{{ item.point }}
+ {{ item.point }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/worker/blind/components/gameBox.vue b/pages/worker/blind/components/gameBox.vue
new file mode 100644
index 0000000..4c4687b
--- /dev/null
+++ b/pages/worker/blind/components/gameBox.vue
@@ -0,0 +1,149 @@
+
+
+
+
+
+ 技能类型
+
+
+ {{option.name}}
+
+
+
+
+
+
+ 选项
+
+
+ {{option.name}}
+
+
+
+
+
+
+ 选项
+
+
+ {{option.name}}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/worker/blind/components/layout.vue b/pages/worker/blind/components/layout.vue
new file mode 100644
index 0000000..022d227
--- /dev/null
+++ b/pages/worker/blind/components/layout.vue
@@ -0,0 +1,357 @@
+
+
+
+
+
+
+
+
+ 达人性别
+
+
+
+
+
+
+
+
+
+
+
+ 小姐姐
+
+
+
+
+
+
+
+
+
+
+ 小哥哥
+
+
+
+
+
+
+ 达人等级
+
+
+
+ {{option.name}}
+
+
+
+
+
+
+
+ 购买数量
+
+
+
+
+
+
+
+
+
+ 排除下单过的达人
+
+
+
+
+
+
+
+
+
+
+
+ 总价:
+ {{ fen2yuan(game.price*form.num) }}
+ 钻石
+
+
+ 立即下单
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/worker/blind/index.vue b/pages/worker/blind/index.vue
new file mode 100644
index 0000000..f4756f4
--- /dev/null
+++ b/pages/worker/blind/index.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/worker/levelList/components/layout.vue b/pages/worker/levelList/components/layout.vue
new file mode 100644
index 0000000..5823785
--- /dev/null
+++ b/pages/worker/levelList/components/layout.vue
@@ -0,0 +1,109 @@
+
+
+
+
+
+
+
+
+ 当前等级:{{clerkLevel}}
+
+
+
+
+ 保存配置
+
+
+
+
+
+
+
+
diff --git a/pages/worker/levelList/components/levelList.vue b/pages/worker/levelList/components/levelList.vue
new file mode 100644
index 0000000..e26a464
--- /dev/null
+++ b/pages/worker/levelList/components/levelList.vue
@@ -0,0 +1,105 @@
+
+
+
+
+ 技能列表
+ 开关
+
+
+
+
+ {{tb.name}}
+
+
+
+
+
+ {{tb2.name}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{tb2.name}}
+
+
+
+ {{tb3.name}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/worker/levelList/components/table-bd.vue b/pages/worker/levelList/components/table-bd.vue
new file mode 100644
index 0000000..8819269
--- /dev/null
+++ b/pages/worker/levelList/components/table-bd.vue
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
diff --git a/pages/worker/levelList/components/table-td.vue b/pages/worker/levelList/components/table-td.vue
new file mode 100644
index 0000000..13c6ea3
--- /dev/null
+++ b/pages/worker/levelList/components/table-td.vue
@@ -0,0 +1,305 @@
+
+
+
+
+
+
+
+
+
diff --git a/pages/worker/levelList/components/table-tr.vue b/pages/worker/levelList/components/table-tr.vue
new file mode 100644
index 0000000..2b12c95
--- /dev/null
+++ b/pages/worker/levelList/components/table-tr.vue
@@ -0,0 +1,208 @@
+
+
+
+
+
+
+
+
+
diff --git a/pages/worker/levelList/index.vue b/pages/worker/levelList/index.vue
new file mode 100644
index 0000000..7737e8b
--- /dev/null
+++ b/pages/worker/levelList/index.vue
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/worker/workerList/components/layout.vue b/pages/worker/workerList/components/layout.vue
new file mode 100644
index 0000000..ff333ca
--- /dev/null
+++ b/pages/worker/workerList/components/layout.vue
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 添加
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/worker/workerList/components/workerList.vue b/pages/worker/workerList/components/workerList.vue
new file mode 100644
index 0000000..c3292e9
--- /dev/null
+++ b/pages/worker/workerList/components/workerList.vue
@@ -0,0 +1,208 @@
+
+
+
+
+
+
+
+
+ 在线
+ 离线
+
+
+
+
+
+ {{item.nickname}}
+
+
+ {{item.age}}
+
+
+
+ {{item.age}}
+
+
+ 待审核
+ 已审核
+
+
+
+ 编辑资料
+ 技能管理
+ 在线状态
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/worker/workerList/index.vue b/pages/worker/workerList/index.vue
new file mode 100644
index 0000000..37b091f
--- /dev/null
+++ b/pages/worker/workerList/index.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/worker/workerList/set.vue b/pages/worker/workerList/set.vue
new file mode 100644
index 0000000..e4f5d72
--- /dev/null
+++ b/pages/worker/workerList/set.vue
@@ -0,0 +1,148 @@
+
+
+
+
+
+ 接单时间段
+
+
+
+
+
+ 当前在线状态
+
+
+
+
+
+ 盲盒订单提醒
+
+
+
+
+
+
+ 保存
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sheep/api/im/memberConversation.js b/sheep/api/im/memberConversation.js
new file mode 100644
index 0000000..17bb4a7
--- /dev/null
+++ b/sheep/api/im/memberConversation.js
@@ -0,0 +1,80 @@
+import request from '@/sheep/request';
+
+const ImConversationApi = {
+ // 获得会话列表
+ getMemberConversationPage: (params) => {
+ return request({
+ url: '/im/member-conversation/page',
+ method: 'GET',
+ params,
+ custom: {
+ auth: true,
+ showLoading: false,
+ },
+ });
+ },
+ getRandomMemberConversation: () => {
+ return request({
+ url: '/im/member-conversation/getRandom',
+ method: 'GET',
+ custom: {
+ auth: true,
+ showLoading: false,
+ },
+ });
+ },
+ // 创建会话
+ createMemberConversation: (data) => {
+ return request({
+ url: '/im/member-conversation/create',
+ method: 'POST',
+ data,
+ custom: {
+ auth: true,
+ showLoading: false,
+ },
+ });
+ },
+ // 删除会话
+ deleteMemberConversation: (id) => {
+ return request({
+ url: '/im/member-conversation/delete',
+ method: 'DELETE',
+ params: {
+ id
+ },
+ custom: {
+ auth: true,
+ showLoading: false,
+ },
+ });
+ },
+ // 拉黑
+ slashedMemberConversation: (id) => {
+ return request({
+ url: '/im/member-conversation/slashed',
+ method: 'DELETE',
+ params: {
+ id
+ },
+ custom: {
+ auth: true,
+ showLoading: false,
+ },
+ });
+ },
+ // 置顶会话
+ pinnedMemberConversation: (data) => {
+ return request({
+ url: '/im/member-conversation/pinned',
+ method: 'PUT',
+ data,
+ custom: {
+ auth: true,
+ showLoading: false,
+ },
+ });
+ },
+};
+
+export default ImConversationApi;
diff --git a/sheep/api/im/memberMessage.js b/sheep/api/im/memberMessage.js
new file mode 100644
index 0000000..f10bb64
--- /dev/null
+++ b/sheep/api/im/memberMessage.js
@@ -0,0 +1,44 @@
+import request from '@/sheep/request';
+
+const ImMessageApi = {
+ // 获得消息列表
+ getMemberMessagePage: (params) => {
+ return request({
+ url: '/im/member-message/page',
+ method: 'GET',
+ params,
+ custom: {
+ auth: true,
+ showLoading: false,
+ },
+ });
+ },
+ // 更新消息已读
+ updateReadStatus: (messageId) => {
+ return request({
+ url: '/im/member-message/update-read-status',
+ method: 'POST',
+ params: { messageId },
+ custom: {
+ auth: true,
+ showLoading: false,
+ },
+ });
+ },
+ // 发送消息
+ sendImMessage: (data) => {
+ return request({
+ url: '/im/member-message/send',
+ method: 'POST',
+ data,
+ custom: {
+ auth: true,
+ showLoading: false,
+ showSuccess: false,
+ successMsg: '保存成功'
+ },
+ });
+ },
+};
+
+export default ImMessageApi;
diff --git a/sheep/api/infra/file.js b/sheep/api/infra/file.js
new file mode 100644
index 0000000..f7f2a96
--- /dev/null
+++ b/sheep/api/infra/file.js
@@ -0,0 +1,45 @@
+import { baseUrl, apiPath, tenantId } from '@/sheep/config';
+
+const FileApi = {
+ // 上传文件
+ uploadFile: (file) => {
+ // TODO 芋艿:访问令牌的接入;
+ const token = uni.getStorageSync('token');
+ uni.showLoading({
+ title: '上传中',
+ });
+ return new Promise((resolve, reject) => {
+ uni.uploadFile({
+ url: baseUrl + apiPath + '/infra/file/upload',
+ filePath: file,
+ name: 'file',
+ header: {
+ // Accept: 'text/json',
+ Accept: '*/*',
+ 'tenant-id': tenantId,
+ // Authorization: 'Bearer test247',
+ },
+ success: (uploadFileRes) => {
+ let result = JSON.parse(uploadFileRes.data);
+ if (result.error === 1) {
+ uni.showToast({
+ icon: 'none',
+ title: result.msg,
+ });
+ } else {
+ return resolve(result);
+ }
+ },
+ fail: (error) => {
+ console.log('上传失败:', error);
+ return resolve(false);
+ },
+ complete: () => {
+ uni.hideLoading();
+ },
+ });
+ });
+ },
+};
+
+export default FileApi;
diff --git a/sheep/api/member/address.js b/sheep/api/member/address.js
new file mode 100644
index 0000000..d0c16ce
--- /dev/null
+++ b/sheep/api/member/address.js
@@ -0,0 +1,53 @@
+import request from '@/sheep/request';
+
+const AddressApi = {
+ // 获得用户收件地址列表
+ getAddressList: () => {
+ return request({
+ url: '/member/address/list',
+ method: 'GET'
+ });
+ },
+ // 创建用户收件地址
+ createAddress: (data) => {
+ return request({
+ url: '/member/address/create',
+ method: 'POST',
+ data,
+ custom: {
+ showSuccess: true,
+ successMsg: '保存成功'
+ },
+ });
+ },
+ // 更新用户收件地址
+ updateAddress: (data) => {
+ return request({
+ url: '/member/address/update',
+ method: 'PUT',
+ data,
+ custom: {
+ showSuccess: true,
+ successMsg: '更新成功'
+ },
+ });
+ },
+ // 获得用户收件地址
+ getAddress: (id) => {
+ return request({
+ url: '/member/address/get',
+ method: 'GET',
+ params: { id }
+ });
+ },
+ // 删除用户收件地址
+ deleteAddress: (id) => {
+ return request({
+ url: '/member/address/delete',
+ method: 'DELETE',
+ params: { id }
+ });
+ },
+};
+
+export default AddressApi;
diff --git a/sheep/api/member/auth.js b/sheep/api/member/auth.js
new file mode 100644
index 0000000..a1c0660
--- /dev/null
+++ b/sheep/api/member/auth.js
@@ -0,0 +1,132 @@
+import request from '@/sheep/request';
+
+const AuthUtil = {
+ // 使用手机 + 密码登录
+ login: (data) => {
+ return request({
+ url: '/member/auth/login',
+ method: 'POST',
+ data,
+ custom: {
+ showSuccess: true,
+ loadingMsg: '登录中',
+ successMsg: '登录成功',
+ },
+ });
+ },
+ // 使用手机 + 验证码登录
+ smsLogin: (data) => {
+ return request({
+ url: '/member/auth/sms-login',
+ method: 'POST',
+ data,
+ custom: {
+ showSuccess: true,
+ loadingMsg: '登录中',
+ successMsg: '登录成功',
+ },
+ });
+ },
+ // 发送手机验证码
+ sendSmsCode: (mobile, scene) => {
+ return request({
+ url: '/member/auth/send-sms-code',
+ method: 'POST',
+ data: {
+ mobile,
+ scene,
+ },
+ custom: {
+ loadingMsg: '发送中',
+ showSuccess: true,
+ successMsg: '发送成功',
+ },
+ });
+ },
+ // 登出系统
+ logout: () => {
+ return request({
+ url: '/member/auth/logout',
+ method: 'POST',
+ });
+ },
+ // 刷新令牌
+ refreshToken: (refreshToken) => {
+ return request({
+ url: '/member/auth/refresh-token',
+ method: 'POST',
+ params: {
+ refreshToken
+ },
+ custom: {
+ loading: false, // 不用加载中
+ showError: false, // 不展示错误提示
+ },
+ });
+ },
+ // 社交授权的跳转
+ socialAuthRedirect: (type, redirectUri) => {
+ return request({
+ url: '/member/auth/social-auth-redirect',
+ method: 'GET',
+ params: {
+ type,
+ redirectUri,
+ },
+ custom: {
+ showSuccess: true,
+ loadingMsg: '登陆中',
+ },
+ });
+ },
+ // 社交快捷登录
+ socialLogin: (type, code, state) => {
+ return request({
+ url: '/member/auth/social-login',
+ method: 'POST',
+ data: {
+ type,
+ code,
+ state,
+ },
+ custom: {
+ showSuccess: true,
+ loadingMsg: '登陆中',
+ },
+ });
+ },
+ // 微信小程序的一键登录
+ weixinMiniAppLogin: (phoneCode, loginCode, state) => {
+ return request({
+ url: '/member/auth/weixin-mini-app-login',
+ method: 'POST',
+ data: {
+ phoneCode,
+ loginCode,
+ state
+ },
+ custom: {
+ showSuccess: true,
+ loadingMsg: '登陆中',
+ successMsg: '登录成功',
+ },
+ });
+ },
+ // 创建微信 JS SDK 初始化所需的签名
+ createWeixinMpJsapiSignature: (url) => {
+ return request({
+ url: '/member/auth/create-weixin-jsapi-signature',
+ method: 'POST',
+ params: {
+ url
+ },
+ custom: {
+ showError: false,
+ showLoading: false,
+ },
+ })
+ },
+ //
+};
+
+export default AuthUtil;
diff --git a/sheep/api/member/point.js b/sheep/api/member/point.js
new file mode 100644
index 0000000..188ffd4
--- /dev/null
+++ b/sheep/api/member/point.js
@@ -0,0 +1,19 @@
+import request from '@/sheep/request';
+
+const PointApi = {
+ // 获得用户积分记录分页
+ getPointRecordPage: (params) => {
+ if (params.addStatus === undefined) {
+ delete params.addStatus
+ }
+ const queryString = Object.keys(params)
+ .map((key) => encodeURIComponent(key) + '=' + params[key])
+ .join('&');
+ return request({
+ url: `/member/point/record/page?${queryString}`,
+ method: 'GET',
+ });
+ }
+};
+
+export default PointApi;
diff --git a/sheep/api/member/signin.js b/sheep/api/member/signin.js
new file mode 100644
index 0000000..35169ef
--- /dev/null
+++ b/sheep/api/member/signin.js
@@ -0,0 +1,37 @@
+import request from '@/sheep/request';
+
+const SignInApi = {
+ // 获得签到规则列表
+ getSignInConfigList: () => {
+ return request({
+ url: '/member/sign-in/config/list',
+ method: 'GET',
+ });
+ },
+ // 获得个人签到统计
+ getSignInRecordSummary: () => {
+ return request({
+ url: '/member/sign-in/record/get-summary',
+ method: 'GET',
+ });
+ },
+ // 签到
+ createSignInRecord: () => {
+ return request({
+ url: '/member/sign-in/record/create',
+ method: 'POST',
+ });
+ },
+ // 获得签到记录分页
+ getSignRecordPage: (params) => {
+ const queryString = Object.keys(params)
+ .map((key) => encodeURIComponent(key) + '=' + params[key])
+ .join('&');
+ return request({
+ url: `/member/sign-in/record/page?${queryString}`,
+ method: 'GET',
+ });
+ },
+};
+
+export default SignInApi;
\ No newline at end of file
diff --git a/sheep/api/member/social.js b/sheep/api/member/social.js
new file mode 100644
index 0000000..14e6edf
--- /dev/null
+++ b/sheep/api/member/social.js
@@ -0,0 +1,76 @@
+import request from '@/sheep/request';
+
+const SocialApi = {
+ // 获得社交用户
+ getSocialUser: (type) => {
+ return request({
+ url: '/member/social-user/get',
+ method: 'GET',
+ params: {
+ type
+ },
+ custom: {
+ showLoading: false,
+ },
+ });
+ },
+ // 社交绑定
+ socialBind: (type, code, state) => {
+ return request({
+ url: '/member/social-user/bind',
+ method: 'POST',
+ data: {
+ type,
+ code,
+ state
+ },
+ custom: {
+ custom: {
+ showSuccess: true,
+ loadingMsg: '绑定中',
+ successMsg: '绑定成功',
+ },
+ },
+ });
+ },
+ // 社交绑定
+ socialUnbind: (type, openid) => {
+ return request({
+ url: '/member/social-user/unbind',
+ method: 'DELETE',
+ data: {
+ type,
+ openid
+ },
+ custom: {
+ showLoading: false,
+ loadingMsg: '解除绑定',
+ successMsg: '解绑成功',
+ },
+ });
+ },
+ // 获取订阅消息模板列表
+ getSubscribeTemplateList: () =>
+ request({
+ url: '/member/social-user/get-subscribe-template-list',
+ method: 'GET',
+ custom: {
+ showError: false,
+ showLoading: false,
+ },
+ }),
+ // 获取微信小程序码
+ getWxaQrcode: async (path, query) => {
+ return await request({
+ url: '/member/social-user/wxa-qrcode',
+ method: 'POST',
+ data: {
+ scene: query,
+ path,
+ checkPath: false, // TODO 开发环境暂不检查 path 是否存在
+ },
+ });
+ },
+};
+
+export default SocialApi;
\ No newline at end of file
diff --git a/sheep/api/member/user.js b/sheep/api/member/user.js
new file mode 100644
index 0000000..671324c
--- /dev/null
+++ b/sheep/api/member/user.js
@@ -0,0 +1,166 @@
+import request from '@/sheep/request';
+
+const UserApi = {
+ // 获取会员列表
+ getUserPage: (params) => {
+ return request({
+ url: '/member/user/page',
+ method: 'GET',
+ params,
+ custom: {
+ auth: false,
+ showLoading: false,
+ },
+ });
+ },
+ // 获得基本信息
+ getUserInfo: () => {
+ return request({
+ url: '/member/user/get',
+ method: 'GET',
+ custom: {
+ showLoading: false,
+ auth: true,
+ },
+ });
+ },
+ // 获得榜单信息
+ getWeekTopList: () => {
+ return request({
+ url: '/member/user/getWeekTopList',
+ method: 'GET',
+ custom: {
+ auth: false,
+ showLoading: false,
+ },
+ });
+ },
+ // 获得首页信息
+ getHomeData: () => {
+ return request({
+ url: '/member/user/getHomeData',
+ method: 'GET',
+ custom: {
+ auth: false,
+ showLoading: false,
+ },
+ });
+ },
+ // 获得基本信息
+ getUserInfoById: (id) => {
+ return request({
+ url: '/member/user/getByUserId',
+ method: 'GET',
+ params: { id },
+ custom: {
+ showLoading: false,
+ auth: false,
+ },
+ });
+ },
+ // 交换名片
+ getQrcodeByUserId: (id) => {
+ return request({
+ url: '/member/user/getQrcodeByUserId',
+ method: 'GET',
+ params: { id },
+ custom: {
+ showLoading: false,
+ auth: true,
+ },
+ });
+ },
+ // 判断是否关注公众号
+ getQrcode: () => {
+ return request({
+ url: '/mp/user/getQrcode',
+ method: 'GET',
+ custom: {
+ showLoading: false,
+ auth: true,
+ },
+ });
+ },
+ // 修改基本信息
+ updateUser: (data) => {
+ return request({
+ url: '/member/user/update',
+ method: 'PUT',
+ data,
+ custom: {
+ auth: true,
+ showSuccess: true,
+ successMsg: '更新成功'
+ },
+ });
+ },
+ // 首页置顶
+ slashed: () => {
+ return request({
+ url: '/member/user/slashed',
+ method: 'PUT',
+ custom: {
+ auth: true,
+ showSuccess: true,
+ successMsg: '置顶成功'
+ },
+ });
+ },
+ // 修改用户手机
+ updateUserMobile: (data) => {
+ return request({
+ url: '/member/user/update-mobile',
+ method: 'PUT',
+ data,
+ custom: {
+ loadingMsg: '验证中',
+ showSuccess: true,
+ successMsg: '修改成功'
+ },
+ });
+ },
+ // 基于微信小程序的授权码,修改用户手机
+ updateUserMobileByWeixin: (code) => {
+ return request({
+ url: '/member/user/update-mobile-by-weixin',
+ method: 'PUT',
+ data: {
+ code
+ },
+ custom: {
+ showSuccess: true,
+ loadingMsg: '获取中',
+ successMsg: '修改成功'
+ },
+ });
+ },
+ // 修改密码
+ updateUserPassword: (data) => {
+ return request({
+ url: '/member/user/update-password',
+ method: 'PUT',
+ data,
+ custom: {
+ loadingMsg: '验证中',
+ showSuccess: true,
+ successMsg: '修改成功'
+ },
+ });
+ },
+ // 重置密码
+ resetUserPassword: (data) => {
+ return request({
+ url: '/member/user/reset-password',
+ method: 'PUT',
+ data,
+ custom: {
+ loadingMsg: '验证中',
+ showSuccess: true,
+ successMsg: '修改成功'
+ }
+ });
+ },
+
+};
+
+export default UserApi;
diff --git a/sheep/api/migration/app.js b/sheep/api/migration/app.js
new file mode 100644
index 0000000..158414f
--- /dev/null
+++ b/sheep/api/migration/app.js
@@ -0,0 +1,21 @@
+import request from '@/sheep/request';
+
+// TODO 芋艿:小程序直播还不支持
+export default {
+ //小程序直播
+ mplive: {
+ getRoomList: (ids) =>
+ request({
+ url: 'app/mplive/getRoomList',
+ method: 'GET',
+ params: {
+ ids: ids.join(','),
+ }
+ }),
+ getMpLink: () =>
+ request({
+ url: 'app/mplive/getMpLink',
+ method: 'GET'
+ }),
+ },
+};
diff --git a/sheep/api/migration/index.js b/sheep/api/migration/index.js
new file mode 100644
index 0000000..31a85ef
--- /dev/null
+++ b/sheep/api/migration/index.js
@@ -0,0 +1,10 @@
+const files = import.meta.glob('./*.js', { eager: true });
+let api = {};
+Object.keys(files).forEach((key) => {
+ api = {
+ ...api,
+ [key.replace(/(.*\/)*([^.]+).*/gi, '$2')]: files[key].default,
+ };
+});
+
+export default api;
\ No newline at end of file
diff --git a/sheep/api/migration/third.js b/sheep/api/migration/third.js
new file mode 100644
index 0000000..325638c
--- /dev/null
+++ b/sheep/api/migration/third.js
@@ -0,0 +1,18 @@
+import request from '@/sheep/request';
+
+export default {
+ // 苹果相关
+ apple: {
+ // 第三方登录
+ login: (data) =>
+ request({
+ url: 'third/apple/login',
+ method: 'POST',
+ data,
+ custom: {
+ showSuccess: true,
+ loadingMsg: '登陆中',
+ },
+ }),
+ },
+};
diff --git a/sheep/api/pay/channel.js b/sheep/api/pay/channel.js
new file mode 100644
index 0000000..4e7bfc5
--- /dev/null
+++ b/sheep/api/pay/channel.js
@@ -0,0 +1,14 @@
+import request from '@/sheep/request';
+
+const PayChannelApi = {
+ // 获得指定应用的开启的支付渠道编码列表
+ getEnableChannelCodeList: (appId) => {
+ return request({
+ url: '/pay/channel/get-enable-code-list',
+ method: 'GET',
+ params: { appId }
+ });
+ },
+};
+
+export default PayChannelApi;
diff --git a/sheep/api/pay/order.js b/sheep/api/pay/order.js
new file mode 100644
index 0000000..f985359
--- /dev/null
+++ b/sheep/api/pay/order.js
@@ -0,0 +1,22 @@
+import request from '@/sheep/request';
+
+const PayOrderApi = {
+ // 获得支付订单
+ getOrder: (id) => {
+ return request({
+ url: '/pay/order/get',
+ method: 'GET',
+ params: { id }
+ });
+ },
+ // 提交支付订单
+ submitOrder: (data) => {
+ return request({
+ url: '/pay/order/submit',
+ method: 'POST',
+ data
+ });
+ }
+};
+
+export default PayOrderApi;
diff --git a/sheep/api/pay/point.js b/sheep/api/pay/point.js
new file mode 100644
index 0000000..09c7a1d
--- /dev/null
+++ b/sheep/api/pay/point.js
@@ -0,0 +1,37 @@
+import request from '@/sheep/request';
+
+const PayPointApi = {
+ // 获得钱包充值套餐列表
+ getPointRechargePackageList: () => {
+ return request({
+ url: '/pay/point-recharge-package/list',
+ method: 'GET',
+ custom: {
+ showError: false,
+ showLoading: false,
+ },
+ });
+ },
+ // 创建钱包充值记录(发起充值)
+ createPointRecharge: (data) => {
+ return request({
+ url: '/pay/point-recharge/create',
+ method: 'POST',
+ data,
+ });
+ },
+ // 获得钱包充值记录分页
+ getPointRechargePage: (params) => {
+ return request({
+ url: '/pay/point-recharge/page',
+ method: 'GET',
+ params,
+ custom: {
+ showError: false,
+ showLoading: false,
+ },
+ });
+ },
+};
+
+export default PayPointApi;
diff --git a/sheep/api/pay/wallet.js b/sheep/api/pay/wallet.js
new file mode 100644
index 0000000..023902a
--- /dev/null
+++ b/sheep/api/pay/wallet.js
@@ -0,0 +1,68 @@
+import request from '@/sheep/request';
+
+const PayWalletApi = {
+ // 获取钱包
+ getPayWallet() {
+ return request({
+ url: '/pay/wallet/get',
+ method: 'GET',
+ custom: {
+ showLoading: false,
+ auth: true,
+ },
+ });
+ },
+ // 获得钱包流水分页
+ getWalletTransactionPage: (params) => {
+ const queryString = Object.keys(params)
+ .map((key) => encodeURIComponent(key) + '=' + params[key])
+ .join('&');
+ return request({
+ url: `/pay/wallet-transaction/page?${queryString}`,
+ method: 'GET',
+ });
+ },
+ // 获得钱包流水统计
+ getWalletTransactionSummary: (params) => {
+ const queryString = `createTime=${params.createTime[0]}&createTime=${params.createTime[1]}`;
+ return request({
+ url: `/pay/wallet-transaction/get-summary?${queryString}`,
+ // url: `/pay/wallet-transaction/get-summary`,
+ method: 'GET',
+ // params: params
+ });
+ },
+ // 获得钱包充值套餐列表
+ getWalletRechargePackageList: () => {
+ return request({
+ url: '/pay/wallet-recharge-package/list',
+ method: 'GET',
+ custom: {
+ showError: false,
+ showLoading: false,
+ },
+ });
+ },
+ // 创建钱包充值记录(发起充值)
+ createWalletRecharge: (data) => {
+ return request({
+ url: '/pay/wallet-recharge/create',
+ method: 'POST',
+ data,
+ });
+ },
+ // 获得钱包充值记录分页
+ getWalletRechargePage: (params) => {
+ return request({
+ url: '/pay/wallet-recharge/page',
+ method: 'GET',
+ params,
+ custom: {
+ showError: false,
+ showLoading: false,
+ },
+ });
+ },
+};
+
+export default PayWalletApi;
diff --git a/sheep/api/product/category.js b/sheep/api/product/category.js
new file mode 100644
index 0000000..3b6f8f0
--- /dev/null
+++ b/sheep/api/product/category.js
@@ -0,0 +1,21 @@
+import request from '@/sheep/request';
+
+const CategoryApi = {
+ // 查询分类列表
+ getCategoryList: () => {
+ return request({
+ url: '/product/category/list',
+ method: 'GET',
+ });
+ },
+ // 查询分类列表,指定编号
+ getCategoryListByIds: (ids) => {
+ return request({
+ url: '/product/category/list-by-ids',
+ method: 'GET',
+ params: { ids },
+ });
+ },
+};
+
+export default CategoryApi;
diff --git a/sheep/api/product/comment.js b/sheep/api/product/comment.js
new file mode 100644
index 0000000..2bbffd1
--- /dev/null
+++ b/sheep/api/product/comment.js
@@ -0,0 +1,22 @@
+import request from '@/sheep/request';
+
+const CommentApi = {
+ // 获得商品评价分页
+ getCommentPage: (spuId, pageNo, pageSize, type) => {
+ return request({
+ url: '/product/comment/page',
+ method: 'GET',
+ params: {
+ spuId,
+ pageNo,
+ pageSize,
+ type,
+ },
+ custom: {
+ showLoading: false,
+ showError: false,
+ },
+ });
+ },
+};
+export default CommentApi;
diff --git a/sheep/api/product/favorite.js b/sheep/api/product/favorite.js
new file mode 100644
index 0000000..134c231
--- /dev/null
+++ b/sheep/api/product/favorite.js
@@ -0,0 +1,54 @@
+import request from '@/sheep/request';
+
+const FavoriteApi = {
+ // 获得商品收藏分页
+ getFavoritePage: (data) => {
+ return request({
+ url: '/product/favorite/page',
+ method: 'GET',
+ params: data,
+ });
+ },
+ // 检查是否收藏过商品
+ isFavoriteExists: (spuId) => {
+ return request({
+ url: '/product/favorite/exits',
+ method: 'GET',
+ params: {
+ spuId,
+ },
+ });
+ },
+ // 添加商品收藏
+ createFavorite: (spuId) => {
+ return request({
+ url: '/product/favorite/create',
+ method: 'POST',
+ data: {
+ spuId,
+ },
+ custom: {
+ auth: true,
+ showSuccess: true,
+ successMsg: '收藏成功',
+ },
+ });
+ },
+ // 取消商品收藏
+ deleteFavorite: (spuId) => {
+ return request({
+ url: '/product/favorite/delete',
+ method: 'DELETE',
+ data: {
+ spuId,
+ },
+ custom: {
+ auth: true,
+ showSuccess: true,
+ successMsg: '取消成功',
+ },
+ });
+ },
+};
+
+export default FavoriteApi;
diff --git a/sheep/api/product/history.js b/sheep/api/product/history.js
new file mode 100644
index 0000000..9ed53e3
--- /dev/null
+++ b/sheep/api/product/history.js
@@ -0,0 +1,39 @@
+import request from '@/sheep/request';
+
+const SpuHistoryApi = {
+ // 删除商品浏览记录
+ deleteBrowseHistory: (spuIds) => {
+ return request({
+ url: '/product/browse-history/delete',
+ method: 'DELETE',
+ data: { spuIds },
+ custom: {
+ showSuccess: true,
+ successMsg: '删除成功',
+ },
+ });
+ },
+ // 清空商品浏览记录
+ cleanBrowseHistory: () => {
+ return request({
+ url: '/product/browse-history/clean',
+ method: 'DELETE',
+ custom: {
+ showSuccess: true,
+ successMsg: '清空成功',
+ },
+ });
+ },
+ // 获得商品浏览记录分页
+ getBrowseHistoryPage: (data) => {
+ return request({
+ url: '/product/browse-history/page',
+ method: 'GET',
+ data,
+ custom: {
+ showLoading: false
+ },
+ });
+ },
+};
+export default SpuHistoryApi;
diff --git a/sheep/api/product/spu.js b/sheep/api/product/spu.js
new file mode 100644
index 0000000..3b84c1d
--- /dev/null
+++ b/sheep/api/product/spu.js
@@ -0,0 +1,41 @@
+import request from '@/sheep/request';
+
+const SpuApi = {
+ // 获得商品 SPU 列表
+ getSpuListByIds: (ids) => {
+ return request({
+ url: '/product/spu/list-by-ids',
+ method: 'GET',
+ params: { ids },
+ custom: {
+ showLoading: false,
+ showError: false,
+ },
+ });
+ },
+ // 获得商品 SPU 分页
+ getSpuPage: (params) => {
+ return request({
+ url: '/product/spu/page',
+ method: 'GET',
+ params,
+ custom: {
+ showLoading: false,
+ showError: false,
+ },
+ });
+ },
+ // 查询商品
+ getSpuDetail: (id) => {
+ return request({
+ url: '/product/spu/get-detail',
+ method: 'GET',
+ params: { id },
+ custom: {
+ showLoading: false,
+ showError: false,
+ },
+ });
+ },
+};
+export default SpuApi;
diff --git a/sheep/api/promotion/activity.js b/sheep/api/promotion/activity.js
new file mode 100644
index 0000000..eb47ce1
--- /dev/null
+++ b/sheep/api/promotion/activity.js
@@ -0,0 +1,16 @@
+import request from '@/sheep/request';
+
+const ActivityApi = {
+ // 获得单个商品,近期参与的每个活动
+ getActivityListBySpuId: (spuId) => {
+ return request({
+ url: '/promotion/activity/list-by-spu-id',
+ method: 'GET',
+ params: {
+ spuId,
+ },
+ });
+ },
+};
+
+export default ActivityApi;
diff --git a/sheep/api/promotion/article.js b/sheep/api/promotion/article.js
new file mode 100644
index 0000000..ded5fb1
--- /dev/null
+++ b/sheep/api/promotion/article.js
@@ -0,0 +1,12 @@
+import request from '@/sheep/request';
+
+export default {
+ // 获得文章详情
+ getArticle: (id, title) => {
+ return request({
+ url: '/promotion/article/get',
+ method: 'GET',
+ params: { id, title }
+ });
+ }
+}
diff --git a/sheep/api/promotion/combination.js b/sheep/api/promotion/combination.js
new file mode 100644
index 0000000..8dfa0c2
--- /dev/null
+++ b/sheep/api/promotion/combination.js
@@ -0,0 +1,68 @@
+import request from '@/sheep/request';
+
+// 拼团 API
+const CombinationApi = {
+
+ // 获得拼团活动分页
+ getCombinationActivityPage: (params) => {
+ return request({
+ url: '/promotion/combination-activity/page',
+ method: 'GET',
+ params,
+ });
+ },
+
+ // 获得拼团活动明细
+ getCombinationActivity: (id) => {
+ return request({
+ url: '/promotion/combination-activity/get-detail',
+ method: 'GET',
+ params: {
+ id,
+ },
+ });
+ },
+
+ // 获得最近 n 条拼团记录(团长发起的)
+ getHeadCombinationRecordList: (activityId, status, count) => {
+ return request({
+ url: '/promotion/combination-record/get-head-list',
+ method: 'GET',
+ params: {
+ activityId,
+ status,
+ count,
+ },
+ });
+ },
+
+ // 获得我的拼团记录分页
+ getCombinationRecordPage: (params) => {
+ return request({
+ url: "/promotion/combination-record/page",
+ method: 'GET',
+ params
+ });
+ },
+
+ // 获得拼团记录明细
+ getCombinationRecordDetail: (id) => {
+ return request({
+ url: '/promotion/combination-record/get-detail',
+ method: 'GET',
+ params: {
+ id,
+ },
+ });
+ },
+
+ // 获得拼团记录的概要信息
+ getCombinationRecordSummary: () => {
+ return request({
+ url: '/promotion/combination-record/get-summary',
+ method: 'GET',
+ });
+ },
+};
+
+export default CombinationApi;
diff --git a/sheep/api/promotion/coupon.js b/sheep/api/promotion/coupon.js
new file mode 100644
index 0000000..c9dfa52
--- /dev/null
+++ b/sheep/api/promotion/coupon.js
@@ -0,0 +1,101 @@
+import request from '@/sheep/request';
+
+const CouponApi = {
+ // 获得优惠劵模板列表
+ getCouponTemplateListByIds: (ids) => {
+ return request({
+ url: '/promotion/coupon-template/list-by-ids',
+ method: 'GET',
+ params: { ids },
+ custom: {
+ showLoading: false, // 不展示 Loading,避免领取优惠劵时,不成功提示
+ showError: false,
+ },
+ });
+ },
+ // 获得优惠劵模版列表
+ getCouponTemplateList: (spuId, productScope, count) => {
+ return request({
+ url: '/promotion/coupon-template/list',
+ method: 'GET',
+ params: { spuId, productScope, count },
+ });
+ },
+ // 获得优惠劵模版分页
+ getCouponTemplatePage: (params) => {
+ return request({
+ url: '/promotion/coupon-template/page',
+ method: 'GET',
+ params,
+ });
+ },
+ // 获得优惠劵模版
+ getCouponTemplate: (id) => {
+ return request({
+ url: '/promotion/coupon-template/get',
+ method: 'GET',
+ params: { id },
+ });
+ },
+ // 我的优惠劵列表
+ getCouponPage: (params) => {
+ return request({
+ url: '/promotion/coupon/page',
+ method: 'GET',
+ params,
+ });
+ },
+ // 领取优惠券
+ takeCoupon: (templateId) => {
+ return request({
+ url: '/promotion/coupon/take',
+ method: 'POST',
+ data: { templateId },
+ custom: {
+ auth: true,
+ showLoading: true,
+ loadingMsg: '领取中',
+ showSuccess: true,
+ successMsg: '领取成功',
+ },
+ });
+ },
+ // 获得优惠劵
+ getCoupon: (id) => {
+ return request({
+ url: '/promotion/coupon/get',
+ method: 'GET',
+ params: { id },
+ });
+ },
+ // 获得未使用的优惠劵数量
+ getUnusedCouponCount: () => {
+ return request({
+ url: '/promotion/coupon/get-unused-count',
+ method: 'GET',
+ custom: {
+ showLoading: false,
+ auth: true,
+ },
+ });
+ },
+ // 获得匹配指定商品的优惠劵列表
+ getMatchCouponList: (price, spuIds, skuIds, categoryIds) => {
+ return request({
+ url: '/promotion/coupon/match-list',
+ method: 'GET',
+ params: {
+ price,
+ spuIds: spuIds.join(','),
+ skuIds: skuIds.join(','),
+ categoryIds: categoryIds.join(','),
+ },
+ custom: {
+ showError: false,
+ showLoading: false, // 避免影响 settlementOrder 结算的结果
+ },
+ });
+ }
+};
+
+export default CouponApi;
diff --git a/sheep/api/promotion/diy.js b/sheep/api/promotion/diy.js
new file mode 100644
index 0000000..e524f69
--- /dev/null
+++ b/sheep/api/promotion/diy.js
@@ -0,0 +1,38 @@
+import request from '@/sheep/request';
+
+const DiyApi = {
+ getUsedDiyTemplate: () => {
+ return request({
+ url: '/promotion/diy-template/used',
+ method: 'GET',
+ custom: {
+ showError: false,
+ showLoading: false,
+ },
+ });
+ },
+ getDiyTemplate: (id) => {
+ return request({
+ url: '/promotion/diy-template/get',
+ method: 'GET',
+ params: {
+ id
+ },
+ custom: {
+ showError: false,
+ showLoading: false,
+ },
+ });
+ },
+ getDiyPage: (id) => {
+ return request({
+ url: '/promotion/diy-page/get',
+ method: 'GET',
+ params: {
+ id
+ }
+ });
+ },
+};
+
+export default DiyApi;
diff --git a/sheep/api/promotion/kefu.js b/sheep/api/promotion/kefu.js
new file mode 100644
index 0000000..86481ab
--- /dev/null
+++ b/sheep/api/promotion/kefu.js
@@ -0,0 +1,31 @@
+import request from '@/sheep/request';
+
+const KeFuApi = {
+ sendKefuMessage: (data) => {
+ return request({
+ url: '/promotion/kefu-message/send',
+ method: 'POST',
+ data,
+ custom: {
+ auth: true,
+ showLoading: true,
+ loadingMsg: '发送中',
+ showSuccess: true,
+ successMsg: '发送成功',
+ },
+ });
+ },
+ getKefuMessagePage: (params) => {
+ return request({
+ url: '/promotion/kefu-message/page',
+ method: 'GET',
+ params,
+ custom: {
+ auth: true,
+ showLoading: false,
+ },
+ });
+ },
+};
+
+export default KeFuApi;
diff --git a/sheep/api/promotion/rewardActivity.js b/sheep/api/promotion/rewardActivity.js
new file mode 100644
index 0000000..5f74db7
--- /dev/null
+++ b/sheep/api/promotion/rewardActivity.js
@@ -0,0 +1,14 @@
+import request from '@/sheep/request';
+
+const RewardActivityApi = {
+ // 获得满减送活动
+ getRewardActivity: (id) => {
+ return request({
+ url: '/promotion/reward-activity/get',
+ method: 'GET',
+ params: { id },
+ });
+ }
+};
+
+export default RewardActivityApi;
\ No newline at end of file
diff --git a/sheep/api/promotion/seckill.js b/sheep/api/promotion/seckill.js
new file mode 100644
index 0000000..4d41e8b
--- /dev/null
+++ b/sheep/api/promotion/seckill.js
@@ -0,0 +1,33 @@
+import request from "@/sheep/request";
+
+const SeckillApi = {
+ // 获得秒杀时间段列表
+ getSeckillConfigList: () => {
+ return request({ url: 'promotion/seckill-config/list', method: 'GET' });
+ },
+
+ // 获得当前秒杀活动
+ getNowSeckillActivity: () => {
+ return request({ url: 'promotion/seckill-activity/get-now', method: 'GET' });
+ },
+
+ // 获得秒杀活动分页
+ getSeckillActivityPage: (params) => {
+ return request({ url: 'promotion/seckill-activity/page', method: 'GET', params });
+ },
+
+ /**
+ * 获得秒杀活动明细
+ * @param {number} id 秒杀活动编号
+ * @return {*}
+ */
+ getSeckillActivity: (id) => {
+ return request({
+ url: 'promotion/seckill-activity/get-detail',
+ method: 'GET',
+ params: { id }
+ });
+ }
+}
+
+export default SeckillApi;
diff --git a/sheep/api/system/area.js b/sheep/api/system/area.js
new file mode 100644
index 0000000..7c41eff
--- /dev/null
+++ b/sheep/api/system/area.js
@@ -0,0 +1,13 @@
+import request from '@/sheep/request';
+
+const AreaApi = {
+ // 获得地区树
+ getAreaTree: () => {
+ return request({
+ url: '/system/area/tree',
+ method: 'GET'
+ });
+ },
+};
+
+export default AreaApi;
diff --git a/sheep/api/system/dict.js b/sheep/api/system/dict.js
new file mode 100644
index 0000000..cab64f7
--- /dev/null
+++ b/sheep/api/system/dict.js
@@ -0,0 +1,16 @@
+import request from '@/sheep/request';
+
+const DictApi = {
+ // 根据字典类型查询字典数据信息
+ getDictDataListByType: (type) => {
+ return request({
+ url: `/system/dict-data/type`,
+ method: 'GET',
+ params: {
+ type,
+ },
+ });
+ },
+};
+
+export default DictApi;
diff --git a/sheep/api/trade/afterSale.js b/sheep/api/trade/afterSale.js
new file mode 100644
index 0000000..44c4dd3
--- /dev/null
+++ b/sheep/api/trade/afterSale.js
@@ -0,0 +1,63 @@
+import request from '@/sheep/request';
+
+const AfterSaleApi = {
+ // 获得售后分页
+ getAfterSalePage: (params) => {
+ return request({
+ url: `/trade/after-sale/page`,
+ method: 'GET',
+ params,
+ custom: {
+ showLoading: false,
+ },
+ });
+ },
+ // 创建售后
+ createAfterSale: (data) => {
+ return request({
+ url: `/trade/after-sale/create`,
+ method: 'POST',
+ data,
+ });
+ },
+ // 获得售后
+ getAfterSale: (id) => {
+ return request({
+ url: `/trade/after-sale/get`,
+ method: 'GET',
+ params: {
+ id,
+ },
+ });
+ },
+ // 取消售后
+ cancelAfterSale: (id) => {
+ return request({
+ url: `/trade/after-sale/cancel`,
+ method: 'DELETE',
+ params: {
+ id,
+ },
+ });
+ },
+ // 获得售后日志列表
+ getAfterSaleLogList: (afterSaleId) => {
+ return request({
+ url: `/trade/after-sale-log/list`,
+ method: 'GET',
+ params: {
+ afterSaleId,
+ },
+ });
+ },
+ // 退回货物
+ deliveryAfterSale: (data) => {
+ return request({
+ url: `/trade/after-sale/delivery`,
+ method: 'PUT',
+ data,
+ });
+ }
+};
+
+export default AfterSaleApi;
diff --git a/sheep/api/trade/brokerage.js b/sheep/api/trade/brokerage.js
new file mode 100644
index 0000000..206e7ec
--- /dev/null
+++ b/sheep/api/trade/brokerage.js
@@ -0,0 +1,93 @@
+import request from '@/sheep/request';
+
+const BrokerageApi = {
+ // 绑定分销用户
+ bindBrokerageUser: (data)=>{
+ return request({
+ url: '/trade/brokerage-user/bind',
+ method: 'PUT',
+ data
+ });
+ },
+ // 获得个人分销信息
+ getBrokerageUser: () => {
+ return request({
+ url: '/trade/brokerage-user/get',
+ method: 'GET'
+ });
+ },
+ // 获得个人分销统计
+ getBrokerageUserSummary: () => {
+ return request({
+ url: '/trade/brokerage-user/get-summary',
+ method: 'GET',
+ });
+ },
+ // 获得分销记录分页
+ getBrokerageRecordPage: params => {
+ if (params.status === undefined) {
+ delete params.status
+ }
+ const queryString = Object.keys(params)
+ .map(key => encodeURIComponent(key) + '=' + params[key])
+ .join('&');
+ return request({
+ url: `/trade/brokerage-record/page?${queryString}`,
+ method: 'GET',
+ });
+ },
+ // 创建分销提现
+ createBrokerageWithdraw: data => {
+ return request({
+ url: '/trade/brokerage-withdraw/create',
+ method: 'POST',
+ data,
+ });
+ },
+ // 获得商品的分销金额
+ getProductBrokeragePrice: spuId => {
+ return request({
+ url: '/trade/brokerage-record/get-product-brokerage-price',
+ method: 'GET',
+ params: { spuId }
+ });
+ },
+ // 获得分销用户排行(基于佣金)
+ getRankByPrice: params => {
+ const queryString = `times=${params.times[0]}×=${params.times[1]}`;
+ return request({
+ url: `/trade/brokerage-user/get-rank-by-price?${queryString}`,
+ method: 'GET',
+ });
+ },
+ // 获得分销用户排行分页(基于佣金)
+ getBrokerageUserChildSummaryPageByPrice: params => {
+ const queryString = Object.keys(params)
+ .map(key => encodeURIComponent(key) + '=' + params[key])
+ .join('&');
+ return request({
+ url: `/trade/brokerage-user/rank-page-by-price?${queryString}`,
+ method: 'GET',
+ });
+ },
+ // 获得分销用户排行分页(基于用户量)
+ getBrokerageUserRankPageByUserCount: params => {
+ const queryString = Object.keys(params)
+ .map(key => encodeURIComponent(key) + '=' + params[key])
+ .join('&');
+ return request({
+ url: `/trade/brokerage-user/rank-page-by-user-count?${queryString}`,
+ method: 'GET',
+ });
+ },
+ // 获得下级分销统计分页
+ getBrokerageUserChildSummaryPage: params => {
+ return request({
+ url: '/trade/brokerage-user/child-summary-page',
+ method: 'GET',
+ params,
+ })
+ }
+}
+
+export default BrokerageApi
diff --git a/sheep/api/trade/cart.js b/sheep/api/trade/cart.js
new file mode 100644
index 0000000..63cea18
--- /dev/null
+++ b/sheep/api/trade/cart.js
@@ -0,0 +1,50 @@
+import request from '@/sheep/request';
+
+const CartApi = {
+ addCart: (data) => {
+ return request({
+ url: '/trade/cart/add',
+ method: 'POST',
+ data: data,
+ custom: {
+ showSuccess: true,
+ successMsg: '已添加到购物车~',
+ }
+ });
+ },
+ updateCartCount: (data) => {
+ return request({
+ url: '/trade/cart/update-count',
+ method: 'PUT',
+ data: data
+ });
+ },
+ updateCartSelected: (data) => {
+ return request({
+ url: '/trade/cart/update-selected',
+ method: 'PUT',
+ data: data
+ });
+ },
+ deleteCart: (ids) => {
+ return request({
+ url: '/trade/cart/delete',
+ method: 'DELETE',
+ params: {
+ ids
+ }
+ });
+ },
+ getCartList: () => {
+ return request({
+ url: '/trade/cart/list',
+ method: 'GET',
+ custom: {
+ showLoading: false,
+ auth: true,
+ },
+ });
+ },
+};
+
+export default CartApi;
\ No newline at end of file
diff --git a/sheep/api/trade/config.js b/sheep/api/trade/config.js
new file mode 100644
index 0000000..92dccae
--- /dev/null
+++ b/sheep/api/trade/config.js
@@ -0,0 +1,20 @@
+import request from '@/sheep/request';
+
+const TradeConfigApi = {
+ // 获得交易配置
+ getTradeConfig: (userId) => {
+ return request({
+ url: `/trade/config/get`,
+ params: {
+ userId,
+ },
+ custom: {
+ auth: false,
+ showLoading: false,
+ },
+ method: 'GET',
+ });
+ },
+};
+
+export default TradeConfigApi;
diff --git a/sheep/api/trade/delivery.js b/sheep/api/trade/delivery.js
new file mode 100644
index 0000000..a6551da
--- /dev/null
+++ b/sheep/api/trade/delivery.js
@@ -0,0 +1,31 @@
+import request from '@/sheep/request';
+
+const DeliveryApi = {
+ // 获得快递公司列表
+ getDeliveryExpressList: () => {
+ return request({
+ url: `/trade/delivery/express/list`,
+ method: 'get',
+ });
+ },
+ // 获得自提门店列表
+ getDeliveryPickUpStoreList: (params) => {
+ return request({
+ url: `/trade/delivery/pick-up-store/list`,
+ method: 'GET',
+ params,
+ });
+ },
+ // 获得自提门店
+ getDeliveryPickUpStore: (id) => {
+ return request({
+ url: `/trade/delivery/pick-up-store/get`,
+ method: 'GET',
+ params: {
+ id,
+ },
+ });
+ },
+};
+
+export default DeliveryApi;
diff --git a/sheep/api/trade/order.js b/sheep/api/trade/order.js
new file mode 100644
index 0000000..77118ba
--- /dev/null
+++ b/sheep/api/trade/order.js
@@ -0,0 +1,247 @@
+import request from '@/sheep/request';
+import { isEmpty } from '@/sheep/helper/utils';
+
+const OrderApi = {
+ // 计算订单信息
+ settlementOrder: (data) => {
+ const data2 = {
+ ...data,
+ };
+ // 移除多余字段
+ if (!(data.couponId > 0)) {
+ delete data2.couponId;
+ }
+ if (!(data.addressId > 0)) {
+ delete data2.addressId;
+ }
+ if (!(data.pickUpStoreId > 0)) {
+ delete data2.pickUpStoreId;
+ }
+ if (isEmpty(data.receiverName)) {
+ delete data2.receiverName;
+ }
+ if (isEmpty(data.receiverMobile)) {
+ delete data2.receiverMobile;
+ }
+ if (!(data.combinationActivityId > 0)) {
+ delete data2.combinationActivityId;
+ }
+ if (!(data.combinationHeadId > 0)) {
+ delete data2.combinationHeadId;
+ }
+ if (!(data.seckillActivityId > 0)) {
+ delete data2.seckillActivityId;
+ }
+ // 解决 SpringMVC 接受 List- 参数的问题
+ delete data2.items;
+ for (let i = 0; i < data.items.length; i++) {
+ data2[encodeURIComponent('items[' + i + '' + '].skuId')] = data.items[i].skuId + '';
+ data2[encodeURIComponent('items[' + i + '' + '].count')] = data.items[i].count + '';
+ if (data.items[i].cartId) {
+ data2[encodeURIComponent('items[' + i + '' + '].cartId')] = data.items[i].cartId + '';
+ }
+ }
+ const queryString = Object.keys(data2)
+ .map((key) => key + '=' + data2[key])
+ .join('&');
+ return request({
+ url: `/trade/order/settlement?${queryString}`,
+ method: 'GET',
+ custom: {
+ showError: true,
+ showLoading: true,
+ },
+ });
+ },
+ clerkOrder: (data) => {
+ const data2 = {
+ ...data,
+ };
+ // 移除多余字段
+ if (!(data.couponId > 0)) {
+ delete data2.couponId;
+ }
+ if (!(data.addressId > 0)) {
+ delete data2.addressId;
+ }
+ if (!(data.pickUpStoreId > 0)) {
+ delete data2.pickUpStoreId;
+ }
+ if (isEmpty(data.receiverName)) {
+ delete data2.receiverName;
+ }
+ if (isEmpty(data.receiverMobile)) {
+ delete data2.receiverMobile;
+ }
+ if (!(data.combinationActivityId > 0)) {
+ delete data2.combinationActivityId;
+ }
+ if (!(data.combinationHeadId > 0)) {
+ delete data2.combinationHeadId;
+ }
+ if (!(data.seckillActivityId > 0)) {
+ delete data2.seckillActivityId;
+ }
+ // 解决 SpringMVC 接受 List
- 参数的问题
+ delete data2.items;
+ for (let i = 0; i < data.items.length; i++) {
+ data2[encodeURIComponent('items[' + i + '' + '].skuId')] = data.items[i].skuId + '';
+ data2[encodeURIComponent('items[' + i + '' + '].count')] = data.items[i].count + '';
+ if (data.items[i].cartId) {
+ data2[encodeURIComponent('items[' + i + '' + '].cartId')] = data.items[i].cartId + '';
+ }
+ }
+ const queryString = Object.keys(data2)
+ .map((key) => key + '=' + data2[key])
+ .join('&');
+ return request({
+ url: `/trade/order/clerkOrder?${queryString}`,
+ method: 'GET',
+ custom: {
+ showError: true,
+ showLoading: true,
+ },
+ });
+ },
+ // 创建订单
+ createOrder: (data) => {
+ return request({
+ url: `/trade/order/create`,
+ method: 'POST',
+ data,
+ });
+ },
+ // 创建陪玩订单
+ createWorkerOrder: (data) => {
+ return request({
+ url: `/trade/order/createWorkerOrder`,
+ method: 'POST',
+ data,
+ });
+ },
+ // 获得订单
+ getOrder: (id) => {
+ return request({
+ url: `/trade/order/get-detail`,
+ method: 'GET',
+ params: {
+ id,
+ },
+ custom: {
+ showLoading: false,
+ },
+ });
+ },
+ // 订单列表
+ getOrderPage: (params) => {
+ return request({
+ url: '/trade/order/page',
+ method: 'GET',
+ params,
+ custom: {
+ auth: true,
+ showLoading: false,
+ },
+ });
+ },
+ // 订单列表
+ getWorkerOrderPage: (params) => {
+ return request({
+ url: '/trade/order/worker/page',
+ method: 'GET',
+ params,
+ custom: {
+ auth: true,
+ showLoading: false,
+ },
+ });
+ },
+ // 订单列表
+ getBlindOrderPage: (params) => {
+ return request({
+ url: '/trade/order/blind/page',
+ method: 'GET',
+ params,
+ custom: {
+ auth: true,
+ showLoading: false,
+ },
+ });
+ },
+ // 确认收货
+ receiveOrder: (id) => {
+ return request({
+ url: `/trade/order/receive`,
+ method: 'PUT',
+ params: {
+ id,
+ },
+ });
+ },
+ // 确认接单
+ deliveryOrder: (id) => {
+ return request({
+ url: `/trade/order/delivery`,
+ method: 'PUT',
+ data: {
+ id: id,
+ logisticsId: 0
+ },
+ });
+ },
+ // 取消订单
+ cancelOrder: (id) => {
+ return request({
+ url: `/trade/order/cancel`,
+ method: 'DELETE',
+ params: {
+ id,
+ },
+ });
+ },
+ // 删除订单
+ deleteOrder: (id) => {
+ return request({
+ url: `/trade/order/delete`,
+ method: 'DELETE',
+ params: {
+ id,
+ },
+ });
+ },
+ // 获得交易订单的物流轨迹
+ getOrderExpressTrackList: (id) => {
+ return request({
+ url: `/trade/order/get-express-track-list`,
+ method: 'GET',
+ params: {
+ id,
+ },
+ });
+ },
+ // 获得交易订单数量
+ getOrderCount: () => {
+ return request({
+ url: '/trade/order/get-count',
+ method: 'GET',
+ custom: {
+ showLoading: false,
+ auth: true,
+ },
+ });
+ },
+ // 创建单个评论
+ createOrderItemComment: (data) => {
+ return request({
+ url: `/trade/order/item/create-comment`,
+ method: 'POST',
+ data,
+ custom: {
+ showSuccess: true,
+ successMsg: '评价成功'
+ },
+ });
+ },
+};
+
+export default OrderApi;
diff --git a/sheep/api/worker/clerk.js b/sheep/api/worker/clerk.js
new file mode 100644
index 0000000..cf2c7be
--- /dev/null
+++ b/sheep/api/worker/clerk.js
@@ -0,0 +1,195 @@
+import request from '@/sheep/request';
+
+const ClerkApi = {
+ // 创建店员申请
+ createClerkApply: (data) => {
+ return request({
+ url: '/worker/clerk-apply/create',
+ method: 'POST',
+ data,
+ custom: {
+ showSuccess: true,
+ successMsg: '提交成功'
+ },
+ });
+ },
+ // 更新店员申请
+ updateClerkApply: (data) => {
+ return request({
+ url: '/worker/clerk-apply/update',
+ method: 'PUT',
+ data,
+ custom: {
+ showSuccess: true,
+ successMsg: '提交成功'
+ },
+ });
+ },
+ // 更新店员在线状态
+ updateOnlineStatus: (data) => {
+ return request({
+ url: '/worker/clerk-apply/updateOnlineStatus',
+ method: 'PUT',
+ data,
+ custom: {
+ showSuccess: true,
+ successMsg: '提交成功'
+ },
+ });
+ },
+ // 获得店员申请
+ getClerkApply: (id) => {
+ return request({
+ url: '/worker/clerk-apply/get',
+ method: 'GET',
+ params: { id },
+ custom: {
+ auth: true,
+ showLoading: false,
+ },
+ });
+ },
+ // 获得店员等级
+ getClerkLevel: (id) => {
+ return request({
+ url: '/worker/clerk-apply/getClerkLevel',
+ method: 'GET',
+ params: { id },
+ custom: {
+ auth: true,
+ showLoading: false,
+ },
+ });
+ },
+ // 获得店员申请
+ getClerk: (params) => {
+ return request({
+ url: '/worker/clerk/get',
+ method: 'GET',
+ params,
+ custom: {
+ auth: false,
+ showLoading: false,
+ },
+ });
+ },
+ // 获得店员盲盒
+ getClerkBlind: () => {
+ return request({
+ url: '/worker/clerk/getClerkBlind',
+ method: 'GET',
+ custom: {
+ auth: false,
+ showLoading: false,
+ },
+ });
+ },
+ // 获得商品分类列表
+ getCategoryListByParentId: (parentId) => {
+ return request({
+ url: '/worker/category/getCategoryListByParentId',
+ method: 'GET',
+ params: { parentId },
+ custom: {
+ auth: false,
+ showLoading: false,
+ },
+ });
+ },
+
+ // 保存技能管理
+ saveGoodsList: (data) => {
+ return request({
+ url: '/worker/clerk-apply/save',
+ method: 'PUT',
+ data,
+ custom: {
+ showSuccess: true,
+ successMsg: '保存成功'
+ },
+ });
+ },
+ // 获得店员列表
+ getClerkPage: (params) => {
+ return request({
+ url: '/worker/clerk/page',
+ method: 'GET',
+ params,
+ custom: {
+ auth: false,
+ showLoading: false,
+ },
+ });
+ },
+ // 获得店员关注列表
+ getClerkFansPage: (params) => {
+ return request({
+ url: '/worker/clerk-fans/page',
+ method: 'GET',
+ params,
+ custom: {
+ auth: false,
+ showLoading: false,
+ },
+ });
+ },
+ // 获得首页信息
+ getHomeData: () => {
+ return request({
+ url: '/worker/clerk/getHomeData',
+ method: 'GET',
+ custom: {
+ auth: false,
+ showLoading: false,
+ },
+ });
+ },
+ // 获得首页信息
+ getClerkList: () => {
+ return request({
+ url: '/worker/clerk/getClerkList',
+ method: 'GET',
+ custom: {
+ auth: true,
+ showLoading: false,
+ },
+ });
+ },
+ // 获得榜单信息
+ getWeekTopList: () => {
+ return request({
+ url: '/worker/clerk/getWeekTopList',
+ method: 'GET',
+ custom: {
+ auth: false,
+ showLoading: false,
+ },
+ });
+ },
+ // 获得店员申请列表
+ getClerkApplyPage: (params) => {
+ return request({
+ url: '/worker/clerk-apply/page',
+ method: 'GET',
+ params,
+ custom: {
+ auth: true,
+ showLoading: false,
+ },
+ });
+ },
+ // 获得商品列表
+ getGoodsList: (id) => {
+ return request({
+ url: '/worker/clerk-apply/list',
+ method: 'GET',
+ params: { id },
+ custom: {
+ auth: true,
+ showLoading: false,
+ },
+ });
+ },
+};
+
+export default ClerkApi;
diff --git a/sheep/api/worker/reward.js b/sheep/api/worker/reward.js
new file mode 100644
index 0000000..d269732
--- /dev/null
+++ b/sheep/api/worker/reward.js
@@ -0,0 +1,60 @@
+import request from '@/sheep/request';
+
+const RewardApi = {
+ // 获得礼物列表
+ getGiftList: () => {
+ return request({
+ url: '/worker/gift/getList',
+ method: 'GET',
+ custom: {
+ auth: true,
+ showLoading: false,
+ },
+ });
+ },
+ // 获得打赏礼物列表
+ getRewardGiftList: (params) => {
+ return request({
+ url: '/worker/reward/getGiftList',
+ method: 'GET',
+ params: params,
+ custom: {
+ auth: false,
+ showLoading: false,
+ },
+ });
+ },
+ // 获得礼物列表
+ getTopList: () => {
+ return request({
+ url: '/worker/reward/getTopList',
+ method: 'GET',
+ custom: {
+ auth: false,
+ showLoading: false,
+ },
+ });
+ },
+ // 创建打赏订单
+ createRewardOrder: (data) => {
+ return request({
+ url: `/worker/reward/createOrder`,
+ method: 'POST',
+ data,
+ });
+ },
+ // 获得打赏分页
+ getRewardPage: (params) => {
+ return request({
+ url: '/worker/reward/page',
+ method: 'GET',
+ params,
+ custom: {
+ auth: true,
+ showLoading: false,
+ },
+ });
+ },
+};
+
+export default RewardApi;
diff --git a/sheep/api/worker/trend.js b/sheep/api/worker/trend.js
new file mode 100644
index 0000000..3e33e73
--- /dev/null
+++ b/sheep/api/worker/trend.js
@@ -0,0 +1,100 @@
+import request from '@/sheep/request';
+
+const TrendApi = {
+ // 发布动态
+ createTrend: (data) => {
+ return request({
+ url: '/worker/trend/create',
+ method: 'POST',
+ data,
+ custom: {
+ auth: true,
+ showSuccess: true,
+ successMsg: '发布成功,请等待管理员审核'
+ },
+ });
+ },
+ // 动态点赞
+ createTrendLike: (data) => {
+ return request({
+ url: '/worker/trend-like/create',
+ method: 'POST',
+ data,
+ custom: {
+ auth: true,
+ showSuccess: false,
+ showLoading: false,
+ successMsg: '点赞成功'
+ },
+ });
+ },
+ // 删除动态
+ deleteTrendLike: (id) => {
+ return request({
+ url: '/worker/trend/delete',
+ method: 'DELETE',
+ params: {
+ id,
+ },
+ custom: {
+ auth: true,
+ showSuccess: true,
+ showLoading: false,
+ successMsg: '删除成功'
+ },
+ });
+ },
+ // 获得动态详情
+ getTrend: (id) => {
+ return request({
+ url: '/worker/trend/get',
+ method: 'GET',
+ params: { id },
+ custom: {
+ auth: false,
+ showLoading: false,
+ },
+ });
+ },
+ // 店员关注
+ createClerkFans: (data) => {
+ return request({
+ url: '/worker/clerk-fans/create',
+ method: 'POST',
+ data,
+ custom: {
+ auth: true,
+ showSuccess: false,
+ showLoading: false,
+ successMsg: '关注成功'
+ },
+ });
+ },
+ // 获得动态分页
+ getTrendPage: (params) => {
+ return request({
+ url: '/worker/trend/page',
+ method: 'GET',
+ params,
+ custom: {
+ auth: false,
+ showLoading: false,
+ },
+ });
+ },
+ // 获得动态分页
+ getMyTrendPage: (params) => {
+ return request({
+ url: '/worker/trend/myPage',
+ method: 'GET',
+ params,
+ custom: {
+ auth: true,
+ showLoading: false,
+ },
+ });
+ },
+
+};
+
+export default TrendApi;
diff --git a/sheep/components/s-activity-pop/s-activity-pop.vue b/sheep/components/s-activity-pop/s-activity-pop.vue
new file mode 100644
index 0000000..432dc45
--- /dev/null
+++ b/sheep/components/s-activity-pop/s-activity-pop.vue
@@ -0,0 +1,105 @@
+
+
+
+
+ 营销活动
+
+
+
+ 满减
+
+
+ {{ formatRewardActivityRule(state.activityMap[item.id], rule) }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-address-item/s-address-item.vue b/sheep/components/s-address-item/s-address-item.vue
new file mode 100644
index 0000000..45e361f
--- /dev/null
+++ b/sheep/components/s-address-item/s-address-item.vue
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+ {{ props.item.areaName }}
+
+
+ {{ props.item.detailAddress }}
+
+ {{ props.item.name }} {{ props.item.mobile }}
+
+
+ 请选择收货地址
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-auth-modal/components/account-login.vue b/sheep/components/s-auth-modal/components/account-login.vue
new file mode 100644
index 0000000..579614c
--- /dev/null
+++ b/sheep/components/s-auth-modal/components/account-login.vue
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+ 短信登录
+
+ 账号登录
+
+ 如果未设置过密码,请点击忘记密码
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-auth-modal/components/change-mobile.vue b/sheep/components/s-auth-modal/components/change-mobile.vue
new file mode 100644
index 0000000..f4dd5f1
--- /dev/null
+++ b/sheep/components/s-auth-modal/components/change-mobile.vue
@@ -0,0 +1,127 @@
+
+
+
+
+
+
+ {{ userInfo.mobile ? '更换手机号' : '绑定手机号' }}
+
+ 为了您的账号安全,请使用本人手机号码
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-auth-modal/components/change-password.vue b/sheep/components/s-auth-modal/components/change-password.vue
new file mode 100644
index 0000000..b02ea02
--- /dev/null
+++ b/sheep/components/s-auth-modal/components/change-password.vue
@@ -0,0 +1,106 @@
+
+
+
+
+
+ 修改密码
+ 如密码丢失或未设置,请点击忘记密码重新设置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-auth-modal/components/chat-authorization.vue b/sheep/components/s-auth-modal/components/chat-authorization.vue
new file mode 100644
index 0000000..b2fc774
--- /dev/null
+++ b/sheep/components/s-auth-modal/components/chat-authorization.vue
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+ 完善资料
+
+ 完善您的交友名片、个人相册
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-auth-modal/components/formImage.vue b/sheep/components/s-auth-modal/components/formImage.vue
new file mode 100644
index 0000000..a6045f6
--- /dev/null
+++ b/sheep/components/s-auth-modal/components/formImage.vue
@@ -0,0 +1,73 @@
+
+
+
+ 上传相册
+ {{imgList.length}}/{{number}}
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sheep/components/s-auth-modal/components/formQrcode.vue b/sheep/components/s-auth-modal/components/formQrcode.vue
new file mode 100644
index 0000000..5f2ded4
--- /dev/null
+++ b/sheep/components/s-auth-modal/components/formQrcode.vue
@@ -0,0 +1,88 @@
+
+
+ 交换名片
+
+ {{item.name}}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sheep/components/s-auth-modal/components/formSex.vue b/sheep/components/s-auth-modal/components/formSex.vue
new file mode 100644
index 0000000..34b84e0
--- /dev/null
+++ b/sheep/components/s-auth-modal/components/formSex.vue
@@ -0,0 +1,88 @@
+
+
+ 性别
+
+ {{item.name}}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sheep/components/s-auth-modal/components/h5-authorization.vue b/sheep/components/s-auth-modal/components/h5-authorization.vue
new file mode 100644
index 0000000..2a907f3
--- /dev/null
+++ b/sheep/components/s-auth-modal/components/h5-authorization.vue
@@ -0,0 +1,194 @@
+
+
+
+
+
+
+ 授权信息
+
+ 完善您的头像、昵称、性别、年龄
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-auth-modal/components/mp-authorization.vue b/sheep/components/s-auth-modal/components/mp-authorization.vue
new file mode 100644
index 0000000..65efd16
--- /dev/null
+++ b/sheep/components/s-auth-modal/components/mp-authorization.vue
@@ -0,0 +1,203 @@
+
+
+
+
+
+
+ 授权信息
+
+ 完善您的头像、昵称、手机号
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-auth-modal/components/reset-password.vue b/sheep/components/s-auth-modal/components/reset-password.vue
new file mode 100644
index 0000000..bc1be8b
--- /dev/null
+++ b/sheep/components/s-auth-modal/components/reset-password.vue
@@ -0,0 +1,119 @@
+
+
+
+
+
+ 重置密码
+ 为了您的账号安全,设置密码前请先进行安全验证
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-auth-modal/components/sms-login.vue b/sheep/components/s-auth-modal/components/sms-login.vue
new file mode 100644
index 0000000..0651b78
--- /dev/null
+++ b/sheep/components/s-auth-modal/components/sms-login.vue
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+ 短信登录
+
+ 账号登录
+
+
+ 未注册的手机号,验证后自动注册账号
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-auth-modal/index.scss b/sheep/components/s-auth-modal/index.scss
new file mode 100644
index 0000000..c4424e7
--- /dev/null
+++ b/sheep/components/s-auth-modal/index.scss
@@ -0,0 +1,151 @@
+@keyframes title-animation {
+ 0% {
+ font-size: 32rpx;
+ }
+ 100% {
+ font-size: 36rpx;
+ }
+}
+
+.login-wrap {
+ padding: 50rpx 34rpx;
+ min-height: 500rpx;
+ background-color: #fff;
+ border-radius: 20rpx 20rpx 0 0;
+}
+
+.head-box {
+ .head-title {
+ min-width: 160rpx;
+ font-size: 36rpx;
+ font-weight: bold;
+ color: #333333;
+ line-height: 36rpx;
+ }
+ .head-title-active {
+ width: 160rpx;
+ font-size: 32rpx;
+ font-weight: 600;
+ color: #999;
+ line-height: 36rpx;
+ }
+ .head-title-animation {
+ animation-name: title-animation;
+ animation-duration: 0.1s;
+ animation-timing-function: ease-out;
+ animation-fill-mode: forwards;
+ }
+ .head-title-line {
+ position: relative;
+ &::before {
+ content: '';
+ width: 1rpx;
+ height: 34rpx;
+ background-color: #e4e7ed;
+ position: absolute;
+ left: -30rpx;
+ top: 50%;
+ transform: translateY(-50%);
+ }
+ }
+ .head-subtitle {
+ font-size: 26rpx;
+ font-weight: 400;
+ color: #afb6c0;
+ text-align: left;
+ display: flex;
+ }
+}
+
+// .code-btn[disabled] {
+// background-color: #fff;
+// }
+.code-btn-start {
+ width: 160rpx;
+ height: 56rpx;
+ line-height: normal;
+ border: 2rpx solid var(--ui-BG-Main);
+ border-radius: 28rpx;
+ font-size: 26rpx;
+ font-weight: 400;
+ color: var(--ui-BG-Main);
+ opacity: 1;
+}
+
+.forgot-btn {
+ width: 160rpx;
+ line-height: 56rpx;
+ font-size: 30rpx;
+ font-weight: 500;
+ color: #999;
+}
+
+.login-btn-start {
+ width: 158rpx;
+ height: 56rpx;
+ line-height: normal;
+ background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
+ border-radius: 28rpx;
+ font-size: 26rpx;
+ font-weight: 500;
+ color: #fff;
+}
+
+.type-btn {
+ padding: 20rpx;
+ margin: 40rpx auto;
+ width: 200rpx;
+ font-size: 30rpx;
+ font-weight: 500;
+ color: #999999;
+}
+
+.auto-login-box {
+ width: 100%;
+ .auto-login-btn {
+ width: 68rpx;
+ height: 68rpx;
+ border-radius: 50%;
+ margin: 0 30rpx;
+ }
+ .auto-login-img {
+ width: 68rpx;
+ height: 68rpx;
+ border-radius: 50%;
+ }
+}
+
+.agreement-box {
+ margin: 80rpx auto 0;
+ .protocol-check {
+ transform: scale(0.7);
+ }
+ .agreement-text {
+ font-size: 26rpx;
+ font-weight: 500;
+ color: #999999;
+ .tcp-text {
+ color: var(--ui-BG-Main);
+ }
+ }
+}
+
+// 修改密码
+.editPwd-btn-box {
+ .save-btn {
+ width: 690rpx;
+ line-height: 70rpx;
+ background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
+ border-radius: 35rpx;
+ font-size: 28rpx;
+ font-weight: 500;
+ color: #ffffff;
+ }
+ .forgot-btn {
+ width: 690rpx;
+ line-height: 70rpx;
+ font-size: 28rpx;
+ font-weight: 500;
+ color: #999999;
+ }
+}
diff --git a/sheep/components/s-auth-modal/s-auth-modal.vue b/sheep/components/s-auth-modal/s-auth-modal.vue
new file mode 100644
index 0000000..0d591a9
--- /dev/null
+++ b/sheep/components/s-auth-modal/s-auth-modal.vue
@@ -0,0 +1,256 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-block-item/s-block-item.vue b/sheep/components/s-block-item/s-block-item.vue
new file mode 100644
index 0000000..5e65b36
--- /dev/null
+++ b/sheep/components/s-block-item/s-block-item.vue
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-block/s-block.vue b/sheep/components/s-block/s-block.vue
new file mode 100644
index 0000000..152b8a6
--- /dev/null
+++ b/sheep/components/s-block/s-block.vue
@@ -0,0 +1,54 @@
+
+
+
+
+
+
diff --git a/sheep/components/s-count-down/s-count-down.vue b/sheep/components/s-count-down/s-count-down.vue
new file mode 100644
index 0000000..98b3a1f
--- /dev/null
+++ b/sheep/components/s-count-down/s-count-down.vue
@@ -0,0 +1,173 @@
+
+
+ {{ tipText }}
+ {{ day }}{{bgColor.isDay?'天':''}}
+ {{ dayText }}
+ {{ hour }}
+ {{ hourText }}
+ {{ minute }}
+ {{ minuteText }}
+ {{ second }}
+ {{ secondText }}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sheep/components/s-coupon-block/s-coupon-block.vue b/sheep/components/s-coupon-block/s-coupon-block.vue
new file mode 100644
index 0000000..89a0f0e
--- /dev/null
+++ b/sheep/components/s-coupon-block/s-coupon-block.vue
@@ -0,0 +1,176 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sheep/components/s-coupon-card/s-coupon-card.vue b/sheep/components/s-coupon-card/s-coupon-card.vue
new file mode 100644
index 0000000..dac69e3
--- /dev/null
+++ b/sheep/components/s-coupon-card/s-coupon-card.vue
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sheep/components/s-coupon-get/s-coupon-get.vue b/sheep/components/s-coupon-get/s-coupon-get.vue
new file mode 100644
index 0000000..6df6b55
--- /dev/null
+++ b/sheep/components/s-coupon-get/s-coupon-get.vue
@@ -0,0 +1,109 @@
+
+
+
+
+ 优惠券
+
+ 可使用优惠券
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-coupon-list/s-coupon-list.vue b/sheep/components/s-coupon-list/s-coupon-list.vue
new file mode 100644
index 0000000..411a4c0
--- /dev/null
+++ b/sheep/components/s-coupon-list/s-coupon-list.vue
@@ -0,0 +1,205 @@
+
+
+
+
+ {{ data.discountType === 1 ? '满减券' : '折扣券' }}
+
+
+
+
+ {{ data.name }}
+
+
+
+ ¥
+
+ {{
+ data.discountType === 1
+ ? fen2yuan(data.discountPrice)
+ : data.discountPercent / 10.0
+ }}
+
+ 折
+
+
+
+
+
+ 有效期:领取后 {{ data.fixedEndTerm }} 天内可用
+
+
+ 有效期: {{ sheep.$helper.timeFormat(data.validStartTime, 'yyyy-mm-dd') }} 至
+ {{ sheep.$helper.timeFormat(data.validEndTime, 'yyyy-mm-dd') }}
+
+
+ 满 {{ fen2yuan(data.usePrice) }} 可用
+
+
+
+
+
+
+
+
+ {{ data.description }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sheep/components/s-coupon-select/s-coupon-select.vue b/sheep/components/s-coupon-select/s-coupon-select.vue
new file mode 100644
index 0000000..3572e1b
--- /dev/null
+++ b/sheep/components/s-coupon-select/s-coupon-select.vue
@@ -0,0 +1,140 @@
+
+
+
+
+ 优惠券
+
+
+
+
+
+
+
+ 可用原因:
+ {{ item.description || '已达到使用门槛' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-custom-navbar/components/navbar-item.vue b/sheep/components/s-custom-navbar/components/navbar-item.vue
new file mode 100644
index 0000000..fce7ce7
--- /dev/null
+++ b/sheep/components/s-custom-navbar/components/navbar-item.vue
@@ -0,0 +1,66 @@
+
+
+
+
+
+ {{ data.text }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-custom-navbar/components/navbar.vue b/sheep/components/s-custom-navbar/components/navbar.vue
new file mode 100644
index 0000000..36050ec
--- /dev/null
+++ b/sheep/components/s-custom-navbar/components/navbar.vue
@@ -0,0 +1,314 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-custom-navbar/s-custom-navbar.vue b/sheep/components/s-custom-navbar/s-custom-navbar.vue
new file mode 100644
index 0000000..aabc215
--- /dev/null
+++ b/sheep/components/s-custom-navbar/s-custom-navbar.vue
@@ -0,0 +1,207 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-discount-list/s-discount-list.vue b/sheep/components/s-discount-list/s-discount-list.vue
new file mode 100644
index 0000000..22fbd43
--- /dev/null
+++ b/sheep/components/s-discount-list/s-discount-list.vue
@@ -0,0 +1,114 @@
+
+
+
+ 活动优惠
+
+
+
+ 共{{ item.goods_ids.length }}件,
+
+ 满{{ item.discount_rule.full }}打{{ item.discount_rule.discount }}折,已减
+
+ 满赠
+
+ 满{{ item.discount_rule.full }}减{{ item.discount_rule.discount }},已减
+
+ ¥{{ item.promo_discount_money || '0.00' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-empty/s-empty.vue b/sheep/components/s-empty/s-empty.vue
new file mode 100644
index 0000000..16e40ed
--- /dev/null
+++ b/sheep/components/s-empty/s-empty.vue
@@ -0,0 +1,93 @@
+
+
+
+
+ {{ text }}
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-float-menu/s-float-menu.vue b/sheep/components/s-float-menu/s-float-menu.vue
new file mode 100644
index 0000000..b53db00
--- /dev/null
+++ b/sheep/components/s-float-menu/s-float-menu.vue
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-goods-card/s-goods-card.vue b/sheep/components/s-goods-card/s-goods-card.vue
new file mode 100644
index 0000000..59f2bf1
--- /dev/null
+++ b/sheep/components/s-goods-card/s-goods-card.vue
@@ -0,0 +1,286 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-goods-column/s-goods-column.vue b/sheep/components/s-goods-column/s-goods-column.vue
new file mode 100644
index 0000000..228c64e
--- /dev/null
+++ b/sheep/components/s-goods-column/s-goods-column.vue
@@ -0,0 +1,751 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ data.title || data.name }}
+
+
+ {{ priceUnit }}
+ {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ data.title || data.name }}
+
+
+ {{ priceUnit }}
+ {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ data.title || data.name }}
+
+
+ {{ data.subtitle || data.introduction }}
+
+
+
+
+ {{ item.title }}
+
+
+
+
+
+ {{ priceUnit }}
+ {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
+
+
+
+ {{ priceUnit }}
+ {{ fen2yuan(data.marketPrice) }}
+
+
+
+
+ {{ salesAndStock }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 秒杀
+
+ 拼团
+
+
+
+
+
+ {{ data.title || data.name }}
+
+
+ {{ data.subtitle || data.introduction }}
+
+
+
+
+
+
+ {{ item.title }}
+
+
+
+
+
+ {{ priceUnit }}
+ {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
+
+
+ {{ priceUnit }}
+ {{ fen2yuan(data.marketPrice) }}
+
+
+
+ {{ salesAndStock }}
+
+
+
+
+
+ 去购买
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ data.title || data.name }}
+
+
+ {{ data.subtitle || data.introduction }}
+
+
+
+
+
+
+ {{ item.title }}
+
+
+
+
+
+ {{ priceUnit }}
+ {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
+
+
+ {{ priceUnit }}
+ {{ fen2yuan(data.marketPrice) }}
+
+
+
+ {{ salesAndStock }}
+
+
+
+
+ 去购买
+
+
+
+
+
+
+
diff --git a/sheep/components/s-goods-item/s-goods-item.vue b/sheep/components/s-goods-item/s-goods-item.vue
new file mode 100644
index 0000000..456bb16
--- /dev/null
+++ b/sheep/components/s-goods-item/s-goods-item.vue
@@ -0,0 +1,181 @@
+
+
+
+
+
+
+
+
+
+
+ {{ title }}
+ {{ skuString }}
+
+
+
+
+
+
+ ¥{{ fen2yuan(price) }}
+
+ x {{ num }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-goods-scroll/s-goods-scroll.vue b/sheep/components/s-goods-scroll/s-goods-scroll.vue
new file mode 100644
index 0000000..175cc66
--- /dev/null
+++ b/sheep/components/s-goods-scroll/s-goods-scroll.vue
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-goods-shelves/s-goods-shelves.vue b/sheep/components/s-goods-shelves/s-goods-shelves.vue
new file mode 100644
index 0000000..e2ce60a
--- /dev/null
+++ b/sheep/components/s-goods-shelves/s-goods-shelves.vue
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-groupon-block/s-groupon-block.vue b/sheep/components/s-groupon-block/s-groupon-block.vue
new file mode 100644
index 0000000..d7e6fcf
--- /dev/null
+++ b/sheep/components/s-groupon-block/s-groupon-block.vue
@@ -0,0 +1,171 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sheep/components/s-hotzone-block/s-hotzone-block.vue b/sheep/components/s-hotzone-block/s-hotzone-block.vue
new file mode 100644
index 0000000..246d6d4
--- /dev/null
+++ b/sheep/components/s-hotzone-block/s-hotzone-block.vue
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-image-banner/s-image-banner.vue b/sheep/components/s-image-banner/s-image-banner.vue
new file mode 100644
index 0000000..478e7af
--- /dev/null
+++ b/sheep/components/s-image-banner/s-image-banner.vue
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-image-block/s-image-block.vue b/sheep/components/s-image-block/s-image-block.vue
new file mode 100644
index 0000000..c898749
--- /dev/null
+++ b/sheep/components/s-image-block/s-image-block.vue
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-image-cube/s-image-cube.vue b/sheep/components/s-image-cube/s-image-cube.vue
new file mode 100644
index 0000000..9794d8f
--- /dev/null
+++ b/sheep/components/s-image-cube/s-image-cube.vue
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-layout/s-layout.vue b/sheep/components/s-layout/s-layout.vue
new file mode 100644
index 0000000..3fc666f
--- /dev/null
+++ b/sheep/components/s-layout/s-layout.vue
@@ -0,0 +1,246 @@
+
+
+
+
+ emits('search', e)"
+ :defaultSearch="defaultSearch"
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-line-block/s-line-block.vue b/sheep/components/s-line-block/s-line-block.vue
new file mode 100644
index 0000000..c0628f9
--- /dev/null
+++ b/sheep/components/s-line-block/s-line-block.vue
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-live-block/s-live-block.vue b/sheep/components/s-live-block/s-live-block.vue
new file mode 100644
index 0000000..9d1ad03
--- /dev/null
+++ b/sheep/components/s-live-block/s-live-block.vue
@@ -0,0 +1,144 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-live-card/s-live-card.vue b/sheep/components/s-live-card/s-live-card.vue
new file mode 100644
index 0000000..9cefee0
--- /dev/null
+++ b/sheep/components/s-live-card/s-live-card.vue
@@ -0,0 +1,234 @@
+
+
+
+
+
+
+ {{ state.liveStatus[data.status].title }}
+
+
+
+
+ {{ data.name }}
+
+
+ 主播:{{ data.anchor_name }}
+
+
+
+
+
+
+
+ {{ state.liveStatus[data.status].title }}
+
+
+
+
+ {{ data.name }}
+
+
+ 主播:{{ data.anchor_name }}
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-menu-button/s-menu-button.vue b/sheep/components/s-menu-button/s-menu-button.vue
new file mode 100644
index 0000000..ef647b8
--- /dev/null
+++ b/sheep/components/s-menu-button/s-menu-button.vue
@@ -0,0 +1,343 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ state.cur + 1 }} / {{ menuList.length }}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sheep/components/s-menu-grid/s-menu-grid.vue b/sheep/components/s-menu-grid/s-menu-grid.vue
new file mode 100644
index 0000000..d05a49d
--- /dev/null
+++ b/sheep/components/s-menu-grid/s-menu-grid.vue
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+ {{ item.badge.text }}
+
+
+
+
+
+
+ {{ item.title }}
+
+
+ {{ item.subtitle }}
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sheep/components/s-menu-list/s-menu-list.vue b/sheep/components/s-menu-list/s-menu-list.vue
new file mode 100644
index 0000000..ecbb396
--- /dev/null
+++ b/sheep/components/s-menu-list/s-menu-list.vue
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-menu-tools/s-menu-tools.vue b/sheep/components/s-menu-tools/s-menu-tools.vue
new file mode 100644
index 0000000..147ead2
--- /dev/null
+++ b/sheep/components/s-menu-tools/s-menu-tools.vue
@@ -0,0 +1,118 @@
+
+
+
+
+
+ 快捷菜单
+
+
+
+
+ {{ item.title }}
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-notice-block/s-notice-block.vue b/sheep/components/s-notice-block/s-notice-block.vue
new file mode 100644
index 0000000..e7d74a0
--- /dev/null
+++ b/sheep/components/s-notice-block/s-notice-block.vue
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-order-card/s-order-card.vue b/sheep/components/s-order-card/s-order-card.vue
new file mode 100644
index 0000000..b3d851b
--- /dev/null
+++ b/sheep/components/s-order-card/s-order-card.vue
@@ -0,0 +1,132 @@
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-popup-image/s-popup-image.vue b/sheep/components/s-popup-image/s-popup-image.vue
new file mode 100644
index 0000000..b10f477
--- /dev/null
+++ b/sheep/components/s-popup-image/s-popup-image.vue
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-richtext-block/s-richtext-block.vue b/sheep/components/s-richtext-block/s-richtext-block.vue
new file mode 100644
index 0000000..4daa264
--- /dev/null
+++ b/sheep/components/s-richtext-block/s-richtext-block.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
diff --git a/sheep/components/s-search-block/s-search-block.vue b/sheep/components/s-search-block/s-search-block.vue
new file mode 100644
index 0000000..1e9c2b5
--- /dev/null
+++ b/sheep/components/s-search-block/s-search-block.vue
@@ -0,0 +1,164 @@
+
+
+
+
+
+ {{ placeholder }}
+
+
+
+
+
+ {{ item }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-seckill-block/s-seckill-block.vue b/sheep/components/s-seckill-block/s-seckill-block.vue
new file mode 100644
index 0000000..bfc61be
--- /dev/null
+++ b/sheep/components/s-seckill-block/s-seckill-block.vue
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sheep/components/s-select-groupon-sku/s-select-groupon-sku.vue b/sheep/components/s-select-groupon-sku/s-select-groupon-sku.vue
new file mode 100644
index 0000000..6259a08
--- /dev/null
+++ b/sheep/components/s-select-groupon-sku/s-select-groupon-sku.vue
@@ -0,0 +1,472 @@
+
+
+
+
+
+
+
+
+
+ {{ property.name }}
+
+
+
+
+
+ 购买数量
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-select-seckill-sku/s-select-seckill-sku.vue b/sheep/components/s-select-seckill-sku/s-select-seckill-sku.vue
new file mode 100644
index 0000000..99b28a5
--- /dev/null
+++ b/sheep/components/s-select-seckill-sku/s-select-seckill-sku.vue
@@ -0,0 +1,431 @@
+
+
+
+
+
+
+
+
+
+
+ {{ property.name }}
+
+
+
+
+
+ 购买数量
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-select-sku/s-select-sku.vue b/sheep/components/s-select-sku/s-select-sku.vue
new file mode 100644
index 0000000..b339d4a
--- /dev/null
+++ b/sheep/components/s-select-sku/s-select-sku.vue
@@ -0,0 +1,406 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ property.name }}
+
+
+
+
+
+ 购买数量
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sheep/components/s-share-modal/canvas-poster/index.vue b/sheep/components/s-share-modal/canvas-poster/index.vue
new file mode 100644
index 0000000..9e67943
--- /dev/null
+++ b/sheep/components/s-share-modal/canvas-poster/index.vue
@@ -0,0 +1,168 @@
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-share-modal/canvas-poster/poster/goods.js b/sheep/components/s-share-modal/canvas-poster/poster/goods.js
new file mode 100644
index 0000000..883e4be
--- /dev/null
+++ b/sheep/components/s-share-modal/canvas-poster/poster/goods.js
@@ -0,0 +1,125 @@
+import sheep from '@/sheep';
+import { formatImageUrlProtocol, getWxaQrcode } from './index';
+
+const goods = async (poster) => {
+ const width = poster.width;
+ const userInfo = sheep.$store('user').userInfo;
+ const wxa_qrcode = await getWxaQrcode(poster.shareInfo.path, poster.shareInfo.query);
+ return [
+ {
+ type: 'image',
+ src: formatImageUrlProtocol(sheep.$url.cdn(sheep.$store('app').platform.share.posterInfo.goods_bg)),
+ css: {
+ width,
+ position: 'fixed',
+ 'object-fit': 'contain',
+ top: '0',
+ left: '0',
+ zIndex: -1,
+ },
+ },
+ {
+ type: 'text',
+ text: userInfo.nickname,
+ css: {
+ color: '#333',
+ fontSize: 16,
+ fontFamily: 'sans-serif',
+ position: 'fixed',
+ top: width * 0.06,
+ left: width * 0.22,
+ },
+ },
+ {
+ type: 'image',
+ src: formatImageUrlProtocol(sheep.$url.cdn(userInfo.avatar)),
+ css: {
+ position: 'fixed',
+ left: width * 0.04,
+ top: width * 0.04,
+ width: width * 0.14,
+ height: width * 0.14,
+ },
+ },
+ {
+ type: 'image',
+ src: formatImageUrlProtocol(poster.shareInfo.poster.image),
+ css: {
+ position: 'fixed',
+ left: width * 0.03,
+ top: width * 0.21,
+ width: width * 0.94,
+ height: width * 0.94,
+ },
+ },
+ {
+ type: 'text',
+ text: poster.shareInfo.poster.title,
+ css: {
+ position: 'fixed',
+ left: width * 0.04,
+ top: width * 1.18,
+ color: '#333',
+ fontSize: 14,
+ lineHeight: 15,
+ maxWidth: width * 0.91,
+ },
+ },
+ {
+ type: 'text',
+ text: '¥' + poster.shareInfo.poster.price,
+ css: {
+ position: 'fixed',
+ left: width * 0.04,
+ top: width * 1.31,
+ fontSize: 20,
+ fontFamily: 'OPPOSANS',
+ color: '#333',
+ },
+ },
+ {
+ type: 'text',
+ text:
+ poster.shareInfo.poster.original_price > 0
+ ? '¥' + poster.shareInfo.poster.original_price
+ : '',
+ css: {
+ position: 'fixed',
+ left: width * 0.3,
+ top: width * 1.33,
+ color: '#999',
+ fontSize: 10,
+ fontFamily: 'OPPOSANS',
+ textDecoration: 'line-through',
+ },
+ },
+ // #ifndef MP-WEIXIN
+ {
+ type: 'qrcode',
+ text: poster.shareInfo.link,
+ css: {
+ position: 'fixed',
+ left: width * 0.75,
+ top: width * 1.3,
+ width: width * 0.2,
+ height: width * 0.2,
+ },
+ },
+ // #endif
+ // #ifdef MP-WEIXIN
+ {
+ type: 'image',
+ src: wxa_qrcode,
+ css: {
+ position: 'fixed',
+ left: width * 0.75,
+ top: width * 1.3,
+ width: width * 0.2,
+ height: width * 0.2,
+ },
+ },
+ // #endif
+ ];
+};
+
+export default goods;
diff --git a/sheep/components/s-share-modal/canvas-poster/poster/groupon.js b/sheep/components/s-share-modal/canvas-poster/poster/groupon.js
new file mode 100644
index 0000000..4b33c8c
--- /dev/null
+++ b/sheep/components/s-share-modal/canvas-poster/poster/groupon.js
@@ -0,0 +1,122 @@
+import sheep from '@/sheep';
+import { formatImageUrlProtocol, getWxaQrcode } from './index';
+
+const groupon = async (poster) => {
+ const width = poster.width;
+ const userInfo = sheep.$store('user').userInfo;
+ const wxa_qrcode = await getWxaQrcode(poster.shareInfo.path, poster.shareInfo.query);
+ return [
+ {
+ type: 'image',
+ src: formatImageUrlProtocol(sheep.$url.cdn(sheep.$store('app').platform.share.posterInfo.groupon_bg)),
+ css: {
+ width,
+ position: 'fixed',
+ 'object-fit': 'contain',
+ top: '0',
+ left: '0',
+ zIndex: -1,
+ },
+ },
+ {
+ type: 'text',
+ text: userInfo.nickname,
+ css: {
+ color: '#333',
+ fontSize: 16,
+ fontFamily: 'sans-serif',
+ position: 'fixed',
+ top: width * 0.06,
+ left: width * 0.22,
+ },
+ },
+ {
+ type: 'image',
+ src: formatImageUrlProtocol(sheep.$url.cdn(userInfo.avatar)),
+ css: {
+ position: 'fixed',
+ left: width * 0.04,
+ top: width * 0.04,
+ width: width * 0.14,
+ height: width * 0.14,
+ },
+ },
+ {
+ type: 'image',
+ src: formatImageUrlProtocol(poster.shareInfo.poster.image),
+ css: {
+ position: 'fixed',
+ left: width * 0.03,
+ top: width * 0.21,
+ width: width * 0.94,
+ height: width * 0.94,
+ borderRadius: 10,
+ },
+ },
+ {
+ type: 'text',
+ text: poster.shareInfo.poster.title,
+ css: {
+ color: '#333',
+ fontSize: 14,
+ position: 'fixed',
+ top: width * 1.18,
+ left: width * 0.04,
+ maxWidth: width * 0.91,
+ lineHeight: 5,
+ },
+ },
+ {
+ type: 'text',
+ text: '¥' + poster.shareInfo.poster.price,
+ css: {
+ color: '#ff0000',
+ fontSize: 20,
+ fontFamily: 'OPPOSANS',
+ position: 'fixed',
+ top: width * 1.3,
+ left: width * 0.04,
+ },
+ },
+ {
+ type: 'text',
+ text: '2人团',
+ css: {
+ color: '#fff',
+ fontSize: 12,
+ fontFamily: 'OPPOSANS',
+ position: 'fixed',
+ left: width * 0.84,
+ top: width * 1.3,
+ },
+ },
+ // #ifndef MP-WEIXIN
+ {
+ type: 'qrcode',
+ text: poster.shareInfo.link,
+ css: {
+ position: 'fixed',
+ left: width * 0.5,
+ top: width * 1.3,
+ width: width * 0.2,
+ height: width * 0.2,
+ },
+ },
+ // #endif
+ // #ifdef MP-WEIXIN
+ {
+ type: 'image',
+ src: wxa_qrcode,
+ css: {
+ position: 'fixed',
+ left: width * 0.75,
+ top: width * 1.3,
+ width: width * 0.2,
+ height: width * 0.2,
+ },
+ },
+ // #endif
+ ];
+};
+
+export default groupon;
diff --git a/sheep/components/s-share-modal/canvas-poster/poster/index.js b/sheep/components/s-share-modal/canvas-poster/poster/index.js
new file mode 100644
index 0000000..0724e7f
--- /dev/null
+++ b/sheep/components/s-share-modal/canvas-poster/poster/index.js
@@ -0,0 +1,39 @@
+import user from './user';
+import goods from './goods';
+import groupon from './groupon';
+import SocialApi from '@/sheep/api/member/social';
+
+export function getPosterData(options) {
+ switch (options.shareInfo.poster.type) {
+ case 'user':
+ return user(options);
+ case 'goods':
+ return goods(options);
+ case 'groupon':
+ return groupon(options);
+ }
+}
+
+export function formatImageUrlProtocol(url) {
+ // #ifdef H5
+ // H5平台 https协议下需要转换
+ if (window.location.protocol === 'https:' && url.indexOf('http:') === 0) {
+ url = url.replace('http:', 'https:');
+ }
+ // #endif
+
+ // #ifdef MP-WEIXIN
+ // 小程序平台 需要强制转换为https协议
+ if (url.indexOf('http:') === 0) {
+ url = url.replace('http:', 'https:');
+ }
+ // #endif
+
+ return url;
+}
+
+// 获得微信小程序码 (Base64 image)
+export async function getWxaQrcode(path, query) {
+ const res = await SocialApi.getWxaQrcode(path, query);
+ return 'data:image/png;base64,' + res.data;
+}
diff --git a/sheep/components/s-share-modal/canvas-poster/poster/user.js b/sheep/components/s-share-modal/canvas-poster/poster/user.js
new file mode 100644
index 0000000..5c4d3b9
--- /dev/null
+++ b/sheep/components/s-share-modal/canvas-poster/poster/user.js
@@ -0,0 +1,74 @@
+import sheep from '@/sheep';
+import { formatImageUrlProtocol, getWxaQrcode } from './index';
+
+const user = async (poster) => {
+ const width = poster.width;
+ const userInfo = sheep.$store('user').userInfo;
+ const wxa_qrcode = await getWxaQrcode(poster.shareInfo.path, poster.shareInfo.query);
+ return [
+ {
+ type: 'image',
+ src: formatImageUrlProtocol(sheep.$url.cdn(sheep.$store('app').platform.share.posterInfo.user_bg)),
+ css: {
+ width,
+ position: 'fixed',
+ 'object-fit': 'contain',
+ top: '0',
+ left: '0',
+ zIndex: -1,
+ },
+ },
+ {
+ type: 'text',
+ text: userInfo.nickname,
+ css: {
+ color: '#333',
+ fontSize: 14,
+ textAlign: 'center',
+ fontFamily: 'sans-serif',
+ position: 'fixed',
+ top: width * 0.4,
+ left: width / 2,
+ },
+ },
+ {
+ type: 'image',
+ src: formatImageUrlProtocol(sheep.$url.cdn(userInfo.avatar)),
+ css: {
+ position: 'fixed',
+ left: width * 0.4,
+ top: width * 0.16,
+ width: width * 0.2,
+ height: width * 0.2,
+ },
+ },
+ // #ifndef MP-WEIXIN
+ {
+ type: 'qrcode',
+ text: poster.shareInfo.link,
+ css: {
+ position: 'fixed',
+ left: width * 0.35,
+ top: width * 0.84,
+ width: width * 0.3,
+ height: width * 0.3,
+ },
+ },
+ // #endif
+ // #ifdef MP-WEIXIN
+ {
+ type: 'image',
+ src: wxa_qrcode,
+ css: {
+ position: 'fixed',
+ left: width * 0.35,
+ top: width * 0.84,
+ width: width * 0.3,
+ height: width * 0.3,
+ },
+ },
+ // #endif
+ ];
+};
+
+export default user;
diff --git a/sheep/components/s-share-modal/s-share-modal.vue b/sheep/components/s-share-modal/s-share-modal.vue
new file mode 100644
index 0000000..717940e
--- /dev/null
+++ b/sheep/components/s-share-modal/s-share-modal.vue
@@ -0,0 +1,196 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-statusbar/s-statusbar.vue b/sheep/components/s-statusbar/s-statusbar.vue
new file mode 100644
index 0000000..8b58c97
--- /dev/null
+++ b/sheep/components/s-statusbar/s-statusbar.vue
@@ -0,0 +1,10 @@
+
+
+
+
+
diff --git a/sheep/components/s-tabbar/s-tabbar.vue b/sheep/components/s-tabbar/s-tabbar.vue
new file mode 100644
index 0000000..369a823
--- /dev/null
+++ b/sheep/components/s-tabbar/s-tabbar.vue
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-title-block/s-title-block.vue b/sheep/components/s-title-block/s-title-block.vue
new file mode 100644
index 0000000..cb61033
--- /dev/null
+++ b/sheep/components/s-title-block/s-title-block.vue
@@ -0,0 +1,108 @@
+
+
+
+
+
+ {{ data.title }}
+
+ {{ data.description }}
+
+
+
+ {{ data.more.text }}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sheep/components/s-uploader/choose-and-upload-file.js b/sheep/components/s-uploader/choose-and-upload-file.js
new file mode 100644
index 0000000..604ff9d
--- /dev/null
+++ b/sheep/components/s-uploader/choose-and-upload-file.js
@@ -0,0 +1,213 @@
+'use strict';
+import FileApi from '@/sheep/api/infra/file';
+
+const ERR_MSG_OK = 'chooseAndUploadFile:ok';
+const ERR_MSG_FAIL = 'chooseAndUploadFile:fail';
+
+function chooseImage(opts) {
+ const {
+ count,
+ sizeType = ['original', 'compressed'],
+ sourceType = ['album', 'camera'],
+ extension,
+ } = opts;
+ return new Promise((resolve, reject) => {
+ uni.chooseImage({
+ count,
+ sizeType,
+ sourceType,
+ extension,
+ success(res) {
+ resolve(normalizeChooseAndUploadFileRes(res, 'image'));
+ },
+ fail(res) {
+ reject({
+ errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL),
+ });
+ },
+ });
+ });
+}
+
+function chooseVideo(opts) {
+ const { camera, compressed, maxDuration, sourceType = ['album', 'camera'], extension } = opts;
+ return new Promise((resolve, reject) => {
+ uni.chooseVideo({
+ camera,
+ compressed,
+ maxDuration,
+ sourceType,
+ extension,
+ success(res) {
+ const { tempFilePath, duration, size, height, width } = res;
+ resolve(
+ normalizeChooseAndUploadFileRes(
+ {
+ errMsg: 'chooseVideo:ok',
+ tempFilePaths: [tempFilePath],
+ tempFiles: [
+ {
+ name: (res.tempFile && res.tempFile.name) || '',
+ path: tempFilePath,
+ size,
+ type: (res.tempFile && res.tempFile.type) || '',
+ width,
+ height,
+ duration,
+ fileType: 'video',
+ cloudPath: '',
+ },
+ ],
+ },
+ 'video',
+ ),
+ );
+ },
+ fail(res) {
+ reject({
+ errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL),
+ });
+ },
+ });
+ });
+}
+
+function chooseAll(opts) {
+ const { count, extension } = opts;
+ return new Promise((resolve, reject) => {
+ let chooseFile = uni.chooseFile;
+ if (typeof wx !== 'undefined' && typeof wx.chooseMessageFile === 'function') {
+ chooseFile = wx.chooseMessageFile;
+ }
+ if (typeof chooseFile !== 'function') {
+ return reject({
+ errMsg: ERR_MSG_FAIL + ' 请指定 type 类型,该平台仅支持选择 image 或 video。',
+ });
+ }
+ chooseFile({
+ type: 'all',
+ count,
+ extension,
+ success(res) {
+ resolve(normalizeChooseAndUploadFileRes(res));
+ },
+ fail(res) {
+ reject({
+ errMsg: res.errMsg.replace('chooseFile:fail', ERR_MSG_FAIL),
+ });
+ },
+ });
+ });
+}
+
+function normalizeChooseAndUploadFileRes(res, fileType) {
+ res.tempFiles.forEach((item, index) => {
+ if (!item.name) {
+ item.name = item.path.substring(item.path.lastIndexOf('/') + 1);
+ }
+ if (fileType) {
+ item.fileType = fileType;
+ }
+ item.cloudPath = Date.now() + '_' + index + item.name.substring(item.name.lastIndexOf('.'));
+ });
+ if (!res.tempFilePaths) {
+ res.tempFilePaths = res.tempFiles.map((file) => file.path);
+ }
+ return res;
+}
+
+function uploadCloudFiles(files, max = 5, onUploadProgress) {
+ files = JSON.parse(JSON.stringify(files));
+ const len = files.length;
+ let count = 0;
+ let self = this;
+ return new Promise((resolve) => {
+ while (count < max) {
+ next();
+ }
+
+ function next() {
+ let cur = count++;
+ if (cur >= len) {
+ !files.find((item) => !item.url && !item.errMsg) && resolve(files);
+ return;
+ }
+ const fileItem = files[cur];
+ const index = self.files.findIndex((v) => v.uuid === fileItem.uuid);
+ fileItem.url = '';
+ delete fileItem.errMsg;
+
+ uniCloud
+ .uploadFile({
+ filePath: fileItem.path,
+ cloudPath: fileItem.cloudPath,
+ fileType: fileItem.fileType,
+ onUploadProgress: (res) => {
+ res.index = index;
+ onUploadProgress && onUploadProgress(res);
+ },
+ })
+ .then((res) => {
+ fileItem.url = res.fileID;
+ fileItem.index = index;
+ if (cur < len) {
+ next();
+ }
+ })
+ .catch((res) => {
+ fileItem.errMsg = res.errMsg || res.message;
+ fileItem.index = index;
+ if (cur < len) {
+ next();
+ }
+ });
+ }
+ });
+}
+
+function uploadFiles(choosePromise, { onChooseFile, onUploadProgress }) {
+ return choosePromise
+ .then((res) => {
+ if (onChooseFile) {
+ const customChooseRes = onChooseFile(res);
+ if (typeof customChooseRes !== 'undefined') {
+ return Promise.resolve(customChooseRes).then((chooseRes) =>
+ typeof chooseRes === 'undefined' ? res : chooseRes,
+ );
+ }
+ }
+ return res;
+ })
+ .then((res) => {
+ if (res === false) {
+ return {
+ errMsg: ERR_MSG_OK,
+ tempFilePaths: [],
+ tempFiles: [],
+ };
+ }
+ return res;
+ })
+ .then(async (files) => {
+ for (let file of files.tempFiles) {
+ const { data } = await FileApi.uploadFile(file.path);
+ file.url = data;
+ }
+ return files;
+ });
+}
+
+function chooseAndUploadFile(
+ opts = {
+ type: 'all',
+ },
+) {
+ if (opts.type === 'image') {
+ return uploadFiles(chooseImage(opts), opts);
+ } else if (opts.type === 'video') {
+ return uploadFiles(chooseVideo(opts), opts);
+ }
+ return uploadFiles(chooseAll(opts), opts);
+}
+
+export { chooseAndUploadFile, uploadCloudFiles };
diff --git a/sheep/components/s-uploader/s-uploader.vue b/sheep/components/s-uploader/s-uploader.vue
new file mode 100644
index 0000000..95cfb05
--- /dev/null
+++ b/sheep/components/s-uploader/s-uploader.vue
@@ -0,0 +1,675 @@
+
+
+
+
+
+ {{ subtitle }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-uploader/upload-file.vue b/sheep/components/s-uploader/upload-file.vue
new file mode 100644
index 0000000..233d281
--- /dev/null
+++ b/sheep/components/s-uploader/upload-file.vue
@@ -0,0 +1,335 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.name }}
+
+
+
+
+
+
+
+
+
+ 点击重试
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-uploader/upload-image.vue b/sheep/components/s-uploader/upload-image.vue
new file mode 100644
index 0000000..b66956a
--- /dev/null
+++ b/sheep/components/s-uploader/upload-image.vue
@@ -0,0 +1,306 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-uploader/utils.js b/sheep/components/s-uploader/utils.js
new file mode 100644
index 0000000..c1e8073
--- /dev/null
+++ b/sheep/components/s-uploader/utils.js
@@ -0,0 +1,110 @@
+/**
+ * 获取文件名和后缀
+ * @param {String} name
+ */
+export const get_file_ext = (name) => {
+ const last_len = name.lastIndexOf('.');
+ const len = name.length;
+ return {
+ name: name.substring(0, last_len),
+ ext: name.substring(last_len + 1, len),
+ };
+};
+
+/**
+ * 获取扩展名
+ * @param {Array} fileExtname
+ */
+export const get_extname = (fileExtname) => {
+ if (!Array.isArray(fileExtname)) {
+ let extname = fileExtname.replace(/(\[|\])/g, '');
+ return extname.split(',');
+ } else {
+ return fileExtname;
+ }
+ return [];
+};
+
+/**
+ * 获取文件和检测是否可选
+ */
+export const get_files_and_is_max = (res, _extname) => {
+ let filePaths = [];
+ let files = [];
+ if (!_extname || _extname.length === 0) {
+ return {
+ filePaths,
+ files,
+ };
+ }
+ res.tempFiles.forEach((v) => {
+ let fileFullName = get_file_ext(v.name);
+ const extname = fileFullName.ext.toLowerCase();
+ if (_extname.indexOf(extname) !== -1) {
+ files.push(v);
+ filePaths.push(v.path);
+ }
+ });
+ if (files.length !== res.tempFiles.length) {
+ uni.showToast({
+ title: `当前选择了${res.tempFiles.length}个文件 ,${
+ res.tempFiles.length - files.length
+ } 个文件格式不正确`,
+ icon: 'none',
+ duration: 5000,
+ });
+ }
+
+ return {
+ filePaths,
+ files,
+ };
+};
+
+/**
+ * 获取图片信息
+ * @param {Object} filepath
+ */
+export const get_file_info = (filepath) => {
+ return new Promise((resolve, reject) => {
+ uni.getImageInfo({
+ src: filepath,
+ success(res) {
+ resolve(res);
+ },
+ fail(err) {
+ reject(err);
+ },
+ });
+ });
+};
+/**
+ * 获取封装数据
+ */
+export const get_file_data = async (files, type = 'image') => {
+ // 最终需要上传数据库的数据
+ let fileFullName = get_file_ext(files.name);
+ const extname = fileFullName.ext.toLowerCase();
+ let filedata = {
+ name: files.name,
+ uuid: files.uuid,
+ extname: extname || '',
+ cloudPath: files.cloudPath,
+ fileType: files.fileType,
+ url: files.path || files.path,
+ size: files.size, //单位是字节
+ image: {},
+ path: files.path,
+ video: {},
+ };
+ if (type === 'image') {
+ const imageinfo = await get_file_info(files.path);
+ delete filedata.video;
+ filedata.image.width = imageinfo.width;
+ filedata.image.height = imageinfo.height;
+ filedata.image.location = imageinfo.path;
+ } else {
+ delete filedata.image;
+ }
+ return filedata;
+};
diff --git a/sheep/components/s-user-card/s-user-card.vue b/sheep/components/s-user-card/s-user-card.vue
new file mode 100644
index 0000000..754d536
--- /dev/null
+++ b/sheep/components/s-user-card/s-user-card.vue
@@ -0,0 +1,185 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ userInfo?.nickname || nickname }}
+
+
+
+
+
+
+
+
+
+
+
+
+ 点击绑定手机号确保账户安全
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sheep/components/s-video-block/s-video-block.vue b/sheep/components/s-video-block/s-video-block.vue
new file mode 100644
index 0000000..38e5b84
--- /dev/null
+++ b/sheep/components/s-video-block/s-video-block.vue
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-wallet-card/s-wallet-card.vue b/sheep/components/s-wallet-card/s-wallet-card.vue
new file mode 100644
index 0000000..aff0bf8
--- /dev/null
+++ b/sheep/components/s-wallet-card/s-wallet-card.vue
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+
+
+
diff --git a/sheep/components/s-worker-item/s-worker-item.vue b/sheep/components/s-worker-item/s-worker-item.vue
new file mode 100644
index 0000000..1c304e6
--- /dev/null
+++ b/sheep/components/s-worker-item/s-worker-item.vue
@@ -0,0 +1,198 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ title }}
+ {{ skuString }}
+
+ 开始服务时间:
+ 剩余时间:
+
+
+
+
+
+
+ ¥{{ fen2yuan(price) }}
+
+ x {{ num }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/config/index.js b/sheep/config/index.js
new file mode 100644
index 0000000..f6669a3
--- /dev/null
+++ b/sheep/config/index.js
@@ -0,0 +1,23 @@
+// 开发环境配置
+export let baseUrl;
+export let version;
+if (process.env.NODE_ENV === 'development') {
+ baseUrl = import.meta.env.SHOPRO_DEV_BASE_URL;
+} else {
+ baseUrl = import.meta.env.SHOPRO_BASE_URL;
+}
+version = import.meta.env.SHOPRO_VERSION;
+console.log(`[晚趣语音 ${version}]`);
+
+export const apiPath = import.meta.env.SHOPRO_API_PATH;
+export const staticUrl = import.meta.env.SHOPRO_STATIC_URL;
+export const tenantId = import.meta.env.SHOPRO_TENANT_ID;
+export const websocketPath = import.meta.env.SHOPRO_WEBSOCKET_PATH;
+
+export default {
+ baseUrl,
+ apiPath,
+ staticUrl,
+ tenantId,
+ websocketPath,
+};
diff --git a/sheep/config/zIndex.js b/sheep/config/zIndex.js
new file mode 100644
index 0000000..6652d48
--- /dev/null
+++ b/sheep/config/zIndex.js
@@ -0,0 +1,20 @@
+// uniapp在H5中各API的z-index值如下:
+/**
+ * actionsheet: 999
+ * modal: 999
+ * navigate: 998
+ * tabbar: 998
+ * toast: 999
+ */
+
+export default {
+ toast: 10090,
+ noNetwork: 10080,
+ popup: 10075, // popup包含popup,actionsheet,keyboard,picker的值
+ mask: 10070,
+ navbar: 980,
+ topTips: 975,
+ sticky: 970,
+ indexListSticky: 965,
+ popover: 960,
+};
diff --git a/sheep/helper/digit.js b/sheep/helper/digit.js
new file mode 100644
index 0000000..be50b32
--- /dev/null
+++ b/sheep/helper/digit.js
@@ -0,0 +1,168 @@
+let _boundaryCheckingState = true; // 是否进行越界检查的全局开关
+
+/**
+ * 把错误的数据转正
+ * @private
+ * @example strip(0.09999999999999998)=0.1
+ */
+function strip(num, precision = 15) {
+ return +parseFloat(Number(num).toPrecision(precision));
+}
+
+/**
+ * Return digits length of a number
+ * @private
+ * @param {*number} num Input number
+ */
+function digitLength(num) {
+ // Get digit length of e
+ const eSplit = num.toString().split(/[eE]/);
+ const len = (eSplit[0].split('.')[1] || '').length - +(eSplit[1] || 0);
+ return len > 0 ? len : 0;
+}
+
+/**
+ * 把小数转成整数,如果是小数则放大成整数
+ * @private
+ * @param {*number} num 输入数
+ */
+function float2Fixed(num) {
+ if (num.toString().indexOf('e') === -1) {
+ return Number(num.toString().replace('.', ''));
+ }
+ const dLen = digitLength(num);
+ return dLen > 0 ? strip(Number(num) * Math.pow(10, dLen)) : Number(num);
+}
+
+/**
+ * 检测数字是否越界,如果越界给出提示
+ * @private
+ * @param {*number} num 输入数
+ */
+function checkBoundary(num) {
+ if (_boundaryCheckingState) {
+ if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) {
+ console.warn(`${num} 超出了精度限制,结果可能不正确`);
+ }
+ }
+}
+
+/**
+ * 把递归操作扁平迭代化
+ * @param {number[]} arr 要操作的数字数组
+ * @param {function} operation 迭代操作
+ * @private
+ */
+function iteratorOperation(arr, operation) {
+ const [num1, num2, ...others] = arr;
+ let res = operation(num1, num2);
+
+ others.forEach((num) => {
+ res = operation(res, num);
+ });
+
+ return res;
+}
+
+/**
+ * 高精度乘法
+ * @export
+ */
+export function times(...nums) {
+ if (nums.length > 2) {
+ return iteratorOperation(nums, times);
+ }
+
+ const [num1, num2] = nums;
+ const num1Changed = float2Fixed(num1);
+ const num2Changed = float2Fixed(num2);
+ const baseNum = digitLength(num1) + digitLength(num2);
+ const leftValue = num1Changed * num2Changed;
+
+ checkBoundary(leftValue);
+
+ return leftValue / Math.pow(10, baseNum);
+}
+
+/**
+ * 高精度加法
+ * @export
+ */
+export function plus(...nums) {
+ if (nums.length > 2) {
+ return iteratorOperation(nums, plus);
+ }
+
+ const [num1, num2] = nums;
+ // 取最大的小数位
+ const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
+ // 把小数都转为整数然后再计算
+ return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
+}
+
+/**
+ * 高精度减法
+ * @export
+ */
+export function minus(...nums) {
+ if (nums.length > 2) {
+ return iteratorOperation(nums, minus);
+ }
+
+ const [num1, num2] = nums;
+ const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
+ return (times(num1, baseNum) - times(num2, baseNum)) / baseNum;
+}
+
+/**
+ * 高精度除法
+ * @export
+ */
+export function divide(...nums) {
+ if (nums.length > 2) {
+ return iteratorOperation(nums, divide);
+ }
+
+ const [num1, num2] = nums;
+ const num1Changed = float2Fixed(num1);
+ const num2Changed = float2Fixed(num2);
+ checkBoundary(num1Changed);
+ checkBoundary(num2Changed);
+ // 重要,这里必须用strip进行修正
+ return times(
+ num1Changed / num2Changed,
+ strip(Math.pow(10, digitLength(num2) - digitLength(num1))),
+ );
+}
+
+/**
+ * 四舍五入
+ * @export
+ */
+export function round(num, ratio) {
+ const base = Math.pow(10, ratio);
+ let result = divide(Math.round(Math.abs(times(num, base))), base);
+ if (num < 0 && result !== 0) {
+ result = times(result, -1);
+ }
+ // 位数不足则补0
+ return result;
+}
+
+/**
+ * 是否进行边界检查,默认开启
+ * @param flag 标记开关,true 为开启,false 为关闭,默认为 true
+ * @export
+ */
+export function enableBoundaryChecking(flag = true) {
+ _boundaryCheckingState = flag;
+}
+
+export default {
+ times,
+ plus,
+ minus,
+ divide,
+ round,
+ enableBoundaryChecking,
+};
diff --git a/sheep/helper/index.js b/sheep/helper/index.js
new file mode 100644
index 0000000..bdd0134
--- /dev/null
+++ b/sheep/helper/index.js
@@ -0,0 +1,714 @@
+import test from './test.js';
+import { round } from './digit.js';
+/**
+ * @description 如果value小于min,取min;如果value大于max,取max
+ * @param {number} min
+ * @param {number} max
+ * @param {number} value
+ */
+function range(min = 0, max = 0, value = 0) {
+ return Math.max(min, Math.min(max, Number(value)));
+}
+
+/**
+ * @description 用于获取用户传递值的px值 如果用户传递了"xxpx"或者"xxrpx",取出其数值部分,如果是"xxxrpx"还需要用过uni.upx2px进行转换
+ * @param {number|string} value 用户传递值的px值
+ * @param {boolean} unit
+ * @returns {number|string}
+ */
+export function getPx(value, unit = false) {
+ if (test.number(value)) {
+ return unit ? `${value}px` : Number(value);
+ }
+ // 如果带有rpx,先取出其数值部分,再转为px值
+ if (/(rpx|upx)$/.test(value)) {
+ return unit ? `${uni.upx2px(parseInt(value))}px` : Number(uni.upx2px(parseInt(value)));
+ }
+ return unit ? `${parseInt(value)}px` : parseInt(value);
+}
+
+/**
+ * @description 进行延时,以达到可以简写代码的目的
+ * @param {number} value 堵塞时间 单位ms 毫秒
+ * @returns {Promise} 返回promise
+ */
+export function sleep(value = 30) {
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ resolve();
+ }, value);
+ });
+}
+/**
+ * @description 运行期判断平台
+ * @returns {string} 返回所在平台(小写)
+ * @link 运行期判断平台 https://uniapp.dcloud.io/frame?id=判断平台
+ */
+export function os() {
+ return uni.getSystemInfoSync().platform.toLowerCase();
+}
+/**
+ * @description 获取系统信息同步接口
+ * @link 获取系统信息同步接口 https://uniapp.dcloud.io/api/system/info?id=getsysteminfosync
+ */
+export function sys() {
+ return uni.getSystemInfoSync();
+}
+
+/**
+ * @description 取一个区间数
+ * @param {Number} min 最小值
+ * @param {Number} max 最大值
+ */
+function random(min, max) {
+ if (min >= 0 && max > 0 && max >= min) {
+ const gab = max - min + 1;
+ return Math.floor(Math.random() * gab + min);
+ }
+ return 0;
+}
+
+/**
+ * @param {Number} len uuid的长度
+ * @param {Boolean} firstU 将返回的首字母置为"u"
+ * @param {Nubmer} radix 生成uuid的基数(意味着返回的字符串都是这个基数),2-二进制,8-八进制,10-十进制,16-十六进制
+ */
+export function guid(len = 32, firstU = true, radix = null) {
+ const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
+ const uuid = [];
+ radix = radix || chars.length;
+
+ if (len) {
+ // 如果指定uuid长度,只是取随机的字符,0|x为位运算,能去掉x的小数位,返回整数位
+ for (let i = 0; i < len; i++) uuid[i] = chars[0 | (Math.random() * radix)];
+ } else {
+ let r;
+ // rfc4122标准要求返回的uuid中,某些位为固定的字符
+ uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
+ uuid[14] = '4';
+
+ for (let i = 0; i < 36; i++) {
+ if (!uuid[i]) {
+ r = 0 | (Math.random() * 16);
+ uuid[i] = chars[i == 19 ? (r & 0x3) | 0x8 : r];
+ }
+ }
+ }
+ // 移除第一个字符,并用u替代,因为第一个字符为数值时,该guuid不能用作id或者class
+ if (firstU) {
+ uuid.shift();
+ return `u${uuid.join('')}`;
+ }
+ return uuid.join('');
+}
+
+/**
+* @description 获取父组件的参数,因为支付宝小程序不支持provide/inject的写法
+ this.$parent在非H5中,可以准确获取到父组件,但是在H5中,需要多次this.$parent.$parent.xxx
+ 这里默认值等于undefined有它的含义,因为最顶层元素(组件)的$parent就是undefined,意味着不传name
+ 值(默认为undefined),就是查找最顶层的$parent
+* @param {string|undefined} name 父组件的参数名
+*/
+export function $parent(name = undefined) {
+ let parent = this.$parent;
+ // 通过while历遍,这里主要是为了H5需要多层解析的问题
+ while (parent) {
+ // 父组件
+ if (parent.$options && parent.$options.name !== name) {
+ // 如果组件的name不相等,继续上一级寻找
+ parent = parent.$parent;
+ } else {
+ return parent;
+ }
+ }
+ return false;
+}
+
+/**
+ * @description 样式转换
+ * 对象转字符串,或者字符串转对象
+ * @param {object | string} customStyle 需要转换的目标
+ * @param {String} target 转换的目的,object-转为对象,string-转为字符串
+ * @returns {object|string}
+ */
+export function addStyle(customStyle, target = 'object') {
+ // 字符串转字符串,对象转对象情形,直接返回
+ if (
+ test.empty(customStyle) ||
+ (typeof customStyle === 'object' && target === 'object') ||
+ (target === 'string' && typeof customStyle === 'string')
+ ) {
+ return customStyle;
+ }
+ // 字符串转对象
+ if (target === 'object') {
+ // 去除字符串样式中的两端空格(中间的空格不能去掉,比如padding: 20px 0如果去掉了就错了),空格是无用的
+ customStyle = trim(customStyle);
+ // 根据";"将字符串转为数组形式
+ const styleArray = customStyle.split(';');
+ const style = {};
+ // 历遍数组,拼接成对象
+ for (let i = 0; i < styleArray.length; i++) {
+ // 'font-size:20px;color:red;',如此最后字符串有";"的话,会导致styleArray最后一个元素为空字符串,这里需要过滤
+ if (styleArray[i]) {
+ const item = styleArray[i].split(':');
+ style[trim(item[0])] = trim(item[1]);
+ }
+ }
+ return style;
+ }
+ // 这里为对象转字符串形式
+ let string = '';
+ for (const i in customStyle) {
+ // 驼峰转为中划线的形式,否则css内联样式,无法识别驼峰样式属性名
+ const key = i.replace(/([A-Z])/g, '-$1').toLowerCase();
+ string += `${key}:${customStyle[i]};`;
+ }
+ // 去除两端空格
+ return trim(string);
+}
+
+/**
+ * @description 添加单位,如果有rpx,upx,%,px等单位结尾或者值为auto,直接返回,否则加上px单位结尾
+ * @param {string|number} value 需要添加单位的值
+ * @param {string} unit 添加的单位名 比如px
+ */
+export function addUnit(value = 'auto', unit = 'px') {
+ value = String(value);
+ return test.number(value) ? `${value}${unit}` : value;
+}
+
+/**
+ * @description 深度克隆
+ * @param {object} obj 需要深度克隆的对象
+ * @returns {*} 克隆后的对象或者原值(不是对象)
+ */
+function deepClone(obj) {
+ // 对常见的“非”值,直接返回原来值
+ if ([null, undefined, NaN, false].includes(obj)) return obj;
+ if (typeof obj !== 'object' && typeof obj !== 'function') {
+ // 原始类型直接返回
+ return obj;
+ }
+ const o = test.array(obj) ? [] : {};
+ for (const i in obj) {
+ if (obj.hasOwnProperty(i)) {
+ o[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i];
+ }
+ }
+ return o;
+}
+
+/**
+ * @description JS对象深度合并
+ * @param {object} target 需要拷贝的对象
+ * @param {object} source 拷贝的来源对象
+ * @returns {object|boolean} 深度合并后的对象或者false(入参有不是对象)
+ */
+export function deepMerge(target = {}, source = {}) {
+ target = deepClone(target);
+ if (typeof target !== 'object' || typeof source !== 'object') return false;
+ for (const prop in source) {
+ if (!source.hasOwnProperty(prop)) continue;
+ if (prop in target) {
+ if (typeof target[prop] !== 'object') {
+ target[prop] = source[prop];
+ } else if (typeof source[prop] !== 'object') {
+ target[prop] = source[prop];
+ } else if (target[prop].concat && source[prop].concat) {
+ target[prop] = target[prop].concat(source[prop]);
+ } else {
+ target[prop] = deepMerge(target[prop], source[prop]);
+ }
+ } else {
+ target[prop] = source[prop];
+ }
+ }
+ return target;
+}
+
+/**
+ * @description error提示
+ * @param {*} err 错误内容
+ */
+function error(err) {
+ // 开发环境才提示,生产环境不会提示
+ if (process.env.NODE_ENV === 'development') {
+ console.error(`SheepJS:${err}`);
+ }
+}
+
+/**
+ * @description 打乱数组
+ * @param {array} array 需要打乱的数组
+ * @returns {array} 打乱后的数组
+ */
+function randomArray(array = []) {
+ // 原理是sort排序,Math.random()产生0<= x < 1之间的数,会导致x-0.05大于或者小于0
+ return array.sort(() => Math.random() - 0.5);
+}
+
+// padStart 的 polyfill,因为某些机型或情况,还无法支持es7的padStart,比如电脑版的微信小程序
+// 所以这里做一个兼容polyfill的兼容处理
+if (!String.prototype.padStart) {
+ // 为了方便表示这里 fillString 用了ES6 的默认参数,不影响理解
+ String.prototype.padStart = function (maxLength, fillString = ' ') {
+ if (Object.prototype.toString.call(fillString) !== '[object String]') {
+ throw new TypeError('fillString must be String');
+ }
+ const str = this;
+ // 返回 String(str) 这里是为了使返回的值是字符串字面量,在控制台中更符合直觉
+ if (str.length >= maxLength) return String(str);
+
+ const fillLength = maxLength - str.length;
+ let times = Math.ceil(fillLength / fillString.length);
+ while ((times >>= 1)) {
+ fillString += fillString;
+ if (times === 1) {
+ fillString += fillString;
+ }
+ }
+ return fillString.slice(0, fillLength) + str;
+ };
+}
+
+/**
+ * @description 格式化时间
+ * @param {String|Number} dateTime 需要格式化的时间戳
+ * @param {String} fmt 格式化规则 yyyy:mm:dd|yyyy:mm|yyyy年mm月dd日|yyyy年mm月dd日 hh时MM分等,可自定义组合 默认yyyy-mm-dd
+ * @returns {string} 返回格式化后的字符串
+ */
+function timeFormat(dateTime = null, formatStr = 'yyyy-mm-dd') {
+ let date;
+ // 若传入时间为假值,则取当前时间
+ if (!dateTime) {
+ date = new Date();
+ }
+ // 若为unix秒时间戳,则转为毫秒时间戳(逻辑有点奇怪,但不敢改,以保证历史兼容)
+ else if (/^\d{10}$/.test(dateTime?.toString().trim())) {
+ date = new Date(dateTime * 1000);
+ }
+ // 若用户传入字符串格式时间戳,new Date无法解析,需做兼容
+ else if (typeof dateTime === 'string' && /^\d+$/.test(dateTime.trim())) {
+ date = new Date(Number(dateTime));
+ }
+ // 其他都认为符合 RFC 2822 规范
+ else {
+ // 处理平台性差异,在Safari/Webkit中,new Date仅支持/作为分割符的字符串时间
+ date = new Date(typeof dateTime === 'string' ? dateTime.replace(/-/g, '/') : dateTime);
+ }
+
+ const timeSource = {
+ y: date.getFullYear().toString(), // 年
+ m: (date.getMonth() + 1).toString().padStart(2, '0'), // 月
+ d: date.getDate().toString().padStart(2, '0'), // 日
+ h: date.getHours().toString().padStart(2, '0'), // 时
+ M: date.getMinutes().toString().padStart(2, '0'), // 分
+ s: date.getSeconds().toString().padStart(2, '0'), // 秒
+ // 有其他格式化字符需求可以继续添加,必须转化成字符串
+ };
+
+ for (const key in timeSource) {
+ const [ret] = new RegExp(`${key}+`).exec(formatStr) || [];
+ if (ret) {
+ // 年可能只需展示两位
+ const beginIndex = key === 'y' && ret.length === 2 ? 2 : 0;
+ formatStr = formatStr.replace(ret, timeSource[key].slice(beginIndex));
+ }
+ }
+
+ return formatStr;
+}
+
+/**
+ * @description 时间戳转为多久之前
+ * @param {String|Number} timestamp 时间戳
+ * @param {String|Boolean} format
+ * 格式化规则如果为时间格式字符串,超出一定时间范围,返回固定的时间格式;
+ * 如果为布尔值false,无论什么时间,都返回多久以前的格式
+ * @returns {string} 转化后的内容
+ */
+function timeFrom(timestamp = null, format = 'yyyy-mm-dd') {
+ if (timestamp == null) timestamp = Number(new Date());
+ timestamp = parseInt(timestamp);
+ // 判断用户输入的时间戳是秒还是毫秒,一般前端js获取的时间戳是毫秒(13位),后端传过来的为秒(10位)
+ if (timestamp.toString().length == 10) timestamp *= 1000;
+ let timer = new Date().getTime() - timestamp;
+ timer = parseInt(timer / 1000);
+ // 如果小于5分钟,则返回"刚刚",其他以此类推
+ let tips = '';
+ switch (true) {
+ case timer < 300:
+ tips = '刚刚';
+ break;
+ case timer >= 300 && timer < 3600:
+ tips = `${parseInt(timer / 60)}分钟前`;
+ break;
+ case timer >= 3600 && timer < 86400:
+ tips = `${parseInt(timer / 3600)}小时前`;
+ break;
+ case timer >= 86400 && timer < 2592000:
+ tips = `${parseInt(timer / 86400)}天前`;
+ break;
+ default:
+ // 如果format为false,则无论什么时间戳,都显示xx之前
+ if (format === false) {
+ if (timer >= 2592000 && timer < 365 * 86400) {
+ tips = `${parseInt(timer / (86400 * 30))}个月前`;
+ } else {
+ tips = `${parseInt(timer / (86400 * 365))}年前`;
+ }
+ } else {
+ tips = timeFormat(timestamp, format);
+ }
+ }
+ return tips;
+}
+
+export function parseTimeData(time) {
+ time = time - new Date().getTime();
+ return time
+}
+
+/**
+ * @description 去除空格
+ * @param String str 需要去除空格的字符串
+ * @param String pos both(左右)|left|right|all 默认both
+ */
+function trim(str, pos = 'both') {
+ str = String(str);
+ if (pos == 'both') {
+ return str.replace(/^\s+|\s+$/g, '');
+ }
+ if (pos == 'left') {
+ return str.replace(/^\s*/, '');
+ }
+ if (pos == 'right') {
+ return str.replace(/(\s*$)/g, '');
+ }
+ if (pos == 'all') {
+ return str.replace(/\s+/g, '');
+ }
+ return str;
+}
+
+/**
+ * @description 对象转url参数
+ * @param {object} data,对象
+ * @param {Boolean} isPrefix,是否自动加上"?"
+ * @param {string} arrayFormat 规则 indices|brackets|repeat|comma
+ */
+function queryParams(data = {}, isPrefix = true, arrayFormat = 'brackets') {
+ const prefix = isPrefix ? '?' : '';
+ const _result = [];
+ if (['indices', 'brackets', 'repeat', 'comma'].indexOf(arrayFormat) == -1)
+ arrayFormat = 'brackets';
+ for (const key in data) {
+ const value = data[key];
+ // 去掉为空的参数
+ if (['', undefined, null].indexOf(value) >= 0) {
+ continue;
+ }
+ // 如果值为数组,另行处理
+ if (value.constructor === Array) {
+ // e.g. {ids: [1, 2, 3]}
+ switch (arrayFormat) {
+ case 'indices':
+ // 结果: ids[0]=1&ids[1]=2&ids[2]=3
+ for (let i = 0; i < value.length; i++) {
+ _result.push(`${key}[${i}]=${value[i]}`);
+ }
+ break;
+ case 'brackets':
+ // 结果: ids[]=1&ids[]=2&ids[]=3
+ value.forEach((_value) => {
+ _result.push(`${key}[]=${_value}`);
+ });
+ break;
+ case 'repeat':
+ // 结果: ids=1&ids=2&ids=3
+ value.forEach((_value) => {
+ _result.push(`${key}=${_value}`);
+ });
+ break;
+ case 'comma':
+ // 结果: ids=1,2,3
+ let commaStr = '';
+ value.forEach((_value) => {
+ commaStr += (commaStr ? ',' : '') + _value;
+ });
+ _result.push(`${key}=${commaStr}`);
+ break;
+ default:
+ value.forEach((_value) => {
+ _result.push(`${key}[]=${_value}`);
+ });
+ }
+ } else {
+ _result.push(`${key}=${value}`);
+ }
+ }
+ return _result.length ? prefix + _result.join('&') : '';
+}
+
+/**
+ * 显示消息提示框
+ * @param {String} title 提示的内容,长度与 icon 取值有关。
+ * @param {Number} duration 提示的延迟时间,单位毫秒,默认:2000
+ */
+function toast(title, duration = 2000) {
+ uni.showToast({
+ title: String(title),
+ icon: 'none',
+ duration,
+ });
+}
+
+/**
+ * @description 根据主题type值,获取对应的图标
+ * @param {String} type 主题名称,primary|info|error|warning|success
+ * @param {boolean} fill 是否使用fill填充实体的图标
+ */
+function type2icon(type = 'success', fill = false) {
+ // 如果非预置值,默认为success
+ if (['primary', 'info', 'error', 'warning', 'success'].indexOf(type) == -1) type = 'success';
+ let iconName = '';
+ // 目前(2019-12-12),info和primary使用同一个图标
+ switch (type) {
+ case 'primary':
+ iconName = 'info-circle';
+ break;
+ case 'info':
+ iconName = 'info-circle';
+ break;
+ case 'error':
+ iconName = 'close-circle';
+ break;
+ case 'warning':
+ iconName = 'error-circle';
+ break;
+ case 'success':
+ iconName = 'checkmark-circle';
+ break;
+ default:
+ iconName = 'checkmark-circle';
+ }
+ // 是否是实体类型,加上-fill,在icon组件库中,实体的类名是后面加-fill的
+ if (fill) iconName += '-fill';
+ return iconName;
+}
+
+/**
+ * @description 数字格式化
+ * @param {number|string} number 要格式化的数字
+ * @param {number} decimals 保留几位小数
+ * @param {string} decimalPoint 小数点符号
+ * @param {string} thousandsSeparator 千分位符号
+ * @returns {string} 格式化后的数字
+ */
+function priceFormat(number, decimals = 0, decimalPoint = '.', thousandsSeparator = ',') {
+ number = `${number}`.replace(/[^0-9+-Ee.]/g, '');
+ const n = !isFinite(+number) ? 0 : +number;
+ const prec = !isFinite(+decimals) ? 0 : Math.abs(decimals);
+ const sep = typeof thousandsSeparator === 'undefined' ? ',' : thousandsSeparator;
+ const dec = typeof decimalPoint === 'undefined' ? '.' : decimalPoint;
+ let s = '';
+
+ s = (prec ? round(n, prec) + '' : `${Math.round(n)}`).split('.');
+ const re = /(-?\d+)(\d{3})/;
+ while (re.test(s[0])) {
+ s[0] = s[0].replace(re, `$1${sep}$2`);
+ }
+
+ if ((s[1] || '').length < prec) {
+ s[1] = s[1] || '';
+ s[1] += new Array(prec - s[1].length + 1).join('0');
+ }
+ return s.join(dec);
+}
+
+/**
+ * @description 获取duration值
+ * 如果带有ms或者s直接返回,如果大于一定值,认为是ms单位,小于一定值,认为是s单位
+ * 比如以30位阈值,那么300大于30,可以理解为用户想要的是300ms,而不是想花300s去执行一个动画
+ * @param {String|number} value 比如: "1s"|"100ms"|1|100
+ * @param {boolean} unit 提示: 如果是false 默认返回number
+ * @return {string|number}
+ */
+function getDuration(value, unit = true) {
+ const valueNum = parseInt(value);
+ if (unit) {
+ if (/s$/.test(value)) return value;
+ return value > 30 ? `${value}ms` : `${value}s`;
+ }
+ if (/ms$/.test(value)) return valueNum;
+ if (/s$/.test(value)) return valueNum > 30 ? valueNum : valueNum * 1000;
+ return valueNum;
+}
+
+/**
+ * @description 日期的月或日补零操作
+ * @param {String} value 需要补零的值
+ */
+function padZero(value) {
+ return `00${value}`.slice(-2);
+}
+
+/**
+ * @description 获取某个对象下的属性,用于通过类似'a.b.c'的形式去获取一个对象的的属性的形式
+ * @param {object} obj 对象
+ * @param {string} key 需要获取的属性字段
+ * @returns {*}
+ */
+function getProperty(obj, key) {
+ if (!obj) {
+ return;
+ }
+ if (typeof key !== 'string' || key === '') {
+ return '';
+ }
+ if (key.indexOf('.') !== -1) {
+ const keys = key.split('.');
+ let firstObj = obj[keys[0]] || {};
+
+ for (let i = 1; i < keys.length; i++) {
+ if (firstObj) {
+ firstObj = firstObj[keys[i]];
+ }
+ }
+ return firstObj;
+ }
+ return obj[key];
+}
+
+/**
+ * @description 设置对象的属性值,如果'a.b.c'的形式进行设置
+ * @param {object} obj 对象
+ * @param {string} key 需要设置的属性
+ * @param {string} value 设置的值
+ */
+function setProperty(obj, key, value) {
+ if (!obj) {
+ return;
+ }
+ // 递归赋值
+ const inFn = function (_obj, keys, v) {
+ // 最后一个属性key
+ if (keys.length === 1) {
+ _obj[keys[0]] = v;
+ return;
+ }
+ // 0~length-1个key
+ while (keys.length > 1) {
+ const k = keys[0];
+ if (!_obj[k] || typeof _obj[k] !== 'object') {
+ _obj[k] = {};
+ }
+ const key = keys.shift();
+ // 自调用判断是否存在属性,不存在则自动创建对象
+ inFn(_obj[k], keys, v);
+ }
+ };
+
+ if (typeof key !== 'string' || key === '') {
+ } else if (key.indexOf('.') !== -1) {
+ // 支持多层级赋值操作
+ const keys = key.split('.');
+ inFn(obj, keys, value);
+ } else {
+ obj[key] = value;
+ }
+}
+
+/**
+ * @description 获取当前页面路径
+ */
+function page() {
+ const pages = getCurrentPages();
+ // 某些特殊情况下(比如页面进行redirectTo时的一些时机),pages可能为空数组
+ return `/${pages[pages.length - 1]?.route ?? ''}`;
+}
+
+/**
+ * @description 获取当前路由栈实例数组
+ */
+function pages() {
+ const pages = getCurrentPages();
+ return pages;
+}
+
+/**
+ * 获取H5-真实根地址 兼容hash+history模式
+ */
+export function getRootUrl() {
+ let url = '';
+ // #ifdef H5
+ url = location.origin + '/h5';
+
+ if (location.hash !== '') {
+ url += '/#/';
+ }
+ // #endif
+ return url;
+}
+
+/**
+ * copyText 多端复制文本
+ */
+export function copyText(text) {
+ // #ifndef H5
+ uni.setClipboardData({
+ data: text,
+ success: function () {
+ toast('复制成功!');
+ },
+ fail: function () {
+ toast('复制失败!');
+ },
+ });
+ // #endif
+ // #ifdef H5
+ var createInput = document.createElement('textarea');
+ createInput.value = text;
+ document.body.appendChild(createInput);
+ createInput.select();
+ document.execCommand('Copy');
+ createInput.className = 'createInput';
+ createInput.style.display = 'none';
+ toast('复制成功');
+ // #endif
+}
+
+export default {
+ range,
+ getPx,
+ sleep,
+ os,
+ sys,
+ random,
+ guid,
+ $parent,
+ addStyle,
+ addUnit,
+ deepClone,
+ deepMerge,
+ error,
+ randomArray,
+ timeFormat,
+ parseTimeData,
+ timeFrom,
+ trim,
+ queryParams,
+ toast,
+ type2icon,
+ priceFormat,
+ getDuration,
+ padZero,
+ getProperty,
+ setProperty,
+ page,
+ pages,
+ test,
+ getRootUrl,
+ copyText,
+};
diff --git a/sheep/helper/test.js b/sheep/helper/test.js
new file mode 100644
index 0000000..ca550a1
--- /dev/null
+++ b/sheep/helper/test.js
@@ -0,0 +1,285 @@
+/**
+ * 验证电子邮箱格式
+ */
+function email(value) {
+ return /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/.test(value);
+}
+
+/**
+ * 验证手机格式
+ */
+function mobile(value) {
+ return /^1[23456789]\d{9}$/.test(value);
+}
+
+/**
+ * 验证URL格式
+ */
+function url(value) {
+ return /^((https|http|ftp|rtsp|mms):\/\/)(([0-9a-zA-Z_!~*'().&=+$%-]+: )?[0-9a-zA-Z_!~*'().&=+$%-]+@)?(([0-9]{1,3}.){3}[0-9]{1,3}|([0-9a-zA-Z_!~*'()-]+.)*([0-9a-zA-Z][0-9a-zA-Z-]{0,61})?[0-9a-zA-Z].[a-zA-Z]{2,6})(:[0-9]{1,4})?((\/?)|(\/[0-9a-zA-Z_!~*'().;?:@&=+$,%#-]+)+\/?)$/.test(
+ value,
+ );
+}
+
+/**
+ * 验证日期格式
+ */
+function date(value) {
+ if (!value) return false;
+ // 判断是否数值或者字符串数值(意味着为时间戳),转为数值,否则new Date无法识别字符串时间戳
+ if (number(value)) value = +value;
+ return !/Invalid|NaN/.test(new Date(value).toString());
+}
+
+/**
+ * 验证ISO类型的日期格式
+ */
+function dateISO(value) {
+ return /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(value);
+}
+
+/**
+ * 验证十进制数字
+ */
+function number(value) {
+ return /^[\+-]?(\d+\.?\d*|\.\d+|\d\.\d+e\+\d+)$/.test(value);
+}
+
+/**
+ * 验证字符串
+ */
+function string(value) {
+ return typeof value === 'string';
+}
+
+/**
+ * 验证整数
+ */
+function digits(value) {
+ return /^\d+$/.test(value);
+}
+
+/**
+ * 验证身份证号码
+ */
+function idCard(value) {
+ return /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value);
+}
+
+/**
+ * 是否车牌号
+ */
+function carNo(value) {
+ // 新能源车牌
+ const xreg =
+ /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF]$)|([DF][A-HJ-NP-Z0-9][0-9]{4}$))/;
+ // 旧车牌
+ const creg =
+ /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1}$/;
+ if (value.length === 7) {
+ return creg.test(value);
+ }
+ if (value.length === 8) {
+ return xreg.test(value);
+ }
+ return false;
+}
+
+/**
+ * 金额,只允许2位小数
+ */
+function amount(value) {
+ // 金额,只允许保留两位小数
+ return /^[1-9]\d*(,\d{3})*(\.\d{1,2})?$|^0\.\d{1,2}$/.test(value);
+}
+
+/**
+ * 中文
+ */
+function chinese(value) {
+ const reg = /^[\u4e00-\u9fa5]+$/gi;
+ return reg.test(value);
+}
+
+/**
+ * 只能输入字母
+ */
+function letter(value) {
+ return /^[a-zA-Z]*$/.test(value);
+}
+
+/**
+ * 只能是字母或者数字
+ */
+function enOrNum(value) {
+ // 英文或者数字
+ const reg = /^[0-9a-zA-Z]*$/g;
+ return reg.test(value);
+}
+
+/**
+ * 验证是否包含某个值
+ */
+function contains(value, param) {
+ return value.indexOf(param) >= 0;
+}
+
+/**
+ * 验证一个值范围[min, max]
+ */
+function range(value, param) {
+ return value >= param[0] && value <= param[1];
+}
+
+/**
+ * 验证一个长度范围[min, max]
+ */
+function rangeLength(value, param) {
+ return value.length >= param[0] && value.length <= param[1];
+}
+
+/**
+ * 是否固定电话
+ */
+function landline(value) {
+ const reg = /^\d{3,4}-\d{7,8}(-\d{3,4})?$/;
+ return reg.test(value);
+}
+
+/**
+ * 判断是否为空
+ */
+function empty(value) {
+ switch (typeof value) {
+ case 'undefined':
+ return true;
+ case 'string':
+ if (value.replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '').length == 0) return true;
+ break;
+ case 'boolean':
+ if (!value) return true;
+ break;
+ case 'number':
+ if (value === 0 || isNaN(value)) return true;
+ break;
+ case 'object':
+ if (value === null || value.length === 0) return true;
+ for (const i in value) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+/**
+ * 是否json字符串
+ */
+function jsonString(value) {
+ if (typeof value === 'string') {
+ try {
+ const obj = JSON.parse(value);
+ if (typeof obj === 'object' && obj) {
+ return true;
+ }
+ return false;
+ } catch (e) {
+ return false;
+ }
+ }
+ return false;
+}
+
+/**
+ * 是否数组
+ */
+function array(value) {
+ if (typeof Array.isArray === 'function') {
+ return Array.isArray(value);
+ }
+ return Object.prototype.toString.call(value) === '[object Array]';
+}
+
+/**
+ * 是否对象
+ */
+function object(value) {
+ return Object.prototype.toString.call(value) === '[object Object]';
+}
+
+/**
+ * 是否短信验证码
+ */
+function code(value, len = 6) {
+ return new RegExp(`^\\d{${len}}$`).test(value);
+}
+
+/**
+ * 是否函数方法
+ * @param {Object} value
+ */
+function func(value) {
+ return typeof value === 'function';
+}
+
+/**
+ * 是否promise对象
+ * @param {Object} value
+ */
+function promise(value) {
+ return object(value) && func(value.then) && func(value.catch);
+}
+
+/** 是否图片格式
+ * @param {Object} value
+ */
+function image(value) {
+ const newValue = value.split('?')[0];
+ const IMAGE_REGEXP = /\.(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg)/i;
+ return IMAGE_REGEXP.test(newValue);
+}
+
+/**
+ * 是否视频格式
+ * @param {Object} value
+ */
+function video(value) {
+ const VIDEO_REGEXP = /\.(mp4|mpg|mpeg|dat|asf|avi|rm|rmvb|mov|wmv|flv|mkv|m3u8)/i;
+ return VIDEO_REGEXP.test(value);
+}
+
+/**
+ * 是否为正则对象
+ * @param {Object}
+ * @return {Boolean}
+ */
+function regExp(o) {
+ return o && Object.prototype.toString.call(o) === '[object RegExp]';
+}
+
+export default {
+ email,
+ mobile,
+ url,
+ date,
+ dateISO,
+ number,
+ digits,
+ idCard,
+ carNo,
+ amount,
+ chinese,
+ letter,
+ enOrNum,
+ contains,
+ range,
+ rangeLength,
+ empty,
+ isEmpty: empty,
+ isNumber: number,
+ jsonString,
+ landline,
+ object,
+ array,
+ code,
+};
diff --git a/sheep/helper/throttle.js b/sheep/helper/throttle.js
new file mode 100644
index 0000000..c318127
--- /dev/null
+++ b/sheep/helper/throttle.js
@@ -0,0 +1,31 @@
+let timer;
+let flag;
+/**
+ * 节流原理:在一定时间内,只能触发一次
+ *
+ * @param {Function} func 要执行的回调函数
+ * @param {Number} wait 延时的时间
+ * @param {Boolean} immediate 是否立即执行
+ * @return null
+ */
+function throttle(func, wait = 500, immediate = true) {
+ if (immediate) {
+ if (!flag) {
+ flag = true;
+ // 如果是立即执行,则在wait毫秒内开始时执行
+ typeof func === 'function' && func();
+ timer = setTimeout(() => {
+ flag = false;
+ }, wait);
+ } else {
+ }
+ } else if (!flag) {
+ flag = true;
+ // 如果是非立即执行,则在wait毫秒内的结束处执行
+ timer = setTimeout(() => {
+ flag = false;
+ typeof func === 'function' && func();
+ }, wait);
+ }
+}
+export default throttle;
diff --git a/sheep/helper/tools.js b/sheep/helper/tools.js
new file mode 100644
index 0000000..49efcec
--- /dev/null
+++ b/sheep/helper/tools.js
@@ -0,0 +1,67 @@
+import router from '@/sheep/router';
+export default {
+ /**
+ * 打电话
+ * @param {String} phoneNumber - 数字字符串
+ */
+ callPhone(phoneNumber = '') {
+ let num = phoneNumber.toString();
+ uni.makePhoneCall({
+ phoneNumber: num,
+ fail(err) {
+ console.log('makePhoneCall出错', err);
+ },
+ });
+ },
+
+ /**
+ * 微信头像
+ * @param {String} url -图片地址
+ */
+ checkMPUrl(url) {
+ // #ifdef MP
+ if (
+ url.substring(0, 4) === 'http' &&
+ url.substring(0, 5) !== 'https' &&
+ url.substring(0, 12) !== 'http://store' &&
+ url.substring(0, 10) !== 'http://tmp' &&
+ url.substring(0, 10) !== 'http://usr'
+ ) {
+ url = 'https' + url.substring(4, url.length);
+ }
+ // #endif
+ return url;
+ },
+
+ /**
+ * getUuid 生成唯一id
+ */
+ getUuid(len = 32, firstU = true, radix = null) {
+ const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
+ const uuid = [];
+ radix = radix || chars.length;
+
+ if (len) {
+ // 如果指定uuid长度,只是取随机的字符,0|x为位运算,能去掉x的小数位,返回整数位
+ for (let i = 0; i < len; i++) uuid[i] = chars[0 | (Math.random() * radix)];
+ } else {
+ let r;
+ // rfc4122标准要求返回的uuid中,某些位为固定的字符
+ uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
+ uuid[14] = '4';
+
+ for (let i = 0; i < 36; i++) {
+ if (!uuid[i]) {
+ r = 0 | (Math.random() * 16);
+ uuid[i] = chars[i == 19 ? (r & 0x3) | 0x8 : r];
+ }
+ }
+ }
+ // 移除第一个字符,并用u替代,因为第一个字符为数值时,该guuid不能用作id或者class
+ if (firstU) {
+ uuid.shift();
+ return `u${uuid.join('')}`;
+ }
+ return uuid.join('');
+ },
+};
diff --git a/sheep/helper/utils.js b/sheep/helper/utils.js
new file mode 100644
index 0000000..a0dd86f
--- /dev/null
+++ b/sheep/helper/utils.js
@@ -0,0 +1,172 @@
+export function isArray(value) {
+ if (typeof Array.isArray === 'function') {
+ return Array.isArray(value);
+ } else {
+ return Object.prototype.toString.call(value) === '[object Array]';
+ }
+}
+
+export function isObject(value) {
+ return Object.prototype.toString.call(value) === '[object Object]';
+}
+
+export function isNumber(value) {
+ return !isNaN(Number(value));
+}
+
+export function isFunction(value) {
+ return typeof value == 'function';
+}
+
+export function isString(value) {
+ return typeof value == 'string';
+}
+
+export function isEmpty(value) {
+ if (value === '' || value === undefined || value === null){
+ return true;
+ }
+
+ if (isArray(value)) {
+ return value.length === 0;
+ }
+
+ if (isObject(value)) {
+ return Object.keys(value).length === 0;
+ }
+
+ return false
+}
+
+export function isBoolean(value) {
+ return typeof value === 'boolean';
+}
+
+export function last(data) {
+ if (isArray(data) || isString(data)) {
+ return data[data.length - 1];
+ }
+}
+
+export function cloneDeep(obj) {
+ const d = isArray(obj) ? [...obj] : {};
+
+ if (isObject(obj)) {
+ for (const key in obj) {
+ if (obj[key]) {
+ if (obj[key] && typeof obj[key] === 'object') {
+ d[key] = cloneDeep(obj[key]);
+ } else {
+ d[key] = obj[key];
+ }
+ }
+ }
+ }
+
+ return d;
+}
+
+export function clone(obj) {
+ return Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));
+}
+
+export function deepMerge(a, b) {
+ let k;
+ for (k in b) {
+ a[k] = a[k] && a[k].toString() === '[object Object]' ? deepMerge(a[k], b[k]) : (a[k] = b[k]);
+ }
+ return a;
+}
+
+export function contains(parent, node) {
+ while (node && (node = node.parentNode)) if (node === parent) return true;
+ return false;
+}
+
+export function orderBy(list, key) {
+ return list.sort((a, b) => a[key] - b[key]);
+}
+
+export function deepTree(list) {
+ const newList = [];
+ const map = {};
+
+ list.forEach((e) => (map[e.id] = e));
+
+ list.forEach((e) => {
+ const parent = map[e.parentId];
+
+ if (parent) {
+ (parent.children || (parent.children = [])).push(e);
+ } else {
+ newList.push(e);
+ }
+ });
+
+ const fn = (list) => {
+ list.map((e) => {
+ if (e.children instanceof Array) {
+ e.children = orderBy(e.children, 'orderNum');
+
+ fn(e.children);
+ }
+ });
+ };
+
+ fn(newList);
+
+ return orderBy(newList, 'orderNum');
+}
+
+export function revDeepTree(list = []) {
+ const d = [];
+ let id = 0;
+
+ const deep = (list, parentId) => {
+ list.forEach((e) => {
+ if (!e.id) {
+ e.id = id++;
+ }
+
+ e.parentId = parentId;
+
+ d.push(e);
+
+ if (e.children && isArray(e.children)) {
+ deep(e.children, e.id);
+ }
+ });
+ };
+
+ deep(list || [], null);
+
+ return d;
+}
+
+export function basename(path) {
+ let index = path.lastIndexOf('/');
+ index = index > -1 ? index : path.lastIndexOf('\\');
+ if (index < 0) {
+ return path;
+ }
+ return path.substring(index + 1);
+}
+
+export function isWxBrowser() {
+ const ua = navigator.userAgent.toLowerCase();
+ if (ua.match(/MicroMessenger/i) == 'micromessenger') {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * @description 如果value小于min,取min;如果value大于max,取max
+ * @param {number} min
+ * @param {number} max
+ * @param {number} value
+ */
+export function range(min = 0, max = 0, value = 0) {
+ return Math.max(min, Math.min(max, Number(value)));
+}
diff --git a/sheep/hooks/useApp.js b/sheep/hooks/useApp.js
new file mode 100644
index 0000000..e69de29
diff --git a/sheep/hooks/useGoods.js b/sheep/hooks/useGoods.js
new file mode 100644
index 0000000..1969da9
--- /dev/null
+++ b/sheep/hooks/useGoods.js
@@ -0,0 +1,655 @@
+import { ref } from 'vue';
+import dayjs from 'dayjs';
+import $url from '@/sheep/url';
+import { formatDate } from '@/sheep/util';
+
+/**
+ * 格式化销量
+ * @param {'exact' | string} type 格式类型:exact=精确值,其它=大致数量
+ * @param {number} num 销量
+ * @return {string} 格式化后的销量字符串
+ */
+export function formatSales(type, num) {
+ let prefix = type !== 'exact' && num < 10 ? '销量' : '已售';
+ return formatNum(prefix, type, num)
+}
+
+/**
+ * 格式化兑换量
+ * @param {'exact' | string} type 格式类型:exact=精确值,其它=大致数量
+ * @param {number} num 销量
+ * @return {string} 格式化后的销量字符串
+ */
+export function formatExchange(type, num) {
+ return formatNum('已兑换', type, num)
+}
+
+
+/**
+ * 格式化库存
+ * @param {'exact' | any} type 格式类型:exact=精确值,其它=大致数量
+ * @param {number} num 销量
+ * @return {string} 格式化后的销量字符串
+ */
+export function formatStock(type, num) {
+ return formatNum('库存', type, num)
+}
+
+/**
+ * 格式化数字
+ * @param {string} prefix 前缀
+ * @param {'exact' | string} type 格式类型:exact=精确值,其它=大致数量
+ * @param {number} num 销量
+ * @return {string} 格式化后的销量字符串
+ */
+export function formatNum(prefix, type, num) {
+ num = (num || 0);
+ // 情况一:精确数值
+ if (type === 'exact') {
+ return prefix + num;
+ }
+ // 情况二:小于等于 10
+ if (num < 10) {
+ return `${prefix}≤10`;
+ }
+ // 情况三:大于 10,除第一位外,其它位都显示为0
+ // 例如:100 - 199 显示为 100+
+ // 9000 - 9999 显示为 9000+
+ const numStr = num.toString();
+ const first = numStr[0];
+ const other = '0'.repeat(numStr.length - 1);
+ return `${prefix}${first}${other}+`;
+}
+
+// 格式化价格
+export function formatPrice(e) {
+ return e.length === 1 ? e[0] : e.join('~');
+}
+
+// 视频格式后缀列表
+const VIDEO_SUFFIX_LIST = ['.avi', '.mp4']
+
+/**
+ * 转换商品轮播的链接列表:根据链接的后缀,判断是视频链接还是图片链接
+ *
+ * @param {string[]} urlList 链接列表
+ * @return {{src: string, type: 'video' | 'image' }[]} 转换后的链接列表
+ */
+export function formatGoodsSwiper(urlList) {
+ return urlList?.filter(url => url).map((url, key) => {
+ const isVideo = VIDEO_SUFFIX_LIST.some(suffix => url.includes(suffix));
+ const type = isVideo ? 'video' : 'image'
+ const src = $url.cdn(url);
+ return { type, src }
+ }) || [];
+}
+
+/**
+ * 格式化订单状态的颜色
+ *
+ * @param order 订单
+ * @return {string} 颜色的 class 名称
+ */
+export function formatOrderColor(order) {
+ if (order.status === 0) {
+ return 'info-color';
+ }
+ if (order.status === 10
+ || order.status === 20
+ || (order.status === 30 && !order.commentStatus)) {
+ return 'warning-color';
+ }
+ if (order.status === 30 && order.commentStatus) {
+ return 'success-color';
+ }
+ return 'danger-color';
+}
+
+/**
+ * 格式化订单状态
+ *
+ * @param order 订单
+ */
+export function formatOrderStatus(order) {
+ if (order.status === 0) {
+ return '待付款';
+ }
+ if (order.status === 10 && order.deliveryType === 1) {
+ return '待发货';
+ }
+ if (order.status === 10 && order.deliveryType === 2) {
+ return '待核销';
+ }
+ if (order.status === 20) {
+ return '待收货';
+ }
+ if (order.status === 30 && !order.commentStatus) {
+ return '待评价';
+ }
+ if (order.status === 30 && order.commentStatus) {
+ return '已完成';
+ }
+ return '已关闭';
+}
+
+/**
+ * 格式化订单状态
+ *
+ * @param order 订单
+ */
+export function formatWorkerOrderStatus(order) {
+ if (order.status === 0) {
+ order.statusStr = '待付款';
+ return order.statusStr;
+ }
+ if (order.status === 10) {
+ order.statusStr = '待服务';
+ return order.statusStr;
+ }
+ if (order.status === 20) {
+ order.statusStr = '服务中';
+ return order.statusStr;
+ }
+ if (order.status === 30) {
+ order.statusStr = '已完成';
+ return order.statusStr;
+ }
+
+ order.statusStr = '已取消';
+ return order.statusStr;
+}
+
+/**
+ * 格式化订单状态
+ *
+ * @param order 订单
+ */
+export function formatBlindOrderStatus(order) {
+ if (order.status === 0) {
+ order.statusStr = '待付款';
+ return order.statusStr;
+ }
+ if (order.status === 10) {
+ order.statusStr = '待抢单';
+ return order.statusStr;
+ }
+ if (order.status === 20) {
+ order.statusStr = '服务中';
+ return order.statusStr;
+ }
+ if (order.status === 30) {
+ order.statusStr = '已完成';
+ return order.statusStr;
+ }
+
+ order.statusStr = '已取消';
+ return order.statusStr;
+}
+
+/**
+ * 格式化订单状态
+ *
+ * @param order 订单
+ */
+export function formatMyOrderStatus(order) {
+ if (order.status === 0) {
+ order.statusStr = '待付款';
+ return order.statusStr;
+ }
+ if (order.status === 10) {
+ order.statusStr = '待服务';
+ return order.statusStr;
+ }
+ if (order.status === 20) {
+ order.statusStr = '服务中';
+ return order.statusStr;
+ }
+ if (order.status === 30 && !order.commentStatus) {
+ order.statusStr = '待评价';
+ return order.statusStr;
+ }
+ if (order.status === 30 && order.commentStatus) {
+ order.statusStr = '已完成';
+ return order.statusStr;
+ }
+
+ order.statusStr = '已取消';
+ return order.statusStr;
+}
+
+/**
+ * 格式化订单状态的描述
+ *
+ * @param order 订单
+ */
+export function formatOrderStatusDescription(order) {
+ if (order.status === 0) {
+ return `请在 ${ formatDate(order.payExpireTime) } 前完成支付`;
+ }
+ if (order.status === 10) {
+ return '商家未发货,请耐心等待';
+ }
+ if (order.status === 20) {
+ return '商家已发货,请耐心等待';
+ }
+ if (order.status === 30 && !order.commentStatus) {
+ return '已收货,快去评价一下吧';
+ }
+ if (order.status === 30 && order.commentStatus) {
+ return '交易完成,感谢您的支持';
+ }
+ return '订单取消';
+}
+
+/**
+ * 格式化订单状态的描述
+ *
+ * @param order 订单
+ */
+export function formatMyOrderStatusDescription(order) {
+ if (order.status === 0) {
+ return `请在 ${ formatDate(order.payExpireTime) } 前完成支付`;
+ }
+ if (order.status === 10) {
+ return '店员未接单,请耐心等待';
+ }
+ if (order.status === 20) {
+ return '店员已接单,请打开微信搜索权限,等待添加';
+ }
+ if (order.status === 30 && !order.commentStatus) {
+ return '店员已完成服务,快去评价一下吧';
+ }
+ if (order.status === 30 && order.commentStatus) {
+ return '店员已完成服务,感谢您的支持';
+ }
+ return '订单已取消,有缘自会相遇';
+}
+
+
+/**
+ * 格式化订单状态的描述
+ *
+ * @param order 订单
+ */
+export function formatWorkerOrderStatusDescription(order) {
+ if (order.status === 0) {
+ return `老板未付款,可以主动联系老板下单`;
+ }
+ if (order.status === 10) {
+ return '老板已付款,请尽快添加老板,开始服务';
+ }
+ if (order.status === 20) {
+ return '已抢单成功,快去添加老板,开始服务';
+ }
+ if (order.status === 30 && !order.commentStatus) {
+ return '已完成服务,快去邀请老板评价一下吧';
+ }
+ if (order.status === 30 && order.commentStatus) {
+ return '已完成服务,做的很好';
+ }
+ return '交易关闭';
+}
+
+/**
+ * 格式化订单状态的描述
+ *
+ * @param order 订单
+ */
+export function formatBlindOrderStatusDescription(order) {
+ if (order.status === 0) {
+ return `老板未付款,可以主动联系老板下单`;
+ }
+ if (order.status === 10) {
+ return '老板已付款,抢单成功后添加老板,开始服务';
+ }
+ if (order.status === 20) {
+ return '已抢单成功,快去添加老板,开始服务';
+ }
+ if (order.status === 30 && !order.commentStatus) {
+ return '已完成服务,快去邀请老板评价一下吧';
+ }
+ if (order.status === 30 && order.commentStatus) {
+ return '已完成服务,做的很好';
+ }
+ return '交易关闭';
+}
+
+/**
+ * 处理订单的 button 操作按钮数组
+ *
+ * @param order 订单
+ */
+export function handleOrderButtons(order) {
+ order.buttons = []
+ if (order.type === 3) { // 查看拼团
+ order.buttons.push('combination');
+ }
+ if (order.status === 20) { // 确认收货
+ order.buttons.push('confirm');
+ }
+ if (order.logisticsId > 0) { // 查看物流
+ order.buttons.push('express');
+ }
+ if (order.status === 0) { // 取消订单 / 发起支付
+ order.buttons.push('cancel');
+ order.buttons.push('pay');
+ }
+ if (order.status === 30 && !order.commentStatus) { // 发起评价
+ order.buttons.push('comment');
+ }
+ if (order.status === 40) { // 删除订单
+ order.buttons.push('delete');
+ }
+}
+
+/**
+ * 处理订单的 button 操作按钮数组
+ *
+ * @param order 订单
+ */
+export function handleWorkerOrderButtons(order) {
+ order.buttons = []
+ if (order.status === 10) { // 待服务
+ order.buttons.push('unpay');
+ order.buttons.push('agree');
+ }
+ if (order.status === 20) { // 服务中
+ order.buttons.push('unpay');
+ order.buttons.push('confirm');
+ }
+ if (order.status === 0) { // 取消订单 / 发起支付
+ order.buttons.push('detail');
+ order.buttons.push('invite');
+ }
+ if (order.status === 30) { // 已完成
+ order.buttons.push('detail');
+ order.buttons.push('invite');
+ }
+ if (order.status === 40) { // 取消订单
+ order.buttons.push('detail');
+ order.buttons.push('invite');
+ }
+
+}
+
+/**
+ * 处理订单的 button 操作按钮数组
+ *
+ * @param order 订单
+ */
+export function handleBlindOrderButtons(order, userId) {
+ order.buttons = []
+ if (order.status === 10) { // 待服务
+ order.buttons.push('detail');
+ order.buttons.push('agree');
+ //order.buttons.push('invite');
+ }
+ if (order.status === 20) { // 服务中
+ // 抢单后
+ if(order.workerUserId == userId){
+ order.buttons.push('unpay');
+ order.buttons.push('confirm');
+ }else{
+ order.buttons.push('other');
+ }
+ }
+ if (order.status === 0) { // 取消订单 / 发起支付
+ order.buttons.push('detail');
+ //order.buttons.push('invite');
+ }
+ if (order.status === 30) { // 已完成
+ order.buttons.push('detail');
+ if(order.workerUserId == userId){
+ order.buttons.push('invite2');
+ }
+ }
+ if (order.status === 40) { // 取消订单
+ order.buttons.push('detail');
+ //order.buttons.push('invite');
+ }
+
+}
+
+/**
+ * 处理订单的 button 操作按钮数组
+ *
+ * @param order 订单
+ */
+export function handleMyOrderButtons(order) {
+ order.buttons = []
+ if (order.type === 3) { // 查看拼团
+ order.buttons.push('combination');
+ }
+ if (order.status === 10) { // 待服务
+ order.buttons.push('unpay');
+ order.buttons.push('buy');
+ }
+ if (order.status === 20) { // 服务中
+ order.buttons.push('detail');
+ order.buttons.push('buy');
+ }
+ if (order.logisticsId > 0) { // 查看物流
+ order.buttons.push('express');
+ }
+ if (order.status === 0) { // 取消订单 / 发起支付
+ order.buttons.push('cancel');
+ order.buttons.push('pay');
+ }
+ if (order.status === 30 && !order.commentStatus) { // 发起评价
+ order.buttons.push('comment');
+ order.buttons.push('buy');
+ }
+ if (order.status === 30 && order.commentStatus) { // 发起评价
+ order.buttons.push('detail');
+ order.buttons.push('buy');
+ }
+ if (order.status === 40) { // 删除订单
+ //order.buttons.push('delete');
+ order.buttons.push('detail');
+ order.buttons.push('buy');
+ }
+}
+
+/**
+ * 格式化售后状态
+ *
+ * @param afterSale 售后
+ */
+export function formatAfterSaleStatus(afterSale) {
+ if (afterSale.status === 10) {
+ return '申请售后';
+ }
+ if (afterSale.status === 20) {
+ return '商品待退货';
+ }
+ if (afterSale.status === 30) {
+ return '商家待收货';
+ }
+ if (afterSale.status === 40) {
+ return '等待退款';
+ }
+ if (afterSale.status === 50) {
+ return '取消成功';
+ }
+ if (afterSale.status === 61) {
+ return '买家取消';
+ }
+ if (afterSale.status === 62) {
+ return '商家拒绝';
+ }
+ if (afterSale.status === 63) {
+ return '商家拒收货';
+ }
+ return '未知状态';
+}
+
+/**
+ * 格式化售后状态的描述
+ *
+ * @param afterSale 售后
+ */
+export function formatAfterSaleStatusDescription(afterSale) {
+ if (afterSale.status === 10) {
+ return '退款申请待商家处理';
+ }
+ if (afterSale.status === 20) {
+ return '请退货并填写物流信息';
+ }
+ if (afterSale.status === 30) {
+ return '退货退款申请待商家处理';
+ }
+ if (afterSale.status === 40) {
+ return '等待退款';
+ }
+ if (afterSale.status === 50) {
+ return '退款成功';
+ }
+ if (afterSale.status === 61) {
+ return '退款关闭';
+ }
+ if (afterSale.status === 62) {
+ return `商家不同意退款申请,拒绝原因:${afterSale.auditReason}`;
+ }
+ if (afterSale.status === 63) {
+ return `商家拒绝收货,不同意退款,拒绝原因:${afterSale.auditReason}`;
+ }
+ return '未知状态';
+}
+
+/**
+ * 处理售后的 button 操作按钮数组
+ *
+ * @param afterSale 售后
+ */
+export function handleAfterSaleButtons(afterSale) {
+ afterSale.buttons = [];
+ if ([10, 20, 30].includes(afterSale.status)) { // 取消订单
+ afterSale.buttons.push('cancel');
+ }
+ if (afterSale.status === 20) { // 退货信息
+ afterSale.buttons.push('delivery');
+ }
+}
+
+/**
+ * 倒计时
+ * @param toTime 截止时间
+ * @param fromTime 起始时间,默认当前时间
+ * @return {{s: string, ms: number, h: string, m: string}} 持续时间
+ */
+export function useDurationTime(toTime, fromTime = '') {
+ toTime = getDayjsTime(toTime);
+ if (fromTime === '') {
+ fromTime = dayjs();
+ }
+ let duration = ref(toTime - fromTime);
+ if (duration.value > 0) {
+ setTimeout(() => {
+ if (duration.value > 0) {
+ duration.value -= 1000;
+ }
+ }, 1000);
+ }
+
+ let durationTime = dayjs.duration(duration.value);
+ return {
+ h: (durationTime.months() * 30 * 24 + durationTime.days() * 24 + durationTime.hours())
+ .toString()
+ .padStart(2, '0'),
+ m: durationTime.minutes().toString().padStart(2, '0'),
+ s: durationTime.seconds().toString().padStart(2, '0'),
+ ms: durationTime.$ms,
+ };
+}
+
+/**
+ * 转换为 Dayjs
+ * @param {any} time 时间
+ * @return {dayjs.Dayjs}
+ */
+function getDayjsTime(time) {
+ time = time.toString();
+ if (time.indexOf('-') > 0) {
+ // 'date'
+ return dayjs(time);
+ }
+ if (time.length > 10) {
+ // 'timestamp'
+ return dayjs(parseInt(time));
+ }
+ if (time.length === 10) {
+ // 'unixTime'
+ return dayjs.unix(parseInt(time));
+ }
+}
+
+/**
+ * 将分转成元
+ *
+ * @param price 分,例如说 100 分
+ * @returns {string} 元,例如说 1.00 元
+ */
+export function fen2yuan(price) {
+ return (price / 100.0).toFixed(2)
+}
+
+/**
+ * 从商品 SKU 数组中,转换出商品属性的数组
+ *
+ * 类似结构:[{
+ * id: // 属性的编号
+ * name: // 属性的名字
+ * values: [{
+ * id: // 属性值的编号
+ * name: // 属性值的名字
+ * }]
+ * }]
+ *
+ * @param skus 商品 SKU 数组
+ */
+export function convertProductPropertyList(skus) {
+ let result = [];
+ for (const sku of skus) {
+ if (!sku.properties) {
+ continue
+ }
+ for (const property of sku.properties) {
+ // ① 先处理属性
+ let resultProperty = result.find(item => item.id === property.propertyId)
+ if (!resultProperty) {
+ resultProperty = {
+ id: property.propertyId,
+ name: property.propertyName,
+ values: []
+ }
+ result.push(resultProperty)
+ }
+ // ② 再处理属性值
+ let resultValue = resultProperty.values.find(item => item.id === property.valueId)
+ if (!resultValue) {
+ resultProperty.values.push({
+ id: property.valueId,
+ name: property.valueName
+ })
+ }
+ }
+ }
+ return result;
+}
+
+/**
+ * 格式化满减送活动的规则
+ *
+ * @param activity 活动信息
+ * @param rule 优惠规格
+ * @returns {string} 规格字符串
+ */
+export function formatRewardActivityRule(activity, rule) {
+ if (activity.conditionType === 10) {
+ return `满 ${fen2yuan(rule.limit)} 元减 ${fen2yuan(rule.discountPrice)} 元`;
+ }
+ if (activity.conditionType === 20) {
+ return `满 ${rule.limit} 件减 ${fen2yuan(rule.discountPrice)} 元`;
+ }
+ return '';
+}
diff --git a/sheep/hooks/useModal.js b/sheep/hooks/useModal.js
new file mode 100644
index 0000000..003fe80
--- /dev/null
+++ b/sheep/hooks/useModal.js
@@ -0,0 +1,141 @@
+import $store from '@/sheep/store';
+import $helper from '@/sheep/helper';
+import dayjs from 'dayjs';
+import { ref } from 'vue';
+import test from '@/sheep/helper/test.js';
+import AuthUtil from '@/sheep/api/member/auth';
+
+// 打开授权弹框
+export function showAuthModal(type = 'smsLogin') {
+ const modal = $store('modal');
+ if (modal.auth !== '') {
+ // 注意:延迟修改,保证下面的 closeAuthModal 先执行掉
+ setTimeout(() => {
+ modal.$patch((state) => {
+ state.auth = type;
+ });
+ }, 500);
+ closeAuthModal();
+ } else {
+ modal.$patch((state) => {
+ state.auth = type;
+ });
+ }
+}
+
+// 关闭授权弹框
+export function closeAuthModal() {
+ $store('modal').$patch((state) => {
+ state.auth = '';
+ });
+}
+
+// 打开分享弹框
+export function showShareModal() {
+ $store('modal').$patch((state) => {
+ state.share = true;
+ });
+}
+
+// 关闭分享弹框
+export function closeShareModal() {
+ $store('modal').$patch((state) => {
+ state.share = false;
+ });
+}
+
+// 打开快捷菜单
+export function showMenuTools() {
+ $store('modal').$patch((state) => {
+ state.menu = true;
+ });
+}
+
+// 关闭快捷菜单
+export function closeMenuTools() {
+ $store('modal').$patch((state) => {
+ state.menu = false;
+ });
+}
+
+// 发送短信验证码 60秒
+export function getSmsCode(event, mobile) {
+ const modalStore = $store('modal');
+ const lastSendTimer = modalStore.lastTimer[event];
+ if (typeof lastSendTimer === 'undefined') {
+ $helper.toast('短信发送事件错误');
+ return;
+ }
+
+ const duration = dayjs().unix() - lastSendTimer;
+ const canSend = duration >= 60;
+ if (!canSend) {
+ $helper.toast('请稍后再试');
+ return;
+ }
+ // 只有 mobile 非空时才校验。因为部分场景(修改密码),不需要输入手机
+ if (mobile && !test.mobile(mobile)) {
+ $helper.toast('手机号码格式不正确');
+ return;
+ }
+
+ // 发送验证码 + 更新上次发送验证码时间
+ let scene = -1;
+ switch (event) {
+ case 'resetPassword':
+ scene = 4;
+ break;
+ case 'changePassword':
+ scene = 3;
+ break;
+ case 'changeMobile':
+ scene = 2;
+ break;
+ case 'smsLogin':
+ scene = 1;
+ break;
+ }
+ AuthUtil.sendSmsCode(mobile, scene).then((res) => {
+ if (res.code === 0) {
+ modalStore.$patch((state) => {
+ state.lastTimer[event] = dayjs().unix();
+ });
+ }
+ });
+}
+
+// 获取短信验证码倒计时 -- 60秒
+export function getSmsTimer(event, mobile = '') {
+ const modalStore = $store('modal');
+ const lastSendTimer = modalStore.lastTimer[event];
+
+ if (typeof lastSendTimer === 'undefined') {
+ $helper.toast('短信发送事件错误');
+ return;
+ }
+
+ const duration = ref(dayjs().unix() - lastSendTimer - 60);
+ const canSend = duration.value >= 0;
+
+ if (canSend) {
+ return '获取验证码';
+ }
+
+ if (!canSend) {
+ setTimeout(() => {
+ duration.value++;
+ }, 1000);
+ return -duration.value.toString() + ' 秒';
+ }
+}
+
+// 记录广告弹框历史
+export function saveAdvHistory(adv) {
+ const modal = $store('modal');
+
+ modal.$patch((state) => {
+ if (!state.advHistory.includes(adv.imgUrl)) {
+ state.advHistory.push(adv.imgUrl);
+ }
+ });
+}
diff --git a/sheep/hooks/useWebSocket.js b/sheep/hooks/useWebSocket.js
new file mode 100644
index 0000000..c3980c4
--- /dev/null
+++ b/sheep/hooks/useWebSocket.js
@@ -0,0 +1,163 @@
+import { onBeforeUnmount, reactive, ref, getCurrentInstance } from 'vue';
+import { baseUrl, websocketPath } from '@/sheep/config';
+import { copyValueToTarget } from '@/sheep/util';
+
+/**
+ * WebSocket 创建 hook
+ * @param opt 连接配置
+ * @return {{options: *}}
+ */
+export function useWebSocket(opt) {
+ const { proxy } = getCurrentInstance();
+
+ const getAccessToken = () => {
+ return uni.getStorageSync('token');
+ };
+
+ const getUrl = () => {
+ return (baseUrl + websocketPath).replace('http', 'ws') + '?token=' + getAccessToken();
+ };
+
+ const options = reactive({
+ url: getUrl(), // ws 地址
+ isReconnecting: false, // 正在重新连接
+ reconnectInterval: 3000, // 重连间隔,单位毫秒
+ heartBeatInterval: 5000, // 心跳间隔,单位毫秒
+ pingTimeoutDuration: 1000, // 超过这个时间,后端没有返回pong,则判定后端断线了。
+ heartBeatTimer: null, // 心跳计时器
+ destroy: false, // 是否销毁
+ pingTimeout: null, // 心跳检测定时器
+ reconnectTimeout: null, // 重连定时器ID的属性
+ onConnected: () => {
+ }, // 连接成功时触发
+ onClosed: () => {
+ }, // 连接关闭时触发
+ onMessage: (data) => {
+ }, // 收到消息
+ });
+ const SocketTask = ref(null); // SocketTask 由 uni.connectSocket() 接口创建
+
+ const initEventListeners = () => {
+ // 监听 WebSocket 连接打开事件
+ SocketTask.value.onOpen(() => {
+ console.log('WebSocket 连接成功');
+ // 连接成功时触发
+ options.onConnected();
+ // 开启心跳检查
+ startHeartBeat();
+ });
+ // 监听 WebSocket 接受到服务器的消息事件
+ SocketTask.value.onMessage((res) => {
+ try {
+ if (res.data === 'pong') {
+ // 收到心跳重置心跳超时检查
+ resetPingTimeout();
+ } else {
+ options.onMessage(JSON.parse(res.data));
+ }
+ } catch (error) {
+ console.error(error);
+ }
+ });
+ // 监听 WebSocket 连接关闭事件
+ SocketTask.value.onClose((event) => {
+ // 情况一:实例销毁
+ if (options.destroy) {
+ options.onClosed();
+ } else { // 情况二:连接失败重连
+ // 停止心跳检查
+ stopHeartBeat();
+ // 重连
+ reconnect();
+ }
+ });
+ };
+
+ // 发送消息
+ const sendMessage = (message) => {
+ if (SocketTask.value && !options.destroy) {
+ SocketTask.value.send({ data: message });
+ }
+ };
+ // 开始心跳检查
+ const startHeartBeat = () => {
+ options.heartBeatTimer = setInterval(() => {
+ sendMessage('ping');
+ options.pingTimeout = setTimeout(() => {
+ // 如果在超时时间内没有收到 pong,则认为连接断开
+ reconnect();
+ }, options.pingTimeoutDuration);
+ }, options.heartBeatInterval);
+ };
+ // 停止心跳检查
+ const stopHeartBeat = () => {
+ clearInterval(options.heartBeatTimer);
+ resetPingTimeout();
+ };
+
+ // WebSocket 重连
+ const reconnect = () => {
+ if (options.destroy || !SocketTask.value) {
+ // 如果WebSocket已被销毁或尚未完全关闭,不进行重连
+ return;
+ }
+
+ // 重连中
+ options.isReconnecting = true;
+
+ // 清除现有的重连标志,以避免多次重连
+ if (options.reconnectTimeout) {
+ clearTimeout(options.reconnectTimeout);
+ }
+
+ // 设置重连延迟
+ options.reconnectTimeout = setTimeout(() => {
+ // 检查组件是否仍在运行和WebSocket是否关闭
+ if (!options.destroy) {
+ // 重置重连标志
+ options.isReconnecting = false;
+ // 初始化新的WebSocket连接
+ initSocket();
+ }
+ }, options.reconnectInterval);
+ };
+
+ const resetPingTimeout = () => {
+ if (options.pingTimeout) {
+ clearTimeout(options.pingTimeout);
+ options.pingTimeout = null; // 清除超时ID
+ }
+ };
+
+ const close = () => {
+ options.destroy = true;
+ stopHeartBeat();
+ if (options.reconnectTimeout) {
+ clearTimeout(options.reconnectTimeout);
+ }
+ if (SocketTask.value) {
+ SocketTask.value.close();
+ SocketTask.value = null;
+ }
+ };
+
+ const initSocket = () => {
+ options.destroy = false;
+ copyValueToTarget(options, opt);
+ SocketTask.value = uni.connectSocket({
+ url: getUrl(),
+ complete: () => {
+ },
+ success: () => {
+ },
+ });
+ initEventListeners();
+ };
+
+ initSocket();
+
+ onBeforeUnmount(() => {
+ close();
+ });
+ return { options };
+}
diff --git a/sheep/index.js b/sheep/index.js
new file mode 100644
index 0000000..f00fd29
--- /dev/null
+++ b/sheep/index.js
@@ -0,0 +1,61 @@
+import $url from '@/sheep/url';
+import $router from '@/sheep/router';
+import $platform from '@/sheep/platform';
+import $helper from '@/sheep/helper';
+import zIndex from '@/sheep/config/zIndex.js';
+import $store from '@/sheep/store';
+import dayjs from 'dayjs';
+import relativeTime from 'dayjs/plugin/relativeTime';
+import duration from 'dayjs/plugin/duration';
+import 'dayjs/locale/zh-cn';
+
+dayjs.locale('zh-cn');
+dayjs.extend(relativeTime);
+dayjs.extend(duration);
+
+const sheep = {
+ $store,
+ $url,
+ $router,
+ $platform,
+ $helper,
+ $zIndex: zIndex,
+};
+
+// 加载Shopro底层依赖
+export async function ShoproInit() {
+ // 应用初始化
+ await $store('app').init();
+ await $store('user').getTradeConfig();
+
+ // #ifdef MP
+ // 小程序场景值
+ const config = uni.getLaunchOptionsSync();
+ if(config.scene){
+ $store('sys').setScene(config.scene);
+ }
+ // #endif
+
+ // 平台初始化加载(各平台provider提供不同的加载流程)
+ $platform.load();
+
+ if (process.env.NODE_ENV === 'development') {
+ ShoproDebug();
+ }
+}
+
+// 开发模式
+function ShoproDebug() {
+ // 开发环境引入vconsole调试
+ // #ifdef H5
+ // import("vconsole").then(vconsole => {
+ // new vconsole.default();
+ // });
+ // #endif
+
+ // TODO 芋艿:可以打印路由
+ // 同步前端页面到后端
+ // console.log(ROUTES)
+}
+
+export default sheep;
diff --git a/sheep/libs/mplive-manifest-plugin.js b/sheep/libs/mplive-manifest-plugin.js
new file mode 100644
index 0000000..d1df9bf
--- /dev/null
+++ b/sheep/libs/mplive-manifest-plugin.js
@@ -0,0 +1,32 @@
+const fs = require('fs');
+
+const manifestPath = process.env.UNI_INPUT_DIR + '/manifest.json';
+
+let Manifest = fs.readFileSync(manifestPath, {
+ encoding: 'utf-8'
+});
+
+function mpliveMainfestPlugin(isOpen) {
+ if (process.env.UNI_PLATFORM !== 'mp-weixin') return;
+
+ const manifestData = JSON.parse(Manifest)
+
+ if (isOpen === '0') {
+ delete manifestData['mp-weixin'].plugins['live-player-plugin'];
+ }
+
+ if (isOpen === '1') {
+ manifestData['mp-weixin'].plugins['live-player-plugin'] = {
+ "version": "1.3.5",
+ "provider": "wx2b03c6e691cd7370"
+ }
+ }
+
+ Manifest = JSON.stringify(manifestData, null, 2)
+
+ fs.writeFileSync(manifestPath, Manifest, {
+ "flag": "w"
+ })
+}
+
+export default mpliveMainfestPlugin
diff --git a/sheep/libs/permission.js b/sheep/libs/permission.js
new file mode 100644
index 0000000..59f9413
--- /dev/null
+++ b/sheep/libs/permission.js
@@ -0,0 +1,246 @@
+/// null = 未请求,1 = 已允许,0 = 拒绝|受限, 2 = 系统未开启
+
+var isIOS;
+
+function album() {
+ var result = 0;
+ var PHPhotoLibrary = plus.ios.import('PHPhotoLibrary');
+ var authStatus = PHPhotoLibrary.authorizationStatus();
+ if (authStatus === 0) {
+ result = null;
+ } else if (authStatus == 3) {
+ result = 1;
+ } else {
+ result = 0;
+ }
+ plus.ios.deleteObject(PHPhotoLibrary);
+ return result;
+}
+
+function camera() {
+ var result = 0;
+ var AVCaptureDevice = plus.ios.import('AVCaptureDevice');
+ var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide');
+ if (authStatus === 0) {
+ result = null;
+ } else if (authStatus == 3) {
+ result = 1;
+ } else {
+ result = 0;
+ }
+ plus.ios.deleteObject(AVCaptureDevice);
+ return result;
+}
+
+function location() {
+ var result = 0;
+ var cllocationManger = plus.ios.import('CLLocationManager');
+ var enable = cllocationManger.locationServicesEnabled();
+ var status = cllocationManger.authorizationStatus();
+ if (!enable) {
+ result = 2;
+ } else if (status === 0) {
+ result = null;
+ } else if (status === 3 || status === 4) {
+ result = 1;
+ } else {
+ result = 0;
+ }
+ plus.ios.deleteObject(cllocationManger);
+ return result;
+}
+
+function push() {
+ var result = 0;
+ var UIApplication = plus.ios.import('UIApplication');
+ var app = UIApplication.sharedApplication();
+ var enabledTypes = 0;
+ if (app.currentUserNotificationSettings) {
+ var settings = app.currentUserNotificationSettings();
+ enabledTypes = settings.plusGetAttribute('types');
+ if (enabledTypes == 0) {
+ result = 0;
+ console.log('推送权限没有开启');
+ } else {
+ result = 1;
+ console.log('已经开启推送功能!');
+ }
+ plus.ios.deleteObject(settings);
+ } else {
+ enabledTypes = app.enabledRemoteNotificationTypes();
+ if (enabledTypes == 0) {
+ result = 3;
+ console.log('推送权限没有开启!');
+ } else {
+ result = 4;
+ console.log('已经开启推送功能!');
+ }
+ }
+ plus.ios.deleteObject(app);
+ plus.ios.deleteObject(UIApplication);
+ return result;
+}
+
+function contact() {
+ var result = 0;
+ var CNContactStore = plus.ios.import('CNContactStore');
+ var cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0);
+ if (cnAuthStatus === 0) {
+ result = null;
+ } else if (cnAuthStatus == 3) {
+ result = 1;
+ } else {
+ result = 0;
+ }
+ plus.ios.deleteObject(CNContactStore);
+ return result;
+}
+
+function record() {
+ var result = null;
+ var avaudiosession = plus.ios.import('AVAudioSession');
+ var avaudio = avaudiosession.sharedInstance();
+ var status = avaudio.recordPermission();
+ console.log('permissionStatus:' + status);
+ if (status === 1970168948) {
+ result = null;
+ } else if (status === 1735552628) {
+ result = 1;
+ } else {
+ result = 0;
+ }
+ plus.ios.deleteObject(avaudiosession);
+ return result;
+}
+
+function calendar() {
+ var result = null;
+ var EKEventStore = plus.ios.import('EKEventStore');
+ var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0);
+ if (ekAuthStatus == 3) {
+ result = 1;
+ console.log('日历权限已经开启');
+ } else {
+ console.log('日历权限没有开启');
+ }
+ plus.ios.deleteObject(EKEventStore);
+ return result;
+}
+
+function memo() {
+ var result = null;
+ var EKEventStore = plus.ios.import('EKEventStore');
+ var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1);
+ if (ekAuthStatus == 3) {
+ result = 1;
+ console.log('备忘录权限已经开启');
+ } else {
+ console.log('备忘录权限没有开启');
+ }
+ plus.ios.deleteObject(EKEventStore);
+ return result;
+}
+
+function requestIOS(permissionID) {
+ return new Promise((resolve, reject) => {
+ switch (permissionID) {
+ case 'push':
+ resolve(push());
+ break;
+ case 'location':
+ resolve(location());
+ break;
+ case 'record':
+ resolve(record());
+ break;
+ case 'camera':
+ resolve(camera());
+ break;
+ case 'album':
+ resolve(album());
+ break;
+ case 'contact':
+ resolve(contact());
+ break;
+ case 'calendar':
+ resolve(calendar());
+ break;
+ case 'memo':
+ resolve(memo());
+ break;
+ default:
+ resolve(0);
+ break;
+ }
+ });
+}
+
+function requestAndroid(permissionID) {
+ return new Promise((resolve, reject) => {
+ plus.android.requestPermissions(
+ [permissionID],
+ function (resultObj) {
+ var result = 0;
+ for (var i = 0; i < resultObj.granted.length; i++) {
+ var grantedPermission = resultObj.granted[i];
+ console.log('已获取的权限:' + grantedPermission);
+ result = 1;
+ }
+ for (var i = 0; i < resultObj.deniedPresent.length; i++) {
+ var deniedPresentPermission = resultObj.deniedPresent[i];
+ console.log('拒绝本次申请的权限:' + deniedPresentPermission);
+ result = 0;
+ }
+ for (var i = 0; i < resultObj.deniedAlways.length; i++) {
+ var deniedAlwaysPermission = resultObj.deniedAlways[i];
+ console.log('永久拒绝申请的权限:' + deniedAlwaysPermission);
+ result = -1;
+ }
+ resolve(result);
+ },
+ function (error) {
+ console.log('result error: ' + error.message);
+ resolve({
+ code: error.code,
+ message: error.message,
+ });
+ },
+ );
+ });
+}
+
+function gotoAppPermissionSetting() {
+ if (permission.isIOS) {
+ var UIApplication = plus.ios.import('UIApplication');
+ var application2 = UIApplication.sharedApplication();
+ var NSURL2 = plus.ios.import('NSURL');
+ var setting2 = NSURL2.URLWithString('app-settings:');
+ application2.openURL(setting2);
+ plus.ios.deleteObject(setting2);
+ plus.ios.deleteObject(NSURL2);
+ plus.ios.deleteObject(application2);
+ } else {
+ var Intent = plus.android.importClass('android.content.Intent');
+ var Settings = plus.android.importClass('android.provider.Settings');
+ var Uri = plus.android.importClass('android.net.Uri');
+ var mainActivity = plus.android.runtimeMainActivity();
+ var intent = new Intent();
+ intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ var uri = Uri.fromParts('package', mainActivity.getPackageName(), null);
+ intent.setData(uri);
+ mainActivity.startActivity(intent);
+ }
+}
+
+const permission = {
+ get isIOS() {
+ return typeof isIOS === 'boolean'
+ ? isIOS
+ : (isIOS = uni.getSystemInfoSync().platform === 'ios');
+ },
+ requestIOS: requestIOS,
+ requestAndroid: requestAndroid,
+ gotoAppSetting: gotoAppPermissionSetting,
+};
+
+export default permission;
diff --git a/sheep/libs/sdk-h5-weixin.js b/sheep/libs/sdk-h5-weixin.js
new file mode 100644
index 0000000..984b8db
--- /dev/null
+++ b/sheep/libs/sdk-h5-weixin.js
@@ -0,0 +1,184 @@
+/**
+ * 本模块封装微信浏览器下的一些方法。
+ * 更多微信网页开发sdk方法,详见:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html
+ * 有 the permission value is offline verifying 报错请参考 @see https://segmentfault.com/a/1190000042289419 解决
+ */
+
+import jweixin from 'weixin-js-sdk';
+import $helper from '@/sheep/helper';
+import AuthUtil from '@/sheep/api/member/auth';
+
+let configSuccess = false;
+
+export default {
+ // 判断是否在微信中
+ isWechat() {
+ const ua = window.navigator.userAgent.toLowerCase();
+ // noinspection EqualityComparisonWithCoercionJS
+ return ua.match(/micromessenger/i) == 'micromessenger';
+ },
+
+ isReady(api) {
+ jweixin.ready(api);
+ },
+
+ // 初始化 JSSDK
+ async init(callback) {
+ if (!this.isWechat()) {
+ $helper.toast('请使用微信网页浏览器打开');
+ return;
+ }
+
+ // 调用后端接口,获得 JSSDK 初始化所需的签名
+ const url = location.href.split('#')[0];
+ const { code, data } = await AuthUtil.createWeixinMpJsapiSignature(url);
+ if (code === 0) {
+ jweixin.config({
+ debug: false,
+ appId: data.appId,
+ timestamp: data.timestamp,
+ nonceStr: data.nonceStr,
+ signature: data.signature,
+ jsApiList: ['chooseWXPay', 'openLocation', 'getLocation','updateTimelineShareData','scanQRCode'], // TODO 芋艿:后续可以设置更多权限;
+ openTagList: data.openTagList
+ });
+ }
+
+ // 监听结果
+ configSuccess = true;
+ jweixin.error((err) => {
+ configSuccess = false;
+ console.error('微信 JSSDK 初始化失败', err);
+ // $helper.toast('微信JSSDK:' + err.errMsg);
+ });
+ jweixin.ready(() => {
+ if (configSuccess) {
+ console.log('微信 JSSDK 初始化成功');
+ }
+ })
+
+ // 回调
+ if (callback) {
+ callback(data);
+ }
+ },
+
+ //在需要定位页面调用 TODO 芋艿:未测试
+ getLocation(callback) {
+ this.isReady(() => {
+ jweixin.getLocation({
+ type: 'gcj02', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02'
+ success: function (res) {
+ callback(res);
+ },
+ fail: function (res) {
+ console.log('%c微信H5sdk,getLocation失败:', 'color:green;background:yellow');
+ },
+ });
+ });
+ },
+
+ // 获取微信收货地址
+ openAddress(callback) {
+ this.isReady(() => {
+ jweixin.openAddress({
+ success: function (res) {
+ callback.success && callback.success(res);
+ },
+ fail: function (err) {
+ callback.error && callback.error(err);
+ console.log('%c微信H5sdk,openAddress失败:', 'color:green;background:yellow');
+ },
+ complete: function (res) {},
+ });
+ });
+ },
+
+ // 微信扫码 TODO 芋艿:未测试
+ scanQRCode(callback) {
+ this.isReady(() => {
+ jweixin.scanQRCode({
+ needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
+ scanType: ['qrCode', 'barCode'], // 可以指定扫二维码还是一维码,默认二者都有
+ success: function (res) {
+ callback(res);
+ },
+ fail: function (res) {
+ console.log('%c微信H5sdk,scanQRCode失败:', 'color:green;background:yellow');
+ },
+ });
+ });
+ },
+
+ // 更新微信分享信息 TODO 芋艿:未测试
+ updateShareInfo(data, callback = null) {
+ this.isReady(() => {
+ const shareData = {
+ title: data.title,
+ desc: data.desc,
+ link: data.link,
+ imgUrl: data.image,
+ success: function (res) {
+ if (callback) {
+ callback(res);
+ }
+ // 分享后的一些操作,比如分享统计等等
+ },
+ cancel: function (res) {},
+ };
+
+ // 新版 分享聊天api
+ jweixin.updateAppMessageShareData(shareData);
+ // 新版 分享到朋友圈api
+ jweixin.updateTimelineShareData(shareData);
+ });
+ },
+
+ // 打开坐标位置 TODO 芋艿:未测试
+ openLocation(data, callback) {
+ this.isReady(() => {
+ jweixin.openLocation({
+ ...data,
+ success: function (res) {
+ console.log(res);
+ }
+ });
+ });
+ },
+
+ // 选择图片 TODO 芋艿:未测试
+ chooseImage(callback) {
+ this.isReady(() => {
+ jweixin.chooseImage({
+ count: 1,
+ sizeType: ['compressed'],
+ sourceType: ['album'],
+ success: function (rs) {
+ callback(rs);
+ },
+ });
+ });
+ },
+
+ // 微信支付
+ wxpay(data, callback) {
+ this.isReady(() => {
+ jweixin.chooseWXPay({
+ timestamp: data.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
+ nonceStr: data.nonceStr, // 支付签名随机串,不长于 32 位
+ package: data.packageValue, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
+ signType: data.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
+ paySign: data.paySign, // 支付签名
+ success: function (res) {
+ callback.success && callback.success(res);
+ },
+ fail: function (err) {
+ callback.fail && callback.fail(err);
+ },
+ cancel: function (err) {
+ callback.cancel && callback.cancel(err);
+ },
+ });
+ });
+ },
+};
diff --git a/sheep/platform/index.js b/sheep/platform/index.js
new file mode 100644
index 0000000..50e4b8a
--- /dev/null
+++ b/sheep/platform/index.js
@@ -0,0 +1,175 @@
+/**
+ * Shopro 第三方平台功能聚合
+ * @version 1.0.3
+ * @author lidongtony
+ * @param {String} name - 厂商+平台名称
+ * @param {String} provider - 厂商
+ * @param {String} platform - 平台名称
+ * @param {String} os - 系统型号
+ * @param {Object} device - 设备信息
+ */
+
+import { isEmpty } from 'lodash-es';
+// #ifdef H5
+import { isWxBrowser } from '@/sheep/helper/utils';
+// #endif
+import wechat from './provider/wechat/index.js';
+import apple from './provider/apple';
+import share from './share';
+import Pay from './pay';
+
+const device = uni.getSystemInfoSync();
+
+const os = device.platform;
+
+let name = '';
+let provider = '';
+let platform = '';
+let isWechatInstalled = true;
+
+// #ifdef H5
+if (isWxBrowser()) {
+ name = 'WechatOfficialAccount';
+ provider = 'wechat';
+ platform = 'officialAccount';
+} else {
+ name = 'H5';
+ platform = 'h5';
+}
+// #endif
+
+// #ifdef APP-PLUS
+name = 'App';
+platform = 'openPlatform';
+// 检查微信客户端是否安装,否则AppleStore会因此拒绝上架
+if (os === 'ios') {
+ isWechatInstalled = plus.ios.import('WXApi').isWXAppInstalled();
+}
+// #endif
+
+// #ifdef MP-WEIXIN
+name = 'WechatMiniProgram';
+platform = 'miniProgram';
+provider = 'wechat';
+// #endif
+
+if (isEmpty(name)) {
+ uni.showToast({
+ title: '暂不支持该平台',
+ icon: 'none',
+ });
+}
+
+// 加载当前平台前置行为
+const load = () => {
+ if (provider === 'wechat') {
+ wechat.load();
+ }
+};
+
+// 使用厂商独占sdk name = 'wechat' | 'alipay' | 'apple'
+const useProvider = (_provider = '') => {
+ if (_provider === '') _provider = provider;
+ if (_provider === 'wechat') return wechat;
+ if (_provider === 'apple') return apple;
+};
+
+// 支付服务转发
+const pay = (payment, orderType, orderSN, flag) => {
+ return new Pay(payment, orderType, orderSN, flag);
+};
+
+/**
+ * 检查更新 (只检查小程序和App)
+ * @param {Boolean} silence - 静默检查
+ */
+const checkUpdate = (silence = false) => {
+ let canUpdate;
+ // #ifdef MP-WEIXIN
+ useProvider().checkUpdate(silence);
+ // #endif
+
+ // #ifdef APP-PLUS
+ // TODO: 热更新
+ // #endif
+};
+
+/**
+ * 检查网络
+ * @param {Boolean} silence - 静默检查
+ */
+async function checkNetwork() {
+ const networkStatus = await uni.getNetworkType();
+ if (networkStatus.networkType == 'none') {
+ return Promise.resolve(false);
+ }
+ return Promise.resolve(true);
+}
+
+// 获取小程序胶囊信息
+const getCapsule = () => {
+ // #ifdef MP
+ let capsule = uni.getMenuButtonBoundingClientRect();
+ if (!capsule) {
+ capsule = {
+ bottom: 56,
+ height: 32,
+ left: 278,
+ right: 365,
+ top: 24,
+ width: 87,
+ };
+ }
+ return capsule;
+ // #endif
+
+ // #ifndef MP
+ return {
+ bottom: 56,
+ height: 32,
+ left: 278,
+ right: 365,
+ top: 24,
+ width: 87,
+ };
+ // #endif
+};
+
+const capsule = getCapsule();
+
+// 标题栏高度
+const getNavBar = () => {
+ return device.statusBarHeight + 44;
+};
+const navbar = getNavBar();
+
+function getLandingPage() {
+ let page = '';
+ // #ifdef H5
+ page = location.href.split('?')[0];
+ // #endif
+ return page;
+}
+
+// 设置ios+公众号网页落地页 解决微信sdk签名问题
+const landingPage = getLandingPage();
+
+const _platform = {
+ name,
+ device,
+ os,
+ provider,
+ platform,
+ useProvider,
+ checkUpdate,
+ checkNetwork,
+ pay,
+ share,
+ load,
+ capsule,
+ navbar,
+ landingPage,
+ isWechatInstalled,
+};
+
+export default _platform;
diff --git a/sheep/platform/pay.js b/sheep/platform/pay.js
new file mode 100644
index 0000000..9f6206b
--- /dev/null
+++ b/sheep/platform/pay.js
@@ -0,0 +1,372 @@
+import sheep from '@/sheep';
+// #ifdef H5
+import $wxsdk from '@/sheep/libs/sdk-h5-weixin';
+// #endif
+import { getRootUrl } from '@/sheep/helper';
+import PayOrderApi from '@/sheep/api/pay/order';
+
+/**
+ * 支付
+ *
+ * @param {String} payment = ['wechat','alipay','wallet','mock'] - 支付方式
+ * @param {String} orderType = ['goods','recharge','groupon'] - 订单类型
+ * @param {String} id - 订单号
+ */
+
+export default class SheepPay {
+ constructor(payment, orderType, id, flag) {
+ this.payment = payment;
+ this.id = id;
+ this.orderType = orderType;
+ this.flag = flag;
+ this.payAction();
+ }
+
+ payAction() {
+ const payAction = {
+ WechatOfficialAccount: {
+ wechat: () => {
+ this.wechatOfficialAccountPay();
+ },
+ alipay: () => {
+ this.redirectPay(); // 现在公众号可以直接跳转支付宝页面
+ },
+ wallet: () => {
+ this.walletPay();
+ },
+ mock: () => {
+ this.mockPay();
+ }
+ },
+ WechatMiniProgram: {
+ wechat: () => {
+ this.wechatMiniProgramPay();
+ },
+ alipay: () => {
+ this.copyPayLink();
+ },
+ wallet: () => {
+ this.walletPay();
+ },
+ mock: () => {
+ this.mockPay();
+ }
+ },
+ App: {
+ wechat: () => {
+ this.wechatAppPay();
+ },
+ alipay: () => {
+ this.alipay();
+ },
+ wallet: () => {
+ this.walletPay();
+ },
+ mock: () => {
+ this.mockPay();
+ }
+ },
+ H5: {
+ wechat: () => {
+ this.wechatWapPay();
+ },
+ alipay: () => {
+ this.redirectPay();
+ },
+ wallet: () => {
+ this.walletPay();
+ },
+ mock: () => {
+ this.mockPay();
+ }
+ },
+ };
+ return payAction[sheep.$platform.name][this.payment]();
+ }
+
+ // 预支付
+ prepay(channel) {
+ return new Promise(async (resolve, reject) => {
+ let data = {
+ id: this.id,
+ channelCode: channel,
+ channelExtras: {}
+ };
+ // 特殊逻辑:微信公众号、小程序支付时,必须传入 openid
+ if (['wx_pub', 'wx_lite'].includes(channel)) {
+ const openid = await sheep.$platform.useProvider('wechat').getOpenid();
+ // 如果获取不到 openid,微信无法发起支付,此时需要引导
+ if (!openid) {
+ this.bindWeixin();
+ return;
+ }
+ data.channelExtras.openid = openid;
+ }
+ // 发起预支付 API 调用
+ PayOrderApi.submitOrder(data).then((res) => {
+ // 成功时
+ res.code === 0 && resolve(res);
+ // 失败时
+ if (res.code !== 0 && res.msg.indexOf('无效的openid') >= 0) {
+ // 特殊逻辑:微信公众号、小程序支付时,必须传入 openid 不正确的情况
+ if (res.msg.indexOf('无效的openid') >= 0 // 获取的 openid 不正确时,或者随便输入了个 openid
+ || res.msg.indexOf('下单账号与支付账号不一致') >= 0) { // https://developers.weixin.qq.com/community/develop/doc/00008c53c347804beec82aed051c00
+ this.bindWeixin();
+ }
+ }
+ });
+ });
+ }
+ // #ifdef H5
+ // 微信公众号 JSSDK 支付
+ async wechatOfficialAccountPay() {
+ let { code, data } = await this.prepay('wx_pub');
+ if (code !== 0) {
+ return;
+ }
+ const payConfig = JSON.parse(data.displayContent);
+ $wxsdk.wxpay(payConfig, {
+ success: () => {
+ this.payResult('success');
+ },
+ cancel: () => {
+ sheep.$helper.toast('支付已手动取消');
+ },
+ fail: (error) => {
+ if (error.errMsg.indexOf('chooseWXPay:没有此SDK或暂不支持此SDK模拟') >= 0) {
+ sheep.$helper.toast('发起微信支付失败,原因:可能是微信开发者工具不支持,建议使用微信打开网页后支付');
+ return
+ }
+ this.payResult('fail');
+ },
+ });
+ }
+
+ // 浏览器微信 H5 支付 TODO 芋艿:待接入
+ async wechatWapPay() {
+ const { error, data } = await this.prepay();
+ if (error === 0) {
+ const redirect_url = `${getRootUrl()}pages/pay/result?id=${this.id}&payment=${this.payment}&orderType=${this.orderType}`;
+ location.href = `${data.pay_data.h5_url}&redirect_url=${encodeURIComponent(redirect_url)}`;
+ }
+ }
+
+ // 支付链接 TODO 芋艿:待接入
+ async redirectPay() {
+ let { error, data } = await this.prepay();
+ if (error === 0) {
+ const redirect_url = `${getRootUrl()}pages/pay/result?id=${this.id}&payment=${this.payment}&orderType=${this.orderType}`;
+ location.href = data.pay_data + encodeURIComponent(redirect_url);
+ }
+ }
+
+ // #endif
+
+ // 微信小程序支付
+ async wechatMiniProgramPay() {
+ // let that = this;
+ let { code, data } = await this.prepay('wx_lite');
+ if (code !== 0) {
+ return;
+ }
+ // 调用微信小程序支付
+ const payConfig = JSON.parse(data.displayContent);
+ uni.requestPayment({
+ provider: 'wxpay',
+ timeStamp: payConfig.timeStamp,
+ nonceStr: payConfig.nonceStr,
+ package: payConfig.packageValue,
+ signType: payConfig.signType,
+ paySign: payConfig.paySign,
+ success: (res) => {
+ this.payResult('success');
+ },
+ fail: (err) => {
+ if (err.errMsg === 'requestPayment:fail cancel') {
+ sheep.$helper.toast('支付已手动取消');
+ } else {
+ this.payResult('fail');
+ }
+ },
+ });
+ }
+
+ // 余额支付
+ async walletPay() {
+ const { code } = await this.prepay('wallet');
+ code === 0 && this.payResult('success');
+ }
+
+ // 模拟支付
+ async mockPay() {
+ const { code } = await this.prepay('mock');
+ code === 0 && this.payResult('success');
+ }
+
+ // 支付宝复制链接支付 TODO 芋艿:待接入
+ async copyPayLink() {
+ let that = this;
+ let { error, data } = await this.prepay();
+ if (error === 0) {
+ // 引入showModal 点击确认 复制链接;
+ uni.showModal({
+ title: '支付宝支付',
+ content: '复制链接到外部浏览器',
+ confirmText: '复制链接',
+ success: (res) => {
+ if (res.confirm) {
+ sheep.$helper.copyText(data.pay_data);
+ }
+ },
+ });
+ }
+ }
+
+ // 支付宝支付 TODO 芋艿:待接入
+ async alipay() {
+ let that = this;
+ const { error, data } = await this.prepay();
+ if (error === 0) {
+ uni.requestPayment({
+ provider: 'alipay',
+ orderInfo: data.pay_data, //支付宝订单数据
+ success: (res) => {
+ that.payResult('success');
+ },
+ fail: (err) => {
+ if (err.errMsg === 'requestPayment:fail [paymentAlipay:62001]user cancel') {
+ sheep.$helper.toast('支付已手动取消');
+ } else {
+ that.payResult('fail');
+ }
+ },
+ });
+ }
+ }
+
+ // 微信支付 TODO 芋艿:待接入
+ async wechatAppPay() {
+ let that = this;
+ let { error, data } = await this.prepay();
+ if (error === 0) {
+ uni.requestPayment({
+ provider: 'wxpay',
+ orderInfo: data.pay_data, //微信订单数据(官方说是string。实测为object)
+ success: (res) => {
+ that.payResult('success');
+ },
+ fail: (err) => {
+ err.errMsg !== 'requestPayment:fail cancel' && that.payResult('fail');
+ },
+ });
+ }
+ }
+
+ // 支付结果跳转,success:成功,fail:失败
+ payResult(resultType) {
+ if(this.flag == 'worker'){
+ sheep.$router.redirect('/pages/pay/worker/result', {
+ id: this.id,
+ orderType: this.orderType,
+ payState: resultType
+ });
+ }else if(this.flag == 'reward'){
+ sheep.$helper.toast('打赏成功');
+ uni.navigateBack();
+ }else if(this.flag == 'point'){
+ sheep.$router.redirect('/pages/point/result', {
+ id: this.id,
+ orderType: this.orderType,
+ payState: resultType
+ });
+ }else if(this.flag == 'vip'){
+ sheep.$helper.toast('开通成功');
+ sheep.$router.redirect('/pages/user/vip');
+ }else {
+ sheep.$router.redirect('/pages/pay/result', {
+ id: this.id,
+ orderType: this.orderType,
+ payState: resultType
+ });
+ }
+ }
+
+ // 引导绑定微信
+ bindWeixin() {
+ uni.showModal({
+ title: '微信支付',
+ content: '请先绑定微信再使用微信支付',
+ success: function (res) {
+ if (res.confirm) {
+ sheep.$platform.useProvider('wechat').bind();
+ }
+ },
+ });
+ }
+
+}
+
+export function getPayMethods(channels) {
+ const payMethods = [
+ {
+ icon: '/static/img/shop/pay/wechat.png',
+ title: '微信支付',
+ value: 'wechat',
+ disabled: true,
+ },
+ {
+ icon: '/static/img/shop/pay/alipay.png',
+ title: '支付宝支付',
+ value: 'alipay',
+ disabled: true,
+ },
+ {
+ icon: '/static/img/shop/pay/wallet.png',
+ title: '余额支付',
+ value: 'wallet',
+ disabled: true,
+ },
+ {
+ icon: '/static/img/shop/pay/apple.png',
+ title: 'Apple Pay',
+ value: 'apple',
+ disabled: true,
+ },
+ {
+ icon: '/static/img/shop/pay/wallet.png',
+ title: '模拟支付',
+ value: 'mock',
+ disabled: true,
+ }
+ ];
+ const platform = sheep.$platform.name
+
+ // 1. 处理【微信支付】
+ const wechatMethod = payMethods[0];
+ if ((platform === 'WechatOfficialAccount' && channels.includes('wx_pub'))
+ || (platform === 'WechatMiniProgram' && channels.includes('wx_lite'))
+ || (platform === 'H5' && channels.includes('wx_pub'))
+ || (platform === 'App' && channels.includes('wx_app'))) {
+ wechatMethod.disabled = false;
+ }
+
+ // 2. 处理【支付宝支付】
+ const alipayMethod = payMethods[1];
+ if ((platform === 'WechatOfficialAccount' && channels.includes('alipay_wap'))
+ || platform === 'WechatMiniProgram' && channels.includes('alipay_wap')
+ || platform === 'App' && channels.includes('alipay_app')) {
+ alipayMethod.disabled = false;
+ }
+ // 3. 处理【余额支付】
+ const walletMethod = payMethods[2];
+ if (channels.includes('wallet')) {
+ walletMethod.disabled = false;
+ }
+ // 4. 处理【苹果支付】TODO 芋艿:未来接入
+ // 5. 处理【模拟支付】
+ const mockMethod = payMethods[4];
+ if (channels.includes('mock')) {
+ mockMethod.disabled = false;
+ }
+ return payMethods;
+}
\ No newline at end of file
diff --git a/sheep/platform/provider/apple/app.js b/sheep/platform/provider/apple/app.js
new file mode 100644
index 0000000..c1c9149
--- /dev/null
+++ b/sheep/platform/provider/apple/app.js
@@ -0,0 +1,36 @@
+// import third from '@/sheep/api/third';
+// TODO 芋艿:等后面搞 App 再弄
+
+const login = () => {
+ return new Promise(async (resolve, reject) => {
+ const loginRes = await uni.login({
+ provider: 'apple',
+ success: () => {
+ uni.getUserInfo({
+ provider: 'apple',
+ success: async (res) => {
+ if (res.errMsg === 'getUserInfo:ok') {
+ const payload = res.userInfo;
+ const { error } = await third.apple.login({
+ payload,
+ shareInfo: uni.getStorageSync('shareLog') || {},
+ });
+ if (error === 0) {
+ resolve(true);
+ } else {
+ resolve(false);
+ }
+ }
+ },
+ });
+ },
+ fail: (err) => {
+ resolve(false);
+ },
+ });
+ });
+};
+
+export default {
+ login,
+};
diff --git a/sheep/platform/provider/apple/index.js b/sheep/platform/provider/apple/index.js
new file mode 100644
index 0000000..388c093
--- /dev/null
+++ b/sheep/platform/provider/apple/index.js
@@ -0,0 +1,9 @@
+// #ifdef APP-PLUS
+import service from './app';
+// #endif
+
+let apple = {};
+if (typeof service !== 'undefined') {
+ apple = service;
+}
+export default apple;
diff --git a/sheep/platform/provider/wechat/index.js b/sheep/platform/provider/wechat/index.js
new file mode 100644
index 0000000..3bb2c7f
--- /dev/null
+++ b/sheep/platform/provider/wechat/index.js
@@ -0,0 +1,15 @@
+// #ifdef H5
+import service from './officialAccount';
+// #endif
+
+// #ifdef MP-WEIXIN
+import service from './miniProgram';
+// #endif
+
+// #ifdef APP-PLUS
+import service from './openPlatform';
+// #endif
+
+const wechat = service;
+
+export default wechat;
diff --git a/sheep/platform/provider/wechat/miniProgram.js b/sheep/platform/provider/wechat/miniProgram.js
new file mode 100644
index 0000000..5e95eda
--- /dev/null
+++ b/sheep/platform/provider/wechat/miniProgram.js
@@ -0,0 +1,213 @@
+import AuthUtil from '@/sheep/api/member/auth';
+import SocialApi from '@/sheep/api/member/social';
+import UserApi from '@/sheep/api/member/user';
+
+const socialType = 34; // 社交类型 - 微信小程序
+
+let subscribeEventList = [];
+
+// 加载微信小程序
+function load() {
+ checkUpdate();
+ getSubscribeTemplate();
+}
+
+// 微信小程序静默授权登陆
+const login = async () => {
+ return new Promise(async (resolve, reject) => {
+ // 1. 获得微信 code
+ const codeResult = await uni.login();
+ if (codeResult.errMsg !== 'login:ok') {
+ return resolve(false);
+ }
+
+ // 2. 社交登录
+ const loginResult = await AuthUtil.socialLogin(socialType, codeResult.code, 'default');
+ if (loginResult.code === 0) {
+ setOpenid(loginResult.data.openid);
+ return resolve(true);
+ } else {
+ return resolve(false);
+ }
+ });
+};
+
+// 微信小程序手机号授权登陆
+const mobileLogin = async (e) => {
+ return new Promise(async (resolve, reject) => {
+ if (e.errMsg !== 'getPhoneNumber:ok') {
+ return resolve(false);
+ }
+
+ // 1. 获得微信 code
+ const codeResult = await uni.login();
+ if (codeResult.errMsg !== 'login:ok') {
+ return resolve(false);
+ }
+
+ // 2. 一键登录
+ const loginResult = await AuthUtil.weixinMiniAppLogin(e.code, codeResult.code, 'default');
+ if (loginResult.code === 0) {
+ setOpenid(loginResult.data.openid);
+ return resolve(true);
+ } else {
+ return resolve(false);
+ }
+ });
+};
+
+// 微信小程序绑定
+const bind = () => {
+ return new Promise(async (resolve, reject) => {
+ // 1. 获得微信 code
+ const codeResult = await uni.login();
+ if (codeResult.errMsg !== 'login:ok') {
+ return resolve(false);
+ }
+
+ // 2. 绑定账号
+ const bindResult = await SocialApi.socialBind(socialType, codeResult.code, 'default');
+ if (bindResult.code === 0) {
+ setOpenid(bindResult.data);
+ return resolve(true);
+ } else {
+ return resolve(false);
+ }
+ });
+};
+
+// 微信小程序解除绑定
+const unbind = async (openid) => {
+ const { code } = await SocialApi.socialUnbind(socialType, openid);
+ return code === 0;
+};
+
+// 绑定用户手机号
+const bindUserPhoneNumber = (e) => {
+ return new Promise(async (resolve, reject) => {
+ const { code } = await UserApi.updateUserMobileByWeixin(e.code);
+ if (code === 0) {
+ resolve(true);
+ }
+ resolve(false);
+ });
+};
+
+// 设置 openid 到本地存储,目前只有 pay 支付时会使用
+function setOpenid(openid) {
+ uni.setStorageSync('openid', openid);
+}
+
+// 获得 openid
+async function getOpenid(force = false) {
+ let openid = uni.getStorageSync('openid');
+ if (!openid && force) {
+ const info = await getInfo();
+ if (info && info.openid) {
+ openid = info.openid;
+ setOpenid(openid);
+ }
+ }
+ return openid;
+}
+
+// 获得社交信息
+async function getInfo() {
+ const { code, data } = await SocialApi.getSocialUser(socialType);
+ if (code !== 0) {
+ return undefined;
+ }
+ return data;
+}
+
+// ========== 非登录相关的逻辑 ==========
+
+// 小程序更新
+const checkUpdate = async (silence = true) => {
+ if (uni.canIUse('getUpdateManager')) {
+ const updateManager = uni.getUpdateManager();
+ updateManager.onCheckForUpdate(function(res) {
+ // 请求完新版本信息的回调
+ if (res.hasUpdate) {
+ updateManager.onUpdateReady(function() {
+ uni.showModal({
+ title: '更新提示',
+ content: '新版本已经准备好,是否重启应用?',
+ success: function(res) {
+ if (res.confirm) {
+ // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
+ updateManager.applyUpdate();
+ }
+ },
+ });
+ });
+ updateManager.onUpdateFailed(function() {
+ // 新的版本下载失败
+ // uni.showModal({
+ // title: '已经有新版本了哟~',
+ // content: '新版本已经上线啦,请您删除当前小程序,重新搜索打开~',
+ // });
+ });
+ } else {
+ if (!silence) {
+ uni.showModal({
+ title: '当前为最新版本',
+ showCancel: false,
+ });
+ }
+ }
+ });
+ }
+};
+
+// 获取订阅消息模板
+async function getSubscribeTemplate() {
+ const { code, data } = await SocialApi.getSubscribeTemplateList();
+ if (code === 0) {
+ subscribeEventList = data;
+ }
+}
+
+// 订阅消息
+function subscribeMessage(event, callback= undefined) {
+ let tmplIds = [];
+ if (typeof event === 'string') {
+ const temp = subscribeEventList.find(item => item.title.includes(event));
+ if (temp) {
+ tmplIds.push(temp.id);
+ }
+ }
+ if (typeof event === 'object') {
+ event.forEach((e) => {
+ const temp = subscribeEventList.find(item => item.title.includes(e));
+ if (temp) {
+ tmplIds.push(temp.id);
+ }
+ });
+ }
+ if (tmplIds.length === 0) return;
+
+ uni.requestSubscribeMessage({
+ tmplIds,
+ success: ()=>{
+ // 不管是拒绝还是同意都触发
+ callback && callback()
+ },
+ fail: (err) => {
+ console.log(err);
+ },
+ });
+}
+
+export default {
+ load,
+ login,
+ bind,
+ unbind,
+ bindUserPhoneNumber,
+ mobileLogin,
+ getInfo,
+ getOpenid,
+ subscribeMessage,
+ checkUpdate,
+};
diff --git a/sheep/platform/provider/wechat/officialAccount.js b/sheep/platform/provider/wechat/officialAccount.js
new file mode 100644
index 0000000..ed7beb3
--- /dev/null
+++ b/sheep/platform/provider/wechat/officialAccount.js
@@ -0,0 +1,106 @@
+import $wxsdk from '@/sheep/libs/sdk-h5-weixin';
+import { getRootUrl } from '@/sheep/helper';
+import AuthUtil from '@/sheep/api/member/auth';
+import SocialApi from '@/sheep/api/member/social';
+
+const socialType = 31; // 社交类型 - 微信公众号
+
+// 加载微信公众号JSSDK
+async function load() {
+ $wxsdk.init();
+}
+
+// 微信公众号登陆
+async function login(code = '', state = '') {
+ // 情况一:没有 code 时,去获取 code
+ if (!code) {
+ const loginUrl = await getLoginUrl();
+ if (loginUrl) {
+ uni.setStorageSync('returnUrl', location.href);
+ window.location = loginUrl;
+ }
+ // 情况二:有 code 时,使用 code 去自动登录
+ } else {
+ // 解密 code 发起登陆
+ const loginResult = await AuthUtil.socialLogin(socialType, code, state);
+ if (loginResult.code === 0) {
+ setOpenid(loginResult.data.openid);
+ return loginResult;
+ }
+ }
+ return false;
+}
+
+// 微信公众号绑定
+async function bind(code = '', state = '') {
+ // 情况一:没有 code 时,去获取 code
+ if (code === '') {
+ const loginUrl = await getLoginUrl('bind');
+ if (loginUrl) {
+ uni.setStorageSync('returnUrl', location.href);
+ window.location = loginUrl;
+ }
+ } else {
+ // 情况二:有 code 时,使用 code 去自动绑定
+ const loginResult = await SocialApi.socialBind(socialType, code, state);
+ if (loginResult.code === 0) {
+ setOpenid(loginResult.data);
+ return loginResult;
+ }
+ }
+ return false;
+}
+
+// 微信公众号解除绑定
+const unbind = async (openid) => {
+ const { code } = await SocialApi.socialUnbind(socialType, openid);
+ return code === 0;
+};
+
+// 获取公众号登陆地址
+async function getLoginUrl(event = 'login') {
+ const page = getRootUrl() + 'pages/index/login'
+ + '?event=' + event; // event 目的,区分是 login 还是 bind
+ const { code, data } = await AuthUtil.socialAuthRedirect(socialType, page);
+ if (code !== 0) {
+ return undefined;
+ }
+ return data;
+}
+
+// 设置 openid 到本地存储,目前只有 pay 支付时会使用
+function setOpenid(openid) {
+ uni.setStorageSync('openid', openid);
+}
+
+// 获得 openid
+async function getOpenid(force = false) {
+ let openid = uni.getStorageSync('openid');
+ if (!openid && force) {
+ const info = await getInfo();
+ if (info && info.openid) {
+ openid = info.openid;
+ setOpenid(openid);
+ }
+ }
+ return openid;
+}
+
+// 获得社交信息
+async function getInfo() {
+ const { code, data } = await SocialApi.getSocialUser(socialType);
+ if (code !== 0) {
+ return undefined;
+ }
+ return data;
+}
+
+export default {
+ load,
+ login,
+ bind,
+ unbind,
+ getInfo,
+ getOpenid,
+ jsWxSdk: $wxsdk,
+};
diff --git a/sheep/platform/provider/wechat/openPlatform.js b/sheep/platform/provider/wechat/openPlatform.js
new file mode 100644
index 0000000..a80f0d7
--- /dev/null
+++ b/sheep/platform/provider/wechat/openPlatform.js
@@ -0,0 +1,64 @@
+// 登录
+import third from '@/sheep/api/migration/third';
+import SocialApi from '@/sheep/api/member/social';
+import $share from '@/sheep/platform/share';
+
+// TODO 芋艿:等后面搞 App 再弄
+const socialType = 32; // 社交类型 - 微信开放平台
+
+const load = async () => {};
+
+// 微信开放平台移动应用授权登陆
+const login = () => {
+ return new Promise(async (resolve, reject) => {
+ const loginRes = await uni.login({
+ provider: 'weixin',
+ onlyAuthorize: true,
+ });
+ debugger
+ if (loginRes.errMsg == 'login:ok') {
+ // TODO third.wechat.login 函数未实现
+ const res = await third.wechat.login({
+ platform: 'openPlatform',
+ shareInfo: uni.getStorageSync('shareLog') || {},
+ payload: encodeURIComponent(
+ JSON.stringify({
+ code: loginRes.code,
+ }),
+ ),
+ });
+
+ if (res.error === 0) {
+ $share.bindBrokerageUser()
+ resolve(true);
+ }
+ } else {
+ uni.showToast({
+ icon: 'none',
+ title: loginRes.errMsg,
+ });
+ }
+ resolve(false);
+ });
+};
+
+// 微信 App 解除绑定
+const unbind = async (openid) => {
+ const { code } = await SocialApi.socialUnbind(socialType, openid);
+ return code === 0;
+};
+
+// 获得社交信息
+async function getInfo() {
+ const { code, data } = await SocialApi.getSocialUser(socialType);
+ if (code !== 0) {
+ return undefined;
+ }
+ return data;
+}
+
+export default {
+ load,
+ login,
+ getInfo
+};
diff --git a/sheep/platform/share.js b/sheep/platform/share.js
new file mode 100644
index 0000000..50f70bc
--- /dev/null
+++ b/sheep/platform/share.js
@@ -0,0 +1,207 @@
+import $store from '@/sheep/store';
+import $platform from '@/sheep/platform';
+import $router from '@/sheep/router';
+import $url from '@/sheep/url';
+import BrokerageApi from '@/sheep/api/trade/brokerage';
+// #ifdef H5
+import $wxsdk from '@/sheep/libs/sdk-h5-weixin';
+// #endif
+
+// 设置分享的平台渠道: 1=H5,2=微信公众号网页,3=微信小程序,4=App,...按需扩展
+const platformMap = ['H5', 'WechatOfficialAccount', 'WechatMiniProgram', 'App'];
+
+// 设置分享方式: 1=直接转发,2=海报,3=复制链接,...按需扩展
+const fromMap = ['forward', 'poster', 'link'];
+
+// TODO 芋艿:分享的接入
+// 设置分享信息参数
+const getShareInfo = (
+ scene = {
+ title: '', // 自定义分享标题
+ desc: '', // 自定义描述
+ image: '', // 自定义分享图片
+ params: {}, // 自定义分享参数
+ },
+ poster = {
+ // 自定义海报数据
+ type: 'user',
+ },
+) => {
+ const shareInfo = {
+ title: '', // 分享标题
+ desc: '', // 描述
+ image: '', // 分享图片
+ path: '', // 分享页面+参数
+ link: '', // 分享Url+参数
+ query: '', // 分享参数
+ poster, // 海报所需数据
+ };
+
+ const app = $store('app');
+ const shareConfig = app.platform.share;
+
+ // 自动拼接分享用户参数
+ const query = buildSpmQuery(scene.params);
+ shareInfo.query = query;
+
+ // 配置分享链接地址
+ shareInfo.link = buildSpmLink(query, shareConfig.linkAddress);
+ // 配置页面地址带参数
+ shareInfo.path = buildSpmPath(query);
+
+ // 配置转发参数
+ if (shareConfig.methods.includes('forward')) {
+ // TODO puhui999: forward 这块有点问题
+ if (shareConfig.forwardInfo.title === '' || shareConfig.forwardInfo.image === '') {
+ console.log('请在平台设置中配置转发信息');
+ }
+ // 设置自定义分享信息
+ shareInfo.title = scene.title || shareConfig.forwardInfo.title;
+ shareInfo.image = $url.cdn(scene.image || shareConfig.forwardInfo.image);
+ shareInfo.desc = scene.desc || shareConfig.forwardInfo.subtitle;
+ shareInfo.path = buildSpmPath(scene.path, query);
+ }
+
+ return shareInfo;
+};
+
+/**
+ * 构造 spm 分享参数
+ *
+ * @param params json 格式,其中包含:1)shareId 分享用户的编号;2)page 页面类型;3)query 页面 ID(参数);4)platform 平台类型;5)from 分享来源类型。
+ * @return 分享串 `spm=${shareId}.${page}.${query}.${platform}.${from}`
+ */
+const buildSpmQuery = (params) => {
+ const user = $store('user');
+ let shareId = '0'; // 设置分享者用户ID
+ if (typeof params.shareId === 'undefined') {
+ if (user.isLogin) {
+ shareId = user.userInfo.id;
+ }
+ }
+ let page = '1'; // 页面类型: 1=首页(默认),2=商品,3=拼团商品,4=秒杀商品,5=邀请参团,6=分销邀请...按需扩展
+ if (typeof params.page !== 'undefined') {
+ page = params.page;
+ }
+ let query = '0'; // 设置页面ID: 如商品ID、拼团ID等
+ if (typeof params.query !== 'undefined') {
+ query = params.query;
+ }
+ let platform = platformMap.indexOf($platform.name) + 1;
+ let from = '1';
+ if (typeof params.from !== 'undefined') {
+ from = platformMap.indexOf(params.from) + 1;
+ }
+ // spmParams = ... 可按需扩展
+ return `spm=${shareId}.${page}.${query}.${platform}.${from}`;
+};
+
+// 构造页面分享参数: 所有的分享都先到首页进行 spm 参数解析
+const buildSpmPath = (query) => {
+ // 默认是主页,页面 page,例如 pages/index/index,根路径前不要填加 /,
+ // 不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面。scancode_time为系统保留参数,不允许配置
+ return `pages/tabbar/index`;
+};
+
+// 构造分享链接
+const buildSpmLink = (query, linkAddress = '') => {
+ return `${linkAddress}?${query}`;
+};
+
+// 解析Spm
+const decryptSpm = (spm) => {
+ const user = $store('user');
+ let shareParamsArray = spm.split('.');
+ let shareParams = {
+ spm,
+ shareId: 0,
+ page: '',
+ query: {},
+ platform: '',
+ from: '',
+ };
+ let query;
+ shareParams.shareId = shareParamsArray[0];
+ switch (shareParamsArray[1]) {
+ case '1':
+ // 默认首页不跳转
+ shareParams.page = '/pages/tabbar/index';
+ break;
+ case '2':
+ // 普通商品
+ shareParams.page = '/pages/goods/index';
+ shareParams.query = {
+ id: shareParamsArray[2],
+ };
+ break;
+ case '3':
+ // 拼团商品
+ shareParams.page = '/pages/goods/groupon';
+ query = shareParamsArray[2].split(',');
+ shareParams.query = {
+ id: query[0],
+ activity_id: query[1], // TODO 芋艿:接入分享后,应该统一成 id 参数
+ };
+ break;
+ case '4':
+ // 秒杀商品
+ shareParams.page = '/pages/goods/seckill';
+ query = shareParamsArray[2].split(',');
+ shareParams.query = {
+ id: query[1],
+ };
+ break;
+ case '5':
+ // 参与拼团
+ shareParams.page = '/pages/activity/groupon/detail';
+ shareParams.query = {
+ id: shareParamsArray[2],
+ };
+ break;
+ }
+ shareParams.platform = platformMap[shareParamsArray[3] - 1];
+ shareParams.from = fromMap[shareParamsArray[4] - 1];
+ if (shareParams.shareId !== 0) {
+ // 已登录 绑定推广员
+ if (user.isLogin) {
+ bindBrokerageUser(shareParams.shareId);
+ } else {
+ // 记录分享者编号
+ uni.setStorageSync('shareId', shareParams.shareId);
+ }
+ }
+
+ if (shareParams.page !== '/pages/tabbar/index') {
+ $router.go(shareParams.page, shareParams.query);
+ }
+ return shareParams;
+};
+
+// 绑定推广员
+const bindBrokerageUser = async (val= undefined) => {
+ try {
+ const shareId = val || uni.getStorageSync('shareId');
+ if (!shareId) {
+ return;
+ }
+ await BrokerageApi.bindBrokerageUser({ bindUserId: shareId });
+ uni.removeStorageSync('shareId');
+ } catch {
+ }
+};
+
+// 更新公众号分享sdk
+const updateShareInfo = (shareInfo) => {
+ // #ifdef H5
+ if ($platform.name === 'WechatOfficialAccount') {
+ $wxsdk.updateShareInfo(shareInfo);
+ }
+ // #endif
+};
+
+export default {
+ getShareInfo,
+ updateShareInfo,
+ decryptSpm,
+ bindBrokerageUser,
+};
diff --git a/sheep/request/index.js b/sheep/request/index.js
new file mode 100644
index 0000000..f436f61
--- /dev/null
+++ b/sheep/request/index.js
@@ -0,0 +1,341 @@
+/**
+ * Shopro-request
+ * @description api模块管理,loading配置,请求拦截,错误处理
+ */
+
+import Request from 'luch-request';
+import { apiPath, baseUrl, tenantId } from '@/sheep/config';
+import $store from '@/sheep/store';
+import sheep from '@/sheep';
+import $platform from '@/sheep/platform';
+import { showAuthModal } from '@/sheep/hooks/useModal';
+import AuthUtil from '@/sheep/api/member/auth';
+import { getTerminal } from '@/sheep/util/const';
+
+const options = {
+ // 显示操作成功消息 默认不显示
+ showSuccess: false,
+ // 成功提醒 默认使用后端返回值
+ successMsg: '',
+ // 显示失败消息 默认显示
+ showError: true,
+ // 失败提醒 默认使用后端返回信息
+ errorMsg: '',
+ // 显示请求时loading模态框 默认显示
+ showLoading: true,
+ // loading提醒文字
+ loadingMsg: '加载中',
+ // 需要授权才能请求 默认放开
+ auth: false,
+ // ...
+};
+
+// Loading全局实例
+let LoadingInstance = {
+ target: null,
+ count: 0,
+};
+
+/**
+ * 关闭loading
+ */
+function closeLoading() {
+ if (LoadingInstance.count > 0) LoadingInstance.count--;
+ if (LoadingInstance.count === 0) uni.hideLoading();
+}
+
+/**
+ * @description 请求基础配置 可直接使用访问自定义请求
+ */
+const http = new Request({
+ baseURL: baseUrl + apiPath,
+ timeout: 8000,
+ method: 'GET',
+ header: {
+ Accept: 'text/json',
+ 'Content-Type': 'application/json;charset=UTF-8',
+ platform: $platform.name,
+ },
+ // #ifdef APP-PLUS
+ sslVerify: false,
+ // #endif
+ // #ifdef H5
+ // 跨域请求时是否携带凭证(cookies)仅H5支持(HBuilderX 2.6.15+)
+ withCredentials: false,
+ // #endif
+ custom: options,
+});
+
+/**
+ * @description 请求拦截器
+ */
+http.interceptors.request.use(
+ (config) => {
+ // 自定义处理【auth 授权】:必须登录的接口,则跳出 AuthModal 登录弹窗
+ if (config.custom.auth && !$store('user').isLogin) {
+ showAuthModal();
+ return Promise.reject();
+ }
+
+ // 自定义处理【loading 加载中】:如果需要显示 loading,则显示 loading
+ if (config.custom.showLoading) {
+ LoadingInstance.count++;
+ LoadingInstance.count === 1 &&
+ uni.showLoading({
+ title: config.custom.loadingMsg,
+ mask: true,
+ fail: () => {
+ uni.hideLoading();
+ },
+ });
+ }
+
+ // 增加 token 令牌、terminal 终端、tenant 租户的请求头
+ const token = getAccessToken();
+ if (token) {
+ config.header['Authorization'] = token;
+ }
+ config.header['terminal'] = getTerminal();
+
+ config.header['Accept'] = '*/*';
+ config.header['tenant-id'] = tenantId;
+ return config;
+ },
+ (error) => {
+ return Promise.reject(error);
+ },
+);
+
+/**
+ * @description 响应拦截器
+ */
+http.interceptors.response.use(
+ (response) => {
+ // 约定:如果是 /auth/ 下的 URL 地址,并且返回了 accessToken 说明是登录相关的接口,则自动设置登陆令牌
+ if (response.config.url.indexOf('/member/auth/') >= 0 && response.data?.data?.accessToken) {
+ $store('user').setToken(response.data.data.accessToken, response.data.data.refreshToken);
+ }
+
+ // 自定处理【loading 加载中】:如果需要显示 loading,则关闭 loading
+ response.config.custom.showLoading && closeLoading();
+
+ // 自定义处理【error 错误提示】:如果需要显示错误提示,则显示错误提示
+ if (response.data.code !== 0) {
+ // 特殊:如果 401 错误码,则跳转到登录页 or 刷新令牌
+ if (response.data.code === 401) {
+ return refreshToken(response.config);
+ }
+
+ if (response.data.code === -149) {
+ uni.showModal({
+ title: '积分不足',
+ content: response.data.msg,
+ confirmText: '去充值',
+ success: function (res) {
+ if (res.confirm) {
+ sheep.$router.go('/pages/point/recharge');
+ }
+ },
+ });
+ return;
+ }
+
+ if (response.data.code === 1004001009){
+ showAuthModal('chatAuthorization');
+ return;
+ }
+
+ if (response.data.code === -151){
+ uni.showModal({
+ title: '会员特权',
+ content: response.data.msg,
+ showCancel: false,
+ success: function (res) {
+ if (res.confirm) {
+ sheep.$router.go('/pages/user/vip');
+ }
+ },
+ });
+ return;
+ }
+
+ if (response.data.code === 1004001015){
+ $store('modal').$patch((state) => {
+ state.qrcode = true;
+ });
+ return;
+ }
+
+ // 错误提示
+ if (response.config.custom.showError) {
+ uni.showToast({
+ title: response.data.msg || '服务器开小差啦,请稍后再试~',
+ icon: 'none',
+ mask: true,
+ });
+ }
+ }
+
+ // 自定义处理【showSuccess 成功提示】:如果需要显示成功提示,则显示成功提示
+ if (response.config.custom.showSuccess
+ && response.config.custom.successMsg !== ''
+ && response.data.code === 0) {
+ uni.showToast({
+ title: response.config.custom.successMsg,
+ icon: 'none',
+ });
+ }
+
+ // 返回结果:包括 code + data + msg
+ return Promise.resolve(response.data);
+ },
+ (error) => {
+ const userStore = $store('user');
+ const isLogin = userStore.isLogin;
+ let errorMessage = '网络请求出错';
+ if (error !== undefined) {
+ switch (error.statusCode) {
+ case 400:
+ errorMessage = '请求错误';
+ break;
+ case 401:
+ errorMessage = isLogin ? '您的登陆已过期' : '请先登录';
+ // 正常情况下,后端不会返回 401 错误,所以这里不处理 handleAuthorized
+ break;
+ case 403:
+ errorMessage = '拒绝访问';
+ break;
+ case 404:
+ errorMessage = '请求出错';
+ break;
+ case 408:
+ errorMessage = '请求超时';
+ break;
+ case 429:
+ errorMessage = '请求频繁, 请稍后再访问';
+ break;
+ case 500:
+ errorMessage = '服务器开小差啦,请稍后再试~';
+ break;
+ case 501:
+ errorMessage = '服务未实现';
+ break;
+ case 502:
+ errorMessage = '网络错误';
+ break;
+ case 503:
+ errorMessage = '服务不可用';
+ break;
+ case 504:
+ errorMessage = '网络超时';
+ break;
+ case 505:
+ errorMessage = 'HTTP 版本不受支持';
+ break;
+ }
+ if (error.errMsg.includes('timeout')) errorMessage = '请求超时';
+ // #ifdef H5
+ if (error.errMsg.includes('Network'))
+ errorMessage = window.navigator.onLine ? '服务器异常' : '请检查您的网络连接';
+ // #endif
+ }
+
+ if (error && error.config) {
+ if (error.config.custom.showError === false) {
+ uni.showToast({
+ title: error.data?.msg || errorMessage,
+ icon: 'none',
+ mask: true,
+ });
+ }
+ error.config.custom.showLoading && closeLoading();
+ }
+
+ return false;
+ },
+);
+
+// Axios 无感知刷新令牌,参考 https://www.dashingdog.cn/article/11 与 https://segmentfault.com/a/1190000020210980 实现
+let requestList = [] // 请求队列
+let isRefreshToken = false // 是否正在刷新中
+const refreshToken = async (config) => {
+ // 如果当前已经是 refresh-token 的 URL 地址,并且还是 401 错误,说明是刷新令牌失败了,直接返回 Promise.reject(error)
+ if (config.url.indexOf('/member/auth/refresh-token') >= 0) {
+ return Promise.reject('error')
+ }
+
+ // 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了
+ if (!isRefreshToken) {
+ isRefreshToken = true
+ // 1. 如果获取不到刷新令牌,则只能执行登出操作
+ const refreshToken = getRefreshToken()
+ if (!refreshToken) {
+ return handleAuthorized()
+ }
+ // 2. 进行刷新访问令牌
+ try {
+ const refreshTokenResult = await AuthUtil.refreshToken(refreshToken);
+ if (refreshTokenResult.code !== 0) {
+ // 如果刷新不成功,直接抛出 e 触发 2.2 的逻辑
+ // noinspection ExceptionCaughtLocallyJS
+ throw new Error('刷新令牌失败');
+ }
+ // 2.1 刷新成功,则回放队列的请求 + 当前请求
+ config.header.Authorization = 'Bearer ' + getAccessToken()
+ requestList.forEach((cb) => {
+ cb()
+ })
+ requestList = []
+ return request(config)
+ } catch (e) {
+ // 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。
+ // 2.2 刷新失败,只回放队列的请求
+ requestList.forEach((cb) => {
+ cb()
+ })
+ // 提示是否要登出。即不回放当前请求!不然会形成递归
+ return handleAuthorized()
+ } finally {
+ requestList = []
+ isRefreshToken = false
+ }
+ } else {
+ // 添加到队列,等待刷新获取到新的令牌
+ return new Promise((resolve) => {
+ requestList.push(() => {
+ config.header.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token 请根据实际情况自行修改
+ resolve(request(config))
+ })
+ })
+ }
+}
+
+/**
+ * 处理 401 未登录的错误
+ */
+const handleAuthorized = () => {
+ const userStore = $store('user');
+ userStore.logout(true);
+ showAuthModal();
+ // 登录超时
+ return Promise.reject({
+ code: 401,
+ msg: userStore.isLogin ? '您的登陆已过期' : '请先登录'
+ })
+}
+
+/** 获得访问令牌 */
+const getAccessToken = () => {
+ return uni.getStorageSync('token');
+}
+
+/** 获得刷新令牌 */
+const getRefreshToken = () => {
+ return uni.getStorageSync('refresh-token');
+}
+
+const request = (config) => {
+ return http.middleware(config);
+};
+
+export default request;
diff --git a/sheep/router/index.js b/sheep/router/index.js
new file mode 100644
index 0000000..0a4ecc3
--- /dev/null
+++ b/sheep/router/index.js
@@ -0,0 +1,185 @@
+import $store from '@/sheep/store';
+import { showAuthModal, showShareModal } from '@/sheep/hooks/useModal';
+import { isNumber, isString, isEmpty, startsWith, isObject, isNil, clone } from 'lodash-es';
+import throttle from '@/sheep/helper/throttle';
+
+const _go = (
+ path,
+ params = {},
+ options = {
+ redirect: false,
+ },
+) => {
+ let page = ''; // 跳转页面
+ let query = ''; // 页面参数
+ let url = ''; // 跳转页面完整路径
+
+ if (isString(path)) {
+ // 判断跳转类型是 path | 还是http
+ if (startsWith(path, 'http')) {
+ // #ifdef H5
+ window.location = path;
+ return;
+ // #endif
+ // #ifndef H5
+ page = `/pages/public/webview`;
+ query = `url=${encodeURIComponent(path)}`;
+ // #endif
+ } else if (startsWith(path, 'action:')) {
+ handleAction(path);
+ return;
+ } else {
+ [page, query] = path.split('?');
+ }
+ if (!isEmpty(params)) {
+ let query2 = paramsToQuery(params);
+ if (isEmpty(query)) {
+ query = query2;
+ } else {
+ query += '&' + query2;
+ }
+ }
+ }
+
+ if (isObject(path)) {
+ page = path.url;
+ if (!isNil(path.params)) {
+ query = paramsToQuery(path.params);
+ }
+ }
+
+ const nextRoute = ROUTES_MAP[page];
+
+ // 未找到指定跳转页面
+ // mark: 跳转404页
+ if (!nextRoute) {
+ console.log(`%c跳转路径参数错误<${page || 'EMPTY'}>`, 'color:red;background:yellow');
+ return;
+ }
+
+ // 页面登录拦截
+ if (nextRoute.meta?.auth && !$store('user').isLogin) {
+ showAuthModal();
+ return;
+ }
+
+ url = page;
+ if (!isEmpty(query)) {
+ url += `?${query}`;
+ }
+
+ // 跳转底部导航
+ if (TABBAR.includes(page)) {
+ uni.switchTab({
+ url,
+ });
+ return;
+ }
+
+ // 使用redirect跳转
+ if (options.redirect) {
+ uni.redirectTo({
+ url,
+ });
+ return;
+ }
+
+ uni.navigateTo({
+ url,
+ });
+};
+
+// 限流 防止重复点击跳转
+function go(...args) {
+ throttle(() => {
+ _go(...args);
+ });
+}
+
+function paramsToQuery(params) {
+ if (isEmpty(params)) {
+ return '';
+ }
+ // return new URLSearchParams(Object.entries(params)).toString();
+ let query = [];
+ for (let key in params) {
+ query.push(key + '=' + params[key]);
+ }
+
+ return query.join('&');
+}
+
+function back() {
+ // #ifdef H5
+ history.back();
+ // #endif
+
+ // #ifndef H5
+ uni.navigateBack();
+ // #endif
+}
+
+function redirect(path, params = {}) {
+ go(path, params, {
+ redirect: true,
+ });
+}
+
+// 检测是否有浏览器历史
+function hasHistory() {
+ // #ifndef H5
+ const pages = getCurrentPages();
+ if (pages.length > 1) {
+ return true;
+ }
+ return false;
+ // #endif
+
+ // #ifdef H5
+ return !!history.state.back;
+ // #endif
+}
+
+function getCurrentRoute(field = '') {
+ let currentPage = getCurrentPage();
+ // #ifdef MP
+ currentPage.$page['route'] = currentPage.route;
+ currentPage.$page['options'] = currentPage.options;
+ // #endif
+ if (field !== '') {
+ return currentPage.$page[field];
+ } else {
+ return currentPage.$page;
+ }
+}
+
+function getCurrentPage() {
+ let pages = getCurrentPages();
+ return pages[pages.length - 1];
+}
+
+function handleAction(path) {
+ const action = path.split(':');
+ switch (action[1]) {
+ case 'showShareModal':
+ showShareModal();
+ break;
+ }
+}
+
+function error(errCode, errMsg = '') {
+ redirect('/pages/public/error', {
+ errCode,
+ errMsg,
+ });
+}
+
+export default {
+ go,
+ back,
+ hasHistory,
+ redirect,
+ getCurrentPage,
+ getCurrentRoute,
+ error,
+};
diff --git a/sheep/router/utils/strip-json-comments.js b/sheep/router/utils/strip-json-comments.js
new file mode 100644
index 0000000..5995992
--- /dev/null
+++ b/sheep/router/utils/strip-json-comments.js
@@ -0,0 +1,79 @@
+const singleComment = Symbol('singleComment');
+const multiComment = Symbol('multiComment');
+
+const stripWithoutWhitespace = () => '';
+const stripWithWhitespace = (string, start, end) => string.slice(start, end).replace(/\S/g, ' ');
+
+const isEscaped = (jsonString, quotePosition) => {
+ let index = quotePosition - 1;
+ let backslashCount = 0;
+
+ while (jsonString[index] === '\\') {
+ index -= 1;
+ backslashCount += 1;
+ }
+
+ return Boolean(backslashCount % 2);
+};
+
+export default function stripJsonComments(jsonString, { whitespace = true } = {}) {
+ if (typeof jsonString !== 'string') {
+ throw new TypeError(
+ `Expected argument \`jsonString\` to be a \`string\`, got \`${typeof jsonString}\``,
+ );
+ }
+
+ const strip = whitespace ? stripWithWhitespace : stripWithoutWhitespace;
+
+ let isInsideString = false;
+ let isInsideComment = false;
+ let offset = 0;
+ let result = '';
+
+ for (let index = 0; index < jsonString.length; index++) {
+ const currentCharacter = jsonString[index];
+ const nextCharacter = jsonString[index + 1];
+
+ if (!isInsideComment && currentCharacter === '"') {
+ const escaped = isEscaped(jsonString, index);
+ if (!escaped) {
+ isInsideString = !isInsideString;
+ }
+ }
+
+ if (isInsideString) {
+ continue;
+ }
+
+ if (!isInsideComment && currentCharacter + nextCharacter === '//') {
+ result += jsonString.slice(offset, index);
+ offset = index;
+ isInsideComment = singleComment;
+ index++;
+ } else if (isInsideComment === singleComment && currentCharacter + nextCharacter === '\r\n') {
+ index++;
+ isInsideComment = false;
+ result += strip(jsonString, offset, index);
+ offset = index;
+ continue;
+ } else if (isInsideComment === singleComment && currentCharacter === '\n') {
+ isInsideComment = false;
+ result += strip(jsonString, offset, index);
+ offset = index;
+ } else if (!isInsideComment && currentCharacter + nextCharacter === '/*') {
+ result += jsonString.slice(offset, index);
+ offset = index;
+ isInsideComment = multiComment;
+ index++;
+ continue;
+ } else if (isInsideComment === multiComment && currentCharacter + nextCharacter === '*/') {
+ index++;
+ isInsideComment = false;
+ result += strip(jsonString, offset, index + 1);
+ offset = index + 1;
+ continue;
+ }
+ }
+
+ return result + (isInsideComment ? strip(jsonString.slice(offset)) : jsonString.slice(offset));
+}
diff --git a/sheep/router/utils/uni-read-pages-v3.js b/sheep/router/utils/uni-read-pages-v3.js
new file mode 100644
index 0000000..303f10a
--- /dev/null
+++ b/sheep/router/utils/uni-read-pages-v3.js
@@ -0,0 +1,103 @@
+'use strict';
+Object.defineProperty(exports, '__esModule', {
+ value: true,
+});
+const fs = require('fs');
+import stripJsonComments from './strip-json-comments';
+import { isArray, isEmpty } from 'lodash';
+
+class TransformPages {
+ constructor({ includes, pagesJsonDir }) {
+ this.includes = includes;
+ this.uniPagesJSON = JSON.parse(stripJsonComments(fs.readFileSync(pagesJsonDir, 'utf-8')));
+ this.routes = this.getPagesRoutes().concat(this.getSubPackagesRoutes());
+ this.tabbar = this.getTabbarRoutes();
+ this.routesMap = this.transformPathToKey(this.routes);
+ }
+ /**
+ * 通过读取pages.json文件 生成直接可用的routes
+ */
+ getPagesRoutes(pages = this.uniPagesJSON.pages, rootPath = null) {
+ let routes = [];
+ for (let i = 0; i < pages.length; i++) {
+ const item = pages[i];
+ let route = {};
+ for (let j = 0; j < this.includes.length; j++) {
+ const key = this.includes[j];
+ let value = item[key];
+ if (key === 'path') {
+ value = rootPath ? `/${rootPath}/${value}` : `/${value}`;
+ }
+ if (key === 'aliasPath' && i == 0 && rootPath == null) {
+ route[key] = route[key] || '/';
+ } else if (value !== undefined) {
+ route[key] = value;
+ }
+ }
+ routes.push(route);
+ }
+ return routes;
+ }
+ /**
+ * 解析小程序分包路径
+ */
+ getSubPackagesRoutes() {
+ if (!(this.uniPagesJSON && this.uniPagesJSON.subPackages)) {
+ return [];
+ }
+ const subPackages = this.uniPagesJSON.subPackages;
+ let routes = [];
+ for (let i = 0; i < subPackages.length; i++) {
+ const subPages = subPackages[i].pages;
+ const root = subPackages[i].root;
+ const subRoutes = this.getPagesRoutes(subPages, root);
+ routes = routes.concat(subRoutes);
+ }
+ return routes;
+ }
+
+ getTabbarRoutes() {
+ if (!(this.uniPagesJSON && this.uniPagesJSON.tabBar && this.uniPagesJSON.tabBar.list)) {
+ return [];
+ }
+ const tabbar = this.uniPagesJSON.tabBar.list;
+ let tabbarMap = [];
+ tabbar.forEach((bar) => {
+ tabbarMap.push('/' + bar.pagePath);
+ });
+ return tabbarMap;
+ }
+
+ transformPathToKey(list) {
+ if (!isArray(list) || isEmpty(list)) {
+ return [];
+ }
+ let map = {};
+ list.forEach((i) => {
+ map[i.path] = i;
+ });
+ return map;
+ }
+}
+
+function uniReadPagesV3Plugin({ pagesJsonDir, includes }) {
+ let defaultIncludes = ['path', 'aliasPath', 'name'];
+ includes = [...defaultIncludes, ...includes];
+ let pages = new TransformPages({
+ pagesJsonDir,
+ includes,
+ });
+ return {
+ name: 'uni-read-pages-v3',
+ config(config) {
+ return {
+ define: {
+ ROUTES: pages.routes,
+ ROUTES_MAP: pages.routesMap,
+ TABBAR: pages.tabbar,
+ },
+ };
+ },
+ };
+}
+exports.default = uniReadPagesV3Plugin;
diff --git a/sheep/scss/_main.scss b/sheep/scss/_main.scss
new file mode 100644
index 0000000..999513a
--- /dev/null
+++ b/sheep/scss/_main.scss
@@ -0,0 +1,354 @@
+body {
+ color: var(--text-a);
+ background-color: var(--ui-BG-1) !important;
+ font-family: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans',
+ sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
+}
+
+/* ==================
+ 初始化
+ ==================== */
+.ui-link {
+ cursor: pointer;
+}
+navigator {
+ display: inline-flex;
+}
+navigator.navigator-hover {
+ background-color: inherit;
+ transform: translate(1rpx, 1rpx);
+ // opacity: 1;
+}
+
+/* ==================
+ 辅助类
+ ==================== */
+.none {
+ display: none !important;
+}
+.inline {
+ display: inline !important;
+}
+.inline-block {
+ display: inline-block !important;
+}
+.block {
+ display: block !important;
+}
+.touch-none {
+ pointer-events: none;
+}
+.touch-all {
+ pointer-events: all;
+}
+.flex {
+ display: flex !important;
+}
+.inline-flex {
+ display: inline-flex !important;
+}
+.w-100 {
+ width: 100%;
+}
+/* -- 浮动 -- */
+.cf::after,
+.cf::before {
+ content: '';
+ display: table;
+}
+.cf::after {
+ clear: both;
+}
+.fl {
+ float: left;
+}
+.fr {
+ float: right;
+}
+.position-center {
+ @include position-center;
+}
+.position-relative {
+ position: relative;
+}
+/* -- 工具类 -- */
+@function negativify-map($map) {
+ $result: ();
+ @each $key, $value in $map {
+ @if $key != 0 {
+ $result: map-merge($result, ('n' + $key: (-$value)));
+ }
+ }
+ @return $result;
+}
+
+$utilities: () !default;
+$utilities: map-merge(
+ (
+ 'margin': (
+ responsive: true,
+ property: margin,
+ class: m,
+ values:
+ map-merge(
+ $spacers,
+ (
+ auto: auto,
+ )
+ ),
+ ),
+ 'margin-x': (
+ property: margin-right margin-left,
+ class: mx,
+ values:
+ map-merge(
+ $spacers,
+ (
+ auto: auto,
+ )
+ ),
+ ),
+ 'margin-y': (
+ property: margin-top margin-bottom,
+ class: my,
+ values:
+ map-merge(
+ $spacers,
+ (
+ auto: auto,
+ )
+ ),
+ ),
+ 'margin-top': (
+ property: margin-top,
+ class: mt,
+ values:
+ map-merge(
+ $spacers,
+ (
+ auto: auto,
+ )
+ ),
+ ),
+ 'margin-right': (
+ property: margin-right,
+ class: mr,
+ values:
+ map-merge(
+ $spacers,
+ (
+ auto: auto,
+ )
+ ),
+ ),
+ 'margin-bottom': (
+ property: margin-bottom,
+ class: mb,
+ values:
+ map-merge(
+ $spacers,
+ (
+ auto: auto,
+ )
+ ),
+ ),
+ 'margin-left': (
+ property: margin-left,
+ class: ml,
+ values:
+ map-merge(
+ $spacers,
+ (
+ auto: auto,
+ )
+ ),
+ ),
+ 'padding': (
+ responsive: true,
+ property: padding,
+ class: p,
+ values: $spacers,
+ ),
+ 'padding-x': (
+ property: padding-right padding-left,
+ class: px,
+ values: $spacers,
+ ),
+ 'padding-y': (
+ property: padding-top padding-bottom,
+ class: py,
+ values: $spacers,
+ ),
+ 'padding-top': (
+ property: padding-top,
+ class: pt,
+ values: $spacers,
+ ),
+ 'padding-right': (
+ property: padding-right,
+ class: pr,
+ values: $spacers,
+ ),
+ 'padding-bottom': (
+ property: padding-bottom,
+ class: pb,
+ values: $spacers,
+ ),
+ 'padding-left': (
+ property: padding-left,
+ class: pl,
+ values: $spacers,
+ ),
+ 'font-weight': (
+ property: font-weight,
+ class: text,
+ values: (
+ light: $font-weight-light,
+ lighter: $font-weight-lighter,
+ normal: $font-weight-normal,
+ bold: $font-weight-bold,
+ bolder: $font-weight-bolder,
+ ),
+ ),
+ 'text-align': (
+ property: text-align,
+ class: text,
+ values: left right center,
+ ),
+ 'font-color': (
+ property: color,
+ class: text,
+ values:
+ map-merge(
+ $colors,
+ map-merge(
+ $grays,
+ map-merge(
+ $darks,
+ (
+ 'reset': inherit,
+ )
+ )
+ )
+ ),
+ ),
+ 'line-height': (
+ property: line-height,
+ class: lh,
+ values: (
+ 1: 1,
+ sm: $line-height-sm,
+ base: $line-height-base,
+ lg: $line-height-lg,
+ ),
+ ),
+ 'white-space': (
+ property: white-space,
+ class: text,
+ values: (
+ nowrap: nowrap,
+ ),
+ ),
+ 'radius': (
+ property: border-radius,
+ class: radius,
+ values: (
+ null: $radius,
+ sm: $radius-sm,
+ lg: $radius-lg,
+ 0: 0,
+ ),
+ ),
+ 'round': (
+ property: border-radius,
+ class: round,
+ values: (
+ null: $round-pill,
+ circle: 50%,
+ ),
+ ),
+ 'radius-top': (
+ property: border-top-left-radius border-top-right-radius,
+ class: radius-top,
+ values: (
+ null: $radius,
+ ),
+ ),
+ 'radius-right': (
+ property: border-top-right-radius border-bottom-right-radius,
+ class: radius-right,
+ values: (
+ null: $radius,
+ ),
+ ),
+ 'radius-bottom': (
+ property: border-bottom-right-radius border-bottom-left-radius,
+ class: radius-bottom,
+ values: (
+ null: $radius,
+ ),
+ ),
+ 'radius-left': (
+ property: border-bottom-left-radius border-top-left-radius,
+ class: radius-left,
+ values: (
+ null: $radius,
+ ),
+ ),
+ 'radius-lr': (
+ property: border-top-left-radius border-bottom-right-radius,
+ class: radius-lr,
+ values: (
+ null: $radius,
+ ),
+ ),
+ 'radius-lrs': (
+ property: border-top-right-radius border-bottom-left-radius,
+ class: radius-lr,
+ values: (
+ null: 0,
+ ),
+ ),
+ 'radius-rl': (
+ property: border-top-right-radius border-bottom-left-radius,
+ class: radius-rl,
+ values: (
+ null: $radius,
+ ),
+ ),
+ 'radius-rls': (
+ property: border-top-left-radius border-bottom-right-radius,
+ class: radius-rl,
+ values: (
+ null: 0,
+ ),
+ ),
+ ),
+ $utilities
+);
+@each $key, $utility in $utilities {
+ @if type-of($utility) == 'map' {
+ $values: map-get($utility, values);
+ @if type-of($values) == 'string' or type-of(nth($values, 1)) != 'list' {
+ $values: zip($values, $values);
+ }
+ @each $key, $value in $values {
+ $properties: map-get($utility, property);
+ @if type-of($properties) == 'string' {
+ $properties: append((), $properties);
+ }
+ $property-class: if(
+ map-has-key($utility, class),
+ map-get($utility, class),
+ nth($properties, 1)
+ );
+ $property-class: if($property-class == null, '', $property-class);
+ $property-class-modifier: if($key, if($property-class == '', '', '-') + $key, '');
+ .#{$property-class + $property-class-modifier} {
+ @each $property in $properties {
+ #{$property}: $value !important;
+ }
+ }
+ }
+ }
+}
diff --git a/sheep/scss/_mixins.scss b/sheep/scss/_mixins.scss
new file mode 100644
index 0000000..299f7b1
--- /dev/null
+++ b/sheep/scss/_mixins.scss
@@ -0,0 +1,61 @@
+@mixin bg-square {
+ background: {
+ color: #fff;
+ image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%),
+ linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%);
+ size: 40rpx 40rpx;
+ position: 0 0, 20rpx 20rpx;
+ }
+}
+
+@mixin flex($direction: row) {
+ /* #ifndef APP-NVUE */
+ display: flex;
+ /* #endif */
+ flex-direction: $direction;
+}
+@mixin flex-bar {
+ position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+@mixin flex-center {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+@mixin arrow {
+ content: '';
+ height: 0;
+ width: 0;
+ position: absolute;
+}
+@mixin arrow-top {
+ @include arrow;
+ // border-color: transparent transparent $ui-BG;
+ border-style: none solid solid;
+ border-width: 0 20rpx 20rpx;
+}
+
+@mixin arrow-right {
+ @include arrow;
+ // border-color: transparent $ui-BG transparent;
+ border-style: solid solid solid none;
+ border-width: 20rpx 20rpx 20rpx 0;
+}
+@mixin position-center {
+ position: absolute !important;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ margin: auto;
+}
+
+@mixin blur {
+ -webkit-backdrop-filter: blur(20px);
+ backdrop-filter: blur(20px);
+ color: var(--ui-TC);
+}
diff --git a/sheep/scss/_tools.scss b/sheep/scss/_tools.scss
new file mode 100644
index 0000000..e1fb636
--- /dev/null
+++ b/sheep/scss/_tools.scss
@@ -0,0 +1,286 @@
+/* ==================
+ 常用工具
+ ==================== */
+
+.ss-bg-opactity-block {
+ background-color: rgba(#000, 0.2);
+ color: #fff;
+}
+
+/* ==================
+ flex布局
+ ==================== */
+
+.ss-flex {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+
+.ss-flex-1 {
+ flex: 1;
+}
+
+.ss-flex-col {
+ display: flex;
+ flex-direction: column;
+}
+
+.ss-flex-wrap {
+ flex-wrap: wrap;
+}
+
+.ss-flex-nowrap {
+ flex-wrap: nowrap;
+}
+
+.ss-col-center {
+ align-items: center;
+}
+
+.ss-col-top {
+ align-items: flex-start;
+}
+
+.ss-col-bottom {
+ align-items: flex-end;
+}
+
+.ss-col-stretch {
+ align-items: stretch;
+}
+
+.ss-row-center {
+ justify-content: center;
+}
+
+.ss-row-left {
+ justify-content: flex-start;
+}
+
+.ss-row-right {
+ justify-content: flex-end;
+}
+
+.ss-row-between {
+ justify-content: space-between;
+}
+
+.ss-row-around {
+ justify-content: space-around;
+}
+
+.ss-self-start {
+ align-self: flex-start;
+}
+
+.ss-self-end {
+ align-self: flex-end;
+}
+
+.ss-self-center {
+ align-self: center;
+}
+.ss-h-100 {
+ height: 100%;
+}
+.ss-w-100 {
+ width: 100%;
+}
+
+/* ==================
+
+ margin padding: 内外边距
+
+ ==================== */
+@for $i from 0 through 100 {
+ // 只要双数和能被5除尽的数
+ @if $i % 2==0 or $i % 5==0 {
+ // 得出:u-margin-30或者u-m-30
+ .ss-margin-#{$i},
+ .ss-m-#{$i} {
+ margin: $i + rpx;
+ }
+ .ss-m-x-#{$i} {
+ margin-left: $i + rpx;
+ margin-right: $i + rpx;
+ }
+ .ss-m-y-#{$i} {
+ margin-top: $i + rpx;
+ margin-bottom: $i + rpx;
+ }
+
+ // 得出:u-padding-30或者u-p-30
+ .ss-padding-#{$i},
+ .ss-p-#{$i} {
+ padding: $i + rpx;
+ }
+ .ss-p-x-#{$i} {
+ padding-left: $i + rpx;
+ padding-right: $i + rpx;
+ }
+ .ss-p-y-#{$i} {
+ padding-top: $i + rpx;
+ padding-bottom: $i + rpx;
+ }
+
+ @each $short, $long in l left, t top, r right, b bottom {
+ // 缩写版,结果如: u-m-l-30
+ // 定义外边距
+ .ss-m-#{$short}-#{$i} {
+ margin-#{$long}: $i + rpx;
+ }
+
+ // 定义内边距
+ .ss-p-#{$short}-#{$i} {
+ padding-#{$long}: $i + rpx;
+ }
+
+ // 完整版,结果如:u-margin-left-30
+ // 定义外边距
+ .ss-margin-#{$long}-#{$i} {
+ margin-#{$long}: $i + rpx;
+ }
+
+ // 定义内边距
+ .ss-padding-#{$long}-#{$i} {
+ padding-#{$long}: $i + rpx;
+ }
+ }
+ }
+}
+
+/* ==================
+
+ radius
+
+ ==================== */
+@for $i from 0 through 100 {
+ // 只要双数和能被5除尽的数
+ @if $i % 2==0 or $i % 5==0 {
+ .ss-radius-#{$i},
+ .ss-r-#{$i} {
+ border-radius: $i + rpx;
+ }
+
+ .ss-r-t-#{$i} {
+ border-top-left-radius: $i + rpx;
+ border-top-right-radius: $i + rpx;
+ }
+
+ .ss-r-b-#{$i} {
+ border-bottom-left-radius: $i + rpx;
+ border-bottom-right-radius: $i + rpx;
+ }
+
+ @each $short, $long in tl 'top-left', tr 'top-right', bl 'bottom-right', br 'bottom-right' {
+ // 定义外边距
+ .ss-r-#{$short}-#{$i} {
+ border-#{$long}-radius: $i + rpx;
+ }
+
+ // 定义内边距
+ .ss-radius-#{$long}-#{$i} {
+ border-#{$long}-radius: $i + rpx;
+ }
+ }
+ }
+}
+
+/* ==================
+
+ 溢出省略号
+ @param {Number} 行数
+
+ ==================== */
+@mixin ellipsis($rowCount: 1) {
+ // @if $rowCount <=1 {
+ // overflow: hidden;
+ // text-overflow: ellipsis;
+ // white-space: nowrap;
+ // } @else {
+ // min-width: 0;
+ // overflow: hidden;
+ // text-overflow: ellipsis;
+ // display: -webkit-box;
+ // -webkit-line-clamp: $rowCount;
+ // -webkit-box-orient: vertical;
+ // }
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: -webkit-box;
+ -webkit-line-clamp: $rowCount;
+ -webkit-box-orient: vertical;
+}
+
+@for $i from 1 through 6 {
+ .ss-line-#{$i} {
+ @include ellipsis($i);
+ }
+}
+
+/* ==================
+ hover
+ ==================== */
+.ss-hover-class {
+ background-color: $gray-c;
+ opacity: 0.6;
+}
+.ss-hover-btn {
+ transform: translate(1px, 1px);
+}
+
+/* ==================
+ 底部安全区域
+ ==================== */
+
+.ss-safe-bottom {
+ padding-bottom: 0;
+ padding-bottom: calc(constant(safe-area-inset-bottom) / 5 * 3);
+ padding-bottom: calc(env(safe-area-inset-bottom) / 5 * 3);
+}
+
+/* ==================
+
+ 字体大小
+
+ ==================== */
+
+@for $i from 20 through 50 {
+ .ss-font-#{$i} {
+ font-size: $i + rpx;
+ }
+}
+
+/* ==================
+ 按钮
+ ==================== */
+.ss-reset-button {
+ padding: 0;
+ margin: 0;
+ font-size: inherit;
+ background-color: transparent;
+ color: inherit;
+ position: relative;
+ border: 0rpx;
+ /* #ifndef APP-NVUE */
+ display: flex;
+ /* #endif */
+ align-items: center;
+ justify-content: center;
+ box-sizing: border-box;
+ text-align: center;
+ text-decoration: none;
+ white-space: nowrap;
+ vertical-align: baseline;
+ transform: translate(0, 0);
+}
+.ss-reset-button.button-hover {
+ transform: translate(1px, 1px);
+ background: none;
+}
+
+.ss-reset-button::after {
+ border: none;
+}
diff --git a/sheep/scss/_var.scss b/sheep/scss/_var.scss
new file mode 100644
index 0000000..b9986cc
--- /dev/null
+++ b/sheep/scss/_var.scss
@@ -0,0 +1,162 @@
+@import './mixins';
+
+//颜色 ,渐变背景60%
+$yellow: #ffc300; //ss-黄
+$orange: #ff6000; //ss-橘
+$red: #ff3000; //ss-红
+$pink: #e03997;
+$mauve: #b745cb;
+$purple: #652abf; //rgba(101, 42, 191, 1); // ss-紫
+$blue: #0081ff;
+$cyan: #37c0fe;
+$green: #7ea19e; //ss-绿
+$olive: #8dc63f;
+$grey: #8799a3;
+$brown: #a5673f;
+$black: #484848; //ss-黑
+$golden: #e9b461; //ss-金
+
+$colors: ();
+$colors: map-merge(
+ (
+ 'yellow': $yellow,
+ 'orange': $orange,
+ 'red': $red,
+ 'pink': $pink,
+ 'mauve': $mauve,
+ 'purple': $purple,
+ 'violet': $purple,
+ 'blue': $blue,
+ 'cyan': $cyan,
+ 'green': $green,
+ 'olive': $olive,
+ 'grey': $grey,
+ 'brown': $brown,
+ 'black': $black,
+ 'golden': $golden,
+ ),
+ $colors
+);
+
+//灰度
+$bg-page: #f6f6f6;
+$white: #ffffff;
+$gray-f: #f8f9fa;
+$gray-e: #eeeeee;
+$gray-d: #dddddd;
+$gray-c: #cccccc;
+$gray-b: #bbbbbb;
+$gray-a: #aaaaaa;
+$dark-9: #999999;
+$dark-8: #888888;
+$dark-7: #777777;
+$dark-6: #666666;
+$dark-5: #555555;
+$dark-4: #484848; //ss-黑
+$dark-3: #333333;
+$dark-2: #222222;
+$dark-1: #111111;
+$black: #000000;
+
+$grays: ();
+$grays: map-merge(
+ (
+ 'white': $white,
+ 'gray-f': $gray-f,
+ 'gray-e': $gray-e,
+ 'gray-d': $gray-d,
+ 'gray-c': $gray-c,
+ 'gray-b': $gray-b,
+ 'gray-a': $gray-a,
+ 'gray': $gray-a,
+ ),
+ $grays
+);
+
+$darks: ();
+$darks: map-merge(
+ (
+ 'dark-9': $dark-9,
+ 'dark-8': $dark-8,
+ 'dark-7': $dark-7,
+ 'dark-6': $dark-6,
+ 'dark-5': $dark-5,
+ 'dark-4': $dark-4,
+ 'dark-3': $dark-3,
+ 'dark-2': $dark-2,
+ 'dark-1': $dark-1,
+ 'black': $black,
+ ),
+ $darks
+);
+
+// 边框
+$border-width: 1rpx !default; // 边框大小
+$border-color: $gray-d !default; // 边框颜色
+
+// 圆角
+$radius: 10rpx !default; // 默认圆角大小
+$radius-lg: 40rpx !default; // 大圆角
+$radius-sm: 6rpx !default; // 小圆角
+$round-pill: 1000rpx !default; // 半圆
+
+// 动画过渡
+$transition-base: all 0.2s ease-in-out !default; // 默认过渡
+$transition-base-out: all 0.04s ease-in-out !default; // 进场过渡
+$transition-fade: opacity 0.15s linear !default; // 透明过渡
+$transition-collapse: height 0.35s ease !default; // 收缩过渡
+
+// 间距
+$spacer: 20rpx !default;
+$spacers: () !default;
+$spacers: map-merge(
+ (
+ 0: 0,
+ 1: $spacer * 0.25,
+ 2: $spacer * 0.5,
+ 3: $spacer,
+ 4: $spacer * 1.5,
+ 5: $spacer * 3,
+ 6: $spacer * 5,
+ ),
+ $spacers
+);
+// 字形
+$font-weight-lighter: lighter !default;
+$font-weight-light: 300 !default;
+$font-weight-normal: 400 !default;
+$font-weight-bold: 700 !default;
+$font-weight-bolder: 900 !default;
+$fontsize: () !default;
+$fontsize: map-merge(
+ (
+ xs: 20,
+ sm: 24,
+ df: 28,
+ lg: 32,
+ xl: 36,
+ xxl: 44,
+ sl: 80,
+ xsl: 120,
+ ),
+ $fontsize
+);
+// 段落
+$line-height-base: 1.5 !default;
+$line-height-lg: 2 !default;
+$line-height-sm: 1.25 !default;
+// 图标
+$iconsize: () !default;
+$iconsize: map-merge(
+ (
+ xs: 0.5,
+ sm: 0.75,
+ df: 1,
+ lg: 1.25,
+ xl: 1.5,
+ xxl: 2,
+ sl: 6,
+ xsl: 10,
+ ),
+ $iconsize
+);
diff --git a/sheep/scss/font/OPPOSANS-M-subfont.ttf b/sheep/scss/font/OPPOSANS-M-subfont.ttf
new file mode 100644
index 0000000..88ff835
Binary files /dev/null and b/sheep/scss/font/OPPOSANS-M-subfont.ttf differ
diff --git a/sheep/scss/icon/_coloricon.scss b/sheep/scss/icon/_coloricon.scss
new file mode 100644
index 0000000..f391ca4
--- /dev/null
+++ b/sheep/scss/icon/_coloricon.scss
@@ -0,0 +1,1340 @@
+@font-face {
+ font-family: 'coloricon';
+ src: url('data:application/x-font-woff2;charset=utf-8;base64,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')
+ format('woff2');
+ /* #ifdef MP-ALIPAY */
+ src: url('//at.alicdn.com/t/font_1656945_d66u4pxvlq6.woff2') format('woff2'),
+ url('//at.alicdn.com/t/font_1656945_d66u4pxvlq6.woff') format('woff'),
+ url('//at.alicdn.com/t/font_1656945_d66u4pxvlq6.ttf') format('truetype');
+ /* #endif */
+ font-weight: normal;
+ font-style: normal;
+}
+[class*='cicon-'] {
+ font-family: 'coloricon';
+ display: inline-block;
+}
+
+.cicon-Aa:before {
+ content: '\e7a1';
+}
+.cicon-accounts:before {
+ content: '\e681';
+}
+.cicon-accounts-o:before {
+ content: '\e686';
+}
+.cicon-add:before {
+ content: '\e6e4';
+}
+.cicon-add-round:before {
+ content: '\e717';
+}
+.cicon-add-round-o:before {
+ content: '\e718';
+}
+.cicon-alarm:before {
+ content: '\e61e';
+}
+.cicon-album:before {
+ content: '\e759';
+}
+.cicon-alipay:before {
+ content: '\e6e1';
+}
+.cicon-android:before {
+ content: '\e6e2';
+}
+.cicon-angle:before {
+ content: '\e605';
+}
+.cicon-apple:before {
+ content: '\e8e7';
+}
+.cicon-apps:before {
+ content: '\e737';
+}
+.cicon-archive:before {
+ content: '\e7ae';
+}
+.cicon-archive-o:before {
+ content: '\e7ad';
+}
+.cicon-arrow:before {
+ content: '\e608';
+}
+.cicon-at-line:before {
+ content: '\e75c';
+}
+.cicon-avatar:before {
+ content: '\e663';
+}
+.cicon-avatar-o:before {
+ content: '\e665';
+}
+.cicon-avatars:before {
+ content: '\e67e';
+}
+.cicon-avatars-o:before {
+ content: '\e680';
+}
+.cicon-back:before {
+ content: '\e600';
+}
+.cicon-backspace:before {
+ content: '\e6a9';
+}
+.cicon-backup:before {
+ content: '\e61f';
+}
+.cicon-backup-restore:before {
+ content: '\e62d';
+}
+.cicon-barcode:before {
+ content: '\e71f';
+}
+.cicon-book:before {
+ content: '\e6a2';
+}
+.cicon-bookmark:before {
+ content: '\e6a3';
+}
+.cicon-bookmark-o:before {
+ content: '\e697';
+}
+.cicon-bookmarks:before {
+ content: '\e6a6';
+}
+.cicon-box:before {
+ content: '\e714';
+}
+.cicon-box-block:before {
+ content: '\e6ac';
+}
+.cicon-box-right:before {
+ content: '\e6a0';
+}
+.cicon-brand:before {
+ content: '\e726';
+}
+.cicon-brand-o:before {
+ content: '\e727';
+}
+.cicon-building:before {
+ content: '\e6c3';
+}
+.cicon-building-o:before {
+ content: '\e6c7';
+}
+.cicon-camera:before {
+ content: '\e6fa';
+}
+.cicon-camera-add:before {
+ content: '\e736';
+}
+.cicon-camera-add-o:before {
+ content: '\e735';
+}
+.cicon-camera-lens:before {
+ content: '\e68f';
+}
+.cicon-camera-lens-o:before {
+ content: '\e68e';
+}
+.cicon-camera-o:before {
+ content: '\e6fb';
+}
+.cicon-camera-rotate:before {
+ content: '\e71e';
+}
+.cicon-card:before {
+ content: '\e744';
+}
+.cicon-cardboard:before {
+ content: '\e7a9';
+}
+.cicon-cardboard-o:before {
+ content: '\e7aa';
+}
+.cicon-cardboard-off-o:before {
+ content: '\e7af';
+}
+.cicon-cart:before {
+ content: '\e70b';
+}
+.cicon-cart-o:before {
+ content: '\e708';
+}
+.cicon-chat:before {
+ content: '\e739';
+}
+.cicon-chat-bubble:before {
+ content: '\e69b';
+}
+.cicon-chat-bubble-o:before {
+ content: '\e6a7';
+}
+.cicon-chat-list:before {
+ content: '\e69d';
+}
+.cicon-chat-list-o:before {
+ content: '\e6aa';
+}
+.cicon-chat-o:before {
+ content: '\e73c';
+}
+.cicon-chat-smile:before {
+ content: '\e779';
+}
+.cicon-chat-smile-o:before {
+ content: '\e78e';
+}
+.cicon-chat-smiles:before {
+ content: '\e76b';
+}
+.cicon-chat-smiles-o:before {
+ content: '\e74a';
+}
+.cicon-check:before {
+ content: '\e69f';
+}
+.cicon-checkbox:before {
+ content: '\e713';
+}
+.cicon-checkbox-o:before {
+ content: '\e715';
+}
+.cicon-check-round:before {
+ content: '\e6f1';
+}
+.cicon-check-round-o:before {
+ content: '\e6f2';
+}
+.cicon-choiceness:before {
+ content: '\e728';
+}
+.cicon-choiceness-o:before {
+ content: '\e729';
+}
+.cicon-chrome:before {
+ content: '\e6e3';
+}
+.cicon-circle:before {
+ content: '\e7b0';
+}
+.cicon-circle-o:before {
+ content: '\e7b1';
+}
+.cicon-close:before {
+ content: '\e6ed';
+}
+.cicon-close-round:before {
+ content: '\e6f3';
+}
+.cicon-close-round-o:before {
+ content: '\e6f4';
+}
+.cicon-clothes:before {
+ content: '\e72a';
+}
+.cicon-clothes-o:before {
+ content: '\e72b';
+}
+.cicon-cloud:before {
+ content: '\e64e';
+}
+.cicon-cloud-done:before {
+ content: '\e641';
+}
+.cicon-cloud-download:before {
+ content: '\e647';
+}
+.cicon-cloud-o:before {
+ content: '\e646';
+}
+.cicon-cloud-off:before {
+ content: '\e64b';
+}
+.cicon-cloud-upload:before {
+ content: '\e687';
+}
+.cicon-code-box:before {
+ content: '\e7c3';
+}
+.cicon-coin:before {
+ content: '\e78a';
+}
+.cicon-coin-o:before {
+ content: '\e79d';
+}
+.cicon-comment:before {
+ content: '\e738';
+}
+.cicon-comment-o:before {
+ content: '\e70e';
+}
+.cicon-community:before {
+ content: '\e742';
+}
+.cicon-community-o:before {
+ content: '\e743';
+}
+.cicon-countdown:before {
+ content: '\e722';
+}
+.cicon-countdown-o:before {
+ content: '\e723';
+}
+.cicon-creative:before {
+ content: '\e72c';
+}
+.cicon-creative-o:before {
+ content: '\e72d';
+}
+.cicon-crop:before {
+ content: '\e6d9';
+}
+.cicon-crown:before {
+ content: '\e776';
+}
+.cicon-crown-o:before {
+ content: '\e777';
+}
+.cicon-cut:before {
+ content: '\e74b';
+}
+.cicon-DarkMode:before {
+ content: '\e7c4';
+}
+.cicon-dashboard:before {
+ content: '\e62e';
+}
+.cicon-delete:before {
+ content: '\e6bd';
+}
+.cicon-delete-close:before {
+ content: '\e6ae';
+}
+.cicon-delete-line:before {
+ content: '\e707';
+}
+.cicon-delete-line-o:before {
+ content: '\e709';
+}
+.cicon-delete-o:before {
+ content: '\e69a';
+}
+.cicon-deliver:before {
+ content: '\e7f7';
+}
+.cicon-deliver-o:before {
+ content: '\e6ff';
+}
+.cicon-demo:before {
+ content: '\e916';
+}
+.cicon-discover:before {
+ content: '\e70c';
+}
+.cicon-discover-o:before {
+ content: '\e702';
+}
+.cicon-discuss-fill:before {
+ content: '\e790';
+}
+.cicon-discuss-line:before {
+ content: '\e78f';
+}
+.cicon-dollar:before {
+ content: '\e79f';
+}
+.cicon-dollar-o:before {
+ content: '\e79e';
+}
+.cicon-done:before {
+ content: '\e633';
+}
+.cicon-done-all:before {
+ content: '\e62a';
+}
+.cicon-douyin:before {
+ content: '\e6e7';
+}
+.cicon-drop-down:before {
+ content: '\e61c';
+}
+.cicon-drop-up:before {
+ content: '\e61d';
+}
+.cicon-eject:before {
+ content: '\e63a';
+}
+.cicon-ellipse:before {
+ content: '\e74c';
+}
+.cicon-emoji:before {
+ content: '\e78d';
+}
+.cicon-emoji-o:before {
+ content: '\e6ee';
+}
+.cicon-equalizer:before {
+ content: '\e802';
+}
+.cicon-eraser:before {
+ content: '\e770';
+}
+.cicon-eraser-o:before {
+ content: '\e772';
+}
+.cicon-evaluate:before {
+ content: '\e7f0';
+}
+.cicon-evaluate-o:before {
+ content: '\e700';
+}
+.cicon-event-close:before {
+ content: '\e6a5';
+}
+.cicon-event-done:before {
+ content: '\e6b2';
+}
+.cicon-event-list:before {
+ content: '\e6b8';
+}
+.cicon-explore:before {
+ content: '\e628';
+}
+.cicon-explore-line:before {
+ content: '\e719';
+}
+.cicon-explore-line-o:before {
+ content: '\e710';
+}
+.cicon-explore-o:before {
+ content: '\e626';
+}
+.cicon-extension:before {
+ content: '\e620';
+}
+.cicon-extension-o:before {
+ content: '\e63f';
+}
+.cicon-eye:before {
+ content: '\e740';
+}
+.cicon-eye-favor:before {
+ content: '\e7b4';
+}
+.cicon-eye-favor-o:before {
+ content: '\e7b5';
+}
+.cicon-eye-o:before {
+ content: '\e741';
+}
+.cicon-eye-off:before {
+ content: '\e7b3';
+}
+.cicon-eye-off-o:before {
+ content: '\e7b2';
+}
+.cicon-facebook:before {
+ content: '\e6ea';
+}
+.cicon-favorite:before {
+ content: '\e623';
+}
+.cicon-favorite-o:before {
+ content: '\e621';
+}
+.cicon-female:before {
+ content: '\e72f';
+}
+.cicon-file:before {
+ content: '\e857';
+}
+.cicon-file-copy:before {
+ content: '\e85c';
+}
+.cicon-file-copy-o:before {
+ content: '\e7bc';
+}
+.cicon-file-o:before {
+ content: '\e7bb';
+}
+.cicon-file-text:before {
+ content: '\e858';
+}
+.cicon-file-text-o:before {
+ content: '\e7b9';
+}
+.cicon-filter:before {
+ content: '\e6ec';
+}
+.cicon-fingerprint:before {
+ content: '\e63b';
+}
+.cicon-first-page:before {
+ content: '\e60c';
+}
+.cicon-flag:before {
+ content: '\e64d';
+}
+.cicon-flag-o:before {
+ content: '\e64c';
+}
+.cicon-flash-close:before {
+ content: '\e73b';
+}
+.cicon-flash-off:before {
+ content: '\e6d5';
+}
+.cicon-flash-on:before {
+ content: '\e6dc';
+}
+.cicon-flash-open:before {
+ content: '\e74f';
+}
+.cicon-folder:before {
+ content: '\e6a1';
+}
+.cicon-folder-add:before {
+ content: '\e6b4';
+}
+.cicon-folder-o:before {
+ content: '\e6b0';
+}
+.cicon-folder-special:before {
+ content: '\e65c';
+}
+.cicon-forward:before {
+ content: '\e601';
+}
+.cicon-fullscreen:before {
+ content: '\e915';
+}
+.cicon-fullscreen-exit:before {
+ content: '\e914';
+}
+.cicon-game:before {
+ content: '\e6c0';
+}
+.cicon-game-o:before {
+ content: '\e6d1';
+}
+.cicon-git-commit:before {
+ content: '\e7be';
+}
+.cicon-git-commit-o:before {
+ content: '\e7bd';
+}
+.cicon-github:before {
+ content: '\e6e9';
+}
+.cicon-github-circle:before {
+ content: '\ead8';
+}
+.cicon-goods:before {
+ content: '\e778';
+}
+.cicon-goodsnew:before {
+ content: '\e7bf';
+}
+.cicon-goodsnew-o:before {
+ content: '\e7c0';
+}
+.cicon-goods-o:before {
+ content: '\e70f';
+}
+.cicon-GooglePlaylogo:before {
+ content: '\e6e5';
+}
+.cicon-grid:before {
+ content: '\e6ce';
+}
+.cicon-grid-o:before {
+ content: '\e6cc';
+}
+.cicon-group:before {
+ content: '\e7f5';
+}
+.cicon-group-o:before {
+ content: '\e753';
+}
+.cicon-guanli:before {
+ content: '\e750';
+}
+.cicon-headset:before {
+ content: '\e6a4';
+}
+.cicon-headset-mic:before {
+ content: '\e6b1';
+}
+.cicon-help:before {
+ content: '\e66b';
+}
+.cicon-help-o:before {
+ content: '\e65e';
+}
+.cicon-home:before {
+ content: '\e70d';
+}
+.cicon-home-2:before {
+ content: '\e6fd';
+}
+.cicon-home-2-o:before {
+ content: '\e6cf';
+}
+.cicon-home-3:before {
+ content: '\e6fc';
+}
+.cicon-home-3-o:before {
+ content: '\e6e0';
+}
+.cicon-home-4:before {
+ content: '\e732';
+}
+.cicon-home-4-o:before {
+ content: '\e6e6';
+}
+.cicon-home-community:before {
+ content: '\e799';
+}
+.cicon-home-dot:before {
+ content: '\e794';
+}
+.cicon-home-dot-o:before {
+ content: '\e797';
+}
+.cicon-home-line:before {
+ content: '\e793';
+}
+.cicon-home-line-o:before {
+ content: '\e792';
+}
+.cicon-home-o:before {
+ content: '\e70a';
+}
+.cicon-home-sm:before {
+ content: '\e798';
+}
+.cicon-home-smile:before {
+ content: '\e79c';
+}
+.cicon-home-smile-o:before {
+ content: '\e7a0';
+}
+.cicon-home-smline:before {
+ content: '\e791';
+}
+.cicon-home-smline-o:before {
+ content: '\e731';
+}
+.cicon-home-sm-o:before {
+ content: '\e79b';
+}
+.cicon-hotel:before {
+ content: '\e7a8';
+}
+.cicon-hotel-o:before {
+ content: '\e7a3';
+}
+.cicon-huohu:before {
+ content: '\e72e';
+}
+.cicon-IE:before {
+ content: '\e922';
+}
+.cicon-image-text:before {
+ content: '\e781';
+}
+.cicon-image-text-o:before {
+ content: '\e758';
+}
+.cicon-import-export:before {
+ content: '\e615';
+}
+.cicon-info:before {
+ content: '\e6ef';
+}
+.cicon-info-o:before {
+ content: '\e705';
+}
+.cicon-input:before {
+ content: '\e75f';
+}
+.cicon-input-o:before {
+ content: '\e6c8';
+}
+.cicon-keyboard:before {
+ content: '\e6b6';
+}
+.cicon-kinds:before {
+ content: '\e748';
+}
+.cicon-last-page:before {
+ content: '\e60d';
+}
+.cicon-layout:before {
+ content: '\e7e8';
+}
+.cicon-layout-o:before {
+ content: '\e7e7';
+}
+.cicon-LightMode:before {
+ content: '\e7ba';
+}
+.cicon-link:before {
+ content: '\e6ab';
+}
+.cicon-link-off:before {
+ content: '\e6b9';
+}
+.cicon-loader-fill:before {
+ content: '\e76d';
+}
+.cicon-loading:before {
+ content: '\e746';
+}
+.cicon-loading1:before {
+ content: '\e749';
+}
+.cicon-loading2:before {
+ content: '\e7f1';
+}
+.cicon-location-off:before {
+ content: '\e671';
+}
+.cicon-location-off-o:before {
+ content: '\e66d';
+}
+.cicon-location-on:before {
+ content: '\e65f';
+}
+.cicon-location-on-o:before {
+ content: '\e661';
+}
+.cicon-lock:before {
+ content: '\e6ad';
+}
+.cicon-lock-o:before {
+ content: '\e6b3';
+}
+.cicon-lock-open:before {
+ content: '\e6ba';
+}
+.cicon-logout:before {
+ content: '\e76e';
+}
+.cicon-loop:before {
+ content: '\e616';
+}
+.cicon-magic:before {
+ content: '\e6b7';
+}
+.cicon-magic-o:before {
+ content: '\e6c2';
+}
+.cicon-mail:before {
+ content: '\e6be';
+}
+.cicon-mail-o:before {
+ content: '\e6bc';
+}
+.cicon-male:before {
+ content: '\e730';
+}
+.cicon-mic:before {
+ content: '\e656';
+}
+.cicon-mic-none:before {
+ content: '\e642';
+}
+.cicon-mic-off:before {
+ content: '\e652';
+}
+.cicon-miniprogram:before {
+ content: '\e7d6';
+}
+.cicon-mobile:before {
+ content: '\e854';
+}
+.cicon-mobile-o:before {
+ content: '\e7b6';
+}
+.cicon-moneybag:before {
+ content: '\e7ce';
+}
+.cicon-moneybag-o:before {
+ content: '\e7d1';
+}
+.cicon-more:before {
+ content: '\e688';
+}
+.cicon-more-tag:before {
+ content: '\e672';
+}
+.cicon-move:before {
+ content: '\e768';
+}
+.cicon-move-round:before {
+ content: '\e602';
+}
+.cicon-move-round-o:before {
+ content: '\e603';
+}
+.cicon-music:before {
+ content: '\e795';
+}
+.cicon-music-off:before {
+ content: '\e796';
+}
+.cicon-my:before {
+ content: '\e78c';
+}
+.cicon-my-o:before {
+ content: '\e78b';
+}
+.cicon-near-me:before {
+ content: '\e654';
+}
+.cicon-near-me-o:before {
+ content: '\e649';
+}
+.cicon-not:before {
+ content: '\e667';
+}
+.cicon-notice:before {
+ content: '\e666';
+}
+.cicon-notice-active:before {
+ content: '\e66f';
+}
+.cicon-notice-active-o:before {
+ content: '\e65d';
+}
+.cicon-notice-o:before {
+ content: '\e664';
+}
+.cicon-notice-off:before {
+ content: '\e6b5';
+}
+.cicon-notice-off-o:before {
+ content: '\e6bb';
+}
+.cicon-numcode:before {
+ content: '\e755';
+}
+.cicon-order:before {
+ content: '\e786';
+}
+.cicon-order-o:before {
+ content: '\e7b8';
+}
+.cicon-paint:before {
+ content: '\e75d';
+}
+.cicon-paint-o:before {
+ content: '\e75a';
+}
+.cicon-palette:before {
+ content: '\e696';
+}
+.cicon-palette-o:before {
+ content: '\e691';
+}
+.cicon-pause:before {
+ content: '\e669';
+}
+.cicon-pause-circle:before {
+ content: '\e678';
+}
+.cicon-person:before {
+ content: '\e679';
+}
+.cicon-person-add:before {
+ content: '\e668';
+}
+.cicon-person-add-o:before {
+ content: '\e66a';
+}
+.cicon-person-o:before {
+ content: '\e67d';
+}
+.cicon-person-pin-circle:before {
+ content: '\e66c';
+}
+.cicon-person-pin-circle-o:before {
+ content: '\e670';
+}
+.cicon-phone:before {
+ content: '\e6f0';
+}
+.cicon-phone-call:before {
+ content: '\e6d7';
+}
+.cicon-pic:before {
+ content: '\e756';
+}
+.cicon-pic-o:before {
+ content: '\e69e';
+}
+.cicon-pin-drop:before {
+ content: '\e648';
+}
+.cicon-pin-drop-o:before {
+ content: '\e655';
+}
+.cicon-place:before {
+ content: '\e651';
+}
+.cicon-place-o:before {
+ content: '\e650';
+}
+.cicon-play-arrow:before {
+ content: '\e66e';
+}
+.cicon-play-circle:before {
+ content: '\e674';
+}
+.cicon-play-circle-o:before {
+ content: '\e67f';
+}
+.cicon-popover:before {
+ content: '\e74e';
+}
+.cicon-popover-o:before {
+ content: '\e757';
+}
+.cicon-present:before {
+ content: '\e73a';
+}
+.cicon-present-o:before {
+ content: '\e711';
+}
+.cicon-progress:before {
+ content: '\e784';
+}
+.cicon-qq:before {
+ content: '\e7d9';
+}
+.cicon-qr-code-fill:before {
+ content: '\e767';
+}
+.cicon-qr-code-line:before {
+ content: '\e75e';
+}
+.cicon-quill:before {
+ content: '\e760';
+}
+.cicon-quill-o:before {
+ content: '\e761';
+}
+.cicon-radio:before {
+ content: '\e6d4';
+}
+.cicon-radiobox:before {
+ content: '\e763';
+}
+.cicon-radiobox-o:before {
+ content: '\e75b';
+}
+.cicon-recharge:before {
+ content: '\e71c';
+}
+.cicon-recharge-o:before {
+ content: '\e71d';
+}
+.cicon-record:before {
+ content: '\e7a4';
+}
+.cicon-record-o:before {
+ content: '\e7a6';
+}
+.cicon-redo:before {
+ content: '\e612';
+}
+.cicon-redpacket:before {
+ content: '\e7d3';
+}
+.cicon-redpacket-o:before {
+ content: '\e71a';
+}
+.cicon-refresh:before {
+ content: '\e611';
+}
+.cicon-repair:before {
+ content: '\e73f';
+}
+.cicon-repair-o:before {
+ content: '\e73e';
+}
+.cicon-repeat:before {
+ content: '\e617';
+}
+.cicon-replay:before {
+ content: '\e619';
+}
+.cicon-reply:before {
+ content: '\e618';
+}
+.cicon-reply-all:before {
+ content: '\e614';
+}
+.cicon-road-map:before {
+ content: '\e769';
+}
+.cicon-road-map-o:before {
+ content: '\e76a';
+}
+.cicon-round:before {
+ content: '\e716';
+}
+.cicon-round-angle:before {
+ content: '\e6f5';
+}
+.cicon-round-angle-o:before {
+ content: '\e6f6';
+}
+.cicon-round-arrow-line:before {
+ content: '\e734';
+}
+.cicon-round-box:before {
+ content: '\e604';
+}
+.cicon-safe:before {
+ content: '\e77f';
+}
+.cicon-safe-check:before {
+ content: '\e875';
+}
+.cicon-safe-check-o:before {
+ content: '\e876';
+}
+.cicon-safe-flash:before {
+ content: '\e783';
+}
+.cicon-safe-flash-o:before {
+ content: '\e775';
+}
+.cicon-safe-key:before {
+ content: '\e76c';
+}
+.cicon-safe-key-o:before {
+ content: '\e766';
+}
+.cicon-safe-o:before {
+ content: '\e77e';
+}
+.cicon-save:before {
+ content: '\e677';
+}
+.cicon-save-o:before {
+ content: '\e684';
+}
+.cicon-scan:before {
+ content: '\e703';
+}
+.cicon-scissors:before {
+ content: '\e762';
+}
+.cicon-search:before {
+ content: '\e6f7';
+}
+.cicon-search-line:before {
+ content: '\e771';
+}
+.cicon-searchlist:before {
+ content: '\e720';
+}
+.cicon-search-o:before {
+ content: '\e782';
+}
+.cicon-search-sm:before {
+ content: '\e631';
+}
+.cicon-service:before {
+ content: '\e73d';
+}
+.cicon-service-fill:before {
+ content: '\e704';
+}
+.cicon-service-o:before {
+ content: '\e721';
+}
+.cicon-set:before {
+ content: '\e773';
+}
+.cicon-set-list:before {
+ content: '\e76f';
+}
+.cicon-set-o:before {
+ content: '\e774';
+}
+.cicon-settings:before {
+ content: '\e77a';
+}
+.cicon-settings-o:before {
+ content: '\e780';
+}
+.cicon-share:before {
+ content: '\e6c5';
+}
+.cicon-share-line-o:before {
+ content: '\e74d';
+}
+.cicon-shengji:before {
+ content: '\e747';
+}
+.cicon-shopping-cart:before {
+ content: '\e685';
+}
+.cicon-shopping-cart-o:before {
+ content: '\e676';
+}
+.cicon-show:before {
+ content: '\e785';
+}
+.cicon-show-o:before {
+ content: '\e787';
+}
+.cicon-shuffle:before {
+ content: '\e61a';
+}
+.cicon-sip:before {
+ content: '\e764';
+}
+.cicon-sip-o:before {
+ content: '\e765';
+}
+.cicon-skip-next:before {
+ content: '\e6dd';
+}
+.cicon-skip-previous:before {
+ content: '\e6d6';
+}
+.cicon-slack:before {
+ content: '\e87b';
+}
+.cicon-slack-square:before {
+ content: '\e891';
+}
+.cicon-sort:before {
+ content: '\e6bf';
+}
+.cicon-sort-order:before {
+ content: '\e6fe';
+}
+.cicon-sound:before {
+ content: '\e77b';
+}
+.cicon-sponsor:before {
+ content: '\e77c';
+}
+.cicon-sponsor-o:before {
+ content: '\e77d';
+}
+.cicon-star:before {
+ content: '\e683';
+}
+.cicon-star-half:before {
+ content: '\e67c';
+}
+.cicon-star-o:before {
+ content: '\e67b';
+}
+.cicon-stock:before {
+ content: '\e789';
+}
+.cicon-stop:before {
+ content: '\e6db';
+}
+.cicon-store:before {
+ content: '\e7ac';
+}
+.cicon-store-0:before {
+ content: '\e7ab';
+}
+.cicon-store-2:before {
+ content: '\e7a7';
+}
+.cicon-store-2-o:before {
+ content: '\e7a5';
+}
+.cicon-sub-left:before {
+ content: '\e60b';
+}
+.cicon-sub-right:before {
+ content: '\e60f';
+}
+.cicon-subtitles:before {
+ content: '\e6da';
+}
+.cicon-subtitles-o:before {
+ content: '\e6d8';
+}
+.cicon-sync-alt:before {
+ content: '\e613';
+}
+.cicon-tag:before {
+ content: '\e751';
+}
+.cicon-tag-o:before {
+ content: '\e752';
+}
+.cicon-taobao:before {
+ content: '\e712';
+}
+.cicon-terminal:before {
+ content: '\e7c1';
+}
+.cicon-terminal-o:before {
+ content: '\e7c2';
+}
+.cicon-thumb-down:before {
+ content: '\e6c1';
+}
+.cicon-thumb-down-o:before {
+ content: '\e6c9';
+}
+.cicon-thumb-up:before {
+ content: '\e6c6';
+}
+.cicon-thumb-up-line:before {
+ content: '\e71b';
+}
+.cicon-thumb-up-line-o:before {
+ content: '\e6eb';
+}
+.cicon-thumb-up-o:before {
+ content: '\e6cb';
+}
+.cicon-ticket:before {
+ content: '\e800';
+}
+.cicon-ticket-o:before {
+ content: '\e701';
+}
+.cicon-time:before {
+ content: '\e6f8';
+}
+.cicon-time-o:before {
+ content: '\e6f9';
+}
+.cicon-timer:before {
+ content: '\e69c';
+}
+.cicon-title:before {
+ content: '\e82f';
+}
+.cicon-titles:before {
+ content: '\e745';
+}
+.cicon-toggle:before {
+ content: '\e706';
+}
+.cicon-toggle-o:before {
+ content: '\e733';
+}
+.cicon-topbar:before {
+ content: '\e788';
+}
+.cicon-translate:before {
+ content: '\e79a';
+}
+.cicon-tree:before {
+ content: '\e659';
+}
+.cicon-Tt:before {
+ content: '\e7a2';
+}
+.cicon-twiter:before {
+ content: '\e6e8';
+}
+.cicon-cicon-community-o:before {
+ content: '\e6df';
+}
+.cicon-undo:before {
+ content: '\e61b';
+}
+.cicon-unfold-less:before {
+ content: '\e60e';
+}
+.cicon-unfold-more:before {
+ content: '\e609';
+}
+.cicon-upstage:before {
+ content: '\e724';
+}
+.cicon-upstage-o:before {
+ content: '\e725';
+}
+.cicon-view-agenda:before {
+ content: '\e639';
+}
+.cicon-view-array:before {
+ content: '\e636';
+}
+.cicon-view-carousel:before {
+ content: '\e638';
+}
+.cicon-view-column:before {
+ content: '\e632';
+}
+.cicon-view-day:before {
+ content: '\e627';
+}
+.cicon-view-headline:before {
+ content: '\e62b';
+}
+.cicon-view-list:before {
+ content: '\e63c';
+}
+.cicon-view-module:before {
+ content: '\e629';
+}
+.cicon-view-quilt:before {
+ content: '\e630';
+}
+.cicon-volume:before {
+ content: '\e6c4';
+}
+.cicon-volume-off:before {
+ content: '\e6cd';
+}
+.cicon-warn:before {
+ content: '\e662';
+}
+.cicon-warn-o:before {
+ content: '\e675';
+}
+.cicon-wechat-pay:before {
+ content: '\e7e6';
+}
+.cicon-weibo-fill:before {
+ content: '\e7e4';
+}
+.cicon-weibo-o:before {
+ content: '\e7e3';
+}
+.cicon-weixin:before {
+ content: '\e6de';
+}
+.cicon-whatshot:before {
+ content: '\e6ca';
+}
+.cicon-whatshot-o:before {
+ content: '\e6d0';
+}
+.cicon-wifi:before {
+ content: '\e6d2';
+}
+.cicon-wifi-off:before {
+ content: '\e6d3';
+}
+.cicon-yamaxun:before {
+ content: '\e7b7';
+}
+.cicon-zuoji:before {
+ content: '\e754';
+}
diff --git a/sheep/scss/icon/_icon.scss b/sheep/scss/icon/_icon.scss
new file mode 100644
index 0000000..f277fc8
--- /dev/null
+++ b/sheep/scss/icon/_icon.scss
@@ -0,0 +1,181 @@
+@font-face {
+ font-family: 'colorui'; /* Project id 2620914 */
+ src: url('data:application/x-font-woff2;charset=utf-8;base64,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')
+ format('woff2');
+ /* #ifdef MP-ALIPAY */
+ src: url('//at.alicdn.com/t/font_2620914_57y9q5zpbel.woff?t=1624238023908') format('woff'),
+ url('//at.alicdn.com/t/font_2620914_57y9q5zpbel.ttf?t=1624238023908') format('truetype');
+ /* #endif */
+}
+
+[class*='_icon-'] {
+ font-family: 'colorui' !important;
+ display: inline-block;
+}
+@font-face {
+ font-family: 'ui-num';
+ src: url('data:application/x-font-ttf;base64,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')
+ format('woff2');
+ font-weight: normal;
+ font-style: normal;
+}
+
+._icon-checkbox:before {
+ content: '\e713';
+}
+
+._icon-box:before {
+ content: '\e714';
+}
+
+._icon-checkbox-o:before {
+ content: '\e715';
+}
+
+._icon-round:before {
+ content: '\e716';
+}
+
+._icon-home-o:before {
+ content: '\e70a';
+}
+
+._icon-home:before {
+ content: '\e70d';
+}
+
+._icon-edit:before {
+ content: '\e649';
+}
+
+._icon-close:before {
+ content: '\e6ed';
+}
+
+._icon-check-round:before {
+ content: '\e6f1';
+}
+
+._icon-check-round-o:before {
+ content: '\e6f2';
+}
+
+._icon-close-round:before {
+ content: '\e6f3';
+}
+
+._icon-close-round-o:before {
+ content: '\e6f4';
+}
+
+._icon-waiting:before {
+ content: '\e6f8';
+}
+
+._icon-waiting-o:before {
+ content: '\e6f9';
+}
+
+._icon-warn:before {
+ content: '\e662';
+}
+
+._icon-warn-o:before {
+ content: '\e675';
+}
+
+._icon-more:before {
+ content: '\e688';
+}
+
+._icon-delete:before {
+ content: '\e707';
+}
+
+._icon-delete-o:before {
+ content: '\e709';
+}
+
+._icon-add-round:before {
+ content: '\e717';
+}
+
+._icon-add-round-o:before {
+ content: '\e718';
+}
+
+._icon-add:before {
+ content: '\e6e4';
+}
+
+._icon-info:before {
+ content: '\e6ef';
+}
+
+._icon-info-o:before {
+ content: '\e705';
+}
+
+._icon-move:before {
+ content: '\e768';
+}
+
+._icon-title:before {
+ content: '\e82f';
+}
+
+._icon-titles:before {
+ content: '\e745';
+}
+
+._icon-loading:before {
+ content: '\e746';
+}
+
+._icon-copy-o:before {
+ content: '\e7bc';
+}
+
+._icon-copy:before {
+ content: '\e85c';
+}
+
+._icon-loader:before {
+ content: '\e76d';
+}
+
+._icon-search:before {
+ content: '\e782';
+}
+
+._icon-back:before {
+ content: '\e600';
+}
+
+._icon-forward:before {
+ content: '\e601';
+}
+
+._icon-arrow:before {
+ content: '\e608';
+}
+
+._icon-drop-down:before {
+ content: '\e61c';
+}
+
+._icon-drop-up:before {
+ content: '\e61d';
+}
+
+._icon-check:before {
+ content: '\e69f';
+}
+
+._icon-move-round:before {
+ content: '\e602';
+}
+
+._icon-move-round-o:before {
+ content: '\e603';
+}
diff --git a/sheep/scss/icon/_sheepicon.scss b/sheep/scss/icon/_sheepicon.scss
new file mode 100644
index 0000000..cf7ea08
--- /dev/null
+++ b/sheep/scss/icon/_sheepicon.scss
@@ -0,0 +1,94 @@
+@font-face {
+ font-family: 'sheepicon';
+ src: url('data:application/x-font-woff2;charset=utf-8;base64,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')
+ format('woff2');
+}
+
+[class*='sicon-'] {
+ font-family: 'sheepicon';
+ display: inline-block;
+}
+
+.sicon-edit:before {
+ content: '\e711';
+}
+
+.sicon-basic:before {
+ content: '\e712';
+}
+
+.sicon-home:before {
+ content: '\e70c';
+}
+
+.sicon-more:before {
+ content: '\e707';
+}
+
+.sicon-check-line:before {
+ content: '\e708';
+}
+
+.sicon-transport:before {
+ content: '\e709';
+}
+
+.sicon-goods-card:before {
+ content: '\e70a';
+}
+
+.sicon-collect:before {
+ content: '\e70b';
+}
+
+.sicon-warning-line:before {
+ content: '\e70d';
+}
+
+.sicon-score1:before {
+ content: '\e70e';
+}
+
+.sicon-score2:before {
+ content: '\e70f';
+}
+
+.sicon-goods-list:before {
+ content: '\e710';
+}
+
+.sicon-back:before {
+ content: '\e706';
+}
+
+.sicon-unchecked:before {
+ content: '\e703';
+}
+
+.sicon-warning-outline:before {
+ content: '\e6ff';
+}
+
+.sicon-question-outline:before {
+ content: '\e700';
+}
+
+.sicon-circlecheck:before {
+ content: '\e701';
+}
+
+.sicon-circleclose:before {
+ content: '\e702';
+}
+
+.sicon-delivery:before {
+ content: '\e6fd';
+}
+
+.sicon-orders:before {
+ content: '\e6fe';
+}
+
+.sicon-qrcode:before {
+ content: '\e6f9';
+}
diff --git a/sheep/scss/icon/_style.scss b/sheep/scss/icon/_style.scss
new file mode 100644
index 0000000..a2c4dc8
--- /dev/null
+++ b/sheep/scss/icon/_style.scss
@@ -0,0 +1,43 @@
+@import './icon'; //核心图标库
+@import './coloricon'; //扩展图标库
+@import './sheepicon';
+.icon-spin {
+ animation: icon-spin 2s infinite linear;
+}
+
+.icon-pulse {
+ animation: icon-spin 1s infinite steps(8);
+}
+
+@keyframes icon-spin {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(359deg);
+ }
+}
+.icon-90 {
+ transform: rotate(90deg);
+}
+.icon-180 {
+ transform: rotate(180deg);
+}
+.icon-270 {
+ transform: rotate(270deg);
+}
+.icon-x {
+ transform: scale(-1, 1);
+}
+.icon-y {
+ transform: scale(1, -1);
+}
+.icon-fw {
+ width: calc(18em / 14);
+ text-align: center;
+}
+@each $class, $value in $iconsize {
+ .icon-#{$class} {
+ transform: scale(#{$value});
+ }
+}
diff --git a/sheep/scss/index.scss b/sheep/scss/index.scss
new file mode 100644
index 0000000..c841956
--- /dev/null
+++ b/sheep/scss/index.scss
@@ -0,0 +1,27 @@
+@import './tools';
+@import './ui';
+
+/* 字体文件 */
+@font-face {
+ font-family: OPPOSANS;
+ src: url('~@/sheep/scss/font/OPPOSANS-M-subfont.ttf');
+}
+.font-OPPOSANS {
+ font-family: OPPOSANS;
+}
+page {
+ -webkit-overflow-scrolling: touch; // 解决ios滑动不流畅
+ height: 100%;
+ width: 100%;
+ // font-family: OPPOSANS;
+ word-break: break-all; //英文文本不换行
+ white-space: normal;
+ background-color: $bg-page;
+ color: $dark-3;
+}
+::-webkit-scrollbar {
+ width: 0;
+ height: 0;
+ color: transparent;
+ display: none;
+}
diff --git a/sheep/scss/style/_avatar.scss b/sheep/scss/style/_avatar.scss
new file mode 100644
index 0000000..e69de29
diff --git a/sheep/scss/style/_background.scss b/sheep/scss/style/_background.scss
new file mode 100644
index 0000000..775f37f
--- /dev/null
+++ b/sheep/scss/style/_background.scss
@@ -0,0 +1,204 @@
+/* ==================
+ 背景
+ ==================== */
+/* -- 基础色 -- */
+@each $color, $value in map-merge($colors, $darks) {
+ .bg-#{$color} {
+ background-color: $value !important;
+ @if $color == 'yellow' {
+ color: #333333 !important;
+ } @else {
+ color: #ffffff !important;
+ }
+ }
+}
+
+/* -- 浅色 -- */
+@each $color, $value in $colors {
+ .bg-#{$color}-light {
+ background-image: linear-gradient(45deg, white, mix(white, $value, 85%)) !important;
+ color: $value !important;
+ }
+
+ .bg-#{$color}-thin {
+ background-color: rgba($value, var(--ui-BG-opacity)) !important;
+ color: $value !important;
+ }
+}
+
+/* -- 渐变色 -- */
+
+@each $color, $value in $colors {
+ @each $colorsub, $valuesub in $colors {
+ @if $color != $colorsub {
+ .bg-#{$color}-#{$colorsub} {
+ // background-color: $value !important;
+ background-image: linear-gradient(130deg, $value, $valuesub) !important;
+ color: #ffffff !important;
+ }
+ }
+ }
+}
+.bg-yellow-gradient {
+ background-image: linear-gradient(45deg, #f5fe00, #ff6600) !important;
+ color: $dark-3 !important;
+}
+.bg-orange-gradient {
+ background-image: linear-gradient(90deg, #ff6000, #fe832a) !important;
+ color: $white !important;
+}
+.bg-red-gradient {
+ background-image: linear-gradient(45deg, #f33a41, #ed0586) !important;
+ color: $white !important;
+}
+.bg-pink-gradient {
+ background-image: linear-gradient(45deg, #fea894, #ff1047) !important;
+ color: $white !important;
+}
+.bg-mauve-gradient {
+ background-image: linear-gradient(45deg, #c01f95, #7115cc) !important;
+ color: $white !important;
+}
+.bg-purple-gradient {
+ background-image: linear-gradient(45deg, #9829ea, #5908fb) !important;
+ color: $white !important;
+}
+.bg-blue-gradient {
+ background-image: linear-gradient(45deg, #00b8f9, #0166eb) !important;
+ color: $white !important;
+}
+.bg-cyan-gradient {
+ background-image: linear-gradient(45deg, #06edfe, #48b2fe) !important;
+ color: $white !important;
+}
+.bg-green-gradient {
+ background-image: linear-gradient(45deg, #3ab54a, #8cc63f) !important;
+ color: $white !important;
+}
+.bg-olive-gradient {
+ background-image: linear-gradient(45deg, #90e630, #39d266) !important;
+ color: $white !important;
+}
+.bg-grey-gradient {
+ background-image: linear-gradient(45deg, #9aadb9, #354855) !important;
+ color: $white !important;
+}
+.bg-brown-gradient {
+ background-image: linear-gradient(45deg, #ca6f2e, #cb1413) !important;
+ color: $white !important;
+}
+
+@each $color, $value in $grays {
+ .bg-#{$color} {
+ background-color: $value !important;
+ color: #333333 !important;
+ }
+}
+
+.bg-square {
+ @include bg-square;
+}
+.bg-none {
+ background: transparent !important;
+ color: inherit !important;
+}
+
+[class*='bg-mask'] {
+ position: relative;
+ //background: transparent !important;
+ color: #ffffff !important;
+ > view,
+ > text {
+ position: relative;
+ z-index: 1;
+ color: #ffffff;
+ }
+ &::before {
+ content: '';
+ border-radius: inherit;
+ width: 100%;
+ height: 100%;
+ @include position-center;
+ background-color: rgba(0, 0, 0, 0.4);
+ z-index: 0;
+ }
+ @at-root .bg-mask-80::before {
+ background: rgba(0, 0, 0, 0.8) !important;
+ }
+ @at-root .bg-mask-50::before {
+ background: rgba(0, 0, 0, 0.5) !important;
+ }
+ @at-root .bg-mask-20::before {
+ background: rgba(0, 0, 0, 0.2) !important;
+ }
+ @at-root .bg-mask-top::before {
+ background-color: rgba(0, 0, 0, 0);
+ background-image: linear-gradient(rgba(0, 0, 0, 1), rgba(0, 0, 0, 0.618), rgba(0, 0, 0, 0.01));
+ }
+ @at-root .bg-white-top {
+ background-color: rgba(0, 0, 0, 0);
+ background-image: linear-gradient(rgba(255, 255, 255, 1), rgba(255, 255, 255, 0.3));
+ }
+ @at-root .bg-mask-bottom::before {
+ background-color: rgba(0, 0, 0, 0);
+ background-image: linear-gradient(rgba(0, 0, 0, 0.01), rgba(0, 0, 0, 0.618), rgba(0, 0, 0, 1));
+ }
+}
+.bg-img {
+ background-size: cover;
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+[class*='bg-blur'] {
+ position: relative;
+ > view,
+ > text {
+ position: relative;
+ z-index: 1;
+ }
+ &::before {
+ content: '';
+ width: 100%;
+ height: 100%;
+ @include position-center;
+ border-radius: inherit;
+ transform-origin: 0 0;
+ pointer-events: none;
+ box-sizing: border-box;
+ }
+}
+@supports (-webkit-backdrop-filter: blur(20px)) or (backdrop-filter: blur(20px)) {
+ .bg-blur::before {
+ @include blur;
+ background-color: var(--ui-Blur-1);
+ }
+ .bg-blur-1::before {
+ @include blur;
+ background-color: var(--ui-Blur-2);
+ }
+ .bg-blur-2::before {
+ @include blur;
+ background-color: var(--ui-Blur-3);
+ }
+}
+@supports not (backdrop-filter: blur(5px)) {
+ .bg-blur {
+ color: var(--ui-TC);
+ &::before {
+ background-color: var(--ui-BG);
+ }
+ }
+ .bg-blur-1 {
+ color: var(--ui-TC);
+ &::before {
+ background-color: var(--ui-BG-1);
+ }
+ }
+ .bg-blur-2 {
+ color: var(--ui-TC);
+ &::before {
+ background-color: var(--ui-BG-2);
+ }
+ }
+}
diff --git a/sheep/scss/style/_border.scss b/sheep/scss/style/_border.scss
new file mode 100644
index 0000000..4ef1d54
--- /dev/null
+++ b/sheep/scss/style/_border.scss
@@ -0,0 +1,140 @@
+/* ==================
+ 边框
+ ==================== */
+/* -- 实线 -- */
+.border {
+ overflow: initial !important;
+ @at-root [class*='border'],
+ [class*='dashed'] {
+ position: relative;
+ &.dline {
+ --ui-Border: var(--ui-BG-3);
+ }
+ &::after {
+ content: ' ';
+ width: 200%;
+ height: 200%;
+ position: absolute;
+ z-index: 0;
+ top: 0;
+ left: 0;
+ transform: scale(0.5);
+ transform-origin: 0 0;
+ pointer-events: none;
+ box-sizing: border-box;
+ border-radius: inherit;
+ }
+ &.radius::after {
+ border-radius: calc(#{$radius} * 2);
+ }
+ &.round::after {
+ border-radius: #{$round-pill};
+ }
+ }
+ &::after {
+ border: 1px solid var(--ui-Border);
+ }
+ &s::after {
+ border: 4rpx solid var(--ui-Border);
+ }
+ &ss::after {
+ border: 8rpx solid var(--ui-Border);
+ }
+ @each $value in (top, right, bottom, left) {
+ &-#{$value}::after {
+ border-#{$value}: 1px solid var(--ui-Border);
+ }
+ &s-#{$value}::after {
+ border-#{$value}: 4rpx solid var(--ui-Border);
+ }
+ &ss-#{$value}::after {
+ border-#{$value}: 8rpx solid var(--ui-Border);
+ }
+ }
+}
+/* -- 虚线 -- */
+.dashed {
+ &::after {
+ border: 4rpx dashed var(--ui-Border);
+ }
+ &s::after {
+ border: 6rpx dashed var(--ui-Border);
+ }
+ @each $value in (top, right, bottom, left) {
+ &-#{$value}::after {
+ border-#{$value}: 4rpx dashed var(--ui-Border);
+ }
+ &s-#{$value}::after {
+ border-#{$value}: 6rpx dashed var(--ui-Border);
+ }
+ }
+}
+@each $color, $value in map-merge($colors, map-merge($darks, $grays)) {
+ .border-#{$color}::after,
+ .border-#{$color}[class*='-shine']::before {
+ border-color: $value !important;
+ }
+}
+@each $value in (a, b, c, d, e) {
+ .main-#{$value}-border::after,
+ .main-#{$value}-border[class*='-shine']::before {
+ border-color: var(--main-#{$value}) !important;
+ }
+}
+.dashed-shine,
+.dasheds-shine {
+ position: relative;
+ overflow: hidden;
+ &::after,
+ &::before {
+ border-style: dashed;
+ border-color: var(--ui-Border);
+ animation: shineafter 1s infinite linear;
+ width: calc(200% + 40px);
+ height: 200%;
+ border-width: 2px 0;
+ }
+ &::before {
+ content: ' ';
+ position: absolute;
+ transform: scale(0.5);
+ transform-origin: 0 0;
+ pointer-events: none;
+ box-sizing: border-box;
+ animation: shinebefore 1s infinite linear;
+ width: 200%;
+ height: calc(200% + 40px);
+ border-width: 0 2px;
+ }
+}
+.dasheds-shine {
+ &::after,
+ &::before {
+ border-width: 4px 0;
+ }
+ &::before {
+ border-width: 0 4px;
+ }
+}
+
+@keyframes shineafter {
+ 0% {
+ top: 0;
+ left: -22px;
+ }
+ 100% {
+ top: 0px;
+ left: 0px;
+ }
+}
+
+@keyframes shinebefore {
+ 0% {
+ top: -22px;
+ left: 0;
+ }
+ 100% {
+ top: 0px;
+ left: 0px;
+ }
+}
diff --git a/sheep/scss/style/_button.scss b/sheep/scss/style/_button.scss
new file mode 100644
index 0000000..7069345
--- /dev/null
+++ b/sheep/scss/style/_button.scss
@@ -0,0 +1,87 @@
+.ui-btn-box {
+ display: inline-block;
+}
+.ui-btn {
+ position: relative;
+ border: 0rpx;
+ display: inline-block;
+ align-items: center;
+ justify-content: center;
+ box-sizing: border-box;
+ padding: 0.7857em 1.5em 0.7857em;
+ font-size: 28rpx;
+ line-height: 1em;
+ text-align: center;
+ text-decoration: none;
+ overflow: visible;
+ margin: 0 0.25em 0 0;
+ transform: translate(0rpx, 0rpx);
+ border-radius: $radius;
+ white-space: nowrap;
+ color: var(--text-a);
+ background-color: var(--ui-BG);
+ vertical-align: baseline;
+ &:first-child:last-child {
+ margin: 0;
+ }
+ &:not([class*='round'])::after {
+ border-radius: calc(#{$radius} * 2);
+ }
+ &:not([class*='border'])::after {
+ // content: ' ';
+ // width: 200%;
+ // height: 200%;
+ // display: block;
+ // position: absolute;
+ // z-index: 0;
+ // top: 0;
+ // left: 0;
+ // transform: scale(0.5);
+ // transform-origin: 0 0;
+ // pointer-events: none;
+ // box-sizing: border-box;
+ display: none;
+ }
+ &.round::after {
+ border-radius: #{$round-pill};
+ }
+ &.icon {
+ padding: 0.8em 0.8em;
+ }
+
+ &.sm {
+ font-size: 24rpx;
+ }
+
+ &.lg {
+ font-size: 32rpx;
+ }
+
+ &.xl {
+ font-size: 36rpx;
+ }
+
+ &.block {
+ width: 100%;
+ display: block;
+ font-size: 32rpx;
+ }
+
+ &[disabled] {
+ opacity: 0.6;
+ }
+
+ &.none-style {
+ background-color: transparent !important;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ display: flex;
+ }
+}
+
+.ui-btn:not(.icon) [class*='icon-'] {
+ margin: 0 0.25em;
+}
diff --git a/sheep/scss/style/_card.scss b/sheep/scss/style/_card.scss
new file mode 100644
index 0000000..17aa6b3
--- /dev/null
+++ b/sheep/scss/style/_card.scss
@@ -0,0 +1,353 @@
+/* ==================
+ 卡片
+ ==================== */
+
+.ui-cards {
+ display: block;
+ overflow: hidden;
+ & .ui-btn.badge {
+ top: 0;
+ right: 0;
+ font-size: 24rpx;
+ padding: 0rpx 15rpx;
+ height: 40rpx;
+ }
+ &.no-card > .ui-item {
+ margin: 0rpx;
+ border-radius: 0rpx;
+ }
+ & > .ui-item {
+ display: block;
+ overflow: hidden;
+ border-radius: 10rpx;
+ margin: 30rpx;
+ }
+ & > .ui-item.shadow-blur {
+ overflow: initial;
+ }
+ .grid.grid-square {
+ margin-bottom: -20rpx;
+ }
+ &.article {
+ display: block;
+ & > .ui-item {
+ padding: 30rpx;
+ background-color: var(--box-bg);
+ display: flex;
+ align-items: flex-start;
+ }
+ & > .time {
+ padding: 30rpx 0 0 30rpx;
+ }
+ & > .ui-item .title {
+ font-size: 30rpx;
+ font-weight: 900;
+ color: #333333;
+ }
+ & > .ui-item .content {
+ flex: 1;
+ }
+ & > .ui-item > image {
+ width: 240rpx;
+ height: 6.4em;
+ margin-left: 20rpx;
+ border-radius: 6rpx;
+ }
+ & > .ui-item .content .desc {
+ font-size: 12px;
+ color: var(--text-c);
+ }
+ & > .ui-item .content .text-content {
+ font-size: 28rpx;
+ color: #888;
+ }
+ }
+ &.case {
+ .image {
+ position: relative;
+ image {
+ width: 100%;
+ display: block;
+ }
+ .ui-tag {
+ position: absolute;
+ right: 0;
+ top: 0;
+ }
+ .ui-bar {
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ background-color: transparent;
+ padding: 0rpx 30rpx;
+ }
+ .bg-black {
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ background-color: rgba(0, 0, 0, 0.6);
+ }
+ }
+ &.no-card .image {
+ margin: 30rpx 30rpx 0;
+ overflow: hidden;
+ border-radius: 10rpx;
+ }
+ }
+ &.dynamic {
+ display: block;
+ & > .ui-item {
+ display: block;
+ overflow: hidden;
+ & > .text-content {
+ padding: 0 30rpx 0;
+ font-size: 30rpx;
+ margin-bottom: 20rpx;
+ }
+ & .square-img {
+ width: 100%;
+ height: 200rpx;
+ border-radius: 6rpx;
+ }
+ & .only-img {
+ width: 100%;
+ height: 320rpx;
+ border-radius: 6rpx;
+ }
+ }
+ }
+ &.goods {
+ display: block;
+ & > .ui-item {
+ padding: 30rpx;
+ display: flex;
+ position: relative;
+ background-color: var(--ui-BG);
+ & + .ui-item {
+ border-top: 1rpx solid #eeeeee;
+ }
+ .content {
+ width: 410rpx;
+ padding: 0rpx;
+ }
+ .title {
+ font-size: 30rpx;
+ font-weight: 900;
+ color: #333333;
+ line-height: 1.4;
+ height: 1.4em;
+ overflow: hidden;
+ }
+ }
+ &.col-goods.col-twice {
+ display: flex;
+ flex-wrap: wrap;
+ padding-bottom: 30rpx;
+ & > .ui-item {
+ width: calc(50% - 30rpx);
+ margin: 20rpx 20rpx 0rpx 20rpx;
+ .content {
+ padding: 20rpx;
+ }
+ }
+ & > .ui-item:nth-child(2n) {
+ margin-left: 0rpx;
+ }
+ }
+ &.col-goods > .ui-item {
+ padding: 0rpx;
+ display: block;
+ border: 0px;
+ .content {
+ width: 100%;
+ padding: 30rpx;
+ }
+ }
+ &.no-card > .ui-item .content {
+ width: 470rpx;
+ padding: 0rpx;
+ }
+ &.no-card > .ui-item .title,
+ &.col-goods > .ui-item .title {
+ height: 3em;
+ overflow: hidden;
+ }
+ & > .ui-item .text-linecut-2 {
+ -webkit-line-clamp: 1;
+ }
+ &.no-card > .ui-item .text-linecut-2,
+ &.col-goods > .ui-item .text-linecut-2 {
+ -webkit-line-clamp: 2;
+ line-height: 1.6em;
+ height: 3.2em;
+ }
+ & > .ui-item > image {
+ width: 200rpx;
+ height: 200rpx;
+ margin-right: 20rpx;
+ border-radius: 6rpx;
+ }
+ &.no-card > .ui-item > image {
+ width: 220rpx;
+ height: 170rpx;
+ }
+ &.col-goods > .ui-item > image {
+ width: 100%;
+ height: 340rpx;
+ border-bottom-left-radius: 0rpx;
+ border-bottom-right-radius: 0rpx;
+ display: block;
+ }
+ &.col-goods.col-twice > .ui-item > image {
+ height: 236rpx;
+ }
+ }
+ &.loan {
+ display: block;
+ & > .ui-item {
+ padding: 30rpx 0 30rpx 30rpx;
+ display: flex;
+ position: relative;
+ background-color: var(--box-bg);
+
+ .content {
+ width: 450rpx;
+ padding: 0rpx;
+ .tag-list {
+ width: 450rpx;
+ display: flex;
+ flex-wrap: wrap;
+ font-size: 12px;
+ margin-top: 18rpx;
+ }
+ }
+ .action {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-direction: column;
+ }
+ }
+ }
+ &.houses {
+ display: block;
+ & > .ui-item {
+ padding: 20rpx;
+ display: flex;
+ position: relative;
+ background-color: var(--box-bg);
+ .image {
+ width: 230rpx;
+ height: 180rpx;
+ margin-right: 20rpx;
+ border-radius: 6rpx;
+ }
+ .content {
+ width: 400rpx;
+ padding: 0rpx;
+ .tag-list {
+ width: 400rpx;
+ display: flex;
+ flex-wrap: wrap;
+ font-size: 12px;
+ margin-top: 10rpx;
+ .ui-item {
+ height: 20px;
+ line-height: 20px;
+ }
+ }
+ }
+ .action {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-direction: column;
+ }
+ }
+ }
+
+ &.product {
+ display: flex;
+ flex-wrap: wrap;
+ padding-bottom: 30rpx;
+ & > .ui-item {
+ width: calc(100% - 15rpx);
+ margin: 20rpx 20rpx 0rpx 20rpx;
+ background-color: var(--box-bg);
+ position: relative;
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
+ // display: flex;
+ // flex-wrap: wrap;
+ .content {
+ padding: 20rpx;
+ // width: calc(100% - 345rpx);
+ .text-cut {
+ font-size: 16px;
+ }
+ }
+ .image {
+ width: 100%;
+ height: 240rpx;
+ border-radius: 6rpx 0 0 6rpx;
+ display: block;
+ }
+ .ui-progress-tag {
+ width: 4em;
+ text-align: right;
+ font-size: 12px;
+ }
+ .border-top {
+ width: 100%;
+ }
+ .ui-tag {
+ position: absolute;
+ top: 0;
+ left: 0;
+ border-radius: 6rpx 0 6rpx 0;
+ }
+ }
+ // & > .ui-item:nth-child(2n) {
+ // margin-left: 0rpx;
+ // }
+ }
+ &.shop {
+ display: flex;
+ flex-wrap: wrap;
+ padding-bottom: 30rpx;
+ & > .ui-item {
+ width: calc(50% - 30rpx);
+ margin: 20rpx 20rpx 0rpx 20rpx;
+ background-color: var(--box-bg);
+ padding: 20rpx;
+ .content {
+ margin-top: 15rpx;
+ }
+ .image {
+ width: 100%;
+ height: 285rpx;
+ border-radius: 6rpx;
+ display: block;
+ }
+ }
+ & > .ui-item:nth-child(2n) {
+ margin-left: 0rpx;
+ }
+ }
+
+ &.orders .ui-item {
+ margin-top: 30rpx;
+ .address-box {
+ padding: 15rpx;
+ margin: 0 30rpx 30rpx;
+ border: 1px solid;
+ border-color: var(--main-a);
+ border-radius: 10px;
+ position: relative;
+ .ui-form-group {
+ min-height: 10px;
+ }
+ }
+ }
+}
diff --git a/sheep/scss/style/_code.scss b/sheep/scss/style/_code.scss
new file mode 100644
index 0000000..5221c88
--- /dev/null
+++ b/sheep/scss/style/_code.scss
@@ -0,0 +1,55 @@
+.ui-code {
+ font-family: Monaco, Menlo, Consolas, 'Courier New';
+ font-size: 90%;
+ position: relative;
+ z-index: 1;
+ color: var(--ui-TC);
+ .ui-rich-text {
+ display: inline-block;
+ }
+
+ &.code {
+ display: inline-block;
+ padding: 0 10rpx;
+ margin: 0 10rpx;
+ border-radius: $radius-sm;
+ line-height: 1.6;
+ vertical-align: baseline;
+ }
+
+ &.pre {
+ display: block;
+ margin: 1em 0;
+ line-height: 1.6;
+ &.hasTitle {
+ margin: 3.2em 0 1em;
+ }
+ // border-radius: $radius-sm;
+ .ui-code-title {
+ position: absolute;
+ top: -2.2em;
+ color: var(--ui-TC-2);
+ left: 0;
+ }
+ .ui-rich-text {
+ padding: 40rpx;
+ white-space: pre-wrap;
+ word-break: break-all;
+ word-wrap: break-word;
+ }
+ .ui-scroll-view {
+ &.ui-scroll {
+ max-height: 500px;
+ white-space: pre;
+ }
+ }
+ .ui-copy-btn {
+ position: absolute;
+ z-index: 2;
+ top: 0;
+ right: 0;
+ padding: 0.8em;
+ border-radius: 0 $radius-sm 0 $radius-sm;
+ }
+ }
+}
diff --git a/sheep/scss/style/_flex.scss b/sheep/scss/style/_flex.scss
new file mode 100644
index 0000000..1daa45b
--- /dev/null
+++ b/sheep/scss/style/_flex.scss
@@ -0,0 +1,79 @@
+/* ==================
+ 弹性布局
+ ==================== */
+.flex {
+ display: flex !important;
+ &-sub {
+ flex: 1 !important;
+ }
+ &-twice {
+ flex: 2 !important;
+ }
+ &-treble {
+ flex: 3 !important;
+ }
+ &-column {
+ flex-direction: column !important;
+ }
+ &-row {
+ flex-direction: row !important;
+ }
+ &-column-reverse {
+ flex-direction: column-reverse !important;
+ }
+ &-row-reverse {
+ flex-direction: row-reverse !important;
+ }
+ &-wrap {
+ flex-wrap: wrap !important;
+ }
+ &-center {
+ @include flex-center;
+ }
+ &-bar {
+ @include flex-bar;
+ }
+}
+.basis {
+ @each $class, $value in (xs: 20%, sm: 40%, df: 50%, lg: 60%, xl: 80%) {
+ &-#{$class} {
+ flex-basis: $value !important;
+ }
+ }
+}
+.align {
+ @each $class,
+ $value
+ in (start: flex-start, end: flex-end, center: center, stretch: stretch, baseline: baseline)
+ {
+ &-#{$class} {
+ align-items: $value !important;
+ }
+ }
+}
+.self {
+ @each $class,
+ $value
+ in (start: flex-start, end: flex-end, center: center, stretch: stretch, baseline: baseline)
+ {
+ &-#{$class} {
+ align-self: $value !important;
+ }
+ }
+}
+.justify {
+ @each $class,
+ $value
+ in (
+ start: flex-start,
+ end: flex-end,
+ center: center,
+ between: space-between,
+ around: space-around
+ )
+ {
+ &-#{$class} {
+ justify-content: $value !important;
+ }
+ }
+}
diff --git a/sheep/scss/style/_form.scss b/sheep/scss/style/_form.scss
new file mode 100644
index 0000000..91d3eb3
--- /dev/null
+++ b/sheep/scss/style/_form.scss
@@ -0,0 +1,121 @@
+/* ==================
+ 表单
+ ==================== */
+.ui-form-item {
+ padding: 1rpx 24rpx;
+ display: flex;
+ align-items: center;
+ min-height: 100rpx;
+ justify-content: space-between;
+ .title {
+ text-align: justify;
+ padding-right: 30rpx;
+ font-size: 30rpx;
+ position: relative;
+ height: 60rpx;
+ line-height: 60rpx;
+ }
+ .content {
+ flex: 1;
+ }
+ input,
+ ui-input {
+ flex: 1;
+ font-size: 30rpx;
+ color: #555;
+ padding-right: 20rpx;
+ }
+ text[class*='icon-'] {
+ font-size: 36rpx;
+ padding: 0;
+ box-sizing: border-box;
+ }
+ textarea {
+ margin: 32rpx 0 30rpx;
+ height: 4.6em;
+ width: 100%;
+ line-height: 1.2em;
+ flex: 1;
+ font-size: 28rpx;
+ padding: 0;
+ }
+ picker,
+ .arrow {
+ flex: 1;
+ padding-right: 40rpx;
+ overflow: hidden;
+ position: relative;
+ }
+ picker .picker,
+ .arrow > view {
+ line-height: 100rpx;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ width: 100%;
+ }
+ picker::after,
+ .arrow::after {
+ font-family: 'ui';
+ display: block;
+ content: '\e605';
+ position: absolute;
+ font-size: 34rpx;
+ color: #8799a3;
+ line-height: 100rpx;
+ width: 60rpx;
+ text-align: center;
+ top: 0;
+ bottom: 0;
+ right: -20rpx;
+ margin: auto;
+ }
+ textarea[disabled],
+ textarea[disabled] .placeholder {
+ color: transparent;
+ }
+ &.align-start .title {
+ height: 1em;
+ margin-top: 32rpx;
+ line-height: 1em;
+ }
+ .grid-square {
+ > view {
+ background-color: #f8f8f8;
+ border-radius: 12rpx;
+ .mask {
+ background-color: rgba(0, 0, 0, 0.6);
+ position: absolute;
+ font-size: 20rpx;
+ color: #ffffff;
+ width: 100%;
+ bottom: 0;
+ text-align: center;
+ padding: 6rpx 0;
+ &.red-mask {
+ background-color: rgba(255, 80, 80, 0.6);
+ }
+ }
+ [class*='icon'] {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ transform: scale(1.5);
+ justify-content: center;
+ }
+ .text-gray {
+ position: absolute;
+ width: 100%;
+ font-size: 24rpx;
+ text-align: center;
+ bottom: 20rpx;
+ }
+ }
+ }
+}
+.disabled {
+ opacity: 0.6;
+ cursor: not-allowed !important;
+}
diff --git a/sheep/scss/style/_grid.scss b/sheep/scss/style/_grid.scss
new file mode 100644
index 0000000..b1b5230
--- /dev/null
+++ b/sheep/scss/style/_grid.scss
@@ -0,0 +1,103 @@
+/* ==================
+ 栅栏
+ ==================== */
+@use 'sass:math';
+
+@mixin make_col($screen) {
+ @for $i from 1 through 12 {
+ .ui-col-#{$screen}-#{$i} {
+ width: calc(100% / 12 * #{$i});
+ }
+ .ui-cols-#{$screen}-#{$i} .ui-item {
+ width: calc(100% / #{$i});
+ }
+ }
+}
+.ui-container {
+ box-sizing: border-box;
+ margin-left: auto;
+ margin-right: auto;
+ padding-left: 30rpx;
+ padding-right: 30rpx;
+ width: 100%;
+ max-width: 1440px;
+ &-fluid {
+ max-width: 100%;
+ padding-left: 0;
+ padding-right: 0;
+ }
+}
+.ui-grid {
+ display: flex;
+ flex-wrap: wrap;
+ &.multi-column {
+ display: block;
+ column-count: 2;
+ column-width: 0px;
+ column-gap: 0px;
+ > .ui-item {
+ break-inside: avoid;
+ padding: 0.001em;
+ }
+ }
+ &.grid-square {
+ overflow: hidden;
+ > .ui-item {
+ margin-right: 20rpx;
+ margin-bottom: 20rpx;
+ position: relative;
+ overflow: hidden;
+ }
+ @for $i from 1 through 12 {
+ &.ui-cols-#{$i} > .ui-item {
+ padding-bottom: calc((100% - #{20rpx * ($i - 1)}) / #{$i});
+ height: 0;
+ width: calc((100% - #{20rpx * ($i - 1)}) / #{$i});
+ }
+ }
+ @for $i from 1 through 12 {
+ &.ui-cols-#{$i} > .ui-item:nth-child(#{$i}n) {
+ margin-right: 0;
+ }
+ }
+ }
+}
+@for $i from 1 through 12 {
+ .ui-cols-#{$i} .ui-item {
+ width: calc(100% / #{$i});
+ }
+}
+@for $i from 1 through 12 {
+ .ui-col-#{$i} {
+ width: calc(100% / 12 * #{$i});
+ }
+}
+// 小屏
+@media screen and (min-width: 0px) {
+ @include make_col('xs');
+}
+
+// 小屏
+@media screen and (min-width: 320px) {
+ @include make_col('sm');
+}
+
+// 中屏
+@media screen and (min-width: 768px) {
+ @include make_col('md');
+}
+
+// 普通屏
+@media screen and (min-width: 1025px) {
+ @include make_col('lg');
+}
+
+// 大屏
+@media screen and (min-width: 1440px) {
+ @include make_col('xl');
+}
+
+// 超大屏
+@media screen and (min-width: 1920px) {
+ @include make_col('xxl');
+}
diff --git a/sheep/scss/style/_markdown.scss b/sheep/scss/style/_markdown.scss
new file mode 100644
index 0000000..37b023d
--- /dev/null
+++ b/sheep/scss/style/_markdown.scss
@@ -0,0 +1,62 @@
+.cu-markdown {
+ position: relative;
+ z-index: 1;
+ &.selectable {
+ cursor: auto;
+ user-select: text;
+ }
+ inline {
+ display: inline-block;
+ }
+
+ .list {
+ .list-item {
+ line-height: 1.8;
+ .list {
+ margin-left: 1.28571em;
+ .ui-title {
+ transform: scale(0.6);
+ &:before {
+ content: '\e716';
+ }
+ }
+ }
+ }
+ .list-item-p {
+ position: relative;
+ padding-left: 1.5em;
+ .list-item-t {
+ display: block;
+ width: 1.3em;
+ text-align: center;
+ position: absolute;
+ left: 0;
+ }
+ }
+ }
+ .md-table + .md-table {
+ margin-top: 30rpx;
+ }
+}
+
+.paragraph {
+ margin: 0 0 40rpx;
+ line-height: 1.8;
+}
+
+.blockquote {
+ @extend .paragraph;
+ padding: 20rpx 30rpx;
+ border-left-style: solid;
+ border-left-width: 10rpx;
+ border-color: var(--ui-Border);
+ background: none repeat scroll 0 0 rgba(102, 128, 153, 0.05);
+
+ .paragraph {
+ margin-bottom: 30rpx;
+ }
+
+ .paragraph:last-child {
+ margin-bottom: 0;
+ }
+}
diff --git a/sheep/scss/style/_menu.scss b/sheep/scss/style/_menu.scss
new file mode 100644
index 0000000..a4a8282
--- /dev/null
+++ b/sheep/scss/style/_menu.scss
@@ -0,0 +1,54 @@
+.ui-menu {
+ background-color: var(--ui-BG);
+}
+
+.ui-menu-item {
+ position: relative;
+ @include flex-bar;
+ min-height: 4em;
+ padding: 0 30rpx;
+ .ui-menu-item-icon {
+ width: 1.7em;
+ margin-right: 0.3em;
+ position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transform: scale(1.3);
+ }
+ .ui-menu-item-icon .ui-menu-item-image {
+ width: 1.2em;
+ height: 1.2em;
+ display: inline-block;
+ }
+ .ui-menu-item-content {
+ flex: 1;
+ position: relative;
+ @include flex-bar;
+ }
+ .ui-menu-item-arrow {
+ width: 1.6em;
+ text-align: center;
+ color: var(--ui-TC-3);
+ }
+ &::after {
+ content: ' ';
+ width: calc(200% - 120rpx);
+ left: 30rpx;
+ position: absolute;
+ top: 0;
+ box-sizing: border-box;
+ height: 200%;
+ border-top: 1px solid var(--ui-Border);
+ border-radius: inherit;
+ transform: scale(1);
+ transform-origin: 0 0;
+ pointer-events: none;
+ }
+ &.first-item::after {
+ display: none;
+ }
+ &:first-child::after {
+ display: none;
+ }
+}
diff --git a/sheep/scss/style/_shadow.scss b/sheep/scss/style/_shadow.scss
new file mode 100644
index 0000000..27cb3f6
--- /dev/null
+++ b/sheep/scss/style/_shadow.scss
@@ -0,0 +1,90 @@
+/* ==================
+ 阴影
+ ==================== */
+
+.shadow {
+ box-shadow: var(--ui-Shadow);
+ &-sm {
+ box-shadow: var(--ui-Shadow-sm);
+ }
+ &-lg {
+ box-shadow: var(--ui-Shadow-lg);
+ }
+ &-inset {
+ box-shadow: var(--ui-Shadow-inset);
+ }
+ @each $color, $value in $colors {
+ @at-root .shadow-#{$color} {
+ box-shadow: 0 0.5em 1em rgba($value, var(--ui-Shadow-opacity));
+ }
+ &-sm.shadow-#{$color} {
+ box-shadow: 0 0.125em 0.25em rgba($value, var(--ui-Shadow-opacity));
+ }
+ &-lg.shadow-#{$color} {
+ box-shadow: 0 1em 3em rgba($value, var(--ui-Shadow-opacity-lg));
+ }
+ }
+
+ &-warp {
+ position: relative;
+ }
+ &-warp:before,
+ &-warp:after {
+ position: absolute;
+ content: '';
+ bottom: -10rpx;
+ left: 20rpx;
+ width: calc(50% - #{40rpx});
+ height: 30rpx;
+ transform: skew(0deg, -6deg);
+ transform-origin: 50% 50%;
+ background-color: rgba(0, 0, 0, var(--ui-Shadow-opacity));
+ filter: blur(20rpx);
+ z-index: -1;
+ opacity: 0.5;
+ }
+ &-warp:after {
+ right: 20rpx;
+ left: auto;
+ transform: skew(0deg, 6deg);
+ }
+ &-blur {
+ position: relative;
+ }
+ &-blur::before {
+ content: '';
+ display: block;
+ background: inherit;
+ filter: blur(20rpx);
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ top: 0.5em;
+ left: 0.5em;
+ z-index: -1;
+ opacity: var(--ui-Shadow-opacity-lg);
+ transform-origin: 0 0;
+ border-radius: inherit;
+ transform: scale(1, 1);
+ }
+}
+.drop-shadow {
+ filter: drop-shadow(0 0 30rpx rgba(0, 0, 0, 0.1));
+ &-sm {
+ filter: drop-shadow(0 4rpx 4rpx rgba(0, 0, 0, 0.06));
+ }
+ &-lg {
+ filter: drop-shadow(0 30rpx 60rpx rgba(0, 0, 0, 0.2));
+ }
+ @each $color, $value in $colors {
+ @at-root .drop-shadow-#{$color} {
+ filter: drop-shadow(0 15rpx 15rpx rgba(darken($value, 10%), 0.3));
+ }
+ &-sm.drop-shadow-#{$color} {
+ filter: drop-shadow(0 4rpx 4rpx rgba(darken($value, 10%), 0.3));
+ }
+ &-lg.drop-shadow-#{$color} {
+ filter: drop-shadow(0 50rpx 100rpx rgba(darken($value, 10%), 0.2));
+ }
+ }
+}
diff --git a/sheep/scss/style/_table.scss b/sheep/scss/style/_table.scss
new file mode 100644
index 0000000..ad5effa
--- /dev/null
+++ b/sheep/scss/style/_table.scss
@@ -0,0 +1,133 @@
+.ui-table {
+ background-color: var(--ui-BG);
+ max-width: 100%;
+ display: table;
+ &.table-full {
+ width: 100%;
+ }
+ &.table-radius {
+ border-radius: $radius;
+ .ui-table-header {
+ .ui-table-tr {
+ border-top-left-radius: $radius;
+ border-top-right-radius: $radius;
+ }
+ .ui-table-th {
+ &:first-child {
+ border-top-left-radius: $radius;
+ }
+ &:last-child {
+ border-top-right-radius: $radius;
+ }
+ }
+ }
+ }
+ .ui-table-header {
+ display: table-header-group;
+ .ui-table-th {
+ font-weight: bold;
+ border-bottom: 1px solid var(--ui-Border);
+ white-space: nowrap;
+
+ padding: 1em 0.8em;
+ }
+ }
+
+ .ui-table-tr {
+ display: table-row;
+ z-index: 1;
+ }
+
+ .ui-table-body {
+ display: table-row-group;
+ position: relative;
+ .ui-table-tr:hover {
+ background-color: var(--ui-BG-1) !important;
+ }
+ .ui-table-loading {
+ min-height: 300px;
+ position: absolute !important;
+ width: 100%;
+ height: 100%;
+ z-index: 2;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border: 1px solid var(--ui-Border);
+ }
+ }
+
+ .ui-table-td,
+ .ui-table-th {
+ display: table-cell;
+ text-align: unset;
+ padding: 0.5em 0.8em;
+ // font-size: 90%;
+ vertical-align: middle;
+ }
+}
+
+.ui-table.table-border {
+ &,
+ & .ui-table-td,
+ & .ui-table-th {
+ position: relative;
+ &::after {
+ content: ' ';
+ width: 200%;
+ height: 200%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ border-radius: inherit;
+ transform: scale(0.5);
+ transform-origin: 0 0;
+ pointer-events: none;
+ box-sizing: border-box;
+ border: 1px solid var(--ui-Border);
+ z-index: 1;
+ }
+ }
+ .ui-table-td,
+ .ui-table-th {
+ &::after {
+ border-width: 1px 1px 0 0;
+ }
+ &:last-child::after {
+ border-right: none;
+ }
+ }
+}
+.ui-table.table-radius {
+ &::after {
+ border-radius: calc(#{$radius} * 2);
+ }
+ & .ui-table-tr .ui-table-th:first-child {
+ border-top-left-radius: calc(#{$radius} * 2);
+ }
+ & .ui-table-tr .ui-table-th:last-child {
+ border-top-right-radius: calc(#{$radius} * 2);
+ }
+ & .ui-table-tr:last-child .ui-table-td:first-child {
+ border-bottom-left-radius: #{$radius};
+ }
+ & .ui-table-tr:last-child .ui-table-td:last-child {
+ border-bottom-right-radius: #{$radius};
+ }
+}
+.ui-table.table-striped > .ui-table-body > .ui-table-tr:nth-child(2n + 1),
+.ui-table.table-striped > .ui-table-body > .ui-table-tr:nth-child(2n + 1) {
+ background-color: var(--ui-BG-1);
+}
+
+.table-responsive {
+ width: inherit;
+ height: 100%;
+ max-width: 100%;
+ overflow: hidden;
+ box-sizing: border-box;
+ .table-responsive-box {
+ position: relative;
+ overflow: hidden;
+ }
+}
diff --git a/sheep/scss/style/_tag.scss b/sheep/scss/style/_tag.scss
new file mode 100644
index 0000000..e69de29
diff --git a/sheep/scss/style/_text.scss b/sheep/scss/style/_text.scss
new file mode 100644
index 0000000..8249022
--- /dev/null
+++ b/sheep/scss/style/_text.scss
@@ -0,0 +1,104 @@
+/* ==================
+ 文本
+ ==================== */
+@use 'sass:math';
+.font-0 {
+ font-size: 24rpx;
+ --textSize: -4rpx;
+}
+.font-1 {
+ font-size: 28rpx;
+ --textSize: 0rpx;
+}
+.font-2 {
+ font-size: 32rpx;
+ --textSize: 4rpx;
+}
+.font-3 {
+ font-size: 36rpx;
+ --textSize: 8rpx;
+}
+.font-4 {
+ font-size: 40rpx;
+ --textSize: 12rpx;
+}
+.text {
+ @each $class, $value in $fontsize {
+ &-#{$class},
+ &-#{math.div($value ,2)} {
+ font-size: calc(#{$value}rpx + var(--textSize)) !important;
+ }
+ }
+ &-cut {
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ }
+ @at-root [class*='text-linecut'] {
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 2;
+ overflow: hidden;
+ word-break: break-all;
+ }
+ @for $i from 2 through 10 {
+ &-linecut-#{$i} {
+ -webkit-line-clamp: #{$i};
+ }
+ }
+ &-justify {
+ text-align: justify;
+ }
+ &-justify-line {
+ text-align: justify;
+ line-height: 0.5em;
+ margin-top: 0.5em;
+ &::after {
+ content: '.';
+ display: inline-block;
+ width: 100%;
+ }
+ }
+
+ &-Abc {
+ text-transform: Capitalize !important;
+ }
+ &-ABC {
+ text-transform: Uppercase !important;
+ }
+ &-abc {
+ text-transform: Lowercase !important;
+ }
+ &-del,
+ &-line {
+ text-decoration: line-through !important;
+ }
+ &-bottomline {
+ text-decoration: underline !important;
+ }
+ &-italic {
+ font-style: italic !important;
+ }
+ &-style-none {
+ text-decoration: none !important;
+ }
+ &-break {
+ word-break: break-word !important;
+ overflow-wrap: break-word !important;
+ }
+ &-reset {
+ color: inherit !important;
+ }
+ &-price::before {
+ content: '¥';
+ font-size: 80%;
+ margin-right: 4rpx;
+ }
+ &-hide {
+ font: 0/0 a;
+ color: transparent;
+ text-shadow: none;
+ background-color: transparent;
+ border: 0;
+ }
+}
diff --git a/sheep/scss/theme/_dark.scss b/sheep/scss/theme/_dark.scss
new file mode 100644
index 0000000..8caad17
--- /dev/null
+++ b/sheep/scss/theme/_dark.scss
@@ -0,0 +1,39 @@
+// 核心主题样式文件
+@mixin theme-dark {
+ // 背景色
+ --ui-BG: #393939;
+ --ui-BG-1: #333333;
+ --ui-BG-2: #2c2c2c;
+ --ui-BG-3: #292929;
+ --ui-BG-4: #222222;
+
+ // 文本色
+ --ui-TC: #ffffff;
+ --ui-TC-1: #d4d4d4;
+ --ui-TC-2: #919191;
+ --ui-TC-3: #6a6a6a;
+ --ui-TC-4: #474747;
+
+ // 模糊
+ --ui-Blur: rgba(38, 38, 38, 0.98);
+ --ui-Blur-1: rgba(38, 38, 38, 0.75);
+ --ui-Blur-2: rgba(38, 38, 38, 0.25);
+ --ui-Blur-3: rgba(38, 38, 38, 0.05);
+
+ // 边框
+ --ui-Border: rgba(119, 119, 119, 0.25);
+ --ui-Outline: rgba(255, 255, 255, 0.1);
+ --ui-Line: rgba(119, 119, 119, 0.25);
+
+ // 透明与阴影
+ --ui-Shadow: 0 0.5em 1em rgba(0, 0, 0, 0.45);
+ --ui-Shadow-sm: 0 0.125em 0.25em rgba(0, 0, 0, 0.475);
+ --ui-Shadow-lg: 0 1em 3em rgba(0, 0, 0, 0.475);
+ --ui-Shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.475);
+
+ --ui-Shadow-opacity: 0.55;
+ --ui-Shadow-opacity-sm: 0.175;
+ --ui-Shadow-opacity-lg: 0.75;
+
+ --ui-BG-opacity: 0.1;
+}
diff --git a/sheep/scss/theme/_light.scss b/sheep/scss/theme/_light.scss
new file mode 100644
index 0000000..af5f245
--- /dev/null
+++ b/sheep/scss/theme/_light.scss
@@ -0,0 +1,39 @@
+// 核心主题样式文件
+@mixin theme-light {
+ // 背景色
+ --ui-BG: #ffffff;
+ --ui-BG-1: #f6f6f6;
+ --ui-BG-2: #f1f1f1;
+ --ui-BG-3: #e8e8e8;
+ --ui-BG-4: #e0e0e0;
+
+ // 文本色
+ --ui-TC: #303030;
+ --ui-TC-1: #525252;
+ --ui-TC-2: #777777;
+ --ui-TC-3: #9e9e9e;
+ --ui-TC-4: #c6c6c6;
+
+ // 模糊
+ --ui-Blur: rgba(255, 255, 255, 0.98);
+ --ui-Blur-1: rgba(255, 255, 255, 0.75);
+ --ui-Blur-2: rgba(255, 255, 255, 0.25);
+ --ui-Blur-3: rgba(255, 255, 255, 0.05);
+
+ // 边框
+ --ui-Border: rgba(119, 119, 119, 0.25);
+ --ui-Outline: rgba(0, 0, 0, 0.1);
+ --ui-Line: rgba(119, 119, 119, 0.25);
+
+ // 透明与阴影
+ --ui-Shadow: 0 0.5em 1em rgba(0, 0, 0, 0.15);
+ --ui-Shadow-sm: 0 0.125em 0.25em rgba(0, 0, 0, 0.075);
+ --ui-Shadow-lg: 0 1em 3em rgba(0, 0, 0, 0.175);
+ --ui-Shadow-inset: inset 0 0.1em 0.2em rgba(0, 0, 0, 0.075);
+
+ --ui-Shadow-opacity: 0.45;
+ --ui-Shadow-opacity-sm: 0.075;
+ --ui-Shadow-opacity-lg: 0.65;
+
+ --ui-BG-opacity: 0.1;
+}
diff --git a/sheep/scss/theme/_style.scss b/sheep/scss/theme/_style.scss
new file mode 100644
index 0000000..1eef587
--- /dev/null
+++ b/sheep/scss/theme/_style.scss
@@ -0,0 +1,68 @@
+@import './light'; //浅蓝主题
+@import './dark'; //深蓝主题
+// 多主题
+.theme-light {
+ @include theme-light;
+}
+.theme-dark {
+ @include theme-dark;
+}
+.theme-auto {
+ @include theme-light;
+}
+@media (prefers-color-scheme: dark) {
+ .theme-auto {
+ @include theme-dark;
+ }
+}
+
+@each $value in ('', '-1', '-2', '-3', '-4') {
+ // 背景色 + 文字色 : 白色 + 默认色;
+ .ui-BG#{$value} {
+ background-color: var(--ui-BG#{$value}) !important;
+ color: var(--ui-TC);
+ }
+ // 文字颜色
+ .ui-TC#{$value} {
+ color: var(--ui-TC#{$value}) !important;
+ }
+ // 主题色背景
+ .ui-BG-Main#{$value} {
+ background-color: var(--ui-BG-Main#{$value}) !important;
+ color: var(--ui-BG-Main-TC) !important;
+ }
+ // 主题色渐变,横向
+ .ui-BG-Main-Gradient {
+ background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient)) !important;
+ color: var(--ui-BG-Main-TC) !important;
+ }
+ // 主题色文字
+ .ui-TC-Main#{$value} {
+ color: var(--ui-BG-Main#{$value}) !important;
+ }
+ // 主题色阴影
+ .ui-Shadow-Main {
+ box-shadow: var(--ui-Main-box-shadow) !important;
+ }
+ .ui-BG-Main-light {
+ background: var(----ui-BG-Main-light) !important;
+ color: var(--ui-BG-Main#{$value}) !important;
+ }
+}
+
+@each $color, $value in $colors {
+ .main-#{$color} {
+ --ui-BG-Main: #{$value};
+ --ui-BG-Main-tag: #{rgba($value, 0.05)};
+ --ui-BG-Main-gradient: #{rgba($value, 0.6)};
+ --ui-BG-Main-light: #{rgba($value, 0.2)};
+ --ui-BG-Main-opacity-1: #{rgba($value, 0.1)};
+ --ui-BG-Main-opacity-4: #{rgba($value, 0.4)};
+ --ui-Main-box-shadow: 0 0.2em 0.5em #{rgba($value, var(--ui-Shadow-opacity))};
+ --ui-BG-Main-1: #{mix(rgba(255, 255, 255, 0.7), desaturate($value, 20%), 10%)};
+ --ui-BG-Main-2: #{mix(rgba(255, 255, 255, 0.6), desaturate($value, 40%), 20%)};
+ --ui-BG-Main-3: #{mix(rgba(119, 119, 119, 0.2), desaturate($value, 40%), 40%)};
+ --ui-BG-Main-4: #{mix(rgba(119, 119, 119, 0.1), desaturate($value, 40%), 60%)};
+ --ui-BG-Main-TC: #ffffff !important;
+ }
+}
diff --git a/sheep/scss/ui.scss b/sheep/scss/ui.scss
new file mode 100644
index 0000000..b9b7381
--- /dev/null
+++ b/sheep/scss/ui.scss
@@ -0,0 +1,19 @@
+@import './theme/style'; //系统主题
+@import './main'; //主样式*
+
+@import './style/background'; //背景
+@import './style/grid'; //列
+@import './style/flex'; //布局
+@import './style/border'; //边框
+@import './style/text'; //文本
+@import './style/shadow'; //阴影
+@import './icon/style'; //图标
+@import './style/tag'; //标签
+@import './style/button'; //按钮
+@import './style/avatar'; //头像
+@import './style/table'; //表格
+@import './style/code'; //代码片段
+@import './style/form'; //表单
+@import './style/menu'; //表单
+@import './style/markdown'; //表单
+@import './style/card'; //表单
diff --git a/sheep/store/app.js b/sheep/store/app.js
new file mode 100644
index 0000000..2f95dbe
--- /dev/null
+++ b/sheep/store/app.js
@@ -0,0 +1,134 @@
+import DiyApi from '@/sheep/api/promotion/diy';
+import { defineStore } from 'pinia';
+import $platform from '@/sheep/platform';
+import $router from '@/sheep/router';
+import user from './user';
+import sys from './sys';
+
+const app = defineStore({
+ id: 'app',
+ state: () => ({
+ info: {
+ // 应用信息
+ name: '', // 商城名称
+ logo: '', // logo
+ version: '', // 版本号
+ copyright: '', // 版权信息 I
+ copytime: '', // 版权信息 II
+
+ cdnurl: '', // 云存储域名
+ filesystem: '', // 云存储平台
+ },
+ platform: {
+ share: {
+ methods: [], // 支持的分享方式
+ forwardInfo: {}, // 默认转发信息
+ posterInfo: {}, // 海报信息
+ linkAddress: '', // 复制链接地址
+ },
+ bind_mobile: 0, // 登陆后绑定手机号提醒 (弱提醒,可手动关闭)
+ },
+ template: {
+ // 店铺装修模板
+ basic: {}, // 基本信息
+ home: {
+ // 首页模板
+ style: {},
+ data: [],
+ },
+ user: {
+ // 个人中心模板
+ style: {},
+ data: [],
+ },
+ },
+ shareInfo: {}, // 全局分享信息
+ has_wechat_trade_managed: 0 // 小程序发货信息管理 0 没有 || 1 有
+ }),
+ actions: {
+ // 获取Shopro应用配置和模板
+ async init(templateId = null) {
+ // 检查网络
+ const networkStatus = await $platform.checkNetwork();
+ if (!networkStatus) {
+ $router.error('NetworkError');
+ }
+
+ // 加载装修配置
+ await adaptTemplate(this.template, templateId)
+
+ // TODO 芋艿:未来支持管理后台可配;对应 https://api.shopro.sheepjs.com/shop/api/init
+ if (true) {
+ this.info = {
+ name: '晚趣语音',
+ logo: 'https://rbtnet.oss-cn-hangzhou.aliyuncs.com/aa361225849eeb86428e1a3d647d6f7b94354e74de212403bb968e6ad85e79b3.jpeg',
+ version: '2.2.0',
+ copyright: '上海尔加网络科技提供技术支持',
+ copytime: 'Copyright© 2018-2024',
+
+ cdnurl: 'https://file.sheepjs.com', // 云存储域名
+ filesystem: 'qcloud', // 云存储平台
+ };
+ this.platform = {
+ share: {
+ methods: ["poster", "link"],
+ linkAddress: 'https://peiwan.mfzt.site/h5', // TODO 芋艿:可以考虑改到 .env 那
+ posterInfo: {
+ "user_bg": "/static/img/shop/config/user-poster-bg.png",
+ "goods_bg": "/static/img/shop/config/goods-poster-bg.png",
+ "groupon_bg": "/static/img/shop/config/groupon-poster-bg.png"
+ }
+ },
+ bind_mobile: 0
+ };
+ this.has_wechat_trade_managed = 0;
+
+ // 加载主题
+ const sysStore = sys();
+ sysStore.setTheme();
+
+ // 模拟用户登录
+ const userStore = user();
+ if (userStore.isLogin) {
+ userStore.loginAfter();
+ }
+ return Promise.resolve(true);
+ } else {
+ $router.error('InitError', res.msg || '加载失败');
+ }
+ },
+ },
+ persist: {
+ enabled: true,
+ strategies: [
+ {
+ key: 'app-store',
+ },
+ ],
+ },
+});
+
+// todo: @owen 先做数据适配,后期重构
+const adaptTemplate = async (appTemplate, templateId) => {
+ const { data: diyTemplate } = templateId
+ // 查询指定模板,一般是预览时使用
+ ? await DiyApi.getDiyTemplate(templateId)
+ : await DiyApi.getUsedDiyTemplate();
+ // 模板不存在
+ if (!diyTemplate) {
+ $router.error('TemplateError');
+ return
+ }
+
+ const tabBar = diyTemplate?.property?.tabBar;
+ if (tabBar) {
+ appTemplate.basic.tabbar = tabBar
+ if (tabBar?.theme) {
+ appTemplate.basic.theme = tabBar?.theme;
+ }
+ }
+ appTemplate.home = diyTemplate?.home;
+ appTemplate.user = diyTemplate?.user;
+}
+
+export default app;
diff --git a/sheep/store/cart.js b/sheep/store/cart.js
new file mode 100644
index 0000000..edde779
--- /dev/null
+++ b/sheep/store/cart.js
@@ -0,0 +1,112 @@
+import { defineStore } from 'pinia';
+import CartApi from '@/sheep/api/trade/cart';
+
+const cart = defineStore({
+ id: 'cart',
+ state: () => ({
+ list: [], // 购物车列表
+ selectedIds: [], // 已选列表
+ isAllSelected: false, // 是否全选
+ totalPriceSelected: 0, // 选中项总金额
+ }),
+ actions: {
+ // 获取购物车列表
+ async getList() {
+ const { data, code } = await CartApi.getCartList();
+ if (code === 0) {
+ this.list = data.validList;
+
+ // 计算各种关联属性
+ this.selectedIds = [];
+ this.isAllSelected = true;
+ this.totalPriceSelected = 0;
+ this.list.forEach((item) => {
+ if (item.selected) {
+ this.selectedIds.push(item.id);
+ this.totalPriceSelected += item.count * item.sku.price;
+ } else {
+ this.isAllSelected = false;
+ }
+ });
+ }
+ },
+
+ // 添加购物车
+ async add(goodsInfo) {
+ // 添加购物项
+ const { code } = await CartApi.addCart({
+ skuId: goodsInfo.id,
+ count: goodsInfo.goods_num,
+ });
+ // 刷新购物车列表
+ if (code === 0) {
+ await this.getList();
+ }
+ },
+
+ // 更新购物车
+ async update(goodsInfo) {
+ const { code } = await CartApi.updateCartCount({
+ id: goodsInfo.goods_id,
+ count: goodsInfo.goods_num,
+ });
+ if (code === 0) {
+ await this.getList();
+ }
+ },
+
+ // 移除购物车
+ async delete(ids) {
+ let idsTemp = '';
+ if (Array.isArray(ids)) {
+ idsTemp = ids.join(',');
+ } else {
+ idsTemp = ids;
+ }
+ const { code } = await CartApi.deleteCart(idsTemp);
+ if (code === 0) {
+ await this.getList();
+ }
+ },
+
+ // 单选购物车商品
+ async selectSingle(goodsId) {
+ const { code } = await CartApi.updateCartSelected({
+ ids: [goodsId],
+ selected: !this.selectedIds.includes(goodsId), // 取反
+ });
+ if (code === 0) {
+ await this.getList();
+ }
+ },
+
+ // 全选购物车商品
+ async selectAll(flag) {
+ const { code } = await CartApi.updateCartSelected({
+ ids: this.list.map((item) => item.id),
+ selected: flag
+ });
+ if (code === 0) {
+ await this.getList();
+ }
+ },
+
+ // 清空购物车。注意,仅用于用户退出时,重置数据
+ emptyList() {
+ this.list = [];
+ this.selectedIds = [];
+ this.isAllSelected = true;
+ this.totalPriceSelected = 0;
+ },
+ },
+ persist: {
+ enabled: true,
+ strategies: [
+ {
+ key: 'cart-store',
+ },
+ ],
+ },
+});
+
+export default cart;
diff --git a/sheep/store/index.js b/sheep/store/index.js
new file mode 100644
index 0000000..3d06698
--- /dev/null
+++ b/sheep/store/index.js
@@ -0,0 +1,20 @@
+import { createPinia } from 'pinia';
+import piniaPersist from 'pinia-plugin-persist-uni';
+
+// 自动注入所有pinia模块
+const files = import.meta.glob('./*.js', { eager: true });
+const modules = {};
+Object.keys(files).forEach((key) => {
+ modules[key.replace(/(.*\/)*([^.]+).*/gi, '$2')] = files[key].default;
+});
+
+export const setupPinia = (app) => {
+ const pinia = createPinia();
+ pinia.use(piniaPersist);
+
+ app.use(pinia);
+};
+
+export default (name) => {
+ return modules[name]();
+};
diff --git a/sheep/store/modal.js b/sheep/store/modal.js
new file mode 100644
index 0000000..0cb8383
--- /dev/null
+++ b/sheep/store/modal.js
@@ -0,0 +1,31 @@
+import { defineStore } from 'pinia';
+
+const modal = defineStore({
+ id: 'modal',
+ state: () => ({
+ auth: '', // 授权弹框 accountLogin|smsLogin|resetPassword|changeMobile|changePassword|changeUsername
+ share: false, // 分享弹框
+ menu: false, // 快捷菜单弹框
+ qrcode: false, // 关注公众号
+ search: false, // 搜索弹窗
+ advHistory: [], // 广告弹框记录
+ lastTimer: {
+ // 短信验证码计时器,为了防止刷新请求做了持久化
+ smsLogin: 0,
+ changeMobile: 0,
+ resetPassword: 0,
+ changePassword: 0,
+ }
+ }),
+ persist: {
+ enabled: true,
+ strategies: [
+ {
+ key: 'modal-store',
+ paths: ['lastTimer', 'advHistory'],
+ },
+ ],
+ },
+});
+
+export default modal;
diff --git a/sheep/store/sys.js b/sheep/store/sys.js
new file mode 100644
index 0000000..0ed2240
--- /dev/null
+++ b/sheep/store/sys.js
@@ -0,0 +1,113 @@
+import { defineStore } from 'pinia';
+import app from './app';
+
+const sys = defineStore({
+ id: 'sys',
+ state: () => ({
+ theme: '', // 主题,
+ mode: 'light', // 明亮模式、暗黑模式(暂未支持)
+ modeAuto: false, // 跟随系统
+ fontSize: 1, // 设置默认字号等级(0-4)
+ searchTabs: {
+ sexLabel: '性别',
+ sex2Label: '性别',
+ cityLabel: '城市',
+ categoryLabel: '分类',
+ },
+ categoryList: [],
+ clerk: {},
+ clerkTabIndex: 1,
+ user: {},
+ userTabIndex: 0,
+ homeTabIndex: 0,
+ messageTabIndex: 0,
+
+ currentClerk: {
+ id: -1,
+ avatar: 'https://rbtnet.oss-cn-hangzhou.aliyuncs.com/aa361225849eeb86428e1a3d647d6f7b94354e74de212403bb968e6ad85e79b3.jpeg',
+ },
+ clerkList: [],
+ gift: {
+ id: -1,
+ },
+ giftList: [],
+ scene: "0", // 小程序场景值
+ tradeConfig: {
+ brokerageEnabled: false,
+ weixinEnabled: false,
+ giftEnabled: false,
+ qrcode: '',
+ },
+ }),
+ getters: {},
+ actions: {
+ setTheme(theme = '') {
+ if (theme === '') {
+ this.theme = app().template?.basic.theme || 'orange';
+ } else {
+ this.theme = theme;
+ }
+ },
+ setSexLabel(label) {
+ this.searchTabs.sexLabel = label;
+ },
+ setSex2Label(label) {
+ this.searchTabs.sex2Label = label;
+ },
+ setCityLabel(label) {
+ this.searchTabs.cityLabel = label;
+ },
+ setClerkTabIndex(e) {
+ this.clerkTabIndex = e;
+ },
+ setUserTabIndex(e) {
+ this.userTabIndex = e;
+ },
+ setHomeTabIndex(e) {
+ this.homeTabIndex = e;
+ },
+ setMessageTabIndex(e) {
+ this.messageTabIndex = e;
+ },
+ setCategoryLabel(label) {
+ this.searchTabs.categoryLabel = label;
+ },
+ setCategoryList(list) {
+ this.categoryList = list;
+ },
+ setClerk(o) {
+ this.clerk = o;
+ },
+ setUser(o) {
+ this.user = o;
+ },
+ setCurrentClerk(o) {
+ this.currentClerk = o;
+ },
+ setClerkList(list) {
+ this.clerkList = list;
+ },
+ setGift(e) {
+ this.gift = e;
+ },
+ setGiftList(list) {
+ this.giftList = list;
+ },
+ setScene(scene) {
+ this.scene = scene;
+ },
+ setTradeConfig(config) {
+ this.tradeConfig = config;
+ },
+ },
+ persist: {
+ enabled: true,
+ strategies: [
+ {
+ key: 'sys-store',
+ },
+ ],
+ },
+});
+
+export default sys;
diff --git a/sheep/store/user.js b/sheep/store/user.js
new file mode 100644
index 0000000..25c71d2
--- /dev/null
+++ b/sheep/store/user.js
@@ -0,0 +1,196 @@
+import { defineStore } from 'pinia';
+import $share from '@/sheep/platform/share';
+import { clone, cloneDeep } from 'lodash-es';
+import cart from './cart';
+import app from './app';
+import { showAuthModal } from '@/sheep/hooks/useModal';
+import UserApi from '@/sheep/api/member/user';
+import PayWalletApi from '@/sheep/api/pay/wallet';
+import TradeConfigApi from '@/sheep/api/trade/config';
+import OrderApi from '@/sheep/api/trade/order';
+import CouponApi from '@/sheep/api/promotion/coupon';
+
+// 默认用户信息
+const defaultUserInfo = {
+ id: null,
+ avatar: '', // 头像
+ nickname: '', // 昵称
+ age: 0,
+ sex: 1,
+ visible: false,
+ qrcodeShow: 0,
+ photo: '',
+ gender: 0, // 性别
+ mobile: '', // 手机号
+ point: 0, // 积分
+ isVip: false,
+};
+
+const defaultTradeConfig = {
+ brokerageEnabled: false,
+ weixinEnabled: false,
+ giftEnabled: false,
+ friendEnabled: false,
+ peiwanEnabled: false,
+ adUnitId: '',
+ qrcode: '',
+};
+
+// 默认钱包信息
+const defaultUserWallet = {
+ balance: 0, // 余额
+};
+
+// 默认订单、优惠券等其他资产信息
+const defaultNumData = {
+ unusedCouponCount: 0,
+ orderCount: {
+ allCount: 0,
+ unpaidCount: 0,
+ undeliveredCount: 0,
+ deliveredCount: 0,
+ uncommentedCount: 0,
+ afterSaleCount: 0,
+ },
+};
+
+const user = defineStore({
+ id: 'user',
+ state: () => ({
+ userInfo: clone(defaultUserInfo), // 用户信息
+ tradeConfig: clone(defaultTradeConfig), // 系统配置
+ userWallet: clone(defaultUserWallet), // 用户钱包信息
+ isLogin: !!uni.getStorageSync('token'), // 登录状态
+ numData: cloneDeep(defaultNumData), // 用户其他数据
+ lastUpdateTime: 0, // 上次更新时间
+ }),
+
+ actions: {
+ setTradeConfig(config) {
+ this.tradeConfig = config;
+ },
+ // 获取用户信息
+ async getInfo() {
+ const { code, data } = await UserApi.getUserInfo();
+ if (code !== 0) {
+ return;
+ }
+ this.userInfo = data;
+ return Promise.resolve(data);
+ },
+
+ async getTradeConfig() {
+ const { code, data } = await TradeConfigApi.getTradeConfig(this.userInfo.id);
+ if (code !== 0) {
+ return;
+ }
+ this.tradeConfig = data;
+ },
+
+ // 获得用户钱包
+ async getWallet() {
+ const { code, data } = await PayWalletApi.getPayWallet();
+ if (code !== 0) {
+ return;
+ }
+ this.userWallet = data;
+ },
+
+ // 获取订单、优惠券等其他资产信息
+ getNumData() {
+ OrderApi.getOrderCount().then((res) => {
+ if (res.code === 0) {
+ this.numData.orderCount = res.data;
+ }
+ });
+ CouponApi.getUnusedCouponCount().then((res) => {
+ if (res.code === 0) {
+ this.numData.unusedCouponCount = res.data;
+ }
+ });
+ },
+
+ // 设置 token
+ setToken(token = '', refreshToken = '') {
+ if (token === '') {
+ this.isLogin = false;
+ uni.removeStorageSync('token');
+ uni.removeStorageSync('refresh-token');
+ } else {
+ this.isLogin = true;
+ uni.setStorageSync('token', token);
+ uni.setStorageSync('refresh-token', refreshToken);
+ this.loginAfter();
+ }
+ return this.isLogin;
+ },
+
+ // 更新用户相关信息 (手动限流,5 秒之内不刷新)
+ async updateUserData() {
+ if (!this.isLogin) {
+ this.resetUserData();
+ return;
+ }
+ // 防抖,5 秒之内不刷新
+ const nowTime = new Date().getTime();
+ if (this.lastUpdateTime + 5000 > nowTime) {
+ return;
+ }
+ this.lastUpdateTime = nowTime;
+
+ // 获取最新信息
+ await this.getInfo();
+ this.getTradeConfig();
+ this.getWallet();
+ this.getNumData();
+ return this.userInfo;
+ },
+
+ // 重置用户默认数据
+ resetUserData() {
+ // 清空 token
+ this.setToken();
+ // 清空用户相关的缓存
+ this.userInfo = clone(defaultUserInfo);
+ this.userWallet = clone(defaultUserWallet);
+ this.numData = cloneDeep(defaultNumData);
+ // 清空购物车的缓存
+ cart().emptyList();
+ },
+
+ // 登录后,加载各种信息
+ // TODO 芋艿:整理下;
+ async loginAfter() {
+ await this.updateUserData();
+
+ // 加载购物车
+ cart().getList();
+ // 登录后设置全局分享参数
+ $share.getShareInfo();
+
+ // 提醒绑定手机号
+ if (app().platform.bind_mobile && !this.userInfo.mobile) {
+ showAuthModal('changeMobile');
+ }
+
+ // 绑定推广员
+ $share.bindBrokerageUser();
+ },
+
+ // 登出系统
+ async logout() {
+ this.resetUserData();
+ return !this.isLogin;
+ },
+ },
+ persist: {
+ enabled: true,
+ strategies: [
+ {
+ key: 'user-store',
+ },
+ ],
+ },
+});
+
+export default user;
diff --git a/sheep/ui/su-coupon/su-coupon.vue b/sheep/ui/su-coupon/su-coupon.vue
new file mode 100644
index 0000000..472d17f
--- /dev/null
+++ b/sheep/ui/su-coupon/su-coupon.vue
@@ -0,0 +1,319 @@
+
+
+
+
+
+
+ {{ type === 'reduce' ? value : Number(value) }}
+ {{ type === 'reduce' ? '元' : '折' }}
+
+ {{ props.title }}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ type === 'reduce' ? value : Number(value) }}
+ {{ type === 'reduce' ? '元' : '折' }}
+
+
+ {{ props.title }}
+ 仅剩:{{ props.surplus }}张
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ type === 'reduce' ? value : Number(value) }}
+ {{ type === 'reduce' ? '元' : '折' }}
+
+
+ {{ props.title }}
+ 有效期:{{ props.sellBy }}
+
+
+
+
+
+
+ 仅剩:{{ props.surplus }}张
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-data-checkbox/su-data-checkbox.vue b/sheep/ui/su-data-checkbox/su-data-checkbox.vue
new file mode 100644
index 0000000..537ead5
--- /dev/null
+++ b/sheep/ui/su-data-checkbox/su-data-checkbox.vue
@@ -0,0 +1,894 @@
+
+
+
+
+
+ {{ mixinDatacomErrorMessage }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-dialog/su-dialog.vue b/sheep/ui/su-dialog/su-dialog.vue
new file mode 100644
index 0000000..b53e9ce
--- /dev/null
+++ b/sheep/ui/su-dialog/su-dialog.vue
@@ -0,0 +1,269 @@
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-fixed/su-fixed.vue b/sheep/ui/su-fixed/su-fixed.vue
new file mode 100644
index 0000000..e2a9808
--- /dev/null
+++ b/sheep/ui/su-fixed/su-fixed.vue
@@ -0,0 +1,217 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-image/su-image.vue b/sheep/ui/su-image/su-image.vue
new file mode 100644
index 0000000..35f8410
--- /dev/null
+++ b/sheep/ui/su-image/su-image.vue
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-inner-navbar/su-inner-navbar.vue b/sheep/ui/su-inner-navbar/su-inner-navbar.vue
new file mode 100644
index 0000000..8072032
--- /dev/null
+++ b/sheep/ui/su-inner-navbar/su-inner-navbar.vue
@@ -0,0 +1,365 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-navbar/su-navbar.vue b/sheep/ui/su-navbar/su-navbar.vue
new file mode 100644
index 0000000..e02249a
--- /dev/null
+++ b/sheep/ui/su-navbar/su-navbar.vue
@@ -0,0 +1,483 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-notice-bar/su-notice-bar.vue b/sheep/ui/su-notice-bar/su-notice-bar.vue
new file mode 100644
index 0000000..fc5075a
--- /dev/null
+++ b/sheep/ui/su-notice-bar/su-notice-bar.vue
@@ -0,0 +1,473 @@
+
+
+
+
+
+
+
+
+
+ {{ text }}
+
+
+
+
+
+ {{ moreText }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-number-box/su-number-box.vue b/sheep/ui/su-number-box/su-number-box.vue
new file mode 100644
index 0000000..6b662cd
--- /dev/null
+++ b/sheep/ui/su-number-box/su-number-box.vue
@@ -0,0 +1,225 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-popover/su-popover.vue b/sheep/ui/su-popover/su-popover.vue
new file mode 100644
index 0000000..adff127
--- /dev/null
+++ b/sheep/ui/su-popover/su-popover.vue
@@ -0,0 +1,314 @@
+
+
+
+
+
+
+
+
+ {{ tips }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-popup/keypress.js b/sheep/ui/su-popup/keypress.js
new file mode 100644
index 0000000..6141c4c
--- /dev/null
+++ b/sheep/ui/su-popup/keypress.js
@@ -0,0 +1,45 @@
+// #ifdef H5
+export default {
+ name: 'Keypress',
+ props: {
+ disable: {
+ type: Boolean,
+ default: false,
+ },
+ },
+ mounted() {
+ const keyNames = {
+ esc: ['Esc', 'Escape'],
+ tab: 'Tab',
+ enter: 'Enter',
+ space: [' ', 'Spacebar'],
+ up: ['Up', 'ArrowUp'],
+ left: ['Left', 'ArrowLeft'],
+ right: ['Right', 'ArrowRight'],
+ down: ['Down', 'ArrowDown'],
+ delete: ['Backspace', 'Delete', 'Del'],
+ };
+ const listener = ($event) => {
+ if (this.disable) {
+ return;
+ }
+ const keyName = Object.keys(keyNames).find((key) => {
+ const keyName = $event.key;
+ const value = keyNames[key];
+ return value === keyName || (Array.isArray(value) && value.includes(keyName));
+ });
+ if (keyName) {
+ // 避免和其他按键事件冲突
+ setTimeout(() => {
+ this.$emit(keyName, {});
+ }, 0);
+ }
+ };
+ document.addEventListener('keyup', listener);
+ // this.$once('hook:beforeDestroy', () => {
+ // document.removeEventListener('keyup', listener)
+ // })
+ },
+ render: () => {},
+};
+// #endif
diff --git a/sheep/ui/su-popup/su-popup.vue b/sheep/ui/su-popup/su-popup.vue
new file mode 100644
index 0000000..b55b007
--- /dev/null
+++ b/sheep/ui/su-popup/su-popup.vue
@@ -0,0 +1,589 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-progress/su-progress.vue b/sheep/ui/su-progress/su-progress.vue
new file mode 100644
index 0000000..4612705
--- /dev/null
+++ b/sheep/ui/su-progress/su-progress.vue
@@ -0,0 +1,203 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ percentage }}%
+
+
+
+
+ {{ percentage }}%
+
+
+
+
+ {{ percentage }}%
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-radio/su-radio.vue b/sheep/ui/su-radio/su-radio.vue
new file mode 100644
index 0000000..6fc4f74
--- /dev/null
+++ b/sheep/ui/su-radio/su-radio.vue
@@ -0,0 +1,301 @@
+
+
+
+
+
+
+
+ {{ label }}
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-region-picker/su-region-picker.vue b/sheep/ui/su-region-picker/su-region-picker.vue
new file mode 100644
index 0000000..1f8d89e
--- /dev/null
+++ b/sheep/ui/su-region-picker/su-region-picker.vue
@@ -0,0 +1,247 @@
+
+
+
+
+
+
+
+
+
+ {{ province.name }}
+
+
+
+
+ {{ city.name }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-status-bar/su-status-bar.vue b/sheep/ui/su-status-bar/su-status-bar.vue
new file mode 100644
index 0000000..9af07f9
--- /dev/null
+++ b/sheep/ui/su-status-bar/su-status-bar.vue
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-sticky/su-sticky.vue b/sheep/ui/su-sticky/su-sticky.vue
new file mode 100644
index 0000000..a8831a2
--- /dev/null
+++ b/sheep/ui/su-sticky/su-sticky.vue
@@ -0,0 +1,264 @@
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-subline/su-subline.vue b/sheep/ui/su-subline/su-subline.vue
new file mode 100644
index 0000000..c11d176
--- /dev/null
+++ b/sheep/ui/su-subline/su-subline.vue
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-swiper/su-swiper.vue b/sheep/ui/su-swiper/su-swiper.vue
new file mode 100644
index 0000000..7465db1
--- /dev/null
+++ b/sheep/ui/su-swiper/su-swiper.vue
@@ -0,0 +1,502 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ state.cur + 1 }} / {{ props.list.length }}
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-switch/su-switch.vue b/sheep/ui/su-switch/su-switch.vue
new file mode 100644
index 0000000..d63e800
--- /dev/null
+++ b/sheep/ui/su-switch/su-switch.vue
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-tab-item/su-tab-item.vue b/sheep/ui/su-tab-item/su-tab-item.vue
new file mode 100644
index 0000000..615df2f
--- /dev/null
+++ b/sheep/ui/su-tab-item/su-tab-item.vue
@@ -0,0 +1,169 @@
+
+
+
+
+
+ {{ props.data.title }}
+
+
+ {{ props.data.tag }}
+
+
+ {{ props.data.subtitle }}
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-tab/su-tab.vue b/sheep/ui/su-tab/su-tab.vue
new file mode 100644
index 0000000..17a7983
--- /dev/null
+++ b/sheep/ui/su-tab/su-tab.vue
@@ -0,0 +1,474 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-tabbar-item/su-tabbar-item.vue b/sheep/ui/su-tabbar-item/su-tabbar-item.vue
new file mode 100644
index 0000000..cc55ac1
--- /dev/null
+++ b/sheep/ui/su-tabbar-item/su-tabbar-item.vue
@@ -0,0 +1,234 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ text }}
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-tabbar/su-tabbar.vue b/sheep/ui/su-tabbar/su-tabbar.vue
new file mode 100644
index 0000000..92e0352
--- /dev/null
+++ b/sheep/ui/su-tabbar/su-tabbar.vue
@@ -0,0 +1,227 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-tabs-item/props.js b/sheep/ui/su-tabs-item/props.js
new file mode 100644
index 0000000..3908c36
--- /dev/null
+++ b/sheep/ui/su-tabs-item/props.js
@@ -0,0 +1,3 @@
+export default {
+ props: {},
+};
diff --git a/sheep/ui/su-tabs-item/su-tabs-item.vue b/sheep/ui/su-tabs-item/su-tabs-item.vue
new file mode 100644
index 0000000..7139684
--- /dev/null
+++ b/sheep/ui/su-tabs-item/su-tabs-item.vue
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-tabs/su-tabs.vue b/sheep/ui/su-tabs/su-tabs.vue
new file mode 100644
index 0000000..05d7dcb
--- /dev/null
+++ b/sheep/ui/su-tabs/su-tabs.vue
@@ -0,0 +1,434 @@
+
+
+
+
+
+
+
+
+ {{ item[keyName] }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-time-line/su-time-line.vue b/sheep/ui/su-time-line/su-time-line.vue
new file mode 100644
index 0000000..9c3f8c1
--- /dev/null
+++ b/sheep/ui/su-time-line/su-time-line.vue
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-timeline-item/su-timeline-item.vue b/sheep/ui/su-timeline-item/su-timeline-item.vue
new file mode 100644
index 0000000..ddf7a0b
--- /dev/null
+++ b/sheep/ui/su-timeline-item/su-timeline-item.vue
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-toolbar/su-toolbar.vue b/sheep/ui/su-toolbar/su-toolbar.vue
new file mode 100644
index 0000000..17351ec
--- /dev/null
+++ b/sheep/ui/su-toolbar/su-toolbar.vue
@@ -0,0 +1,129 @@
+
+
+
+
+ {{ cancelText }}
+
+
+ {{ title }}
+
+
+ {{ confirmText }}
+
+
+
+
+
+
+
+
diff --git a/sheep/ui/su-video/su-video.vue b/sheep/ui/su-video/su-video.vue
new file mode 100644
index 0000000..a75a79c
--- /dev/null
+++ b/sheep/ui/su-video/su-video.vue
@@ -0,0 +1,199 @@
+
+
+
+
+
+
+
diff --git a/sheep/url/index.js b/sheep/url/index.js
new file mode 100644
index 0000000..d216f83
--- /dev/null
+++ b/sheep/url/index.js
@@ -0,0 +1,199 @@
+import $store from '@/sheep/store';
+import { staticUrl } from '@/sheep/config';
+
+const cdn = (url = '', cdnurl = '') => {
+ if (!url) return '';
+ if (url.indexOf('http') === 0) {
+ return url;
+ }
+ if (cdnurl === '') {
+ cdnurl = $store('app').info.cdnurl;
+ }
+ return cdnurl + url;
+};
+export default {
+ // 添加cdn域名前缀
+ cdn,
+ // 对象存储自动剪裁缩略图
+ thumb: (url = '', params) => {
+ url = cdn(url);
+ return append_thumbnail_params(url, params);
+ },
+ // 静态资源地址
+ static: (url = '', staticurl = '') => {
+ if (staticurl === '') {
+ staticurl = staticUrl;
+ }
+ if (staticurl !== 'local') {
+ url = cdn(url, staticurl);
+ }
+ return url;
+ },
+ // css背景图片地址
+ css: (url = '', staticurl = '') => {
+ if (staticurl === '') {
+ staticurl = staticUrl;
+ }
+ if (staticurl !== 'local') {
+ url = cdn(url, staticurl);
+ }
+ // #ifdef APP-PLUS
+ if (staticurl === 'local') {
+ url = plus.io.convertLocalFileSystemURL(url);
+ }
+ // #endif
+ return `url(${url})`;
+ },
+};
+
+/**
+ * 追加对象存储自动裁剪/压缩参数
+ *
+ * @return string
+ */
+function append_thumbnail_params(url, params) {
+ const filesystem = $store('app').info.filesystem;
+ if (filesystem === 'public') {
+ return url;
+ }
+ let width = params.width || '200'; // 宽度
+ let height = params.height || '200'; // 高度
+ let mode = params.mode || 'lfit'; // 缩放模式
+ let quality = params.quality || 90; // 压缩质量
+ let gravity = params.gravity || 'center'; // 剪裁质量
+ let suffix = '';
+ let crop_str = '';
+ let quality_str = '';
+ let size = width + 'x' + height;
+ switch (filesystem) {
+ case 'aliyun':
+ // 裁剪
+ if (!gravity && gravity != 'center') {
+ // 指定了裁剪区域
+ mode = 'mfit';
+ crop_str = '/crop,g_' + gravityFormatMap('aliyun', gravity) + ',w_' + width + ',h_' + height;
+ }
+
+ // 质量压缩
+ if (quality > 0 && quality < 100) {
+ quality_str = '/quality,q_' + quality;
+ }
+
+ // 缩放参数
+ suffix = 'x-oss-process=image/resize,m_' + mode + ',w_' + width + ',h_' + height;
+
+ // 拼接裁剪和质量压缩
+ suffix += crop_str + quality_str;
+ break;
+ case 'qcloud':
+ let mode_str = 'thumbnail';
+ if (mode == 'fill' || (!gravity && gravity != 'center')) {
+ // 指定了裁剪区域
+ mode_str = 'crop';
+ mode = 'fill';
+ crop_str = '/gravity/' + gravityFormatMap('qcloud', gravity);
+ }
+
+ // 质量压缩
+ if (quality > 0 && quality < 100) {
+ quality_str = '/rquality/' + quality;
+ }
+
+ switch (mode) {
+ case 'lfit':
+ size = '' + size + '>';
+ break;
+ case 'mfit':
+ size = '!' + size + 'r';
+ case 'fill':
+ break;
+ case 'pad':
+ size = size + '/pad/1';
+ break;
+ case 'fixed':
+ size = size + '!';
+ break;
+ }
+
+ suffix = 'imageMogr2/' + mode_str + '/' + size + crop_str + quality_str;
+ break;
+ case 'qiniu':
+ if (mode == 'fill' || (!gravity && gravity != 'center')) {
+ // 指定了裁剪区域,全部转为 mfit
+ mode = 'mfit';
+ crop_str = '/gravity/' + gravityFormatMap('qiniu', gravity) + '/crop/' + size;
+ }
+ // 质量压缩
+ if (quality > 0 && quality < 100) {
+ quality_str = '/quality/' + quality;
+ }
+
+ switch (mode) {
+ case 'lfit':
+ case 'pad': // 七牛不支持在缩放之后,尺寸不足时,填充背景色,所以这里和 lfit 模式一样
+ size = size + '>';
+ break;
+ case 'mfit':
+ size = '!' + size + 'r';
+ break;
+ case 'fill':
+ // 会被转为 mfit
+ break;
+ case 'fixed':
+ size = size + '!';
+ break;
+ }
+
+ suffix = 'imageMogr2/thumbnail/' + size + crop_str + quality_str;
+ break;
+ }
+ return url + '?' + suffix;
+}
+
+/**
+ * 裁剪区域格式转换
+ *
+ * @param string $type aliyun|qcloud|qiniu
+ * @param string $gravity 统一的裁剪区域字符
+ *
+ * @return string
+ */
+function gravityFormatMap(type, gravity) {
+ let gravityFormat = {
+ aliyun: {
+ north_west: 'nw', // 左上
+ north: 'north', // 中上
+ north_east: 'ne', // 右上
+ west: 'west', // 左中
+ center: 'center', // 中部
+ east: 'east', // 右中
+ south_west: 'sw', // 左下
+ south: 'south', // 中下
+ south_east: 'se', // 右下
+ },
+ qcloud: {
+ northwest: 'nw', // 左上
+ north: 'north', // 中上
+ northeast: 'ne', // 右上
+ west: 'west', // 左中
+ center: 'center', // 中部
+ east: 'east', // 右中
+ southwest: 'sw', // 左下
+ south: 'south', // 中下
+ southeast: 'se', // 右下
+ },
+ qiniu: {
+ NorthWest: 'nw', // 左上
+ North: 'north', // 中上
+ NorthEast: 'ne', // 右上
+ West: 'west', // 左中
+ Center: 'center', // 中部
+ East: 'east', // 右中
+ SouthWest: 'sw', // 左下
+ South: 'south', // 中下
+ SouthEast: 'se', // 右下
+ },
+ };
+
+ return gravityFormat[type][gravity];
+}
diff --git a/sheep/util/adVideoUtils.js b/sheep/util/adVideoUtils.js
new file mode 100644
index 0000000..2696826
--- /dev/null
+++ b/sheep/util/adVideoUtils.js
@@ -0,0 +1,107 @@
+let videoAd = null;
+let adVideoUtils = {
+ /**
+ * @param {String} adUnitId 小程序广告视频id
+ * videoAdInit 初始化激励广告
+ */
+ videoAdInit(adUnitId) {
+ if (videoAd) {
+ videoAd = null;
+ }
+ if (uni.createRewardedVideoAd) {
+ videoAd = uni.createRewardedVideoAd({
+ adUnitId: adUnitId,
+ });
+ if (videoAd) {
+ videoAd.onLoad(() => {
+ console.log('激励视频 广告加载成功');
+ });
+ videoAd.onError((err) => {
+ console.log('onError event emit');
+ });
+ }
+ // return videoAd;
+ }
+ },
+ /**
+ * @param {String} adUnitId 小程序广告视频id
+ * videoAdInit 初始化插屏广告
+ */
+ insertVideoAdInit(adUnitId) {
+ if (videoAd) {
+ videoAd = null;
+ }
+ if (uni.createInterstitialAd) {
+ videoAd = uni.createInterstitialAd({
+ adUnitId: adUnitId,
+ });
+ if (videoAd) {
+ videoAd.onLoad(() => {
+ console.log('插屏视频 广告加载成功');
+ });
+ videoAd.onError((err) => {
+ console.log('onError event emit');
+ });
+ }
+ // return videoAd;
+ }
+ },
+ /* 显示广告 ture为播放完成 */
+ videoAdShow() {
+ return new Promise((resolve, reject) => {
+ adVideoUtils._showAd().then((val) => {
+ if (val) {
+ videoAd.onClose((res) => {
+ videoAd.offClose();
+ if (res.isEnded) {
+ //成功 给予奖励
+ resolve(true);
+ } else {
+ resolve(false);
+ }
+ });
+ videoAd.onError((err) => {
+ if (err.errCode == "1004") {
+ reject("1004");
+ } else {
+ reject(err);
+ }
+ });
+ } else {
+ resolve(true);
+ //reject(err);
+ }
+ });
+ });
+ },
+ _showAd() {
+ return new Promise((resolve) => {
+ videoAd
+ .show()
+ .then(() => {
+ console.log("广告显示成功");
+ uni.setStorageSync("adClick", false);
+ resolve(true);
+ })
+ .catch((err) => {
+ console.log("广告组件出现问题", err);
+ // 可以手动加载一次
+ videoAd
+ .load()
+ .then(() => {
+ console.log("手动加载成功");
+ uni.setStorageSync("adClick", false);
+ resolve(true);
+ // 加载成功后需要再显示广告
+ return videoAd.show();
+ })
+ .catch((err) => {
+ resolve(false);
+ console.log("广告组件出现问题2次加载", err);
+ // this.showUToast("加载失败啦,请稍后在试", "error");
+ });
+ });
+ });
+ },
+};
+export default adVideoUtils;
\ No newline at end of file
diff --git a/sheep/util/const.js b/sheep/util/const.js
new file mode 100644
index 0000000..ad36845
--- /dev/null
+++ b/sheep/util/const.js
@@ -0,0 +1,122 @@
+// ========== COMMON - 公共模块 ==========
+
+/**
+ * 与后端Terminal枚举一一对应
+ */
+export const TerminalEnum = {
+ UNKNOWN: 0, // 未知, 目的:在无法解析到 terminal 时,使用它
+ WECHAT_MINI_PROGRAM: 10, //微信小程序
+ WECHAT_WAP: 11, // 微信公众号
+ H5: 20, // H5 网页
+ APP: 31, // 手机 App
+};
+
+/**
+ * 将 uni-app 提供的平台转换为后端所需的 terminal值
+ *
+ * @return 终端
+ */
+export const getTerminal = () => {
+ const platformType = uni.getSystemInfoSync().uniPlatform;
+ // 与后端terminal枚举一一对应
+ switch (platformType) {
+ case 'app':
+ return TerminalEnum.APP;
+ case 'web':
+ return TerminalEnum.H5;
+ case 'mp-weixin':
+ return TerminalEnum.WECHAT_MINI_PROGRAM;
+ default:
+ return TerminalEnum.UNKNOWN;
+ }
+};
+
+// ========== MALL - 营销模块 ==========
+
+import dayjs from "dayjs";
+
+/**
+ * 优惠类型枚举
+ */
+export const PromotionDiscountTypeEnum = {
+ PRICE: {
+ type: 1,
+ name: '满减'
+ },
+ PERCENT: {
+ type: 2,
+ name: '折扣'
+ }
+}
+
+/**
+ * 优惠劵模板的有限期类型的枚举
+ */
+export const CouponTemplateValidityTypeEnum = {
+ DATE: {
+ type: 1,
+ name: '固定日期可用'
+ },
+ TERM: {
+ type: 2,
+ name: '领取之后可用'
+ }
+}
+
+/**
+ * 营销的商品范围枚举
+ */
+export const PromotionProductScopeEnum = {
+ ALL: {
+ scope: 1,
+ name: '通用劵'
+ },
+ SPU: {
+ scope: 2,
+ name: '商品劵'
+ },
+ CATEGORY: {
+ scope: 3,
+ name: '品类劵'
+ }
+}
+
+
+// 时间段的状态枚举
+export const TimeStatusEnum = {
+ WAIT_START: '即将开始',
+ STARTED: '进行中',
+ END: '已结束',
+}
+
+// Promotion 的 WebSocket 消息类型枚举类
+export const WebSocketMessageTypeConstants = {
+ IM_MESSAGE_READ: 'im_message_read_status_change', // IM消息已读
+ IM_MESSAGE_NEWS: 'im_message_news', // IM新消息
+}
+
+/**
+ * 微信小程序的订阅模版
+ */
+export const WxaSubscribeTemplate = {
+ TRADE_ORDER_DELIVERY: "订单已接单提醒",
+ CLERK_APPLY_SUCCESS: "认证审核通知",
+ CLERK_BLIND: "抢单提醒",
+ CLERK_ORDER: "新订单通知",
+ TREND_APPLY_SUCCESS: "审核通过提醒",
+ REWARD_SUCCESS: "收到打赏通知",
+ UNREAD_MESSAGE: "未读回信提醒",
+ PROMOTION_COMBINATION_SUCCESS: "拼团结果通知",
+ PAY_WALLET_RECHARGER_SUCCESS: "充值成功通知",
+}
+
+export const getTimeStatusEnum = (startTime, endTime) => {
+ const now = dayjs();
+ if (now.isBefore(startTime)) {
+ return TimeStatusEnum.WAIT_START;
+ } else if (now.isAfter(endTime)) {
+ return TimeStatusEnum.END;
+ } else {
+ return TimeStatusEnum.STARTED;
+ }
+}
diff --git a/sheep/util/index.js b/sheep/util/index.js
new file mode 100644
index 0000000..e2d8ff7
--- /dev/null
+++ b/sheep/util/index.js
@@ -0,0 +1,133 @@
+import dayjs from "dayjs";
+
+/**
+ * 将一个整数转换为分数保留两位小数
+ * @param {number | string | undefined} num 整数
+ * @return {number} 分数
+ */
+export const formatToFraction = (num) => {
+ if (typeof num === 'undefined') return 0
+ const parsedNumber = typeof num === 'string' ? parseFloat(num) : num
+ return parseFloat((parsedNumber / 100).toFixed(2))
+}
+
+/**
+ * 将一个数转换为 1.00 这样
+ * 数据呈现的时候使用
+ *
+ * @param {number | string | undefined} num 整数
+ * @return {string} 分数
+ */
+export const floatToFixed2 = (num) => {
+ let str = '0.00'
+ if (typeof num === 'undefined') {
+ return str
+ }
+ const f = formatToFraction(num)
+ const decimalPart = f.toString().split('.')[1]
+ const len = decimalPart ? decimalPart.length : 0
+ switch (len) {
+ case 0:
+ str = f.toString() + '.00'
+ break
+ case 1:
+ str = f.toString() + '.0'
+ break
+ case 2:
+ str = f.toString()
+ break
+ }
+ return str
+}
+
+/**
+ * 将一个分数转换为整数
+ *
+ * @param {number | string | undefined} num 分数
+ * @return {number} 整数
+ */
+export const convertToInteger = (num) => {
+ if (typeof num === 'undefined') return 0
+ const parsedNumber = typeof num === 'string' ? parseFloat(num) : num
+ // TODO 分转元后还有小数则四舍五入
+ return Math.round(parsedNumber * 100)
+}
+
+/**
+ * 时间日期转换
+ * @param {dayjs.ConfigType} date 当前时间,new Date() 格式
+ * @param {string} format 需要转换的时间格式字符串
+ * @description format 字符串随意,如 `YYYY-mm、YYYY-mm-dd`
+ * @description format 季度:"YYYY-mm-dd HH:MM:SS QQQQ"
+ * @description format 星期:"YYYY-mm-dd HH:MM:SS WWW"
+ * @description format 几周:"YYYY-mm-dd HH:MM:SS ZZZ"
+ * @description format 季度 + 星期 + 几周:"YYYY-mm-dd HH:MM:SS WWW QQQQ ZZZ"
+ * @returns {string} 返回拼接后的时间字符串
+ */
+export function formatDate(date, format= 'YYYY-MM-DD HH:mm:ss') {
+ // 日期不存在,则返回空
+ if (!date) {
+ return ''
+ }
+ // 日期存在,则进行格式化
+ if (format === undefined) {
+ format = 'YYYY-MM-DD HH:mm:ss'
+ }
+ return dayjs(date).format(format)
+}
+
+/**
+ * 构造树型结构数据
+ *
+ * @param {*} data 数据源
+ * @param {*} id id字段 默认 'id'
+ * @param {*} parentId 父节点字段 默认 'parentId'
+ * @param {*} children 孩子节点字段 默认 'children'
+ * @param {*} rootId 根Id 默认 0
+ */
+export function handleTree(data, id = 'id', parentId = 'parentId', children = 'children', rootId = 0) {
+ // 对源数据深度克隆
+ const cloneData = JSON.parse(JSON.stringify(data))
+ // 循环所有项
+ const treeData = cloneData.filter(father => {
+ let branchArr = cloneData.filter(child => {
+ //返回每一项的子级数组
+ return father[id] === child[parentId]
+ });
+ branchArr.length > 0 ? father.children = branchArr : '';
+ //返回第一层
+ return father[parentId] === rootId;
+ });
+ return treeData !== '' ? treeData : data;
+}
+
+/**
+ * 重置分页对象
+ *
+ * TODO 芋艿:需要处理其它页面
+ *
+ * @param pagination 分页对象
+ */
+export function resetPagination(pagination) {
+ pagination.list = [];
+ pagination.total = 0;
+ pagination.pageNo = 1;
+}
+
+/**
+ * 将值复制到目标对象,且以目标对象属性为准,例:target: {a:1} source:{a:2,b:3} 结果为:{a:2}
+ * @param target 目标对象
+ * @param source 源对象
+ */
+export const copyValueToTarget = (target, source) => {
+ const newObj = Object.assign({}, target, source)
+ // 删除多余属性
+ Object.keys(newObj).forEach((key) => {
+ // 如果不是target中的属性则删除
+ if (Object.keys(target).indexOf(key) === -1) {
+ delete newObj[key]
+ }
+ })
+ // 更新目标对象值
+ Object.assign(target, newObj)
+}
diff --git a/sheep/validate/form.js b/sheep/validate/form.js
new file mode 100644
index 0000000..07b5725
--- /dev/null
+++ b/sheep/validate/form.js
@@ -0,0 +1,164 @@
+/**
+ * Validate v1.0.0 通用验证
+ * @description 项目中用到的表单验证规则
+ */
+import test from '@/sheep/helper/test.js';
+
+// 手机号
+export const mobile = {
+ rules: [
+ {
+ required: true,
+ errorMessage: '请输入手机号',
+ },
+ {
+ validateFunction: function (rule, value, data, callback) {
+ if (!test.mobile(value)) {
+ callback('手机号码格式不正确');
+ }
+ return true;
+ },
+ },
+ ],
+};
+
+// 密码
+export const password = {
+ rules: [
+ {
+ required: true,
+ errorMessage: '请输入密码',
+ },
+ {
+ validateFunction: function (rule, value, data, callback) {
+ if (!/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]+\S{5,12}$/.test(value)) {
+ callback('需包含字母和数字,长度在6-12之间');
+ }
+ return true;
+ },
+ },
+ ],
+};
+
+// 短信验证码
+export const code = {
+ rules: [
+ {
+ required: true,
+ errorMessage: '请输入验证码',
+ },
+ ],
+};
+
+// 真实姓名
+export const realName = {
+ rules: [
+ {
+ required: true,
+ errorMessage: '请输入姓名',
+ },
+ {
+ validateFunction: function (rule, value, data, callback) {
+ if (!test.chinese(value)) {
+ callback('请输入汉字');
+ }
+ return true;
+ },
+ },
+ ],
+};
+
+export const taxName = {
+ rules: [
+ {
+ required: true,
+ errorMessage: '请输入发票抬头名称',
+ },
+ {
+ validateFunction: function (rule, value, data, callback) {
+ if (!test.chinese(value)) {
+ callback('请输入汉字');
+ }
+ return true;
+ },
+ },
+ ],
+};
+
+// 税号
+export const taxNo = {
+ rules: [
+ {
+ required: true,
+ errorMessage: '请输入税号',
+ },
+ ],
+};
+
+// 开户行
+export const bankName = {
+ rules: [
+ {
+ required: true,
+ errorMessage: '请输入开户行',
+ },
+ {
+ validateFunction: function (rule, value, data, callback) {
+ if (!test.chinese(value)) {
+ callback('请输入汉字');
+ }
+ return true;
+ },
+ },
+ ],
+};
+// 银行卡号
+export const bankCode = {
+ rules: [
+ {
+ required: true,
+ errorMessage: '请输入银行卡号',
+ },
+ {
+ validateFunction: function (rule, value, data, callback) {
+ if (!test.number(value)) {
+ callback('请输入正确账号');
+ }
+ return true;
+ },
+ },
+ ],
+};
+
+// 支付宝账号
+export const alipayAccount = {
+ rules: [
+ {
+ required: true,
+ errorMessage: '请输入支付宝账号',
+ },
+ {
+ validateFunction: function (rule, value, data, callback) {
+ let isEmail = test.email(value);
+ let isMobile = test.mobile(value);
+
+ if (!isEmail && !isMobile) {
+ callback('请输入正确账号');
+ }
+ return true;
+ },
+ },
+ ],
+};
+
+export default {
+ mobile,
+ alipayAccount,
+ bankCode,
+ bankName,
+ realName,
+ password,
+ code,
+ taxNo,
+ taxName,
+};
diff --git a/static/activity-left.png b/static/activity-left.png
new file mode 100644
index 0000000..62e3b83
Binary files /dev/null and b/static/activity-left.png differ
diff --git a/static/activity-right.png b/static/activity-right.png
new file mode 100644
index 0000000..e18a96c
Binary files /dev/null and b/static/activity-right.png differ
diff --git a/static/cart-empty.png b/static/cart-empty.png
new file mode 100644
index 0000000..355d182
Binary files /dev/null and b/static/cart-empty.png differ
diff --git a/static/collect-empty.png b/static/collect-empty.png
new file mode 100644
index 0000000..300bd21
Binary files /dev/null and b/static/collect-empty.png differ
diff --git a/static/comment-empty.png b/static/comment-empty.png
new file mode 100644
index 0000000..810a3b1
Binary files /dev/null and b/static/comment-empty.png differ
diff --git a/static/coupon-empty.png b/static/coupon-empty.png
new file mode 100644
index 0000000..9e14d9d
Binary files /dev/null and b/static/coupon-empty.png differ
diff --git a/static/css/iconfont.css b/static/css/iconfont.css
new file mode 100644
index 0000000..27dfb7c
--- /dev/null
+++ b/static/css/iconfont.css
@@ -0,0 +1,558 @@
+@font-face {
+ font-family: "iconfont"; /* Project id 578560 */
+ src:
+ url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2');
+}
+
+.iconfont {
+ font-family: "iconfont" !important;
+ font-size: 16px;
+ font-style: normal;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.iconfont-qiehuan1:before {
+ content: "\e620";
+}
+
+.iconfont-qiehuanyonghu:before {
+ content: "\e6ed";
+}
+
+.iconfont-follow:before {
+ content: "\e60d";
+}
+
+.iconfont-following:before {
+ content: "\e653";
+}
+
+.iconfont-yiguanzhu:before {
+ content: "\e67c";
+}
+
+.iconfont-snatch:before {
+ content: "\e835";
+}
+
+.iconfont-outline-empty-wallet-time:before {
+ content: "\e6f6";
+}
+
+.iconfont-pingtaidengji:before {
+ content: "\e636";
+}
+
+.iconfont-tingkebiji:before {
+ content: "\e62d";
+}
+
+.iconfont-tuijian:before {
+ content: "\e62c";
+}
+
+.iconfont-mianfei-liwutujian:before {
+ content: "\e668";
+}
+
+.iconfont-kaidian:before {
+ content: "\e6e8";
+}
+
+.iconfont-xingxing:before {
+ content: "\e625";
+}
+
+.iconfont-youhuiquan:before {
+ content: "\e686";
+}
+
+.iconfont-dianyuan1:before {
+ content: "\e606";
+}
+
+.iconfont-fenxiaozhongxin2:before {
+ content: "\e603";
+}
+
+.iconfont-quanbudingdan:before {
+ content: "\e640";
+}
+
+.iconfont-dashang:before {
+ content: "\e604";
+}
+
+.iconfont-kefuzhongxin:before {
+ content: "\e63b";
+}
+
+.iconfont-tixian:before {
+ content: "\e60e";
+}
+
+.iconfont-dianyuan:before {
+ content: "\e689";
+}
+
+.iconfont-jiedan:before {
+ content: "\e629";
+}
+
+.iconfont-shimingrenzheng:before {
+ content: "\e6a3";
+}
+
+.iconfont-zhaopiandashangjilu:before {
+ content: "\e602";
+}
+
+.iconfont-vuesax-outline-task-square:before {
+ content: "\e69a";
+}
+
+.iconfont-vuesax-outline-note:before {
+ content: "\e69b";
+}
+
+.iconfont-outline-timer-start:before {
+ content: "\e6bb";
+}
+
+.iconfont-outline-timer-1:before {
+ content: "\e6bc";
+}
+
+.iconfont-gouwudai:before {
+ content: "\e60c";
+}
+
+.iconfont-jinbi:before {
+ content: "\e613";
+}
+
+.iconfont-outline-copy:before {
+ content: "\e6e6";
+}
+
+.iconfont-chat_voice:before {
+ content: "\e690";
+}
+
+.iconfont-voice1:before {
+ content: "\e601";
+}
+
+.iconfont-outline-microphone:before {
+ content: "\e6c2";
+}
+
+.iconfont-outline-image:before {
+ content: "\e6c3";
+}
+
+.iconfont-outline-camera:before {
+ content: "\e6cc";
+}
+
+.iconfont-outline-map:before {
+ content: "\e6d4";
+}
+
+.iconfont-vuesax-outline-slash:before {
+ content: "\e679";
+}
+
+.iconfont-outline-keyboard:before {
+ content: "\e6a7";
+}
+
+.iconfont-bell-slash:before {
+ content: "\eb97";
+}
+
+.iconfont-outline-gift:before {
+ content: "\e6df";
+}
+
+.iconfont-outline-heart:before {
+ content: "\e67a";
+}
+
+.iconfont-vuesax-outline-add-circle:before {
+ content: "\e66f";
+}
+
+.iconfont-vuesax-outline-happyemoji:before {
+ content: "\e678";
+}
+
+.iconfont-outline-voice-cricle:before {
+ content: "\e6c9";
+}
+
+.iconfont-emoji-good:before {
+ content: "\e773";
+}
+
+.iconfont-weixinbiaoqing:before {
+ content: "\e608";
+}
+
+.iconfont-wurao:before {
+ content: "\e644";
+}
+
+.iconfont-fanhuidingbu:before {
+ content: "\e635";
+}
+
+.iconfont-huidaodingbu:before {
+ content: "\e652";
+}
+
+.iconfont-bofang:before {
+ content: "\e624";
+}
+
+.iconfont-voice:before {
+ content: "\e6ef";
+}
+
+.iconfont-phone:before {
+ content: "\e71d";
+}
+
+.iconfont-timefill:before {
+ content: "\e65e";
+}
+
+.iconfont-creativefill:before {
+ content: "\e718";
+}
+
+.iconfont-servicefill:before {
+ content: "\e737";
+}
+
+.iconfont-emoji:before {
+ content: "\e64b";
+}
+
+.iconfont-locationfill:before {
+ content: "\e651";
+}
+
+.iconfont-warnfill:before {
+ content: "\e662";
+}
+
+.iconfont-roundadd:before {
+ content: "\e6d9";
+}
+
+.iconfont-voicefill:before {
+ content: "\e6f0";
+}
+
+.iconfont-keyboard:before {
+ content: "\e71b";
+}
+
+.iconfont-picfill:before {
+ content: "\e72c";
+}
+
+.iconfont-presentfill:before {
+ content: "\e732";
+}
+
+.iconfont-repeal:before {
+ content: "\e733";
+}
+
+.iconfont-goodsfavor:before {
+ content: "\e794";
+}
+
+.iconfont-jubao:before {
+ content: "\e6c4";
+}
+
+.iconfont-dizhi:before {
+ content: "\e670";
+}
+
+.iconfont-faqiqunliaobeifen:before {
+ content: "\e672";
+}
+
+.iconfont-jilu:before {
+ content: "\e675";
+}
+
+.iconfont-tupian3:before {
+ content: "\e676";
+}
+
+.iconfont-quanbubeifen2:before {
+ content: "\e677";
+}
+
+.iconfont-kuozhan:before {
+ content: "\e673";
+}
+
+.iconfont-jianpan:before {
+ content: "\e674";
+}
+
+.iconfont-biaoqing:before {
+ content: "\e671";
+}
+
+.iconfont-yuyinshuohua:before {
+ content: "\e67d";
+}
+
+.iconfont-jiahao:before {
+ content: "\e726";
+}
+
+.iconfont-liwu:before {
+ content: "\e64e";
+}
+
+.iconfont-xiaolian:before {
+ content: "\ec80";
+}
+
+.iconfont-fanhui:before {
+ content: "\e634";
+}
+
+.iconfont-weizhi:before {
+ content: "\e628";
+}
+
+.iconfont-hai:before {
+ content: "\e727";
+}
+
+.iconfont-holiday:before {
+ content: "\e605";
+}
+
+.iconfont-daifukuan:before {
+ content: "\e612";
+}
+
+.iconfont-daipingjia:before {
+ content: "\ee90";
+}
+
+.iconfont-jinhangzhong2:before {
+ content: "\eb2f";
+}
+
+.iconfont-bianji:before {
+ content: "\e65d";
+}
+
+.iconfont-fabu:before {
+ content: "\e68f";
+}
+
+.iconfont-remen:before {
+ content: "\e617";
+}
+
+.iconfont-dianhuahover:before {
+ content: "\e61f";
+}
+
+.iconfont-weixin:before {
+ content: "\e607";
+}
+
+.iconfont-a-Asset54:before {
+ content: "\e60b";
+}
+
+.iconfont-renzhengguanli:before {
+ content: "\e650";
+}
+
+.iconfont-shouye1:before {
+ content: "\e66a";
+}
+
+.iconfont-taocan-suoxiao:before {
+ content: "\e8cd";
+}
+
+.iconfont-shafakongwei:before {
+ content: "\e688";
+}
+
+.iconfont-wode_duanwei:before {
+ content: "\e619";
+}
+
+.iconfont-lightning:before {
+ content: "\e655";
+}
+
+.iconfont-game:before {
+ content: "\e627";
+}
+
+.iconfont-shengboyuyinxiaoxi:before {
+ content: "\e8c5";
+}
+
+.iconfont-yonghu:before {
+ content: "\e63f";
+}
+
+.iconfont-fenxiang1:before {
+ content: "\e633";
+}
+
+.iconfont-zhuye:before {
+ content: "\e618";
+}
+
+.iconfont-withdraw-fill:before {
+ content: "\e642";
+}
+
+.iconfont-fenxiang:before {
+ content: "\e64d";
+}
+
+.iconfont-shangchuan:before {
+ content: "\e639";
+}
+
+.iconfont-shaixuan:before {
+ content: "\e61d";
+}
+
+.iconfont-yirenzheng:before {
+ content: "\e68c";
+}
+
+.iconfont-qiandai:before {
+ content: "\e600";
+}
+
+.iconfont-erweima:before {
+ content: "\e61e";
+}
+
+.iconfont-shouye:before {
+ content: "\e62b";
+}
+
+.iconfont-xianxinghuiyuan:before {
+ content: "\e6b4";
+}
+
+.iconfont-renzheng1:before {
+ content: "\e811";
+}
+
+.iconfont-ziyuan2:before {
+ content: "\e78c";
+}
+
+.iconfont-ziyuan3:before {
+ content: "\e78d";
+}
+
+.iconfont-nan:before {
+ content: "\e64a";
+}
+
+.iconfont-nv:before {
+ content: "\e63a";
+}
+
+.iconfont-xiaoxi:before {
+ content: "\ed59";
+}
+
+.iconfont-shoucang:before {
+ content: "\ed5a";
+}
+
+.iconfont-renzheng:before {
+ content: "\ed5d";
+}
+
+.iconfont-qianbao:before {
+ content: "\ed5f";
+}
+
+.iconfont-zijin:before {
+ content: "\ed61";
+}
+
+.iconfont-zhengjian:before {
+ content: "\ed65";
+}
+
+.iconfont-daohang:before {
+ content: "\ed69";
+}
+
+.iconfont-tongzhi:before {
+ content: "\ed54";
+}
+
+.iconfont-bianpinghuatubiaosheji-:before {
+ content: "\e62a";
+}
+
+.iconfont-wenhao:before {
+ content: "\e616";
+}
+
+.iconfont-icfemale:before {
+ content: "\e768";
+}
+
+.iconfont-icmale:before {
+ content: "\e769";
+}
+
+.iconfont-leimuxigengduo:before {
+ content: "\e64c";
+}
+
+.iconfont-aixin:before {
+ content: "\e8ab";
+}
+
+.iconfont-pinglun:before {
+ content: "\e8b4";
+}
+
+.iconfont-yiwancheng:before {
+ content: "\e615";
+}
+
+.iconfont-guanbi1:before {
+ content: "\e614";
+}
+
+.iconfont-huati:before {
+ content: "\e8c4";
+}
+
+.iconfont-huo:before {
+ content: "\e64f";
+}
+
diff --git a/static/data-empty.png b/static/data-empty.png
new file mode 100644
index 0000000..a682ff7
Binary files /dev/null and b/static/data-empty.png differ
diff --git a/static/goods-empty.png b/static/goods-empty.png
new file mode 100644
index 0000000..bd42eca
Binary files /dev/null and b/static/goods-empty.png differ
diff --git a/static/images/audio.png b/static/images/audio.png
new file mode 100644
index 0000000..885164b
Binary files /dev/null and b/static/images/audio.png differ
diff --git a/static/images/line.png b/static/images/line.png
new file mode 100644
index 0000000..d4b633d
Binary files /dev/null and b/static/images/line.png differ
diff --git a/static/images/writeOff.png b/static/images/writeOff.png
new file mode 100644
index 0000000..68749d8
Binary files /dev/null and b/static/images/writeOff.png differ
diff --git a/static/internet-empty.png b/static/internet-empty.png
new file mode 100644
index 0000000..55ac2f6
Binary files /dev/null and b/static/internet-empty.png differ
diff --git a/static/order-empty.png b/static/order-empty.png
new file mode 100644
index 0000000..a7b46fe
Binary files /dev/null and b/static/order-empty.png differ
diff --git a/static/soldout-empty.png b/static/soldout-empty.png
new file mode 100644
index 0000000..1761466
Binary files /dev/null and b/static/soldout-empty.png differ
diff --git a/uni.scss b/uni.scss
new file mode 100644
index 0000000..e4f9098
--- /dev/null
+++ b/uni.scss
@@ -0,0 +1,77 @@
+/**
+ * 这里是uni-app内置的常用样式变量
+ *
+ * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
+ * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
+ *
+ */
+@import '@/sheep/scss/_var.scss';
+@import "@/uni_modules/vk-uview-ui/theme.scss";
+/**
+ * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
+ *
+ * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
+ */
+
+/* 颜色变量 */
+
+/* 行为相关颜色 */
+$uni-color-primary: #007aff;
+$uni-color-success: #4cd964;
+$uni-color-warning: #f0ad4e;
+$uni-color-error: #dd524d;
+
+/* 文字基本颜色 */
+$uni-text-color:#333;//基本色
+$uni-text-color-inverse:#fff;//反色
+$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
+$uni-text-color-placeholder: #808080;
+$uni-text-color-disable:#c0c0c0;
+
+/* 背景颜色 */
+$uni-bg-color:#ffffff;
+$uni-bg-color-grey:#f8f8f8;
+$uni-bg-color-hover:#f1f1f1;//点击状态颜色
+$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
+
+/* 边框颜色 */
+$uni-border-color:#e5e5e5;
+
+/* 尺寸变量 */
+
+/* 文字尺寸 */
+$uni-font-size-sm:12px;
+$uni-font-size-base:14px;
+$uni-font-size-lg:16;
+
+/* 图片尺寸 */
+$uni-img-size-sm:20px;
+$uni-img-size-base:26px;
+$uni-img-size-lg:40px;
+
+/* Border Radius */
+$uni-border-radius-sm: 2px;
+$uni-border-radius-base: 3px;
+$uni-border-radius-lg: 6px;
+$uni-border-radius-circle: 50%;
+
+/* 水平间距 */
+$uni-spacing-row-sm: 5px;
+$uni-spacing-row-base: 10px;
+$uni-spacing-row-lg: 15px;
+
+/* 垂直间距 */
+$uni-spacing-col-sm: 4px;
+$uni-spacing-col-base: 8px;
+$uni-spacing-col-lg: 12px;
+
+/* 透明度 */
+$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
+
+/* 文章场景相关 */
+$uni-color-title: #2C405A; // 文章标题颜色
+$uni-font-size-title:20px;
+$uni-color-subtitle: #555555; // 二级标题颜色
+$uni-font-size-subtitle:26px;
+$uni-color-paragraph: #3F536E; // 文章段落颜色
+$uni-font-size-paragraph:15px;
diff --git a/uni_modules/all-speech/changelog.md b/uni_modules/all-speech/changelog.md
new file mode 100644
index 0000000..8818514
--- /dev/null
+++ b/uni_modules/all-speech/changelog.md
@@ -0,0 +1,25 @@
+## 1.1.1(2024-05-22)
+1.新增node后端方便测试
+2.修复H5及H5上传示例
+## 1.0.7(2024-05-22)
+更新H5上传示例,新增node后端测试 自行进行测试
+## 1.0.6(2024-03-19)
+上传示例项目
+## 1.0.5(2024-03-19)
+修复PC语音录制
+## 1.0.4(2024-03-19)
+兼容pc
+## 1.0.0(2024-03-19)
+兼容PC
+## 1.0.3(2024-03-15)
+修复安卓导入失败
+## 1.0.2(2024-03-14)
+修复小程序报错,支持vue3
+## 1.0.1(2024-03-05)
+补充说明,原作者信息。本人只是补充
+
+
+## 1.0.0(2024-03-05)
+### 首次发布
+1.原地址 https://ext.dcloud.net.cn/plugin?id=9595
+2.原有基础上兼容H5,如有侵权联系立刻下架
diff --git a/uni_modules/all-speech/components/all-speech/all-speech.vue b/uni_modules/all-speech/components/all-speech/all-speech.vue
new file mode 100644
index 0000000..4095b73
--- /dev/null
+++ b/uni_modules/all-speech/components/all-speech/all-speech.vue
@@ -0,0 +1,652 @@
+
+
+
+
+
+
+ {{showRecordTime}}
+
+
+
+ 最短{{minTime}}秒,最长{{maxTime}}秒
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ btnTextContent }}
+
+
+
+
+
+
diff --git a/uni_modules/all-speech/js_sdk/h5-speech/speech.js b/uni_modules/all-speech/js_sdk/h5-speech/speech.js
new file mode 100644
index 0000000..d6acbd9
--- /dev/null
+++ b/uni_modules/all-speech/js_sdk/h5-speech/speech.js
@@ -0,0 +1,226 @@
+class Recoder {
+ constructor(sampleRate) {
+ this.leftDataList = []
+ this.rightDataList = []
+ this.mediaPlayer = null
+ this.audioContext = null
+ this.source = null
+ this.sampleRate = sampleRate || 44100
+ }
+ start() {
+ return new Promise((resolve, reject) => {
+ window.navigator.mediaDevices.getUserMedia({
+ audio: {
+ sampleRate: 8000, // 采样率
+ channelCount: 1, // 声道
+ audioBitsPerSecond: 64,
+ volume: 1.0, // 音量
+ autoGainControl: true
+ }
+ }).then(mediaStream => {
+ console.log(mediaStream, 'mediaStream')
+ this.mediaPlayer = mediaStream
+ this.beginRecord(mediaStream)
+ resolve()
+ }).catch(err => {
+ // 如果用户电脑没有麦克风设备或者用户拒绝了,或者连接出问题了等
+ // 这里都会抛异常,并且通过err.name可以知道是哪种类型的错误
+ console.error(err)
+ reject(err)
+ })
+ })
+ }
+
+ beginRecord(mediaStream) {
+ let audioContext = new(window.AudioContext || window.webkitAudioContext)()
+ // mediaNode包含 mediaStream,audioContext
+ let mediaNode = audioContext.createMediaStreamSource(mediaStream)
+ console.log(mediaNode, 'mediaNode')
+ // 创建一个jsNode
+ // audioContext.sampleRate = 8000
+ console.log(audioContext, 'audioContext')
+ let jsNode = this.createJSNode(audioContext)
+ console.log(jsNode, 'jsnode')
+ // 需要连到扬声器消费掉outputBuffer,process回调才能触发
+ // 并且由于不给outputBuffer设置内容,所以扬声器不会播放出声音
+ jsNode.connect(audioContext.destination)
+ jsNode.onaudioprocess = this.onAudioProcess.bind(this)
+ // 把mediaNode连接到jsNode
+ mediaNode.connect(jsNode)
+ this.audioContext = audioContext
+ }
+
+ onAudioProcess(event) {
+ console.log('is recording')
+ // 拿到输入buffer Float32Array
+ let audioBuffer = event.inputBuffer
+ let leftChannelData = audioBuffer.getChannelData(0)
+ // let rightChannelData = audioBuffer.getChannelData(1)
+
+ // 需要克隆一下
+ this.leftDataList.push(leftChannelData.slice(0))
+ //this.rightDataList.push(rightChannelData.slice(0))
+ }
+
+ createJSNode(audioContext) {
+ const BUFFER_SIZE = 4096
+ const INPUT_CHANNEL_COUNT = 1
+ const OUTPUT_CHANNEL_COUNT = 1
+ // createJavaScriptNode已被废弃
+ let creator = audioContext.createScriptProcessor || audioContext.createJavaScriptNode
+ creator = creator.bind(audioContext)
+ return creator(BUFFER_SIZE, INPUT_CHANNEL_COUNT, OUTPUT_CHANNEL_COUNT)
+ }
+
+ playRecord(arrayBuffer) {
+ let blob = new Blob([new Int8Array(arrayBuffer)], {
+ type: 'audio/mp3' // files[0].type
+ })
+ let blobUrl = URL.createObjectURL(blob)
+ this.source = blob
+ this.blobUrl = blobUrl
+ // document.querySelector(‘.audio-node‘).src = blobUrl
+ return blobUrl
+ }
+
+ stop() {
+ // 停止录音
+ let leftData = this.mergeArray(this.leftDataList)
+ //let rightData = this.mergeArray(this.rightDataList)
+ let allData = this.interSingleData(leftData)
+ let wavBuffer = this.createWavFile(allData)
+
+ // 转到播放
+ let source = this.playRecord(wavBuffer)
+ // if (source) {
+ // source = source.slice(5)
+ // }
+ console.log("我最后转换完播放的---------------------", source);
+ this.resetRecord()
+ return source
+ }
+
+ transformArrayBufferToBase64(buffer) {
+ var binary = ''
+ var bytes = new Uint8Array(buffer)
+ for (var len = bytes.byteLength, i = 0; i < len; i++) {
+ binary += String.fromCharCode(bytes[i])
+ }
+ return window.btoa(binary)
+ }
+
+ // 停止控件录音
+ resetRecord() {
+ this.leftDataList = []
+ this.rightDataList = []
+ this.audioContext.close()
+ this.mediaPlayer.getAudioTracks().forEach(track => {
+ track.stop()
+ this.mediaPlayer.removeTrack(track)
+ })
+ }
+
+ createWavFile(audioData) {
+ let channelCount = 1
+ const WAV_HEAD_SIZE = 44
+ const sampleBits = 16
+ let sampleRate = this.sampleRate
+
+ let buffer = new ArrayBuffer(audioData.length * 2 + WAV_HEAD_SIZE)
+ // 需要用一个view来操控buffer
+ let view = new DataView(buffer)
+ // 写入wav头部信息
+ // RIFF chunk descriptor/identifier
+ this.writeUTFBytes(view, 0, 'RIFF')
+ // RIFF chunk length
+ view.setUint32(4, 44 + audioData.length * channelCount, true)
+ // RIFF type
+ this.writeUTFBytes(view, 8, 'WAVE')
+ // format chunk identifier
+ // FMT sub-chunk
+ this.writeUTFBytes(view, 12, 'fmt ')
+ // format chunk length
+ view.setUint32(16, 16, true)
+ // sample format (raw)
+ view.setUint16(20, 1, true)
+ // stereo (2 channels)
+ view.setUint16(22, channelCount, true)
+ // sample rate
+ view.setUint32(24, sampleRate, true)
+ // byte rate (sample rate * block align)
+ view.setUint32(28, sampleRate * 2, true)
+ // block align (channel count * bytes per sample)
+ view.setUint16(32, 2 * 2, true)
+ // bits per sample
+ view.setUint16(34, 16, true)
+ // data sub-chunk
+ // data chunk identifier
+ this.writeUTFBytes(view, 36, 'data')
+ // data chunk length
+ view.setUint32(40, audioData.length * 2, true)
+
+ console.log(view, 'view')
+ let length = audioData.length
+ let index = 44
+ let volume = 1
+ for (let i = 0; i < length; i++) {
+ view.setInt16(index, audioData[i] * (0x7FFF * volume), true)
+ index += 2
+ }
+ return buffer
+ }
+
+ writeUTFBytes(view, offset, string) {
+ var lng = string.length
+ for (var i = 0; i < lng; i++) {
+ view.setUint8(offset + i, string.charCodeAt(i))
+ }
+ }
+
+ interSingleData(left) {
+ var t = left.length;
+ let sampleRate = this.audioContext.sampleRate,
+ outputSampleRate = this.sampleRate
+ sampleRate += 0.0;
+ outputSampleRate += 0.0;
+ var s = 0,
+ o = sampleRate / outputSampleRate,
+ u = Math.ceil(t * outputSampleRate / sampleRate),
+ a = new Float32Array(u);
+ for (let i = 0; i < u; i++) {
+ a[i] = left[Math.floor(s)];
+ s += o;
+ }
+ return a;
+ }
+
+ // 交叉合并左右声道的数据
+ interleaveLeftAndRight(left, right) {
+ let totalLength = left.length + right.length
+ let data = new Float32Array(totalLength)
+ for (let i = 0; i < left.length; i++) {
+ let k = i * 2
+ data[k] = left[i]
+ data[k + 1] = right[i]
+ }
+ return data
+ }
+
+ mergeArray(list) {
+ let length = list.length * list[0].length
+ let data = new Float32Array(length)
+ let offset = 0
+ for (let i = 0; i < list.length; i++) {
+ data.set(list[i], offset)
+ offset += list[i].length
+ }
+ return data
+ }
+
+
+
+
+}
+
+
+export default Recoder
\ No newline at end of file
diff --git a/uni_modules/all-speech/js_sdk/wa-permission/permission.js b/uni_modules/all-speech/js_sdk/wa-permission/permission.js
new file mode 100644
index 0000000..543f035
--- /dev/null
+++ b/uni_modules/all-speech/js_sdk/wa-permission/permission.js
@@ -0,0 +1,272 @@
+/**
+ * 本模块封装了Android、iOS的应用权限判断、打开应用权限设置界面、以及位置系统服务是否开启
+ */
+
+var isIos
+// #ifdef APP-PLUS
+isIos = (plus.os.name == "iOS")
+// #endif
+
+// 判断推送权限是否开启
+function judgeIosPermissionPush() {
+ var result = false;
+ var UIApplication = plus.ios.import("UIApplication");
+ var app = UIApplication.sharedApplication();
+ var enabledTypes = 0;
+ if (app.currentUserNotificationSettings) {
+ var settings = app.currentUserNotificationSettings();
+ enabledTypes = settings.plusGetAttribute("types");
+ console.log("enabledTypes1:" + enabledTypes);
+ if (enabledTypes == 0) {
+ console.log("推送权限没有开启");
+ } else {
+ result = true;
+ console.log("已经开启推送功能!")
+ }
+ plus.ios.deleteObject(settings);
+ } else {
+ enabledTypes = app.enabledRemoteNotificationTypes();
+ if (enabledTypes == 0) {
+ console.log("推送权限没有开启!");
+ } else {
+ result = true;
+ console.log("已经开启推送功能!")
+ }
+ console.log("enabledTypes2:" + enabledTypes);
+ }
+ plus.ios.deleteObject(app);
+ plus.ios.deleteObject(UIApplication);
+ return result;
+}
+
+// 判断定位权限是否开启
+function judgeIosPermissionLocation() {
+ var result = false;
+ var cllocationManger = plus.ios.import("CLLocationManager");
+ var status = cllocationManger.authorizationStatus();
+ result = (status != 2)
+ console.log("定位权限开启:" + result);
+ // 以下代码判断了手机设备的定位是否关闭,推荐另行使用方法 checkSystemEnableLocation
+ /* var enable = cllocationManger.locationServicesEnabled();
+ var status = cllocationManger.authorizationStatus();
+ console.log("enable:" + enable);
+ console.log("status:" + status);
+ if (enable && status != 2) {
+ result = true;
+ console.log("手机定位服务已开启且已授予定位权限");
+ } else {
+ console.log("手机系统的定位没有打开或未给予定位权限");
+ } */
+ plus.ios.deleteObject(cllocationManger);
+ return result;
+}
+
+// 判断麦克风权限是否开启
+function judgeIosPermissionRecord() {
+ var result = false;
+ var avaudiosession = plus.ios.import("AVAudioSession");
+ var avaudio = avaudiosession.sharedInstance();
+ var permissionStatus = avaudio.recordPermission();
+ console.log("permissionStatus:" + permissionStatus);
+ if (permissionStatus == 1684369017 || permissionStatus == 1970168948) {
+ console.log("麦克风权限没有开启");
+ } else {
+ result = true;
+ console.log("麦克风权限已经开启");
+ }
+ plus.ios.deleteObject(avaudiosession);
+ return result;
+}
+
+// 判断相机权限是否开启
+function judgeIosPermissionCamera() {
+ var result = false;
+ var AVCaptureDevice = plus.ios.import("AVCaptureDevice");
+ var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide');
+ console.log("authStatus:" + authStatus);
+ if (authStatus == 3) {
+ result = true;
+ console.log("相机权限已经开启");
+ } else {
+ console.log("相机权限没有开启");
+ }
+ plus.ios.deleteObject(AVCaptureDevice);
+ return result;
+}
+
+// 判断相册权限是否开启
+function judgeIosPermissionPhotoLibrary() {
+ var result = false;
+ var PHPhotoLibrary = plus.ios.import("PHPhotoLibrary");
+ var authStatus = PHPhotoLibrary.authorizationStatus();
+ console.log("authStatus:" + authStatus);
+ if (authStatus == 3) {
+ result = true;
+ console.log("相册权限已经开启");
+ } else {
+ console.log("相册权限没有开启");
+ }
+ plus.ios.deleteObject(PHPhotoLibrary);
+ return result;
+}
+
+// 判断通讯录权限是否开启
+function judgeIosPermissionContact() {
+ var result = false;
+ var CNContactStore = plus.ios.import("CNContactStore");
+ var cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0);
+ if (cnAuthStatus == 3) {
+ result = true;
+ console.log("通讯录权限已经开启");
+ } else {
+ console.log("通讯录权限没有开启");
+ }
+ plus.ios.deleteObject(CNContactStore);
+ return result;
+}
+
+// 判断日历权限是否开启
+function judgeIosPermissionCalendar() {
+ var result = false;
+ var EKEventStore = plus.ios.import("EKEventStore");
+ var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0);
+ if (ekAuthStatus == 3) {
+ result = true;
+ console.log("日历权限已经开启");
+ } else {
+ console.log("日历权限没有开启");
+ }
+ plus.ios.deleteObject(EKEventStore);
+ return result;
+}
+
+// 判断备忘录权限是否开启
+function judgeIosPermissionMemo() {
+ var result = false;
+ var EKEventStore = plus.ios.import("EKEventStore");
+ var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1);
+ if (ekAuthStatus == 3) {
+ result = true;
+ console.log("备忘录权限已经开启");
+ } else {
+ console.log("备忘录权限没有开启");
+ }
+ plus.ios.deleteObject(EKEventStore);
+ return result;
+}
+
+// Android权限查询
+function requestAndroidPermission(permissionID) {
+ return new Promise((resolve, reject) => {
+ plus.android.requestPermissions(
+ [permissionID], // 理论上支持多个权限同时查询,但实际上本函数封装只处理了一个权限的情况。有需要的可自行扩展封装
+ function(resultObj) {
+ var result = 0;
+ for (var i = 0; i < resultObj.granted.length; i++) {
+ var grantedPermission = resultObj.granted[i];
+ console.log('已获取的权限:' + grantedPermission);
+ result = 1
+ }
+ for (var i = 0; i < resultObj.deniedPresent.length; i++) {
+ var deniedPresentPermission = resultObj.deniedPresent[i];
+ console.log('拒绝本次申请的权限:' + deniedPresentPermission);
+ result = 0
+ }
+ for (var i = 0; i < resultObj.deniedAlways.length; i++) {
+ var deniedAlwaysPermission = resultObj.deniedAlways[i];
+ console.log('永久拒绝申请的权限:' + deniedAlwaysPermission);
+ result = -1
+ }
+ resolve(result);
+ // 若所需权限被拒绝,则打开APP设置界面,可以在APP设置界面打开相应权限
+ // if (result != 1) {
+ // gotoAppPermissionSetting()
+ // }
+ },
+ function(error) {
+ console.log('申请权限错误:' + error.code + " = " + error.message);
+ resolve({
+ code: error.code,
+ message: error.message
+ });
+ }
+ );
+ });
+}
+
+// 使用一个方法,根据参数判断权限
+function judgeIosPermission(permissionID) {
+ if (permissionID == "location") {
+ return judgeIosPermissionLocation()
+ } else if (permissionID == "camera") {
+ return judgeIosPermissionCamera()
+ } else if (permissionID == "photoLibrary") {
+ return judgeIosPermissionPhotoLibrary()
+ } else if (permissionID == "record") {
+ return judgeIosPermissionRecord()
+ } else if (permissionID == "push") {
+ return judgeIosPermissionPush()
+ } else if (permissionID == "contact") {
+ return judgeIosPermissionContact()
+ } else if (permissionID == "calendar") {
+ return judgeIosPermissionCalendar()
+ } else if (permissionID == "memo") {
+ return judgeIosPermissionMemo()
+ }
+ return false;
+}
+
+// 跳转到**应用**的权限页面
+function gotoAppPermissionSetting() {
+ if (isIos) {
+ var UIApplication = plus.ios.import("UIApplication");
+ var application2 = UIApplication.sharedApplication();
+ var NSURL2 = plus.ios.import("NSURL");
+ // var setting2 = NSURL2.URLWithString("prefs:root=LOCATION_SERVICES");
+ var setting2 = NSURL2.URLWithString("app-settings:");
+ application2.openURL(setting2);
+
+ plus.ios.deleteObject(setting2);
+ plus.ios.deleteObject(NSURL2);
+ plus.ios.deleteObject(application2);
+ } else {
+ // console.log(plus.device.vendor);
+ var Intent = plus.android.importClass("android.content.Intent");
+ var Settings = plus.android.importClass("android.provider.Settings");
+ var Uri = plus.android.importClass("android.net.Uri");
+ var mainActivity = plus.android.runtimeMainActivity();
+ var intent = new Intent();
+ intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ var uri = Uri.fromParts("package", mainActivity.getPackageName(), null);
+ intent.setData(uri);
+ mainActivity.startActivity(intent);
+ }
+}
+
+// 检查系统的设备服务是否开启
+// var checkSystemEnableLocation = async function () {
+function checkSystemEnableLocation() {
+ if (isIos) {
+ var result = false;
+ var cllocationManger = plus.ios.import("CLLocationManager");
+ var result = cllocationManger.locationServicesEnabled();
+ console.log("系统定位开启:" + result);
+ plus.ios.deleteObject(cllocationManger);
+ return result;
+ } else {
+ var context = plus.android.importClass("android.content.Context");
+ var locationManager = plus.android.importClass("android.location.LocationManager");
+ var main = plus.android.runtimeMainActivity();
+ var mainSvr = main.getSystemService(context.LOCATION_SERVICE);
+ var result = mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER);
+ console.log("系统定位开启:" + result);
+ return result
+ }
+}
+
+export default {
+ judgeIosPermission: judgeIosPermission,
+ requestAndroidPermission: requestAndroidPermission,
+ checkSystemEnableLocation: checkSystemEnableLocation,
+ gotoAppPermissionSetting: gotoAppPermissionSetting
+}
diff --git a/uni_modules/all-speech/package.json b/uni_modules/all-speech/package.json
new file mode 100644
index 0000000..1eaa4c5
--- /dev/null
+++ b/uni_modules/all-speech/package.json
@@ -0,0 +1,82 @@
+{
+ "id": "all-speech",
+ "displayName": "allspeech长按录音动画组件,多端权限判断,可监听开始、结束、取消事件",
+ "version": "1.1.1",
+ "description": "https://ext.dcloud.net.cn/plugin?id=9595这个是原项目,本人再次基础上兼容了H5",
+ "keywords": [
+ "长按,录音,动画组件"
+ ],
+ "repository": "",
+ "engines": {
+ "HBuilderX": "^3.1.0"
+ },
+ "dcloudext": {
+ "type": "component-vue",
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://gitee.com/imboya/nb-voice-record"
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y",
+ "alipay": "n"
+ },
+ "client": {
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ },
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "u"
+ },
+ "H5-mobile": {
+ "Safari": "u",
+ "Android Browser": "u",
+ "微信浏览器(Android)": "n",
+ "QQ浏览器(Android)": "n"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "n",
+ "Edge": "n",
+ "Firefox": "y",
+ "Safari": "n"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "u",
+ "百度": "u",
+ "字节跳动": "u",
+ "QQ": "u",
+ "钉钉": "u",
+ "快手": "u",
+ "飞书": "u",
+ "京东": "u"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/all-speech/readme.md b/uni_modules/all-speech/readme.md
new file mode 100644
index 0000000..2722046
--- /dev/null
+++ b/uni_modules/all-speech/readme.md
@@ -0,0 +1,89 @@
+### nbVoiceRecord概述
+ - 这是个基于uni-app 符合uni_modules 的插件
+ - 无任何依赖、纯css动画
+ - nb是NeverBug的意思
+
+### 主要功能
+ - 长按组件后弹出录音弹窗,松手完成录音,手指向上滑动可取消;
+ - 支持各种自定义,如弹窗高度、宽度、各处文字甚至声纹波形的尺寸和颜色;
+ - 已完成多端适配,自动根据授权情况提示完成授权、已获得授权才开始录音
+ - endRecord回调事件附带录音文件
+
+### 动画预览
+
+ - 默认样式
+
+
+
+ - 自定义按钮为圆形(红背景、白字)、弹窗为正方形
+
+
+
+### 基本用法:
+
+```
+
+
+
+
+
+
+
+
+```
+
+### 全部支持参数
+
+| 参数名 | 类型 | 默认值 | 作用 | 注意事项 |
+| ----- | ----- | ------ | ------- | --- |
+| recordOptions | Object | {duration:60000} | 录音配置 |各端支持情况不同,请自行查看[官方说明](https://uniapp.dcloud.net.cn/api/media/record-manager.html#getrecordermanager) |
+| btnStyle | Object | 请查看源码 | 按钮样式 |对象格式 |
+| btnHoverFontcolor | String | #000 | 按钮长按时文字颜色 | |
+| btnHoverBgcolor | String | whitesmoke | 按钮长按时背景颜色 | |
+| btnDefaultText | String | 长按开始录音 | 初始按钮文字 | |
+| btnRecordingText | String | 录音中 | 录制时按钮文字 | |
+| vibrate | Boolean | true | 震动反馈 | 弹窗、滑动取消时 |
+| popupTitle | String | 正在录制音频 | 弹窗顶部文字 | |
+| popupDefaultTips | String | 松手完成录音 | 录制时弹窗底部提示 | |
+| popupCancelTips | String | 松手取消录音 | 滑动取消时弹窗底部提示 | |
+| popupMaxWidth | Number | 600 | 弹窗展开后宽度 |注意这里几个单位都是rpx |
+| popupMaxHeight | Number | 300 | 弹窗展开后高度 | |
+| popupFixBottom | Number | 200 | 弹窗展开后距底部高度 | |
+| popupBgColor | String | whitesmoke | 弹窗背景颜色 | |
+| lineHeight | Number | 50 | 声波高度 | |
+| lineStartColor | String | royalblue | 声波波谷时颜色色值 | 色值或者颜色名均可 |
+| lineEndColor | String | indianred | 声波波峰时颜色色值 | |
+
+### 原作者其他插件
+
+ - [bwinBrand多端自适应企业官网、uniCloud云端一体【用户端】](https://ext.dcloud.net.cn/plugin?id=7821)
+ - [bwinBrand多端自适应企业官网、uniCloud云端一体【管理端】](https://ext.dcloud.net.cn/plugin?id=7822)
+ - [bwinAgent多端、多项目全民经纪人、uniCloud云端一体【经纪人端】](https://ext.dcloud.net.cn/plugin?id=8606)
+ - [bwinAgent多端、多项目全民经纪人、uniCloud云端一体【管理员端】](https://ext.dcloud.net.cn/plugin?id=8607)
+ - [必闻优学,教育培训机构模板(单校区版,纯模板)](https://ext.dcloud.net.cn/plugin?id=7709)
+
+### 一个有趣的社区
+
+ - [NeverBug.cn 弹幕式互动社区](https://neverbug.cn)
+
+### 原作者
+ - QQ:123060128
+ - Email:karma.zhao@gmail.com
+ - 官网:https://brand.neverbug.cn
+
+### 补充作者
+ - QQ:27836407
+ - Email:zgdabao.zhao@gmail.com
diff --git a/uni_modules/c-svga/changelog.md b/uni_modules/c-svga/changelog.md
new file mode 100644
index 0000000..491186d
--- /dev/null
+++ b/uni_modules/c-svga/changelog.md
@@ -0,0 +1,35 @@
+## 1.0.16(2023-04-18)
+优化实现细节
+## 1.0.15(2023-04-18)
+修复已知问题
+## 1.0.14(2023-04-18)
+修复条件编译导致的编译异常
+## 1.0.13(2023-04-10)
+修复vue3 小程序端依赖查找失败的问题
+## 1.0.12(2023-04-10)
+H5、APP端支持音频 小程序暂不支持
+## 1.0.11(2023-04-04)
+修复vue2编译到H5平台加载异常的问题
+## 1.0.10(2023-03-29)
+兼容vue2
+## 1.0.9(2023-03-08)
+修复props响应性丢失问题
+## 1.0.8(2023-03-04)
+新增svga文件加载完成事件 loaded
+## 1.0.7(2023-03-02)
+去除监听事件的on前缀
+## 1.0.6(2023-03-01)
+由于Hbuilderx上传插件无法上传node_odules依赖 导入插件后进入插件目录/uni_modules/c-svga 使用npm i 进行依赖安装
+上两个版本请忽略
+## 1.0.5(2023-03-01)
+预置相关node_modules
+## 1.0.4(2023-03-01)
+预置相关node_modules
+## 1.0.3(2023-03-01)
+修改为node_modules依赖
+## 1.0.2(2023-02-28)
+优化APP端加载速度
+## 1.0.1(2023-01-11)
+修复已知问题
+## 1.0.0(2023-01-10)
+初次提交
diff --git a/uni_modules/c-svga/components/c-svga/c-svga.vue b/uni_modules/c-svga/components/c-svga/c-svga.vue
new file mode 100644
index 0000000..6f71098
--- /dev/null
+++ b/uni_modules/c-svga/components/c-svga/c-svga.vue
@@ -0,0 +1,267 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/uni_modules/c-svga/components/c-svga/js/getfile.js b/uni_modules/c-svga/components/c-svga/js/getfile.js
new file mode 100644
index 0000000..e8cc366
--- /dev/null
+++ b/uni_modules/c-svga/components/c-svga/js/getfile.js
@@ -0,0 +1,67 @@
+export default function getfile(e,isIosDown=false) {
+ // #ifdef APP-PLUS
+ let isIOS = plus.os.name==='iOS'
+ let url = plus.io.convertLocalFileSystemURL(e)
+ return new Promise((resolve, reject) => {
+ if (/(http|https):\/\/([\w.]+\/?)\S*/.test(url)) {
+ if(!isIosDown||!isIOS){
+ resolve(e)
+ return
+ }
+ if(isIOS){
+ let dtask = plus.downloader.createDownload(url, {}, function(d, status) {
+ // 下载完成
+ if (status == 200) {
+ let newurl = plus.io.convertLocalFileSystemURL(d.filename);
+ // console.log("Download success: " + newurl);
+ plus.io.resolveLocalFileSystemURL(newurl, entry => {
+ let reader = null;
+ entry.file(file => {
+ reader = new plus.io.FileReader();
+ reader.onloadend = (read) => {
+ resolve(read.target.result)
+ };
+ reader.readAsDataURL(file);
+ }, function(error) {
+ console.log(error.message);
+ });
+ }, err => {
+ resolve(e)
+ })
+
+ } else {
+ console.log("Download failed: " + status);
+ reject(status)
+ }
+ })
+ dtask.start();
+ }
+ } else {
+
+ plus.io.resolveLocalFileSystemURL(url, entry => {
+ let reader = null;
+ entry.file(file => {
+ reader = new plus.io.FileReader();
+ reader.onloadend = (read) => {
+ resolve(read.target.result)
+ };
+ reader.readAsDataURL(file);
+ }, function(error) {
+ console.log(error.message);
+ });
+ }, err => {
+ resolve(e)
+ })
+
+ }
+
+ })
+ // #endif
+ // #ifdef H5
+
+ return new Promise((resolve, reject) => {
+ resolve(e)
+ })
+
+ // #endif
+}
diff --git a/uni_modules/c-svga/components/c-svga/js/render.js b/uni_modules/c-svga/components/c-svga/js/render.js
new file mode 100644
index 0000000..283ed1a
--- /dev/null
+++ b/uni_modules/c-svga/components/c-svga/js/render.js
@@ -0,0 +1,120 @@
+// #ifdef VUE3
+import { Howl } from 'howler';
+import SVGA from 'svgaplayerweb'
+// #endif
+
+// #ifdef VUE2
+import SVGA from '../../../node_modules/svgaplayerweb'
+import { Howl } from '../../../node_modules/howler';
+// #endif
+import getfile from './getfile.js'
+export default {
+ data() {
+ return {
+ player:null,
+ parser:null,
+ pdata:{}
+ }
+ },
+ methods: {
+ dataURLtoBlob(dataURL) {
+ // 获取 Data URL 的数据部分,去掉头信息
+ let parts = dataURL.split(',');
+ let contentType = parts[0].split(':')[1];
+ let raw = parts[1];
+
+ // 将 Data URL 转换为 Blob 对象
+ let byteString = atob(raw);
+ let arrayBuffer = new ArrayBuffer(byteString.length);
+ let uint8Array = new Uint8Array(arrayBuffer);
+ for (let i = 0; i < byteString.length; i++) {
+ uint8Array[i] = byteString.charCodeAt(i);
+ }
+ return new Blob([arrayBuffer], {type: contentType});
+ },
+ async render(val,oldValue,vm) {
+ this.$nextTick(async()=>{
+ let data,player,parser;
+ if(val){
+ data =val
+ this.pdata=data
+ }else{
+ data=this.pdata
+ }
+ if(!data.src){
+ //console.error('缺少src');
+ return
+ }
+ if(!this.player){
+ player = new SVGA.Player('#'+data.myCanvasId);
+ parser = new SVGA.Parser();
+ }else{
+ player=this.player
+ parser=this.parser
+ player.stopAnimation()
+ }
+ player.loops=data.loops
+ player.clearsAfterStop=data.clearsAfterStop
+ player.fillMode=data.fillMode
+ // console.time("test");
+ // console.log(await getfile(data.src));
+ // return
+ parser.load(await getfile(data.src),(videoItem)=>{
+ player.setVideoItem(videoItem);
+ // console.log(player,videoItem);
+ // let {audios,images} = videoItem
+ // let audioFile="data:audio/x-mpeg;base64," + images[audios[0].audioKey]
+ // console.log(URL.createObjectURL(this.dataURLtoBlob(audioFile)));
+ // console.timeEnd("test");
+
+ this.$ownerInstance.callMethod('receiveRenderData',{name:'loaded'})
+ if(data.autoPlay){
+ player.startAnimation();
+ }
+ },err=>{
+ console.error(err);
+ })
+
+ player.onFinished(()=>{ //只有在loop不为0时候触发
+ // console.log('动画停止播放时回调');
+ vm.callMethod('receiveRenderData',{name:'finished'})
+ })
+ if(data.isOnChange){
+ player.onFrame(frame=>{ //动画播放至某帧后回调
+ // console.log(frame);
+ vm.callMethod('receiveRenderData',{name:'frame',val:frame})
+ })
+ player.onPercentage(percentage=>{ //动画播放至某进度后回调
+ // console.log(percentage);
+ vm.callMethod('receiveRenderData',{name:'percentage',val:percentage})
+ })
+ }
+ this.player=player
+ this.parser=parser
+ });
+ },
+ async callPlayer(val){
+ if(!val.name)return;
+ let {name, args} = val
+ // console.log(name, args);
+ if(name=='setImage'){
+ args[0]=await getfile(args[0])
+ }
+ if(name=='clearDynamicObjects'){
+ const parser = new SVGA.Parser();
+ parser.load(await getfile(this.pdata.src),(videoItem)=>{
+ this.player.setVideoItem(videoItem);
+ this.player.startAnimation();
+ })
+ }
+ if(Array.isArray(args)){
+ this.player[name](...args)
+ }else{
+ this.player[name](args)
+ }
+ }
+
+ },
+ mounted() {
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/c-svga/components/c-svga/js/uuid.js b/uni_modules/c-svga/components/c-svga/js/uuid.js
new file mode 100644
index 0000000..d9c4505
--- /dev/null
+++ b/uni_modules/c-svga/components/c-svga/js/uuid.js
@@ -0,0 +1,23 @@
+
+export default (len = 32, radix = null) => {
+ let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
+ let uuid = [];
+ radix = radix || chars.length;
+ if (len) {
+ // 如果指定uuid长度,只是取随机的字符,0|x为位运算,能去掉x的小数位,返回整数位
+ for (let i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
+ } else {
+ let r;
+ // rfc4122标准要求返回的uuid中,某些位为固定的字符
+ uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
+ uuid[14] = '4';
+
+ for (let i = 0; i < 36; i++) {
+ if (!uuid[i]) {
+ r = 0 | Math.random() * 16;
+ uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
+ }
+ }
+ }
+ return uuid.join('');
+}
diff --git a/uni_modules/c-svga/node_modules/howler/LICENSE.md b/uni_modules/c-svga/node_modules/howler/LICENSE.md
new file mode 100644
index 0000000..29686f5
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/howler/LICENSE.md
@@ -0,0 +1,20 @@
+Copyright (c) 2013-2020 James Simpson and GoldFire Studios, Inc.
+
+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.
\ No newline at end of file
diff --git a/uni_modules/c-svga/node_modules/howler/README.md b/uni_modules/c-svga/node_modules/howler/README.md
new file mode 100644
index 0000000..4a4766f
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/howler/README.md
@@ -0,0 +1,564 @@
+[](https://howlerjs.com)
+
+# Description
+[howler.js](https://howlerjs.com) is an audio library for the modern web. It defaults to [Web Audio API](http://webaudio.github.io/web-audio-api/) and falls back to [HTML5 Audio](https://html.spec.whatwg.org/multipage/embedded-content.html#the-audio-element). This makes working with audio in JavaScript easy and reliable across all platforms.
+
+Additional information, live demos and a user showcase are available at [howlerjs.com](https://howlerjs.com).
+
+Follow on Twitter for howler.js and development-related discussion: [@GoldFireStudios](https://twitter.com/goldfirestudios).
+
+### Features
+* Single API for all audio needs
+* Defaults to Web Audio API and falls back to HTML5 Audio
+* Handles edge cases and bugs across environments
+* Supports all codecs for full cross-browser support
+* Automatic caching for improved performance
+* Control sounds individually, in groups or globally
+* Playback of multiple sounds at once
+* Easy sound sprite definition and playback
+* Full control for fading, rate, seek, volume, etc.
+* Easily add 3D spatial sound or stereo panning
+* Modular - use what you want and easy to extend
+* No outside dependencies, just pure JavaScript
+* As light as 7kb gzipped
+
+### Browser Compatibility
+Tested in the following browsers/versions:
+* Google Chrome 7.0+
+* Internet Explorer 9.0+
+* Firefox 4.0+
+* Safari 5.1.4+
+* Mobile Safari 6.0+ (after user input)
+* Opera 12.0+
+* Microsoft Edge
+
+### Live Demos
+* [Audio Player](https://howlerjs.com/#player)
+* [Radio](https://howlerjs.com/#radio)
+* [Spatial Audio](https://howlerjs.com/#spatial)
+* [Audio Sprites](https://howlerjs.com/#sprite)
+
+# Documentation
+
+### Contents
+* [Quick Start](#quick-start)
+* [Examples](#examples)
+* [Core](#core)
+ * [Options](#options)
+ * [Methods](#methods)
+ * [Global Options](#global-options)
+ * [Global Methods](#global-methods)
+* [Plugin: Spatial](#plugin-spatial)
+ * [Options](#options-1)
+ * [Methods](#methods-1)
+ * [Global Methods](#global-methods-1)
+* [Group Playback](#group-playback)
+* [Mobile Playback](#mobilechrome-playback)
+* [Dolby Audio Playback](#dolby-audio-playback)
+* [Facebook Instant Games](#facebook-instant-games)
+* [Format Recommendations](#format-recommendations)
+* [License](#license)
+
+### Quick Start
+
+Several options to get up and running:
+
+* Clone the repo: `git clone https://github.com/goldfire/howler.js.git`
+* Install with [npm](https://www.npmjs.com/package/howler): `npm install howler`
+* Install with [Yarn](https://yarnpkg.com/en/package/howler): `yarn add howler`
+* Install with [Bower](http://bower.io/): `bower install howler`
+* Hosted CDN: [`cdnjs`](https://cdnjs.com/libraries/howler) [`jsDelivr`](https://www.jsdelivr.com/projects/howler.js)
+
+In the browser:
+
+```html
+
+
+```
+
+As a dependency:
+
+```javascript
+import {Howl, Howler} from 'howler';
+```
+
+```javascript
+const {Howl, Howler} = require('howler');
+```
+
+Included distribution files:
+
+* **howler**: This is the default and fully bundled source that includes `howler.core` and `howler.spatial`. It includes all functionality that howler comes with.
+* **howler.core**: This includes only the core functionality that aims to create parity between Web Audio and HTML5 Audio. It doesn't include any of the spatial/stereo audio functionality.
+* **howler.spatial**: This is a plugin that adds spatial/stereo audio functionality. It requires `howler.core` to operate as it is simply an add-on to the core.
+
+
+### Examples
+
+##### Most basic, play an MP3:
+```javascript
+var sound = new Howl({
+ src: ['sound.mp3']
+});
+
+sound.play();
+```
+
+##### Streaming audio (for live audio or large files):
+```javascript
+var sound = new Howl({
+ src: ['stream.mp3'],
+ html5: true
+});
+
+sound.play();
+```
+
+##### More playback options:
+```javascript
+var sound = new Howl({
+ src: ['sound.webm', 'sound.mp3', 'sound.wav'],
+ autoplay: true,
+ loop: true,
+ volume: 0.5,
+ onend: function() {
+ console.log('Finished!');
+ }
+});
+```
+
+##### Define and play a sound sprite:
+```javascript
+var sound = new Howl({
+ src: ['sounds.webm', 'sounds.mp3'],
+ sprite: {
+ blast: [0, 3000],
+ laser: [4000, 1000],
+ winner: [6000, 5000]
+ }
+});
+
+// Shoot the laser!
+sound.play('laser');
+```
+
+##### Listen for events:
+```javascript
+var sound = new Howl({
+ src: ['sound.webm', 'sound.mp3']
+});
+
+// Clear listener after first call.
+sound.once('load', function(){
+ sound.play();
+});
+
+// Fires when the sound finishes playing.
+sound.on('end', function(){
+ console.log('Finished!');
+});
+```
+
+##### Control multiple sounds:
+```javascript
+var sound = new Howl({
+ src: ['sound.webm', 'sound.mp3']
+});
+
+// Play returns a unique Sound ID that can be passed
+// into any method on Howl to control that specific sound.
+var id1 = sound.play();
+var id2 = sound.play();
+
+// Fade out the first sound and speed up the second.
+sound.fade(1, 0, 1000, id1);
+sound.rate(1.5, id2);
+```
+
+##### ES6:
+```javascript
+import {Howl, Howler} from 'howler';
+
+// Setup the new Howl.
+const sound = new Howl({
+ src: ['sound.webm', 'sound.mp3']
+});
+
+// Play the sound.
+sound.play();
+
+// Change global volume.
+Howler.volume(0.5);
+```
+
+
+More in-depth examples (with accompanying live demos) can be found in the [examples directory](https://github.com/goldfire/howler.js/tree/master/examples).
+
+
+## Core
+
+### Options
+#### src `Array/String` `[]` *`required`*
+The sources to the track(s) to be loaded for the sound (URLs or base64 data URIs). These should be in order of preference, howler.js will automatically load the first one that is compatible with the current browser. If your files have no extensions, you will need to explicitly specify the extension using the `format` property.
+#### volume `Number` `1.0`
+The volume of the specific track, from `0.0` to `1.0`.
+#### html5 `Boolean` `false`
+Set to `true` to force HTML5 Audio. This should be used for large audio files so that you don't have to wait for the full file to be downloaded and decoded before playing.
+#### loop `Boolean` `false`
+Set to `true` to automatically loop the sound forever.
+#### preload `Boolean|String` `true`
+Automatically begin downloading the audio file when the `Howl` is defined. If using HTML5 Audio, you can set this to `'metadata'` to only preload the file's metadata (to get its duration without download the entire file, for example).
+#### autoplay `Boolean` `false`
+Set to `true` to automatically start playback when sound is loaded.
+#### mute `Boolean` `false`
+Set to `true` to load the audio muted.
+#### sprite `Object` `{}`
+Define a sound sprite for the sound. The offset and duration are defined in milliseconds. A third (optional) parameter is available to set a sprite as looping. An easy way to generate compatible sound sprites is with [audiosprite](https://github.com/tonistiigi/audiosprite).
+```javascript
+new Howl({
+ sprite: {
+ key1: [offset, duration, (loop)]
+ },
+});
+```
+#### rate `Number` `1.0`
+The rate of playback. 0.5 to 4.0, with 1.0 being normal speed.
+#### pool `Number` `5`
+The size of the inactive sounds pool. Once sounds are stopped or finish playing, they are marked as ended and ready for cleanup. We keep a pool of these to recycle for improved performance. Generally this doesn't need to be changed. It is important to keep in mind that when a sound is paused, it won't be removed from the pool and will still be considered active so that it can be resumed later.
+#### format `Array` `[]`
+howler.js automatically detects your file format from the extension, but you may also specify a format in situations where extraction won't work (such as with a SoundCloud stream).
+#### xhr `Object` `null`
+When using Web Audio, howler.js uses an XHR request to load the audio files. If you need to send custom headers, set the HTTP method or enable `withCredentials` ([see reference](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials)), include them with this parameter. Each is optional (method defaults to `GET`, headers default to `null` and withCredentials defaults to `false`). For example:
+```javascript
+// Using each of the properties.
+new Howl({
+ xhr: {
+ method: 'POST',
+ headers: {
+ Authorization: 'Bearer:' + token,
+ },
+ withCredentials: true,
+ }
+});
+
+// Only changing the method.
+new Howl({
+ xhr: {
+ method: 'POST',
+ }
+});
+```
+#### onload `Function`
+Fires when the sound is loaded.
+#### onloaderror `Function`
+Fires when the sound is unable to load. The first parameter is the ID of the sound (if it exists) and the second is the error message/code.
+
+The load error codes are [defined in the spec](http://dev.w3.org/html5/spec-author-view/spec.html#mediaerror):
+* **1** - The fetching process for the media resource was aborted by the user agent at the user's request.
+* **2** - A network error of some description caused the user agent to stop fetching the media resource, after the resource was established to be usable.
+* **3** - An error of some description occurred while decoding the media resource, after the resource was established to be usable.
+* **4** - The media resource indicated by the src attribute or assigned media provider object was not suitable.
+#### onplayerror `Function`
+Fires when the sound is unable to play. The first parameter is the ID of the sound and the second is the error message/code.
+#### onplay `Function`
+Fires when the sound begins playing. The first parameter is the ID of the sound.
+#### onend `Function`
+Fires when the sound finishes playing (if it is looping, it'll fire at the end of each loop). The first parameter is the ID of the sound.
+#### onpause `Function`
+Fires when the sound has been paused. The first parameter is the ID of the sound.
+#### onstop `Function`
+Fires when the sound has been stopped. The first parameter is the ID of the sound.
+#### onmute `Function`
+Fires when the sound has been muted/unmuted. The first parameter is the ID of the sound.
+#### onvolume `Function`
+Fires when the sound's volume has changed. The first parameter is the ID of the sound.
+#### onrate `Function`
+Fires when the sound's playback rate has changed. The first parameter is the ID of the sound.
+#### onseek `Function`
+Fires when the sound has been seeked. The first parameter is the ID of the sound.
+#### onfade `Function`
+Fires when the current sound finishes fading in/out. The first parameter is the ID of the sound.
+#### onunlock `Function`
+Fires when audio has been automatically unlocked through a touch/click event.
+
+
+### Methods
+#### play([sprite/id])
+Begins playback of a sound. Returns the sound id to be used with other methods. Only method that can't be chained.
+* **sprite/id**: `String/Number` `optional` Takes one parameter that can either be a sprite or sound ID. If a sprite is passed, a new sound will play based on the sprite's definition. If a sound ID is passed, the previously played sound will be played (for example, after pausing it). However, if an ID of a sound that has been drained from the pool is passed, nothing will play.
+
+#### pause([id])
+Pauses playback of sound or group, saving the `seek` of playback.
+* **id**: `Number` `optional` The sound ID. If none is passed, all sounds in group are paused.
+
+#### stop([id])
+Stops playback of sound, resetting `seek` to `0`.
+* **id**: `Number` `optional` The sound ID. If none is passed, all sounds in group are stopped.
+
+#### mute([muted], [id])
+Mutes the sound, but doesn't pause the playback.
+* **muted**: `Boolean` `optional` True to mute and false to unmute.
+* **id**: `Number` `optional` The sound ID. If none is passed, all sounds in group are stopped.
+
+#### volume([volume], [id])
+Get/set volume of this sound or the group. This method optionally takes 0, 1 or 2 arguments.
+* **volume**: `Number` `optional` Volume from `0.0` to `1.0`.
+* **id**: `Number` `optional` The sound ID. If none is passed, all sounds in group have volume altered relative to their own volume.
+
+#### fade(from, to, duration, [id])
+Fade a currently playing sound between two volumes. Fires the `fade` event when complete.
+* **from**: `Number` Volume to fade from (`0.0` to `1.0`).
+* **to**: `Number` Volume to fade to (`0.0` to `1.0`).
+* **duration**: `Number` Time in milliseconds to fade.
+* **id**: `Number` `optional` The sound ID. If none is passed, all sounds in group will fade.
+
+#### rate([rate], [id])
+Get/set the rate of playback for a sound. This method optionally takes 0, 1 or 2 arguments.
+* **rate**: `Number` `optional` The rate of playback. 0.5 to 4.0, with 1.0 being normal speed.
+* **id**: `Number` `optional` The sound ID. If none is passed, playback rate of all sounds in group will change.
+
+#### seek([seek], [id])
+Get/set the position of playback for a sound. This method optionally takes 0, 1 or 2 arguments.
+* **seek**: `Number` `optional` The position to move current playback to (in seconds).
+* **id**: `Number` `optional` The sound ID. If none is passed, the first sound will seek.
+
+#### loop([loop], [id])
+Get/set whether to loop the sound or group. This method can optionally take 0, 1 or 2 arguments.
+* **loop**: `Boolean` `optional` To loop or not to loop, that is the question.
+* **id**: `Number` `optional` The sound ID. If none is passed, all sounds in group will have their `loop` property updated.
+
+#### state()
+Check the load status of the `Howl`, returns a `unloaded`, `loading` or `loaded`.
+
+#### playing([id])
+Check if a sound is currently playing or not, returns a `Boolean`. If no sound ID is passed, check if any sound in the `Howl` group is playing.
+* **id**: `Number` `optional` The sound ID to check.
+
+#### duration([id])
+Get the duration of the audio source (in seconds). Will return 0 until after the `load` event fires.
+* **id**: `Number` `optional` The sound ID to check. Passing an ID will return the duration of the sprite being played on this instance; otherwise, the full source duration is returned.
+
+#### on(event, function, [id])
+Listen for events. Multiple events can be added by calling this multiple times.
+* **event**: `String` Name of event to fire/set (`load`, `loaderror`, `playerror`, `play`, `end`, `pause`, `stop`, `mute`, `volume`, `rate`, `seek`, `fade`, `unlock`).
+* **function**: `Function` Define function to fire on event.
+* **id**: `Number` `optional` Only listen to events for this sound id.
+
+#### once(event, function, [id])
+Same as `on`, but it removes itself after the callback is fired.
+* **event**: `String` Name of event to fire/set (`load`, `loaderror`, `playerror`, `play`, `end`, `pause`, `stop`, `mute`, `volume`, `rate`, `seek`, `fade`, `unlock`).
+* **function**: `Function` Define function to fire on event.
+* **id**: `Number` `optional` Only listen to events for this sound id.
+
+#### off(event, [function], [id])
+Remove event listener that you've set. Call without parameters to remove all events.
+* **event**: `String` Name of event (`load`, `loaderror`, `playerror`, `play`, `end`, `pause`, `stop`, `mute`, `volume`, `rate`, `seek`, `fade`, `unlock`).
+* **function**: `Function` `optional` The listener to remove. Omit this to remove all events of type.
+* **id**: `Number` `optional` Only remove events for this sound id.
+
+#### load()
+This is called by default, but if you set `preload` to false, you must call `load` before you can play any sounds.
+
+#### unload()
+Unload and destroy a Howl object. This will immediately stop all sounds attached to this sound and remove it from the cache.
+
+
+### Global Options
+#### usingWebAudio `Boolean`
+`true` if the Web Audio API is available.
+#### noAudio `Boolean`
+`true` if no audio is available.
+#### autoUnlock `Boolean` `true`
+Automatically attempts to enable audio on mobile (iOS, Android, etc) devices and desktop Chrome/Safari.
+#### html5PoolSize `Number` `10`
+Each HTML5 Audio object must be unlocked individually, so we keep a global pool of unlocked nodes to share between all `Howl` instances. This pool gets created on the first user interaction and is set to the size of this property.
+#### autoSuspend `Boolean` `true`
+Automatically suspends the Web Audio AudioContext after 30 seconds of inactivity to decrease processing and energy usage. Automatically resumes upon new playback. Set this property to `false` to disable this behavior.
+#### ctx `Boolean` *`Web Audio Only`*
+Exposes the `AudioContext` with Web Audio API.
+#### masterGain `Boolean` *`Web Audio Only`*
+Exposes the master `GainNode` with Web Audio API. This can be useful for writing plugins or advanced usage.
+
+
+### Global Methods
+The following methods are used to modify all sounds globally, and are called from the `Howler` object.
+#### mute(muted)
+Mute or unmute all sounds.
+* **muted**: `Boolean` True to mute and false to unmute.
+
+#### volume([volume])
+Get/set the global volume for all sounds, relative to their own volume.
+* **volume**: `Number` `optional` Volume from `0.0` to `1.0`.
+
+#### stop()
+Stop all sounds and reset their seek position to the beginning.
+
+#### codecs(ext)
+Check supported audio codecs. Returns `true` if the codec is supported in the current browser.
+* **ext**: `String` File extension. One of: "mp3", "mpeg", "opus", "ogg", "oga", "wav", "aac", "caf", "m4a", "m4b", "mp4", "weba", "webm", "dolby", "flac".
+
+#### unload()
+Unload and destroy all currently loaded Howl objects. This will immediately stop all sounds and remove them from cache.
+
+
+## Plugin: Spatial
+
+### Options
+#### orientation `Array` `[1, 0, 0]`
+Sets the direction the audio source is pointing in the 3D cartesian coordinate space. Depending on how directional the sound is, based on the `cone` attributes, a sound pointing away from the listener can be quiet or silent.
+#### stereo `Number` `null`
+Sets the stereo panning value of the audio source for this sound or group. This makes it easy to setup left/right panning with a value of `-1.0` being far left and a value of `1.0` being far right.
+#### pos `Array` `null`
+Sets the 3D spatial position of the audio source for this sound or group relative to the global listener.
+#### pannerAttr `Object`
+Sets the panner node's attributes for a sound or group of sounds. See the `pannerAttr` method for all available options.
+#### onstereo `Function`
+Fires when the current sound has the stereo panning changed. The first parameter is the ID of the sound.
+#### onpos `Function`
+Fires when the current sound has the listener position changed. The first parameter is the ID of the sound.
+#### onorientation `Function`
+Fires when the current sound has the direction of the listener changed. The first parameter is the ID of the sound.
+
+
+### Methods
+#### stereo(pan, [id])
+Get/set the stereo panning of the audio source for this sound or all in the group.
+* **pan**: `Number` A value of `-1.0` is all the way left and `1.0` is all the way right.
+* **id**: `Number` `optional` The sound ID. If none is passed, all in group will be updated.
+
+#### pos(x, y, z, [id])
+Get/set the 3D spatial position of the audio source for this sound or group relative to the global listener.
+* **x**: `Number` The x-position of the audio source.
+* **y**: `Number` The y-position of the audio source.
+* **z**: `Number` The z-position of the audio source.
+* **id**: `Number` `optional` The sound ID. If none is passed, all in group will be updated.
+
+#### orientation(x, y, z, [id])
+Get/set the direction the audio source is pointing in the 3D cartesian coordinate space. Depending on how directional the sound is, based on the `cone` attributes, a sound pointing away from the listener can be quiet or silent.
+* **x**: `Number` The x-orientation of the source.
+* **y**: `Number` The y-orientation of the source.
+* **z**: `Number` The z-orientation of the source.
+* **id**: `Number` `optional` The sound ID. If none is passed, all in group will be updated.
+
+#### pannerAttr(o, [id])
+Get/set the panner node's attributes for a sound or group of sounds.
+* **o**: `Object` All values to update.
+ * **coneInnerAngle** `360` A parameter for directional audio sources, this is an angle, in degrees, inside of which there will be no volume reduction.
+ * **coneOuterAngle** `360` A parameter for directional audio sources, this is an angle, in degrees, outside of which the volume will be reduced to a constant value of `coneOuterGain`.
+ * **coneOuterGain** `0` A parameter for directional audio sources, this is the gain outside of the `coneOuterAngle`. It is a linear value in the range `[0, 1]`.
+ * **distanceModel** `inverse` Determines algorithm used to reduce volume as audio moves away from listener. Can be `linear`, `inverse` or `exponential`. You can find the implementations of each in the [spec](https://webaudio.github.io/web-audio-api/#idl-def-DistanceModelType).
+ * **maxDistance** `10000` The maximum distance between source and listener, after which the volume will not be reduced any further.
+ * **refDistance** `1` A reference distance for reducing volume as source moves further from the listener. This is simply a variable of the distance model and has a different effect depending on which model is used and the scale of your coordinates. Generally, volume will be equal to 1 at this distance.
+ * **rolloffFactor** `1` How quickly the volume reduces as source moves from listener. This is simply a variable of the distance model and can be in the range of `[0, 1]` with `linear` and `[0, ∞]` with `inverse` and `exponential`.
+ * **panningModel** `HRTF` Determines which spatialization algorithm is used to position audio. Can be `HRTF` or `equalpower`.
+* **id**: `Number` `optional` The sound ID. If none is passed, all in group will be updated.
+
+
+### Global Methods
+#### stereo(pan)
+Helper method to update the stereo panning position of all current `Howls`. Future `Howls` will not use this value unless explicitly set.
+* **pan**: `Number` A value of -1.0 is all the way left and 1.0 is all the way right.
+
+#### pos(x, y, z)
+Get/set the position of the listener in 3D cartesian space. Sounds using 3D position will be relative to the listener's position.
+* **x**: `Number` The x-position of the listener.
+* **y**: `Number` The y-position of the listener.
+* **z**: `Number` The z-position of the listener.
+
+#### orientation(x, y, z, xUp, yUp, zUp)
+Get/set the direction the listener is pointing in the 3D cartesian space. A front and up vector must be provided. The front is the direction the face of the listener is pointing, and up is the direction the top of the listener is pointing. Thus, these values are expected to be at right angles from each other.
+* **x**: `Number` The x-orientation of listener.
+* **y**: `Number` The y-orientation of listener.
+* **z**: `Number` The z-orientation of listener.
+* **xUp**: `Number` The x-orientation of the top of the listener.
+* **yUp**: `Number` The y-orientation of the top of the listener.
+* **zUp**: `Number` The z-orientation of the top of the listener.
+
+
+### Group Playback
+Each `new Howl()` instance is also a group. You can play multiple sound instances from the `Howl` and control them individually or as a group (note: each `Howl` can only contain a single audio file). For example, the following plays two sounds from a sprite, changes their volume together and then pauses both of them at the same time.
+
+```javascript
+var sound = new Howl({
+ src: ['sound.webm', 'sound.mp3'],
+ sprite: {
+ track01: [0, 20000],
+ track02: [21000, 41000]
+ }
+});
+
+// Play each of the track.s
+sound.play('track01');
+sound.play('track02');
+
+// Change the volume of both tracks.
+sound.volume(0.5);
+
+// After a second, pause both sounds in the group.
+setTimeout(function() {
+ sound.pause();
+}, 1000);
+```
+
+
+### Mobile/Chrome Playback
+By default, audio on mobile browsers and Chrome/Safari is locked until a sound is played within a user interaction, and then it plays normally the rest of the page session ([Apple documentation](https://developer.apple.com/library/safari/documentation/audiovideo/conceptual/using_html5_audio_video/PlayingandSynthesizingSounds/PlayingandSynthesizingSounds.html)). The default behavior of howler.js is to attempt to silently unlock audio playback by playing an empty buffer on the first `touchend` event. This behavior can be disabled by calling:
+
+```javascript
+Howler.autoUnlock = false;
+```
+
+If you try to play audio automatically on page load, you can listen to a `playerror` event and then wait for the `unlock` event to try and play the audio again:
+
+```javascript
+var sound = new Howl({
+ src: ['sound.webm', 'sound.mp3'],
+ onplayerror: function() {
+ sound.once('unlock', function() {
+ sound.play();
+ });
+ }
+});
+
+sound.play();
+```
+
+
+### Dolby Audio Playback
+Full support for playback of the Dolby Audio format (currently support in Edge and Safari) is included. However, you must specify that the file you are loading is `dolby` since it is in a `mp4` container.
+
+```javascript
+var dolbySound = new Howl({
+ src: ['sound.mp4', 'sound.webm', 'sound.mp3'],
+ format: ['dolby', 'webm', 'mp3']
+});
+```
+
+### Facebook Instant Games
+Howler.js provides audio support for the new [Facebook Instant Games](https://developers.facebook.com/docs/games/instant-games/engine-recommendations) platform. If you encounter any issues while developing for Instant Games, open an issue with the tag `[IG]`.
+
+### Format Recommendations
+Howler.js supports a wide array of audio codecs that have varying browser support ("mp3", "opus", "ogg", "wav", "aac", "m4a", "m4b", "mp4", "webm", ...), but if you want full browser coverage you still need to use at least two of them. If your goal is to have the best balance of small filesize and high quality, based on extensive production testing, your best bet is to default to `webm` and fallback to `mp3`. `webm` has nearly full browser coverage with a great combination of compression and quality. You'll need the `mp3` fallback for Internet Explorer.
+
+It is important to remember that howler.js selects the first compatible sound from your array of sources. So if you want `webm` to be used before `mp3`, you need to put the sources in that order.
+
+If you want your `webm` files to be seekable in Firefox, be sure to encode them with the cues element. One way to do this is by using the `dash` flag in [ffmpeg](https://www.ffmpeg.org/):
+
+```
+ffmpeg -i sound1.wav -dash 1 sound1.webm
+```
+
+### Sponsors
+Support the ongoing development of howler.js and get your logo on our README with a link to your site [[become a sponsor](https://github.com/sponsors/goldfire)]. You can also become a backer at a lower tier and get your name in the [BACKERS](https://github.com/goldfire/howler.js/blob/master/BACKERS.md) list. All support is greatly appreciated!
+
+[](https://goldfirestudios.com)
+
+### License
+
+Copyright (c) 2013-2021 [James Simpson](https://twitter.com/GoldFireStudios) and [GoldFire Studios, Inc.](http://goldfirestudios.com)
+
+Released under the [MIT License](https://github.com/goldfire/howler.js/blob/master/LICENSE.md).
diff --git a/uni_modules/c-svga/node_modules/howler/dist/howler.core.min.js b/uni_modules/c-svga/node_modules/howler/dist/howler.core.min.js
new file mode 100644
index 0000000..3901ac4
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/howler/dist/howler.core.min.js
@@ -0,0 +1,2 @@
+/*! howler.js v2.2.4 | (c) 2013-2020, James Simpson of GoldFire Studios | MIT License | howlerjs.com */
+!function(){"use strict";var e=function(){this.init()};e.prototype={init:function(){var e=this||n;return e._counter=1e3,e._html5AudioPool=[],e.html5PoolSize=10,e._codecs={},e._howls=[],e._muted=!1,e._volume=1,e._canPlayEvent="canplaythrough",e._navigator="undefined"!=typeof window&&window.navigator?window.navigator:null,e.masterGain=null,e.noAudio=!1,e.usingWebAudio=!0,e.autoSuspend=!0,e.ctx=null,e.autoUnlock=!0,e._setup(),e},volume:function(e){var o=this||n;if(e=parseFloat(e),o.ctx||_(),void 0!==e&&e>=0&&e<=1){if(o._volume=e,o._muted)return o;o.usingWebAudio&&o.masterGain.gain.setValueAtTime(e,n.ctx.currentTime);for(var t=0;t=0;o--)e._howls[o].unload();return e.usingWebAudio&&e.ctx&&void 0!==e.ctx.close&&(e.ctx.close(),e.ctx=null,_()),e},codecs:function(e){return(this||n)._codecs[e.replace(/^x-/,"")]},_setup:function(){var e=this||n;if(e.state=e.ctx?e.ctx.state||"suspended":"suspended",e._autoSuspend(),!e.usingWebAudio)if("undefined"!=typeof Audio)try{var o=new Audio;void 0===o.oncanplaythrough&&(e._canPlayEvent="canplay")}catch(n){e.noAudio=!0}else e.noAudio=!0;try{var o=new Audio;o.muted&&(e.noAudio=!0)}catch(e){}return e.noAudio||e._setupCodecs(),e},_setupCodecs:function(){var e=this||n,o=null;try{o="undefined"!=typeof Audio?new Audio:null}catch(n){return e}if(!o||"function"!=typeof o.canPlayType)return e;var t=o.canPlayType("audio/mpeg;").replace(/^no$/,""),r=e._navigator?e._navigator.userAgent:"",a=r.match(/OPR\/(\d+)/g),u=a&&parseInt(a[0].split("/")[1],10)<33,d=-1!==r.indexOf("Safari")&&-1===r.indexOf("Chrome"),i=r.match(/Version\/(.*?) /),_=d&&i&&parseInt(i[1],10)<15;return e._codecs={mp3:!(u||!t&&!o.canPlayType("audio/mp3;").replace(/^no$/,"")),mpeg:!!t,opus:!!o.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/,""),ogg:!!o.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),oga:!!o.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),wav:!!(o.canPlayType('audio/wav; codecs="1"')||o.canPlayType("audio/wav")).replace(/^no$/,""),aac:!!o.canPlayType("audio/aac;").replace(/^no$/,""),caf:!!o.canPlayType("audio/x-caf;").replace(/^no$/,""),m4a:!!(o.canPlayType("audio/x-m4a;")||o.canPlayType("audio/m4a;")||o.canPlayType("audio/aac;")).replace(/^no$/,""),m4b:!!(o.canPlayType("audio/x-m4b;")||o.canPlayType("audio/m4b;")||o.canPlayType("audio/aac;")).replace(/^no$/,""),mp4:!!(o.canPlayType("audio/x-mp4;")||o.canPlayType("audio/mp4;")||o.canPlayType("audio/aac;")).replace(/^no$/,""),weba:!(_||!o.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/,"")),webm:!(_||!o.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/,"")),dolby:!!o.canPlayType('audio/mp4; codecs="ec-3"').replace(/^no$/,""),flac:!!(o.canPlayType("audio/x-flac;")||o.canPlayType("audio/flac;")).replace(/^no$/,"")},e},_unlockAudio:function(){var e=this||n;if(!e._audioUnlocked&&e.ctx){e._audioUnlocked=!1,e.autoUnlock=!1,e._mobileUnloaded||44100===e.ctx.sampleRate||(e._mobileUnloaded=!0,e.unload()),e._scratchBuffer=e.ctx.createBuffer(1,1,22050);var o=function(n){for(;e._html5AudioPool.length0?d._seek:t._sprite[e][0]/1e3),s=Math.max(0,(t._sprite[e][0]+t._sprite[e][1])/1e3-_),l=1e3*s/Math.abs(d._rate),c=t._sprite[e][0]/1e3,f=(t._sprite[e][0]+t._sprite[e][1])/1e3;d._sprite=e,d._ended=!1;var p=function(){d._paused=!1,d._seek=_,d._start=c,d._stop=f,d._loop=!(!d._loop&&!t._sprite[e][2])};if(_>=f)return void t._ended(d);var m=d._node;if(t._webAudio){var v=function(){t._playLock=!1,p(),t._refreshBuffer(d);var e=d._muted||t._muted?0:d._volume;m.gain.setValueAtTime(e,n.ctx.currentTime),d._playStart=n.ctx.currentTime,void 0===m.bufferSource.start?d._loop?m.bufferSource.noteGrainOn(0,_,86400):m.bufferSource.noteGrainOn(0,_,s):d._loop?m.bufferSource.start(0,_,86400):m.bufferSource.start(0,_,s),l!==1/0&&(t._endTimers[d._id]=setTimeout(t._ended.bind(t,d),l)),o||setTimeout(function(){t._emit("play",d._id),t._loadQueue()},0)};"running"===n.state&&"interrupted"!==n.ctx.state?v():(t._playLock=!0,t.once("resume",v),t._clearTimer(d._id))}else{var h=function(){m.currentTime=_,m.muted=d._muted||t._muted||n._muted||m.muted,m.volume=d._volume*n.volume(),m.playbackRate=d._rate;try{var r=m.play();if(r&&"undefined"!=typeof Promise&&(r instanceof Promise||"function"==typeof r.then)?(t._playLock=!0,p(),r.then(function(){t._playLock=!1,m._unlocked=!0,o?t._loadQueue():t._emit("play",d._id)}).catch(function(){t._playLock=!1,t._emit("playerror",d._id,"Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction."),d._ended=!0,d._paused=!0})):o||(t._playLock=!1,p(),t._emit("play",d._id)),m.playbackRate=d._rate,m.paused)return void t._emit("playerror",d._id,"Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction.");"__default"!==e||d._loop?t._endTimers[d._id]=setTimeout(t._ended.bind(t,d),l):(t._endTimers[d._id]=function(){t._ended(d),m.removeEventListener("ended",t._endTimers[d._id],!1)},m.addEventListener("ended",t._endTimers[d._id],!1))}catch(e){t._emit("playerror",d._id,e)}};"data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA"===m.src&&(m.src=t._src,m.load());var y=window&&window.ejecta||!m.readyState&&n._navigator.isCocoonJS;if(m.readyState>=3||y)h();else{t._playLock=!0,t._state="loading";var g=function(){t._state="loaded",h(),m.removeEventListener(n._canPlayEvent,g,!1)};m.addEventListener(n._canPlayEvent,g,!1),t._clearTimer(d._id)}}return d._id},pause:function(e){var n=this;if("loaded"!==n._state||n._playLock)return n._queue.push({event:"pause",action:function(){n.pause(e)}}),n;for(var o=n._getSoundIds(e),t=0;t=0?o=parseInt(r[0],10):e=parseFloat(r[0])}else r.length>=2&&(e=parseFloat(r[0]),o=parseInt(r[1],10));var a;if(!(void 0!==e&&e>=0&&e<=1))return a=o?t._soundById(o):t._sounds[0],a?a._volume:0;if("loaded"!==t._state||t._playLock)return t._queue.push({event:"volume",action:function(){t.volume.apply(t,r)}}),t;void 0===o&&(t._volume=e),o=t._getSoundIds(o);for(var u=0;u0?t/_:t),l=Date.now();e._fadeTo=o,e._interval=setInterval(function(){var r=(Date.now()-l)/t;l=Date.now(),d+=i*r,d=Math.round(100*d)/100,d=i<0?Math.max(o,d):Math.min(o,d),u._webAudio?e._volume=d:u.volume(d,e._id,!0),a&&(u._volume=d),(on&&d>=o)&&(clearInterval(e._interval),e._interval=null,e._fadeTo=null,u.volume(o,e._id),u._emit("fade",e._id))},s)},_stopFade:function(e){var o=this,t=o._soundById(e);return t&&t._interval&&(o._webAudio&&t._node.gain.cancelScheduledValues(n.ctx.currentTime),clearInterval(t._interval),t._interval=null,o.volume(t._fadeTo,e),t._fadeTo=null,o._emit("fade",e)),o},loop:function(){var e,n,o,t=this,r=arguments;if(0===r.length)return t._loop;if(1===r.length){if("boolean"!=typeof r[0])return!!(o=t._soundById(parseInt(r[0],10)))&&o._loop;e=r[0],t._loop=e}else 2===r.length&&(e=r[0],n=parseInt(r[1],10));for(var a=t._getSoundIds(n),u=0;u=0?o=parseInt(r[0],10):e=parseFloat(r[0])}else 2===r.length&&(e=parseFloat(r[0]),o=parseInt(r[1],10));var d;if("number"!=typeof e)return d=t._soundById(o),d?d._rate:t._rate;if("loaded"!==t._state||t._playLock)return t._queue.push({event:"rate",action:function(){t.rate.apply(t,r)}}),t;void 0===o&&(t._rate=e),o=t._getSoundIds(o);for(var i=0;i=0?o=parseInt(r[0],10):t._sounds.length&&(o=t._sounds[0]._id,e=parseFloat(r[0]))}else 2===r.length&&(e=parseFloat(r[0]),o=parseInt(r[1],10));if(void 0===o)return 0;if("number"==typeof e&&("loaded"!==t._state||t._playLock))return t._queue.push({event:"seek",action:function(){t.seek.apply(t,r)}}),t;var d=t._soundById(o);if(d){if(!("number"==typeof e&&e>=0)){if(t._webAudio){var i=t.playing(o)?n.ctx.currentTime-d._playStart:0,_=d._rateSeek?d._rateSeek-d._seek:0;return d._seek+(_+i*Math.abs(d._rate))}return d._node.currentTime}var s=t.playing(o);s&&t.pause(o,!0),d._seek=e,d._ended=!1,t._clearTimer(o),t._webAudio||!d._node||isNaN(d._node.duration)||(d._node.currentTime=e);var l=function(){s&&t.play(o,!0),t._emit("seek",o)};if(s&&!t._webAudio){var c=function(){t._playLock?setTimeout(c,0):l()};setTimeout(c,0)}else l()}return t},playing:function(e){var n=this;if("number"==typeof e){var o=n._soundById(e);return!!o&&!o._paused}for(var t=0;t=0&&n._howls.splice(a,1);var u=!0;for(t=0;t=0){u=!1;break}return r&&u&&delete r[e._src],n.noAudio=!1,e._state="unloaded",e._sounds=[],e=null,null},on:function(e,n,o,t){var r=this,a=r["_on"+e];return"function"==typeof n&&a.push(t?{id:o,fn:n,once:t}:{id:o,fn:n}),r},off:function(e,n,o){var t=this,r=t["_on"+e],a=0;if("number"==typeof n&&(o=n,n=null),n||o)for(a=0;a=0;a--)r[a].id&&r[a].id!==n&&"load"!==e||(setTimeout(function(e){e.call(this,n,o)}.bind(t,r[a].fn),0),r[a].once&&t.off(e,r[a].fn,r[a].id));return t._loadQueue(e),t},_loadQueue:function(e){var n=this;if(n._queue.length>0){var o=n._queue[0];o.event===e&&(n._queue.shift(),n._loadQueue()),e||o.action()}return n},_ended:function(e){var o=this,t=e._sprite;if(!o._webAudio&&e._node&&!e._node.paused&&!e._node.ended&&e._node.currentTime=0;t--){if(o<=n)return;e._sounds[t]._ended&&(e._webAudio&&e._sounds[t]._node&&e._sounds[t]._node.disconnect(0),e._sounds.splice(t,1),o--)}}},_getSoundIds:function(e){var n=this;if(void 0===e){for(var o=[],t=0;t=0;if(!e.bufferSource)return o;if(n._scratchBuffer&&e.bufferSource&&(e.bufferSource.onended=null,e.bufferSource.disconnect(0),t))try{e.bufferSource.buffer=n._scratchBuffer}catch(e){}return e.bufferSource=null,o},_clearSound:function(e){/MSIE |Trident\//.test(n._navigator&&n._navigator.userAgent)||(e.src="data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA")}};var t=function(e){this._parent=e,this.init()};t.prototype={init:function(){var e=this,o=e._parent;return e._muted=o._muted,e._loop=o._loop,e._volume=o._volume,e._rate=o._rate,e._seek=0,e._paused=!0,e._ended=!0,e._sprite="__default",e._id=++n._counter,o._sounds.push(e),e.create(),e},create:function(){var e=this,o=e._parent,t=n._muted||e._muted||e._parent._muted?0:e._volume;return o._webAudio?(e._node=void 0===n.ctx.createGain?n.ctx.createGainNode():n.ctx.createGain(),e._node.gain.setValueAtTime(t,n.ctx.currentTime),e._node.paused=!0,e._node.connect(n.masterGain)):n.noAudio||(e._node=n._obtainHtml5Audio(),e._errorFn=e._errorListener.bind(e),e._node.addEventListener("error",e._errorFn,!1),e._loadFn=e._loadListener.bind(e),e._node.addEventListener(n._canPlayEvent,e._loadFn,!1),e._endFn=e._endListener.bind(e),e._node.addEventListener("ended",e._endFn,!1),e._node.src=o._src,e._node.preload=!0===o._preload?"auto":o._preload,e._node.volume=t*n.volume(),e._node.load()),e},reset:function(){var e=this,o=e._parent;return e._muted=o._muted,e._loop=o._loop,e._volume=o._volume,e._rate=o._rate,e._seek=0,e._rateSeek=0,e._paused=!0,e._ended=!0,e._sprite="__default",e._id=++n._counter,e},_errorListener:function(){var e=this;e._parent._emit("loaderror",e._id,e._node.error?e._node.error.code:0),e._node.removeEventListener("error",e._errorFn,!1)},_loadListener:function(){var e=this,o=e._parent;o._duration=Math.ceil(10*e._node.duration)/10,0===Object.keys(o._sprite).length&&(o._sprite={__default:[0,1e3*o._duration]}),"loaded"!==o._state&&(o._state="loaded",o._emit("load"),o._loadQueue()),e._node.removeEventListener(n._canPlayEvent,e._loadFn,!1)},_endListener:function(){var e=this,n=e._parent;n._duration===1/0&&(n._duration=Math.ceil(10*e._node.duration)/10,n._sprite.__default[1]===1/0&&(n._sprite.__default[1]=1e3*n._duration),n._ended(e)),e._node.removeEventListener("ended",e._endFn,!1)}};var r={},a=function(e){var n=e._src;if(r[n])return e._duration=r[n].duration,void i(e);if(/^data:[^;]+;base64,/.test(n)){for(var o=atob(n.split(",")[1]),t=new Uint8Array(o.length),a=0;a0?(r[o._src]=e,i(o,e)):t()};"undefined"!=typeof Promise&&1===n.ctx.decodeAudioData.length?n.ctx.decodeAudioData(e).then(a).catch(t):n.ctx.decodeAudioData(e,a,t)},i=function(e,n){n&&!e._duration&&(e._duration=n.duration),0===Object.keys(e._sprite).length&&(e._sprite={__default:[0,1e3*e._duration]}),"loaded"!==e._state&&(e._state="loaded",e._emit("load"),e._loadQueue())},_=function(){if(n.usingWebAudio){try{"undefined"!=typeof AudioContext?n.ctx=new AudioContext:"undefined"!=typeof webkitAudioContext?n.ctx=new webkitAudioContext:n.usingWebAudio=!1}catch(e){n.usingWebAudio=!1}n.ctx||(n.usingWebAudio=!1);var e=/iP(hone|od|ad)/.test(n._navigator&&n._navigator.platform),o=n._navigator&&n._navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/),t=o?parseInt(o[1],10):null;if(e&&t&&t<9){var r=/safari/.test(n._navigator&&n._navigator.userAgent.toLowerCase());n._navigator&&!r&&(n.usingWebAudio=!1)}n.usingWebAudio&&(n.masterGain=void 0===n.ctx.createGain?n.ctx.createGainNode():n.ctx.createGain(),n.masterGain.gain.setValueAtTime(n._muted?0:n._volume,n.ctx.currentTime),n.masterGain.connect(n.ctx.destination)),n._setup()}};"function"==typeof define&&define.amd&&define([],function(){return{Howler:n,Howl:o}}),"undefined"!=typeof exports&&(exports.Howler=n,exports.Howl=o),"undefined"!=typeof global?(global.HowlerGlobal=e,global.Howler=n,global.Howl=o,global.Sound=t):"undefined"!=typeof window&&(window.HowlerGlobal=e,window.Howler=n,window.Howl=o,window.Sound=t)}();
\ No newline at end of file
diff --git a/uni_modules/c-svga/node_modules/howler/dist/howler.js b/uni_modules/c-svga/node_modules/howler/dist/howler.js
new file mode 100644
index 0000000..bb5a463
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/howler/dist/howler.js
@@ -0,0 +1,3248 @@
+/*!
+ * howler.js v2.2.4
+ * howlerjs.com
+ *
+ * (c) 2013-2020, James Simpson of GoldFire Studios
+ * goldfirestudios.com
+ *
+ * MIT License
+ */
+
+(function() {
+
+ 'use strict';
+
+ /** Global Methods **/
+ /***************************************************************************/
+
+ /**
+ * Create the global controller. All contained methods and properties apply
+ * to all sounds that are currently playing or will be in the future.
+ */
+ var HowlerGlobal = function() {
+ this.init();
+ };
+ HowlerGlobal.prototype = {
+ /**
+ * Initialize the global Howler object.
+ * @return {Howler}
+ */
+ init: function() {
+ var self = this || Howler;
+
+ // Create a global ID counter.
+ self._counter = 1000;
+
+ // Pool of unlocked HTML5 Audio objects.
+ self._html5AudioPool = [];
+ self.html5PoolSize = 10;
+
+ // Internal properties.
+ self._codecs = {};
+ self._howls = [];
+ self._muted = false;
+ self._volume = 1;
+ self._canPlayEvent = 'canplaythrough';
+ self._navigator = (typeof window !== 'undefined' && window.navigator) ? window.navigator : null;
+
+ // Public properties.
+ self.masterGain = null;
+ self.noAudio = false;
+ self.usingWebAudio = true;
+ self.autoSuspend = true;
+ self.ctx = null;
+
+ // Set to false to disable the auto audio unlocker.
+ self.autoUnlock = true;
+
+ // Setup the various state values for global tracking.
+ self._setup();
+
+ return self;
+ },
+
+ /**
+ * Get/set the global volume for all sounds.
+ * @param {Float} vol Volume from 0.0 to 1.0.
+ * @return {Howler/Float} Returns self or current volume.
+ */
+ volume: function(vol) {
+ var self = this || Howler;
+ vol = parseFloat(vol);
+
+ // If we don't have an AudioContext created yet, run the setup.
+ if (!self.ctx) {
+ setupAudioContext();
+ }
+
+ if (typeof vol !== 'undefined' && vol >= 0 && vol <= 1) {
+ self._volume = vol;
+
+ // Don't update any of the nodes if we are muted.
+ if (self._muted) {
+ return self;
+ }
+
+ // When using Web Audio, we just need to adjust the master gain.
+ if (self.usingWebAudio) {
+ self.masterGain.gain.setValueAtTime(vol, Howler.ctx.currentTime);
+ }
+
+ // Loop through and change volume for all HTML5 audio nodes.
+ for (var i=0; i=0; i--) {
+ self._howls[i].unload();
+ }
+
+ // Create a new AudioContext to make sure it is fully reset.
+ if (self.usingWebAudio && self.ctx && typeof self.ctx.close !== 'undefined') {
+ self.ctx.close();
+ self.ctx = null;
+ setupAudioContext();
+ }
+
+ return self;
+ },
+
+ /**
+ * Check for codec support of specific extension.
+ * @param {String} ext Audio file extention.
+ * @return {Boolean}
+ */
+ codecs: function(ext) {
+ return (this || Howler)._codecs[ext.replace(/^x-/, '')];
+ },
+
+ /**
+ * Setup various state values for global tracking.
+ * @return {Howler}
+ */
+ _setup: function() {
+ var self = this || Howler;
+
+ // Keeps track of the suspend/resume state of the AudioContext.
+ self.state = self.ctx ? self.ctx.state || 'suspended' : 'suspended';
+
+ // Automatically begin the 30-second suspend process
+ self._autoSuspend();
+
+ // Check if audio is available.
+ if (!self.usingWebAudio) {
+ // No audio is available on this system if noAudio is set to true.
+ if (typeof Audio !== 'undefined') {
+ try {
+ var test = new Audio();
+
+ // Check if the canplaythrough event is available.
+ if (typeof test.oncanplaythrough === 'undefined') {
+ self._canPlayEvent = 'canplay';
+ }
+ } catch(e) {
+ self.noAudio = true;
+ }
+ } else {
+ self.noAudio = true;
+ }
+ }
+
+ // Test to make sure audio isn't disabled in Internet Explorer.
+ try {
+ var test = new Audio();
+ if (test.muted) {
+ self.noAudio = true;
+ }
+ } catch (e) {}
+
+ // Check for supported codecs.
+ if (!self.noAudio) {
+ self._setupCodecs();
+ }
+
+ return self;
+ },
+
+ /**
+ * Check for browser support for various codecs and cache the results.
+ * @return {Howler}
+ */
+ _setupCodecs: function() {
+ var self = this || Howler;
+ var audioTest = null;
+
+ // Must wrap in a try/catch because IE11 in server mode throws an error.
+ try {
+ audioTest = (typeof Audio !== 'undefined') ? new Audio() : null;
+ } catch (err) {
+ return self;
+ }
+
+ if (!audioTest || typeof audioTest.canPlayType !== 'function') {
+ return self;
+ }
+
+ var mpegTest = audioTest.canPlayType('audio/mpeg;').replace(/^no$/, '');
+
+ // Opera version <33 has mixed MP3 support, so we need to check for and block it.
+ var ua = self._navigator ? self._navigator.userAgent : '';
+ var checkOpera = ua.match(/OPR\/(\d+)/g);
+ var isOldOpera = (checkOpera && parseInt(checkOpera[0].split('/')[1], 10) < 33);
+ var checkSafari = ua.indexOf('Safari') !== -1 && ua.indexOf('Chrome') === -1;
+ var safariVersion = ua.match(/Version\/(.*?) /);
+ var isOldSafari = (checkSafari && safariVersion && parseInt(safariVersion[1], 10) < 15);
+
+ self._codecs = {
+ mp3: !!(!isOldOpera && (mpegTest || audioTest.canPlayType('audio/mp3;').replace(/^no$/, ''))),
+ mpeg: !!mpegTest,
+ opus: !!audioTest.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/, ''),
+ ogg: !!audioTest.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ''),
+ oga: !!audioTest.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ''),
+ wav: !!(audioTest.canPlayType('audio/wav; codecs="1"') || audioTest.canPlayType('audio/wav')).replace(/^no$/, ''),
+ aac: !!audioTest.canPlayType('audio/aac;').replace(/^no$/, ''),
+ caf: !!audioTest.canPlayType('audio/x-caf;').replace(/^no$/, ''),
+ m4a: !!(audioTest.canPlayType('audio/x-m4a;') || audioTest.canPlayType('audio/m4a;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),
+ m4b: !!(audioTest.canPlayType('audio/x-m4b;') || audioTest.canPlayType('audio/m4b;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),
+ mp4: !!(audioTest.canPlayType('audio/x-mp4;') || audioTest.canPlayType('audio/mp4;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),
+ weba: !!(!isOldSafari && audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, '')),
+ webm: !!(!isOldSafari && audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, '')),
+ dolby: !!audioTest.canPlayType('audio/mp4; codecs="ec-3"').replace(/^no$/, ''),
+ flac: !!(audioTest.canPlayType('audio/x-flac;') || audioTest.canPlayType('audio/flac;')).replace(/^no$/, '')
+ };
+
+ return self;
+ },
+
+ /**
+ * Some browsers/devices will only allow audio to be played after a user interaction.
+ * Attempt to automatically unlock audio on the first user interaction.
+ * Concept from: http://paulbakaus.com/tutorials/html5/web-audio-on-ios/
+ * @return {Howler}
+ */
+ _unlockAudio: function() {
+ var self = this || Howler;
+
+ // Only run this if Web Audio is supported and it hasn't already been unlocked.
+ if (self._audioUnlocked || !self.ctx) {
+ return;
+ }
+
+ self._audioUnlocked = false;
+ self.autoUnlock = false;
+
+ // Some mobile devices/platforms have distortion issues when opening/closing tabs and/or web views.
+ // Bugs in the browser (especially Mobile Safari) can cause the sampleRate to change from 44100 to 48000.
+ // By calling Howler.unload(), we create a new AudioContext with the correct sampleRate.
+ if (!self._mobileUnloaded && self.ctx.sampleRate !== 44100) {
+ self._mobileUnloaded = true;
+ self.unload();
+ }
+
+ // Scratch buffer for enabling iOS to dispose of web audio buffers correctly, as per:
+ // http://stackoverflow.com/questions/24119684
+ self._scratchBuffer = self.ctx.createBuffer(1, 1, 22050);
+
+ // Call this method on touch start to create and play a buffer,
+ // then check if the audio actually played to determine if
+ // audio has now been unlocked on iOS, Android, etc.
+ var unlock = function(e) {
+ // Create a pool of unlocked HTML5 Audio objects that can
+ // be used for playing sounds without user interaction. HTML5
+ // Audio objects must be individually unlocked, as opposed
+ // to the WebAudio API which only needs a single activation.
+ // This must occur before WebAudio setup or the source.onended
+ // event will not fire.
+ while (self._html5AudioPool.length < self.html5PoolSize) {
+ try {
+ var audioNode = new Audio();
+
+ // Mark this Audio object as unlocked to ensure it can get returned
+ // to the unlocked pool when released.
+ audioNode._unlocked = true;
+
+ // Add the audio node to the pool.
+ self._releaseHtml5Audio(audioNode);
+ } catch (e) {
+ self.noAudio = true;
+ break;
+ }
+ }
+
+ // Loop through any assigned audio nodes and unlock them.
+ for (var i=0; i= 55.
+ if (typeof self.ctx.resume === 'function') {
+ self.ctx.resume();
+ }
+
+ // Setup a timeout to check that we are unlocked on the next event loop.
+ source.onended = function() {
+ source.disconnect(0);
+
+ // Update the unlocked state and prevent this check from happening again.
+ self._audioUnlocked = true;
+
+ // Remove the touch start listener.
+ document.removeEventListener('touchstart', unlock, true);
+ document.removeEventListener('touchend', unlock, true);
+ document.removeEventListener('click', unlock, true);
+ document.removeEventListener('keydown', unlock, true);
+
+ // Let all sounds know that audio has been unlocked.
+ for (var i=0; i 0 ? sound._seek : self._sprite[sprite][0] / 1000);
+ var duration = Math.max(0, ((self._sprite[sprite][0] + self._sprite[sprite][1]) / 1000) - seek);
+ var timeout = (duration * 1000) / Math.abs(sound._rate);
+ var start = self._sprite[sprite][0] / 1000;
+ var stop = (self._sprite[sprite][0] + self._sprite[sprite][1]) / 1000;
+ sound._sprite = sprite;
+
+ // Mark the sound as ended instantly so that this async playback
+ // doesn't get grabbed by another call to play while this one waits to start.
+ sound._ended = false;
+
+ // Update the parameters of the sound.
+ var setParams = function() {
+ sound._paused = false;
+ sound._seek = seek;
+ sound._start = start;
+ sound._stop = stop;
+ sound._loop = !!(sound._loop || self._sprite[sprite][2]);
+ };
+
+ // End the sound instantly if seek is at the end.
+ if (seek >= stop) {
+ self._ended(sound);
+ return;
+ }
+
+ // Begin the actual playback.
+ var node = sound._node;
+ if (self._webAudio) {
+ // Fire this when the sound is ready to play to begin Web Audio playback.
+ var playWebAudio = function() {
+ self._playLock = false;
+ setParams();
+ self._refreshBuffer(sound);
+
+ // Setup the playback params.
+ var vol = (sound._muted || self._muted) ? 0 : sound._volume;
+ node.gain.setValueAtTime(vol, Howler.ctx.currentTime);
+ sound._playStart = Howler.ctx.currentTime;
+
+ // Play the sound using the supported method.
+ if (typeof node.bufferSource.start === 'undefined') {
+ sound._loop ? node.bufferSource.noteGrainOn(0, seek, 86400) : node.bufferSource.noteGrainOn(0, seek, duration);
+ } else {
+ sound._loop ? node.bufferSource.start(0, seek, 86400) : node.bufferSource.start(0, seek, duration);
+ }
+
+ // Start a new timer if none is present.
+ if (timeout !== Infinity) {
+ self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);
+ }
+
+ if (!internal) {
+ setTimeout(function() {
+ self._emit('play', sound._id);
+ self._loadQueue();
+ }, 0);
+ }
+ };
+
+ if (Howler.state === 'running' && Howler.ctx.state !== 'interrupted') {
+ playWebAudio();
+ } else {
+ self._playLock = true;
+
+ // Wait for the audio context to resume before playing.
+ self.once('resume', playWebAudio);
+
+ // Cancel the end timer.
+ self._clearTimer(sound._id);
+ }
+ } else {
+ // Fire this when the sound is ready to play to begin HTML5 Audio playback.
+ var playHtml5 = function() {
+ node.currentTime = seek;
+ node.muted = sound._muted || self._muted || Howler._muted || node.muted;
+ node.volume = sound._volume * Howler.volume();
+ node.playbackRate = sound._rate;
+
+ // Some browsers will throw an error if this is called without user interaction.
+ try {
+ var play = node.play();
+
+ // Support older browsers that don't support promises, and thus don't have this issue.
+ if (play && typeof Promise !== 'undefined' && (play instanceof Promise || typeof play.then === 'function')) {
+ // Implements a lock to prevent DOMException: The play() request was interrupted by a call to pause().
+ self._playLock = true;
+
+ // Set param values immediately.
+ setParams();
+
+ // Releases the lock and executes queued actions.
+ play
+ .then(function() {
+ self._playLock = false;
+ node._unlocked = true;
+ if (!internal) {
+ self._emit('play', sound._id);
+ } else {
+ self._loadQueue();
+ }
+ })
+ .catch(function() {
+ self._playLock = false;
+ self._emit('playerror', sound._id, 'Playback was unable to start. This is most commonly an issue ' +
+ 'on mobile devices and Chrome where playback was not within a user interaction.');
+
+ // Reset the ended and paused values.
+ sound._ended = true;
+ sound._paused = true;
+ });
+ } else if (!internal) {
+ self._playLock = false;
+ setParams();
+ self._emit('play', sound._id);
+ }
+
+ // Setting rate before playing won't work in IE, so we set it again here.
+ node.playbackRate = sound._rate;
+
+ // If the node is still paused, then we can assume there was a playback issue.
+ if (node.paused) {
+ self._emit('playerror', sound._id, 'Playback was unable to start. This is most commonly an issue ' +
+ 'on mobile devices and Chrome where playback was not within a user interaction.');
+ return;
+ }
+
+ // Setup the end timer on sprites or listen for the ended event.
+ if (sprite !== '__default' || sound._loop) {
+ self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);
+ } else {
+ self._endTimers[sound._id] = function() {
+ // Fire ended on this audio node.
+ self._ended(sound);
+
+ // Clear this listener.
+ node.removeEventListener('ended', self._endTimers[sound._id], false);
+ };
+ node.addEventListener('ended', self._endTimers[sound._id], false);
+ }
+ } catch (err) {
+ self._emit('playerror', sound._id, err);
+ }
+ };
+
+ // If this is streaming audio, make sure the src is set and load again.
+ if (node.src === 'data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA') {
+ node.src = self._src;
+ node.load();
+ }
+
+ // Play immediately if ready, or wait for the 'canplaythrough'e vent.
+ var loadedNoReadyState = (window && window.ejecta) || (!node.readyState && Howler._navigator.isCocoonJS);
+ if (node.readyState >= 3 || loadedNoReadyState) {
+ playHtml5();
+ } else {
+ self._playLock = true;
+ self._state = 'loading';
+
+ var listener = function() {
+ self._state = 'loaded';
+
+ // Begin playback.
+ playHtml5();
+
+ // Clear this listener.
+ node.removeEventListener(Howler._canPlayEvent, listener, false);
+ };
+ node.addEventListener(Howler._canPlayEvent, listener, false);
+
+ // Cancel the end timer.
+ self._clearTimer(sound._id);
+ }
+ }
+
+ return sound._id;
+ },
+
+ /**
+ * Pause playback and save current position.
+ * @param {Number} id The sound ID (empty to pause all in group).
+ * @return {Howl}
+ */
+ pause: function(id) {
+ var self = this;
+
+ // If the sound hasn't loaded or a play() promise is pending, add it to the load queue to pause when capable.
+ if (self._state !== 'loaded' || self._playLock) {
+ self._queue.push({
+ event: 'pause',
+ action: function() {
+ self.pause(id);
+ }
+ });
+
+ return self;
+ }
+
+ // If no id is passed, get all ID's to be paused.
+ var ids = self._getSoundIds(id);
+
+ for (var i=0; i Returns the group's volume value.
+ * volume(id) -> Returns the sound id's current volume.
+ * volume(vol) -> Sets the volume of all sounds in this Howl group.
+ * volume(vol, id) -> Sets the volume of passed sound id.
+ * @return {Howl/Number} Returns self or current volume.
+ */
+ volume: function() {
+ var self = this;
+ var args = arguments;
+ var vol, id;
+
+ // Determine the values based on arguments.
+ if (args.length === 0) {
+ // Return the value of the groups' volume.
+ return self._volume;
+ } else if (args.length === 1 || args.length === 2 && typeof args[1] === 'undefined') {
+ // First check if this is an ID, and if not, assume it is a new volume.
+ var ids = self._getSoundIds();
+ var index = ids.indexOf(args[0]);
+ if (index >= 0) {
+ id = parseInt(args[0], 10);
+ } else {
+ vol = parseFloat(args[0]);
+ }
+ } else if (args.length >= 2) {
+ vol = parseFloat(args[0]);
+ id = parseInt(args[1], 10);
+ }
+
+ // Update the volume or return the current volume.
+ var sound;
+ if (typeof vol !== 'undefined' && vol >= 0 && vol <= 1) {
+ // If the sound hasn't loaded, add it to the load queue to change volume when capable.
+ if (self._state !== 'loaded'|| self._playLock) {
+ self._queue.push({
+ event: 'volume',
+ action: function() {
+ self.volume.apply(self, args);
+ }
+ });
+
+ return self;
+ }
+
+ // Set the group volume.
+ if (typeof id === 'undefined') {
+ self._volume = vol;
+ }
+
+ // Update one or all volumes.
+ id = self._getSoundIds(id);
+ for (var i=0; i 0) ? len / steps : len);
+ var lastTick = Date.now();
+
+ // Store the value being faded to.
+ sound._fadeTo = to;
+
+ // Update the volume value on each interval tick.
+ sound._interval = setInterval(function() {
+ // Update the volume based on the time since the last tick.
+ var tick = (Date.now() - lastTick) / len;
+ lastTick = Date.now();
+ vol += diff * tick;
+
+ // Round to within 2 decimal points.
+ vol = Math.round(vol * 100) / 100;
+
+ // Make sure the volume is in the right bounds.
+ if (diff < 0) {
+ vol = Math.max(to, vol);
+ } else {
+ vol = Math.min(to, vol);
+ }
+
+ // Change the volume.
+ if (self._webAudio) {
+ sound._volume = vol;
+ } else {
+ self.volume(vol, sound._id, true);
+ }
+
+ // Set the group's volume.
+ if (isGroup) {
+ self._volume = vol;
+ }
+
+ // When the fade is complete, stop it and fire event.
+ if ((to < from && vol <= to) || (to > from && vol >= to)) {
+ clearInterval(sound._interval);
+ sound._interval = null;
+ sound._fadeTo = null;
+ self.volume(to, sound._id);
+ self._emit('fade', sound._id);
+ }
+ }, stepLen);
+ },
+
+ /**
+ * Internal method that stops the currently playing fade when
+ * a new fade starts, volume is changed or the sound is stopped.
+ * @param {Number} id The sound id.
+ * @return {Howl}
+ */
+ _stopFade: function(id) {
+ var self = this;
+ var sound = self._soundById(id);
+
+ if (sound && sound._interval) {
+ if (self._webAudio) {
+ sound._node.gain.cancelScheduledValues(Howler.ctx.currentTime);
+ }
+
+ clearInterval(sound._interval);
+ sound._interval = null;
+ self.volume(sound._fadeTo, id);
+ sound._fadeTo = null;
+ self._emit('fade', id);
+ }
+
+ return self;
+ },
+
+ /**
+ * Get/set the loop parameter on a sound. This method can optionally take 0, 1 or 2 arguments.
+ * loop() -> Returns the group's loop value.
+ * loop(id) -> Returns the sound id's loop value.
+ * loop(loop) -> Sets the loop value for all sounds in this Howl group.
+ * loop(loop, id) -> Sets the loop value of passed sound id.
+ * @return {Howl/Boolean} Returns self or current loop value.
+ */
+ loop: function() {
+ var self = this;
+ var args = arguments;
+ var loop, id, sound;
+
+ // Determine the values for loop and id.
+ if (args.length === 0) {
+ // Return the grou's loop value.
+ return self._loop;
+ } else if (args.length === 1) {
+ if (typeof args[0] === 'boolean') {
+ loop = args[0];
+ self._loop = loop;
+ } else {
+ // Return this sound's loop value.
+ sound = self._soundById(parseInt(args[0], 10));
+ return sound ? sound._loop : false;
+ }
+ } else if (args.length === 2) {
+ loop = args[0];
+ id = parseInt(args[1], 10);
+ }
+
+ // If no id is passed, get all ID's to be looped.
+ var ids = self._getSoundIds(id);
+ for (var i=0; i Returns the first sound node's current playback rate.
+ * rate(id) -> Returns the sound id's current playback rate.
+ * rate(rate) -> Sets the playback rate of all sounds in this Howl group.
+ * rate(rate, id) -> Sets the playback rate of passed sound id.
+ * @return {Howl/Number} Returns self or the current playback rate.
+ */
+ rate: function() {
+ var self = this;
+ var args = arguments;
+ var rate, id;
+
+ // Determine the values based on arguments.
+ if (args.length === 0) {
+ // We will simply return the current rate of the first node.
+ id = self._sounds[0]._id;
+ } else if (args.length === 1) {
+ // First check if this is an ID, and if not, assume it is a new rate value.
+ var ids = self._getSoundIds();
+ var index = ids.indexOf(args[0]);
+ if (index >= 0) {
+ id = parseInt(args[0], 10);
+ } else {
+ rate = parseFloat(args[0]);
+ }
+ } else if (args.length === 2) {
+ rate = parseFloat(args[0]);
+ id = parseInt(args[1], 10);
+ }
+
+ // Update the playback rate or return the current value.
+ var sound;
+ if (typeof rate === 'number') {
+ // If the sound hasn't loaded, add it to the load queue to change playback rate when capable.
+ if (self._state !== 'loaded' || self._playLock) {
+ self._queue.push({
+ event: 'rate',
+ action: function() {
+ self.rate.apply(self, args);
+ }
+ });
+
+ return self;
+ }
+
+ // Set the group rate.
+ if (typeof id === 'undefined') {
+ self._rate = rate;
+ }
+
+ // Update one or all volumes.
+ id = self._getSoundIds(id);
+ for (var i=0; i Returns the first sound node's current seek position.
+ * seek(id) -> Returns the sound id's current seek position.
+ * seek(seek) -> Sets the seek position of the first sound node.
+ * seek(seek, id) -> Sets the seek position of passed sound id.
+ * @return {Howl/Number} Returns self or the current seek position.
+ */
+ seek: function() {
+ var self = this;
+ var args = arguments;
+ var seek, id;
+
+ // Determine the values based on arguments.
+ if (args.length === 0) {
+ // We will simply return the current position of the first node.
+ if (self._sounds.length) {
+ id = self._sounds[0]._id;
+ }
+ } else if (args.length === 1) {
+ // First check if this is an ID, and if not, assume it is a new seek position.
+ var ids = self._getSoundIds();
+ var index = ids.indexOf(args[0]);
+ if (index >= 0) {
+ id = parseInt(args[0], 10);
+ } else if (self._sounds.length) {
+ id = self._sounds[0]._id;
+ seek = parseFloat(args[0]);
+ }
+ } else if (args.length === 2) {
+ seek = parseFloat(args[0]);
+ id = parseInt(args[1], 10);
+ }
+
+ // If there is no ID, bail out.
+ if (typeof id === 'undefined') {
+ return 0;
+ }
+
+ // If the sound hasn't loaded, add it to the load queue to seek when capable.
+ if (typeof seek === 'number' && (self._state !== 'loaded' || self._playLock)) {
+ self._queue.push({
+ event: 'seek',
+ action: function() {
+ self.seek.apply(self, args);
+ }
+ });
+
+ return self;
+ }
+
+ // Get the sound.
+ var sound = self._soundById(id);
+
+ if (sound) {
+ if (typeof seek === 'number' && seek >= 0) {
+ // Pause the sound and update position for restarting playback.
+ var playing = self.playing(id);
+ if (playing) {
+ self.pause(id, true);
+ }
+
+ // Move the position of the track and cancel timer.
+ sound._seek = seek;
+ sound._ended = false;
+ self._clearTimer(id);
+
+ // Update the seek position for HTML5 Audio.
+ if (!self._webAudio && sound._node && !isNaN(sound._node.duration)) {
+ sound._node.currentTime = seek;
+ }
+
+ // Seek and emit when ready.
+ var seekAndEmit = function() {
+ // Restart the playback if the sound was playing.
+ if (playing) {
+ self.play(id, true);
+ }
+
+ self._emit('seek', id);
+ };
+
+ // Wait for the play lock to be unset before emitting (HTML5 Audio).
+ if (playing && !self._webAudio) {
+ var emitSeek = function() {
+ if (!self._playLock) {
+ seekAndEmit();
+ } else {
+ setTimeout(emitSeek, 0);
+ }
+ };
+ setTimeout(emitSeek, 0);
+ } else {
+ seekAndEmit();
+ }
+ } else {
+ if (self._webAudio) {
+ var realTime = self.playing(id) ? Howler.ctx.currentTime - sound._playStart : 0;
+ var rateSeek = sound._rateSeek ? sound._rateSeek - sound._seek : 0;
+ return sound._seek + (rateSeek + realTime * Math.abs(sound._rate));
+ } else {
+ return sound._node.currentTime;
+ }
+ }
+ }
+
+ return self;
+ },
+
+ /**
+ * Check if a specific sound is currently playing or not (if id is provided), or check if at least one of the sounds in the group is playing or not.
+ * @param {Number} id The sound id to check. If none is passed, the whole sound group is checked.
+ * @return {Boolean} True if playing and false if not.
+ */
+ playing: function(id) {
+ var self = this;
+
+ // Check the passed sound ID (if any).
+ if (typeof id === 'number') {
+ var sound = self._soundById(id);
+ return sound ? !sound._paused : false;
+ }
+
+ // Otherwise, loop through all sounds and check if any are playing.
+ for (var i=0; i= 0) {
+ Howler._howls.splice(index, 1);
+ }
+
+ // Delete this sound from the cache (if no other Howl is using it).
+ var remCache = true;
+ for (i=0; i= 0) {
+ remCache = false;
+ break;
+ }
+ }
+
+ if (cache && remCache) {
+ delete cache[self._src];
+ }
+
+ // Clear global errors.
+ Howler.noAudio = false;
+
+ // Clear out `self`.
+ self._state = 'unloaded';
+ self._sounds = [];
+ self = null;
+
+ return null;
+ },
+
+ /**
+ * Listen to a custom event.
+ * @param {String} event Event name.
+ * @param {Function} fn Listener to call.
+ * @param {Number} id (optional) Only listen to events for this sound.
+ * @param {Number} once (INTERNAL) Marks event to fire only once.
+ * @return {Howl}
+ */
+ on: function(event, fn, id, once) {
+ var self = this;
+ var events = self['_on' + event];
+
+ if (typeof fn === 'function') {
+ events.push(once ? {id: id, fn: fn, once: once} : {id: id, fn: fn});
+ }
+
+ return self;
+ },
+
+ /**
+ * Remove a custom event. Call without parameters to remove all events.
+ * @param {String} event Event name.
+ * @param {Function} fn Listener to remove. Leave empty to remove all.
+ * @param {Number} id (optional) Only remove events for this sound.
+ * @return {Howl}
+ */
+ off: function(event, fn, id) {
+ var self = this;
+ var events = self['_on' + event];
+ var i = 0;
+
+ // Allow passing just an event and ID.
+ if (typeof fn === 'number') {
+ id = fn;
+ fn = null;
+ }
+
+ if (fn || id) {
+ // Loop through event store and remove the passed function.
+ for (i=0; i=0; i--) {
+ // Only fire the listener if the correct ID is used.
+ if (!events[i].id || events[i].id === id || event === 'load') {
+ setTimeout(function(fn) {
+ fn.call(this, id, msg);
+ }.bind(self, events[i].fn), 0);
+
+ // If this event was setup with `once`, remove it.
+ if (events[i].once) {
+ self.off(event, events[i].fn, events[i].id);
+ }
+ }
+ }
+
+ // Pass the event type into load queue so that it can continue stepping.
+ self._loadQueue(event);
+
+ return self;
+ },
+
+ /**
+ * Queue of actions initiated before the sound has loaded.
+ * These will be called in sequence, with the next only firing
+ * after the previous has finished executing (even if async like play).
+ * @return {Howl}
+ */
+ _loadQueue: function(event) {
+ var self = this;
+
+ if (self._queue.length > 0) {
+ var task = self._queue[0];
+
+ // Remove this task if a matching event was passed.
+ if (task.event === event) {
+ self._queue.shift();
+ self._loadQueue();
+ }
+
+ // Run the task if no event type is passed.
+ if (!event) {
+ task.action();
+ }
+ }
+
+ return self;
+ },
+
+ /**
+ * Fired when playback ends at the end of the duration.
+ * @param {Sound} sound The sound object to work with.
+ * @return {Howl}
+ */
+ _ended: function(sound) {
+ var self = this;
+ var sprite = sound._sprite;
+
+ // If we are using IE and there was network latency we may be clipping
+ // audio before it completes playing. Lets check the node to make sure it
+ // believes it has completed, before ending the playback.
+ if (!self._webAudio && sound._node && !sound._node.paused && !sound._node.ended && sound._node.currentTime < sound._stop) {
+ setTimeout(self._ended.bind(self, sound), 100);
+ return self;
+ }
+
+ // Should this sound loop?
+ var loop = !!(sound._loop || self._sprite[sprite][2]);
+
+ // Fire the ended event.
+ self._emit('end', sound._id);
+
+ // Restart the playback for HTML5 Audio loop.
+ if (!self._webAudio && loop) {
+ self.stop(sound._id, true).play(sound._id);
+ }
+
+ // Restart this timer if on a Web Audio loop.
+ if (self._webAudio && loop) {
+ self._emit('play', sound._id);
+ sound._seek = sound._start || 0;
+ sound._rateSeek = 0;
+ sound._playStart = Howler.ctx.currentTime;
+
+ var timeout = ((sound._stop - sound._start) * 1000) / Math.abs(sound._rate);
+ self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);
+ }
+
+ // Mark the node as paused.
+ if (self._webAudio && !loop) {
+ sound._paused = true;
+ sound._ended = true;
+ sound._seek = sound._start || 0;
+ sound._rateSeek = 0;
+ self._clearTimer(sound._id);
+
+ // Clean up the buffer source.
+ self._cleanBuffer(sound._node);
+
+ // Attempt to auto-suspend AudioContext if no sounds are still playing.
+ Howler._autoSuspend();
+ }
+
+ // When using a sprite, end the track.
+ if (!self._webAudio && !loop) {
+ self.stop(sound._id, true);
+ }
+
+ return self;
+ },
+
+ /**
+ * Clear the end timer for a sound playback.
+ * @param {Number} id The sound ID.
+ * @return {Howl}
+ */
+ _clearTimer: function(id) {
+ var self = this;
+
+ if (self._endTimers[id]) {
+ // Clear the timeout or remove the ended listener.
+ if (typeof self._endTimers[id] !== 'function') {
+ clearTimeout(self._endTimers[id]);
+ } else {
+ var sound = self._soundById(id);
+ if (sound && sound._node) {
+ sound._node.removeEventListener('ended', self._endTimers[id], false);
+ }
+ }
+
+ delete self._endTimers[id];
+ }
+
+ return self;
+ },
+
+ /**
+ * Return the sound identified by this ID, or return null.
+ * @param {Number} id Sound ID
+ * @return {Object} Sound object or null.
+ */
+ _soundById: function(id) {
+ var self = this;
+
+ // Loop through all sounds and find the one with this ID.
+ for (var i=0; i=0; i--) {
+ if (cnt <= limit) {
+ return;
+ }
+
+ if (self._sounds[i]._ended) {
+ // Disconnect the audio source when using Web Audio.
+ if (self._webAudio && self._sounds[i]._node) {
+ self._sounds[i]._node.disconnect(0);
+ }
+
+ // Remove sounds until we have the pool size.
+ self._sounds.splice(i, 1);
+ cnt--;
+ }
+ }
+ },
+
+ /**
+ * Get all ID's from the sounds pool.
+ * @param {Number} id Only return one ID if one is passed.
+ * @return {Array} Array of IDs.
+ */
+ _getSoundIds: function(id) {
+ var self = this;
+
+ if (typeof id === 'undefined') {
+ var ids = [];
+ for (var i=0; i= 0;
+
+ if (!node.bufferSource) {
+ return self;
+ }
+
+ if (Howler._scratchBuffer && node.bufferSource) {
+ node.bufferSource.onended = null;
+ node.bufferSource.disconnect(0);
+ if (isIOS) {
+ try { node.bufferSource.buffer = Howler._scratchBuffer; } catch(e) {}
+ }
+ }
+ node.bufferSource = null;
+
+ return self;
+ },
+
+ /**
+ * Set the source to a 0-second silence to stop any downloading (except in IE).
+ * @param {Object} node Audio node to clear.
+ */
+ _clearSound: function(node) {
+ var checkIE = /MSIE |Trident\//.test(Howler._navigator && Howler._navigator.userAgent);
+ if (!checkIE) {
+ node.src = 'data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA';
+ }
+ }
+ };
+
+ /** Single Sound Methods **/
+ /***************************************************************************/
+
+ /**
+ * Setup the sound object, which each node attached to a Howl group is contained in.
+ * @param {Object} howl The Howl parent group.
+ */
+ var Sound = function(howl) {
+ this._parent = howl;
+ this.init();
+ };
+ Sound.prototype = {
+ /**
+ * Initialize a new Sound object.
+ * @return {Sound}
+ */
+ init: function() {
+ var self = this;
+ var parent = self._parent;
+
+ // Setup the default parameters.
+ self._muted = parent._muted;
+ self._loop = parent._loop;
+ self._volume = parent._volume;
+ self._rate = parent._rate;
+ self._seek = 0;
+ self._paused = true;
+ self._ended = true;
+ self._sprite = '__default';
+
+ // Generate a unique ID for this sound.
+ self._id = ++Howler._counter;
+
+ // Add itself to the parent's pool.
+ parent._sounds.push(self);
+
+ // Create the new node.
+ self.create();
+
+ return self;
+ },
+
+ /**
+ * Create and setup a new sound object, whether HTML5 Audio or Web Audio.
+ * @return {Sound}
+ */
+ create: function() {
+ var self = this;
+ var parent = self._parent;
+ var volume = (Howler._muted || self._muted || self._parent._muted) ? 0 : self._volume;
+
+ if (parent._webAudio) {
+ // Create the gain node for controlling volume (the source will connect to this).
+ self._node = (typeof Howler.ctx.createGain === 'undefined') ? Howler.ctx.createGainNode() : Howler.ctx.createGain();
+ self._node.gain.setValueAtTime(volume, Howler.ctx.currentTime);
+ self._node.paused = true;
+ self._node.connect(Howler.masterGain);
+ } else if (!Howler.noAudio) {
+ // Get an unlocked Audio object from the pool.
+ self._node = Howler._obtainHtml5Audio();
+
+ // Listen for errors (http://dev.w3.org/html5/spec-author-view/spec.html#mediaerror).
+ self._errorFn = self._errorListener.bind(self);
+ self._node.addEventListener('error', self._errorFn, false);
+
+ // Listen for 'canplaythrough' event to let us know the sound is ready.
+ self._loadFn = self._loadListener.bind(self);
+ self._node.addEventListener(Howler._canPlayEvent, self._loadFn, false);
+
+ // Listen for the 'ended' event on the sound to account for edge-case where
+ // a finite sound has a duration of Infinity.
+ self._endFn = self._endListener.bind(self);
+ self._node.addEventListener('ended', self._endFn, false);
+
+ // Setup the new audio node.
+ self._node.src = parent._src;
+ self._node.preload = parent._preload === true ? 'auto' : parent._preload;
+ self._node.volume = volume * Howler.volume();
+
+ // Begin loading the source.
+ self._node.load();
+ }
+
+ return self;
+ },
+
+ /**
+ * Reset the parameters of this sound to the original state (for recycle).
+ * @return {Sound}
+ */
+ reset: function() {
+ var self = this;
+ var parent = self._parent;
+
+ // Reset all of the parameters of this sound.
+ self._muted = parent._muted;
+ self._loop = parent._loop;
+ self._volume = parent._volume;
+ self._rate = parent._rate;
+ self._seek = 0;
+ self._rateSeek = 0;
+ self._paused = true;
+ self._ended = true;
+ self._sprite = '__default';
+
+ // Generate a new ID so that it isn't confused with the previous sound.
+ self._id = ++Howler._counter;
+
+ return self;
+ },
+
+ /**
+ * HTML5 Audio error listener callback.
+ */
+ _errorListener: function() {
+ var self = this;
+
+ // Fire an error event and pass back the code.
+ self._parent._emit('loaderror', self._id, self._node.error ? self._node.error.code : 0);
+
+ // Clear the event listener.
+ self._node.removeEventListener('error', self._errorFn, false);
+ },
+
+ /**
+ * HTML5 Audio canplaythrough listener callback.
+ */
+ _loadListener: function() {
+ var self = this;
+ var parent = self._parent;
+
+ // Round up the duration to account for the lower precision in HTML5 Audio.
+ parent._duration = Math.ceil(self._node.duration * 10) / 10;
+
+ // Setup a sprite if none is defined.
+ if (Object.keys(parent._sprite).length === 0) {
+ parent._sprite = {__default: [0, parent._duration * 1000]};
+ }
+
+ if (parent._state !== 'loaded') {
+ parent._state = 'loaded';
+ parent._emit('load');
+ parent._loadQueue();
+ }
+
+ // Clear the event listener.
+ self._node.removeEventListener(Howler._canPlayEvent, self._loadFn, false);
+ },
+
+ /**
+ * HTML5 Audio ended listener callback.
+ */
+ _endListener: function() {
+ var self = this;
+ var parent = self._parent;
+
+ // Only handle the `ended`` event if the duration is Infinity.
+ if (parent._duration === Infinity) {
+ // Update the parent duration to match the real audio duration.
+ // Round up the duration to account for the lower precision in HTML5 Audio.
+ parent._duration = Math.ceil(self._node.duration * 10) / 10;
+
+ // Update the sprite that corresponds to the real duration.
+ if (parent._sprite.__default[1] === Infinity) {
+ parent._sprite.__default[1] = parent._duration * 1000;
+ }
+
+ // Run the regular ended method.
+ parent._ended(self);
+ }
+
+ // Clear the event listener since the duration is now correct.
+ self._node.removeEventListener('ended', self._endFn, false);
+ }
+ };
+
+ /** Helper Methods **/
+ /***************************************************************************/
+
+ var cache = {};
+
+ /**
+ * Buffer a sound from URL, Data URI or cache and decode to audio source (Web Audio API).
+ * @param {Howl} self
+ */
+ var loadBuffer = function(self) {
+ var url = self._src;
+
+ // Check if the buffer has already been cached and use it instead.
+ if (cache[url]) {
+ // Set the duration from the cache.
+ self._duration = cache[url].duration;
+
+ // Load the sound into this Howl.
+ loadSound(self);
+
+ return;
+ }
+
+ if (/^data:[^;]+;base64,/.test(url)) {
+ // Decode the base64 data URI without XHR, since some browsers don't support it.
+ var data = atob(url.split(',')[1]);
+ var dataView = new Uint8Array(data.length);
+ for (var i=0; i 0) {
+ cache[self._src] = buffer;
+ loadSound(self, buffer);
+ } else {
+ error();
+ }
+ };
+
+ // Decode the buffer into an audio source.
+ if (typeof Promise !== 'undefined' && Howler.ctx.decodeAudioData.length === 1) {
+ Howler.ctx.decodeAudioData(arraybuffer).then(success).catch(error);
+ } else {
+ Howler.ctx.decodeAudioData(arraybuffer, success, error);
+ }
+ }
+
+ /**
+ * Sound is now loaded, so finish setting everything up and fire the loaded event.
+ * @param {Howl} self
+ * @param {Object} buffer The decoded buffer sound source.
+ */
+ var loadSound = function(self, buffer) {
+ // Set the duration.
+ if (buffer && !self._duration) {
+ self._duration = buffer.duration;
+ }
+
+ // Setup a sprite if none is defined.
+ if (Object.keys(self._sprite).length === 0) {
+ self._sprite = {__default: [0, self._duration * 1000]};
+ }
+
+ // Fire the loaded event.
+ if (self._state !== 'loaded') {
+ self._state = 'loaded';
+ self._emit('load');
+ self._loadQueue();
+ }
+ };
+
+ /**
+ * Setup the audio context when available, or switch to HTML5 Audio mode.
+ */
+ var setupAudioContext = function() {
+ // If we have already detected that Web Audio isn't supported, don't run this step again.
+ if (!Howler.usingWebAudio) {
+ return;
+ }
+
+ // Check if we are using Web Audio and setup the AudioContext if we are.
+ try {
+ if (typeof AudioContext !== 'undefined') {
+ Howler.ctx = new AudioContext();
+ } else if (typeof webkitAudioContext !== 'undefined') {
+ Howler.ctx = new webkitAudioContext();
+ } else {
+ Howler.usingWebAudio = false;
+ }
+ } catch(e) {
+ Howler.usingWebAudio = false;
+ }
+
+ // If the audio context creation still failed, set using web audio to false.
+ if (!Howler.ctx) {
+ Howler.usingWebAudio = false;
+ }
+
+ // Check if a webview is being used on iOS8 or earlier (rather than the browser).
+ // If it is, disable Web Audio as it causes crashing.
+ var iOS = (/iP(hone|od|ad)/.test(Howler._navigator && Howler._navigator.platform));
+ var appVersion = Howler._navigator && Howler._navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/);
+ var version = appVersion ? parseInt(appVersion[1], 10) : null;
+ if (iOS && version && version < 9) {
+ var safari = /safari/.test(Howler._navigator && Howler._navigator.userAgent.toLowerCase());
+ if (Howler._navigator && !safari) {
+ Howler.usingWebAudio = false;
+ }
+ }
+
+ // Create and expose the master GainNode when using Web Audio (useful for plugins or advanced usage).
+ if (Howler.usingWebAudio) {
+ Howler.masterGain = (typeof Howler.ctx.createGain === 'undefined') ? Howler.ctx.createGainNode() : Howler.ctx.createGain();
+ Howler.masterGain.gain.setValueAtTime(Howler._muted ? 0 : Howler._volume, Howler.ctx.currentTime);
+ Howler.masterGain.connect(Howler.ctx.destination);
+ }
+
+ // Re-run the setup on Howler.
+ Howler._setup();
+ };
+
+ // Add support for AMD (Asynchronous Module Definition) libraries such as require.js.
+ if (typeof define === 'function' && define.amd) {
+ define([], function() {
+ return {
+ Howler: Howler,
+ Howl: Howl
+ };
+ });
+ }
+
+ // Add support for CommonJS libraries such as browserify.
+ if (typeof exports !== 'undefined') {
+ exports.Howler = Howler;
+ exports.Howl = Howl;
+ }
+
+ // Add to global in Node.js (for testing, etc).
+ if (typeof global !== 'undefined') {
+ global.HowlerGlobal = HowlerGlobal;
+ global.Howler = Howler;
+ global.Howl = Howl;
+ global.Sound = Sound;
+ } else if (typeof window !== 'undefined') { // Define globally in case AMD is not available or unused.
+ window.HowlerGlobal = HowlerGlobal;
+ window.Howler = Howler;
+ window.Howl = Howl;
+ window.Sound = Sound;
+ }
+})();
+
+
+/*!
+ * Spatial Plugin - Adds support for stereo and 3D audio where Web Audio is supported.
+ *
+ * howler.js v2.2.4
+ * howlerjs.com
+ *
+ * (c) 2013-2020, James Simpson of GoldFire Studios
+ * goldfirestudios.com
+ *
+ * MIT License
+ */
+
+(function() {
+
+ 'use strict';
+
+ // Setup default properties.
+ HowlerGlobal.prototype._pos = [0, 0, 0];
+ HowlerGlobal.prototype._orientation = [0, 0, -1, 0, 1, 0];
+
+ /** Global Methods **/
+ /***************************************************************************/
+
+ /**
+ * Helper method to update the stereo panning position of all current Howls.
+ * Future Howls will not use this value unless explicitly set.
+ * @param {Number} pan A value of -1.0 is all the way left and 1.0 is all the way right.
+ * @return {Howler/Number} Self or current stereo panning value.
+ */
+ HowlerGlobal.prototype.stereo = function(pan) {
+ var self = this;
+
+ // Stop right here if not using Web Audio.
+ if (!self.ctx || !self.ctx.listener) {
+ return self;
+ }
+
+ // Loop through all Howls and update their stereo panning.
+ for (var i=self._howls.length-1; i>=0; i--) {
+ self._howls[i].stereo(pan);
+ }
+
+ return self;
+ };
+
+ /**
+ * Get/set the position of the listener in 3D cartesian space. Sounds using
+ * 3D position will be relative to the listener's position.
+ * @param {Number} x The x-position of the listener.
+ * @param {Number} y The y-position of the listener.
+ * @param {Number} z The z-position of the listener.
+ * @return {Howler/Array} Self or current listener position.
+ */
+ HowlerGlobal.prototype.pos = function(x, y, z) {
+ var self = this;
+
+ // Stop right here if not using Web Audio.
+ if (!self.ctx || !self.ctx.listener) {
+ return self;
+ }
+
+ // Set the defaults for optional 'y' & 'z'.
+ y = (typeof y !== 'number') ? self._pos[1] : y;
+ z = (typeof z !== 'number') ? self._pos[2] : z;
+
+ if (typeof x === 'number') {
+ self._pos = [x, y, z];
+
+ if (typeof self.ctx.listener.positionX !== 'undefined') {
+ self.ctx.listener.positionX.setTargetAtTime(self._pos[0], Howler.ctx.currentTime, 0.1);
+ self.ctx.listener.positionY.setTargetAtTime(self._pos[1], Howler.ctx.currentTime, 0.1);
+ self.ctx.listener.positionZ.setTargetAtTime(self._pos[2], Howler.ctx.currentTime, 0.1);
+ } else {
+ self.ctx.listener.setPosition(self._pos[0], self._pos[1], self._pos[2]);
+ }
+ } else {
+ return self._pos;
+ }
+
+ return self;
+ };
+
+ /**
+ * Get/set the direction the listener is pointing in the 3D cartesian space.
+ * A front and up vector must be provided. The front is the direction the
+ * face of the listener is pointing, and up is the direction the top of the
+ * listener is pointing. Thus, these values are expected to be at right angles
+ * from each other.
+ * @param {Number} x The x-orientation of the listener.
+ * @param {Number} y The y-orientation of the listener.
+ * @param {Number} z The z-orientation of the listener.
+ * @param {Number} xUp The x-orientation of the top of the listener.
+ * @param {Number} yUp The y-orientation of the top of the listener.
+ * @param {Number} zUp The z-orientation of the top of the listener.
+ * @return {Howler/Array} Returns self or the current orientation vectors.
+ */
+ HowlerGlobal.prototype.orientation = function(x, y, z, xUp, yUp, zUp) {
+ var self = this;
+
+ // Stop right here if not using Web Audio.
+ if (!self.ctx || !self.ctx.listener) {
+ return self;
+ }
+
+ // Set the defaults for optional 'y' & 'z'.
+ var or = self._orientation;
+ y = (typeof y !== 'number') ? or[1] : y;
+ z = (typeof z !== 'number') ? or[2] : z;
+ xUp = (typeof xUp !== 'number') ? or[3] : xUp;
+ yUp = (typeof yUp !== 'number') ? or[4] : yUp;
+ zUp = (typeof zUp !== 'number') ? or[5] : zUp;
+
+ if (typeof x === 'number') {
+ self._orientation = [x, y, z, xUp, yUp, zUp];
+
+ if (typeof self.ctx.listener.forwardX !== 'undefined') {
+ self.ctx.listener.forwardX.setTargetAtTime(x, Howler.ctx.currentTime, 0.1);
+ self.ctx.listener.forwardY.setTargetAtTime(y, Howler.ctx.currentTime, 0.1);
+ self.ctx.listener.forwardZ.setTargetAtTime(z, Howler.ctx.currentTime, 0.1);
+ self.ctx.listener.upX.setTargetAtTime(xUp, Howler.ctx.currentTime, 0.1);
+ self.ctx.listener.upY.setTargetAtTime(yUp, Howler.ctx.currentTime, 0.1);
+ self.ctx.listener.upZ.setTargetAtTime(zUp, Howler.ctx.currentTime, 0.1);
+ } else {
+ self.ctx.listener.setOrientation(x, y, z, xUp, yUp, zUp);
+ }
+ } else {
+ return or;
+ }
+
+ return self;
+ };
+
+ /** Group Methods **/
+ /***************************************************************************/
+
+ /**
+ * Add new properties to the core init.
+ * @param {Function} _super Core init method.
+ * @return {Howl}
+ */
+ Howl.prototype.init = (function(_super) {
+ return function(o) {
+ var self = this;
+
+ // Setup user-defined default properties.
+ self._orientation = o.orientation || [1, 0, 0];
+ self._stereo = o.stereo || null;
+ self._pos = o.pos || null;
+ self._pannerAttr = {
+ coneInnerAngle: typeof o.coneInnerAngle !== 'undefined' ? o.coneInnerAngle : 360,
+ coneOuterAngle: typeof o.coneOuterAngle !== 'undefined' ? o.coneOuterAngle : 360,
+ coneOuterGain: typeof o.coneOuterGain !== 'undefined' ? o.coneOuterGain : 0,
+ distanceModel: typeof o.distanceModel !== 'undefined' ? o.distanceModel : 'inverse',
+ maxDistance: typeof o.maxDistance !== 'undefined' ? o.maxDistance : 10000,
+ panningModel: typeof o.panningModel !== 'undefined' ? o.panningModel : 'HRTF',
+ refDistance: typeof o.refDistance !== 'undefined' ? o.refDistance : 1,
+ rolloffFactor: typeof o.rolloffFactor !== 'undefined' ? o.rolloffFactor : 1
+ };
+
+ // Setup event listeners.
+ self._onstereo = o.onstereo ? [{fn: o.onstereo}] : [];
+ self._onpos = o.onpos ? [{fn: o.onpos}] : [];
+ self._onorientation = o.onorientation ? [{fn: o.onorientation}] : [];
+
+ // Complete initilization with howler.js core's init function.
+ return _super.call(this, o);
+ };
+ })(Howl.prototype.init);
+
+ /**
+ * Get/set the stereo panning of the audio source for this sound or all in the group.
+ * @param {Number} pan A value of -1.0 is all the way left and 1.0 is all the way right.
+ * @param {Number} id (optional) The sound ID. If none is passed, all in group will be updated.
+ * @return {Howl/Number} Returns self or the current stereo panning value.
+ */
+ Howl.prototype.stereo = function(pan, id) {
+ var self = this;
+
+ // Stop right here if not using Web Audio.
+ if (!self._webAudio) {
+ return self;
+ }
+
+ // If the sound hasn't loaded, add it to the load queue to change stereo pan when capable.
+ if (self._state !== 'loaded') {
+ self._queue.push({
+ event: 'stereo',
+ action: function() {
+ self.stereo(pan, id);
+ }
+ });
+
+ return self;
+ }
+
+ // Check for PannerStereoNode support and fallback to PannerNode if it doesn't exist.
+ var pannerType = (typeof Howler.ctx.createStereoPanner === 'undefined') ? 'spatial' : 'stereo';
+
+ // Setup the group's stereo panning if no ID is passed.
+ if (typeof id === 'undefined') {
+ // Return the group's stereo panning if no parameters are passed.
+ if (typeof pan === 'number') {
+ self._stereo = pan;
+ self._pos = [pan, 0, 0];
+ } else {
+ return self._stereo;
+ }
+ }
+
+ // Change the streo panning of one or all sounds in group.
+ var ids = self._getSoundIds(id);
+ for (var i=0; i Returns the group's values.
+ * pannerAttr(id) -> Returns the sound id's values.
+ * pannerAttr(o) -> Set's the values of all sounds in this Howl group.
+ * pannerAttr(o, id) -> Set's the values of passed sound id.
+ *
+ * Attributes:
+ * coneInnerAngle - (360 by default) A parameter for directional audio sources, this is an angle, in degrees,
+ * inside of which there will be no volume reduction.
+ * coneOuterAngle - (360 by default) A parameter for directional audio sources, this is an angle, in degrees,
+ * outside of which the volume will be reduced to a constant value of `coneOuterGain`.
+ * coneOuterGain - (0 by default) A parameter for directional audio sources, this is the gain outside of the
+ * `coneOuterAngle`. It is a linear value in the range `[0, 1]`.
+ * distanceModel - ('inverse' by default) Determines algorithm used to reduce volume as audio moves away from
+ * listener. Can be `linear`, `inverse` or `exponential.
+ * maxDistance - (10000 by default) The maximum distance between source and listener, after which the volume
+ * will not be reduced any further.
+ * refDistance - (1 by default) A reference distance for reducing volume as source moves further from the listener.
+ * This is simply a variable of the distance model and has a different effect depending on which model
+ * is used and the scale of your coordinates. Generally, volume will be equal to 1 at this distance.
+ * rolloffFactor - (1 by default) How quickly the volume reduces as source moves from listener. This is simply a
+ * variable of the distance model and can be in the range of `[0, 1]` with `linear` and `[0, ∞]`
+ * with `inverse` and `exponential`.
+ * panningModel - ('HRTF' by default) Determines which spatialization algorithm is used to position audio.
+ * Can be `HRTF` or `equalpower`.
+ *
+ * @return {Howl/Object} Returns self or current panner attributes.
+ */
+ Howl.prototype.pannerAttr = function() {
+ var self = this;
+ var args = arguments;
+ var o, id, sound;
+
+ // Stop right here if not using Web Audio.
+ if (!self._webAudio) {
+ return self;
+ }
+
+ // Determine the values based on arguments.
+ if (args.length === 0) {
+ // Return the group's panner attribute values.
+ return self._pannerAttr;
+ } else if (args.length === 1) {
+ if (typeof args[0] === 'object') {
+ o = args[0];
+
+ // Set the grou's panner attribute values.
+ if (typeof id === 'undefined') {
+ if (!o.pannerAttr) {
+ o.pannerAttr = {
+ coneInnerAngle: o.coneInnerAngle,
+ coneOuterAngle: o.coneOuterAngle,
+ coneOuterGain: o.coneOuterGain,
+ distanceModel: o.distanceModel,
+ maxDistance: o.maxDistance,
+ refDistance: o.refDistance,
+ rolloffFactor: o.rolloffFactor,
+ panningModel: o.panningModel
+ };
+ }
+
+ self._pannerAttr = {
+ coneInnerAngle: typeof o.pannerAttr.coneInnerAngle !== 'undefined' ? o.pannerAttr.coneInnerAngle : self._coneInnerAngle,
+ coneOuterAngle: typeof o.pannerAttr.coneOuterAngle !== 'undefined' ? o.pannerAttr.coneOuterAngle : self._coneOuterAngle,
+ coneOuterGain: typeof o.pannerAttr.coneOuterGain !== 'undefined' ? o.pannerAttr.coneOuterGain : self._coneOuterGain,
+ distanceModel: typeof o.pannerAttr.distanceModel !== 'undefined' ? o.pannerAttr.distanceModel : self._distanceModel,
+ maxDistance: typeof o.pannerAttr.maxDistance !== 'undefined' ? o.pannerAttr.maxDistance : self._maxDistance,
+ refDistance: typeof o.pannerAttr.refDistance !== 'undefined' ? o.pannerAttr.refDistance : self._refDistance,
+ rolloffFactor: typeof o.pannerAttr.rolloffFactor !== 'undefined' ? o.pannerAttr.rolloffFactor : self._rolloffFactor,
+ panningModel: typeof o.pannerAttr.panningModel !== 'undefined' ? o.pannerAttr.panningModel : self._panningModel
+ };
+ }
+ } else {
+ // Return this sound's panner attribute values.
+ sound = self._soundById(parseInt(args[0], 10));
+ return sound ? sound._pannerAttr : self._pannerAttr;
+ }
+ } else if (args.length === 2) {
+ o = args[0];
+ id = parseInt(args[1], 10);
+ }
+
+ // Update the values of the specified sounds.
+ var ids = self._getSoundIds(id);
+ for (var i=0; i=0&&e<=1){if(o._volume=e,o._muted)return o;o.usingWebAudio&&o.masterGain.gain.setValueAtTime(e,n.ctx.currentTime);for(var t=0;t=0;o--)e._howls[o].unload();return e.usingWebAudio&&e.ctx&&void 0!==e.ctx.close&&(e.ctx.close(),e.ctx=null,_()),e},codecs:function(e){return(this||n)._codecs[e.replace(/^x-/,"")]},_setup:function(){var e=this||n;if(e.state=e.ctx?e.ctx.state||"suspended":"suspended",e._autoSuspend(),!e.usingWebAudio)if("undefined"!=typeof Audio)try{var o=new Audio;void 0===o.oncanplaythrough&&(e._canPlayEvent="canplay")}catch(n){e.noAudio=!0}else e.noAudio=!0;try{var o=new Audio;o.muted&&(e.noAudio=!0)}catch(e){}return e.noAudio||e._setupCodecs(),e},_setupCodecs:function(){var e=this||n,o=null;try{o="undefined"!=typeof Audio?new Audio:null}catch(n){return e}if(!o||"function"!=typeof o.canPlayType)return e;var t=o.canPlayType("audio/mpeg;").replace(/^no$/,""),r=e._navigator?e._navigator.userAgent:"",a=r.match(/OPR\/(\d+)/g),u=a&&parseInt(a[0].split("/")[1],10)<33,d=-1!==r.indexOf("Safari")&&-1===r.indexOf("Chrome"),i=r.match(/Version\/(.*?) /),_=d&&i&&parseInt(i[1],10)<15;return e._codecs={mp3:!(u||!t&&!o.canPlayType("audio/mp3;").replace(/^no$/,"")),mpeg:!!t,opus:!!o.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/,""),ogg:!!o.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),oga:!!o.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),wav:!!(o.canPlayType('audio/wav; codecs="1"')||o.canPlayType("audio/wav")).replace(/^no$/,""),aac:!!o.canPlayType("audio/aac;").replace(/^no$/,""),caf:!!o.canPlayType("audio/x-caf;").replace(/^no$/,""),m4a:!!(o.canPlayType("audio/x-m4a;")||o.canPlayType("audio/m4a;")||o.canPlayType("audio/aac;")).replace(/^no$/,""),m4b:!!(o.canPlayType("audio/x-m4b;")||o.canPlayType("audio/m4b;")||o.canPlayType("audio/aac;")).replace(/^no$/,""),mp4:!!(o.canPlayType("audio/x-mp4;")||o.canPlayType("audio/mp4;")||o.canPlayType("audio/aac;")).replace(/^no$/,""),weba:!(_||!o.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/,"")),webm:!(_||!o.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/,"")),dolby:!!o.canPlayType('audio/mp4; codecs="ec-3"').replace(/^no$/,""),flac:!!(o.canPlayType("audio/x-flac;")||o.canPlayType("audio/flac;")).replace(/^no$/,"")},e},_unlockAudio:function(){var e=this||n;if(!e._audioUnlocked&&e.ctx){e._audioUnlocked=!1,e.autoUnlock=!1,e._mobileUnloaded||44100===e.ctx.sampleRate||(e._mobileUnloaded=!0,e.unload()),e._scratchBuffer=e.ctx.createBuffer(1,1,22050);var o=function(n){for(;e._html5AudioPool.length0?d._seek:t._sprite[e][0]/1e3),s=Math.max(0,(t._sprite[e][0]+t._sprite[e][1])/1e3-_),l=1e3*s/Math.abs(d._rate),c=t._sprite[e][0]/1e3,f=(t._sprite[e][0]+t._sprite[e][1])/1e3;d._sprite=e,d._ended=!1;var p=function(){d._paused=!1,d._seek=_,d._start=c,d._stop=f,d._loop=!(!d._loop&&!t._sprite[e][2])};if(_>=f)return void t._ended(d);var m=d._node;if(t._webAudio){var v=function(){t._playLock=!1,p(),t._refreshBuffer(d);var e=d._muted||t._muted?0:d._volume;m.gain.setValueAtTime(e,n.ctx.currentTime),d._playStart=n.ctx.currentTime,void 0===m.bufferSource.start?d._loop?m.bufferSource.noteGrainOn(0,_,86400):m.bufferSource.noteGrainOn(0,_,s):d._loop?m.bufferSource.start(0,_,86400):m.bufferSource.start(0,_,s),l!==1/0&&(t._endTimers[d._id]=setTimeout(t._ended.bind(t,d),l)),o||setTimeout(function(){t._emit("play",d._id),t._loadQueue()},0)};"running"===n.state&&"interrupted"!==n.ctx.state?v():(t._playLock=!0,t.once("resume",v),t._clearTimer(d._id))}else{var h=function(){m.currentTime=_,m.muted=d._muted||t._muted||n._muted||m.muted,m.volume=d._volume*n.volume(),m.playbackRate=d._rate;try{var r=m.play();if(r&&"undefined"!=typeof Promise&&(r instanceof Promise||"function"==typeof r.then)?(t._playLock=!0,p(),r.then(function(){t._playLock=!1,m._unlocked=!0,o?t._loadQueue():t._emit("play",d._id)}).catch(function(){t._playLock=!1,t._emit("playerror",d._id,"Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction."),d._ended=!0,d._paused=!0})):o||(t._playLock=!1,p(),t._emit("play",d._id)),m.playbackRate=d._rate,m.paused)return void t._emit("playerror",d._id,"Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction.");"__default"!==e||d._loop?t._endTimers[d._id]=setTimeout(t._ended.bind(t,d),l):(t._endTimers[d._id]=function(){t._ended(d),m.removeEventListener("ended",t._endTimers[d._id],!1)},m.addEventListener("ended",t._endTimers[d._id],!1))}catch(e){t._emit("playerror",d._id,e)}};"data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA"===m.src&&(m.src=t._src,m.load());var y=window&&window.ejecta||!m.readyState&&n._navigator.isCocoonJS;if(m.readyState>=3||y)h();else{t._playLock=!0,t._state="loading";var g=function(){t._state="loaded",h(),m.removeEventListener(n._canPlayEvent,g,!1)};m.addEventListener(n._canPlayEvent,g,!1),t._clearTimer(d._id)}}return d._id},pause:function(e){var n=this;if("loaded"!==n._state||n._playLock)return n._queue.push({event:"pause",action:function(){n.pause(e)}}),n;for(var o=n._getSoundIds(e),t=0;t=0?o=parseInt(r[0],10):e=parseFloat(r[0])}else r.length>=2&&(e=parseFloat(r[0]),o=parseInt(r[1],10));var a;if(!(void 0!==e&&e>=0&&e<=1))return a=o?t._soundById(o):t._sounds[0],a?a._volume:0;if("loaded"!==t._state||t._playLock)return t._queue.push({event:"volume",action:function(){t.volume.apply(t,r)}}),t;void 0===o&&(t._volume=e),o=t._getSoundIds(o);for(var u=0;u0?t/_:t),l=Date.now();e._fadeTo=o,e._interval=setInterval(function(){var r=(Date.now()-l)/t;l=Date.now(),d+=i*r,d=Math.round(100*d)/100,d=i<0?Math.max(o,d):Math.min(o,d),u._webAudio?e._volume=d:u.volume(d,e._id,!0),a&&(u._volume=d),(on&&d>=o)&&(clearInterval(e._interval),e._interval=null,e._fadeTo=null,u.volume(o,e._id),u._emit("fade",e._id))},s)},_stopFade:function(e){var o=this,t=o._soundById(e);return t&&t._interval&&(o._webAudio&&t._node.gain.cancelScheduledValues(n.ctx.currentTime),clearInterval(t._interval),t._interval=null,o.volume(t._fadeTo,e),t._fadeTo=null,o._emit("fade",e)),o},loop:function(){var e,n,o,t=this,r=arguments;if(0===r.length)return t._loop;if(1===r.length){if("boolean"!=typeof r[0])return!!(o=t._soundById(parseInt(r[0],10)))&&o._loop;e=r[0],t._loop=e}else 2===r.length&&(e=r[0],n=parseInt(r[1],10));for(var a=t._getSoundIds(n),u=0;u=0?o=parseInt(r[0],10):e=parseFloat(r[0])}else 2===r.length&&(e=parseFloat(r[0]),o=parseInt(r[1],10));var d;if("number"!=typeof e)return d=t._soundById(o),d?d._rate:t._rate;if("loaded"!==t._state||t._playLock)return t._queue.push({event:"rate",action:function(){t.rate.apply(t,r)}}),t;void 0===o&&(t._rate=e),o=t._getSoundIds(o);for(var i=0;i=0?o=parseInt(r[0],10):t._sounds.length&&(o=t._sounds[0]._id,e=parseFloat(r[0]))}else 2===r.length&&(e=parseFloat(r[0]),o=parseInt(r[1],10));if(void 0===o)return 0;if("number"==typeof e&&("loaded"!==t._state||t._playLock))return t._queue.push({event:"seek",action:function(){t.seek.apply(t,r)}}),t;var d=t._soundById(o);if(d){if(!("number"==typeof e&&e>=0)){if(t._webAudio){var i=t.playing(o)?n.ctx.currentTime-d._playStart:0,_=d._rateSeek?d._rateSeek-d._seek:0;return d._seek+(_+i*Math.abs(d._rate))}return d._node.currentTime}var s=t.playing(o);s&&t.pause(o,!0),d._seek=e,d._ended=!1,t._clearTimer(o),t._webAudio||!d._node||isNaN(d._node.duration)||(d._node.currentTime=e);var l=function(){s&&t.play(o,!0),t._emit("seek",o)};if(s&&!t._webAudio){var c=function(){t._playLock?setTimeout(c,0):l()};setTimeout(c,0)}else l()}return t},playing:function(e){var n=this;if("number"==typeof e){var o=n._soundById(e);return!!o&&!o._paused}for(var t=0;t=0&&n._howls.splice(a,1);var u=!0;for(t=0;t=0){u=!1;break}return r&&u&&delete r[e._src],n.noAudio=!1,e._state="unloaded",e._sounds=[],e=null,null},on:function(e,n,o,t){var r=this,a=r["_on"+e];return"function"==typeof n&&a.push(t?{id:o,fn:n,once:t}:{id:o,fn:n}),r},off:function(e,n,o){var t=this,r=t["_on"+e],a=0;if("number"==typeof n&&(o=n,n=null),n||o)for(a=0;a=0;a--)r[a].id&&r[a].id!==n&&"load"!==e||(setTimeout(function(e){e.call(this,n,o)}.bind(t,r[a].fn),0),r[a].once&&t.off(e,r[a].fn,r[a].id));return t._loadQueue(e),t},_loadQueue:function(e){var n=this;if(n._queue.length>0){var o=n._queue[0];o.event===e&&(n._queue.shift(),n._loadQueue()),e||o.action()}return n},_ended:function(e){var o=this,t=e._sprite;if(!o._webAudio&&e._node&&!e._node.paused&&!e._node.ended&&e._node.currentTime=0;t--){if(o<=n)return;e._sounds[t]._ended&&(e._webAudio&&e._sounds[t]._node&&e._sounds[t]._node.disconnect(0),e._sounds.splice(t,1),o--)}}},_getSoundIds:function(e){var n=this;if(void 0===e){for(var o=[],t=0;t=0;if(!e.bufferSource)return o;if(n._scratchBuffer&&e.bufferSource&&(e.bufferSource.onended=null,e.bufferSource.disconnect(0),t))try{e.bufferSource.buffer=n._scratchBuffer}catch(e){}return e.bufferSource=null,o},_clearSound:function(e){/MSIE |Trident\//.test(n._navigator&&n._navigator.userAgent)||(e.src="data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA")}};var t=function(e){this._parent=e,this.init()};t.prototype={init:function(){var e=this,o=e._parent;return e._muted=o._muted,e._loop=o._loop,e._volume=o._volume,e._rate=o._rate,e._seek=0,e._paused=!0,e._ended=!0,e._sprite="__default",e._id=++n._counter,o._sounds.push(e),e.create(),e},create:function(){var e=this,o=e._parent,t=n._muted||e._muted||e._parent._muted?0:e._volume;return o._webAudio?(e._node=void 0===n.ctx.createGain?n.ctx.createGainNode():n.ctx.createGain(),e._node.gain.setValueAtTime(t,n.ctx.currentTime),e._node.paused=!0,e._node.connect(n.masterGain)):n.noAudio||(e._node=n._obtainHtml5Audio(),e._errorFn=e._errorListener.bind(e),e._node.addEventListener("error",e._errorFn,!1),e._loadFn=e._loadListener.bind(e),e._node.addEventListener(n._canPlayEvent,e._loadFn,!1),e._endFn=e._endListener.bind(e),e._node.addEventListener("ended",e._endFn,!1),e._node.src=o._src,e._node.preload=!0===o._preload?"auto":o._preload,e._node.volume=t*n.volume(),e._node.load()),e},reset:function(){var e=this,o=e._parent;return e._muted=o._muted,e._loop=o._loop,e._volume=o._volume,e._rate=o._rate,e._seek=0,e._rateSeek=0,e._paused=!0,e._ended=!0,e._sprite="__default",e._id=++n._counter,e},_errorListener:function(){var e=this;e._parent._emit("loaderror",e._id,e._node.error?e._node.error.code:0),e._node.removeEventListener("error",e._errorFn,!1)},_loadListener:function(){var e=this,o=e._parent;o._duration=Math.ceil(10*e._node.duration)/10,0===Object.keys(o._sprite).length&&(o._sprite={__default:[0,1e3*o._duration]}),"loaded"!==o._state&&(o._state="loaded",o._emit("load"),o._loadQueue()),e._node.removeEventListener(n._canPlayEvent,e._loadFn,!1)},_endListener:function(){var e=this,n=e._parent;n._duration===1/0&&(n._duration=Math.ceil(10*e._node.duration)/10,n._sprite.__default[1]===1/0&&(n._sprite.__default[1]=1e3*n._duration),n._ended(e)),e._node.removeEventListener("ended",e._endFn,!1)}};var r={},a=function(e){var n=e._src;if(r[n])return e._duration=r[n].duration,void i(e);if(/^data:[^;]+;base64,/.test(n)){for(var o=atob(n.split(",")[1]),t=new Uint8Array(o.length),a=0;a0?(r[o._src]=e,i(o,e)):t()};"undefined"!=typeof Promise&&1===n.ctx.decodeAudioData.length?n.ctx.decodeAudioData(e).then(a).catch(t):n.ctx.decodeAudioData(e,a,t)},i=function(e,n){n&&!e._duration&&(e._duration=n.duration),0===Object.keys(e._sprite).length&&(e._sprite={__default:[0,1e3*e._duration]}),"loaded"!==e._state&&(e._state="loaded",e._emit("load"),e._loadQueue())},_=function(){if(n.usingWebAudio){try{"undefined"!=typeof AudioContext?n.ctx=new AudioContext:"undefined"!=typeof webkitAudioContext?n.ctx=new webkitAudioContext:n.usingWebAudio=!1}catch(e){n.usingWebAudio=!1}n.ctx||(n.usingWebAudio=!1);var e=/iP(hone|od|ad)/.test(n._navigator&&n._navigator.platform),o=n._navigator&&n._navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/),t=o?parseInt(o[1],10):null;if(e&&t&&t<9){var r=/safari/.test(n._navigator&&n._navigator.userAgent.toLowerCase());n._navigator&&!r&&(n.usingWebAudio=!1)}n.usingWebAudio&&(n.masterGain=void 0===n.ctx.createGain?n.ctx.createGainNode():n.ctx.createGain(),n.masterGain.gain.setValueAtTime(n._muted?0:n._volume,n.ctx.currentTime),n.masterGain.connect(n.ctx.destination)),n._setup()}};"function"==typeof define&&define.amd&&define([],function(){return{Howler:n,Howl:o}}),"undefined"!=typeof exports&&(exports.Howler=n,exports.Howl=o),"undefined"!=typeof global?(global.HowlerGlobal=e,global.Howler=n,global.Howl=o,global.Sound=t):"undefined"!=typeof window&&(window.HowlerGlobal=e,window.Howler=n,window.Howl=o,window.Sound=t)}();
+/*! Spatial Plugin */
+!function(){"use strict";HowlerGlobal.prototype._pos=[0,0,0],HowlerGlobal.prototype._orientation=[0,0,-1,0,1,0],HowlerGlobal.prototype.stereo=function(e){var n=this;if(!n.ctx||!n.ctx.listener)return n;for(var t=n._howls.length-1;t>=0;t--)n._howls[t].stereo(e);return n},HowlerGlobal.prototype.pos=function(e,n,t){var r=this;return r.ctx&&r.ctx.listener?(n="number"!=typeof n?r._pos[1]:n,t="number"!=typeof t?r._pos[2]:t,"number"!=typeof e?r._pos:(r._pos=[e,n,t],void 0!==r.ctx.listener.positionX?(r.ctx.listener.positionX.setTargetAtTime(r._pos[0],Howler.ctx.currentTime,.1),r.ctx.listener.positionY.setTargetAtTime(r._pos[1],Howler.ctx.currentTime,.1),r.ctx.listener.positionZ.setTargetAtTime(r._pos[2],Howler.ctx.currentTime,.1)):r.ctx.listener.setPosition(r._pos[0],r._pos[1],r._pos[2]),r)):r},HowlerGlobal.prototype.orientation=function(e,n,t,r,o,i){var a=this;if(!a.ctx||!a.ctx.listener)return a;var p=a._orientation;return n="number"!=typeof n?p[1]:n,t="number"!=typeof t?p[2]:t,r="number"!=typeof r?p[3]:r,o="number"!=typeof o?p[4]:o,i="number"!=typeof i?p[5]:i,"number"!=typeof e?p:(a._orientation=[e,n,t,r,o,i],void 0!==a.ctx.listener.forwardX?(a.ctx.listener.forwardX.setTargetAtTime(e,Howler.ctx.currentTime,.1),a.ctx.listener.forwardY.setTargetAtTime(n,Howler.ctx.currentTime,.1),a.ctx.listener.forwardZ.setTargetAtTime(t,Howler.ctx.currentTime,.1),a.ctx.listener.upX.setTargetAtTime(r,Howler.ctx.currentTime,.1),a.ctx.listener.upY.setTargetAtTime(o,Howler.ctx.currentTime,.1),a.ctx.listener.upZ.setTargetAtTime(i,Howler.ctx.currentTime,.1)):a.ctx.listener.setOrientation(e,n,t,r,o,i),a)},Howl.prototype.init=function(e){return function(n){var t=this;return t._orientation=n.orientation||[1,0,0],t._stereo=n.stereo||null,t._pos=n.pos||null,t._pannerAttr={coneInnerAngle:void 0!==n.coneInnerAngle?n.coneInnerAngle:360,coneOuterAngle:void 0!==n.coneOuterAngle?n.coneOuterAngle:360,coneOuterGain:void 0!==n.coneOuterGain?n.coneOuterGain:0,distanceModel:void 0!==n.distanceModel?n.distanceModel:"inverse",maxDistance:void 0!==n.maxDistance?n.maxDistance:1e4,panningModel:void 0!==n.panningModel?n.panningModel:"HRTF",refDistance:void 0!==n.refDistance?n.refDistance:1,rolloffFactor:void 0!==n.rolloffFactor?n.rolloffFactor:1},t._onstereo=n.onstereo?[{fn:n.onstereo}]:[],t._onpos=n.onpos?[{fn:n.onpos}]:[],t._onorientation=n.onorientation?[{fn:n.onorientation}]:[],e.call(this,n)}}(Howl.prototype.init),Howl.prototype.stereo=function(n,t){var r=this;if(!r._webAudio)return r;if("loaded"!==r._state)return r._queue.push({event:"stereo",action:function(){r.stereo(n,t)}}),r;var o=void 0===Howler.ctx.createStereoPanner?"spatial":"stereo";if(void 0===t){if("number"!=typeof n)return r._stereo;r._stereo=n,r._pos=[n,0,0]}for(var i=r._getSoundIds(t),a=0;a=0;t--)n._howls[t].stereo(e);return n},HowlerGlobal.prototype.pos=function(e,n,t){var r=this;return r.ctx&&r.ctx.listener?(n="number"!=typeof n?r._pos[1]:n,t="number"!=typeof t?r._pos[2]:t,"number"!=typeof e?r._pos:(r._pos=[e,n,t],void 0!==r.ctx.listener.positionX?(r.ctx.listener.positionX.setTargetAtTime(r._pos[0],Howler.ctx.currentTime,.1),r.ctx.listener.positionY.setTargetAtTime(r._pos[1],Howler.ctx.currentTime,.1),r.ctx.listener.positionZ.setTargetAtTime(r._pos[2],Howler.ctx.currentTime,.1)):r.ctx.listener.setPosition(r._pos[0],r._pos[1],r._pos[2]),r)):r},HowlerGlobal.prototype.orientation=function(e,n,t,r,o,i){var a=this;if(!a.ctx||!a.ctx.listener)return a;var p=a._orientation;return n="number"!=typeof n?p[1]:n,t="number"!=typeof t?p[2]:t,r="number"!=typeof r?p[3]:r,o="number"!=typeof o?p[4]:o,i="number"!=typeof i?p[5]:i,"number"!=typeof e?p:(a._orientation=[e,n,t,r,o,i],void 0!==a.ctx.listener.forwardX?(a.ctx.listener.forwardX.setTargetAtTime(e,Howler.ctx.currentTime,.1),a.ctx.listener.forwardY.setTargetAtTime(n,Howler.ctx.currentTime,.1),a.ctx.listener.forwardZ.setTargetAtTime(t,Howler.ctx.currentTime,.1),a.ctx.listener.upX.setTargetAtTime(r,Howler.ctx.currentTime,.1),a.ctx.listener.upY.setTargetAtTime(o,Howler.ctx.currentTime,.1),a.ctx.listener.upZ.setTargetAtTime(i,Howler.ctx.currentTime,.1)):a.ctx.listener.setOrientation(e,n,t,r,o,i),a)},Howl.prototype.init=function(e){return function(n){var t=this;return t._orientation=n.orientation||[1,0,0],t._stereo=n.stereo||null,t._pos=n.pos||null,t._pannerAttr={coneInnerAngle:void 0!==n.coneInnerAngle?n.coneInnerAngle:360,coneOuterAngle:void 0!==n.coneOuterAngle?n.coneOuterAngle:360,coneOuterGain:void 0!==n.coneOuterGain?n.coneOuterGain:0,distanceModel:void 0!==n.distanceModel?n.distanceModel:"inverse",maxDistance:void 0!==n.maxDistance?n.maxDistance:1e4,panningModel:void 0!==n.panningModel?n.panningModel:"HRTF",refDistance:void 0!==n.refDistance?n.refDistance:1,rolloffFactor:void 0!==n.rolloffFactor?n.rolloffFactor:1},t._onstereo=n.onstereo?[{fn:n.onstereo}]:[],t._onpos=n.onpos?[{fn:n.onpos}]:[],t._onorientation=n.onorientation?[{fn:n.onorientation}]:[],e.call(this,n)}}(Howl.prototype.init),Howl.prototype.stereo=function(n,t){var r=this;if(!r._webAudio)return r;if("loaded"!==r._state)return r._queue.push({event:"stereo",action:function(){r.stereo(n,t)}}),r;var o=void 0===Howler.ctx.createStereoPanner?"spatial":"stereo";if(void 0===t){if("number"!=typeof n)return r._stereo;r._stereo=n,r._pos=[n,0,0]}for(var i=r._getSoundIds(t),a=0;a dist/howler.min.js && awk '(NR>1 && FNR==1){printf (\"\\n\\n\")};1' src/howler.core.js src/plugins/howler.spatial.js > dist/howler.js",
+ "release": "VERSION=`printf 'v' && node -e 'console.log(require(\"./package.json\").version)'` && git tag $VERSION && git push && git push origin $VERSION && npm publish"
+ },
+ "version": "2.2.4"
+}
diff --git a/uni_modules/c-svga/node_modules/howler/src/howler.core.js b/uni_modules/c-svga/node_modules/howler/src/howler.core.js
new file mode 100644
index 0000000..5198bdf
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/howler/src/howler.core.js
@@ -0,0 +1,2587 @@
+/*!
+ * howler.js v2.2.4
+ * howlerjs.com
+ *
+ * (c) 2013-2020, James Simpson of GoldFire Studios
+ * goldfirestudios.com
+ *
+ * MIT License
+ */
+
+(function() {
+
+ 'use strict';
+
+ /** Global Methods **/
+ /***************************************************************************/
+
+ /**
+ * Create the global controller. All contained methods and properties apply
+ * to all sounds that are currently playing or will be in the future.
+ */
+ var HowlerGlobal = function() {
+ this.init();
+ };
+ HowlerGlobal.prototype = {
+ /**
+ * Initialize the global Howler object.
+ * @return {Howler}
+ */
+ init: function() {
+ var self = this || Howler;
+
+ // Create a global ID counter.
+ self._counter = 1000;
+
+ // Pool of unlocked HTML5 Audio objects.
+ self._html5AudioPool = [];
+ self.html5PoolSize = 10;
+
+ // Internal properties.
+ self._codecs = {};
+ self._howls = [];
+ self._muted = false;
+ self._volume = 1;
+ self._canPlayEvent = 'canplaythrough';
+ self._navigator = (typeof window !== 'undefined' && window.navigator) ? window.navigator : null;
+
+ // Public properties.
+ self.masterGain = null;
+ self.noAudio = false;
+ self.usingWebAudio = true;
+ self.autoSuspend = true;
+ self.ctx = null;
+
+ // Set to false to disable the auto audio unlocker.
+ self.autoUnlock = true;
+
+ // Setup the various state values for global tracking.
+ self._setup();
+
+ return self;
+ },
+
+ /**
+ * Get/set the global volume for all sounds.
+ * @param {Float} vol Volume from 0.0 to 1.0.
+ * @return {Howler/Float} Returns self or current volume.
+ */
+ volume: function(vol) {
+ var self = this || Howler;
+ vol = parseFloat(vol);
+
+ // If we don't have an AudioContext created yet, run the setup.
+ if (!self.ctx) {
+ setupAudioContext();
+ }
+
+ if (typeof vol !== 'undefined' && vol >= 0 && vol <= 1) {
+ self._volume = vol;
+
+ // Don't update any of the nodes if we are muted.
+ if (self._muted) {
+ return self;
+ }
+
+ // When using Web Audio, we just need to adjust the master gain.
+ if (self.usingWebAudio) {
+ self.masterGain.gain.setValueAtTime(vol, Howler.ctx.currentTime);
+ }
+
+ // Loop through and change volume for all HTML5 audio nodes.
+ for (var i=0; i=0; i--) {
+ self._howls[i].unload();
+ }
+
+ // Create a new AudioContext to make sure it is fully reset.
+ if (self.usingWebAudio && self.ctx && typeof self.ctx.close !== 'undefined') {
+ self.ctx.close();
+ self.ctx = null;
+ setupAudioContext();
+ }
+
+ return self;
+ },
+
+ /**
+ * Check for codec support of specific extension.
+ * @param {String} ext Audio file extention.
+ * @return {Boolean}
+ */
+ codecs: function(ext) {
+ return (this || Howler)._codecs[ext.replace(/^x-/, '')];
+ },
+
+ /**
+ * Setup various state values for global tracking.
+ * @return {Howler}
+ */
+ _setup: function() {
+ var self = this || Howler;
+
+ // Keeps track of the suspend/resume state of the AudioContext.
+ self.state = self.ctx ? self.ctx.state || 'suspended' : 'suspended';
+
+ // Automatically begin the 30-second suspend process
+ self._autoSuspend();
+
+ // Check if audio is available.
+ if (!self.usingWebAudio) {
+ // No audio is available on this system if noAudio is set to true.
+ if (typeof Audio !== 'undefined') {
+ try {
+ var test = new Audio();
+
+ // Check if the canplaythrough event is available.
+ if (typeof test.oncanplaythrough === 'undefined') {
+ self._canPlayEvent = 'canplay';
+ }
+ } catch(e) {
+ self.noAudio = true;
+ }
+ } else {
+ self.noAudio = true;
+ }
+ }
+
+ // Test to make sure audio isn't disabled in Internet Explorer.
+ try {
+ var test = new Audio();
+ if (test.muted) {
+ self.noAudio = true;
+ }
+ } catch (e) {}
+
+ // Check for supported codecs.
+ if (!self.noAudio) {
+ self._setupCodecs();
+ }
+
+ return self;
+ },
+
+ /**
+ * Check for browser support for various codecs and cache the results.
+ * @return {Howler}
+ */
+ _setupCodecs: function() {
+ var self = this || Howler;
+ var audioTest = null;
+
+ // Must wrap in a try/catch because IE11 in server mode throws an error.
+ try {
+ audioTest = (typeof Audio !== 'undefined') ? new Audio() : null;
+ } catch (err) {
+ return self;
+ }
+
+ if (!audioTest || typeof audioTest.canPlayType !== 'function') {
+ return self;
+ }
+
+ var mpegTest = audioTest.canPlayType('audio/mpeg;').replace(/^no$/, '');
+
+ // Opera version <33 has mixed MP3 support, so we need to check for and block it.
+ var ua = self._navigator ? self._navigator.userAgent : '';
+ var checkOpera = ua.match(/OPR\/(\d+)/g);
+ var isOldOpera = (checkOpera && parseInt(checkOpera[0].split('/')[1], 10) < 33);
+ var checkSafari = ua.indexOf('Safari') !== -1 && ua.indexOf('Chrome') === -1;
+ var safariVersion = ua.match(/Version\/(.*?) /);
+ var isOldSafari = (checkSafari && safariVersion && parseInt(safariVersion[1], 10) < 15);
+
+ self._codecs = {
+ mp3: !!(!isOldOpera && (mpegTest || audioTest.canPlayType('audio/mp3;').replace(/^no$/, ''))),
+ mpeg: !!mpegTest,
+ opus: !!audioTest.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/, ''),
+ ogg: !!audioTest.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ''),
+ oga: !!audioTest.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ''),
+ wav: !!(audioTest.canPlayType('audio/wav; codecs="1"') || audioTest.canPlayType('audio/wav')).replace(/^no$/, ''),
+ aac: !!audioTest.canPlayType('audio/aac;').replace(/^no$/, ''),
+ caf: !!audioTest.canPlayType('audio/x-caf;').replace(/^no$/, ''),
+ m4a: !!(audioTest.canPlayType('audio/x-m4a;') || audioTest.canPlayType('audio/m4a;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),
+ m4b: !!(audioTest.canPlayType('audio/x-m4b;') || audioTest.canPlayType('audio/m4b;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),
+ mp4: !!(audioTest.canPlayType('audio/x-mp4;') || audioTest.canPlayType('audio/mp4;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),
+ weba: !!(!isOldSafari && audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, '')),
+ webm: !!(!isOldSafari && audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, '')),
+ dolby: !!audioTest.canPlayType('audio/mp4; codecs="ec-3"').replace(/^no$/, ''),
+ flac: !!(audioTest.canPlayType('audio/x-flac;') || audioTest.canPlayType('audio/flac;')).replace(/^no$/, '')
+ };
+
+ return self;
+ },
+
+ /**
+ * Some browsers/devices will only allow audio to be played after a user interaction.
+ * Attempt to automatically unlock audio on the first user interaction.
+ * Concept from: http://paulbakaus.com/tutorials/html5/web-audio-on-ios/
+ * @return {Howler}
+ */
+ _unlockAudio: function() {
+ var self = this || Howler;
+
+ // Only run this if Web Audio is supported and it hasn't already been unlocked.
+ if (self._audioUnlocked || !self.ctx) {
+ return;
+ }
+
+ self._audioUnlocked = false;
+ self.autoUnlock = false;
+
+ // Some mobile devices/platforms have distortion issues when opening/closing tabs and/or web views.
+ // Bugs in the browser (especially Mobile Safari) can cause the sampleRate to change from 44100 to 48000.
+ // By calling Howler.unload(), we create a new AudioContext with the correct sampleRate.
+ if (!self._mobileUnloaded && self.ctx.sampleRate !== 44100) {
+ self._mobileUnloaded = true;
+ self.unload();
+ }
+
+ // Scratch buffer for enabling iOS to dispose of web audio buffers correctly, as per:
+ // http://stackoverflow.com/questions/24119684
+ self._scratchBuffer = self.ctx.createBuffer(1, 1, 22050);
+
+ // Call this method on touch start to create and play a buffer,
+ // then check if the audio actually played to determine if
+ // audio has now been unlocked on iOS, Android, etc.
+ var unlock = function(e) {
+ // Create a pool of unlocked HTML5 Audio objects that can
+ // be used for playing sounds without user interaction. HTML5
+ // Audio objects must be individually unlocked, as opposed
+ // to the WebAudio API which only needs a single activation.
+ // This must occur before WebAudio setup or the source.onended
+ // event will not fire.
+ while (self._html5AudioPool.length < self.html5PoolSize) {
+ try {
+ var audioNode = new Audio();
+
+ // Mark this Audio object as unlocked to ensure it can get returned
+ // to the unlocked pool when released.
+ audioNode._unlocked = true;
+
+ // Add the audio node to the pool.
+ self._releaseHtml5Audio(audioNode);
+ } catch (e) {
+ self.noAudio = true;
+ break;
+ }
+ }
+
+ // Loop through any assigned audio nodes and unlock them.
+ for (var i=0; i= 55.
+ if (typeof self.ctx.resume === 'function') {
+ self.ctx.resume();
+ }
+
+ // Setup a timeout to check that we are unlocked on the next event loop.
+ source.onended = function() {
+ source.disconnect(0);
+
+ // Update the unlocked state and prevent this check from happening again.
+ self._audioUnlocked = true;
+
+ // Remove the touch start listener.
+ document.removeEventListener('touchstart', unlock, true);
+ document.removeEventListener('touchend', unlock, true);
+ document.removeEventListener('click', unlock, true);
+ document.removeEventListener('keydown', unlock, true);
+
+ // Let all sounds know that audio has been unlocked.
+ for (var i=0; i 0 ? sound._seek : self._sprite[sprite][0] / 1000);
+ var duration = Math.max(0, ((self._sprite[sprite][0] + self._sprite[sprite][1]) / 1000) - seek);
+ var timeout = (duration * 1000) / Math.abs(sound._rate);
+ var start = self._sprite[sprite][0] / 1000;
+ var stop = (self._sprite[sprite][0] + self._sprite[sprite][1]) / 1000;
+ sound._sprite = sprite;
+
+ // Mark the sound as ended instantly so that this async playback
+ // doesn't get grabbed by another call to play while this one waits to start.
+ sound._ended = false;
+
+ // Update the parameters of the sound.
+ var setParams = function() {
+ sound._paused = false;
+ sound._seek = seek;
+ sound._start = start;
+ sound._stop = stop;
+ sound._loop = !!(sound._loop || self._sprite[sprite][2]);
+ };
+
+ // End the sound instantly if seek is at the end.
+ if (seek >= stop) {
+ self._ended(sound);
+ return;
+ }
+
+ // Begin the actual playback.
+ var node = sound._node;
+ if (self._webAudio) {
+ // Fire this when the sound is ready to play to begin Web Audio playback.
+ var playWebAudio = function() {
+ self._playLock = false;
+ setParams();
+ self._refreshBuffer(sound);
+
+ // Setup the playback params.
+ var vol = (sound._muted || self._muted) ? 0 : sound._volume;
+ node.gain.setValueAtTime(vol, Howler.ctx.currentTime);
+ sound._playStart = Howler.ctx.currentTime;
+
+ // Play the sound using the supported method.
+ if (typeof node.bufferSource.start === 'undefined') {
+ sound._loop ? node.bufferSource.noteGrainOn(0, seek, 86400) : node.bufferSource.noteGrainOn(0, seek, duration);
+ } else {
+ sound._loop ? node.bufferSource.start(0, seek, 86400) : node.bufferSource.start(0, seek, duration);
+ }
+
+ // Start a new timer if none is present.
+ if (timeout !== Infinity) {
+ self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);
+ }
+
+ if (!internal) {
+ setTimeout(function() {
+ self._emit('play', sound._id);
+ self._loadQueue();
+ }, 0);
+ }
+ };
+
+ if (Howler.state === 'running' && Howler.ctx.state !== 'interrupted') {
+ playWebAudio();
+ } else {
+ self._playLock = true;
+
+ // Wait for the audio context to resume before playing.
+ self.once('resume', playWebAudio);
+
+ // Cancel the end timer.
+ self._clearTimer(sound._id);
+ }
+ } else {
+ // Fire this when the sound is ready to play to begin HTML5 Audio playback.
+ var playHtml5 = function() {
+ node.currentTime = seek;
+ node.muted = sound._muted || self._muted || Howler._muted || node.muted;
+ node.volume = sound._volume * Howler.volume();
+ node.playbackRate = sound._rate;
+
+ // Some browsers will throw an error if this is called without user interaction.
+ try {
+ var play = node.play();
+
+ // Support older browsers that don't support promises, and thus don't have this issue.
+ if (play && typeof Promise !== 'undefined' && (play instanceof Promise || typeof play.then === 'function')) {
+ // Implements a lock to prevent DOMException: The play() request was interrupted by a call to pause().
+ self._playLock = true;
+
+ // Set param values immediately.
+ setParams();
+
+ // Releases the lock and executes queued actions.
+ play
+ .then(function() {
+ self._playLock = false;
+ node._unlocked = true;
+ if (!internal) {
+ self._emit('play', sound._id);
+ } else {
+ self._loadQueue();
+ }
+ })
+ .catch(function() {
+ self._playLock = false;
+ self._emit('playerror', sound._id, 'Playback was unable to start. This is most commonly an issue ' +
+ 'on mobile devices and Chrome where playback was not within a user interaction.');
+
+ // Reset the ended and paused values.
+ sound._ended = true;
+ sound._paused = true;
+ });
+ } else if (!internal) {
+ self._playLock = false;
+ setParams();
+ self._emit('play', sound._id);
+ }
+
+ // Setting rate before playing won't work in IE, so we set it again here.
+ node.playbackRate = sound._rate;
+
+ // If the node is still paused, then we can assume there was a playback issue.
+ if (node.paused) {
+ self._emit('playerror', sound._id, 'Playback was unable to start. This is most commonly an issue ' +
+ 'on mobile devices and Chrome where playback was not within a user interaction.');
+ return;
+ }
+
+ // Setup the end timer on sprites or listen for the ended event.
+ if (sprite !== '__default' || sound._loop) {
+ self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);
+ } else {
+ self._endTimers[sound._id] = function() {
+ // Fire ended on this audio node.
+ self._ended(sound);
+
+ // Clear this listener.
+ node.removeEventListener('ended', self._endTimers[sound._id], false);
+ };
+ node.addEventListener('ended', self._endTimers[sound._id], false);
+ }
+ } catch (err) {
+ self._emit('playerror', sound._id, err);
+ }
+ };
+
+ // If this is streaming audio, make sure the src is set and load again.
+ if (node.src === 'data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA') {
+ node.src = self._src;
+ node.load();
+ }
+
+ // Play immediately if ready, or wait for the 'canplaythrough'e vent.
+ var loadedNoReadyState = (window && window.ejecta) || (!node.readyState && Howler._navigator.isCocoonJS);
+ if (node.readyState >= 3 || loadedNoReadyState) {
+ playHtml5();
+ } else {
+ self._playLock = true;
+ self._state = 'loading';
+
+ var listener = function() {
+ self._state = 'loaded';
+
+ // Begin playback.
+ playHtml5();
+
+ // Clear this listener.
+ node.removeEventListener(Howler._canPlayEvent, listener, false);
+ };
+ node.addEventListener(Howler._canPlayEvent, listener, false);
+
+ // Cancel the end timer.
+ self._clearTimer(sound._id);
+ }
+ }
+
+ return sound._id;
+ },
+
+ /**
+ * Pause playback and save current position.
+ * @param {Number} id The sound ID (empty to pause all in group).
+ * @return {Howl}
+ */
+ pause: function(id) {
+ var self = this;
+
+ // If the sound hasn't loaded or a play() promise is pending, add it to the load queue to pause when capable.
+ if (self._state !== 'loaded' || self._playLock) {
+ self._queue.push({
+ event: 'pause',
+ action: function() {
+ self.pause(id);
+ }
+ });
+
+ return self;
+ }
+
+ // If no id is passed, get all ID's to be paused.
+ var ids = self._getSoundIds(id);
+
+ for (var i=0; i Returns the group's volume value.
+ * volume(id) -> Returns the sound id's current volume.
+ * volume(vol) -> Sets the volume of all sounds in this Howl group.
+ * volume(vol, id) -> Sets the volume of passed sound id.
+ * @return {Howl/Number} Returns self or current volume.
+ */
+ volume: function() {
+ var self = this;
+ var args = arguments;
+ var vol, id;
+
+ // Determine the values based on arguments.
+ if (args.length === 0) {
+ // Return the value of the groups' volume.
+ return self._volume;
+ } else if (args.length === 1 || args.length === 2 && typeof args[1] === 'undefined') {
+ // First check if this is an ID, and if not, assume it is a new volume.
+ var ids = self._getSoundIds();
+ var index = ids.indexOf(args[0]);
+ if (index >= 0) {
+ id = parseInt(args[0], 10);
+ } else {
+ vol = parseFloat(args[0]);
+ }
+ } else if (args.length >= 2) {
+ vol = parseFloat(args[0]);
+ id = parseInt(args[1], 10);
+ }
+
+ // Update the volume or return the current volume.
+ var sound;
+ if (typeof vol !== 'undefined' && vol >= 0 && vol <= 1) {
+ // If the sound hasn't loaded, add it to the load queue to change volume when capable.
+ if (self._state !== 'loaded'|| self._playLock) {
+ self._queue.push({
+ event: 'volume',
+ action: function() {
+ self.volume.apply(self, args);
+ }
+ });
+
+ return self;
+ }
+
+ // Set the group volume.
+ if (typeof id === 'undefined') {
+ self._volume = vol;
+ }
+
+ // Update one or all volumes.
+ id = self._getSoundIds(id);
+ for (var i=0; i 0) ? len / steps : len);
+ var lastTick = Date.now();
+
+ // Store the value being faded to.
+ sound._fadeTo = to;
+
+ // Update the volume value on each interval tick.
+ sound._interval = setInterval(function() {
+ // Update the volume based on the time since the last tick.
+ var tick = (Date.now() - lastTick) / len;
+ lastTick = Date.now();
+ vol += diff * tick;
+
+ // Round to within 2 decimal points.
+ vol = Math.round(vol * 100) / 100;
+
+ // Make sure the volume is in the right bounds.
+ if (diff < 0) {
+ vol = Math.max(to, vol);
+ } else {
+ vol = Math.min(to, vol);
+ }
+
+ // Change the volume.
+ if (self._webAudio) {
+ sound._volume = vol;
+ } else {
+ self.volume(vol, sound._id, true);
+ }
+
+ // Set the group's volume.
+ if (isGroup) {
+ self._volume = vol;
+ }
+
+ // When the fade is complete, stop it and fire event.
+ if ((to < from && vol <= to) || (to > from && vol >= to)) {
+ clearInterval(sound._interval);
+ sound._interval = null;
+ sound._fadeTo = null;
+ self.volume(to, sound._id);
+ self._emit('fade', sound._id);
+ }
+ }, stepLen);
+ },
+
+ /**
+ * Internal method that stops the currently playing fade when
+ * a new fade starts, volume is changed or the sound is stopped.
+ * @param {Number} id The sound id.
+ * @return {Howl}
+ */
+ _stopFade: function(id) {
+ var self = this;
+ var sound = self._soundById(id);
+
+ if (sound && sound._interval) {
+ if (self._webAudio) {
+ sound._node.gain.cancelScheduledValues(Howler.ctx.currentTime);
+ }
+
+ clearInterval(sound._interval);
+ sound._interval = null;
+ self.volume(sound._fadeTo, id);
+ sound._fadeTo = null;
+ self._emit('fade', id);
+ }
+
+ return self;
+ },
+
+ /**
+ * Get/set the loop parameter on a sound. This method can optionally take 0, 1 or 2 arguments.
+ * loop() -> Returns the group's loop value.
+ * loop(id) -> Returns the sound id's loop value.
+ * loop(loop) -> Sets the loop value for all sounds in this Howl group.
+ * loop(loop, id) -> Sets the loop value of passed sound id.
+ * @return {Howl/Boolean} Returns self or current loop value.
+ */
+ loop: function() {
+ var self = this;
+ var args = arguments;
+ var loop, id, sound;
+
+ // Determine the values for loop and id.
+ if (args.length === 0) {
+ // Return the grou's loop value.
+ return self._loop;
+ } else if (args.length === 1) {
+ if (typeof args[0] === 'boolean') {
+ loop = args[0];
+ self._loop = loop;
+ } else {
+ // Return this sound's loop value.
+ sound = self._soundById(parseInt(args[0], 10));
+ return sound ? sound._loop : false;
+ }
+ } else if (args.length === 2) {
+ loop = args[0];
+ id = parseInt(args[1], 10);
+ }
+
+ // If no id is passed, get all ID's to be looped.
+ var ids = self._getSoundIds(id);
+ for (var i=0; i Returns the first sound node's current playback rate.
+ * rate(id) -> Returns the sound id's current playback rate.
+ * rate(rate) -> Sets the playback rate of all sounds in this Howl group.
+ * rate(rate, id) -> Sets the playback rate of passed sound id.
+ * @return {Howl/Number} Returns self or the current playback rate.
+ */
+ rate: function() {
+ var self = this;
+ var args = arguments;
+ var rate, id;
+
+ // Determine the values based on arguments.
+ if (args.length === 0) {
+ // We will simply return the current rate of the first node.
+ id = self._sounds[0]._id;
+ } else if (args.length === 1) {
+ // First check if this is an ID, and if not, assume it is a new rate value.
+ var ids = self._getSoundIds();
+ var index = ids.indexOf(args[0]);
+ if (index >= 0) {
+ id = parseInt(args[0], 10);
+ } else {
+ rate = parseFloat(args[0]);
+ }
+ } else if (args.length === 2) {
+ rate = parseFloat(args[0]);
+ id = parseInt(args[1], 10);
+ }
+
+ // Update the playback rate or return the current value.
+ var sound;
+ if (typeof rate === 'number') {
+ // If the sound hasn't loaded, add it to the load queue to change playback rate when capable.
+ if (self._state !== 'loaded' || self._playLock) {
+ self._queue.push({
+ event: 'rate',
+ action: function() {
+ self.rate.apply(self, args);
+ }
+ });
+
+ return self;
+ }
+
+ // Set the group rate.
+ if (typeof id === 'undefined') {
+ self._rate = rate;
+ }
+
+ // Update one or all volumes.
+ id = self._getSoundIds(id);
+ for (var i=0; i Returns the first sound node's current seek position.
+ * seek(id) -> Returns the sound id's current seek position.
+ * seek(seek) -> Sets the seek position of the first sound node.
+ * seek(seek, id) -> Sets the seek position of passed sound id.
+ * @return {Howl/Number} Returns self or the current seek position.
+ */
+ seek: function() {
+ var self = this;
+ var args = arguments;
+ var seek, id;
+
+ // Determine the values based on arguments.
+ if (args.length === 0) {
+ // We will simply return the current position of the first node.
+ if (self._sounds.length) {
+ id = self._sounds[0]._id;
+ }
+ } else if (args.length === 1) {
+ // First check if this is an ID, and if not, assume it is a new seek position.
+ var ids = self._getSoundIds();
+ var index = ids.indexOf(args[0]);
+ if (index >= 0) {
+ id = parseInt(args[0], 10);
+ } else if (self._sounds.length) {
+ id = self._sounds[0]._id;
+ seek = parseFloat(args[0]);
+ }
+ } else if (args.length === 2) {
+ seek = parseFloat(args[0]);
+ id = parseInt(args[1], 10);
+ }
+
+ // If there is no ID, bail out.
+ if (typeof id === 'undefined') {
+ return 0;
+ }
+
+ // If the sound hasn't loaded, add it to the load queue to seek when capable.
+ if (typeof seek === 'number' && (self._state !== 'loaded' || self._playLock)) {
+ self._queue.push({
+ event: 'seek',
+ action: function() {
+ self.seek.apply(self, args);
+ }
+ });
+
+ return self;
+ }
+
+ // Get the sound.
+ var sound = self._soundById(id);
+
+ if (sound) {
+ if (typeof seek === 'number' && seek >= 0) {
+ // Pause the sound and update position for restarting playback.
+ var playing = self.playing(id);
+ if (playing) {
+ self.pause(id, true);
+ }
+
+ // Move the position of the track and cancel timer.
+ sound._seek = seek;
+ sound._ended = false;
+ self._clearTimer(id);
+
+ // Update the seek position for HTML5 Audio.
+ if (!self._webAudio && sound._node && !isNaN(sound._node.duration)) {
+ sound._node.currentTime = seek;
+ }
+
+ // Seek and emit when ready.
+ var seekAndEmit = function() {
+ // Restart the playback if the sound was playing.
+ if (playing) {
+ self.play(id, true);
+ }
+
+ self._emit('seek', id);
+ };
+
+ // Wait for the play lock to be unset before emitting (HTML5 Audio).
+ if (playing && !self._webAudio) {
+ var emitSeek = function() {
+ if (!self._playLock) {
+ seekAndEmit();
+ } else {
+ setTimeout(emitSeek, 0);
+ }
+ };
+ setTimeout(emitSeek, 0);
+ } else {
+ seekAndEmit();
+ }
+ } else {
+ if (self._webAudio) {
+ var realTime = self.playing(id) ? Howler.ctx.currentTime - sound._playStart : 0;
+ var rateSeek = sound._rateSeek ? sound._rateSeek - sound._seek : 0;
+ return sound._seek + (rateSeek + realTime * Math.abs(sound._rate));
+ } else {
+ return sound._node.currentTime;
+ }
+ }
+ }
+
+ return self;
+ },
+
+ /**
+ * Check if a specific sound is currently playing or not (if id is provided), or check if at least one of the sounds in the group is playing or not.
+ * @param {Number} id The sound id to check. If none is passed, the whole sound group is checked.
+ * @return {Boolean} True if playing and false if not.
+ */
+ playing: function(id) {
+ var self = this;
+
+ // Check the passed sound ID (if any).
+ if (typeof id === 'number') {
+ var sound = self._soundById(id);
+ return sound ? !sound._paused : false;
+ }
+
+ // Otherwise, loop through all sounds and check if any are playing.
+ for (var i=0; i= 0) {
+ Howler._howls.splice(index, 1);
+ }
+
+ // Delete this sound from the cache (if no other Howl is using it).
+ var remCache = true;
+ for (i=0; i= 0) {
+ remCache = false;
+ break;
+ }
+ }
+
+ if (cache && remCache) {
+ delete cache[self._src];
+ }
+
+ // Clear global errors.
+ Howler.noAudio = false;
+
+ // Clear out `self`.
+ self._state = 'unloaded';
+ self._sounds = [];
+ self = null;
+
+ return null;
+ },
+
+ /**
+ * Listen to a custom event.
+ * @param {String} event Event name.
+ * @param {Function} fn Listener to call.
+ * @param {Number} id (optional) Only listen to events for this sound.
+ * @param {Number} once (INTERNAL) Marks event to fire only once.
+ * @return {Howl}
+ */
+ on: function(event, fn, id, once) {
+ var self = this;
+ var events = self['_on' + event];
+
+ if (typeof fn === 'function') {
+ events.push(once ? {id: id, fn: fn, once: once} : {id: id, fn: fn});
+ }
+
+ return self;
+ },
+
+ /**
+ * Remove a custom event. Call without parameters to remove all events.
+ * @param {String} event Event name.
+ * @param {Function} fn Listener to remove. Leave empty to remove all.
+ * @param {Number} id (optional) Only remove events for this sound.
+ * @return {Howl}
+ */
+ off: function(event, fn, id) {
+ var self = this;
+ var events = self['_on' + event];
+ var i = 0;
+
+ // Allow passing just an event and ID.
+ if (typeof fn === 'number') {
+ id = fn;
+ fn = null;
+ }
+
+ if (fn || id) {
+ // Loop through event store and remove the passed function.
+ for (i=0; i=0; i--) {
+ // Only fire the listener if the correct ID is used.
+ if (!events[i].id || events[i].id === id || event === 'load') {
+ setTimeout(function(fn) {
+ fn.call(this, id, msg);
+ }.bind(self, events[i].fn), 0);
+
+ // If this event was setup with `once`, remove it.
+ if (events[i].once) {
+ self.off(event, events[i].fn, events[i].id);
+ }
+ }
+ }
+
+ // Pass the event type into load queue so that it can continue stepping.
+ self._loadQueue(event);
+
+ return self;
+ },
+
+ /**
+ * Queue of actions initiated before the sound has loaded.
+ * These will be called in sequence, with the next only firing
+ * after the previous has finished executing (even if async like play).
+ * @return {Howl}
+ */
+ _loadQueue: function(event) {
+ var self = this;
+
+ if (self._queue.length > 0) {
+ var task = self._queue[0];
+
+ // Remove this task if a matching event was passed.
+ if (task.event === event) {
+ self._queue.shift();
+ self._loadQueue();
+ }
+
+ // Run the task if no event type is passed.
+ if (!event) {
+ task.action();
+ }
+ }
+
+ return self;
+ },
+
+ /**
+ * Fired when playback ends at the end of the duration.
+ * @param {Sound} sound The sound object to work with.
+ * @return {Howl}
+ */
+ _ended: function(sound) {
+ var self = this;
+ var sprite = sound._sprite;
+
+ // If we are using IE and there was network latency we may be clipping
+ // audio before it completes playing. Lets check the node to make sure it
+ // believes it has completed, before ending the playback.
+ if (!self._webAudio && sound._node && !sound._node.paused && !sound._node.ended && sound._node.currentTime < sound._stop) {
+ setTimeout(self._ended.bind(self, sound), 100);
+ return self;
+ }
+
+ // Should this sound loop?
+ var loop = !!(sound._loop || self._sprite[sprite][2]);
+
+ // Fire the ended event.
+ self._emit('end', sound._id);
+
+ // Restart the playback for HTML5 Audio loop.
+ if (!self._webAudio && loop) {
+ self.stop(sound._id, true).play(sound._id);
+ }
+
+ // Restart this timer if on a Web Audio loop.
+ if (self._webAudio && loop) {
+ self._emit('play', sound._id);
+ sound._seek = sound._start || 0;
+ sound._rateSeek = 0;
+ sound._playStart = Howler.ctx.currentTime;
+
+ var timeout = ((sound._stop - sound._start) * 1000) / Math.abs(sound._rate);
+ self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);
+ }
+
+ // Mark the node as paused.
+ if (self._webAudio && !loop) {
+ sound._paused = true;
+ sound._ended = true;
+ sound._seek = sound._start || 0;
+ sound._rateSeek = 0;
+ self._clearTimer(sound._id);
+
+ // Clean up the buffer source.
+ self._cleanBuffer(sound._node);
+
+ // Attempt to auto-suspend AudioContext if no sounds are still playing.
+ Howler._autoSuspend();
+ }
+
+ // When using a sprite, end the track.
+ if (!self._webAudio && !loop) {
+ self.stop(sound._id, true);
+ }
+
+ return self;
+ },
+
+ /**
+ * Clear the end timer for a sound playback.
+ * @param {Number} id The sound ID.
+ * @return {Howl}
+ */
+ _clearTimer: function(id) {
+ var self = this;
+
+ if (self._endTimers[id]) {
+ // Clear the timeout or remove the ended listener.
+ if (typeof self._endTimers[id] !== 'function') {
+ clearTimeout(self._endTimers[id]);
+ } else {
+ var sound = self._soundById(id);
+ if (sound && sound._node) {
+ sound._node.removeEventListener('ended', self._endTimers[id], false);
+ }
+ }
+
+ delete self._endTimers[id];
+ }
+
+ return self;
+ },
+
+ /**
+ * Return the sound identified by this ID, or return null.
+ * @param {Number} id Sound ID
+ * @return {Object} Sound object or null.
+ */
+ _soundById: function(id) {
+ var self = this;
+
+ // Loop through all sounds and find the one with this ID.
+ for (var i=0; i=0; i--) {
+ if (cnt <= limit) {
+ return;
+ }
+
+ if (self._sounds[i]._ended) {
+ // Disconnect the audio source when using Web Audio.
+ if (self._webAudio && self._sounds[i]._node) {
+ self._sounds[i]._node.disconnect(0);
+ }
+
+ // Remove sounds until we have the pool size.
+ self._sounds.splice(i, 1);
+ cnt--;
+ }
+ }
+ },
+
+ /**
+ * Get all ID's from the sounds pool.
+ * @param {Number} id Only return one ID if one is passed.
+ * @return {Array} Array of IDs.
+ */
+ _getSoundIds: function(id) {
+ var self = this;
+
+ if (typeof id === 'undefined') {
+ var ids = [];
+ for (var i=0; i= 0;
+
+ if (!node.bufferSource) {
+ return self;
+ }
+
+ if (Howler._scratchBuffer && node.bufferSource) {
+ node.bufferSource.onended = null;
+ node.bufferSource.disconnect(0);
+ if (isIOS) {
+ try { node.bufferSource.buffer = Howler._scratchBuffer; } catch(e) {}
+ }
+ }
+ node.bufferSource = null;
+
+ return self;
+ },
+
+ /**
+ * Set the source to a 0-second silence to stop any downloading (except in IE).
+ * @param {Object} node Audio node to clear.
+ */
+ _clearSound: function(node) {
+ var checkIE = /MSIE |Trident\//.test(Howler._navigator && Howler._navigator.userAgent);
+ if (!checkIE) {
+ node.src = 'data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA';
+ }
+ }
+ };
+
+ /** Single Sound Methods **/
+ /***************************************************************************/
+
+ /**
+ * Setup the sound object, which each node attached to a Howl group is contained in.
+ * @param {Object} howl The Howl parent group.
+ */
+ var Sound = function(howl) {
+ this._parent = howl;
+ this.init();
+ };
+ Sound.prototype = {
+ /**
+ * Initialize a new Sound object.
+ * @return {Sound}
+ */
+ init: function() {
+ var self = this;
+ var parent = self._parent;
+
+ // Setup the default parameters.
+ self._muted = parent._muted;
+ self._loop = parent._loop;
+ self._volume = parent._volume;
+ self._rate = parent._rate;
+ self._seek = 0;
+ self._paused = true;
+ self._ended = true;
+ self._sprite = '__default';
+
+ // Generate a unique ID for this sound.
+ self._id = ++Howler._counter;
+
+ // Add itself to the parent's pool.
+ parent._sounds.push(self);
+
+ // Create the new node.
+ self.create();
+
+ return self;
+ },
+
+ /**
+ * Create and setup a new sound object, whether HTML5 Audio or Web Audio.
+ * @return {Sound}
+ */
+ create: function() {
+ var self = this;
+ var parent = self._parent;
+ var volume = (Howler._muted || self._muted || self._parent._muted) ? 0 : self._volume;
+
+ if (parent._webAudio) {
+ // Create the gain node for controlling volume (the source will connect to this).
+ self._node = (typeof Howler.ctx.createGain === 'undefined') ? Howler.ctx.createGainNode() : Howler.ctx.createGain();
+ self._node.gain.setValueAtTime(volume, Howler.ctx.currentTime);
+ self._node.paused = true;
+ self._node.connect(Howler.masterGain);
+ } else if (!Howler.noAudio) {
+ // Get an unlocked Audio object from the pool.
+ self._node = Howler._obtainHtml5Audio();
+
+ // Listen for errors (http://dev.w3.org/html5/spec-author-view/spec.html#mediaerror).
+ self._errorFn = self._errorListener.bind(self);
+ self._node.addEventListener('error', self._errorFn, false);
+
+ // Listen for 'canplaythrough' event to let us know the sound is ready.
+ self._loadFn = self._loadListener.bind(self);
+ self._node.addEventListener(Howler._canPlayEvent, self._loadFn, false);
+
+ // Listen for the 'ended' event on the sound to account for edge-case where
+ // a finite sound has a duration of Infinity.
+ self._endFn = self._endListener.bind(self);
+ self._node.addEventListener('ended', self._endFn, false);
+
+ // Setup the new audio node.
+ self._node.src = parent._src;
+ self._node.preload = parent._preload === true ? 'auto' : parent._preload;
+ self._node.volume = volume * Howler.volume();
+
+ // Begin loading the source.
+ self._node.load();
+ }
+
+ return self;
+ },
+
+ /**
+ * Reset the parameters of this sound to the original state (for recycle).
+ * @return {Sound}
+ */
+ reset: function() {
+ var self = this;
+ var parent = self._parent;
+
+ // Reset all of the parameters of this sound.
+ self._muted = parent._muted;
+ self._loop = parent._loop;
+ self._volume = parent._volume;
+ self._rate = parent._rate;
+ self._seek = 0;
+ self._rateSeek = 0;
+ self._paused = true;
+ self._ended = true;
+ self._sprite = '__default';
+
+ // Generate a new ID so that it isn't confused with the previous sound.
+ self._id = ++Howler._counter;
+
+ return self;
+ },
+
+ /**
+ * HTML5 Audio error listener callback.
+ */
+ _errorListener: function() {
+ var self = this;
+
+ // Fire an error event and pass back the code.
+ self._parent._emit('loaderror', self._id, self._node.error ? self._node.error.code : 0);
+
+ // Clear the event listener.
+ self._node.removeEventListener('error', self._errorFn, false);
+ },
+
+ /**
+ * HTML5 Audio canplaythrough listener callback.
+ */
+ _loadListener: function() {
+ var self = this;
+ var parent = self._parent;
+
+ // Round up the duration to account for the lower precision in HTML5 Audio.
+ parent._duration = Math.ceil(self._node.duration * 10) / 10;
+
+ // Setup a sprite if none is defined.
+ if (Object.keys(parent._sprite).length === 0) {
+ parent._sprite = {__default: [0, parent._duration * 1000]};
+ }
+
+ if (parent._state !== 'loaded') {
+ parent._state = 'loaded';
+ parent._emit('load');
+ parent._loadQueue();
+ }
+
+ // Clear the event listener.
+ self._node.removeEventListener(Howler._canPlayEvent, self._loadFn, false);
+ },
+
+ /**
+ * HTML5 Audio ended listener callback.
+ */
+ _endListener: function() {
+ var self = this;
+ var parent = self._parent;
+
+ // Only handle the `ended`` event if the duration is Infinity.
+ if (parent._duration === Infinity) {
+ // Update the parent duration to match the real audio duration.
+ // Round up the duration to account for the lower precision in HTML5 Audio.
+ parent._duration = Math.ceil(self._node.duration * 10) / 10;
+
+ // Update the sprite that corresponds to the real duration.
+ if (parent._sprite.__default[1] === Infinity) {
+ parent._sprite.__default[1] = parent._duration * 1000;
+ }
+
+ // Run the regular ended method.
+ parent._ended(self);
+ }
+
+ // Clear the event listener since the duration is now correct.
+ self._node.removeEventListener('ended', self._endFn, false);
+ }
+ };
+
+ /** Helper Methods **/
+ /***************************************************************************/
+
+ var cache = {};
+
+ /**
+ * Buffer a sound from URL, Data URI or cache and decode to audio source (Web Audio API).
+ * @param {Howl} self
+ */
+ var loadBuffer = function(self) {
+ var url = self._src;
+
+ // Check if the buffer has already been cached and use it instead.
+ if (cache[url]) {
+ // Set the duration from the cache.
+ self._duration = cache[url].duration;
+
+ // Load the sound into this Howl.
+ loadSound(self);
+
+ return;
+ }
+
+ if (/^data:[^;]+;base64,/.test(url)) {
+ // Decode the base64 data URI without XHR, since some browsers don't support it.
+ var data = atob(url.split(',')[1]);
+ var dataView = new Uint8Array(data.length);
+ for (var i=0; i 0) {
+ cache[self._src] = buffer;
+ loadSound(self, buffer);
+ } else {
+ error();
+ }
+ };
+
+ // Decode the buffer into an audio source.
+ if (typeof Promise !== 'undefined' && Howler.ctx.decodeAudioData.length === 1) {
+ Howler.ctx.decodeAudioData(arraybuffer).then(success).catch(error);
+ } else {
+ Howler.ctx.decodeAudioData(arraybuffer, success, error);
+ }
+ }
+
+ /**
+ * Sound is now loaded, so finish setting everything up and fire the loaded event.
+ * @param {Howl} self
+ * @param {Object} buffer The decoded buffer sound source.
+ */
+ var loadSound = function(self, buffer) {
+ // Set the duration.
+ if (buffer && !self._duration) {
+ self._duration = buffer.duration;
+ }
+
+ // Setup a sprite if none is defined.
+ if (Object.keys(self._sprite).length === 0) {
+ self._sprite = {__default: [0, self._duration * 1000]};
+ }
+
+ // Fire the loaded event.
+ if (self._state !== 'loaded') {
+ self._state = 'loaded';
+ self._emit('load');
+ self._loadQueue();
+ }
+ };
+
+ /**
+ * Setup the audio context when available, or switch to HTML5 Audio mode.
+ */
+ var setupAudioContext = function() {
+ // If we have already detected that Web Audio isn't supported, don't run this step again.
+ if (!Howler.usingWebAudio) {
+ return;
+ }
+
+ // Check if we are using Web Audio and setup the AudioContext if we are.
+ try {
+ if (typeof AudioContext !== 'undefined') {
+ Howler.ctx = new AudioContext();
+ } else if (typeof webkitAudioContext !== 'undefined') {
+ Howler.ctx = new webkitAudioContext();
+ } else {
+ Howler.usingWebAudio = false;
+ }
+ } catch(e) {
+ Howler.usingWebAudio = false;
+ }
+
+ // If the audio context creation still failed, set using web audio to false.
+ if (!Howler.ctx) {
+ Howler.usingWebAudio = false;
+ }
+
+ // Check if a webview is being used on iOS8 or earlier (rather than the browser).
+ // If it is, disable Web Audio as it causes crashing.
+ var iOS = (/iP(hone|od|ad)/.test(Howler._navigator && Howler._navigator.platform));
+ var appVersion = Howler._navigator && Howler._navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/);
+ var version = appVersion ? parseInt(appVersion[1], 10) : null;
+ if (iOS && version && version < 9) {
+ var safari = /safari/.test(Howler._navigator && Howler._navigator.userAgent.toLowerCase());
+ if (Howler._navigator && !safari) {
+ Howler.usingWebAudio = false;
+ }
+ }
+
+ // Create and expose the master GainNode when using Web Audio (useful for plugins or advanced usage).
+ if (Howler.usingWebAudio) {
+ Howler.masterGain = (typeof Howler.ctx.createGain === 'undefined') ? Howler.ctx.createGainNode() : Howler.ctx.createGain();
+ Howler.masterGain.gain.setValueAtTime(Howler._muted ? 0 : Howler._volume, Howler.ctx.currentTime);
+ Howler.masterGain.connect(Howler.ctx.destination);
+ }
+
+ // Re-run the setup on Howler.
+ Howler._setup();
+ };
+
+ // Add support for AMD (Asynchronous Module Definition) libraries such as require.js.
+ if (typeof define === 'function' && define.amd) {
+ define([], function() {
+ return {
+ Howler: Howler,
+ Howl: Howl
+ };
+ });
+ }
+
+ // Add support for CommonJS libraries such as browserify.
+ if (typeof exports !== 'undefined') {
+ exports.Howler = Howler;
+ exports.Howl = Howl;
+ }
+
+ // Add to global in Node.js (for testing, etc).
+ if (typeof global !== 'undefined') {
+ global.HowlerGlobal = HowlerGlobal;
+ global.Howler = Howler;
+ global.Howl = Howl;
+ global.Sound = Sound;
+ } else if (typeof window !== 'undefined') { // Define globally in case AMD is not available or unused.
+ window.HowlerGlobal = HowlerGlobal;
+ window.Howler = Howler;
+ window.Howl = Howl;
+ window.Sound = Sound;
+ }
+})();
diff --git a/uni_modules/c-svga/node_modules/howler/src/plugins/howler.spatial.js b/uni_modules/c-svga/node_modules/howler/src/plugins/howler.spatial.js
new file mode 100644
index 0000000..6ae0fdc
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/howler/src/plugins/howler.spatial.js
@@ -0,0 +1,659 @@
+/*!
+ * Spatial Plugin - Adds support for stereo and 3D audio where Web Audio is supported.
+ *
+ * howler.js v2.2.4
+ * howlerjs.com
+ *
+ * (c) 2013-2020, James Simpson of GoldFire Studios
+ * goldfirestudios.com
+ *
+ * MIT License
+ */
+
+(function() {
+
+ 'use strict';
+
+ // Setup default properties.
+ HowlerGlobal.prototype._pos = [0, 0, 0];
+ HowlerGlobal.prototype._orientation = [0, 0, -1, 0, 1, 0];
+
+ /** Global Methods **/
+ /***************************************************************************/
+
+ /**
+ * Helper method to update the stereo panning position of all current Howls.
+ * Future Howls will not use this value unless explicitly set.
+ * @param {Number} pan A value of -1.0 is all the way left and 1.0 is all the way right.
+ * @return {Howler/Number} Self or current stereo panning value.
+ */
+ HowlerGlobal.prototype.stereo = function(pan) {
+ var self = this;
+
+ // Stop right here if not using Web Audio.
+ if (!self.ctx || !self.ctx.listener) {
+ return self;
+ }
+
+ // Loop through all Howls and update their stereo panning.
+ for (var i=self._howls.length-1; i>=0; i--) {
+ self._howls[i].stereo(pan);
+ }
+
+ return self;
+ };
+
+ /**
+ * Get/set the position of the listener in 3D cartesian space. Sounds using
+ * 3D position will be relative to the listener's position.
+ * @param {Number} x The x-position of the listener.
+ * @param {Number} y The y-position of the listener.
+ * @param {Number} z The z-position of the listener.
+ * @return {Howler/Array} Self or current listener position.
+ */
+ HowlerGlobal.prototype.pos = function(x, y, z) {
+ var self = this;
+
+ // Stop right here if not using Web Audio.
+ if (!self.ctx || !self.ctx.listener) {
+ return self;
+ }
+
+ // Set the defaults for optional 'y' & 'z'.
+ y = (typeof y !== 'number') ? self._pos[1] : y;
+ z = (typeof z !== 'number') ? self._pos[2] : z;
+
+ if (typeof x === 'number') {
+ self._pos = [x, y, z];
+
+ if (typeof self.ctx.listener.positionX !== 'undefined') {
+ self.ctx.listener.positionX.setTargetAtTime(self._pos[0], Howler.ctx.currentTime, 0.1);
+ self.ctx.listener.positionY.setTargetAtTime(self._pos[1], Howler.ctx.currentTime, 0.1);
+ self.ctx.listener.positionZ.setTargetAtTime(self._pos[2], Howler.ctx.currentTime, 0.1);
+ } else {
+ self.ctx.listener.setPosition(self._pos[0], self._pos[1], self._pos[2]);
+ }
+ } else {
+ return self._pos;
+ }
+
+ return self;
+ };
+
+ /**
+ * Get/set the direction the listener is pointing in the 3D cartesian space.
+ * A front and up vector must be provided. The front is the direction the
+ * face of the listener is pointing, and up is the direction the top of the
+ * listener is pointing. Thus, these values are expected to be at right angles
+ * from each other.
+ * @param {Number} x The x-orientation of the listener.
+ * @param {Number} y The y-orientation of the listener.
+ * @param {Number} z The z-orientation of the listener.
+ * @param {Number} xUp The x-orientation of the top of the listener.
+ * @param {Number} yUp The y-orientation of the top of the listener.
+ * @param {Number} zUp The z-orientation of the top of the listener.
+ * @return {Howler/Array} Returns self or the current orientation vectors.
+ */
+ HowlerGlobal.prototype.orientation = function(x, y, z, xUp, yUp, zUp) {
+ var self = this;
+
+ // Stop right here if not using Web Audio.
+ if (!self.ctx || !self.ctx.listener) {
+ return self;
+ }
+
+ // Set the defaults for optional 'y' & 'z'.
+ var or = self._orientation;
+ y = (typeof y !== 'number') ? or[1] : y;
+ z = (typeof z !== 'number') ? or[2] : z;
+ xUp = (typeof xUp !== 'number') ? or[3] : xUp;
+ yUp = (typeof yUp !== 'number') ? or[4] : yUp;
+ zUp = (typeof zUp !== 'number') ? or[5] : zUp;
+
+ if (typeof x === 'number') {
+ self._orientation = [x, y, z, xUp, yUp, zUp];
+
+ if (typeof self.ctx.listener.forwardX !== 'undefined') {
+ self.ctx.listener.forwardX.setTargetAtTime(x, Howler.ctx.currentTime, 0.1);
+ self.ctx.listener.forwardY.setTargetAtTime(y, Howler.ctx.currentTime, 0.1);
+ self.ctx.listener.forwardZ.setTargetAtTime(z, Howler.ctx.currentTime, 0.1);
+ self.ctx.listener.upX.setTargetAtTime(xUp, Howler.ctx.currentTime, 0.1);
+ self.ctx.listener.upY.setTargetAtTime(yUp, Howler.ctx.currentTime, 0.1);
+ self.ctx.listener.upZ.setTargetAtTime(zUp, Howler.ctx.currentTime, 0.1);
+ } else {
+ self.ctx.listener.setOrientation(x, y, z, xUp, yUp, zUp);
+ }
+ } else {
+ return or;
+ }
+
+ return self;
+ };
+
+ /** Group Methods **/
+ /***************************************************************************/
+
+ /**
+ * Add new properties to the core init.
+ * @param {Function} _super Core init method.
+ * @return {Howl}
+ */
+ Howl.prototype.init = (function(_super) {
+ return function(o) {
+ var self = this;
+
+ // Setup user-defined default properties.
+ self._orientation = o.orientation || [1, 0, 0];
+ self._stereo = o.stereo || null;
+ self._pos = o.pos || null;
+ self._pannerAttr = {
+ coneInnerAngle: typeof o.coneInnerAngle !== 'undefined' ? o.coneInnerAngle : 360,
+ coneOuterAngle: typeof o.coneOuterAngle !== 'undefined' ? o.coneOuterAngle : 360,
+ coneOuterGain: typeof o.coneOuterGain !== 'undefined' ? o.coneOuterGain : 0,
+ distanceModel: typeof o.distanceModel !== 'undefined' ? o.distanceModel : 'inverse',
+ maxDistance: typeof o.maxDistance !== 'undefined' ? o.maxDistance : 10000,
+ panningModel: typeof o.panningModel !== 'undefined' ? o.panningModel : 'HRTF',
+ refDistance: typeof o.refDistance !== 'undefined' ? o.refDistance : 1,
+ rolloffFactor: typeof o.rolloffFactor !== 'undefined' ? o.rolloffFactor : 1
+ };
+
+ // Setup event listeners.
+ self._onstereo = o.onstereo ? [{fn: o.onstereo}] : [];
+ self._onpos = o.onpos ? [{fn: o.onpos}] : [];
+ self._onorientation = o.onorientation ? [{fn: o.onorientation}] : [];
+
+ // Complete initilization with howler.js core's init function.
+ return _super.call(this, o);
+ };
+ })(Howl.prototype.init);
+
+ /**
+ * Get/set the stereo panning of the audio source for this sound or all in the group.
+ * @param {Number} pan A value of -1.0 is all the way left and 1.0 is all the way right.
+ * @param {Number} id (optional) The sound ID. If none is passed, all in group will be updated.
+ * @return {Howl/Number} Returns self or the current stereo panning value.
+ */
+ Howl.prototype.stereo = function(pan, id) {
+ var self = this;
+
+ // Stop right here if not using Web Audio.
+ if (!self._webAudio) {
+ return self;
+ }
+
+ // If the sound hasn't loaded, add it to the load queue to change stereo pan when capable.
+ if (self._state !== 'loaded') {
+ self._queue.push({
+ event: 'stereo',
+ action: function() {
+ self.stereo(pan, id);
+ }
+ });
+
+ return self;
+ }
+
+ // Check for PannerStereoNode support and fallback to PannerNode if it doesn't exist.
+ var pannerType = (typeof Howler.ctx.createStereoPanner === 'undefined') ? 'spatial' : 'stereo';
+
+ // Setup the group's stereo panning if no ID is passed.
+ if (typeof id === 'undefined') {
+ // Return the group's stereo panning if no parameters are passed.
+ if (typeof pan === 'number') {
+ self._stereo = pan;
+ self._pos = [pan, 0, 0];
+ } else {
+ return self._stereo;
+ }
+ }
+
+ // Change the streo panning of one or all sounds in group.
+ var ids = self._getSoundIds(id);
+ for (var i=0; i Returns the group's values.
+ * pannerAttr(id) -> Returns the sound id's values.
+ * pannerAttr(o) -> Set's the values of all sounds in this Howl group.
+ * pannerAttr(o, id) -> Set's the values of passed sound id.
+ *
+ * Attributes:
+ * coneInnerAngle - (360 by default) A parameter for directional audio sources, this is an angle, in degrees,
+ * inside of which there will be no volume reduction.
+ * coneOuterAngle - (360 by default) A parameter for directional audio sources, this is an angle, in degrees,
+ * outside of which the volume will be reduced to a constant value of `coneOuterGain`.
+ * coneOuterGain - (0 by default) A parameter for directional audio sources, this is the gain outside of the
+ * `coneOuterAngle`. It is a linear value in the range `[0, 1]`.
+ * distanceModel - ('inverse' by default) Determines algorithm used to reduce volume as audio moves away from
+ * listener. Can be `linear`, `inverse` or `exponential.
+ * maxDistance - (10000 by default) The maximum distance between source and listener, after which the volume
+ * will not be reduced any further.
+ * refDistance - (1 by default) A reference distance for reducing volume as source moves further from the listener.
+ * This is simply a variable of the distance model and has a different effect depending on which model
+ * is used and the scale of your coordinates. Generally, volume will be equal to 1 at this distance.
+ * rolloffFactor - (1 by default) How quickly the volume reduces as source moves from listener. This is simply a
+ * variable of the distance model and can be in the range of `[0, 1]` with `linear` and `[0, ∞]`
+ * with `inverse` and `exponential`.
+ * panningModel - ('HRTF' by default) Determines which spatialization algorithm is used to position audio.
+ * Can be `HRTF` or `equalpower`.
+ *
+ * @return {Howl/Object} Returns self or current panner attributes.
+ */
+ Howl.prototype.pannerAttr = function() {
+ var self = this;
+ var args = arguments;
+ var o, id, sound;
+
+ // Stop right here if not using Web Audio.
+ if (!self._webAudio) {
+ return self;
+ }
+
+ // Determine the values based on arguments.
+ if (args.length === 0) {
+ // Return the group's panner attribute values.
+ return self._pannerAttr;
+ } else if (args.length === 1) {
+ if (typeof args[0] === 'object') {
+ o = args[0];
+
+ // Set the grou's panner attribute values.
+ if (typeof id === 'undefined') {
+ if (!o.pannerAttr) {
+ o.pannerAttr = {
+ coneInnerAngle: o.coneInnerAngle,
+ coneOuterAngle: o.coneOuterAngle,
+ coneOuterGain: o.coneOuterGain,
+ distanceModel: o.distanceModel,
+ maxDistance: o.maxDistance,
+ refDistance: o.refDistance,
+ rolloffFactor: o.rolloffFactor,
+ panningModel: o.panningModel
+ };
+ }
+
+ self._pannerAttr = {
+ coneInnerAngle: typeof o.pannerAttr.coneInnerAngle !== 'undefined' ? o.pannerAttr.coneInnerAngle : self._coneInnerAngle,
+ coneOuterAngle: typeof o.pannerAttr.coneOuterAngle !== 'undefined' ? o.pannerAttr.coneOuterAngle : self._coneOuterAngle,
+ coneOuterGain: typeof o.pannerAttr.coneOuterGain !== 'undefined' ? o.pannerAttr.coneOuterGain : self._coneOuterGain,
+ distanceModel: typeof o.pannerAttr.distanceModel !== 'undefined' ? o.pannerAttr.distanceModel : self._distanceModel,
+ maxDistance: typeof o.pannerAttr.maxDistance !== 'undefined' ? o.pannerAttr.maxDistance : self._maxDistance,
+ refDistance: typeof o.pannerAttr.refDistance !== 'undefined' ? o.pannerAttr.refDistance : self._refDistance,
+ rolloffFactor: typeof o.pannerAttr.rolloffFactor !== 'undefined' ? o.pannerAttr.rolloffFactor : self._rolloffFactor,
+ panningModel: typeof o.pannerAttr.panningModel !== 'undefined' ? o.pannerAttr.panningModel : self._panningModel
+ };
+ }
+ } else {
+ // Return this sound's panner attribute values.
+ sound = self._soundById(parseInt(args[0], 10));
+ return sound ? sound._pannerAttr : self._pannerAttr;
+ }
+ } else if (args.length === 2) {
+ o = args[0];
+ id = parseInt(args[1], 10);
+ }
+
+ // Update the values of the specified sounds.
+ var ids = self._getSoundIds(id);
+ for (var i=0; i
+
+
+```
+
+3. 在需要播放的时机,这里是 `onLoad`,执行以下代码,即可播放动画。
+
+```js
+const { Parser, Player } = require("../../libs/svgaplayer.weapp"); // 此处替换为 svgaplayer.weapp.js 放置位置
+
+Page({
+ data: {
+ },
+ async onLoad() {
+ try {
+ const parser = new Parser;
+ const player = new Player;
+ await player.setCanvas('#demoCanvas')
+ const videoItem = await parser.load("https://cdn.jsdelivr.net/gh/svga/SVGA-Samples@master/angel.svga");
+ await player.setVideoItem(videoItem);
+ player.startAnimation();
+ } catch (error) {
+ console.log(error);
+ }
+ },
+})
+```
+
+### 原生小程序(支付宝)
+1. 直接复制 `./dist/svgaplayer.weapp.js` 到你的小程序工程目录下。
+
+2. 由于需要使用到[my.getFileSystemManager](https://opendocs.alipay.com/mini/api/0226oc)相关的API,请先为小程序添加[文件管理器](https://opendocs.alipay.com/mini/introduce/022rw2#%E6%B7%BB%E5%8A%A0%E8%83%BD%E5%8A%9B)能力。添加完毕后需要重新预览方可调用相关API。
+
+3. 在需要添加播放器的 `axml` 文件内,添加 `canvas` 组件,注意 canvas 的 id 必填,后面会用到,且type 必须为 2d。因为svga动画所需的各项前置能力支付宝基础库2.7.3以上才全部支持,请确保支付宝小程序已[启用基础库2.0](https://opendocs.alipay.com/mini/framework/lib-upgrade-v2)。
+
+```xml
+
+
+
+
+```
+
+4. 在需要播放的时机,播放svga逻辑请在[onReady事件](https://opendocs.alipay.com/mini/component/canvas)触发之后执行,在这个时刻之前执行可能因native canvas还未初始化完毕而出现异常。
+
+5. 若需要读取本地文件,需要在`mini.project.json`内配置需要读取的内容。例如
+```json
+{
+ "include": [
+ "assets/*.svg"
+ ]
+}
+```
+
+```js
+const { Parser, Player } = require("../../libs/svgaplayer.weapp"); // 此处替换为 svgaplayer.weapp.js 放置位置
+
+Page({
+ data: {
+ },
+ async onCanvasReady() {
+ try {
+ const parser = new Parser;
+ const player = new Player;
+ await player.setCanvas('#demoCanvas')
+ // await player.setCanvas('#demoCanvas', this.selectComponent('#component_id'))
+ const videoItem = await parser.load("https://cdn.jsdelivr.net/gh/svga/SVGA-Samples@master/angel.svga");
+ await player.setVideoItem(videoItem);
+ player.startAnimation();
+ } catch (error) {
+ console.log(error);
+ }
+ },
+})
+```
+
+### Taro
+
+1. 通过 `npm install git+https://github.com/svga/svgaplayer-weapp.git --save` 安装依赖。
+
+2. 参照以下代码添加 Canvas 并配置动画。
+
+```typescript
+import { Component } from 'react'
+import { View, Text, Canvas } from '@tarojs/components'
+import { Parser, Player } from "svgaplayer-weapp";
+
+import "taro-ui/dist/style/components/button.scss" // 按需引入
+import './index.scss'
+
+export default class Index extends Component {
+
+ componentDidMount () {
+ this.loadAnimation();
+ }
+
+ async loadAnimation() {
+ const parser = new Parser;
+ const player = new Player;
+ await player.setCanvas('#demoCanvas')
+ const videoItem = await parser.load("https://cdn.jsdelivr.net/gh/svga/SVGA-Samples@master/angel.svga");
+ await player.setVideoItem(videoItem);
+ player.startAnimation();
+ }
+
+ render () {
+ return (
+
+
+
+ )
+ }
+}
+```
+
+### Types
+
+npm 包已附带 `Types`,可支持 `TypeScript` 代码提示。
+
+## API
+
+### Parser
+
+`load(url: string): Promise`
+
+从网络或本地资源包加载 `VideoEntity`。
+
+### Player
+
+`loops = 0`
+属性,设置当前动画的循环次数,0代表无限循环。
+
+`clearsAfterStop = true`
+属性,为 true 时,表示动画停止播放后默认清空画布。
+
+`fillMode = "Forward"`
+属性,为 Forward 时,表示动画播放结束后保留在最后一帧。为 Backward 时,表示保留在第一帧。
+
+`async setCanvas(selector: string, component?: Component.TrivialInstance): Promise`
+设置目标 canvas,这里需要填入 selector,比如 id="demoCanvas",则填 #demoCanvas。
+如果 Canvas 在组件内,则在第二个参数填入 Component 的实例。
+
+`async setVideoItem(videoItem?: VideoEntity): Promise`
+设置需要播放的 `VideoEntity` 动画实体。
+
+`setContentMode(contentMode: string)`
+设置动画缩放模式,可选值为 Fill / AspectFill / AspectFit。
+
+`startAnimation(reverse: boolean = false)`
+开始播放动画,reverse = true 时则反向播放。
+
+`startAnimationWithRange(range: Range, reverse: boolean = false)`
+开始播放动画,在指定 `Range` 内播放。
+
+`pauseAnimation()`
+暂停播放动画。
+
+`stopAnimation(clear?: boolean)`
+停止播放动画,当 clear 为 true 时,清空画布。
+
+`clear()`
+清空画布
+
+`stepToFrame(frame: number, andPlay: boolean = false)`
+跳转动画的指定帧,andPlay 为 true 时,从该帧开始播放动画。
+
+`stepToPercentage(percentage: number, andPlay: boolean = false)`
+跳转动画的指定进度百分比,andPlay 为 true 时,从该帧开始播放动画。
+
+`async setImage(src: Uint8Array | string, forKey: string): Promise`
+使用图片替换指定元素
+
+`setText(dynamicText: DynamicText, forKey: string)`
+添加文本到指定元素上
+
+`clearDynamicObjects()`
+清空所有替换元素。
+
+`onFinished(callback: () => void)`
+监听动画完成
+
+`onFrame(callback: (frame: number) => void)`
+监听动画播放过程中,当前帧的变化。
+
+`onPercentage(callback: (percentage: number) => void)`
+监听动画播放过程中,当前进度的变化。
+
+### Range
+
+```js
+interface Range {
+ location: number; // 起始帧
+ length: number; // 长度
+}
+```
+
+### DynamicText
+
+```js
+interface DynamicText {
+ text: string;
+ size: number;
+ family: string;
+ color: string;
+ offset: { x: number; y: number };
+}
+```
+
+## 感谢或联系作者
+
+
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/build.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/build.js
new file mode 100644
index 0000000..2caebda
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/build.js
@@ -0,0 +1,13 @@
+var browserify = require("browserify");
+var tsify = require("tsify");
+var tinyify = require("tinyify");
+
+browserify({ standalone: "SVGA" })
+ .add("./src/main.ts")
+ .plugin(tsify, { noImplicitAny: true })
+ .plugin(tinyify, { flat: false })
+ .bundle()
+ .on("error", function (error) {
+ console.error(error.toString());
+ })
+ .pipe(process.stdout);
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/dist/svgaplayer.weapp.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/dist/svgaplayer.weapp.js
new file mode 100644
index 0000000..313d6d4
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/dist/svgaplayer.weapp.js
@@ -0,0 +1 @@
+!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).SVGA=t()}}((function(){return function t(e,r,i){function n(s,a){if(!r[s]){if(!e[s]){var u="function"==typeof require&&require;if(!a&&u)return u(s,!0);if(o)return o(s,!0);var h=new Error("Cannot find module '"+s+"'");throw h.code="MODULE_NOT_FOUND",h}var l=r[s]={exports:{}};e[s][0].call(l.exports,(function(t){return n(e[s][1][t]||t)}),l,l.exports,t,e,r,i)}return r[s].exports}for(var o="function"==typeof require&&require,s=0;s]/g,n=/(?:"([^"\\]*(?:\\.[^"\\]*)*)")/g,o=/(?:'([^'\\]*(?:\\.[^'\\]*)*)')/g,s=/^ *[*/]+ */,a=/^\s*\*?\/*/,u=/\n/g,h=/\s/,l=/\\(.?)/g,f={0:"\0",r:"\r",n:"\n",t:"\t"};function c(t){return t.replace(l,(function(t,e){switch(e){case"\\":case"":return e;default:return f[e]||""}}))}function d(t,e){t=t.toString();var r=0,l=t.length,f=1,d=null,p=null,y=0,m=!1,v=[],g=null;function b(t){return Error("illegal "+t+" (line "+f+")")}function w(e){return t.charAt(e)}function _(r,i){d=t.charAt(r++),y=f,m=!1;var n,o=r-(e?2:3);do{if(--o<0||"\n"===(n=t.charAt(o))){m=!0;break}}while(" "===n||"\t"===n);for(var h=t.substring(r,i).split(u),l=0;l0)return v.shift();if(g)return function(){var e="'"===g?o:n;e.lastIndex=r-1;var i=e.exec(t);if(!i)throw b("string");return r=e.lastIndex,O(g),g=null,c(i[1])}();var s,a,u,d,p;do{if(r===l)return null;for(s=!1;h.test(u=w(r));)if("\n"===u&&++f,++r===l)return null;if("/"===w(r)){if(++r===l)throw b("comment");if("/"===w(r))if(e){if(d=r,p=!1,x(r)){p=!0;do{if((r=k(r))===l)break;r++}while(x(r))}else r=Math.min(l,k(r)+1);p&&_(d,r),f++,s=!0}else{for(p="/"===w(d=r+1);"\n"!==w(++r);)if(r===l)return null;++r,p&&_(d,r-1),++f,s=!0}else{if("*"!==(u=w(r)))return"/";d=r+1,p=e||"*"===w(d);do{if("\n"===u&&++f,++r===l)throw b("comment");a=u,u=w(r)}while("*"!==a||"/"!==u);++r,p&&_(d,r-2),s=!0}}}while(s);var y=r;if(i.lastIndex=0,!i.test(w(y++)))for(;y "+t.len)}function a(t){this.buf=t,this.pos=0,this.len=t.length}var u,h="undefined"!=typeof Uint8Array?function(t){if(t instanceof Uint8Array||Array.isArray(t))return new a(t);if("undefined"!=typeof ArrayBuffer&&t instanceof ArrayBuffer)return new a(new Uint8Array(t));throw Error("illegal buffer")}:function(t){if(Array.isArray(t))return new a(t);throw Error("illegal buffer")};function l(){var t=new i(0,0),e=0;if(!(this.len-this.pos>4)){for(;e<3;++e){if(this.pos>=this.len)throw s(this);if(t.lo=(t.lo|(127&this.buf[this.pos])<<7*e)>>>0,this.buf[this.pos++]<128)return t}return t.lo=(t.lo|(127&this.buf[this.pos++])<<7*e)>>>0,t}for(;e<4;++e)if(t.lo=(t.lo|(127&this.buf[this.pos])<<7*e)>>>0,this.buf[this.pos++]<128)return t;if(t.lo=(t.lo|(127&this.buf[this.pos])<<28)>>>0,t.hi=(t.hi|(127&this.buf[this.pos])>>4)>>>0,this.buf[this.pos++]<128)return t;if(e=0,this.len-this.pos>4){for(;e<5;++e)if(t.hi=(t.hi|(127&this.buf[this.pos])<<7*e+3)>>>0,this.buf[this.pos++]<128)return t}else for(;e<5;++e){if(this.pos>=this.len)throw s(this);if(t.hi=(t.hi|(127&this.buf[this.pos])<<7*e+3)>>>0,this.buf[this.pos++]<128)return t}throw Error("invalid varint encoding")}function f(t,e){return(t[e-4]|t[e-3]<<8|t[e-2]<<16|t[e-1]<<24)>>>0}function c(){if(this.pos+8>this.len)throw s(this,8);return new i(f(this.buf,this.pos+=4),f(this.buf,this.pos+=4))}a.create=o.Buffer?function(t){return(a.create=function(t){return o.Buffer.isBuffer(t)?new(void 0)(t):h(t)})(t)}:h,a.prototype._slice=o.Array.prototype.subarray||o.Array.prototype.slice,a.prototype.uint32=(u=4294967295,function(){if(u=(127&this.buf[this.pos])>>>0,this.buf[this.pos++]<128)return u;if(u=(u|(127&this.buf[this.pos])<<7)>>>0,this.buf[this.pos++]<128)return u;if(u=(u|(127&this.buf[this.pos])<<14)>>>0,this.buf[this.pos++]<128)return u;if(u=(u|(127&this.buf[this.pos])<<21)>>>0,this.buf[this.pos++]<128)return u;if(u=(u|(15&this.buf[this.pos])<<28)>>>0,this.buf[this.pos++]<128)return u;if((this.pos+=5)>this.len)throw this.pos=this.len,s(this,10);return u}),a.prototype.int32=function(){return 0|this.uint32()},a.prototype.sint32=function(){var t=this.uint32();return t>>>1^-(1&t)|0},a.prototype.bool=function(){return 0!==this.uint32()},a.prototype.fixed32=function(){if(this.pos+4>this.len)throw s(this,4);return f(this.buf,this.pos+=4)},a.prototype.sfixed32=function(){if(this.pos+4>this.len)throw s(this,4);return 0|f(this.buf,this.pos+=4)},a.prototype.float=function(){if(this.pos+4>this.len)throw s(this,4);var t=o.float.readFloatLE(this.buf,this.pos);return this.pos+=4,t},a.prototype.double=function(){if(this.pos+8>this.len)throw s(this,4);var t=o.float.readDoubleLE(this.buf,this.pos);return this.pos+=8,t},a.prototype.bytes=function(){var t=this.uint32(),e=this.pos,r=this.pos+t;if(r>this.len)throw s(this,t);return this.pos+=t,Array.isArray(this.buf)?this.buf.slice(e,r):e===r?new this.buf.constructor(0):this._slice.call(this.buf,e,r)},a.prototype.string=function(){var t=this.bytes();return n.read(t,0,t.length)},a.prototype.skip=function(t){if("number"==typeof t){if(this.pos+t>this.len)throw s(this,t);this.pos+=t}else do{if(this.pos>=this.len)throw s(this)}while(128&this.buf[this.pos++]);return this},a.prototype.skipType=function(t){switch(t){case 0:this.skip();break;case 1:this.skip(8);break;case 2:this.skip(this.uint32());break;case 3:for(;4!=(t=7&this.uint32());)this.skipType(t);break;case 5:this.skip(4);break;default:throw Error("invalid wire type "+t+" at offset "+this.pos)}return this},a._configure=function(){i=t(12),n=t(30);var e=o.Long?"toLong":"toNumber";o.merge(a.prototype,{int64:function(){return l.call(this)[e](!1)},uint64:function(){return l.call(this)[e](!0)},sint64:function(){return l.call(this).zzDecode()[e](!1)},fixed64:function(){return c.call(this)[e](!0)},sfixed64:function(){return c.call(this)[e](!1)}})}},{12:12,30:30,31:31}],32:[function(t,e,r){"use strict";var i,n;function o(t,e){return t.name+": "+e+(t.repeated&&"array"!==e?"[]":t.map&&"object"!==e?"{k:"+t.keyType+"}":"")+" expected"}function s(t,e,r,s){var a=s.types;if(t.resolvedType)if(t.resolvedType instanceof i){if(Object.keys(t.resolvedType.values).indexOf(r)<0)return o(t,"enum value")}else{var u=a[e].verify(r);if(u)return t.name+"."+u}else switch(t.type){case"int32":case"uint32":case"sint32":case"fixed32":case"sfixed32":if(!n.isInteger(r))return o(t,"integer");break;case"int64":case"uint64":case"sint64":case"fixed64":case"sfixed64":if(!(n.isInteger(r)||r&&n.isInteger(r.low)&&n.isInteger(r.high)))return o(t,"integer|Long");break;case"float":case"double":if("number"!=typeof r)return o(t,"number");break;case"bool":if("boolean"!=typeof r)return o(t,"boolean");break;case"string":if(!n.isString(r))return o(t,"string");break;case"bytes":if(!(r&&"number"==typeof r.length||n.isString(r)))return o(t,"buffer")}}function a(t,e){switch(t.keyType){case"int32":case"uint32":case"sint32":case"fixed32":case"sfixed32":if(!n.key32Re.test(e))return o(t,"integer key");break;case"int64":case"uint64":case"sint64":case"fixed64":case"sfixed64":if(!n.key64Re.test(e))return o(t,"integer|Long key");break;case"bool":if(!n.key2Re.test(e))return o(t,"boolean key")}}function u(t){return function(e){return function(r){var i;if("object"!=typeof r||null===r)return"object expected";var u,h={};t.oneofsArray.length&&(u={});for(var l=0;l");var i=R();if(!_.test(i))throw z(i,"name");B("=");var n=new a(L(i),q(R()),e,r);W(n,(function(t){if("option"!==t)throw z(t);G(n,t),B(";")}),(function(){tt(n)})),t.add(n)}(r);break;case"required":case"optional":case"repeated":X(r,t);break;case"oneof":!function(t,e){if(!_.test(e=R()))throw z(e,"name");var r=new u(L(e));W(r,(function(t){"option"===t?(G(r,t),B(";")):(F(t),X(r,"optional"))})),t.add(r)}(r,t);break;case"extensions":U(r.extensions||(r.extensions=[]));break;case"reserved":U(r.reserved||(r.reserved=[]),!0);break;default:if(!M||!x.test(t))throw z(t);F(t),X(r,"optional")}})),t.add(r)}(t,e),!0;case"enum":return function(t,e){if(!_.test(e=R()))throw z(e,"name");var r=new h(e);W(r,(function(t){switch(t){case"option":G(r,t),B(";");break;case"reserved":U(r.reserved||(r.reserved=[]),!0);break;default:!function(t,e){if(!_.test(e))throw z(e,"name");B("=");var r=q(R(),!0),i={};W(i,(function(t){if("option"!==t)throw z(t);G(i,t),B(";")}),(function(){tt(i)})),t.add(e,r,i.comment)}(r,t)}})),t.add(r)}(t,e),!0;case"service":return function(t,e){if(!_.test(e=R()))throw z(e,"service name");var r=new l(e);W(r,(function(t){if(!H(r,t)){if("rpc"!==t)throw z(t);!function(t,e){var r=e;if(!_.test(e=R()))throw z(e,"name");var i,n,o,s,a=e;if(B("("),B("stream",!0)&&(n=!0),!x.test(e=R()))throw z(e);if(i=e,B(")"),B("returns"),B("("),B("stream",!0)&&(s=!0),!x.test(e=R()))throw z(e);o=e,B(")");var u=new f(a,r,i,o,n,s);W(u,(function(t){if("option"!==t)throw z(t);G(u,t),B(";")})),t.add(u)}(r,t)}})),t.add(r)}(t,e),!0;case"extend":return function(t,e){if(!x.test(e=R()))throw z(e,"reference");var r=e;W(null,(function(e){switch(e){case"required":case"repeated":case"optional":X(t,e,r);break;default:if(!M||!x.test(e))throw z(e);F(e),X(t,"optional",r)}}))}(t,e),!0}return!1}function W(t,e,r){var i=j.line;if(t&&(t.comment=P(),t.filename=A.filename),B("{",!0)){for(var n;"}"!==(n=R());)e(n);B(";",!0)}else r&&r(),B(";"),t&&"string"!=typeof t.comment&&(t.comment=P(i))}function X(t,e,r){var i=R();if("group"!==i){if(!x.test(i))throw z(i,"type");var n=R();if(!_.test(n))throw z(n,"name");n=L(n),B("=");var a=new s(n,q(R()),i,e,r);W(a,(function(t){if("option"!==t)throw z(t);G(a,t),B(";")}),(function(){tt(a)})),t.add(a),M||!a.repeated||void 0===c.packed[i]&&void 0!==c.basic[i]||a.setOption("packed",!1,!0)}else!function(t,e){var r=R();if(!_.test(r))throw z(r,"name");var i=d.lcFirst(r);r===i&&(r=d.ucFirst(r)),B("=");var n=q(R()),a=new o(r);a.group=!0;var u=new s(i,n,r,e);u.filename=A.filename,W(a,(function(t){switch(t){case"option":G(a,t),B(";");break;case"required":case"optional":case"repeated":X(a,t);break;default:throw z(t)}})),t.add(a).add(u)}(t,e)}function G(t,e){var r=B("(",!0);if(!x.test(e=R()))throw z(e,"name");var i=e;r&&(B(")"),i="("+i+")",e=I(),k.test(e)&&(i+=e,R())),B("="),Y(t,i)}function Y(t,e){if(B("{",!0))do{if(!_.test(T=R()))throw z(T,"name");"{"===I()?Y(t,e+"."+T):(B(":"),"{"===I()?Y(t,e+"."+T):Q(t,e+"."+T,Z(!0)))}while(!B("}",!0));else Q(t,e,Z(!0))}function Q(t,e,r){t.setOption&&t.setOption(e,r)}function tt(t){if(B("[",!0)){do{G(t,"option")}while(B(",",!0));B("]")}return t}for(;null!==(T=R());)switch(T){case"package":if(!C)throw z(T);J();break;case"import":if(!C)throw z(T);$();break;case"syntax":if(!C)throw z(T);K();break;case"option":if(!C)throw z(T);G(D,T),B(";");break;default:if(H(D,T)){C=!1;continue}throw z(T)}return A.filename=null,{package:O,imports:S,weakImports:E,syntax:N,root:e}}A._configure=function(){i=t(27),n=t(23),o=t(28),s=t(9),a=t(13),u=t(18),h=t(8),l=t(26),f=t(15),c=t(29),d=t(31)}},{13:13,15:15,18:18,23:23,26:26,27:27,28:28,29:29,31:31,8:8,9:9}],17:[function(t,e,r){"use strict";var i,n;function o(t,e){if(!i.isString(t))throw TypeError("name must be a string");if(e&&!i.isObject(e))throw TypeError("options must be an object");this.options=e,this.name=t,this.parent=null,this.resolved=!1,this.comment=null,this.filename=null}e.exports=o,o.className="ReflectionObject",Object.defineProperties(o.prototype,{root:{get:function(){for(var t=this;null!==t.parent;)t=t.parent;return t}},fullName:{get:function(){for(var t=[this.name],e=this.parent;e;)t.unshift(e.name),e=e.parent;return t.join(".")}}}),o.prototype.toJSON=function(){throw Error()},o.prototype.onAdd=function(t){this.parent&&this.parent!==t&&this.parent.remove(this),this.parent=t,this.resolved=!1;var e=t.root;e instanceof n&&e._handleAdd(this)},o.prototype.onRemove=function(t){var e=t.root;e instanceof n&&e._handleRemove(this),this.parent=null,this.resolved=!1},o.prototype.resolve=function(){return this.resolved||this.root instanceof n&&(this.resolved=!0),this},o.prototype.getOption=function(t){if(this.options)return this.options[t]},o.prototype.setOption=function(t,e,r){return r&&this.options&&void 0!==this.options[t]||((this.options||(this.options={}))[t]=e),this},o.prototype.setOptions=function(t,e){if(t)for(var r=Object.keys(t),i=0;i=e)return!0;return!1},l.isReservedName=function(t,e){if(t)for(var r=0;r0;){var i=t.shift();if(r.nested&&r.nested[i]){if(!((r=r.nested[i])instanceof l))throw Error("path conflicts with non-namespace objects")}else r.add(r=new l(i))}return e&&r.addJSON(e),r},l.prototype.resolveAll=function(){for(var t=this.nestedArray,e=0;e-1)return i}else if(i instanceof l&&(i=i.lookup(t.slice(1),e,!0)))return i}else for(var n=0;n-1||(n.names.push(t),t in s&&h(t,s[t]))}h(a.name,a.pbJsonStr)},f.prototype.load=function t(e,r,i){"function"==typeof r&&(i=r,r=void 0);var n=this;if(!i)return l.asPromise(t,n,e,r);var a=i===c;function u(t,e){if(i){var r=i;if(i=null,a)throw t;r(t,e)}}function h(t,e){try{if(l.isString(e)&&"{"===e.charAt(0)&&(e=JSON.parse(e)),l.isString(e)){o.filename=t;var i,s=o(e,n,r),h=0;if(s.imports)for(;h-1){var o=t.substring(r);o in s&&(t=o)}if(!(n.files.indexOf(t)>-1))if(n.files.push(t),t in s)a?h(t,s[t]):(++d,setTimeout((function(){--d,h(t,s[t])})));else if(a){var f;try{f=l.fs.readFileSync(t).toString("utf8")}catch(c){return void(e||u(c))}h(t,f)}else++d,l.fetch(t,(function(r,o){--d,i&&(r?e?d||u(null,n):u(r):h(t,o))}))}var d=0;l.isString(e)&&(e=[e]);for(var p,y=0;y-1&&this.deferred.splice(e,1)}}else if(t instanceof u)d.test(t.name)&&delete t.parent[t.name];else if(t instanceof i){for(var r=0;r-1;--r)if(1===e[t[r]]&&void 0!==this[t[r]]&&null!==this[t[r]])return t[r]}}}(this._oneofsArray[r].oneof);i[n]={get:s.getter,set:s.setter}}r&&Object.defineProperties(t.prototype,i)}}}),m.generateConstructor=function(t){return function(e){for(var r,i=0;i-1&&this.oneof.splice(e,1),t.partOf=null,this},s.prototype.onAdd=function(t){o.prototype.onAdd.call(this,t);for(var e=0;e>>3,y=0,m=!1;y>>0:s[r]=a[r]>>>0;break;case"int32":case"sint32":case"sfixed32":l?s[r][h]=0|a[r][h]:s[r]=0|a[r];break;case"uint64":y=!0;case"int64":case"sint64":case"fixed64":case"sfixed64":n.Long?l?s[r][h]=n.Long.fromValue(a[r][h]).unsigned=y:s[r]=n.Long.fromValue(a[r]).unsigned=y:"string"==typeof(l?a[r][h]:a[r])?l?s[r][h]=parseInt(a[r][h],10):s[r]=parseInt(a[r],10):"number"==typeof(l?a[r][h]:a[r])?l?s[r][h]=a[r][h]:s[r]=a[r]:"object"==typeof(l?a[r][h]:a[r])&&(l?s[r][h]=new n.LongBits(a[r][h].low>>>0,a[r][h].high>>>0).toNumber(y):s[r]=new n.LongBits(a[r].low>>>0,a[r].high>>>0).toNumber(y));break;case"bytes":"string"==typeof(l?a[r][h]:a[r])?l?n.base64.decode(a[r][h],s[r][h]=n.newBuffer(n.base64.length(a[r][h])),0):n.base64.decode(a[r],s[r]=n.newBuffer(n.base64.length(a[r])),0):(l?a[r][h]:a[r]).length&&(l?s[r][h]=a[r][h]:s[r]=a[r]);break;case"string":l?s[r][h]=String(a[r][h]):s[r]=String(a[r]);break;case"bool":l?s[r][h]=Boolean(a[r][h]):s[r]=Boolean(a[r])}}}function a(t,e,r,o){var s=o.m,a=o.d,u=o.types,h=o.ksi,l=o.o,f=void 0!==h;if(t.resolvedType)t.resolvedType instanceof i?f?a[r][h]=l.enums===String?u[e].values[s[r][h]]:s[r][h]:a[r]=l.enums===String?u[e].values[s[r]]:s[r]:f?a[r][h]=u[e].toObject(s[r][h],l):a[r]=u[e].toObject(s[r],l);else{var c=!1;switch(t.type){case"double":case"float":f?a[r][h]=l.json&&!isFinite(s[r][h])?String(s[r][h]):s[r][h]:a[r]=l.json&&!isFinite(s[r])?String(s[r]):s[r];break;case"uint64":c=!0;case"int64":case"sint64":case"fixed64":case"sfixed64":"number"==typeof s[r][h]?f?a[r][h]=l.longs===String?String(s[r][h]):s[r][h]:a[r]=l.longs===String?String(s[r]):s[r]:f?a[r][h]=l.longs===String?n.Long.prototype.toString.call(s[r][h]):l.longs===Number?new n.LongBits(s[r][h].low>>>0,s[r][h].high>>>0).toNumber(c):s[r][h]:a[r]=l.longs===String?n.Long.prototype.toString.call(s[r]):l.longs===Number?new n.LongBits(s[r].low>>>0,s[r].high>>>0).toNumber(c):s[r];break;case"bytes":f?a[r][h]=l.bytes===String?n.base64.encode(s[r][h],0,s[r][h].length):l.bytes===Array?Array.prototype.slice.call(s[r][h]):s[r][h]:a[r]=l.bytes===String?n.base64.encode(s[r],0,s[r].length):l.bytes===Array?Array.prototype.slice.call(s[r]):s[r];break;default:f?a[r][h]=s[r][h]:a[r]=s[r]}}}o._configure=function(){i=t(8),n=t(31)},o.fromObject=function(t){var e=t.fieldsArray;return function(t){return function(r){if(r instanceof this.ctor)return r;if(!e.length)return new this.ctor;for(var o=new this.ctor,a=0;a>>7|t.hi<<25)>>>0,t.hi>>>=7;for(;t.lo>127;)e[r++]=127&t.lo|128,t.lo=t.lo>>>7;e[r++]=t.lo}function d(t,e,r){e[r]=255&t,e[r+1]=t>>>8&255,e[r+2]=t>>>16&255,e[r+3]=t>>>24}h.create=n.Buffer?function(){return(h.create=function(){return new(void 0)})()}:function(){return new h},h.alloc=function(t){return new n.Array(t)},n.Array!==Array&&(h.alloc=n.pool(h.alloc,n.Array.prototype.subarray)),h.prototype._push=function(t,e,r){return this.tail=this.tail.next=new s(t,e,r),this.len+=e,this},f.prototype=Object.create(s.prototype),f.prototype.fn=function(t,e,r){for(;t>127;)e[r++]=127&t|128,t>>>=7;e[r]=t},h.prototype.uint32=function(t){return this.len+=(this.tail=this.tail.next=new f((t>>>=0)<128?1:t<16384?2:t<2097152?3:t<268435456?4:5,t)).len,this},h.prototype.int32=function(t){return t<0?this._push(c,10,i.fromNumber(t)):this.uint32(t)},h.prototype.sint32=function(t){return this.uint32((t<<1^t>>31)>>>0)},h.prototype.uint64=function(t){var e=i.from(t);return this._push(c,e.length(),e)},h.prototype.int64=h.prototype.uint64,h.prototype.sint64=function(t){var e=i.from(t).zzEncode();return this._push(c,e.length(),e)},h.prototype.bool=function(t){return this._push(l,1,t?1:0)},h.prototype.fixed32=function(t){return this._push(d,4,t>>>0)},h.prototype.sfixed32=h.prototype.fixed32,h.prototype.fixed64=function(t){var e=i.from(t);return this._push(d,4,e.lo)._push(d,4,e.hi)},h.prototype.sfixed64=h.prototype.fixed64,h.prototype.float=function(t){return this._push(n.float.writeFloatLE,4,t)},h.prototype.double=function(t){return this._push(n.float.writeDoubleLE,8,t)};var p=n.Array.prototype.set?function(t,e,r){e.set(t,r)}:function(t,e,r){for(var i=0;i>>0;if(!e)return this._push(l,1,0);if(n.isString(t)){var r=h.alloc(e=o.length(t));o.write(t,r,0),t=r}return this.uint32(e)._push(p,e,t)},h.prototype.string=function(t){var e=o.length(t);return e?this.uint32(e)._push(o.write,e,t):this._push(l,1,0)},h.prototype.fork=function(){return this.states=new u(this),this.head=this.tail=new s(a,0,0),this.len=0,this},h.prototype.reset=function(){return this.states?(this.head=this.states.head,this.tail=this.states.tail,this.len=this.states.len,this.states=this.states.next):(this.head=this.tail=new s(a,0,0),this.len=0),this},h.prototype.ldelim=function(){var t=this.head,e=this.tail,r=this.len;return this.reset().uint32(r),r&&(this.tail.next=t.next,this.tail=e,this.len+=r),this},h.prototype.finish=function(){for(var t=this.head.next,e=this.constructor.alloc(this.len),r=0;t;)t.fn(t.val,e,r),r+=t.len,t=t.next;return e},h._configure=function(){i=t(12),t(4),o=t(30)}},{12:12,30:30,31:31,4:4}],31:[function(t,e,r){"use strict";var i=e.exports,n=t(24);i.LongBits=t(12),i.Long=t(11),i.pool=t(21),i.float=t(10),i.asPromise=t(3),i.EventEmitter=t(2),i.path=t(20),i.base64=t(4),i.utf8=t(30),i.compareFieldsById=function(t,e){return t.id-e.id},i.toArray=function(t){if(t){for(var e=Object.keys(t),r=new Array(e.length),i=0;i-1;--r)if(1===e[t[r]]&&void 0!==this[t[r]]&&null!==this[t[r]])return t[r]}},i.oneOfSetter=function(t){return function(e){for(var r=0;r=65536&&r<=1114111?(i.push(r>>18&7|240),i.push(r>>12&63|128),i.push(r>>6&63|128),i.push(63&r|128)):r>=2048&&r<=65535?(i.push(r>>12&15|224),i.push(r>>6&63|128),i.push(63&r|128)):r>=128&&r<=2047?(i.push(r>>6&31|192),i.push(63&r|128)):i.push(255&r);return i},i.byteToString=function(t){if("string"==typeof t)return t;for(var e="",r=t,i=0;i1&&"="===t.charAt(e);)++r;return Math.ceil(3*t.length)/4-r};for(var n=new Array(64),o=new Array(123),s=0;s<64;)o[n[s]=s<26?s+65:s<52?s+71:s<62?s-4:s-59|43]=s++;i.encode=function(t,e,r){for(var i,o=null,s=[],a=0,u=0;e>2],i=(3&h)<<4,u=1;break;case 1:s[a++]=n[i|h>>4],i=(15&h)<<2,u=2;break;case 2:s[a++]=n[i|h>>6],s[a++]=n[63&h],u=0}a>8191&&((o||(o=[])).push(String.fromCharCode.apply(String,s)),a=0)}return u&&(s[a++]=n[i],s[a++]=61,1===u&&(s[a++]=61)),o?(a&&o.push(String.fromCharCode.apply(String,s.slice(0,a))),o.join("")):String.fromCharCode.apply(String,s.slice(0,a))},i.decode=function(t,e,r){for(var i,n=r,s=0,a=0;a1)break;if(void 0===(u=o[u]))throw Error("invalid encoding");switch(s){case 0:i=u,s=1;break;case 1:e[r++]=i<<2|(48&u)>>4,i=u,s=2;break;case 2:e[r++]=(15&i)<<4|(60&u)>>2,i=u,s=3;break;case 3:e[r++]=(3&i)<<6|u,s=0}}if(1===s)throw Error("invalid encoding");return r-n},i.test=function(t){return/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(t)}},{}],10:[function(t,e,r){"use strict";function i(t){return"undefined"!=typeof Float32Array?function(){var e=new Float32Array([-0]),r=new Uint8Array(e.buffer),i=128===r[3];function n(t,i,n){e[0]=t,i[n]=r[0],i[n+1]=r[1],i[n+2]=r[2],i[n+3]=r[3]}function o(t,i,n){e[0]=t,i[n]=r[3],i[n+1]=r[2],i[n+2]=r[1],i[n+3]=r[0]}function s(t,i){return r[0]=t[i],r[1]=t[i+1],r[2]=t[i+2],r[3]=t[i+3],e[0]}function a(t,i){return r[3]=t[i],r[2]=t[i+1],r[1]=t[i+2],r[0]=t[i+3],e[0]}t.writeFloatLE=i?n:o,t.writeFloatBE=i?o:n,t.readFloatLE=i?s:a,t.readFloatBE=i?a:s}():function(){function e(t,e,r,i){var n=e<0?1:0;if(n&&(e=-e),0===e)t(1/e>0?0:2147483648,r,i);else if(isNaN(e))t(2143289344,r,i);else if(e>34028234663852886e22)t((n<<31|2139095040)>>>0,r,i);else if(e<11754943508222875e-54)t((n<<31|Math.round(e/1401298464324817e-60))>>>0,r,i);else{var o=Math.floor(Math.log(e)/Math.LN2);t((n<<31|o+127<<23|8388607&Math.round(e*Math.pow(2,-o)*8388608))>>>0,r,i)}}function r(t,e,r){var i=t(e,r),n=2*(i>>31)+1,o=i>>>23&255,s=8388607&i;return 255===o?s?NaN:n*(1/0):0===o?1401298464324817e-60*n*s:n*Math.pow(2,o-150)*(s+8388608)}t.writeFloatLE=e.bind(null,n),t.writeFloatBE=e.bind(null,o),t.readFloatLE=r.bind(null,s),t.readFloatBE=r.bind(null,a)}(),"undefined"!=typeof Float64Array?function(){var e=new Float64Array([-0]),r=new Uint8Array(e.buffer),i=128===r[7];function n(t,i,n){e[0]=t,i[n]=r[0],i[n+1]=r[1],i[n+2]=r[2],i[n+3]=r[3],i[n+4]=r[4],i[n+5]=r[5],i[n+6]=r[6],i[n+7]=r[7]}function o(t,i,n){e[0]=t,i[n]=r[7],i[n+1]=r[6],i[n+2]=r[5],i[n+3]=r[4],i[n+4]=r[3],i[n+5]=r[2],i[n+6]=r[1],i[n+7]=r[0]}function s(t,i){return r[0]=t[i],r[1]=t[i+1],r[2]=t[i+2],r[3]=t[i+3],r[4]=t[i+4],r[5]=t[i+5],r[6]=t[i+6],r[7]=t[i+7],e[0]}function a(t,i){return r[7]=t[i],r[6]=t[i+1],r[5]=t[i+2],r[4]=t[i+3],r[3]=t[i+4],r[2]=t[i+5],r[1]=t[i+6],r[0]=t[i+7],e[0]}t.writeDoubleLE=i?n:o,t.writeDoubleBE=i?o:n,t.readDoubleLE=i?s:a,t.readDoubleBE=i?a:s}():function(){function e(t,e,r,i,n,o){var s=i<0?1:0;if(s&&(i=-i),0===i)t(0,n,o+e),t(1/i>0?0:2147483648,n,o+r);else if(isNaN(i))t(0,n,o+e),t(2146959360,n,o+r);else if(i>17976931348623157e292)t(0,n,o+e),t((s<<31|2146435072)>>>0,n,o+r);else{var a;if(i<22250738585072014e-324)t((a=i/5e-324)>>>0,n,o+e),t((s<<31|a/4294967296)>>>0,n,o+r);else{var u=Math.floor(Math.log(i)/Math.LN2);1024===u&&(u=1023),t(4503599627370496*(a=i*Math.pow(2,-u))>>>0,n,o+e),t((s<<31|u+1023<<20|1048576*a&1048575)>>>0,n,o+r)}}}function r(t,e,r,i,n){var o=t(i,n+e),s=t(i,n+r),a=2*(s>>31)+1,u=s>>>20&2047,h=4294967296*(1048575&s)+o;return 2047===u?h?NaN:a*(1/0):0===u?5e-324*a*h:a*Math.pow(2,u-1075)*(h+4503599627370496)}t.writeDoubleLE=e.bind(null,n,0,4),t.writeDoubleBE=e.bind(null,o,4,0),t.readDoubleLE=r.bind(null,s,0,4),t.readDoubleBE=r.bind(null,a,4,0)}(),t}function n(t,e,r){e[r]=255&t,e[r+1]=t>>>8&255,e[r+2]=t>>>16&255,e[r+3]=t>>>24}function o(t,e,r){e[r]=t>>>24,e[r+1]=t>>>16&255,e[r+2]=t>>>8&255,e[r+3]=255&t}function s(t,e){return(t[e]|t[e+1]<<8|t[e+2]<<16|t[e+3]<<24)>>>0}function a(t,e){return(t[e]<<24|t[e+1]<<16|t[e+2]<<8|t[e+3])>>>0}e.exports=i(i)},{}],11:[function(t,e,r){"use strict";e.exports=n;var i=null;try{i=new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([0,97,115,109,1,0,0,0,1,13,2,96,0,1,127,96,4,127,127,127,127,1,127,3,7,6,0,1,1,1,1,1,6,6,1,127,1,65,0,11,7,50,6,3,109,117,108,0,1,5,100,105,118,95,115,0,2,5,100,105,118,95,117,0,3,5,114,101,109,95,115,0,4,5,114,101,109,95,117,0,5,8,103,101,116,95,104,105,103,104,0,0,10,191,1,6,4,0,35,0,11,36,1,1,126,32,0,173,32,1,173,66,32,134,132,32,2,173,32,3,173,66,32,134,132,126,34,4,66,32,135,167,36,0,32,4,167,11,36,1,1,126,32,0,173,32,1,173,66,32,134,132,32,2,173,32,3,173,66,32,134,132,127,34,4,66,32,135,167,36,0,32,4,167,11,36,1,1,126,32,0,173,32,1,173,66,32,134,132,32,2,173,32,3,173,66,32,134,132,128,34,4,66,32,135,167,36,0,32,4,167,11,36,1,1,126,32,0,173,32,1,173,66,32,134,132,32,2,173,32,3,173,66,32,134,132,129,34,4,66,32,135,167,36,0,32,4,167,11,36,1,1,126,32,0,173,32,1,173,66,32,134,132,32,2,173,32,3,173,66,32,134,132,130,34,4,66,32,135,167,36,0,32,4,167,11])),{}).exports}catch(E){}function n(t,e,r){this.low=0|t,this.high=0|e,this.unsigned=!!r}function o(t){return!0===(t&&t.__isLong__)}n.prototype.__isLong__,Object.defineProperty(n.prototype,"__isLong__",{value:!0}),n.isLong=o;var s={},a={};function u(t,e){var r,i,n;return e?(n=0<=(t>>>=0)&&t<256)&&(i=a[t])?i:(r=l(t,(0|t)<0?-1:0,!0),n&&(a[t]=r),r):(n=-128<=(t|=0)&&t<128)&&(i=s[t])?i:(r=l(t,t<0?-1:0,!1),n&&(s[t]=r),r)}function h(t,e){if(isNaN(t))return e?b:g;if(e){if(t<0)return b;if(t>=y)return A}else{if(t<=-m)return O;if(t+1>=m)return k}return t<0?h(-t,e).neg():l(t%p|0,t/p|0,e)}function l(t,e,r){return new n(t,e,r)}n.fromInt=u,n.fromNumber=h,n.fromBits=l;var f=Math.pow;function c(t,e,r){if(0===t.length)throw Error("empty string");if("NaN"===t||"Infinity"===t||"+Infinity"===t||"-Infinity"===t)return g;if("number"==typeof e?(r=e,e=!1):e=!!e,(r=r||10)<2||360)throw Error("interior hyphen");if(0===i)return c(t.substring(1),e,r).neg();for(var n=h(f(r,8)),o=g,s=0;s>>0:this.low},S.toNumber=function(){return this.unsigned?(this.high>>>0)*p+(this.low>>>0):this.high*p+(this.low>>>0)},S.toString=function(t){if((t=t||10)<2||36>>0).toString(t);if((o=a).isZero())return u+s;for(;u.length<6;)u="0"+u;s=""+u+s}},S.getHighBits=function(){return this.high},S.getHighBitsUnsigned=function(){return this.high>>>0},S.getLowBits=function(){return this.low},S.getLowBitsUnsigned=function(){return this.low>>>0},S.getNumBitsAbs=function(){if(this.isNegative())return this.eq(O)?64:this.neg().getNumBitsAbs();for(var t=0!=this.high?this.high:this.low,e=31;e>0&&0==(t&1<=0},S.isOdd=function(){return 1==(1&this.low)},S.isEven=function(){return 0==(1&this.low)},S.equals=function(t){return o(t)||(t=d(t)),(this.unsigned===t.unsigned||this.high>>>31!=1||t.high>>>31!=1)&&this.high===t.high&&this.low===t.low},S.eq=S.equals,S.notEquals=function(t){return!this.eq(t)},S.neq=S.notEquals,S.ne=S.notEquals,S.lessThan=function(t){return this.comp(t)<0},S.lt=S.lessThan,S.lessThanOrEqual=function(t){return this.comp(t)<=0},S.lte=S.lessThanOrEqual,S.le=S.lessThanOrEqual,S.greaterThan=function(t){return this.comp(t)>0},S.gt=S.greaterThan,S.greaterThanOrEqual=function(t){return this.comp(t)>=0},S.gte=S.greaterThanOrEqual,S.ge=S.greaterThanOrEqual,S.compare=function(t){if(o(t)||(t=d(t)),this.eq(t))return 0;var e=this.isNegative(),r=t.isNegative();return e&&!r?-1:!e&&r?1:this.unsigned?t.high>>>0>this.high>>>0||t.high===this.high&&t.low>>>0>this.low>>>0?-1:1:this.sub(t).isNegative()?-1:1},S.comp=S.compare,S.negate=function(){return!this.unsigned&&this.eq(O)?O:this.not().add(w)},S.neg=S.negate,S.add=function(t){o(t)||(t=d(t));var e=this.high>>>16,r=65535&this.high,i=this.low>>>16,n=65535&this.low,s=t.high>>>16,a=65535&t.high,u=t.low>>>16,h=0,f=0,c=0,p=0;return c+=(p+=n+(65535&t.low))>>>16,f+=(c+=i+u)>>>16,h+=(f+=r+a)>>>16,h+=e+s,l((c&=65535)<<16|(p&=65535),(h&=65535)<<16|(f&=65535),this.unsigned)},S.subtract=function(t){return o(t)||(t=d(t)),this.add(t.neg())},S.sub=S.subtract,S.multiply=function(t){if(this.isZero())return g;if(o(t)||(t=d(t)),i)return l(i.mul(this.low,this.high,t.low,t.high),i.get_high(),this.unsigned);if(t.isZero())return g;if(this.eq(O))return t.isOdd()?O:g;if(t.eq(O))return this.isOdd()?O:g;if(this.isNegative())return t.isNegative()?this.neg().mul(t.neg()):this.neg().mul(t).neg();if(t.isNegative())return this.mul(t.neg()).neg();if(this.lt(v)&&t.lt(v))return h(this.toNumber()*t.toNumber(),this.unsigned);var e=this.high>>>16,r=65535&this.high,n=this.low>>>16,s=65535&this.low,a=t.high>>>16,u=65535&t.high,f=t.low>>>16,c=65535&t.low,p=0,y=0,m=0,b=0;return m+=(b+=s*c)>>>16,y+=(m+=n*c)>>>16,m&=65535,y+=(m+=s*f)>>>16,p+=(y+=r*c)>>>16,y&=65535,p+=(y+=n*f)>>>16,y&=65535,p+=(y+=s*u)>>>16,p+=e*c+r*f+n*u+s*a,l((m&=65535)<<16|(b&=65535),(p&=65535)<<16|(y&=65535),this.unsigned)},S.mul=S.multiply,S.divide=function(t){if(o(t)||(t=d(t)),t.isZero())throw Error("division by zero");var e,r,n;if(i)return this.unsigned||-2147483648!==this.high||-1!==t.low||-1!==t.high?l((this.unsigned?i.div_u:i.div_s)(this.low,this.high,t.low,t.high),i.get_high(),this.unsigned):this;if(this.isZero())return this.unsigned?b:g;if(this.unsigned){if(t.unsigned||(t=t.toUnsigned()),t.gt(this))return b;if(t.gt(this.shru(1)))return _;n=b}else{if(this.eq(O))return t.eq(w)||t.eq(x)?O:t.eq(O)?w:(e=this.shr(1).div(t).shl(1)).eq(g)?t.isNegative()?w:x:(r=this.sub(t.mul(e)),n=e.add(r.div(t)));if(t.eq(O))return this.unsigned?b:g;if(this.isNegative())return t.isNegative()?this.neg().div(t.neg()):this.neg().div(t).neg();if(t.isNegative())return this.div(t.neg()).neg();n=g}for(r=this;r.gte(t);){e=Math.max(1,Math.floor(r.toNumber()/t.toNumber()));for(var s=Math.ceil(Math.log(e)/Math.LN2),a=s<=48?1:f(2,s-48),u=h(e),c=u.mul(t);c.isNegative()||c.gt(r);)c=(u=h(e-=a,this.unsigned)).mul(t);u.isZero()&&(u=w),n=n.add(u),r=r.sub(c)}return n},S.div=S.divide,S.modulo=function(t){return o(t)||(t=d(t)),i?l((this.unsigned?i.rem_u:i.rem_s)(this.low,this.high,t.low,t.high),i.get_high(),this.unsigned):this.sub(this.div(t).mul(t))},S.mod=S.modulo,S.rem=S.modulo,S.not=function(){return l(~this.low,~this.high,this.unsigned)},S.and=function(t){return o(t)||(t=d(t)),l(this.low&t.low,this.high&t.high,this.unsigned)},S.or=function(t){return o(t)||(t=d(t)),l(this.low|t.low,this.high|t.high,this.unsigned)},S.xor=function(t){return o(t)||(t=d(t)),l(this.low^t.low,this.high^t.high,this.unsigned)},S.shiftLeft=function(t){return o(t)&&(t=t.toInt()),0==(t&=63)?this:t<32?l(this.low<>>32-t,this.unsigned):l(0,this.low<>>t|this.high<<32-t,this.high>>t,this.unsigned):l(this.high>>t-32,this.high>=0?0:-1,this.unsigned)},S.shr=S.shiftRight,S.shiftRightUnsigned=function(t){if(o(t)&&(t=t.toInt()),0==(t&=63))return this;var e=this.high;return t<32?l(this.low>>>t|e<<32-t,e>>>t,this.unsigned):l(32===t?e:e>>>t-32,0,this.unsigned)},S.shru=S.shiftRightUnsigned,S.shr_u=S.shiftRightUnsigned,S.toSigned=function(){return this.unsigned?l(this.low,this.high,!1):this},S.toUnsigned=function(){return this.unsigned?this:l(this.low,this.high,!0)},S.toBytes=function(t){return t?this.toBytesLE():this.toBytesBE()},S.toBytesLE=function(){var t=this.high,e=this.low;return[255&e,e>>>8&255,e>>>16&255,e>>>24,255&t,t>>>8&255,t>>>16&255,t>>>24]},S.toBytesBE=function(){var t=this.high,e=this.low;return[t>>>24,t>>>16&255,t>>>8&255,255&t,e>>>24,e>>>16&255,e>>>8&255,255&e]},n.fromBytes=function(t,e,r){return r?n.fromBytesLE(t,e):n.fromBytesBE(t,e)},n.fromBytesLE=function(t,e){return new n(t[0]|t[1]<<8|t[2]<<16|t[3]<<24,t[4]|t[5]<<8|t[6]<<16|t[7]<<24,e)},n.fromBytesBE=function(t,e){return new n(t[4]<<24|t[5]<<16|t[6]<<8|t[7],t[0]<<24|t[1]<<16|t[2]<<8|t[3],e)}},{}],12:[function(t,e,r){"use strict";function i(t,e){this.lo=t>>>0,this.hi=e>>>0}e.exports=i;var n=i.zero=new i(0,0);n.toNumber=function(){return 0},n.zzEncode=n.zzDecode=function(){return this},n.length=function(){return 1};var o=i.zeroHash="\0\0\0\0\0\0\0\0";i.fromNumber=function(t){if(0===t)return n;var e=t<0;e&&(t=-t);var r=t>>>0,o=(t-r)/4294967296>>>0;return e&&(o=~o>>>0,r=~r>>>0,++r>4294967295&&(r=0,++o>4294967295&&(o=0))),new i(r,o)},i.from=function(t){return"number"==typeof t?i.fromNumber(t):"string"==typeof t||t instanceof String?i.fromNumber(parseInt(t,10)):t.low||t.high?new i(t.low>>>0,t.high>>>0):n},i.prototype.toNumber=function(t){if(!t&&this.hi>>>31){var e=1+~this.lo>>>0,r=~this.hi>>>0;return e||(r=r+1>>>0),-(e+4294967296*r)}return this.lo+4294967296*this.hi},i.prototype.toLong=function(t){return{low:0|this.lo,high:0|this.hi,unsigned:Boolean(t)}};var s=String.prototype.charCodeAt;i.fromHash=function(t){return t===o?n:new i((s.call(t,0)|s.call(t,1)<<8|s.call(t,2)<<16|s.call(t,3)<<24)>>>0,(s.call(t,4)|s.call(t,5)<<8|s.call(t,6)<<16|s.call(t,7)<<24)>>>0)},i.prototype.toHash=function(){return String.fromCharCode(255&this.lo,this.lo>>>8&255,this.lo>>>16&255,this.lo>>>24,255&this.hi,this.hi>>>8&255,this.hi>>>16&255,this.hi>>>24)},i.prototype.zzEncode=function(){var t=this.hi>>31;return this.hi=((this.hi<<1|this.lo>>>31)^t)>>>0,this.lo=(this.lo<<1^t)>>>0,this},i.prototype.zzDecode=function(){var t=-(1&this.lo);return this.lo=((this.lo>>>1|this.hi<<31)^t)>>>0,this.hi=(this.hi>>>1^t)>>>0,this},i.prototype.length=function(){var t=this.lo,e=(this.lo>>>28|this.hi<<4)>>>0,r=this.hi>>>24;return 0===r?0===e?t<16384?t<128?1:2:t<2097152?3:4:e<16384?e<128?5:6:e<2097152?7:8:r<128?9:10}},{}],20:[function(t,e,r){"use strict";var i=e.exports,n=i.isAbsolute=function(t){return/^(?:\/|\w+:)/.test(t)},o=i.normalize=function(t){var e=(t=t.replace(/\\/g,"/").replace(/\/{2,}/g,"/")).split("/"),r=n(t),i="";r&&(i=e.shift()+"/");for(var o=0;o0&&".."!==e[o-1]?e.splice(--o,2):r?e.splice(o,1):++o:"."===e[o]?e.splice(o,1):++o;return i+e.join("/")};i.resolve=function(t,e,r){return r||(e=o(e)),n(e)?e:(r||(t=o(t)),(t=t.replace(/(?:\/|^)[^/]+$/,"")).length?o(t+"/"+e):e)}},{}],21:[function(t,e,r){"use strict";e.exports=function(t,e,r){var i=r||8192,n=i>>>1,o=null,s=i;return function(r){if(r<1||r>n)return t(r);s+r>i&&(o=t(i),s=0);var a=e.call(o,s,s+=r);return 7&s&&(s=1+(7|s)),a}}},{}],30:[function(t,e,r){"use strict";var i=e.exports;i.length=function(t){for(var e=0,r=0,i=0;i191&&i<224?o[s++]=(31&i)<<6|63&t[e++]:i>239&&i<365?(i=((7&i)<<18|(63&t[e++])<<12|(63&t[e++])<<6|63&t[e++])-65536,o[s++]=55296+(i>>10),o[s++]=56320+(1023&i)):o[s++]=(15&i)<<12|(63&t[e++])<<6|63&t[e++],s>8191&&((n||(n=[])).push(String.fromCharCode.apply(String,o)),s=0);return n?(s&&n.push(String.fromCharCode.apply(String,o.slice(0,s))),n.join("")):String.fromCharCode.apply(String,o.slice(0,s))},i.write=function(t,e,r){for(var i,n,o=r,s=0;s>6|192,e[r++]=63&i|128):55296==(64512&i)&&56320==(64512&(n=t.charCodeAt(s+1)))?(i=65536+((1023&i)<<10)+(1023&n),++s,e[r++]=i>>18|240,e[r++]=i>>12&63|128,e[r++]=i>>6&63|128,e[r++]=63&i|128):(e[r++]=i>>12|224,e[r++]=i>>6&63|128,e[r++]=63&i|128);return r-o}},{}],35:[function(t,e,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.getMiniBridge=void 0,r.getMiniBridge=function(){return"undefined"==typeof wx&&"undefined"!=typeof my?my:wx}},{}],36:[function(t,e,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.BezierPath=void 0;var i=function(t,e,r){this.d=t,this.transform=e,this.styles=r,this._d=t,this._transform=e,this._styles=r};r.BezierPath=i},{}],37:[function(t,e,r){"use strict";var i,n=this&&this.__extends||(i=function(t,e){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(t,e)},function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");function r(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(r,"__esModule",{value:!0}),r.EllipsePath=void 0;var o=function(t){function e(e,r,i,n,o,s){var a=t.call(this,"",o,s)||this;return a._x=e,a._y=r,a._radiusX=i,a._radiusY=n,a._transform=o,a._styles=s,a}return n(e,t),e}(t(36).BezierPath);r.EllipsePath=o},{36:36}],38:[function(t,e,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.FrameEntity=void 0;var i=t(36),n=function t(e){this.alpha=0,this.transform={a:1,b:0,c:0,d:1,tx:0,ty:0},this.layout={x:0,y:0,width:0,height:0},this.nx=0,this.ny=0,this.shapes=[],this.alpha=parseFloat(e.alpha)||0,e.layout&&(this.layout.x=parseFloat(e.layout.x)||0,this.layout.y=parseFloat(e.layout.y)||0,this.layout.width=parseFloat(e.layout.width)||0,this.layout.height=parseFloat(e.layout.height)||0),e.transform&&(this.transform.a=parseFloat(e.transform.a)||1,this.transform.b=parseFloat(e.transform.b)||0,this.transform.c=parseFloat(e.transform.c)||0,this.transform.d=parseFloat(e.transform.d)||1,this.transform.tx=parseFloat(e.transform.tx)||0,this.transform.ty=parseFloat(e.transform.ty)||0),e.clipPath&&e.clipPath.length>0&&(this.maskPath=new i.BezierPath(e.clipPath,void 0,{fill:"#000000"})),e.shapes&&(e.shapes instanceof Array&&e.shapes.forEach((function(t){switch(t.pathArgs=t.args,t.type){case 0:t.type="shape",t.pathArgs=t.shape;break;case 1:t.type="rect",t.pathArgs=t.rect;break;case 2:t.type="ellipse",t.pathArgs=t.ellipse;break;case 3:t.type="keep"}if(t.styles){t.styles.fill&&("number"==typeof t.styles.fill.r&&(t.styles.fill[0]=t.styles.fill.r),"number"==typeof t.styles.fill.g&&(t.styles.fill[1]=t.styles.fill.g),"number"==typeof t.styles.fill.b&&(t.styles.fill[2]=t.styles.fill.b),"number"==typeof t.styles.fill.a&&(t.styles.fill[3]=t.styles.fill.a)),t.styles.stroke&&("number"==typeof t.styles.stroke.r&&(t.styles.stroke[0]=t.styles.stroke.r),"number"==typeof t.styles.stroke.g&&(t.styles.stroke[1]=t.styles.stroke.g),"number"==typeof t.styles.stroke.b&&(t.styles.stroke[2]=t.styles.stroke.b),"number"==typeof t.styles.stroke.a&&(t.styles.stroke[3]=t.styles.stroke.a));var e=t.styles.lineDash||[];switch(t.styles.lineDashI>0&&e.push(t.styles.lineDashI),t.styles.lineDashII>0&&(e.length<1&&e.push(0),e.push(t.styles.lineDashII),e.push(0)),t.styles.lineDashIII>0&&(e.length<2&&(e.push(0),e.push(0)),e[2]=t.styles.lineDashIII),t.styles.lineDash=e,t.styles.lineJoin){case 0:t.styles.lineJoin="miter";break;case 1:t.styles.lineJoin="round";break;case 2:t.styles.lineJoin="bevel"}switch(t.styles.lineCap){case 0:t.styles.lineCap="butt";break;case 1:t.styles.lineCap="round";break;case 2:t.styles.lineCap="square"}}})),e.shapes[0]&&"keep"===e.shapes[0].type?this.shapes=t.lastShapes:(this.shapes=e.shapes,t.lastShapes=e.shapes));var r=this.transform.a*this.layout.x+this.transform.c*this.layout.y+this.transform.tx,n=this.transform.a*(this.layout.x+this.layout.width)+this.transform.c*this.layout.y+this.transform.tx,o=this.transform.a*this.layout.x+this.transform.c*(this.layout.y+this.layout.height)+this.transform.tx,s=this.transform.a*(this.layout.x+this.layout.width)+this.transform.c*(this.layout.y+this.layout.height)+this.transform.tx,a=this.transform.b*this.layout.x+this.transform.d*this.layout.y+this.transform.ty,u=this.transform.b*(this.layout.x+this.layout.width)+this.transform.d*this.layout.y+this.transform.ty,h=this.transform.b*this.layout.x+this.transform.d*(this.layout.y+this.layout.height)+this.transform.ty,l=this.transform.b*(this.layout.x+this.layout.width)+this.transform.d*(this.layout.y+this.layout.height)+this.transform.ty;this.nx=Math.min(Math.min(o,s),Math.min(r,n)),this.ny=Math.min(Math.min(h,l),Math.min(a,u))};r.FrameEntity=n},{36:36}],39:[function(t,e,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.Player=r.Parser=void 0;var i=t(41),n=t(42);r.Parser=i.Parser,r.Player=n.Player},{41:41,42:42}],42:[function(t,e,r){"use strict";var i=this&&this.__awaiter||function(t,e,r,i){return new(r||(r=Promise))((function(n,o){function s(t){try{u(i.next(t))}catch(e){o(e)}}function a(t){try{u(i.throw(t))}catch(e){o(e)}}function u(t){var e;t.done?n(t.value):(e=t.value,e instanceof r?e:new r((function(t){t(e)}))).then(s,a)}u((i=i.apply(t,e||[])).next())}))},n=this&&this.__generator||function(t,e){var r,i,n,o,s={label:0,sent:function(){if(1&n[0])throw n[1];return n[1]},trys:[],ops:[]};return o={next:a(0),throw:a(1),return:a(2)},"function"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function a(o){return function(a){return function(o){if(r)throw new TypeError("Generator is already executing.");for(;s;)try{if(r=1,i&&(n=2&o[0]?i.return:o[0]?i.throw||((n=i.return)&&n.call(i),0):i.next)&&!(n=n.call(i,o[1])).done)return n;switch(i=0,n&&(o=[2&o[0],n.value]),o[0]){case 0:case 1:n=o;break;case 4:return s.label++,{value:o[1],done:!1};case 5:s.label++,i=o[1],o=[0];continue;case 7:o=s.ops.pop(),s.trys.pop();continue;default:if(!(n=(n=s.trys).length>0&&n[n.length-1])&&(6===o[0]||2===o[0])){s=0;continue}if(3===o[0]&&(!n||o[1]>n[0]&&o[1]=r.frames||t<0||(this.pauseAnimation(),this._currentFrame=t,this._update(),e&&this._doStart(void 0,!1,this._currentFrame)))},t.prototype.stepToPercentage=function(t,e){void 0===e&&(e=!1);var r=this._videoItem;if(r){var i=t*r.frames;i>=r.frames&&i>0&&(i=r.frames-1),this.stepToFrame(i,e)}},t.prototype.setImage=function(t,e){return i(this,void 0,void 0,(function(){var r;return n(this,(function(i){switch(i.label){case 0:return[4,this.loadWXImage(t)];case 1:return r=i.sent(),this._dynamicImage[e]=r,[2]}}))}))},t.prototype.setText=function(t,e){this._dynamicText[e]=t},t.prototype.clearDynamicObjects=function(){this._dynamicImage={},this._dynamicText={}},t.prototype.onFinished=function(t){this._onFinished=t},t.prototype.onFrame=function(t){this._onFrame=t},t.prototype.onPercentage=function(t){this._onPercentage=t},t.prototype._doStart=function(t,e,r){var i=this;void 0===e&&(e=!1),void 0===r&&(r=0);var n=this._videoItem;n&&(this._animator=new s.ValueAnimator,this._animator.canvas=this.canvas,void 0!==t?(this._animator.startValue=Math.max(0,t.location),this._animator.endValue=Math.min(n.frames-1,t.location+t.length),this._animator.duration=(this._animator.endValue-this._animator.startValue+1)*(1/n.FPS)*1e3):(this._animator.startValue=0,this._animator.endValue=n.frames-1,this._animator.duration=n.frames*(1/n.FPS)*1e3),this._animator.loops=this.loops<=0?1/0:this.loops,this._animator.fillRule="Backward"===this.fillMode?1:0,this._animator.onUpdate=function(t){i._currentFrame!==Math.floor(t)&&(i._forwardAnimating&&(i._currentFrame,Math.floor(t)),i._currentFrame=Math.floor(t),i._update(),"function"==typeof i._onFrame&&i._onFrame(i._currentFrame),"function"==typeof i._onPercentage&&i._onPercentage((i._currentFrame+1)/n.frames))},this._animator.onEnd=function(){i._forwardAnimating=!1,!0===i.clearsAfterStop&&i.clear(),"function"==typeof i._onFinished&&i._onFinished()},!0===e?(this._animator.reverse(r),this._forwardAnimating=!1):(this._animator.start(r),this._forwardAnimating=!0),this._currentFrame=this._animator.startValue,this._update())},t.prototype._resize=function(){var t=this.ctx,e=this._videoItem;if(t&&e){var r=1,i=1,n=0,o=0,s=this.canvas.width,a=this.canvas.height,u=e.videoSize;if("Fill"===this._contentMode)r=s/u.width,i=a/u.height;else if("AspectFit"===this._contentMode||"AspectFill"===this._contentMode){var h=u.width/u.height,l=s/a;h>=l&&"AspectFit"===this._contentMode||h<=l&&"AspectFill"===this._contentMode?(r=i=s/u.width,o=(a-u.height*i)/2):(hl&&"AspectFill"===this._contentMode)&&(r=i=a/u.height,n=(s-u.width*r)/2)}this._renderer&&(this._renderer.globalTransform={a:r,b:0,c:0,d:i,tx:n,ty:o})}},t.prototype._update=function(){this._resize(),this._renderer&&(this._renderer._dynamicImage=this._dynamicImage,this._renderer._dynamicText=this._dynamicText,this._renderer.drawFrame(this._currentFrame),this._renderer.playAudio(this._currentFrame))},t}();r.Player=u},{35:35,45:45,47:47}],41:[function(t,e,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.Parser=void 0;var i=t(48),n=t(35),o=t(40).inflate,s=t(43).ProtoMovieEntity,a=n.getMiniBridge(),u=function(){function t(){}return t.prototype.load=function(t){return new Promise((function(e,r){0===t.indexOf("http://")||0===t.indexOf("https://")?a.request({url:t,dataType:"arraybuffer",responseType:"arraybuffer",success:function(t){try{var n=o(t.data),a=s.decode(n);e(new i.VideoEntity(a))}catch(u){r(u)}},fail:function(t){r(t)}}):a.getFileSystemManager().readFile({filePath:t,success:function(t){try{var n=o(t.data),a=s.decode(n);e(new i.VideoEntity(a))}catch(u){r(u)}},fail:function(t){r(t)}})}))},t}();r.Parser=u},{35:35,40:40,43:43,48:48}],40:[function(t,e,r){"use strict";var i;i=this,function(t){var e=function(t,e,r,i){for(var n=65535&t|0,o=t>>>16&65535|0,s=0;0!==r;){r-=s=r>2e3?2e3:r;do{o=o+(n=n+e[i++]|0)|0}while(--s);n%=65521,o%=65521}return n|o<<16|0},r=new Uint32Array(function(){for(var t,e=[],r=0;r<256;r++){t=r;for(var i=0;i<8;i++)t=1&t?3988292384^t>>>1:t>>>1;e[r]=t}return e}()),i=function(t,e,i,n){var o=r,s=n+i;t^=-1;for(var a=n;a>>8^o[255&(t^e[a])];return-1^t},n=function(t,e){var r,i,n,o,s,a,u,h,l,f,c,d,p,y,m,v,g,b,w,_,x,k,A,O,S=t.state;r=t.next_in,A=t.input,i=r+(t.avail_in-5),n=t.next_out,O=t.output,o=n-(e-t.avail_out),s=n+(t.avail_out-257),a=S.dmax,u=S.wsize,h=S.whave,l=S.wnext,f=S.window,c=S.hold,d=S.bits,p=S.lencode,y=S.distcode,m=(1<>>=b=g>>>24,d-=b,0==(b=g>>>16&255))O[n++]=65535&g;else{if(!(16&b)){if(0==(64&b)){g=p[(65535&g)+(c&(1<>>=b,d-=b),d<15&&(c+=A[r++]<>>=b=g>>>24,d-=b,!(16&(b=g>>>16&255))){if(0==(64&b)){g=y[(65535&g)+(c&(1<a){t.msg="invalid distance too far back",S.mode=30;break t}if(c>>>=b,d-=b,_>(b=n-o)){if((b=_-b)>h&&S.sane){t.msg="invalid distance too far back",S.mode=30;break t}if(x=0,k=f,0===l){if(x+=u-b,b2;)O[n++]=k[x++],O[n++]=k[x++],O[n++]=k[x++],w-=3;w&&(O[n++]=k[x++],w>1&&(O[n++]=k[x++]))}else{x=n-_;do{O[n++]=O[x++],O[n++]=O[x++],O[n++]=O[x++],w-=3}while(w>2);w&&(O[n++]=O[x++],w>1&&(O[n++]=O[x++]))}break}}break}}while(r>3,c&=(1<<(d-=w<<3))-1,t.next_in=r,t.next_out=n,t.avail_in=r=1&&0===B[O];O--);if(S>O&&(S=O),0===O)return n[h++]=20971520,n[h++]=20971520,f.bits=1,0;for(A=1;A0&&(0===t||1!==O))return-1;for(P[1]=0,x=1;x<15;x++)P[x+1]=P[x]+B[x];for(k=0;k852||2===t&&j>592)return 1;for(;;){g=x-N,l[k]v?(b=C[M+l[k]],w=F[I+l[k]]):(b=96,w=0),c=1<>N)+(d-=c)]=g<<24|b<<16|w|0}while(0!==d);for(c=1<>=1;if(0!==c?(R&=c-1,R+=c):R=0,k++,0==--B[x]){if(x===O)break;x=e[r+l[k]]}if(x>S&&(R&y)!==p){for(0===N&&(N=S),m+=A,T=1<<(E=x-N);E+N852||2===t&&j>592)return 1;n[p=R&y]=S<<24|E<<16|m-h|0}}return 0!==R&&(n[m+R]=x-N<<24|64<<16|0),f.bits=S,0},l={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_MEM_ERROR:-4,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8},f=l.Z_FINISH,c=l.Z_BLOCK,d=l.Z_TREES,p=l.Z_OK,y=l.Z_STREAM_END,m=l.Z_NEED_DICT,v=l.Z_STREAM_ERROR,g=l.Z_DATA_ERROR,b=l.Z_MEM_ERROR,w=l.Z_BUF_ERROR,_=l.Z_DEFLATED,x=12,k=30,A=function(t){return(t>>>24&255)+(t>>>8&65280)+((65280&t)<<8)+((255&t)<<24)};function O(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new Uint16Array(320),this.work=new Uint16Array(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}var S,E,N=function(t){if(!t||!t.state)return v;var e=t.state;return t.total_in=t.total_out=e.total=0,t.msg="",e.wrap&&(t.adler=1&e.wrap),e.mode=1,e.last=0,e.havedict=0,e.dmax=32768,e.head=null,e.hold=0,e.bits=0,e.lencode=e.lendyn=new Int32Array(852),e.distcode=e.distdyn=new Int32Array(592),e.sane=1,e.back=-1,p},T=function(t){if(!t||!t.state)return v;var e=t.state;return e.wsize=0,e.whave=0,e.wnext=0,N(t)},j=function(t,e){var r;if(!t||!t.state)return v;var i=t.state;return e<0?(r=0,e=-e):(r=1+(e>>4),e<48&&(e&=15)),e&&(e<8||e>15)?v:(null!==i.window&&i.wbits!==e&&(i.window=null),i.wrap=r,i.wbits=e,T(t))},R=function(t,e){if(!t)return v;var r=new O;t.state=r,r.window=null;var i=j(t,e);return i!==p&&(t.state=null),i},F=!0,I=function(t){if(F){S=new Int32Array(512),E=new Int32Array(32);for(var e=0;e<144;)t.lens[e++]=8;for(;e<256;)t.lens[e++]=9;for(;e<280;)t.lens[e++]=7;for(;e<288;)t.lens[e++]=8;for(h(1,t.lens,0,288,S,0,t.work,{bits:9}),e=0;e<32;)t.lens[e++]=5;h(2,t.lens,0,32,E,0,t.work,{bits:5}),F=!1}t.lencode=S,t.lenbits=9,t.distcode=E,t.distbits=5},B=function(t,e,r,i){var n,o=t.state;return null===o.window&&(o.wsize=1<=o.wsize?(o.window.set(e.subarray(r-o.wsize,r),0),o.wnext=0,o.whave=o.wsize):((n=o.wsize-o.wnext)>i&&(n=i),o.window.set(e.subarray(r-i,r-i+n),o.wnext),(i-=n)?(o.window.set(e.subarray(r-i,r),0),o.wnext=i,o.whave=o.wsize):(o.wnext+=n,o.wnext===o.wsize&&(o.wnext=0),o.whave>>8&255,o.check=i(o.check,K,2,0),E=0,N=0,o.mode=2;break}if(o.flags=0,o.head&&(o.head.done=!1),!(1&o.wrap)||(((255&E)<<8)+(E>>8))%31){t.msg="incorrect header check",o.mode=k;break}if((15&E)!==_){t.msg="unknown compression method",o.mode=k;break}if(N-=4,Z=8+(15&(E>>>=4)),0===o.wbits)o.wbits=Z;else if(Z>o.wbits){t.msg="invalid window size",o.mode=k;break}o.dmax=1<>8&1),512&o.flags&&(K[0]=255&E,K[1]=E>>>8&255,o.check=i(o.check,K,2,0)),E=0,N=0,o.mode=3;case 3:for(;N<32;){if(0===O)break t;O--,E+=s[u++]<>>8&255,K[2]=E>>>16&255,K[3]=E>>>24&255,o.check=i(o.check,K,4,0)),E=0,N=0,o.mode=4;case 4:for(;N<16;){if(0===O)break t;O--,E+=s[u++]<>8),512&o.flags&&(K[0]=255&E,K[1]=E>>>8&255,o.check=i(o.check,K,2,0)),E=0,N=0,o.mode=5;case 5:if(1024&o.flags){for(;N<16;){if(0===O)break t;O--,E+=s[u++]<>>8&255,o.check=i(o.check,K,2,0)),E=0,N=0}else o.head&&(o.head.extra=null);o.mode=6;case 6:if(1024&o.flags&&((R=o.length)>O&&(R=O),R&&(o.head&&(Z=o.head.extra_len-o.length,o.head.extra||(o.head.extra=new Uint8Array(o.head.extra_len)),o.head.extra.set(s.subarray(u,u+R),Z)),512&o.flags&&(o.check=i(o.check,s,R,u)),O-=R,u+=R,o.length-=R),o.length))break t;o.length=0,o.mode=7;case 7:if(2048&o.flags){if(0===O)break t;R=0;do{Z=s[u+R++],o.head&&Z&&o.length<65536&&(o.head.name+=String.fromCharCode(Z))}while(Z&&R>9&1,o.head.done=!0),t.adler=o.check=0,o.mode=x;break;case 10:for(;N<32;){if(0===O)break t;O--,E+=s[u++]<>>=7&N,N-=7&N,o.mode=27;break}for(;N<3;){if(0===O)break t;O--,E+=s[u++]<>>=1)){case 0:o.mode=14;break;case 1:if(I(o),o.mode=20,r===d){E>>>=2,N-=2;break t}break;case 2:o.mode=17;break;case 3:t.msg="invalid block type",o.mode=k}E>>>=2,N-=2;break;case 14:for(E>>>=7&N,N-=7&N;N<32;){if(0===O)break t;O--,E+=s[u++]<>>16^65535)){t.msg="invalid stored block lengths",o.mode=k;break}if(o.length=65535&E,E=0,N=0,o.mode=15,r===d)break t;case 15:o.mode=16;case 16:if(R=o.length){if(R>O&&(R=O),R>S&&(R=S),0===R)break t;a.set(s.subarray(u,u+R),l),O-=R,u+=R,S-=R,l+=R,o.length-=R;break}o.mode=x;break;case 17:for(;N<14;){if(0===O)break t;O--,E+=s[u++]<>>=5,N-=5,o.ndist=1+(31&E),E>>>=5,N-=5,o.ncode=4+(15&E),E>>>=4,N-=4,o.nlen>286||o.ndist>30){t.msg="too many length or distance symbols",o.mode=k;break}o.have=0,o.mode=18;case 18:for(;o.have>>=3,N-=3}for(;o.have<19;)o.lens[H[o.have++]]=0;if(o.lencode=o.lendyn,o.lenbits=7,q={bits:o.lenbits},U=h(0,o.lens,0,19,o.lencode,0,o.work,q),o.lenbits=q.bits,U){t.msg="invalid code lengths set",o.mode=k;break}o.have=0,o.mode=19;case 19:for(;o.have>>16&255,D=65535&$,!((C=$>>>24)<=N);){if(0===O)break t;O--,E+=s[u++]<>>=C,N-=C,o.lens[o.have++]=D;else{if(16===D){for(J=C+2;N>>=C,N-=C,0===o.have){t.msg="invalid bit length repeat",o.mode=k;break}Z=o.lens[o.have-1],R=3+(3&E),E>>>=2,N-=2}else if(17===D){for(J=C+3;N>>=C)),E>>>=3,N-=3}else{for(J=C+7;N>>=C)),E>>>=7,N-=7}if(o.have+R>o.nlen+o.ndist){t.msg="invalid bit length repeat",o.mode=k;break}for(;R--;)o.lens[o.have++]=Z}}if(o.mode===k)break;if(0===o.lens[256]){t.msg="invalid code -- missing end-of-block",o.mode=k;break}if(o.lenbits=9,q={bits:o.lenbits},U=h(1,o.lens,0,o.nlen,o.lencode,0,o.work,q),o.lenbits=q.bits,U){t.msg="invalid literal/lengths set",o.mode=k;break}if(o.distbits=6,o.distcode=o.distdyn,q={bits:o.distbits},U=h(2,o.lens,o.nlen,o.ndist,o.distcode,0,o.work,q),o.distbits=q.bits,U){t.msg="invalid distances set",o.mode=k;break}if(o.mode=20,r===d)break t;case 20:o.mode=21;case 21:if(O>=6&&S>=258){t.next_out=l,t.avail_out=S,t.next_in=u,t.avail_in=O,o.hold=E,o.bits=N,n(t,j),l=t.next_out,a=t.output,S=t.avail_out,u=t.next_in,s=t.input,O=t.avail_in,E=o.hold,N=o.bits,o.mode===x&&(o.back=-1);break}for(o.back=0;M=($=o.lencode[E&(1<>>16&255,D=65535&$,!((C=$>>>24)<=N);){if(0===O)break t;O--,E+=s[u++]<>L)])>>>16&255,D=65535&$,!(L+(C=$>>>24)<=N);){if(0===O)break t;O--,E+=s[u++]<>>=L,N-=L,o.back+=L}if(E>>>=C,N-=C,o.back+=C,o.length=D,0===M){o.mode=26;break}if(32&M){o.back=-1,o.mode=x;break}if(64&M){t.msg="invalid literal/length code",o.mode=k;break}o.extra=15&M,o.mode=22;case 22:if(o.extra){for(J=o.extra;N>>=o.extra,N-=o.extra,o.back+=o.extra}o.was=o.length,o.mode=23;case 23:for(;M=($=o.distcode[E&(1<>>16&255,D=65535&$,!((C=$>>>24)<=N);){if(0===O)break t;O--,E+=s[u++]<>L)])>>>16&255,D=65535&$,!(L+(C=$>>>24)<=N);){if(0===O)break t;O--,E+=s[u++]<>>=L,N-=L,o.back+=L}if(E>>>=C,N-=C,o.back+=C,64&M){t.msg="invalid distance code",o.mode=k;break}o.offset=D,o.extra=15&M,o.mode=24;case 24:if(o.extra){for(J=o.extra;N>>=o.extra,N-=o.extra,o.back+=o.extra}if(o.offset>o.dmax){t.msg="invalid distance too far back",o.mode=k;break}o.mode=25;case 25:if(0===S)break t;if(R=j-S,o.offset>R){if((R=o.offset-R)>o.whave&&o.sane){t.msg="invalid distance too far back",o.mode=k;break}R>o.wnext?(R-=o.wnext,F=o.wsize-R):F=o.wnext-R,R>o.length&&(R=o.length),P=o.window}else P=a,F=l-o.offset,R=o.length;R>S&&(R=S),S-=R,o.length-=R;do{a[l++]=P[F++]}while(--R);0===o.length&&(o.mode=21);break;case 26:if(0===S)break t;a[l++]=o.length,S--,o.mode=21;break;case 27:if(o.wrap){for(;N<32;){if(0===O)break t;O--,E|=s[u++]<=252?6:q>=248?5:q>=240?4:q>=224?3:q>=192?2:1;U[254]=U[254]=1;var J=function(t,e){var r,i,n=e||t.length,o=new Array(2*n);for(i=0,r=0;r4)o[i++]=65533,r+=a-1;else{for(s&=2===a?31:3===a?15:7;a>1&&r1?o[i++]=65533:s<65536?o[i++]=s:(s-=65536,o[i++]=55296|s>>10&1023,o[i++]=56320|1023&s)}}}return function(t,e){if(e<65534&&t.subarray&&Z)return String.fromCharCode.apply(null,t.length===e?t:t.subarray(0,e));for(var r="",i=0;it.length&&(e=t.length);for(var r=e-1;r>=0&&128==(192&t[r]);)r--;return r<0||0===r?e:r+U[t[r]]>e?r:e},K={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"},H=function(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0},W=function(){this.text=0,this.time=0,this.xflags=0,this.os=0,this.extra=null,this.extra_len=0,this.name="",this.comment="",this.hcrc=0,this.done=!1},X=Object.prototype.toString,G=l.Z_NO_FLUSH,Y=l.Z_FINISH,Q=l.Z_OK,tt=l.Z_STREAM_END,et=l.Z_NEED_DICT,rt=l.Z_STREAM_ERROR,it=l.Z_DATA_ERROR,nt=l.Z_MEM_ERROR;function ot(t){this.options=function(t){for(var e=Array.prototype.slice.call(arguments,1);e.length;){var r=e.shift();if(r){if("object"!=typeof r)throw new TypeError(r+"must be non-object");for(var i in r)V(r,i)&&(t[i]=r[i])}}return t}({chunkSize:65536,windowBits:15,to:""},t||{});var e=this.options;e.raw&&e.windowBits>=0&&e.windowBits<16&&(e.windowBits=-e.windowBits,0===e.windowBits&&(e.windowBits=-15)),!(e.windowBits>=0&&e.windowBits<16)||t&&t.windowBits||(e.windowBits+=32),e.windowBits>15&&e.windowBits<48&&0==(15&e.windowBits)&&(e.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new H,this.strm.avail_out=0;var r=C(this.strm,e.windowBits);if(r!==Q)throw new Error(K[r]);if(this.header=new W,L(this.strm,this.header),e.dictionary&&("string"==typeof e.dictionary?e.dictionary=function(t){var e,r,i,n,o,s=t.length,a=0;for(n=0;n>>6,e[o++]=128|63&r):r<65536?(e[o++]=224|r>>>12,e[o++]=128|r>>>6&63,e[o++]=128|63&r):(e[o++]=240|r>>>18,e[o++]=128|r>>>12&63,e[o++]=128|r>>>6&63,e[o++]=128|63&r);return e}(e.dictionary):"[object ArrayBuffer]"===X.call(e.dictionary)&&(e.dictionary=new Uint8Array(e.dictionary)),e.raw&&(r=z(this.strm,e.dictionary))!==Q))throw new Error(K[r])}function st(t,e){var r=new ot(e);if(r.push(t),r.err)throw r.msg||K[r.err];return r.result}ot.prototype.push=function(t,e){var r,i,n,o=this.strm,s=this.options.chunkSize,a=this.options.dictionary;if(this.ended)return!1;for(i=e===~~e?e:!0===e?Y:G,"[object ArrayBuffer]"===X.call(t)?o.input=new Uint8Array(t):o.input=t,o.next_in=0,o.avail_in=o.input.length;;){for(0===o.avail_out&&(o.output=new Uint8Array(s),o.next_out=0,o.avail_out=s),(r=M(o,i))===et&&a&&((r=z(o,a))===Q?r=M(o,i):r===it&&(r=et));o.avail_in>0&&r===tt&&o.state.wrap>0&&0!==t[o.next_in];)P(o),r=M(o,i);switch(r){case rt:case it:case et:case nt:return this.onEnd(r),this.ended=!0,!1}if(n=o.avail_out,o.next_out&&(0===o.avail_out||r===tt))if("string"===this.options.to){var u=$(o.output,o.next_out),h=o.next_out-u,l=J(o.output,u);o.next_out=h,o.avail_out=s-h,h&&o.output.set(o.output.subarray(u,u+h),0),this.onData(l)}else this.onData(o.output.length===o.next_out?o.output:o.output.subarray(0,o.next_out));if(r!==Q||0!==n){if(r===tt)return r=D(this.strm),this.onEnd(r),this.ended=!0,!0;if(0===o.avail_in)break}}return!0},ot.prototype.onData=function(t){this.chunks.push(t)},ot.prototype.onEnd=function(t){t===Q&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=function(t){for(var e=0,r=0,i=t.length;r=this.duration*this.loops?(this.mCurrentFrication=1===this.fillRule?0:1,this.mRunning=!1,e=!0):(this.mCurrentFrication=t%this.duration/this.duration,this.mReverse&&(this.mCurrentFrication=1-this.mCurrentFrication)),this.onUpdate(this.animatedValue()),!1===this.mRunning&&e&&this.onEnd()},t.currentTimeMillsecond=function(){return"undefined"==typeof performance?(new Date).getTime():performance.now()},t}();r.ValueAnimator=i},{}],45:[function(t,e,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.Renderer=void 0;var i=t(36),n=t(37),o=t(44),s=function(){function t(t,e,r){this.videoItem=t,this.ctx=e,this.canvas=r,this._dynamicImage={},this._dynamicText={}}return t.prototype.clear=function(){var t=this.ctx,e={x:0,y:0,width:this.canvas.width,height:this.canvas.height};t.clearRect(e.x,e.y,e.width,e.height)},t.prototype.drawFrame=function(t){var e=this,r=this.ctx,i={x:0,y:0,width:this.canvas.width,height:this.canvas.height};r.clearRect(i.x,i.y,i.width,i.height);var n={},o=!1,s=this.videoItem.sprites;s.forEach((function(i,a){var u,h;if(-1!=(null===(u=s[0].imageKey)||void 0===u?void 0:u.indexOf(".matte")))if(-1==(null===(h=i.imageKey)||void 0===h?void 0:h.indexOf(".matte"))){var l=s[a-1];if(o&&(!i.matteKey||0==i.matteKey.length||i.matteKey!=l.matteKey)){o=!1;var f=n[i.matteKey];r.globalCompositeOperation="destination-in",e.drawSprite(f,t),r.globalCompositeOperation="source-over",r.restore()}null==i.matteKey||null!=l.matteKey&&0!=l.matteKey.length&&l.matteKey==i.matteKey||(o=!0,r.save()),e.drawSprite(i,t),o&&a==s.length-1&&(f=n.get(i.matteKey),r.globalCompositeOperation="destination-in",e.drawSprite(f,t),r.globalCompositeOperation="source-over",r.restore())}else f[i.imageKey]=i;else e.drawSprite(i,t)}))},t.prototype.drawSprite=function(t,e){var r,s,a,u=this,h=t.frames[e];if(!(h.alpha<.05)){var l=this.ctx;l.save(),this.globalTransform&&l.transform(this.globalTransform.a,this.globalTransform.b,this.globalTransform.c,this.globalTransform.d,this.globalTransform.tx,this.globalTransform.ty),l.globalAlpha=h.alpha,l.transform(h.transform.a,h.transform.b,h.transform.c,h.transform.d,h.transform.tx,h.transform.ty);var f=null===(r=t.imageKey)||void 0===r?void 0:r.replace(".matte","");if(f){var c=null!==(s=this._dynamicImage[f])&&void 0!==s?s:this.videoItem.decodedImages[f];void 0!==h.maskPath&&null!==h.maskPath&&(h.maskPath._styles=void 0,this.drawBezier(h.maskPath),l.clip()),c&&l.drawImage(c,0,0,c.width,c.height,0,0,h.layout.width,h.layout.height),h.shapes&&h.shapes.forEach((function(t){"shape"===t.type&&t.pathArgs&&t.pathArgs.d&&u.drawBezier(new i.BezierPath(t.pathArgs.d,t.transform,t.styles)),"ellipse"===t.type&&t.pathArgs&&u.drawEllipse(new n.EllipsePath(parseFloat(t.pathArgs.x)||0,parseFloat(t.pathArgs.y)||0,parseFloat(t.pathArgs.radiusX)||0,parseFloat(t.pathArgs.radiusY)||0,t.transform,t.styles)),"rect"===t.type&&t.pathArgs&&u.drawRect(new o.RectPath(parseFloat(t.pathArgs.x)||0,parseFloat(t.pathArgs.y)||0,parseFloat(t.pathArgs.width)||0,parseFloat(t.pathArgs.height)||0,parseFloat(t.pathArgs.cornerRadius)||0,t.transform,t.styles))}));var d=this._dynamicText[f];if(void 0!==d){l.font=d.size+"px "+(null!==(a=d.family)&&void 0!==a?a:"Arial");var p=l.measureText(d.text).width;l.fillStyle=d.color;var y=void 0!==d.offset&&void 0!==d.offset.x?isNaN(d.offset.x)?0:d.offset.x:0,m=void 0!==d.offset&&void 0!==d.offset.y?isNaN(d.offset.y)?0:d.offset.y:0;l.fillText(d.text,(h.layout.width-p)/2+y,h.layout.height/2+m)}l.restore()}}},t.prototype.playAudio=function(t){},t.prototype.resetShapeStyles=function(t){var e=this.ctx,r=t._styles;r&&(r&&r.stroke?e.strokeStyle="rgba("+(255*r.stroke[0]).toFixed(0)+", "+(255*r.stroke[1]).toFixed(0)+", "+(255*r.stroke[2]).toFixed(0)+", "+r.stroke[3]+")":e.strokeStyle="transparent",r&&(e.lineWidth=r.strokeWidth||void 0,e.lineCap=r.lineCap||void 0,e.lineJoin=r.lineJoin||void 0,e.miterLimit=r.miterLimit||void 0),r&&r.fill?e.fillStyle="rgba("+(255*r.fill[0]).toFixed(0)+", "+(255*r.fill[1]).toFixed(0)+", "+(255*r.fill[2]).toFixed(0)+", "+r.fill[3]+")":e.fillStyle="transparent",r&&r.lineDash&&e.setLineDash([r.lineDash[0],r.lineDash[1]],r.lineDash[2]))},t.prototype.drawBezier=function(t){var e=this,r=this.ctx;r.save(),this.resetShapeStyles(t),void 0!==t._transform&&null!==t._transform&&r.transform(t._transform.a,t._transform.b,t._transform.c,t._transform.d,t._transform.tx,t._transform.ty);var i={x:0,y:0,x1:0,y1:0,x2:0,y2:0};r.beginPath(),t._d.replace(/([a-zA-Z])/g,"|||$1 ").replace(/,/g," ").split("|||").forEach((function(t){if(0!=t.length){var r=t.substr(0,1);if("MLHVCSQRZmlhvcsqrz".indexOf(r)>=0){var n=t.substr(1).trim().split(" ");e.drawBezierElement(i,r,n)}}})),t._styles&&t._styles.fill&&r.fill(),t._styles&&t._styles.stroke&&r.stroke(),r.restore()},t.prototype.drawBezierElement=function(t,e,r){var i=this.ctx;switch(e){case"M":t.x=Number(r[0]),t.y=Number(r[1]),i.moveTo(t.x,t.y);break;case"m":t.x+=Number(r[0]),t.y+=Number(r[1]),i.moveTo(t.x,t.y);break;case"L":t.x=Number(r[0]),t.y=Number(r[1]),i.lineTo(t.x,t.y);break;case"l":t.x+=Number(r[0]),t.y+=Number(r[1]),i.lineTo(t.x,t.y);break;case"H":t.x=Number(r[0]),i.lineTo(t.x,t.y);break;case"h":t.x+=Number(r[0]),i.lineTo(t.x,t.y);break;case"V":t.y=Number(r[0]),i.lineTo(t.x,t.y);break;case"v":t.y+=Number(r[0]),i.lineTo(t.x,t.y);break;case"C":t.x1=Number(r[0]),t.y1=Number(r[1]),t.x2=Number(r[2]),t.y2=Number(r[3]),t.x=Number(r[4]),t.y=Number(r[5]),i.bezierCurveTo(t.x1,t.y1,t.x2,t.y2,t.x,t.y);break;case"c":t.x1=t.x+Number(r[0]),t.y1=t.y+Number(r[1]),t.x2=t.x+Number(r[2]),t.y2=t.y+Number(r[3]),t.x+=Number(r[4]),t.y+=Number(r[5]),i.bezierCurveTo(t.x1,t.y1,t.x2,t.y2,t.x,t.y);break;case"S":t.x1&&t.y1&&t.x2&&t.y2?(t.x1=t.x-t.x2+t.x,t.y1=t.y-t.y2+t.y,t.x2=Number(r[0]),t.y2=Number(r[1]),t.x=Number(r[2]),t.y=Number(r[3]),i.bezierCurveTo(t.x1,t.y1,t.x2,t.y2,t.x,t.y)):(t.x1=Number(r[0]),t.y1=Number(r[1]),t.x=Number(r[2]),t.y=Number(r[3]),i.quadraticCurveTo(t.x1,t.y1,t.x,t.y));break;case"s":t.x1&&t.y1&&t.x2&&t.y2?(t.x1=t.x-t.x2+t.x,t.y1=t.y-t.y2+t.y,t.x2=t.x+Number(r[0]),t.y2=t.y+Number(r[1]),t.x+=Number(r[2]),t.y+=Number(r[3]),i.bezierCurveTo(t.x1,t.y1,t.x2,t.y2,t.x,t.y)):(t.x1=t.x+Number(r[0]),t.y1=t.y+Number(r[1]),t.x+=Number(r[2]),t.y+=Number(r[3]),i.quadraticCurveTo(t.x1,t.y1,t.x,t.y));break;case"Q":t.x1=Number(r[0]),t.y1=Number(r[1]),t.x=Number(r[2]),t.y=Number(r[3]),i.quadraticCurveTo(t.x1,t.y1,t.x,t.y);break;case"q":t.x1=t.x+Number(r[0]),t.y1=t.y+Number(r[1]),t.x+=Number(r[2]),t.y+=Number(r[3]),i.quadraticCurveTo(t.x1,t.y1,t.x,t.y);break;case"A":case"a":break;case"Z":case"z":i.closePath()}},t.prototype.drawEllipse=function(t){var e=this.ctx;e.save(),this.resetShapeStyles(t),void 0!==t._transform&&null!==t._transform&&e.transform(t._transform.a,t._transform.b,t._transform.c,t._transform.d,t._transform.tx,t._transform.ty);var r=t._x-t._radiusX,i=t._y-t._radiusY,n=2*t._radiusX,o=2*t._radiusY,s=n/2*.5522848,a=o/2*.5522848,u=r+n,h=i+o,l=r+n/2,f=i+o/2;e.beginPath(),e.moveTo(r,f),e.bezierCurveTo(r,f-a,l-s,i,l,i),e.bezierCurveTo(l+s,i,u,f-a,u,f),e.bezierCurveTo(u,f+a,l+s,h,l,h),e.bezierCurveTo(l-s,h,r,f+a,r,f),t._styles&&t._styles.fill&&e.fill(),t._styles&&t._styles.stroke&&e.stroke(),e.restore()},t.prototype.drawRect=function(t){var e=this.ctx;e.save(),this.resetShapeStyles(t),void 0!==t._transform&&null!==t._transform&&e.transform(t._transform.a,t._transform.b,t._transform.c,t._transform.d,t._transform.tx,t._transform.ty);var r=t._x,i=t._y,n=t._width,o=t._height,s=t._cornerRadius;n<2*s&&(s=n/2),o<2*s&&(s=o/2),e.beginPath(),e.moveTo(r+s,i),e.arcTo(r+n,i,r+n,i+o,s),e.arcTo(r+n,i+o,r,i+o,s),e.arcTo(r,i+o,r,i,s),e.arcTo(r,i,r+n,i,s),e.closePath(),t._styles&&t._styles.fill&&e.fill(),t._styles&&t._styles.stroke&&e.stroke(),e.restore()},t}();r.Renderer=s},{36:36,37:37,44:44}],44:[function(t,e,r){"use strict";var i,n=this&&this.__extends||(i=function(t,e){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(t,e)},function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");function r(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(r,"__esModule",{value:!0}),r.RectPath=void 0;var o=function(t){function e(e,r,i,n,o,s,a){var u=t.call(this,"",s,a)||this;return u._x=e,u._y=r,u._width=i,u._height=n,u._cornerRadius=o,u._transform=s,u._styles=a,u}return n(e,t),e}(t(36).BezierPath);r.RectPath=o},{36:36}],46:[function(t,e,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.SpriteEntity=void 0;var i=t(38),n=function(t){var e,r;this.matteKey=t.matteKey,this.imageKey=t.imageKey,this.frames=null!==(r=null===(e=t.frames)||void 0===e?void 0:e.map((function(t){return new i.FrameEntity(t)})))&&void 0!==r?r:[]};r.SpriteEntity=n},{38:38}]},{},[39])(39)}));
\ No newline at end of file
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/package.json b/uni_modules/c-svga/node_modules/svgaplayer-weapp/package.json
new file mode 100644
index 0000000..b268648
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/package.json
@@ -0,0 +1,45 @@
+{
+ "_from": "svgaplayer-weapp@^1.0.0",
+ "_id": "svgaplayer-weapp@1.0.0",
+ "_inBundle": false,
+ "_integrity": "sha512-zH3y9rBHcvoRVsKwuuiRQkOP0cPeyFMxz9NJQZF+uvqwH7uO/LKLS0vEvjrRh2WhfynoXWsxxSTzWpc4Ix2cJw==",
+ "_location": "/svgaplayer-weapp",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "range",
+ "registry": true,
+ "raw": "svgaplayer-weapp@^1.0.0",
+ "name": "svgaplayer-weapp",
+ "escapedName": "svgaplayer-weapp",
+ "rawSpec": "^1.0.0",
+ "saveSpec": null,
+ "fetchSpec": "^1.0.0"
+ },
+ "_requiredBy": [
+ "/"
+ ],
+ "_resolved": "https://registry.npmmirror.com/svgaplayer-weapp/-/svgaplayer-weapp-1.0.0.tgz",
+ "_shasum": "3866a67a5355b4760bc1fae20d7d4f63b2e7cc05",
+ "_spec": "svgaplayer-weapp@^1.0.0",
+ "_where": "C:\\Users\\pc\\Documents\\HBuilderProjects\\Sapp\\uni_modules\\c-svga",
+ "author": "",
+ "bundleDependencies": false,
+ "deprecated": false,
+ "description": "专为微信小程序开发的 SVGA 播放器,已在 iOS 及 Android 手机上测试通过。",
+ "devDependencies": {
+ "@types/wechat-miniprogram": "^3.3.0",
+ "browserify": "^17.0.0",
+ "tinyify": "^3.0.0",
+ "tsify": "^5.0.4",
+ "typescript": "^4.3.2"
+ },
+ "license": "ISC",
+ "main": "dist/svgaplayer.weapp.js",
+ "miniprogram": "dist",
+ "name": "svgaplayer-weapp",
+ "scripts": {
+ "build": "node build.js > ./dist/svgaplayer.weapp.js"
+ },
+ "typings": "svgaplayer-weapp.d.ts",
+ "version": "1.0.0"
+}
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/protobuf.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/protobuf.js
new file mode 100644
index 0000000..ad11579
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/protobuf.js
@@ -0,0 +1,133 @@
+/**
+ * Created by zhangmiao on 2018/3/13.
+ */
+
+
+
+(function (protobufFactory){
+ //if (typeof define === 'function')//这里会不会定义重复呢?怎么去掉呢
+ // define('protobuf', protobufFactory);
+ //else
+ module.exports = protobufFactory();
+})(function(){
+ var protobuf = {};
+//app.globalData.protobuf = protobuf;
+
+ /**
+ * Build type, one of `"full"`, `"light"` or `"minimal"`.
+ * @name build
+ * @type {string}
+ * @const
+ */
+ protobuf.build = "minimal";
+
+// Serialization
+ protobuf.Writer = require("./src/writer");
+ protobuf.Reader = require("./src/reader");
+
+// Utility
+ protobuf.util = require("./src/util");
+ protobuf.rpc = require("./src/rpc/service");
+ protobuf.roots = require("./src/roots");
+ protobuf.verifier = require("./src/verifier");
+
+ protobuf.tokenize = require("./src/tokenize");
+ protobuf.parse = require("./src/parse");
+ protobuf.common = require("./src/common");
+
+ protobuf.ReflectionObject = require("./src/object");
+ protobuf.Namespace = require("./src/namespace");
+ protobuf.Root = require("./src/root");
+ protobuf.Enum = require("./src/enum");
+ protobuf.Type = require("./src/type");
+ protobuf.Field = require("./src/field");
+ protobuf.OneOf = require("./src/oneof");
+ protobuf.MapField = require("./src/mapField");
+ protobuf.Service = require("./src/service");
+ protobuf.Method = require("./src/method");
+ protobuf.converter = require("./src/converter");
+ protobuf.decoder = require("./src/decoder");
+
+// Runtime
+ protobuf.Message = require("./src/message");
+ protobuf.wrappers = require("./src/wrappers");
+
+// Utility
+ protobuf.types = require("./src/types");
+ protobuf.util = require("./src/util");
+
+ protobuf.configure = configure;
+
+
+ function load(filename, root, callback) {
+ if (typeof root === "function") {
+ callback = root;
+ root = new protobuf.Root();
+ } else if (!root)
+ root = new protobuf.Root();
+ return root.load(filename, callback);
+ }
+
+ protobuf.load = load;
+
+ function loadSync(filename, root) {
+ if (!root)
+ root = new protobuf.Root();
+ return root.loadSync(filename);
+ }
+
+ protobuf.loadSync = loadSync;
+
+
+//新增weichat支持的解析pbConfig接口
+ function parseFromPbString(pbString, root, callback){
+ if (typeof root === "function") {
+ callback = root;
+ root = new protobuf.Root();
+ } else if (!root)
+ root = new protobuf.Root();
+ return root.parseFromPbString(pbString, callback);
+ }
+
+ protobuf.parseFromPbString = parseFromPbString;
+
+ /**
+ * Reconfigures the library according to the environment.
+ * @returns {undefined}
+ */
+ function configure() {
+
+ protobuf.converter._configure();
+ protobuf.decoder._configure();
+ protobuf.Field._configure();
+ protobuf.MapField._configure();
+ protobuf.Message._configure();
+ protobuf.Namespace._configure();
+ protobuf.Method._configure();
+ protobuf.ReflectionObject._configure();
+ protobuf.OneOf._configure();
+ protobuf.parse._configure();
+ protobuf.Reader._configure();
+ protobuf.Root._configure();
+ protobuf.Service._configure();
+ protobuf.verifier._configure();
+ protobuf.Type._configure();
+ protobuf.types._configure();
+ protobuf.wrappers._configure();
+ protobuf.Writer._configure();
+ }
+ configure();
+
+ if(arguments&&arguments.length){
+ for (var i = 0 ;i < arguments.length; i++){
+ var argument = arguments[i];
+ if(argument.hasOwnProperty("exports")){
+ argument.exports = protobuf;
+ return;
+ }
+ }
+ }
+ return protobuf;
+});
+
+
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/EventEmitter.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/EventEmitter.js
new file mode 100644
index 0000000..f766fd0
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/EventEmitter.js
@@ -0,0 +1,76 @@
+"use strict";
+module.exports = EventEmitter;
+
+/**
+ * Constructs a new event emitter instance.
+ * @classdesc A minimal event emitter.
+ * @memberof util
+ * @constructor
+ */
+function EventEmitter() {
+
+ /**
+ * Registered listeners.
+ * @type {Object.}
+ * @private
+ */
+ this._listeners = {};
+}
+
+/**
+ * Registers an event listener.
+ * @param {string} evt Event name
+ * @param {function} fn Listener
+ * @param {*} [ctx] Listener context
+ * @returns {util.EventEmitter} `this`
+ */
+EventEmitter.prototype.on = function on(evt, fn, ctx) {
+ (this._listeners[evt] || (this._listeners[evt] = [])).push({
+ fn : fn,
+ ctx : ctx || this
+ });
+ return this;
+};
+
+/**
+ * Removes an event listener or any matching listeners if arguments are omitted.
+ * @param {string} [evt] Event name. Removes all listeners if omitted.
+ * @param {function} [fn] Listener to remove. Removes all listeners of `evt` if omitted.
+ * @returns {util.EventEmitter} `this`
+ */
+EventEmitter.prototype.off = function off(evt, fn) {
+ if (evt === undefined)
+ this._listeners = {};
+ else {
+ if (fn === undefined)
+ this._listeners[evt] = [];
+ else {
+ var listeners = this._listeners[evt];
+ for (var i = 0; i < listeners.length;)
+ if (listeners[i].fn === fn)
+ listeners.splice(i, 1);
+ else
+ ++i;
+ }
+ }
+ return this;
+};
+
+/**
+ * Emits an event by calling its listeners with the specified arguments.
+ * @param {string} evt Event name
+ * @param {...*} args Arguments
+ * @returns {util.EventEmitter} `this`
+ */
+EventEmitter.prototype.emit = function emit(evt) {
+ var listeners = this._listeners[evt];
+ if (listeners) {
+ var args = [],
+ i = 1;
+ for (; i < arguments.length;)
+ args.push(arguments[i++]);
+ for (i = 0; i < listeners.length;)
+ listeners[i].fn.apply(listeners[i++].ctx, args);
+ }
+ return this;
+};
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/asPromise.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/asPromise.js
new file mode 100644
index 0000000..d6f642c
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/asPromise.js
@@ -0,0 +1,52 @@
+"use strict";
+module.exports = asPromise;
+
+/**
+ * Callback as used by {@link util.asPromise}.
+ * @typedef asPromiseCallback
+ * @type {function}
+ * @param {Error|null} error Error, if any
+ * @param {...*} params Additional arguments
+ * @returns {undefined}
+ */
+
+/**
+ * Returns a promise from a node-style callback function.
+ * @memberof util
+ * @param {asPromiseCallback} fn Function to call
+ * @param {*} ctx Function context
+ * @param {...*} params Function arguments
+ * @returns {Promise<*>} Promisified function
+ */
+function asPromise(fn, ctx/*, varargs */) {
+ var params = new Array(arguments.length - 1),
+ offset = 0,
+ index = 2,
+ pending = true;
+ while (index < arguments.length)
+ params[offset++] = arguments[index++];
+ return new Promise(function executor(resolve, reject) {
+ params[offset] = function callback(err/*, varargs */) {
+ if (pending) {
+ pending = false;
+ if (err)
+ reject(err);
+ else {
+ var params = new Array(arguments.length - 1),
+ offset = 0;
+ while (offset < params.length)
+ params[offset++] = arguments[offset];
+ resolve.apply(null, params);
+ }
+ }
+ };
+ try {
+ fn.apply(ctx || null, params);
+ } catch (err) {
+ if (pending) {
+ pending = false;
+ reject(err);
+ }
+ }
+ });
+}
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/base64.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/base64.js
new file mode 100644
index 0000000..dd2855b
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/base64.js
@@ -0,0 +1,139 @@
+"use strict";
+
+/**
+ * A minimal base64 implementation for number arrays.
+ * @memberof util
+ * @namespace
+ */
+var base64 = module.exports;
+
+/**
+ * Calculates the byte length of a base64 encoded string.
+ * @param {string} string Base64 encoded string
+ * @returns {number} Byte length
+ */
+base64.length = function length(string) {
+ var p = string.length;
+ if (!p)
+ return 0;
+ var n = 0;
+ while (--p % 4 > 1 && string.charAt(p) === "=")
+ ++n;
+ return Math.ceil(string.length * 3) / 4 - n;
+};
+
+// Base64 encoding table
+var b64 = new Array(64);
+
+// Base64 decoding table
+var s64 = new Array(123);
+
+// 65..90, 97..122, 48..57, 43, 47
+for (var i = 0; i < 64;)
+ s64[b64[i] = i < 26 ? i + 65 : i < 52 ? i + 71 : i < 62 ? i - 4 : i - 59 | 43] = i++;
+
+/**
+ * Encodes a buffer to a base64 encoded string.
+ * @param {Uint8Array} buffer Source buffer
+ * @param {number} start Source start
+ * @param {number} end Source end
+ * @returns {string} Base64 encoded string
+ */
+base64.encode = function encode(buffer, start, end) {
+ var parts = null,
+ chunk = [];
+ var i = 0, // output index
+ j = 0, // goto index
+ t; // temporary
+ while (start < end) {
+ var b = buffer[start++];
+ switch (j) {
+ case 0:
+ chunk[i++] = b64[b >> 2];
+ t = (b & 3) << 4;
+ j = 1;
+ break;
+ case 1:
+ chunk[i++] = b64[t | b >> 4];
+ t = (b & 15) << 2;
+ j = 2;
+ break;
+ case 2:
+ chunk[i++] = b64[t | b >> 6];
+ chunk[i++] = b64[b & 63];
+ j = 0;
+ break;
+ }
+ if (i > 8191) {
+ (parts || (parts = [])).push(String.fromCharCode.apply(String, chunk));
+ i = 0;
+ }
+ }
+ if (j) {
+ chunk[i++] = b64[t];
+ chunk[i++] = 61;
+ if (j === 1)
+ chunk[i++] = 61;
+ }
+ if (parts) {
+ if (i)
+ parts.push(String.fromCharCode.apply(String, chunk.slice(0, i)));
+ return parts.join("");
+ }
+ return String.fromCharCode.apply(String, chunk.slice(0, i));
+};
+
+var invalidEncoding = "invalid encoding";
+
+/**
+ * Decodes a base64 encoded string to a buffer.
+ * @param {string} string Source string
+ * @param {Uint8Array} buffer Destination buffer
+ * @param {number} offset Destination offset
+ * @returns {number} Number of bytes written
+ * @throws {Error} If encoding is invalid
+ */
+base64.decode = function decode(string, buffer, offset) {
+ var start = offset;
+ var j = 0, // goto index
+ t; // temporary
+ for (var i = 0; i < string.length;) {
+ var c = string.charCodeAt(i++);
+ if (c === 61 && j > 1)
+ break;
+ if ((c = s64[c]) === undefined)
+ throw Error(invalidEncoding);
+ switch (j) {
+ case 0:
+ t = c;
+ j = 1;
+ break;
+ case 1:
+ buffer[offset++] = t << 2 | (c & 48) >> 4;
+ t = c;
+ j = 2;
+ break;
+ case 2:
+ buffer[offset++] = (t & 15) << 4 | (c & 60) >> 2;
+ t = c;
+ j = 3;
+ break;
+ case 3:
+ buffer[offset++] = (t & 3) << 6 | c;
+ j = 0;
+ break;
+ }
+ }
+ if (j === 1)
+ throw Error(invalidEncoding);
+ return offset - start;
+};
+
+/**
+ * Tests if the specified string appears to be base64 encoded.
+ * @param {string} string String to test
+ * @returns {boolean} `true` if probably base64 encoded, otherwise false
+ */
+base64.test = function test(string) {
+ return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(string);
+};
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/common.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/common.js
new file mode 100644
index 0000000..fbf4e95
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/common.js
@@ -0,0 +1,398 @@
+module.exports = common;
+
+var commonRe = /\/|\./;
+
+/**
+ * Provides common type definitions.
+ * Can also be used to provide additional google types or your own custom types.
+ * @param {string} name Short name as in `google/protobuf/[name].proto` or full file name
+ * @param {Object.} json JSON definition within `google.protobuf` if a short name, otherwise the file's root definition
+ * @returns {undefined}
+ * @property {INamespace} google/protobuf/any.proto Any
+ * @property {INamespace} google/protobuf/duration.proto Duration
+ * @property {INamespace} google/protobuf/empty.proto Empty
+ * @property {INamespace} google/protobuf/field_mask.proto FieldMask
+ * @property {INamespace} google/protobuf/struct.proto Struct, Value, NullValue and ListValue
+ * @property {INamespace} google/protobuf/timestamp.proto Timestamp
+ * @property {INamespace} google/protobuf/wrappers.proto Wrappers
+ * @example
+ * // manually provides descriptor.proto (assumes google/protobuf/ namespace and .proto extension)
+ * protobuf.common("descriptor", descriptorJson);
+ *
+ * // manually provides a custom definition (uses my.foo namespace)
+ * protobuf.common("my/foo/bar.proto", myFooBarJson);
+ */
+function common(name, json) {
+ if (!commonRe.test(name)) {
+ name = "google/protobuf/" + name + ".proto";
+ json = { nested: { google: { nested: { protobuf: { nested: json } } } } };
+ }
+ common[name] = json;
+}
+
+// Not provided because of limited use (feel free to discuss or to provide yourself):
+//
+// google/protobuf/descriptor.proto
+// google/protobuf/source_context.proto
+// google/protobuf/type.proto
+//
+// Stripped and pre-parsed versions of these non-bundled files are instead available as part of
+// the repository or package within the google/protobuf directory.
+
+common("any", {
+
+ /**
+ * Properties of a google.protobuf.Any message.
+ * @interface IAny
+ * @type {Object}
+ * @property {string} [typeUrl]
+ * @property {Uint8Array} [bytes]
+ * @memberof common
+ */
+ Any: {
+ fields: {
+ type_url: {
+ type: "string",
+ id: 1
+ },
+ value: {
+ type: "bytes",
+ id: 2
+ }
+ }
+ }
+});
+
+var timeType;
+
+common("duration", {
+
+ /**
+ * Properties of a google.protobuf.Duration message.
+ * @interface IDuration
+ * @type {Object}
+ * @property {number|Long} [seconds]
+ * @property {number} [nanos]
+ * @memberof common
+ */
+ Duration: timeType = {
+ fields: {
+ seconds: {
+ type: "int64",
+ id: 1
+ },
+ nanos: {
+ type: "int32",
+ id: 2
+ }
+ }
+ }
+});
+
+common("timestamp", {
+
+ /**
+ * Properties of a google.protobuf.Timestamp message.
+ * @interface ITimestamp
+ * @type {Object}
+ * @property {number|Long} [seconds]
+ * @property {number} [nanos]
+ * @memberof common
+ */
+ Timestamp: timeType
+});
+
+common("empty", {
+
+ /**
+ * Properties of a google.protobuf.Empty message.
+ * @interface IEmpty
+ * @memberof common
+ */
+ Empty: {
+ fields: {}
+ }
+});
+
+common("struct", {
+
+ /**
+ * Properties of a google.protobuf.Struct message.
+ * @interface IStruct
+ * @type {Object}
+ * @property {Object.} [fields]
+ * @memberof common
+ */
+ Struct: {
+ fields: {
+ fields: {
+ keyType: "string",
+ type: "Value",
+ id: 1
+ }
+ }
+ },
+
+ /**
+ * Properties of a google.protobuf.Value message.
+ * @interface IValue
+ * @type {Object}
+ * @property {string} [kind]
+ * @property {0} [nullValue]
+ * @property {number} [numberValue]
+ * @property {string} [stringValue]
+ * @property {boolean} [boolValue]
+ * @property {IStruct} [structValue]
+ * @property {IListValue} [listValue]
+ * @memberof common
+ */
+ Value: {
+ oneofs: {
+ kind: {
+ oneof: [
+ "nullValue",
+ "numberValue",
+ "stringValue",
+ "boolValue",
+ "structValue",
+ "listValue"
+ ]
+ }
+ },
+ fields: {
+ nullValue: {
+ type: "NullValue",
+ id: 1
+ },
+ numberValue: {
+ type: "double",
+ id: 2
+ },
+ stringValue: {
+ type: "string",
+ id: 3
+ },
+ boolValue: {
+ type: "bool",
+ id: 4
+ },
+ structValue: {
+ type: "Struct",
+ id: 5
+ },
+ listValue: {
+ type: "ListValue",
+ id: 6
+ }
+ }
+ },
+
+ NullValue: {
+ values: {
+ NULL_VALUE: 0
+ }
+ },
+
+ /**
+ * Properties of a google.protobuf.ListValue message.
+ * @interface IListValue
+ * @type {Object}
+ * @property {Array.} [values]
+ * @memberof common
+ */
+ ListValue: {
+ fields: {
+ values: {
+ rule: "repeated",
+ type: "Value",
+ id: 1
+ }
+ }
+ }
+});
+
+common("wrappers", {
+
+ /**
+ * Properties of a google.protobuf.DoubleValue message.
+ * @interface IDoubleValue
+ * @type {Object}
+ * @property {number} [value]
+ * @memberof common
+ */
+ DoubleValue: {
+ fields: {
+ value: {
+ type: "double",
+ id: 1
+ }
+ }
+ },
+
+ /**
+ * Properties of a google.protobuf.FloatValue message.
+ * @interface IFloatValue
+ * @type {Object}
+ * @property {number} [value]
+ * @memberof common
+ */
+ FloatValue: {
+ fields: {
+ value: {
+ type: "float",
+ id: 1
+ }
+ }
+ },
+
+ /**
+ * Properties of a google.protobuf.Int64Value message.
+ * @interface IInt64Value
+ * @type {Object}
+ * @property {number|Long} [value]
+ * @memberof common
+ */
+ Int64Value: {
+ fields: {
+ value: {
+ type: "int64",
+ id: 1
+ }
+ }
+ },
+
+ /**
+ * Properties of a google.protobuf.UInt64Value message.
+ * @interface IUInt64Value
+ * @type {Object}
+ * @property {number|Long} [value]
+ * @memberof common
+ */
+ UInt64Value: {
+ fields: {
+ value: {
+ type: "uint64",
+ id: 1
+ }
+ }
+ },
+
+ /**
+ * Properties of a google.protobuf.Int32Value message.
+ * @interface IInt32Value
+ * @type {Object}
+ * @property {number} [value]
+ * @memberof common
+ */
+ Int32Value: {
+ fields: {
+ value: {
+ type: "int32",
+ id: 1
+ }
+ }
+ },
+
+ /**
+ * Properties of a google.protobuf.UInt32Value message.
+ * @interface IUInt32Value
+ * @type {Object}
+ * @property {number} [value]
+ * @memberof common
+ */
+ UInt32Value: {
+ fields: {
+ value: {
+ type: "uint32",
+ id: 1
+ }
+ }
+ },
+
+ /**
+ * Properties of a google.protobuf.BoolValue message.
+ * @interface IBoolValue
+ * @type {Object}
+ * @property {boolean} [value]
+ * @memberof common
+ */
+ BoolValue: {
+ fields: {
+ value: {
+ type: "bool",
+ id: 1
+ }
+ }
+ },
+
+ /**
+ * Properties of a google.protobuf.StringValue message.
+ * @interface IStringValue
+ * @type {Object}
+ * @property {string} [value]
+ * @memberof common
+ */
+ StringValue: {
+ fields: {
+ value: {
+ type: "string",
+ id: 1
+ }
+ }
+ },
+
+ /**
+ * Properties of a google.protobuf.BytesValue message.
+ * @interface IBytesValue
+ * @type {Object}
+ * @property {Uint8Array} [value]
+ * @memberof common
+ */
+ BytesValue: {
+ fields: {
+ value: {
+ type: "bytes",
+ id: 1
+ }
+ }
+ }
+});
+
+common("field_mask", {
+
+ /**
+ * Properties of a google.protobuf.FieldMask message.
+ * @interface IDoubleValue
+ * @type {Object}
+ * @property {number} [value]
+ * @memberof common
+ */
+ FieldMask: {
+ fields: {
+ paths: {
+ rule: "repeated",
+ type: "string",
+ id: 1
+ }
+ }
+ }
+});
+
+/**
+ * Gets the root definition of the specified common proto file.
+ *
+ * Bundled definitions are:
+ * - google/protobuf/any.proto
+ * - google/protobuf/duration.proto
+ * - google/protobuf/empty.proto
+ * - google/protobuf/field_mask.proto
+ * - google/protobuf/struct.proto
+ * - google/protobuf/timestamp.proto
+ * - google/protobuf/wrappers.proto
+ *
+ * @param {string} file Proto file name
+ * @returns {INamespace|null} Root definition or `null` if not defined
+ */
+common.get = function get(file) {
+ return common[file] || null;
+};
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/converter.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/converter.js
new file mode 100644
index 0000000..67e1f60
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/converter.js
@@ -0,0 +1,330 @@
+/**
+ * Created by zhangmiao on 2018/3/14.
+ * 写这个,有点难;有错误请指出 ,微信中不能Function.Apply 和evl,所以去掉其中所有的gen()
+ */
+var converter = module.exports;
+
+var Enum,
+ util;
+
+
+converter._configure = function () {
+ Enum = require('./enum');
+ util = require('./util');
+};
+
+function valuePartial_fromObject(field, fieldIndex, propName, options){
+ var m = options['m'];
+ var d = options['d'];
+ var _types = options['types'];
+ var ksi = options['ksi'];
+ var ksiFlag = typeof ksi != 'undefined';
+ if(field.resolvedType){
+ if(field.resolvedType instanceof Enum){
+ var prop = ksiFlag ? d[propName][ksi] : d[propName];
+ var values = field.resolvedType.values,
+ keys = Object.keys(values);
+ for (var i = 0; i < keys.length; i++){
+ if(field.repeated && values[keys[i]] === field.typeDefault){
+ continue;
+ }
+ if(keys[i] == prop || values[keys[i]] == prop){
+ ksiFlag ?
+ m[propName][ksi] = values[keys[i]] :
+ m[propName] = values[keys[i]];
+ break
+ }
+ }
+ }else {
+ if(typeof (ksiFlag ? d[propName][ksi] : d[propName]) !== 'object')
+ throw TypeError(field.fullName + ": object expected");
+ ksiFlag ?
+ m[propName][ksi] = _types[fieldIndex].fromObject(d[propName][ksi]):
+ m[propName] = _types[fieldIndex].fromObject(d[propName]);
+ }
+ } else {
+ var isUnsigned = false;
+ switch (field.type){
+ case "double":
+ case "float":
+ ksiFlag ?
+ m[propName][ksi] = Number(d[propName][ksi]) :
+ m[propName] = Number(d[propName]);
+ break;
+ case "uint32":
+ case "fixed32":
+ ksiFlag ?
+ m[propName][ksi] = d[propName][ksi] >>> 0:
+ m[propName] = d[propName] >>> 0;
+ break;
+ case "int32":
+ case "sint32":
+ case "sfixed32":
+ ksiFlag ?
+ m[propName][ksi] = d[propName][ksi] | 0 :
+ m[propName] = d[propName] |0;
+ break;
+ case "uint64":
+ isUnsigned = true;
+ // eslint-disable-line no-fallthrough
+ case "int64":
+ case "sint64":
+ case "fixed64":
+ case "sfixed64":
+ if(util.Long)
+ ksiFlag ?
+ m[propName][ksi] = util.Long.fromValue(d[propName][ksi]).unsigned = isUnsigned :
+ m[propName] = util.Long.fromValue(d[propName]).unsigned = isUnsigned;
+ else if(typeof (ksiFlag ? d[propName][ksi] : d[propName]) === 'string')
+ ksiFlag ?
+ m[propName][ksi] =parseInt(d[propName][ksi], 10) :
+ m[propName] =parseInt(d[propName], 10);
+ else if(typeof (ksiFlag ? d[propName][ksi] : d[propName]) === 'number')
+ ksiFlag ?
+ m[propName][ksi] = d[propName][ksi] :
+ m[propName] = d[propName];
+ else if(typeof (ksiFlag ? d[propName][ksi] : d[propName]) === 'object')
+ ksiFlag ?
+ m[propName][ksi] = new util.LongBits(d[propName][ksi].low >>> 0, d[propName][ksi].high >>> 0).toNumber(isUnsigned) :
+ m[propName] = new util.LongBits(d[propName].low >>> 0, d[propName].high >>> 0).toNumber(isUnsigned);
+ break;
+ case "bytes":
+ if(typeof (ksiFlag ? d[propName][ksi] : d[propName]) ==="string")
+ ksiFlag ?
+ util.base64.decode(d[propName][ksi],m[propName][ksi]=util.newBuffer(util.base64.length(d[propName][ksi])),0) :
+ util.base64.decode(d[propName],m[propName]=util.newBuffer(util.base64.length(d[propName])),0);
+ else if((ksiFlag ? d[propName][ksi] : d[propName]).length)
+ ksiFlag?
+ m[propName][ksi]=d[propName][ksi] :
+ m[propName]=d[propName];
+ break;
+ case "string":
+ ksiFlag?
+ m[propName][ksi]=String(d[propName][ksi]) :
+ m[propName]=String(d[propName]);
+ break;
+ case "bool":
+ ksiFlag?
+ m[propName][ksi]=Boolean(d[propName][ksi]):
+ m[propName]=Boolean(d[propName]);
+ break;
+ }
+ }
+}
+
+/*
+* @param {Type} mtype Message type
+* @returns {Function} Function instance
+*/
+converter.fromObject = function fromObject(mtype){
+ var fields = mtype.fieldsArray;
+ return function (options){
+ return function (d){
+ if(d instanceof this.ctor)
+ return d;
+ if(!fields.length)
+ return new this.ctor;
+
+ var m = new this.ctor;
+ for (var i = 0; i < fields.length; ++i){
+ var field = fields[i].resolve();
+ var propName = field.name;
+ var _i;
+ if(field.map){
+ if(d[propName]){
+ if(typeof d[propName] !== 'object')
+ throw TypeError(field.fullName + ": object expected");
+ m[propName] = {};
+ }
+ var ks = Object.keys(d[propName]);
+ for ( _i = 0; _i>> 0, m[propName][ksi].high >>> 0).toNumber(isUnsigned) : m[propName][ksi]):
+ (d[propName] =
+ o.longs === String ?
+ util.Long.prototype.toString.call(m[propName]) :
+ o.longs === Number ? new util.LongBits(m[propName].low >>> 0, m[propName].high >>> 0).toNumber(isUnsigned) : m[propName]);
+ break;
+ case "bytes":
+ ksiFlag?
+ (d[propName][ksi] =
+ o.bytes === String ?
+ util.base64.encode(m[propName][ksi], 0, m[propName][ksi].length) :
+ o.bytes === Array ? Array.prototype.slice.call(m[propName][ksi]) : m[propName][ksi]):
+ (d[propName] =
+ o.bytes === String ?
+ util.base64.encode(m[propName], 0, m[propName].length) :
+ o.bytes === Array ? Array.prototype.slice.call(m[propName]) : m[propName]);
+ break;
+ default:
+ ksiFlag ? d[propName][ksi] = m[propName][ksi] : d[propName] = m[propName];
+ break;
+ }
+ }
+}
+
+
+converter.toObject = function toObject(mtype){
+ var fields = mtype.fieldsArray.slice().sort(util.compareFieldsById);
+ return function (options){
+ if(!fields.length)
+ return function (){
+ return {};
+ };
+ return function (m, o){
+ o = o || {};
+ var d = {};
+ var repeatedFields = [],
+ mapFields = [],
+ normalFields = [],
+ field,
+ propName,
+ i = 0;
+ for (; i < fields.length; ++i)
+ if (!fields[i].partOf)
+ ( fields[i].resolve().repeated ? repeatedFields
+ : fields[i].map ? mapFields
+ : normalFields).push(fields[i]);
+
+ if (repeatedFields.length) {
+ if(o.arrays || o.defaults ){
+ for (i = 0; i < repeatedFields.length; ++i)
+ d[repeatedFields[i].name] = [];
+ }
+ }
+
+ if (mapFields.length) {
+ if(o.objects || o.defaults){
+ for (i = 0; i < mapFields.length; ++i)
+ d[mapFields[i].name] = {};
+ }
+ }
+
+ if(normalFields.length){
+ if(o.defaults){
+ for (i = 0; i < normalFields.length; ++i){
+ field = normalFields[i],
+ propName = field.name;
+ if(field.resolvedType instanceof Enum)
+ d[propName] = o.enums = String ? field.resolvedType.valuesById[field.typeDefault] : field.typeDefault;
+ else if(field.long){
+ if(util.Long){
+ var n = new util.Long(field.typeDefault.low, field.typeDefault.high, field.typeDefault.unsigned);
+ d[propName] = o.longs === String ? n.toString() : o.longs === Number ? n.toNumber():n;
+ }else {
+ d[propName] = o.longs === String ? field.typeDefault.toString() : field.typeDefault.toNumber();
+ }
+ }else if(field.bytes){
+ d[propName] = o.bytes === String ? String.fromCharCode.apply(String, field.typeDefault) : Array.prototype.slice.call(field.typeDefault).join('*..*').split("*..*");
+ }else {
+ d[propName] =field.typeDefault;
+ }
+
+ }
+ }
+ }
+ var hasKs2 = false;
+ for (i = 0; i < fields.length; ++i){
+ field = fields[i];
+ propName = field.name;
+ var index = mtype._fieldsArray.indexOf(field);
+ var ks2;
+ var j;
+ if(field.map){
+ if (!hasKs2){
+ hasKs2 = true;
+ }
+ if (m[propName]&&(ks2 = Object.keys(m[propName]).length)){
+ d[propName] = {};
+ for (j = 0; j < ks2.length; ++j){
+ valuePartial_toObject(field, index, propName, util.merge(util.copy(options), {m:m,d:d,ksi :ks2[j],o:o}));
+ }
+ }
+ }else if(field.repeated){
+ if(m[propName]&&m[propName].length){
+ d[propName] = [];
+ for (j = 0; j < m[propName].length; ++j){
+ valuePartial_toObject(field, index, propName, util.merge(util.copy(options), {m:m,d:d,ksi:j,o:o}))
+ }
+ }
+ }else {
+ if(m[propName]!=null&& (m.hasOwnProperty(propName)/*|| field.partOf*/)){
+ valuePartial_toObject(field, index, propName, util.merge(util.copy(options), {m:m,d:d,o:o}))
+ }
+ if(field.partOf) {
+ if (o.oneofs)
+ d[field.partOf.name] = propName;
+ }
+ }
+ }
+ return d;
+ }
+ }
+
+
+};
\ No newline at end of file
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/decoder.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/decoder.js
new file mode 100644
index 0000000..0e1fef8
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/decoder.js
@@ -0,0 +1,118 @@
+/**
+ * Created by zhangmiao on 2018/3/13.
+ */
+
+var Enum,
+ types,
+ util;
+
+
+function missing(field) {
+ return "missing required '" + field.name + "'";
+}
+
+function decoder(mtype){
+ return function (options){
+ var Reader = options.Reader;
+ var _types = options.types;
+ var _util = options.util;
+ return function (r, l){
+ if(!(r instanceof Reader))
+ r = Reader.create(r);
+ var c = l === undefined ? r.len : r.pos + l,
+ m = new this.ctor;
+ var k;
+ while (r.pos < c){
+ var t = r.uint32();
+ if (mtype.group){
+ if((t&7) === 4)
+ break;
+ }
+ var fieldId = t>>>3;
+ var i = 0;
+ var find = false;
+ for (; i < mtype.fieldsArray.length; ++i){
+ var field = mtype._fieldsArray[i].resolve(),
+ name = field.name,
+ type = field.resolvedType instanceof Enum ? "int32" : field.type;
+ //ref = m[field.name];
+ if (fieldId != field.id) continue;
+ find = true;
+ if (field.map){
+ r.skip().pos++;
+ if(m[name] === _util.emptyObject)
+ m[name] = {};
+ k = r[field.keyType]();
+ r.pos++;
+ if(types.long[field.keyType] != undefined){
+ if(types.basic[type] == undefined){
+ m[name][typeof k ==='object' ? _util.longToHash(k):k] = _types[i].decode(r, r.uint32());
+ }else {
+ m[name][typeof k ==='object' ? _util.longToHash(k):k] = r[type]();
+ }
+ }else {
+ if(types.basic[type] == undefined){
+ m[name][typeof k === 'object' ? _util.longToHash(k) : k] = _types[i].decode(r, r.uint32());
+ }else {
+ m[name][typeof k === 'object' ? _util.longToHash(k) : k] = r[type]();
+ }
+ }
+ }else if(field.repeated){
+ if(!(m[name] && m[name].length)){
+ m[name] = [];
+ }
+
+ if(types.packed[type] != undefined && (t&7) === 2){
+ var c2 = r.uint32()+ r.pos;
+ while (r.pos < c2)
+ m[name].push(r[type]())
+ }else {
+ if(types.basic[type] == undefined){
+ field.resolvedType.group ?
+ m[name].push(_types[i].decode(r)) :
+ m[name].push(_types[i].decode(r, r.uint32()))
+
+ }else {
+ m[name].push(r[type]());
+ }
+ }
+ }else if (types.basic[type] == undefined){
+ if(field.resolvedType.group){
+ m[name] = _types[i].decode(r);
+ }else {
+ m[name] = _types[i].decode(r, r.uint32());
+ }
+ }else {
+ //console.log("m",JSON.stringify(m),"type",type,"field",field);
+ m[name] = r[type]();
+ }
+ break;
+ }
+
+ if(!find){
+ console.log("t",t);
+ r.skipType(t&7)
+ }
+
+ }
+
+ for (i = 0; i < mtype._fieldsArray.length; ++ i){
+ var rfield = mtype._fieldsArray[i];
+ if(rfield.required){
+ if(!m.hasOwnProperty(rfield.name)){
+ throw util.ProtocolError(missing(rfield),{instance:m})
+ }
+ }
+ }
+ //mtype.fieldsArray.filter(function(field) { return field.map; }).length
+ return m;
+ }
+ }
+}
+
+module.exports = decoder;
+decoder._configure = function (){
+ Enum = require("./enum");
+ types = require("./types");
+ util = require("./util");
+};
\ No newline at end of file
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/enum.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/enum.js
new file mode 100644
index 0000000..f9c4ceb
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/enum.js
@@ -0,0 +1,171 @@
+/**
+ * Created by zhangmiao on 2018/3/12.
+ */
+
+module.exports = Enum;
+
+var ReflectionObject = require("./object");
+
+((Enum.prototype = Object.create(ReflectionObject.prototype)).constructor = Enum).className = "Enum";
+var Namespace = require("./namespace");
+
+function Enum(name, values, options, comment, comments) {
+ ReflectionObject.call(this, name, options);
+
+ if (values && typeof values !== "object")
+ throw TypeError("values must be an object");
+
+ /**
+ * Enum values by id.
+ * @type {Object.}
+ */
+ this.valuesById = {};
+
+ /**
+ * Enum values by name.
+ * @type {Object.}
+ */
+ this.values = Object.create(this.valuesById); // toJSON, marker
+
+ /**
+ * Enum comment text.
+ * @type {string|null}
+ */
+ this.comment = comment;
+
+ /**
+ * Value comment texts, if any.
+ * @type {Object.}
+ */
+ this.comments = comments || {};
+
+ /**
+ * Reserved ranges, if any.
+ * @type {Array.}
+ */
+ this.reserved = undefined; // toJSON
+
+ // Note that values inherit valuesById on their prototype which makes them a TypeScript-
+ // compatible enum. This is used by pbts to write actual enum definitions that work for
+ // static and reflection code alike instead of emitting generic object definitions.
+
+ if (values)
+ for (var keys = Object.keys(values), i = 0; i < keys.length; ++i)
+ if (typeof values[keys[i]] === "number") // use forward entries only
+ this.valuesById[ this.values[keys[i]] = values[keys[i]] ] = keys[i];
+}
+
+/**
+ * Enum descriptor.
+ * @interface IEnum
+ * @property {Object.} values Enum values
+ * @property {Object.} [options] Enum options
+ */
+
+/**
+ * Constructs an enum from an enum descriptor.
+ * @param {string} name Enum name
+ * @param {IEnum} json Enum descriptor
+ * @returns {Enum} Created enum
+ * @throws {TypeError} If arguments are invalid
+ */
+Enum.fromJSON = function fromJSON(name, json) {
+ var enm = new Enum(name, json.values, json.options, json.comment, json.comments);
+ enm.reserved = json.reserved;
+ return enm;
+};
+
+/**
+ * Converts this enum to an enum descriptor.
+ * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
+ * @returns {IEnum} Enum descriptor
+ */
+Enum.prototype.toJSON = function toJSON(toJSONOptions) {
+ var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
+ return util.toObject([
+ "options" , this.options,
+ "values" , this.values,
+ "reserved" , this.reserved && this.reserved.length ? this.reserved : undefined,
+ "comment" , keepComments ? this.comment : undefined,
+ "comments" , keepComments ? this.comments : undefined
+ ]);
+};
+
+/**
+ * Adds a value to this enum.
+ * @param {string} name Value name
+ * @param {number} id Value id
+ * @param {string} [comment] Comment, if any
+ * @returns {Enum} `this`
+ * @throws {TypeError} If arguments are invalid
+ * @throws {Error} If there is already a value with this name or id
+ */
+Enum.prototype.add = function add(name, id, comment) {
+ // utilized by the parser but not by .fromJSON
+
+ if (!util.isString(name))
+ throw TypeError("name must be a string");
+
+ if (!util.isInteger(id))
+ throw TypeError("id must be an integer");
+
+ if (this.values[name] !== undefined)
+ throw Error("duplicate name '" + name + "' in " + this);
+
+ if (this.isReservedId(id))
+ throw Error("id " + id + " is reserved in " + this);
+
+ if (this.isReservedName(name))
+ throw Error("name '" + name + "' is reserved in " + this);
+
+ if (this.valuesById[id] !== undefined) {
+ if (!(this.options && this.options.allow_alias))
+ throw Error("duplicate id " + id + " in " + this);
+ this.values[name] = id;
+ } else
+ this.valuesById[this.values[name] = id] = name;
+
+ this.comments[name] = comment || null;
+ return this;
+};
+
+/**
+ * Removes a value from this enum
+ * @param {string} name Value name
+ * @returns {Enum} `this`
+ * @throws {TypeError} If arguments are invalid
+ * @throws {Error} If `name` is not a name of this enum
+ */
+Enum.prototype.remove = function remove(name) {
+
+ if (!util.isString(name))
+ throw TypeError("name must be a string");
+
+ var val = this.values[name];
+ if (val == null)
+ throw Error("name '" + name + "' does not exist in " + this);
+
+ delete this.valuesById[val];
+ delete this.values[name];
+ delete this.comments[name];
+
+ return this;
+};
+
+/**
+ * Tests if the specified id is reserved.
+ * @param {number} id Id to test
+ * @returns {boolean} `true` if reserved, otherwise `false`
+ */
+Enum.prototype.isReservedId = function isReservedId(id) {
+ return Namespace.isReservedId(this.reserved, id);
+};
+
+/**
+ * Tests if the specified name is reserved.
+ * @param {string} name Name to test
+ * @returns {boolean} `true` if reserved, otherwise `false`
+ */
+Enum.prototype.isReservedName = function isReservedName(name) {
+ return Namespace.isReservedName(this.reserved, name);
+};
\ No newline at end of file
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/field.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/field.js
new file mode 100644
index 0000000..8de03d6
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/field.js
@@ -0,0 +1,377 @@
+/**
+ * Created by zhangmiao on 2018/3/12.
+ */
+
+module.exports = Field;
+
+// extends ReflectionObject
+var ReflectionObject = require("./object");
+((Field.prototype = Object.create(ReflectionObject.prototype)).constructor = Field).className = "Field";
+
+var Enum,
+ types,
+ util;
+
+var Type; // cyclic
+
+var ruleRe = /^required|optional|repeated$/;
+
+/**
+ * Constructs a new message field instance. Note that {@link MapField|map fields} have their own class.
+ * @name Field
+ * @classdesc Reflected message field.
+ * @extends FieldBase
+ * @constructor
+ * @param {string} name Unique name within its namespace
+ * @param {number} id Unique id within its namespace
+ * @param {string} type Value type
+ * @param {string|Object.} [rule="optional"] Field rule
+ * @param {string|Object.} [extend] Extended type if different from parent
+ * @param {Object.} [options] Declared options
+ */
+
+/**
+ * Constructs a field from a field descriptor.
+ * @param {string} name Field name
+ * @param {IField} json Field descriptor
+ * @returns {Field} Created field
+ * @throws {TypeError} If arguments are invalid
+ */
+Field.fromJSON = function fromJSON(name, json) {
+ return new Field(name, json.id, json.type, json.rule, json.extend, json.options, json.comment);
+};
+
+/**
+ * Not an actual constructor. Use {@link Field} instead.
+ * @classdesc Base class of all reflected message fields. This is not an actual class but here for the sake of having consistent type definitions.
+ * @exports FieldBase
+ * @extends ReflectionObject
+ * @constructor
+ * @param {string} name Unique name within its namespace
+ * @param {number} id Unique id within its namespace
+ * @param {string} type Value type
+ * @param {string|Object.} [rule="optional"] Field rule
+ * @param {string|Object.} [extend] Extended type if different from parent
+ * @param {Object.} [options] Declared options
+ * @param {string} [comment] Comment associated with this field
+ */
+function Field(name, id, type, rule, extend, options, comment) {
+
+ if (util.isObject(rule)) {
+ comment = extend;
+ options = rule;
+ rule = extend = undefined;
+ } else if (util.isObject(extend)) {
+ comment = options;
+ options = extend;
+ extend = undefined;
+ }
+
+ ReflectionObject.call(this, name, options);
+
+ if (!util.isInteger(id) || id < 0)
+ throw TypeError("id must be a non-negative integer");
+
+ if (!util.isString(type))
+ throw TypeError("type must be a string");
+
+ if (rule !== undefined && !ruleRe.test(rule = rule.toString().toLowerCase()))
+ throw TypeError("rule must be a string rule");
+
+ if (extend !== undefined && !util.isString(extend))
+ throw TypeError("extend must be a string");
+
+ /**
+ * Field rule, if any.
+ * @type {string|undefined}
+ */
+ this.rule = rule && rule !== "optional" ? rule : undefined; // toJSON
+
+ /**
+ * Field type.
+ * @type {string}
+ */
+ this.type = type; // toJSON
+
+ /**
+ * Unique field id.
+ * @type {number}
+ */
+ this.id = id; // toJSON, marker
+
+ /**
+ * Extended type if different from parent.
+ * @type {string|undefined}
+ */
+ this.extend = extend || undefined; // toJSON
+
+ /**
+ * Whether this field is required.
+ * @type {boolean}
+ */
+ this.required = rule === "required";
+
+ /**
+ * Whether this field is optional.
+ * @type {boolean}
+ */
+ this.optional = !this.required;
+
+ /**
+ * Whether this field is repeated.
+ * @type {boolean}
+ */
+ this.repeated = rule === "repeated";
+
+ /**
+ * Whether this field is a map or not.
+ * @type {boolean}
+ */
+ this.map = false;
+
+ /**
+ * Message this field belongs to.
+ * @type {Type|null}
+ */
+ this.message = null;
+
+ /**
+ * OneOf this field belongs to, if any,
+ * @type {OneOf|null}
+ */
+ this.partOf = null;
+
+ /**
+ * The field type's default value.
+ * @type {*}
+ */
+ this.typeDefault = null;
+
+ /**
+ * The field's default value on prototypes.
+ * @type {*}
+ */
+ this.defaultValue = null;
+
+ /**
+ * Whether this field's value should be treated as a long.
+ * @type {boolean}
+ */
+ this.long = util.Long ? types.long[type] !== undefined : /* istanbul ignore next */ false;
+
+ /**
+ * Whether this field's value is a buffer.
+ * @type {boolean}
+ */
+ this.bytes = type === "bytes";
+
+ /**
+ * Resolved type if not a basic type.
+ * @type {Type|Enum|null}
+ */
+ this.resolvedType = null;
+
+ /**
+ * Sister-field within the extended type if a declaring extension field.
+ * @type {Field|null}
+ */
+ this.extensionField = null;
+
+ /**
+ * Sister-field within the declaring namespace if an extended field.
+ * @type {Field|null}
+ */
+ this.declaringField = null;
+
+ /**
+ * Internally remembers whether this field is packed.
+ * @type {boolean|null}
+ * @private
+ */
+ this._packed = null;
+
+ /**
+ * Comment for this field.
+ * @type {string|null}
+ */
+ this.comment = comment;
+}
+
+/**
+ * Determines whether this field is packed. Only relevant when repeated and working with proto2.
+ * @name Field#packed
+ * @type {boolean}
+ * @readonly
+ */
+Object.defineProperty(Field.prototype, "packed", {
+ get: function() {
+ // defaults to packed=true if not explicity set to false
+ if (this._packed === null)
+ this._packed = this.getOption("packed") !== false;
+ return this._packed;
+ }
+});
+
+/**
+ * @override
+ */
+Field.prototype.setOption = function setOption(name, value, ifNotSet) {
+ if (name === "packed") // clear cached before setting
+ this._packed = null;
+ return ReflectionObject.prototype.setOption.call(this, name, value, ifNotSet);
+};
+
+/**
+ * Field descriptor.
+ * @interface IField
+ * @property {string} [rule="optional"] Field rule
+ * @property {string} type Field type
+ * @property {number} id Field id
+ * @property {Object.} [options] Field options
+ */
+
+/**
+ * Extension field descriptor.
+ * @interface IExtensionField
+ * @extends IField
+ * @property {string} extend Extended type
+ */
+
+/**
+ * Converts this field to a field descriptor.
+ * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
+ * @returns {IField} Field descriptor
+ */
+Field.prototype.toJSON = function toJSON(toJSONOptions) {
+ var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
+ return util.toObject([
+ "rule" , this.rule !== "optional" && this.rule || undefined,
+ "type" , this.type,
+ "id" , this.id,
+ "extend" , this.extend,
+ "options" , this.options,
+ "comment" , keepComments ? this.comment : undefined
+ ]);
+};
+
+/**
+ * Resolves this field's type references.
+ * @returns {Field} `this`
+ * @throws {Error} If any reference cannot be resolved
+ */
+Field.prototype.resolve = function resolve() {
+
+ if (this.resolved)
+ return this;
+
+ if ((this.typeDefault = types.defaults[this.type]) === undefined) { // if not a basic type, resolve it
+ this.resolvedType = (this.declaringField ? this.declaringField.parent : this.parent).lookupTypeOrEnum(this.type);
+ if (this.resolvedType instanceof Type)
+ this.typeDefault = null;
+ else // instanceof Enum
+ this.typeDefault = this.resolvedType.values[Object.keys(this.resolvedType.values)[0]]; // first defined
+ }
+
+ // use explicitly set default value if present
+ if (this.options && this.options["default"] != null) {
+ this.typeDefault = this.options["default"];
+ if (this.resolvedType instanceof Enum && typeof this.typeDefault === "string")
+ this.typeDefault = this.resolvedType.values[this.typeDefault];
+ }
+
+ // remove unnecessary options
+ if (this.options) {
+ if (this.options.packed === true || this.options.packed !== undefined && this.resolvedType && !(this.resolvedType instanceof Enum))
+ delete this.options.packed;
+ if (!Object.keys(this.options).length)
+ this.options = undefined;
+ }
+
+ // convert to internal data type if necesssary
+ if (this.long) {
+ this.typeDefault = util.Long.fromNumber(this.typeDefault, this.type.charAt(0) === "u");
+
+ /* istanbul ignore else */
+ if (Object.freeze)
+ Object.freeze(this.typeDefault); // long instances are meant to be immutable anyway (i.e. use small int cache that even requires it)
+
+ } else if (this.bytes && typeof this.typeDefault === "string") {
+ var buf;
+ //if (util.base64.test(this.typeDefault))
+ // util.base64.decode(this.typeDefault, buf = util.newBuffer(util.base64.length(this.typeDefault)), 0);
+ //else
+ util.utf8.write(this.typeDefault, buf = util.newBuffer(util.utf8.length(this.typeDefault)), 0);
+ this.typeDefault = buf;
+ }
+
+ // take special care of maps and repeated fields
+ if (this.map)
+ this.defaultValue = util.emptyObject;
+ else if (this.repeated)
+ this.defaultValue = util.emptyArray;
+ else
+ this.defaultValue = this.typeDefault;
+
+ // ensure proper value on prototype
+ if (this.parent instanceof Type) {
+ this.parent.ctor.prototype[this.name] = this.defaultValue;
+ }
+ return ReflectionObject.prototype.resolve.call(this);
+};
+
+/**
+ * Decorator function as returned by {@link Field.d} and {@link MapField.d} (TypeScript).
+ * @typedef FieldDecorator
+ * @type {function}
+ * @param {Object} prototype Target prototype
+ * @param {string} fieldName Field name
+ * @returns {undefined}
+ */
+
+/**
+ * Field decorator (TypeScript).
+ * @name Field.d
+ * @function
+ * @param {number} fieldId Field id
+ * @param {"double"|"float"|"int32"|"uint32"|"sint32"|"fixed32"|"sfixed32"|"int64"|"uint64"|"sint64"|"fixed64"|"sfixed64"|"string"|"bool"|"bytes"|Object} fieldType Field type
+ * @param {"optional"|"required"|"repeated"} [fieldRule="optional"] Field rule
+ * @param {T} [defaultValue] Default value
+ * @returns {FieldDecorator} Decorator function
+ * @template T extends number | number[] | Long | Long[] | string | string[] | boolean | boolean[] | Uint8Array | Uint8Array[] | Buffer | Buffer[]
+ */
+Field.d = function decorateField(fieldId, fieldType, fieldRule, defaultValue) {
+
+ // submessage: decorate the submessage and use its name as the type
+ if (typeof fieldType === "function")
+ fieldType = util.decorateType(fieldType).name;
+
+ // enum reference: create a reflected copy of the enum and keep reuseing it
+ else if (fieldType && typeof fieldType === "object")
+ fieldType = util.decorateEnum(fieldType).name;
+
+ return function fieldDecorator(prototype, fieldName) {
+ util.decorateType(prototype.constructor)
+ .add(new Field(fieldName, fieldId, fieldType, fieldRule, { "default": defaultValue }));
+ };
+};
+
+/**
+ * Field decorator (TypeScript).
+ * @name Field.d
+ * @function
+ * @param {number} fieldId Field id
+ * @param {Constructor|string} fieldType Field type
+ * @param {"optional"|"required"|"repeated"} [fieldRule="optional"] Field rule
+ * @returns {FieldDecorator} Decorator function
+ * @template T extends Message
+ * @variation 2
+ */
+// like Field.d but without a default value
+
+Field._configure = function configure() {
+ Type = require('./type');
+
+ Enum = require("./enum");
+ types = require("./types");
+ util = require("./util");
+};
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/float.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/float.js
new file mode 100644
index 0000000..3eabfe0
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/float.js
@@ -0,0 +1,333 @@
+module.exports = factory(factory);
+
+/**
+ * Reads / writes floats / doubles from / to buffers.
+ * @name util.float
+ * @namespace
+ */
+
+/**
+ * Writes a 32 bit float to a buffer using little endian byte order.
+ * @name util.float.writeFloatLE
+ * @function
+ * @param {number} val Value to write
+ * @param {Uint8Array} buf Target buffer
+ * @param {number} pos Target buffer offset
+ * @returns {undefined}
+ */
+
+/**
+ * Writes a 32 bit float to a buffer using big endian byte order.
+ * @name util.float.writeFloatBE
+ * @function
+ * @param {number} val Value to write
+ * @param {Uint8Array} buf Target buffer
+ * @param {number} pos Target buffer offset
+ * @returns {undefined}
+ */
+
+/**
+ * Reads a 32 bit float from a buffer using little endian byte order.
+ * @name util.float.readFloatLE
+ * @function
+ * @param {Uint8Array} buf Source buffer
+ * @param {number} pos Source buffer offset
+ * @returns {number} Value read
+ */
+
+/**
+ * Reads a 32 bit float from a buffer using big endian byte order.
+ * @name util.float.readFloatBE
+ * @function
+ * @param {Uint8Array} buf Source buffer
+ * @param {number} pos Source buffer offset
+ * @returns {number} Value read
+ */
+
+/**
+ * Writes a 64 bit double to a buffer using little endian byte order.
+ * @name util.float.writeDoubleLE
+ * @function
+ * @param {number} val Value to write
+ * @param {Uint8Array} buf Target buffer
+ * @param {number} pos Target buffer offset
+ * @returns {undefined}
+ */
+
+/**
+ * Writes a 64 bit double to a buffer using big endian byte order.
+ * @name util.float.writeDoubleBE
+ * @function
+ * @param {number} val Value to write
+ * @param {Uint8Array} buf Target buffer
+ * @param {number} pos Target buffer offset
+ * @returns {undefined}
+ */
+
+/**
+ * Reads a 64 bit double from a buffer using little endian byte order.
+ * @name util.float.readDoubleLE
+ * @function
+ * @param {Uint8Array} buf Source buffer
+ * @param {number} pos Source buffer offset
+ * @returns {number} Value read
+ */
+
+/**
+ * Reads a 64 bit double from a buffer using big endian byte order.
+ * @name util.float.readDoubleBE
+ * @function
+ * @param {Uint8Array} buf Source buffer
+ * @param {number} pos Source buffer offset
+ * @returns {number} Value read
+ */
+
+// Factory function for the purpose of node-based testing in modified global environments
+function factory(exports) {
+
+ // float: typed array
+ if (typeof Float32Array !== "undefined") (function() {
+
+ var f32 = new Float32Array([ -0 ]),
+ f8b = new Uint8Array(f32.buffer),
+ le = f8b[3] === 128;
+
+ function writeFloat_f32_cpy(val, buf, pos) {
+ f32[0] = val;
+ buf[pos ] = f8b[0];
+ buf[pos + 1] = f8b[1];
+ buf[pos + 2] = f8b[2];
+ buf[pos + 3] = f8b[3];
+ }
+
+ function writeFloat_f32_rev(val, buf, pos) {
+ f32[0] = val;
+ buf[pos ] = f8b[3];
+ buf[pos + 1] = f8b[2];
+ buf[pos + 2] = f8b[1];
+ buf[pos + 3] = f8b[0];
+ }
+
+ /* istanbul ignore next */
+ exports.writeFloatLE = le ? writeFloat_f32_cpy : writeFloat_f32_rev;
+ /* istanbul ignore next */
+ exports.writeFloatBE = le ? writeFloat_f32_rev : writeFloat_f32_cpy;
+
+ function readFloat_f32_cpy(buf, pos) {
+ f8b[0] = buf[pos ];
+ f8b[1] = buf[pos + 1];
+ f8b[2] = buf[pos + 2];
+ f8b[3] = buf[pos + 3];
+ return f32[0];
+ }
+
+ function readFloat_f32_rev(buf, pos) {
+ f8b[3] = buf[pos ];
+ f8b[2] = buf[pos + 1];
+ f8b[1] = buf[pos + 2];
+ f8b[0] = buf[pos + 3];
+ return f32[0];
+ }
+
+ /* istanbul ignore next */
+ exports.readFloatLE = le ? readFloat_f32_cpy : readFloat_f32_rev;
+ /* istanbul ignore next */
+ exports.readFloatBE = le ? readFloat_f32_rev : readFloat_f32_cpy;
+
+ // float: ieee754
+ })(); else (function() {
+
+ function writeFloat_ieee754(writeUint, val, buf, pos) {
+ var sign = val < 0 ? 1 : 0;
+ if (sign)
+ val = -val;
+ if (val === 0)
+ writeUint(1 / val > 0 ? /* positive */ 0 : /* negative 0 */ 2147483648, buf, pos);
+ else if (isNaN(val))
+ writeUint(2143289344, buf, pos);
+ else if (val > 3.4028234663852886e+38) // +-Infinity
+ writeUint((sign << 31 | 2139095040) >>> 0, buf, pos);
+ else if (val < 1.1754943508222875e-38) // denormal
+ writeUint((sign << 31 | Math.round(val / 1.401298464324817e-45)) >>> 0, buf, pos);
+ else {
+ var exponent = Math.floor(Math.log(val) / Math.LN2),
+ mantissa = Math.round(val * Math.pow(2, -exponent) * 8388608) & 8388607;
+ writeUint((sign << 31 | exponent + 127 << 23 | mantissa) >>> 0, buf, pos);
+ }
+ }
+
+ exports.writeFloatLE = writeFloat_ieee754.bind(null, writeUintLE);
+ exports.writeFloatBE = writeFloat_ieee754.bind(null, writeUintBE);
+
+ function readFloat_ieee754(readUint, buf, pos) {
+ var uint = readUint(buf, pos),
+ sign = (uint >> 31) * 2 + 1,
+ exponent = uint >>> 23 & 255,
+ mantissa = uint & 8388607;
+ return exponent === 255
+ ? mantissa
+ ? NaN
+ : sign * Infinity
+ : exponent === 0 // denormal
+ ? sign * 1.401298464324817e-45 * mantissa
+ : sign * Math.pow(2, exponent - 150) * (mantissa + 8388608);
+ }
+
+ exports.readFloatLE = readFloat_ieee754.bind(null, readUintLE);
+ exports.readFloatBE = readFloat_ieee754.bind(null, readUintBE);
+
+ })();
+
+ // double: typed array
+ if (typeof Float64Array !== "undefined") (function() {
+
+ var f64 = new Float64Array([-0]),
+ f8b = new Uint8Array(f64.buffer),
+ le = f8b[7] === 128;
+
+ function writeDouble_f64_cpy(val, buf, pos) {
+ f64[0] = val;
+ buf[pos ] = f8b[0];
+ buf[pos + 1] = f8b[1];
+ buf[pos + 2] = f8b[2];
+ buf[pos + 3] = f8b[3];
+ buf[pos + 4] = f8b[4];
+ buf[pos + 5] = f8b[5];
+ buf[pos + 6] = f8b[6];
+ buf[pos + 7] = f8b[7];
+ }
+
+ function writeDouble_f64_rev(val, buf, pos) {
+ f64[0] = val;
+ buf[pos ] = f8b[7];
+ buf[pos + 1] = f8b[6];
+ buf[pos + 2] = f8b[5];
+ buf[pos + 3] = f8b[4];
+ buf[pos + 4] = f8b[3];
+ buf[pos + 5] = f8b[2];
+ buf[pos + 6] = f8b[1];
+ buf[pos + 7] = f8b[0];
+ }
+
+ /* istanbul ignore next */
+ exports.writeDoubleLE = le ? writeDouble_f64_cpy : writeDouble_f64_rev;
+ /* istanbul ignore next */
+ exports.writeDoubleBE = le ? writeDouble_f64_rev : writeDouble_f64_cpy;
+
+ function readDouble_f64_cpy(buf, pos) {
+ f8b[0] = buf[pos ];
+ f8b[1] = buf[pos + 1];
+ f8b[2] = buf[pos + 2];
+ f8b[3] = buf[pos + 3];
+ f8b[4] = buf[pos + 4];
+ f8b[5] = buf[pos + 5];
+ f8b[6] = buf[pos + 6];
+ f8b[7] = buf[pos + 7];
+ return f64[0];
+ }
+
+ function readDouble_f64_rev(buf, pos) {
+ f8b[7] = buf[pos ];
+ f8b[6] = buf[pos + 1];
+ f8b[5] = buf[pos + 2];
+ f8b[4] = buf[pos + 3];
+ f8b[3] = buf[pos + 4];
+ f8b[2] = buf[pos + 5];
+ f8b[1] = buf[pos + 6];
+ f8b[0] = buf[pos + 7];
+ return f64[0];
+ }
+
+ /* istanbul ignore next */
+ exports.readDoubleLE = le ? readDouble_f64_cpy : readDouble_f64_rev;
+ /* istanbul ignore next */
+ exports.readDoubleBE = le ? readDouble_f64_rev : readDouble_f64_cpy;
+
+ // double: ieee754
+ })(); else (function() {
+
+ function writeDouble_ieee754(writeUint, off0, off1, val, buf, pos) {
+ var sign = val < 0 ? 1 : 0;
+ if (sign)
+ val = -val;
+ if (val === 0) {
+ writeUint(0, buf, pos + off0);
+ writeUint(1 / val > 0 ? /* positive */ 0 : /* negative 0 */ 2147483648, buf, pos + off1);
+ } else if (isNaN(val)) {
+ writeUint(0, buf, pos + off0);
+ writeUint(2146959360, buf, pos + off1);
+ } else if (val > 1.7976931348623157e+308) { // +-Infinity
+ writeUint(0, buf, pos + off0);
+ writeUint((sign << 31 | 2146435072) >>> 0, buf, pos + off1);
+ } else {
+ var mantissa;
+ if (val < 2.2250738585072014e-308) { // denormal
+ mantissa = val / 5e-324;
+ writeUint(mantissa >>> 0, buf, pos + off0);
+ writeUint((sign << 31 | mantissa / 4294967296) >>> 0, buf, pos + off1);
+ } else {
+ var exponent = Math.floor(Math.log(val) / Math.LN2);
+ if (exponent === 1024)
+ exponent = 1023;
+ mantissa = val * Math.pow(2, -exponent);
+ writeUint(mantissa * 4503599627370496 >>> 0, buf, pos + off0);
+ writeUint((sign << 31 | exponent + 1023 << 20 | mantissa * 1048576 & 1048575) >>> 0, buf, pos + off1);
+ }
+ }
+ }
+
+ exports.writeDoubleLE = writeDouble_ieee754.bind(null, writeUintLE, 0, 4);
+ exports.writeDoubleBE = writeDouble_ieee754.bind(null, writeUintBE, 4, 0);
+
+ function readDouble_ieee754(readUint, off0, off1, buf, pos) {
+ var lo = readUint(buf, pos + off0),
+ hi = readUint(buf, pos + off1);
+ var sign = (hi >> 31) * 2 + 1,
+ exponent = hi >>> 20 & 2047,
+ mantissa = 4294967296 * (hi & 1048575) + lo;
+ return exponent === 2047
+ ? mantissa
+ ? NaN
+ : sign * Infinity
+ : exponent === 0 // denormal
+ ? sign * 5e-324 * mantissa
+ : sign * Math.pow(2, exponent - 1075) * (mantissa + 4503599627370496);
+ }
+
+ exports.readDoubleLE = readDouble_ieee754.bind(null, readUintLE, 0, 4);
+ exports.readDoubleBE = readDouble_ieee754.bind(null, readUintBE, 4, 0);
+
+ })();
+
+ return exports;
+}
+
+// uint helpers
+
+function writeUintLE(val, buf, pos) {
+ buf[pos ] = val & 255;
+ buf[pos + 1] = val >>> 8 & 255;
+ buf[pos + 2] = val >>> 16 & 255;
+ buf[pos + 3] = val >>> 24;
+}
+
+function writeUintBE(val, buf, pos) {
+ buf[pos ] = val >>> 24;
+ buf[pos + 1] = val >>> 16 & 255;
+ buf[pos + 2] = val >>> 8 & 255;
+ buf[pos + 3] = val & 255;
+}
+
+function readUintLE(buf, pos) {
+ return (buf[pos ]
+ | buf[pos + 1] << 8
+ | buf[pos + 2] << 16
+ | buf[pos + 3] << 24) >>> 0;
+}
+
+function readUintBE(buf, pos) {
+ return (buf[pos ] << 24
+ | buf[pos + 1] << 16
+ | buf[pos + 2] << 8
+ | buf[pos + 3]) >>> 0;
+}
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/index-light.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/index-light.js
new file mode 100644
index 0000000..1ef2b84
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/index-light.js
@@ -0,0 +1,103 @@
+"use strict";
+var protobuf = module.exports = require("./index-minimal");
+
+protobuf.build = "light";
+
+/**
+ * A node-style callback as used by {@link load} and {@link Root#load}.
+ * @typedef LoadCallback
+ * @type {function}
+ * @param {Error|null} error Error, if any, otherwise `null`
+ * @param {Root} [root] Root, if there hasn't been an error
+ * @returns {undefined}
+ */
+
+/**
+ * Loads one or multiple .proto or preprocessed .json files into a common root namespace and calls the callback.
+ * @param {string|string[]} filename One or multiple files to load
+ * @param {Root} root Root namespace, defaults to create a new one if omitted.
+ * @param {LoadCallback} callback Callback function
+ * @returns {undefined}
+ * @see {@link Root#load}
+ */
+function load(filename, root, callback) {
+ if (typeof root === "function") {
+ callback = root;
+ root = new protobuf.Root();
+ } else if (!root)
+ root = new protobuf.Root();
+ return root.load(filename, callback);
+}
+
+/**
+ * Loads one or multiple .proto or preprocessed .json files into a common root namespace and calls the callback.
+ * @name load
+ * @function
+ * @param {string|string[]} filename One or multiple files to load
+ * @param {LoadCallback} callback Callback function
+ * @returns {undefined}
+ * @see {@link Root#load}
+ * @variation 2
+ */
+// function load(filename:string, callback:LoadCallback):undefined
+
+/**
+ * Loads one or multiple .proto or preprocessed .json files into a common root namespace and returns a promise.
+ * @name load
+ * @function
+ * @param {string|string[]} filename One or multiple files to load
+ * @param {Root} [root] Root namespace, defaults to create a new one if omitted.
+ * @returns {Promise} Promise
+ * @see {@link Root#load}
+ * @variation 3
+ */
+// function load(filename:string, [root:Root]):Promise
+
+protobuf.load = load;
+
+/**
+ * Synchronously loads one or multiple .proto or preprocessed .json files into a common root namespace (node only).
+ * @param {string|string[]} filename One or multiple files to load
+ * @param {Root} [root] Root namespace, defaults to create a new one if omitted.
+ * @returns {Root} Root namespace
+ * @throws {Error} If synchronous fetching is not supported (i.e. in browsers) or if a file's syntax is invalid
+ * @see {@link Root#loadSync}
+ */
+function loadSync(filename, root) {
+ if (!root)
+ root = new protobuf.Root();
+ return root.loadSync(filename);
+}
+
+protobuf.loadSync = loadSync;
+
+// Serialization
+protobuf.decoder = require("./decoder");
+protobuf.verifier = require("./verifier");
+protobuf.converter = require("./converter");
+
+// Reflection
+protobuf.ReflectionObject = require("./object");
+protobuf.Namespace = require("./namespace");
+protobuf.Root = require("./root");
+protobuf.Enum = require("./enum");
+protobuf.Type = require("./type");
+protobuf.Field = require("./field");
+protobuf.OneOf = require("./oneof");
+protobuf.MapField = require("./mapField");
+protobuf.Service = require("./service");
+protobuf.Method = require("./method");
+
+// Runtime
+protobuf.Message = require("./message");
+protobuf.wrappers = require("./wrappers");
+
+// Utility
+protobuf.types = require("./types");
+protobuf.util = require("./util");
+
+// Set up possibly cyclic reflection dependencies
+protobuf.ReflectionObject._configure(protobuf.Root);
+protobuf.Namespace._configure(protobuf.Type, protobuf.Service, protobuf.Enum);
+protobuf.Root._configure(protobuf.Type);
+protobuf.Field._configure(protobuf.Type);
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/index-minimal.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/index-minimal.js
new file mode 100644
index 0000000..9bc051b
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/index-minimal.js
@@ -0,0 +1,36 @@
+"use strict";
+var protobuf = exports;
+
+/**
+ * Build type, one of `"full"`, `"light"` or `"minimal"`.
+ * @name build
+ * @type {string}
+ * @const
+ */
+protobuf.build = "minimal";
+
+// Serialization
+protobuf.Writer = require("./writer");
+protobuf.BufferWriter = require("./writer_buffer");
+protobuf.Reader = require("./reader");
+protobuf.BufferReader = require("./reader_buffer");
+
+// Utility
+protobuf.util = require("./util/minimal");
+protobuf.rpc = require("./rpc");
+protobuf.roots = require("./roots");
+protobuf.configure = configure;
+
+/* istanbul ignore next */
+/**
+ * Reconfigures the library according to the environment.
+ * @returns {undefined}
+ */
+function configure() {
+ protobuf.Reader._configure(protobuf.BufferReader);
+ protobuf.util._configure();
+}
+
+// Set up buffer utility according to the environment
+protobuf.Writer._configure(protobuf.BufferWriter);
+configure();
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/index.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/index.js
new file mode 100644
index 0000000..56bd3d5
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/index.js
@@ -0,0 +1,12 @@
+"use strict";
+var protobuf = module.exports = require("./index-light");
+
+protobuf.build = "full";
+
+// Parser
+protobuf.tokenize = require("./tokenize");
+protobuf.parse = require("./parse");
+protobuf.common = require("./common");
+
+// Configure parser
+protobuf.Root._configure(protobuf.Type, protobuf.parse, protobuf.common);
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/inquire.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/inquire.js
new file mode 100644
index 0000000..22425ec
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/inquire.js
@@ -0,0 +1,34 @@
+/**
+ * Created by zhangmiao on 2018/3/14.
+ */
+module.exports = inquire;
+
+/**
+ * Requires a module only if available.
+ * @memberof util
+ * @param {string} moduleName Module to require
+ * @returns {?Object} Required module if available and not empty, otherwise `null`
+ */
+const app = getApp();
+app.globalData.pbModuleMap = app.globalData.pbModuleMap || {};
+function inquire(moduleName) {
+ var moduleMap = app.globalData.pbModuleMap;
+ var arr = moduleName.split('/');
+ var name = arr[arr.length -1];
+ if(typeof moduleMap[name] != 'undefined')
+ {
+ return moduleMap[name];
+ }
+
+ try {
+ var mod = require(moduleName);
+ if (mod) {
+ moduleMap[name] = mod;
+ return mod;
+ }
+ else {
+ console.log('没有加载到该模块')
+ }
+ } catch (e) {} // eslint-disable-line no-empty
+ return null;
+}
\ No newline at end of file
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/long.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/long.js
new file mode 100644
index 0000000..7a769e2
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/long.js
@@ -0,0 +1,1323 @@
+module.exports = Long;
+
+/**
+ * wasm optimizations, to do native i64 multiplication and divide
+ */
+var wasm = null;
+
+try {
+ wasm = new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([
+ 0, 97, 115, 109, 1, 0, 0, 0, 1, 13, 2, 96, 0, 1, 127, 96, 4, 127, 127, 127, 127, 1, 127, 3, 7, 6, 0, 1, 1, 1, 1, 1, 6, 6, 1, 127, 1, 65, 0, 11, 7, 50, 6, 3, 109, 117, 108, 0, 1, 5, 100, 105, 118, 95, 115, 0, 2, 5, 100, 105, 118, 95, 117, 0, 3, 5, 114, 101, 109, 95, 115, 0, 4, 5, 114, 101, 109, 95, 117, 0, 5, 8, 103, 101, 116, 95, 104, 105, 103, 104, 0, 0, 10, 191, 1, 6, 4, 0, 35, 0, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 126, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 127, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 128, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 129, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 130, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11
+ ])), {}).exports;
+} catch (e) {
+ // no wasm support :(
+}
+
+/**
+ * Constructs a 64 bit two's-complement integer, given its low and high 32 bit values as *signed* integers.
+ * See the from* functions below for more convenient ways of constructing Longs.
+ * @exports Long
+ * @class A Long class for representing a 64 bit two's-complement integer value.
+ * @param {number} low The low (signed) 32 bits of the long
+ * @param {number} high The high (signed) 32 bits of the long
+ * @param {boolean=} unsigned Whether unsigned or not, defaults to signed
+ * @constructor
+ */
+function Long(low, high, unsigned) {
+
+ /**
+ * The low 32 bits as a signed value.
+ * @type {number}
+ */
+ this.low = low | 0;
+
+ /**
+ * The high 32 bits as a signed value.
+ * @type {number}
+ */
+ this.high = high | 0;
+
+ /**
+ * Whether unsigned or not.
+ * @type {boolean}
+ */
+ this.unsigned = !!unsigned;
+}
+
+// The internal representation of a long is the two given signed, 32-bit values.
+// We use 32-bit pieces because these are the size of integers on which
+// Javascript performs bit-operations. For operations like addition and
+// multiplication, we split each number into 16 bit pieces, which can easily be
+// multiplied within Javascript's floating-point representation without overflow
+// or change in sign.
+//
+// In the algorithms below, we frequently reduce the negative case to the
+// positive case by negating the input(s) and then post-processing the result.
+// Note that we must ALWAYS check specially whether those values are MIN_VALUE
+// (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as
+// a positive number, it overflows back into a negative). Not handling this
+// case would often result in infinite recursion.
+//
+// Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the from*
+// methods on which they depend.
+
+/**
+ * An indicator used to reliably determine if an object is a Long or not.
+ * @type {boolean}
+ * @const
+ * @private
+ */
+Long.prototype.__isLong__;
+
+Object.defineProperty(Long.prototype, "__isLong__", { value: true });
+
+/**
+ * @function
+ * @param {*} obj Object
+ * @returns {boolean}
+ * @inner
+ */
+function isLong(obj) {
+ return (obj && obj["__isLong__"]) === true;
+}
+
+/**
+ * Tests if the specified object is a Long.
+ * @function
+ * @param {*} obj Object
+ * @returns {boolean}
+ */
+Long.isLong = isLong;
+
+/**
+ * A cache of the Long representations of small integer values.
+ * @type {!Object}
+ * @inner
+ */
+var INT_CACHE = {};
+
+/**
+ * A cache of the Long representations of small unsigned integer values.
+ * @type {!Object}
+ * @inner
+ */
+var UINT_CACHE = {};
+
+/**
+ * @param {number} value
+ * @param {boolean=} unsigned
+ * @returns {!Long}
+ * @inner
+ */
+function fromInt(value, unsigned) {
+ var obj, cachedObj, cache;
+ if (unsigned) {
+ value >>>= 0;
+ if (cache = (0 <= value && value < 256)) {
+ cachedObj = UINT_CACHE[value];
+ if (cachedObj)
+ return cachedObj;
+ }
+ obj = fromBits(value, (value | 0) < 0 ? -1 : 0, true);
+ if (cache)
+ UINT_CACHE[value] = obj;
+ return obj;
+ } else {
+ value |= 0;
+ if (cache = (-128 <= value && value < 128)) {
+ cachedObj = INT_CACHE[value];
+ if (cachedObj)
+ return cachedObj;
+ }
+ obj = fromBits(value, value < 0 ? -1 : 0, false);
+ if (cache)
+ INT_CACHE[value] = obj;
+ return obj;
+ }
+}
+
+/**
+ * Returns a Long representing the given 32 bit integer value.
+ * @function
+ * @param {number} value The 32 bit integer in question
+ * @param {boolean=} unsigned Whether unsigned or not, defaults to signed
+ * @returns {!Long} The corresponding Long value
+ */
+Long.fromInt = fromInt;
+
+/**
+ * @param {number} value
+ * @param {boolean=} unsigned
+ * @returns {!Long}
+ * @inner
+ */
+function fromNumber(value, unsigned) {
+ if (isNaN(value))
+ return unsigned ? UZERO : ZERO;
+ if (unsigned) {
+ if (value < 0)
+ return UZERO;
+ if (value >= TWO_PWR_64_DBL)
+ return MAX_UNSIGNED_VALUE;
+ } else {
+ if (value <= -TWO_PWR_63_DBL)
+ return MIN_VALUE;
+ if (value + 1 >= TWO_PWR_63_DBL)
+ return MAX_VALUE;
+ }
+ if (value < 0)
+ return fromNumber(-value, unsigned).neg();
+ return fromBits((value % TWO_PWR_32_DBL) | 0, (value / TWO_PWR_32_DBL) | 0, unsigned);
+}
+
+/**
+ * Returns a Long representing the given value, provided that it is a finite number. Otherwise, zero is returned.
+ * @function
+ * @param {number} value The number in question
+ * @param {boolean=} unsigned Whether unsigned or not, defaults to signed
+ * @returns {!Long} The corresponding Long value
+ */
+Long.fromNumber = fromNumber;
+
+/**
+ * @param {number} lowBits
+ * @param {number} highBits
+ * @param {boolean=} unsigned
+ * @returns {!Long}
+ * @inner
+ */
+function fromBits(lowBits, highBits, unsigned) {
+ return new Long(lowBits, highBits, unsigned);
+}
+
+/**
+ * Returns a Long representing the 64 bit integer that comes by concatenating the given low and high bits. Each is
+ * assumed to use 32 bits.
+ * @function
+ * @param {number} lowBits The low 32 bits
+ * @param {number} highBits The high 32 bits
+ * @param {boolean=} unsigned Whether unsigned or not, defaults to signed
+ * @returns {!Long} The corresponding Long value
+ */
+Long.fromBits = fromBits;
+
+/**
+ * @function
+ * @param {number} base
+ * @param {number} exponent
+ * @returns {number}
+ * @inner
+ */
+var pow_dbl = Math.pow; // Used 4 times (4*8 to 15+4)
+
+/**
+ * @param {string} str
+ * @param {(boolean|number)=} unsigned
+ * @param {number=} radix
+ * @returns {!Long}
+ * @inner
+ */
+function fromString(str, unsigned, radix) {
+ if (str.length === 0)
+ throw Error('empty string');
+ if (str === "NaN" || str === "Infinity" || str === "+Infinity" || str === "-Infinity")
+ return ZERO;
+ if (typeof unsigned === 'number') {
+ // For goog.math.long compatibility
+ radix = unsigned,
+ unsigned = false;
+ } else {
+ unsigned = !! unsigned;
+ }
+ radix = radix || 10;
+ if (radix < 2 || 36 < radix)
+ throw RangeError('radix');
+
+ var p;
+ if ((p = str.indexOf('-')) > 0)
+ throw Error('interior hyphen');
+ else if (p === 0) {
+ return fromString(str.substring(1), unsigned, radix).neg();
+ }
+
+ // Do several (8) digits each time through the loop, so as to
+ // minimize the calls to the very expensive emulated div.
+ var radixToPower = fromNumber(pow_dbl(radix, 8));
+
+ var result = ZERO;
+ for (var i = 0; i < str.length; i += 8) {
+ var size = Math.min(8, str.length - i),
+ value = parseInt(str.substring(i, i + size), radix);
+ if (size < 8) {
+ var power = fromNumber(pow_dbl(radix, size));
+ result = result.mul(power).add(fromNumber(value));
+ } else {
+ result = result.mul(radixToPower);
+ result = result.add(fromNumber(value));
+ }
+ }
+ result.unsigned = unsigned;
+ return result;
+}
+
+/**
+ * Returns a Long representation of the given string, written using the specified radix.
+ * @function
+ * @param {string} str The textual representation of the Long
+ * @param {(boolean|number)=} unsigned Whether unsigned or not, defaults to signed
+ * @param {number=} radix The radix in which the text is written (2-36), defaults to 10
+ * @returns {!Long} The corresponding Long value
+ */
+Long.fromString = fromString;
+
+/**
+ * @function
+ * @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val
+ * @param {boolean=} unsigned
+ * @returns {!Long}
+ * @inner
+ */
+function fromValue(val, unsigned) {
+ if (typeof val === 'number')
+ return fromNumber(val, unsigned);
+ if (typeof val === 'string')
+ return fromString(val, unsigned);
+ // Throws for non-objects, converts non-instanceof Long:
+ return fromBits(val.low, val.high, typeof unsigned === 'boolean' ? unsigned : val.unsigned);
+}
+
+/**
+ * Converts the specified value to a Long using the appropriate from* function for its type.
+ * @function
+ * @param {!Long|number|string|!{low: number, high: number, unsigned: boolean}} val Value
+ * @param {boolean=} unsigned Whether unsigned or not, defaults to signed
+ * @returns {!Long}
+ */
+Long.fromValue = fromValue;
+
+// NOTE: the compiler should inline these constant values below and then remove these variables, so there should be
+// no runtime penalty for these.
+
+/**
+ * @type {number}
+ * @const
+ * @inner
+ */
+var TWO_PWR_16_DBL = 1 << 16;
+
+/**
+ * @type {number}
+ * @const
+ * @inner
+ */
+var TWO_PWR_24_DBL = 1 << 24;
+
+/**
+ * @type {number}
+ * @const
+ * @inner
+ */
+var TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL;
+
+/**
+ * @type {number}
+ * @const
+ * @inner
+ */
+var TWO_PWR_64_DBL = TWO_PWR_32_DBL * TWO_PWR_32_DBL;
+
+/**
+ * @type {number}
+ * @const
+ * @inner
+ */
+var TWO_PWR_63_DBL = TWO_PWR_64_DBL / 2;
+
+/**
+ * @type {!Long}
+ * @const
+ * @inner
+ */
+var TWO_PWR_24 = fromInt(TWO_PWR_24_DBL);
+
+/**
+ * @type {!Long}
+ * @inner
+ */
+var ZERO = fromInt(0);
+
+/**
+ * Signed zero.
+ * @type {!Long}
+ */
+Long.ZERO = ZERO;
+
+/**
+ * @type {!Long}
+ * @inner
+ */
+var UZERO = fromInt(0, true);
+
+/**
+ * Unsigned zero.
+ * @type {!Long}
+ */
+Long.UZERO = UZERO;
+
+/**
+ * @type {!Long}
+ * @inner
+ */
+var ONE = fromInt(1);
+
+/**
+ * Signed one.
+ * @type {!Long}
+ */
+Long.ONE = ONE;
+
+/**
+ * @type {!Long}
+ * @inner
+ */
+var UONE = fromInt(1, true);
+
+/**
+ * Unsigned one.
+ * @type {!Long}
+ */
+Long.UONE = UONE;
+
+/**
+ * @type {!Long}
+ * @inner
+ */
+var NEG_ONE = fromInt(-1);
+
+/**
+ * Signed negative one.
+ * @type {!Long}
+ */
+Long.NEG_ONE = NEG_ONE;
+
+/**
+ * @type {!Long}
+ * @inner
+ */
+var MAX_VALUE = fromBits(0xFFFFFFFF|0, 0x7FFFFFFF|0, false);
+
+/**
+ * Maximum signed value.
+ * @type {!Long}
+ */
+Long.MAX_VALUE = MAX_VALUE;
+
+/**
+ * @type {!Long}
+ * @inner
+ */
+var MAX_UNSIGNED_VALUE = fromBits(0xFFFFFFFF|0, 0xFFFFFFFF|0, true);
+
+/**
+ * Maximum unsigned value.
+ * @type {!Long}
+ */
+Long.MAX_UNSIGNED_VALUE = MAX_UNSIGNED_VALUE;
+
+/**
+ * @type {!Long}
+ * @inner
+ */
+var MIN_VALUE = fromBits(0, 0x80000000|0, false);
+
+/**
+ * Minimum signed value.
+ * @type {!Long}
+ */
+Long.MIN_VALUE = MIN_VALUE;
+
+/**
+ * @alias Long.prototype
+ * @inner
+ */
+var LongPrototype = Long.prototype;
+
+/**
+ * Converts the Long to a 32 bit integer, assuming it is a 32 bit integer.
+ * @returns {number}
+ */
+LongPrototype.toInt = function toInt() {
+ return this.unsigned ? this.low >>> 0 : this.low;
+};
+
+/**
+ * Converts the Long to a the nearest floating-point representation of this value (double, 53 bit mantissa).
+ * @returns {number}
+ */
+LongPrototype.toNumber = function toNumber() {
+ if (this.unsigned)
+ return ((this.high >>> 0) * TWO_PWR_32_DBL) + (this.low >>> 0);
+ return this.high * TWO_PWR_32_DBL + (this.low >>> 0);
+};
+
+/**
+ * Converts the Long to a string written in the specified radix.
+ * @param {number=} radix Radix (2-36), defaults to 10
+ * @returns {string}
+ * @override
+ * @throws {RangeError} If `radix` is out of range
+ */
+LongPrototype.toString = function toString(radix) {
+ radix = radix || 10;
+ if (radix < 2 || 36 < radix)
+ throw RangeError('radix');
+ if (this.isZero())
+ return '0';
+ if (this.isNegative()) { // Unsigned Longs are never negative
+ if (this.eq(MIN_VALUE)) {
+ // We need to change the Long value before it can be negated, so we remove
+ // the bottom-most digit in this base and then recurse to do the rest.
+ var radixLong = fromNumber(radix),
+ div = this.div(radixLong),
+ rem1 = div.mul(radixLong).sub(this);
+ return div.toString(radix) + rem1.toInt().toString(radix);
+ } else
+ return '-' + this.neg().toString(radix);
+ }
+
+ // Do several (6) digits each time through the loop, so as to
+ // minimize the calls to the very expensive emulated div.
+ var radixToPower = fromNumber(pow_dbl(radix, 6), this.unsigned),
+ rem = this;
+ var result = '';
+ while (true) {
+ var remDiv = rem.div(radixToPower),
+ intval = rem.sub(remDiv.mul(radixToPower)).toInt() >>> 0,
+ digits = intval.toString(radix);
+ rem = remDiv;
+ if (rem.isZero())
+ return digits + result;
+ else {
+ while (digits.length < 6)
+ digits = '0' + digits;
+ result = '' + digits + result;
+ }
+ }
+};
+
+/**
+ * Gets the high 32 bits as a signed integer.
+ * @returns {number} Signed high bits
+ */
+LongPrototype.getHighBits = function getHighBits() {
+ return this.high;
+};
+
+/**
+ * Gets the high 32 bits as an unsigned integer.
+ * @returns {number} Unsigned high bits
+ */
+LongPrototype.getHighBitsUnsigned = function getHighBitsUnsigned() {
+ return this.high >>> 0;
+};
+
+/**
+ * Gets the low 32 bits as a signed integer.
+ * @returns {number} Signed low bits
+ */
+LongPrototype.getLowBits = function getLowBits() {
+ return this.low;
+};
+
+/**
+ * Gets the low 32 bits as an unsigned integer.
+ * @returns {number} Unsigned low bits
+ */
+LongPrototype.getLowBitsUnsigned = function getLowBitsUnsigned() {
+ return this.low >>> 0;
+};
+
+/**
+ * Gets the number of bits needed to represent the absolute value of this Long.
+ * @returns {number}
+ */
+LongPrototype.getNumBitsAbs = function getNumBitsAbs() {
+ if (this.isNegative()) // Unsigned Longs are never negative
+ return this.eq(MIN_VALUE) ? 64 : this.neg().getNumBitsAbs();
+ var val = this.high != 0 ? this.high : this.low;
+ for (var bit = 31; bit > 0; bit--)
+ if ((val & (1 << bit)) != 0)
+ break;
+ return this.high != 0 ? bit + 33 : bit + 1;
+};
+
+/**
+ * Tests if this Long's value equals zero.
+ * @returns {boolean}
+ */
+LongPrototype.isZero = function isZero() {
+ return this.high === 0 && this.low === 0;
+};
+
+/**
+ * Tests if this Long's value equals zero. This is an alias of {@link Long#isZero}.
+ * @returns {boolean}
+ */
+LongPrototype.eqz = LongPrototype.isZero;
+
+/**
+ * Tests if this Long's value is negative.
+ * @returns {boolean}
+ */
+LongPrototype.isNegative = function isNegative() {
+ return !this.unsigned && this.high < 0;
+};
+
+/**
+ * Tests if this Long's value is positive.
+ * @returns {boolean}
+ */
+LongPrototype.isPositive = function isPositive() {
+ return this.unsigned || this.high >= 0;
+};
+
+/**
+ * Tests if this Long's value is odd.
+ * @returns {boolean}
+ */
+LongPrototype.isOdd = function isOdd() {
+ return (this.low & 1) === 1;
+};
+
+/**
+ * Tests if this Long's value is even.
+ * @returns {boolean}
+ */
+LongPrototype.isEven = function isEven() {
+ return (this.low & 1) === 0;
+};
+
+/**
+ * Tests if this Long's value equals the specified's.
+ * @param {!Long|number|string} other Other value
+ * @returns {boolean}
+ */
+LongPrototype.equals = function equals(other) {
+ if (!isLong(other))
+ other = fromValue(other);
+ if (this.unsigned !== other.unsigned && (this.high >>> 31) === 1 && (other.high >>> 31) === 1)
+ return false;
+ return this.high === other.high && this.low === other.low;
+};
+
+/**
+ * Tests if this Long's value equals the specified's. This is an alias of {@link Long#equals}.
+ * @function
+ * @param {!Long|number|string} other Other value
+ * @returns {boolean}
+ */
+LongPrototype.eq = LongPrototype.equals;
+
+/**
+ * Tests if this Long's value differs from the specified's.
+ * @param {!Long|number|string} other Other value
+ * @returns {boolean}
+ */
+LongPrototype.notEquals = function notEquals(other) {
+ return !this.eq(/* validates */ other);
+};
+
+/**
+ * Tests if this Long's value differs from the specified's. This is an alias of {@link Long#notEquals}.
+ * @function
+ * @param {!Long|number|string} other Other value
+ * @returns {boolean}
+ */
+LongPrototype.neq = LongPrototype.notEquals;
+
+/**
+ * Tests if this Long's value differs from the specified's. This is an alias of {@link Long#notEquals}.
+ * @function
+ * @param {!Long|number|string} other Other value
+ * @returns {boolean}
+ */
+LongPrototype.ne = LongPrototype.notEquals;
+
+/**
+ * Tests if this Long's value is less than the specified's.
+ * @param {!Long|number|string} other Other value
+ * @returns {boolean}
+ */
+LongPrototype.lessThan = function lessThan(other) {
+ return this.comp(/* validates */ other) < 0;
+};
+
+/**
+ * Tests if this Long's value is less than the specified's. This is an alias of {@link Long#lessThan}.
+ * @function
+ * @param {!Long|number|string} other Other value
+ * @returns {boolean}
+ */
+LongPrototype.lt = LongPrototype.lessThan;
+
+/**
+ * Tests if this Long's value is less than or equal the specified's.
+ * @param {!Long|number|string} other Other value
+ * @returns {boolean}
+ */
+LongPrototype.lessThanOrEqual = function lessThanOrEqual(other) {
+ return this.comp(/* validates */ other) <= 0;
+};
+
+/**
+ * Tests if this Long's value is less than or equal the specified's. This is an alias of {@link Long#lessThanOrEqual}.
+ * @function
+ * @param {!Long|number|string} other Other value
+ * @returns {boolean}
+ */
+LongPrototype.lte = LongPrototype.lessThanOrEqual;
+
+/**
+ * Tests if this Long's value is less than or equal the specified's. This is an alias of {@link Long#lessThanOrEqual}.
+ * @function
+ * @param {!Long|number|string} other Other value
+ * @returns {boolean}
+ */
+LongPrototype.le = LongPrototype.lessThanOrEqual;
+
+/**
+ * Tests if this Long's value is greater than the specified's.
+ * @param {!Long|number|string} other Other value
+ * @returns {boolean}
+ */
+LongPrototype.greaterThan = function greaterThan(other) {
+ return this.comp(/* validates */ other) > 0;
+};
+
+/**
+ * Tests if this Long's value is greater than the specified's. This is an alias of {@link Long#greaterThan}.
+ * @function
+ * @param {!Long|number|string} other Other value
+ * @returns {boolean}
+ */
+LongPrototype.gt = LongPrototype.greaterThan;
+
+/**
+ * Tests if this Long's value is greater than or equal the specified's.
+ * @param {!Long|number|string} other Other value
+ * @returns {boolean}
+ */
+LongPrototype.greaterThanOrEqual = function greaterThanOrEqual(other) {
+ return this.comp(/* validates */ other) >= 0;
+};
+
+/**
+ * Tests if this Long's value is greater than or equal the specified's. This is an alias of {@link Long#greaterThanOrEqual}.
+ * @function
+ * @param {!Long|number|string} other Other value
+ * @returns {boolean}
+ */
+LongPrototype.gte = LongPrototype.greaterThanOrEqual;
+
+/**
+ * Tests if this Long's value is greater than or equal the specified's. This is an alias of {@link Long#greaterThanOrEqual}.
+ * @function
+ * @param {!Long|number|string} other Other value
+ * @returns {boolean}
+ */
+LongPrototype.ge = LongPrototype.greaterThanOrEqual;
+
+/**
+ * Compares this Long's value with the specified's.
+ * @param {!Long|number|string} other Other value
+ * @returns {number} 0 if they are the same, 1 if the this is greater and -1
+ * if the given one is greater
+ */
+LongPrototype.compare = function compare(other) {
+ if (!isLong(other))
+ other = fromValue(other);
+ if (this.eq(other))
+ return 0;
+ var thisNeg = this.isNegative(),
+ otherNeg = other.isNegative();
+ if (thisNeg && !otherNeg)
+ return -1;
+ if (!thisNeg && otherNeg)
+ return 1;
+ // At this point the sign bits are the same
+ if (!this.unsigned)
+ return this.sub(other).isNegative() ? -1 : 1;
+ // Both are positive if at least one is unsigned
+ return (other.high >>> 0) > (this.high >>> 0) || (other.high === this.high && (other.low >>> 0) > (this.low >>> 0)) ? -1 : 1;
+};
+
+/**
+ * Compares this Long's value with the specified's. This is an alias of {@link Long#compare}.
+ * @function
+ * @param {!Long|number|string} other Other value
+ * @returns {number} 0 if they are the same, 1 if the this is greater and -1
+ * if the given one is greater
+ */
+LongPrototype.comp = LongPrototype.compare;
+
+/**
+ * Negates this Long's value.
+ * @returns {!Long} Negated Long
+ */
+LongPrototype.negate = function negate() {
+ if (!this.unsigned && this.eq(MIN_VALUE))
+ return MIN_VALUE;
+ return this.not().add(ONE);
+};
+
+/**
+ * Negates this Long's value. This is an alias of {@link Long#negate}.
+ * @function
+ * @returns {!Long} Negated Long
+ */
+LongPrototype.neg = LongPrototype.negate;
+
+/**
+ * Returns the sum of this and the specified Long.
+ * @param {!Long|number|string} addend Addend
+ * @returns {!Long} Sum
+ */
+LongPrototype.add = function add(addend) {
+ if (!isLong(addend))
+ addend = fromValue(addend);
+
+ // Divide each number into 4 chunks of 16 bits, and then sum the chunks.
+
+ var a48 = this.high >>> 16;
+ var a32 = this.high & 0xFFFF;
+ var a16 = this.low >>> 16;
+ var a00 = this.low & 0xFFFF;
+
+ var b48 = addend.high >>> 16;
+ var b32 = addend.high & 0xFFFF;
+ var b16 = addend.low >>> 16;
+ var b00 = addend.low & 0xFFFF;
+
+ var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
+ c00 += a00 + b00;
+ c16 += c00 >>> 16;
+ c00 &= 0xFFFF;
+ c16 += a16 + b16;
+ c32 += c16 >>> 16;
+ c16 &= 0xFFFF;
+ c32 += a32 + b32;
+ c48 += c32 >>> 16;
+ c32 &= 0xFFFF;
+ c48 += a48 + b48;
+ c48 &= 0xFFFF;
+ return fromBits((c16 << 16) | c00, (c48 << 16) | c32, this.unsigned);
+};
+
+/**
+ * Returns the difference of this and the specified Long.
+ * @param {!Long|number|string} subtrahend Subtrahend
+ * @returns {!Long} Difference
+ */
+LongPrototype.subtract = function subtract(subtrahend) {
+ if (!isLong(subtrahend))
+ subtrahend = fromValue(subtrahend);
+ return this.add(subtrahend.neg());
+};
+
+/**
+ * Returns the difference of this and the specified Long. This is an alias of {@link Long#subtract}.
+ * @function
+ * @param {!Long|number|string} subtrahend Subtrahend
+ * @returns {!Long} Difference
+ */
+LongPrototype.sub = LongPrototype.subtract;
+
+/**
+ * Returns the product of this and the specified Long.
+ * @param {!Long|number|string} multiplier Multiplier
+ * @returns {!Long} Product
+ */
+LongPrototype.multiply = function multiply(multiplier) {
+ if (this.isZero())
+ return ZERO;
+ if (!isLong(multiplier))
+ multiplier = fromValue(multiplier);
+
+ // use wasm support if present
+ if (wasm) {
+ var low = wasm.mul(this.low,
+ this.high,
+ multiplier.low,
+ multiplier.high);
+ return fromBits(low, wasm.get_high(), this.unsigned);
+ }
+
+ if (multiplier.isZero())
+ return ZERO;
+ if (this.eq(MIN_VALUE))
+ return multiplier.isOdd() ? MIN_VALUE : ZERO;
+ if (multiplier.eq(MIN_VALUE))
+ return this.isOdd() ? MIN_VALUE : ZERO;
+
+ if (this.isNegative()) {
+ if (multiplier.isNegative())
+ return this.neg().mul(multiplier.neg());
+ else
+ return this.neg().mul(multiplier).neg();
+ } else if (multiplier.isNegative())
+ return this.mul(multiplier.neg()).neg();
+
+ // If both longs are small, use float multiplication
+ if (this.lt(TWO_PWR_24) && multiplier.lt(TWO_PWR_24))
+ return fromNumber(this.toNumber() * multiplier.toNumber(), this.unsigned);
+
+ // Divide each long into 4 chunks of 16 bits, and then add up 4x4 products.
+ // We can skip products that would overflow.
+
+ var a48 = this.high >>> 16;
+ var a32 = this.high & 0xFFFF;
+ var a16 = this.low >>> 16;
+ var a00 = this.low & 0xFFFF;
+
+ var b48 = multiplier.high >>> 16;
+ var b32 = multiplier.high & 0xFFFF;
+ var b16 = multiplier.low >>> 16;
+ var b00 = multiplier.low & 0xFFFF;
+
+ var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
+ c00 += a00 * b00;
+ c16 += c00 >>> 16;
+ c00 &= 0xFFFF;
+ c16 += a16 * b00;
+ c32 += c16 >>> 16;
+ c16 &= 0xFFFF;
+ c16 += a00 * b16;
+ c32 += c16 >>> 16;
+ c16 &= 0xFFFF;
+ c32 += a32 * b00;
+ c48 += c32 >>> 16;
+ c32 &= 0xFFFF;
+ c32 += a16 * b16;
+ c48 += c32 >>> 16;
+ c32 &= 0xFFFF;
+ c32 += a00 * b32;
+ c48 += c32 >>> 16;
+ c32 &= 0xFFFF;
+ c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48;
+ c48 &= 0xFFFF;
+ return fromBits((c16 << 16) | c00, (c48 << 16) | c32, this.unsigned);
+};
+
+/**
+ * Returns the product of this and the specified Long. This is an alias of {@link Long#multiply}.
+ * @function
+ * @param {!Long|number|string} multiplier Multiplier
+ * @returns {!Long} Product
+ */
+LongPrototype.mul = LongPrototype.multiply;
+
+/**
+ * Returns this Long divided by the specified. The result is signed if this Long is signed or
+ * unsigned if this Long is unsigned.
+ * @param {!Long|number|string} divisor Divisor
+ * @returns {!Long} Quotient
+ */
+LongPrototype.divide = function divide(divisor) {
+ if (!isLong(divisor))
+ divisor = fromValue(divisor);
+ if (divisor.isZero())
+ throw Error('division by zero');
+
+ // use wasm support if present
+ if (wasm) {
+ // guard against signed division overflow: the largest
+ // negative number / -1 would be 1 larger than the largest
+ // positive number, due to two's complement.
+ if (!this.unsigned &&
+ this.high === -0x80000000 &&
+ divisor.low === -1 && divisor.high === -1) {
+ // be consistent with non-wasm code path
+ return this;
+ }
+ var low = (this.unsigned ? wasm.div_u : wasm.div_s)(
+ this.low,
+ this.high,
+ divisor.low,
+ divisor.high
+ );
+ return fromBits(low, wasm.get_high(), this.unsigned);
+ }
+
+ if (this.isZero())
+ return this.unsigned ? UZERO : ZERO;
+ var approx, rem, res;
+ if (!this.unsigned) {
+ // This section is only relevant for signed longs and is derived from the
+ // closure library as a whole.
+ if (this.eq(MIN_VALUE)) {
+ if (divisor.eq(ONE) || divisor.eq(NEG_ONE))
+ return MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE
+ else if (divisor.eq(MIN_VALUE))
+ return ONE;
+ else {
+ // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|.
+ var halfThis = this.shr(1);
+ approx = halfThis.div(divisor).shl(1);
+ if (approx.eq(ZERO)) {
+ return divisor.isNegative() ? ONE : NEG_ONE;
+ } else {
+ rem = this.sub(divisor.mul(approx));
+ res = approx.add(rem.div(divisor));
+ return res;
+ }
+ }
+ } else if (divisor.eq(MIN_VALUE))
+ return this.unsigned ? UZERO : ZERO;
+ if (this.isNegative()) {
+ if (divisor.isNegative())
+ return this.neg().div(divisor.neg());
+ return this.neg().div(divisor).neg();
+ } else if (divisor.isNegative())
+ return this.div(divisor.neg()).neg();
+ res = ZERO;
+ } else {
+ // The algorithm below has not been made for unsigned longs. It's therefore
+ // required to take special care of the MSB prior to running it.
+ if (!divisor.unsigned)
+ divisor = divisor.toUnsigned();
+ if (divisor.gt(this))
+ return UZERO;
+ if (divisor.gt(this.shru(1))) // 15 >>> 1 = 7 ; with divisor = 8 ; true
+ return UONE;
+ res = UZERO;
+ }
+
+ // Repeat the following until the remainder is less than other: find a
+ // floating-point that approximates remainder / other *from below*, add this
+ // into the result, and subtract it from the remainder. It is critical that
+ // the approximate value is less than or equal to the real value so that the
+ // remainder never becomes negative.
+ rem = this;
+ while (rem.gte(divisor)) {
+ // Approximate the result of division. This may be a little greater or
+ // smaller than the actual value.
+ approx = Math.max(1, Math.floor(rem.toNumber() / divisor.toNumber()));
+
+ // We will tweak the approximate result by changing it in the 48-th digit or
+ // the smallest non-fractional digit, whichever is larger.
+ var log2 = Math.ceil(Math.log(approx) / Math.LN2),
+ delta = (log2 <= 48) ? 1 : pow_dbl(2, log2 - 48),
+
+ // Decrease the approximation until it is smaller than the remainder. Note
+ // that if it is too large, the product overflows and is negative.
+ approxRes = fromNumber(approx),
+ approxRem = approxRes.mul(divisor);
+ while (approxRem.isNegative() || approxRem.gt(rem)) {
+ approx -= delta;
+ approxRes = fromNumber(approx, this.unsigned);
+ approxRem = approxRes.mul(divisor);
+ }
+
+ // We know the answer can't be zero... and actually, zero would cause
+ // infinite recursion since we would make no progress.
+ if (approxRes.isZero())
+ approxRes = ONE;
+
+ res = res.add(approxRes);
+ rem = rem.sub(approxRem);
+ }
+ return res;
+};
+
+/**
+ * Returns this Long divided by the specified. This is an alias of {@link Long#divide}.
+ * @function
+ * @param {!Long|number|string} divisor Divisor
+ * @returns {!Long} Quotient
+ */
+LongPrototype.div = LongPrototype.divide;
+
+/**
+ * Returns this Long modulo the specified.
+ * @param {!Long|number|string} divisor Divisor
+ * @returns {!Long} Remainder
+ */
+LongPrototype.modulo = function modulo(divisor) {
+ if (!isLong(divisor))
+ divisor = fromValue(divisor);
+
+ // use wasm support if present
+ if (wasm) {
+ var low = (this.unsigned ? wasm.rem_u : wasm.rem_s)(
+ this.low,
+ this.high,
+ divisor.low,
+ divisor.high
+ );
+ return fromBits(low, wasm.get_high(), this.unsigned);
+ }
+
+ return this.sub(this.div(divisor).mul(divisor));
+};
+
+/**
+ * Returns this Long modulo the specified. This is an alias of {@link Long#modulo}.
+ * @function
+ * @param {!Long|number|string} divisor Divisor
+ * @returns {!Long} Remainder
+ */
+LongPrototype.mod = LongPrototype.modulo;
+
+/**
+ * Returns this Long modulo the specified. This is an alias of {@link Long#modulo}.
+ * @function
+ * @param {!Long|number|string} divisor Divisor
+ * @returns {!Long} Remainder
+ */
+LongPrototype.rem = LongPrototype.modulo;
+
+/**
+ * Returns the bitwise NOT of this Long.
+ * @returns {!Long}
+ */
+LongPrototype.not = function not() {
+ return fromBits(~this.low, ~this.high, this.unsigned);
+};
+
+/**
+ * Returns the bitwise AND of this Long and the specified.
+ * @param {!Long|number|string} other Other Long
+ * @returns {!Long}
+ */
+LongPrototype.and = function and(other) {
+ if (!isLong(other))
+ other = fromValue(other);
+ return fromBits(this.low & other.low, this.high & other.high, this.unsigned);
+};
+
+/**
+ * Returns the bitwise OR of this Long and the specified.
+ * @param {!Long|number|string} other Other Long
+ * @returns {!Long}
+ */
+LongPrototype.or = function or(other) {
+ if (!isLong(other))
+ other = fromValue(other);
+ return fromBits(this.low | other.low, this.high | other.high, this.unsigned);
+};
+
+/**
+ * Returns the bitwise XOR of this Long and the given one.
+ * @param {!Long|number|string} other Other Long
+ * @returns {!Long}
+ */
+LongPrototype.xor = function xor(other) {
+ if (!isLong(other))
+ other = fromValue(other);
+ return fromBits(this.low ^ other.low, this.high ^ other.high, this.unsigned);
+};
+
+/**
+ * Returns this Long with bits shifted to the left by the given amount.
+ * @param {number|!Long} numBits Number of bits
+ * @returns {!Long} Shifted Long
+ */
+LongPrototype.shiftLeft = function shiftLeft(numBits) {
+ if (isLong(numBits))
+ numBits = numBits.toInt();
+ if ((numBits &= 63) === 0)
+ return this;
+ else if (numBits < 32)
+ return fromBits(this.low << numBits, (this.high << numBits) | (this.low >>> (32 - numBits)), this.unsigned);
+ else
+ return fromBits(0, this.low << (numBits - 32), this.unsigned);
+};
+
+/**
+ * Returns this Long with bits shifted to the left by the given amount. This is an alias of {@link Long#shiftLeft}.
+ * @function
+ * @param {number|!Long} numBits Number of bits
+ * @returns {!Long} Shifted Long
+ */
+LongPrototype.shl = LongPrototype.shiftLeft;
+
+/**
+ * Returns this Long with bits arithmetically shifted to the right by the given amount.
+ * @param {number|!Long} numBits Number of bits
+ * @returns {!Long} Shifted Long
+ */
+LongPrototype.shiftRight = function shiftRight(numBits) {
+ if (isLong(numBits))
+ numBits = numBits.toInt();
+ if ((numBits &= 63) === 0)
+ return this;
+ else if (numBits < 32)
+ return fromBits((this.low >>> numBits) | (this.high << (32 - numBits)), this.high >> numBits, this.unsigned);
+ else
+ return fromBits(this.high >> (numBits - 32), this.high >= 0 ? 0 : -1, this.unsigned);
+};
+
+/**
+ * Returns this Long with bits arithmetically shifted to the right by the given amount. This is an alias of {@link Long#shiftRight}.
+ * @function
+ * @param {number|!Long} numBits Number of bits
+ * @returns {!Long} Shifted Long
+ */
+LongPrototype.shr = LongPrototype.shiftRight;
+
+/**
+ * Returns this Long with bits logically shifted to the right by the given amount.
+ * @param {number|!Long} numBits Number of bits
+ * @returns {!Long} Shifted Long
+ */
+LongPrototype.shiftRightUnsigned = function shiftRightUnsigned(numBits) {
+ if (isLong(numBits))
+ numBits = numBits.toInt();
+ numBits &= 63;
+ if (numBits === 0)
+ return this;
+ else {
+ var high = this.high;
+ if (numBits < 32) {
+ var low = this.low;
+ return fromBits((low >>> numBits) | (high << (32 - numBits)), high >>> numBits, this.unsigned);
+ } else if (numBits === 32)
+ return fromBits(high, 0, this.unsigned);
+ else
+ return fromBits(high >>> (numBits - 32), 0, this.unsigned);
+ }
+};
+
+/**
+ * Returns this Long with bits logically shifted to the right by the given amount. This is an alias of {@link Long#shiftRightUnsigned}.
+ * @function
+ * @param {number|!Long} numBits Number of bits
+ * @returns {!Long} Shifted Long
+ */
+LongPrototype.shru = LongPrototype.shiftRightUnsigned;
+
+/**
+ * Returns this Long with bits logically shifted to the right by the given amount. This is an alias of {@link Long#shiftRightUnsigned}.
+ * @function
+ * @param {number|!Long} numBits Number of bits
+ * @returns {!Long} Shifted Long
+ */
+LongPrototype.shr_u = LongPrototype.shiftRightUnsigned;
+
+/**
+ * Converts this Long to signed.
+ * @returns {!Long} Signed long
+ */
+LongPrototype.toSigned = function toSigned() {
+ if (!this.unsigned)
+ return this;
+ return fromBits(this.low, this.high, false);
+};
+
+/**
+ * Converts this Long to unsigned.
+ * @returns {!Long} Unsigned long
+ */
+LongPrototype.toUnsigned = function toUnsigned() {
+ if (this.unsigned)
+ return this;
+ return fromBits(this.low, this.high, true);
+};
+
+/**
+ * Converts this Long to its byte representation.
+ * @param {boolean=} le Whether little or big endian, defaults to big endian
+ * @returns {!Array.} Byte representation
+ */
+LongPrototype.toBytes = function toBytes(le) {
+ return le ? this.toBytesLE() : this.toBytesBE();
+};
+
+/**
+ * Converts this Long to its little endian byte representation.
+ * @returns {!Array.} Little endian byte representation
+ */
+LongPrototype.toBytesLE = function toBytesLE() {
+ var hi = this.high,
+ lo = this.low;
+ return [
+ lo & 0xff,
+ lo >>> 8 & 0xff,
+ lo >>> 16 & 0xff,
+ lo >>> 24 ,
+ hi & 0xff,
+ hi >>> 8 & 0xff,
+ hi >>> 16 & 0xff,
+ hi >>> 24
+ ];
+};
+
+/**
+ * Converts this Long to its big endian byte representation.
+ * @returns {!Array.} Big endian byte representation
+ */
+LongPrototype.toBytesBE = function toBytesBE() {
+ var hi = this.high,
+ lo = this.low;
+ return [
+ hi >>> 24 ,
+ hi >>> 16 & 0xff,
+ hi >>> 8 & 0xff,
+ hi & 0xff,
+ lo >>> 24 ,
+ lo >>> 16 & 0xff,
+ lo >>> 8 & 0xff,
+ lo & 0xff
+ ];
+};
+
+/**
+ * Creates a Long from its byte representation.
+ * @param {!Array.} bytes Byte representation
+ * @param {boolean=} unsigned Whether unsigned or not, defaults to signed
+ * @param {boolean=} le Whether little or big endian, defaults to big endian
+ * @returns {Long} The corresponding Long value
+ */
+Long.fromBytes = function fromBytes(bytes, unsigned, le) {
+ return le ? Long.fromBytesLE(bytes, unsigned) : Long.fromBytesBE(bytes, unsigned);
+};
+
+/**
+ * Creates a Long from its little endian byte representation.
+ * @param {!Array.} bytes Little endian byte representation
+ * @param {boolean=} unsigned Whether unsigned or not, defaults to signed
+ * @returns {Long} The corresponding Long value
+ */
+Long.fromBytesLE = function fromBytesLE(bytes, unsigned) {
+ return new Long(
+ bytes[0] |
+ bytes[1] << 8 |
+ bytes[2] << 16 |
+ bytes[3] << 24,
+ bytes[4] |
+ bytes[5] << 8 |
+ bytes[6] << 16 |
+ bytes[7] << 24,
+ unsigned
+ );
+};
+
+/**
+ * Creates a Long from its big endian byte representation.
+ * @param {!Array.} bytes Big endian byte representation
+ * @param {boolean=} unsigned Whether unsigned or not, defaults to signed
+ * @returns {Long} The corresponding Long value
+ */
+Long.fromBytesBE = function fromBytesBE(bytes, unsigned) {
+ return new Long(
+ bytes[4] << 24 |
+ bytes[5] << 16 |
+ bytes[6] << 8 |
+ bytes[7],
+ bytes[0] << 24 |
+ bytes[1] << 16 |
+ bytes[2] << 8 |
+ bytes[3],
+ unsigned
+ );
+};
\ No newline at end of file
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/longBits.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/longBits.js
new file mode 100644
index 0000000..ae87a23
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/longBits.js
@@ -0,0 +1,122 @@
+module.exports = LongBits;
+
+function LongBits(lo, hi) {
+ this.lo = lo >>> 0;
+ this.hi = hi >>> 0;
+}
+
+var zero = LongBits.zero = new LongBits(0, 0);
+
+zero.toNumber = function() { return 0; };
+zero.zzEncode = zero.zzDecode = function() { return this; };
+zero.length = function() { return 1; };
+
+
+var zeroHash = LongBits.zeroHash = "\0\0\0\0\0\0\0\0";
+
+LongBits.fromNumber = function fromNumber(value) {
+ if (value === 0)
+ return zero;
+ var sign = value < 0;//如果sign为 1 ,表示为负数
+ if (sign)
+ value = -value;
+ var lo = value >>> 0,//取出底32位
+ hi = (value - lo) / 4294967296 >>> 0; //取出高32位
+ if (sign) { //负数
+ hi = ~hi >>> 0; //求取高32位的反码
+ lo = ~lo >>> 0; //求取低32位的反码
+ if (++lo > 4294967295) { //低32位大于Math.pow(2,31)-1
+ lo = 0;
+ if (++hi > 4294967295) //高32位大于Math.pow(2,31)-1
+ hi = 0;
+ }
+ }
+ return new LongBits(lo, hi);
+};
+
+
+LongBits.from = function from(value) {
+ if (typeof value === "number")
+ return LongBits.fromNumber(value);
+ if (typeof value === "string" || value instanceof String) {
+ return LongBits.fromNumber(parseInt(value, 10));
+ }
+ return value.low || value.high ? new LongBits(value.low >>> 0, value.high >>> 0) : zero;
+};
+
+LongBits.prototype.toNumber = function toNumber(unsigned) {
+ if (!unsigned && this.hi >>> 31) {
+ var lo = ~this.lo + 1 >>> 0,
+ hi = ~this.hi >>> 0;
+ if (!lo)
+ hi = hi + 1 >>> 0;
+ return -(lo + hi * 4294967296);
+ }
+ return this.lo + this.hi * 4294967296;
+};
+LongBits.prototype.toLong = function toLong(unsigned) {
+ //return util.Long
+ // ? new util.Long(this.lo | 0, this.hi | 0, Boolean(unsigned))
+ // /* istanbul ignore next */
+ // : { low: this.lo | 0, high: this.hi | 0, unsigned: Boolean(unsigned) };
+ return { low: this.lo | 0, high: this.hi | 0, unsigned: Boolean(unsigned) };
+};
+
+var charCodeAt = String.prototype.charCodeAt;
+
+LongBits.fromHash = function fromHash(hash) {
+ if (hash === zeroHash)
+ return zero;
+ return new LongBits(
+ ( charCodeAt.call(hash, 0)
+ | charCodeAt.call(hash, 1) << 8
+ | charCodeAt.call(hash, 2) << 16
+ | charCodeAt.call(hash, 3) << 24) >>> 0
+ ,
+ ( charCodeAt.call(hash, 4)
+ | charCodeAt.call(hash, 5) << 8
+ | charCodeAt.call(hash, 6) << 16
+ | charCodeAt.call(hash, 7) << 24) >>> 0
+ );
+};
+
+LongBits.prototype.toHash = function toHash() {
+ return String.fromCharCode(
+ this.lo & 255,
+ this.lo >>> 8 & 255,
+ this.lo >>> 16 & 255,
+ this.lo >>> 24 ,
+ this.hi & 255,
+ this.hi >>> 8 & 255,
+ this.hi >>> 16 & 255,
+ this.hi >>> 24
+ );
+};
+
+LongBits.prototype.zzEncode = function zzEncode() {
+ var mask = this.hi >> 31;
+ this.hi = ((this.hi << 1 | this.lo >>> 31) ^ mask) >>> 0;
+ this.lo = ( this.lo << 1 ^ mask) >>> 0;
+ return this;
+};
+
+LongBits.prototype.zzDecode = function zzDecode() {
+ var mask = -(this.lo & 1);
+ this.lo = ((this.lo >>> 1 | this.hi << 31) ^ mask) >>> 0;
+ this.hi = ( this.hi >>> 1 ^ mask) >>> 0;
+ return this;
+};
+LongBits.prototype.length = function length() {
+ var part0 = this.lo,
+ part1 = (this.lo >>> 28 | this.hi << 4) >>> 0,
+ part2 = this.hi >>> 24;
+ return part2 === 0
+ ? part1 === 0
+ ? part0 < 16384
+ ? part0 < 128 ? 1 : 2
+ : part0 < 2097152 ? 3 : 4
+ : part1 < 16384
+ ? part1 < 128 ? 5 : 6
+ : part1 < 2097152 ? 7 : 8
+ : part2 < 128 ? 9 : 10;
+};
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/mapField.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/mapField.js
new file mode 100644
index 0000000..4ca5cbe
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/mapField.js
@@ -0,0 +1,130 @@
+module.exports = MapField;
+
+// extends Field
+var Field = require("./field");
+((MapField.prototype = Object.create(Field.prototype)).constructor = MapField).className = "MapField";
+
+var types,
+ util;
+
+/**
+ * Constructs a new map field instance.
+ * @classdesc Reflected map field.
+ * @extends FieldBase
+ * @constructor
+ * @param {string} name Unique name within its namespace
+ * @param {number} id Unique id within its namespace
+ * @param {string} keyType Key type
+ * @param {string} type Value type
+ * @param {Object.} [options] Declared options
+ * @param {string} [comment] Comment associated with this field
+ */
+function MapField(name, id, keyType, type, options, comment) {
+ Field.call(this, name, id, type, undefined, undefined, options, comment);
+
+ /* istanbul ignore if */
+ if (!util.isString(keyType))
+ throw TypeError("keyType must be a string");
+
+ /**
+ * Key type.
+ * @type {string}
+ */
+ this.keyType = keyType; // toJSON, marker
+
+ /**
+ * Resolved key type if not a basic type.
+ * @type {ReflectionObject|null}
+ */
+ this.resolvedKeyType = null;
+
+ // Overrides Field#map
+ this.map = true;
+}
+
+/**
+ * Map field descriptor.
+ * @interface IMapField
+ * @extends {IField}
+ * @property {string} keyType Key type
+ */
+
+/**
+ * Extension map field descriptor.
+ * @interface IExtensionMapField
+ * @extends IMapField
+ * @property {string} extend Extended type
+ */
+
+/**
+ * Constructs a map field from a map field descriptor.
+ * @param {string} name Field name
+ * @param {IMapField} json Map field descriptor
+ * @returns {MapField} Created map field
+ * @throws {TypeError} If arguments are invalid
+ */
+MapField.fromJSON = function fromJSON(name, json) {
+ return new MapField(name, json.id, json.keyType, json.type, json.options, json.comment);
+};
+
+/**
+ * Converts this map field to a map field descriptor.
+ * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
+ * @returns {IMapField} Map field descriptor
+ */
+MapField.prototype.toJSON = function toJSON(toJSONOptions) {
+ var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
+ return util.toObject([
+ "keyType" , this.keyType,
+ "type" , this.type,
+ "id" , this.id,
+ "extend" , this.extend,
+ "options" , this.options,
+ "comment" , keepComments ? this.comment : undefined
+ ]);
+};
+
+/**
+ * @override
+ */
+MapField.prototype.resolve = function resolve() {
+ if (this.resolved)
+ return this;
+
+ // Besides a value type, map fields have a key type that may be "any scalar type except for floating point types and bytes"
+ if (types.mapKey[this.keyType] === undefined)
+ throw Error("invalid key type: " + this.keyType);
+
+ return Field.prototype.resolve.call(this);
+};
+
+/**
+ * Map field decorator (TypeScript).
+ * @name MapField.d
+ * @function
+ * @param {number} fieldId Field id
+ * @param {"int32"|"uint32"|"sint32"|"fixed32"|"sfixed32"|"int64"|"uint64"|"sint64"|"fixed64"|"sfixed64"|"bool"|"string"} fieldKeyType Field key type
+ * @param {"double"|"float"|"int32"|"uint32"|"sint32"|"fixed32"|"sfixed32"|"int64"|"uint64"|"sint64"|"fixed64"|"sfixed64"|"bool"|"string"|"bytes"|Object|Constructor<{}>} fieldValueType Field value type
+ * @returns {FieldDecorator} Decorator function
+ * @template T extends { [key: string]: number | Long | string | boolean | Uint8Array | Buffer | number[] | Message<{}> }
+ */
+MapField.d = function decorateMapField(fieldId, fieldKeyType, fieldValueType) {
+
+ // submessage value: decorate the submessage and use its name as the type
+ if (typeof fieldValueType === "function")
+ fieldValueType = util.decorateType(fieldValueType).name;
+
+ // enum reference value: create a reflected copy of the enum and keep reuseing it
+ else if (fieldValueType && typeof fieldValueType === "object")
+ fieldValueType = util.decorateEnum(fieldValueType).name;
+
+ return function mapFieldDecorator(prototype, fieldName) {
+ util.decorateType(prototype.constructor)
+ .add(new MapField(fieldName, fieldId, fieldKeyType, fieldValueType));
+ };
+};
+
+MapField._configure = function(){
+ types = require("./types");
+ util = require("./util");
+};
\ No newline at end of file
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/message.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/message.js
new file mode 100644
index 0000000..7bc9fce
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/message.js
@@ -0,0 +1,160 @@
+"use strict";
+module.exports = Message;
+
+var util;
+
+/**
+ * Constructs a new message instance.
+ * @classdesc Abstract runtime message.
+ * @constructor
+ * @param {Properties} [properties] Properties to set
+ * @template T extends object
+ */
+function Message(properties) {
+ // not used internally
+ if (properties)
+ for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+ this[keys[i]] = properties[keys[i]];
+}
+
+/**
+ * Reference to the reflected type.
+ * @name Message.$type
+ * @type {Type}
+ * @readonly
+ */
+
+/**
+ * Reference to the reflected type.
+ * @name Message#$type
+ * @type {Type}
+ * @readonly
+ */
+
+/*eslint-disable valid-jsdoc*/
+
+/**
+ * Creates a new message of this type using the specified properties.
+ * @param {Object.} [properties] Properties to set
+ * @returns {Message} Message instance
+ * @template T extends Message
+ * @this Constructor
+ */
+Message.create = function create(properties) {
+ return this.$type.create(properties);
+};
+
+/**
+ * Encodes a message of this type.
+ * @param {T|Object.} message Message to encode
+ * @param {Writer} [writer] Writer to use
+ * @returns {Writer} Writer
+ * @template T extends Message
+ * @this Constructor
+ */
+Message.encode = function encode(message, writer) {
+ if(!arguments.length){
+ return this.$type.encode(this);
+ }else if (arguments.length == 1){
+ return this.$type.encode(arguments[0]);
+ }else{
+ return this.$type.encode(arguments[0], arguments[1]);
+ }
+ //return this.$type.encode(message, writer);
+};
+
+/**
+ * Encodes a message of this type preceeded by its length as a varint.
+ * @param {T|Object.} message Message to encode
+ * @param {Writer} [writer] Writer to use
+ * @returns {Writer} Writer
+ * @template T extends Message
+ * @this Constructor
+ */
+Message.encodeDelimited = function encodeDelimited(message, writer) {
+ return this.$type.encodeDelimited(message, writer);
+};
+
+/**
+ * Decodes a message of this type.
+ * @name Message.decode
+ * @function
+ * @param {Reader|Uint8Array} reader Reader or buffer to decode
+ * @returns {T} Decoded message
+ * @template T extends Message
+ * @this Constructor
+ */
+Message.decode = function decode(reader) {
+ return this.$type.decode(reader);
+};
+
+/**
+ * Decodes a message of this type preceeded by its length as a varint.
+ * @name Message.decodeDelimited
+ * @function
+ * @param {Reader|Uint8Array} reader Reader or buffer to decode
+ * @returns {T} Decoded message
+ * @template T extends Message
+ * @this Constructor
+ */
+Message.decodeDelimited = function decodeDelimited(reader) {
+ return this.$type.decodeDelimited(reader);
+};
+
+/**
+ * Verifies a message of this type.
+ * @name Message.verify
+ * @function
+ * @param {Object.} message Plain object to verify
+ * @returns {string|null} `null` if valid, otherwise the reason why it is not
+ */
+Message.verify = function verify(message) {
+ return this.$type.verify(message);
+};
+
+/**
+ * Creates a new message of this type from a plain object. Also converts values to their respective internal types.
+ * @param {Object.} object Plain object
+ * @returns {T} Message instance
+ * @template T extends Message
+ * @this Constructor
+ */
+Message.fromObject = function fromObject(object) {
+ return this.$type.fromObject(object);
+};
+
+/**
+ * Creates a plain object from a message of this type. Also converts values to other types if specified.
+ * @param {T} message Message instance
+ * @param {IConversionOptions} [options] Conversion options
+ * @returns {Object.} Plain object
+ * @template T extends Message
+ * @this Constructor
+ */
+Message.toObject = function toObject(message, options) {
+ message = message || this;
+ return this.$type.toObject(message, options);
+};
+
+/**
+ * Converts this message to JSON.
+ * @returns {Object.} JSON object
+ */
+Message.prototype.toJSON = function toJSON() {
+ return this.$type.toObject(this, util.toJSONOptions);
+};
+
+
+
+Message.set = function(key,value){
+ Message[key] = value;
+};
+
+Message.get = function (key){
+ return Message[key];
+};
+/*eslint-enable valid-jsdoc*/
+
+Message._configure = function(){
+ util = require("./util");
+}
\ No newline at end of file
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/method.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/method.js
new file mode 100644
index 0000000..3e82f5f
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/method.js
@@ -0,0 +1,155 @@
+"use strict";
+module.exports = Method;
+
+// extends ReflectionObject
+var ReflectionObject = require("./object");
+((Method.prototype = Object.create(ReflectionObject.prototype)).constructor = Method).className = "Method";
+
+var util;
+
+/**
+ * Constructs a new service method instance.
+ * @classdesc Reflected service method.
+ * @extends ReflectionObject
+ * @constructor
+ * @param {string} name Method name
+ * @param {string|undefined} type Method type, usually `"rpc"`
+ * @param {string} requestType Request message type
+ * @param {string} responseType Response message type
+ * @param {boolean|Object.} [requestStream] Whether the request is streamed
+ * @param {boolean|Object.} [responseStream] Whether the response is streamed
+ * @param {Object.} [options] Declared options
+ * @param {string} [comment] The comment for this method
+ */
+function Method(name, type, requestType, responseType, requestStream, responseStream, options, comment) {
+
+ /* istanbul ignore next */
+ if (util.isObject(requestStream)) {
+ options = requestStream;
+ requestStream = responseStream = undefined;
+ } else if (util.isObject(responseStream)) {
+ options = responseStream;
+ responseStream = undefined;
+ }
+
+ /* istanbul ignore if */
+ if (!(type === undefined || util.isString(type)))
+ throw TypeError("type must be a string");
+
+ /* istanbul ignore if */
+ if (!util.isString(requestType))
+ throw TypeError("requestType must be a string");
+
+ /* istanbul ignore if */
+ if (!util.isString(responseType))
+ throw TypeError("responseType must be a string");
+
+ ReflectionObject.call(this, name, options);
+
+ /**
+ * Method type.
+ * @type {string}
+ */
+ this.type = type || "rpc"; // toJSON
+
+ /**
+ * Request type.
+ * @type {string}
+ */
+ this.requestType = requestType; // toJSON, marker
+
+ /**
+ * Whether requests are streamed or not.
+ * @type {boolean|undefined}
+ */
+ this.requestStream = requestStream ? true : undefined; // toJSON
+
+ /**
+ * Response type.
+ * @type {string}
+ */
+ this.responseType = responseType; // toJSON
+
+ /**
+ * Whether responses are streamed or not.
+ * @type {boolean|undefined}
+ */
+ this.responseStream = responseStream ? true : undefined; // toJSON
+
+ /**
+ * Resolved request type.
+ * @type {Type|null}
+ */
+ this.resolvedRequestType = null;
+
+ /**
+ * Resolved response type.
+ * @type {Type|null}
+ */
+ this.resolvedResponseType = null;
+
+ /**
+ * Comment for this method
+ * @type {string|null}
+ */
+ this.comment = comment;
+}
+
+/**
+ * Method descriptor.
+ * @interface IMethod
+ * @property {string} [type="rpc"] Method type
+ * @property {string} requestType Request type
+ * @property {string} responseType Response type
+ * @property {boolean} [requestStream=false] Whether requests are streamed
+ * @property {boolean} [responseStream=false] Whether responses are streamed
+ * @property {Object.} [options] Method options
+ */
+
+/**
+ * Constructs a method from a method descriptor.
+ * @param {string} name Method name
+ * @param {IMethod} json Method descriptor
+ * @returns {Method} Created method
+ * @throws {TypeError} If arguments are invalid
+ */
+Method.fromJSON = function fromJSON(name, json) {
+ return new Method(name, json.type, json.requestType, json.responseType, json.requestStream, json.responseStream, json.options, json.comment);
+};
+
+/**
+ * Converts this method to a method descriptor.
+ * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
+ * @returns {IMethod} Method descriptor
+ */
+Method.prototype.toJSON = function toJSON(toJSONOptions) {
+ var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
+ return util.toObject([
+ "type" , this.type !== "rpc" && /* istanbul ignore next */ this.type || undefined,
+ "requestType" , this.requestType,
+ "requestStream" , this.requestStream,
+ "responseType" , this.responseType,
+ "responseStream" , this.responseStream,
+ "options" , this.options,
+ "comment" , keepComments ? this.comment : undefined
+ ]);
+};
+
+/**
+ * @override
+ */
+Method.prototype.resolve = function resolve() {
+
+ /* istanbul ignore if */
+ if (this.resolved)
+ return this;
+
+ this.resolvedRequestType = this.parent.lookupType(this.requestType);
+ this.resolvedResponseType = this.parent.lookupType(this.responseType);
+
+ return ReflectionObject.prototype.resolve.call(this);
+};
+
+Method._configure = function (){
+ util = require("./util");
+}
\ No newline at end of file
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/namespace.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/namespace.js
new file mode 100644
index 0000000..dddcf0e
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/namespace.js
@@ -0,0 +1,435 @@
+
+module.exports = Namespace;
+
+// extends ReflectionObject
+var ReflectionObject = require("./object");
+((Namespace.prototype = Object.create(ReflectionObject.prototype)).constructor = Namespace).className = "Namespace";
+
+var Enum,
+ Field,
+ util;
+
+var Type; // cyclic
+var Service;
+
+/**
+ * Constructs a new namespace instance.
+ * @name Namespace
+ * @classdesc Reflected namespace.
+ * @extends NamespaceBase
+ * @constructor
+ * @param {string} name Namespace name
+ * @param {Object.} [options] Declared options
+ */
+
+/**
+ * Constructs a namespace from JSON.
+ * @memberof Namespace
+ * @function
+ * @param {string} name Namespace name
+ * @param {Object.} json JSON object
+ * @returns {Namespace} Created namespace
+ * @throws {TypeError} If arguments are invalid
+ */
+Namespace.fromJSON = function fromJSON(name, json) {
+ return new Namespace(name, json.options).addJSON(json.nested);
+};
+
+/**
+ * Converts an array of reflection objects to JSON.
+ * @memberof Namespace
+ * @param {ReflectionObject[]} array Object array
+ * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
+ * @returns {Object.|undefined} JSON object or `undefined` when array is empty
+ */
+function arrayToJSON(array, toJSONOptions) {
+ if (!(array && array.length))
+ return undefined;
+ var obj = {};
+ for (var i = 0; i < array.length; ++i)
+ obj[array[i].name] = array[i].toJSON(toJSONOptions);
+ return obj;
+}
+
+Namespace.arrayToJSON = arrayToJSON;
+
+/**
+ * Tests if the specified id is reserved.
+ * @param {Array.|undefined} reserved Array of reserved ranges and names
+ * @param {number} id Id to test
+ * @returns {boolean} `true` if reserved, otherwise `false`
+ */
+Namespace.isReservedId = function isReservedId(reserved, id) {
+ if (reserved)
+ for (var i = 0; i < reserved.length; ++i)
+ if (typeof reserved[i] !== "string" && reserved[i][0] <= id && reserved[i][1] >= id)
+ return true;
+ return false;
+};
+
+/**
+ * Tests if the specified name is reserved.
+ * @param {Array.|undefined} reserved Array of reserved ranges and names
+ * @param {string} name Name to test
+ * @returns {boolean} `true` if reserved, otherwise `false`
+ */
+Namespace.isReservedName = function isReservedName(reserved, name) {
+ if (reserved)
+ for (var i = 0; i < reserved.length; ++i)
+ if (reserved[i] === name)
+ return true;
+ return false;
+};
+
+/**
+ * Not an actual constructor. Use {@link Namespace} instead.
+ * @classdesc Base class of all reflection objects containing nested objects. This is not an actual class but here for the sake of having consistent type definitions.
+ * @exports NamespaceBase
+ * @extends ReflectionObject
+ * @abstract
+ * @constructor
+ * @param {string} name Namespace name
+ * @param {Object.} [options] Declared options
+ * @see {@link Namespace}
+ */
+function Namespace(name, options) {
+ ReflectionObject.call(this, name, options);
+
+ /**
+ * Nested objects by name.
+ * @type {Object.|undefined}
+ */
+ this.nested = undefined; // toJSON
+
+ /**
+ * Cached nested objects as an array.
+ * @type {ReflectionObject[]|null}
+ * @private
+ */
+ this._nestedArray = null;
+}
+
+function clearCache(namespace) {
+ namespace._nestedArray = null;
+ return namespace;
+}
+
+/**
+ * Nested objects of this namespace as an array for iteration.
+ * @name NamespaceBase#nestedArray
+ * @type {ReflectionObject[]}
+ * @readonly
+ */
+Object.defineProperty(Namespace.prototype, "nestedArray", {
+ get: function() {
+ return this._nestedArray || (this._nestedArray = util.toArray(this.nested));
+ }
+});
+
+/**
+ * Namespace descriptor.
+ * @interface INamespace
+ * @property {Object.} [options] Namespace options
+ * @property {Object.} [nested] Nested object descriptors
+ */
+
+/**
+ * Any extension field descriptor.
+ * @typedef AnyExtensionField
+ * @type {IExtensionField|IExtensionMapField}
+ */
+
+/**
+ * Any nested object descriptor.
+ * @typedef AnyNestedObject
+ * @type {IEnum|IType|IService|AnyExtensionField|INamespace}
+ */
+// ^ BEWARE: VSCode hangs forever when using more than 5 types (that's why AnyExtensionField exists in the first place)
+
+/**
+ * Converts this namespace to a namespace descriptor.
+ * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
+ * @returns {INamespace} Namespace descriptor
+ */
+Namespace.prototype.toJSON = function toJSON(toJSONOptions) {
+ return util.toObject([
+ "options" , this.options,
+ "nested" , arrayToJSON(this.nestedArray, toJSONOptions)
+ ]);
+};
+
+/**
+ * Adds nested objects to this namespace from nested object descriptors.
+ * @param {Object.} nestedJson Any nested object descriptors
+ * @returns {Namespace} `this`
+ */
+Namespace.prototype.addJSON = function addJSON(nestedJson) {
+ var ns = this;
+ /* istanbul ignore else */
+ if (nestedJson) {
+ for (var names = Object.keys(nestedJson), i = 0, nested; i < names.length; ++i) {
+ nested = nestedJson[names[i]];
+ ns.add( // most to least likely
+ ( nested.fields !== undefined
+ ? Type.fromJSON
+ : nested.values !== undefined
+ ? Enum.fromJSON
+ : nested.methods !== undefined
+ ? Service.fromJSON
+ : nested.id !== undefined
+ ? Field.fromJSON
+ : Namespace.fromJSON )(names[i], nested)
+ );
+ }
+ }
+ return this;
+};
+
+/**
+ * Gets the nested object of the specified name.
+ * @param {string} name Nested object name
+ * @returns {ReflectionObject|null} The reflection object or `null` if it doesn't exist
+ */
+Namespace.prototype.get = function get(name) {
+ return this.nested && this.nested[name]
+ || null;
+};
+
+/**
+ * Gets the values of the nested {@link Enum|enum} of the specified name.
+ * This methods differs from {@link Namespace#get|get} in that it returns an enum's values directly and throws instead of returning `null`.
+ * @param {string} name Nested enum name
+ * @returns {Object.} Enum values
+ * @throws {Error} If there is no such enum
+ */
+Namespace.prototype.getEnum = function getEnum(name) {
+ if (this.nested && this.nested[name] instanceof Enum)
+ return this.nested[name].values;
+ throw Error("no such enum: " + name);
+};
+
+/**
+ * Adds a nested object to this namespace.
+ * @param {ReflectionObject} object Nested object to add
+ * @returns {Namespace} `this`
+ * @throws {TypeError} If arguments are invalid
+ * @throws {Error} If there is already a nested object with this name
+ */
+Namespace.prototype.add = function add(object) {
+
+ if (!(object instanceof Field && object.extend !== undefined || object instanceof Type || object instanceof Enum || object instanceof Service || object instanceof Namespace))
+ throw TypeError("object must be a valid nested object");
+
+ if (!this.nested)
+ this.nested = {};
+ else {
+ var prev = this.get(object.name);
+ if (prev) {
+ if (prev instanceof Namespace && object instanceof Namespace && !(prev instanceof Type || prev instanceof Service)) {
+ // replace plain namespace but keep existing nested elements and options
+ var nested = prev.nestedArray;
+ for (var i = 0; i < nested.length; ++i)
+ object.add(nested[i]);
+ this.remove(prev);
+ if (!this.nested)
+ this.nested = {};
+ object.setOptions(prev.options, true);
+
+ } else
+ throw Error("duplicate name '" + object.name + "' in " + this);
+ }
+ }
+ this.nested[object.name] = object;
+ object.onAdd(this);
+ return clearCache(this);
+};
+
+/**
+ * Removes a nested object from this namespace.
+ * @param {ReflectionObject} object Nested object to remove
+ * @returns {Namespace} `this`
+ * @throws {TypeError} If arguments are invalid
+ * @throws {Error} If `object` is not a member of this namespace
+ */
+Namespace.prototype.remove = function remove(object) {
+
+ if (!(object instanceof ReflectionObject))
+ throw TypeError("object must be a ReflectionObject");
+ if (object.parent !== this)
+ throw Error(object + " is not a member of " + this);
+
+ delete this.nested[object.name];
+ if (!Object.keys(this.nested).length)
+ this.nested = undefined;
+
+ object.onRemove(this);
+ return clearCache(this);
+};
+
+/**
+ * Defines additial namespaces within this one if not yet existing.
+ * @param {string|string[]} path Path to create
+ * @param {*} [json] Nested types to create from JSON
+ * @returns {Namespace} Pointer to the last namespace created or `this` if path is empty
+ */
+Namespace.prototype.define = function define(path, json) {
+
+ if (util.isString(path))
+ path = path.split(".");
+ else if (!Array.isArray(path))
+ throw TypeError("illegal path");
+ if (path && path.length && path[0] === "")
+ throw Error("path must be relative");
+
+ var ptr = this;
+ while (path.length > 0) {
+ var part = path.shift();
+ if (ptr.nested && ptr.nested[part]) {
+ ptr = ptr.nested[part];
+ if (!(ptr instanceof Namespace))
+ throw Error("path conflicts with non-namespace objects");
+ } else
+ ptr.add(ptr = new Namespace(part));
+ }
+ if (json)
+ ptr.addJSON(json);
+ return ptr;
+};
+
+/**
+ * Resolves this namespace's and all its nested objects' type references. Useful to validate a reflection tree, but comes at a cost.
+ * @returns {Namespace} `this`
+ */
+Namespace.prototype.resolveAll = function resolveAll() {
+ var nested = this.nestedArray, i = 0;
+ while (i < nested.length)
+ if (nested[i] instanceof Namespace)
+ nested[i++].resolveAll();
+ else
+ nested[i++].resolve();
+ return this.resolve();
+};
+
+/**
+ * Recursively looks up the reflection object matching the specified path in the scope of this namespace.
+ * @param {string|string[]} path Path to look up
+ * @param {*|Array.<*>} filterTypes Filter types, any combination of the constructors of `protobuf.Type`, `protobuf.Enum`, `protobuf.Service` etc.
+ * @param {boolean} [parentAlreadyChecked=false] If known, whether the parent has already been checked
+ * @returns {ReflectionObject|null} Looked up object or `null` if none could be found
+ */
+Namespace.prototype.lookup = function lookup(path, filterTypes, parentAlreadyChecked) {
+
+ /* istanbul ignore next */
+ if (typeof filterTypes === "boolean") {
+ parentAlreadyChecked = filterTypes;
+ filterTypes = undefined;
+ } else if (filterTypes && !Array.isArray(filterTypes))
+ filterTypes = [ filterTypes ];
+
+ if (util.isString(path) && path.length) {
+ if (path === ".")
+ return this.root;
+ path = path.split(".");
+ } else if (!path.length)
+ return this;
+
+ // Start at root if path is absolute
+ if (path[0] === "")
+ return this.root.lookup(path.slice(1), filterTypes);
+
+ // Test if the first part matches any nested object, and if so, traverse if path contains more
+ var found = this.get(path[0]);
+ if (found) {
+ if (path.length === 1) {
+ if (!filterTypes || filterTypes.indexOf(found.constructor) > -1)
+ return found;
+ } else if (found instanceof Namespace && (found = found.lookup(path.slice(1), filterTypes, true)))
+ return found;
+
+ // Otherwise try each nested namespace
+ } else
+ for (var i = 0; i < this.nestedArray.length; ++i)
+ if (this._nestedArray[i] instanceof Namespace && (found = this._nestedArray[i].lookup(path, filterTypes, true)))
+ return found;
+
+ // If there hasn't been a match, try again at the parent
+ if (this.parent === null || parentAlreadyChecked)
+ return null;
+ return this.parent.lookup(path, filterTypes);
+};
+
+/**
+ * Looks up the reflection object at the specified path, relative to this namespace.
+ * @name NamespaceBase#lookup
+ * @function
+ * @param {string|string[]} path Path to look up
+ * @param {boolean} [parentAlreadyChecked=false] Whether the parent has already been checked
+ * @returns {ReflectionObject|null} Looked up object or `null` if none could be found
+ * @variation 2
+ */
+// lookup(path: string, [parentAlreadyChecked: boolean])
+
+/**
+ * Looks up the {@link Type|type} at the specified path, relative to this namespace.
+ * Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.
+ * @param {string|string[]} path Path to look up
+ * @returns {Type} Looked up type
+ * @throws {Error} If `path` does not point to a type
+ */
+Namespace.prototype.lookupType = function lookupType(path) {
+ var found = this.lookup(path, [ Type ]);
+ if (!found)
+ throw Error("no such type: " + path);
+ return found;
+};
+
+/**
+ * Looks up the values of the {@link Enum|enum} at the specified path, relative to this namespace.
+ * Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.
+ * @param {string|string[]} path Path to look up
+ * @returns {Enum} Looked up enum
+ * @throws {Error} If `path` does not point to an enum
+ */
+Namespace.prototype.lookupEnum = function lookupEnum(path) {
+ var found = this.lookup(path, [ Enum ]);
+ if (!found)
+ throw Error("no such Enum '" + path + "' in " + this);
+ return found;
+};
+
+/**
+ * Looks up the {@link Type|type} or {@link Enum|enum} at the specified path, relative to this namespace.
+ * Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.
+ * @param {string|string[]} path Path to look up
+ * @returns {Type} Looked up type or enum
+ * @throws {Error} If `path` does not point to a type or enum
+ */
+Namespace.prototype.lookupTypeOrEnum = function lookupTypeOrEnum(path) {
+ var found = this.lookup(path, [ Type, Enum ]);
+ if (!found)
+ throw Error("no such Type or Enum '" + path + "' in " + this);
+ return found;
+};
+
+/**
+ * Looks up the {@link Service|service} at the specified path, relative to this namespace.
+ * Besides its signature, this methods differs from {@link Namespace#lookup|lookup} in that it throws instead of returning `null`.
+ * @param {string|string[]} path Path to look up
+ * @returns {Service} Looked up service
+ * @throws {Error} If `path` does not point to a service
+ */
+Namespace.prototype.lookupService = function lookupService(path) {
+ var found = this.lookup(path, [ Service ]);
+ if (!found)
+ throw Error("no such Service '" + path + "' in " + this);
+ return found;
+};
+
+Namespace._configure = function() {
+ Enum = require("./enum");
+ Field = require("./field");
+ util = require("./util");
+
+ Type = require("./type"); // cyclic
+ Service = require("./service");
+};
\ No newline at end of file
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/object.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/object.js
new file mode 100644
index 0000000..0b7dfc4
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/object.js
@@ -0,0 +1,199 @@
+"use strict";
+module.exports = ReflectionObject;
+
+ReflectionObject.className = "ReflectionObject";
+var util;
+
+var Root; // cyclic
+
+/**
+ * Constructs a new reflection object instance.
+ * @classdesc Base class of all reflection objects.
+ * @constructor
+ * @param {string} name Object name
+ * @param {Object.} [options] Declared options
+ * @abstract
+ */
+function ReflectionObject(name, options) {
+
+ if (!util.isString(name))
+ throw TypeError("name must be a string");
+
+ if (options && !util.isObject(options))
+ throw TypeError("options must be an object");
+
+ /**
+ * Options.
+ * @type {Object.|undefined}
+ */
+ this.options = options; // toJSON
+
+ /**
+ * Unique name within its namespace.
+ * @type {string}
+ */
+ this.name = name;
+
+ /**
+ * Parent namespace.
+ * @type {Namespace|null}
+ */
+ this.parent = null;
+
+ /**
+ * Whether already resolved or not.
+ * @type {boolean}
+ */
+ this.resolved = false;
+
+ /**
+ * Comment text, if any.
+ * @type {string|null}
+ */
+ this.comment = null;
+
+ /**
+ * Defining file name.
+ * @type {string|null}
+ */
+ this.filename = null;
+}
+
+Object.defineProperties(ReflectionObject.prototype, {
+
+ /**
+ * Reference to the root namespace.
+ * @name ReflectionObject#root
+ * @type {Root}
+ * @readonly
+ */
+ root: {
+ get: function() {
+ var ptr = this;
+ while (ptr.parent !== null)
+ ptr = ptr.parent;
+ return ptr;
+ }
+ },
+
+ /**
+ * Full name including leading dot.
+ * @name ReflectionObject#fullName
+ * @type {string}
+ * @readonly
+ */
+ fullName: {
+ get: function() {
+ var path = [ this.name ],
+ ptr = this.parent;
+ while (ptr) {
+ path.unshift(ptr.name);
+ ptr = ptr.parent;
+ }
+ return path.join(".");
+ }
+ }
+});
+
+/**
+ * Converts this reflection object to its descriptor representation.
+ * @returns {Object.} Descriptor
+ * @abstract
+ */
+ReflectionObject.prototype.toJSON = /* istanbul ignore next */ function toJSON() {
+ throw Error(); // not implemented, shouldn't happen
+};
+
+/**
+ * Called when this object is added to a parent.
+ * @param {ReflectionObject} parent Parent added to
+ * @returns {undefined}
+ */
+ReflectionObject.prototype.onAdd = function onAdd(parent) {
+ if (this.parent && this.parent !== parent)
+ this.parent.remove(this);
+ this.parent = parent;
+ this.resolved = false;
+ var root = parent.root;
+ if (root instanceof Root)
+ root._handleAdd(this);
+};
+
+/**
+ * Called when this object is removed from a parent.
+ * @param {ReflectionObject} parent Parent removed from
+ * @returns {undefined}
+ */
+ReflectionObject.prototype.onRemove = function onRemove(parent) {
+ var root = parent.root;
+ if (root instanceof Root)
+ root._handleRemove(this);
+ this.parent = null;
+ this.resolved = false;
+};
+
+/**
+ * Resolves this objects type references.
+ * @returns {ReflectionObject} `this`
+ */
+ReflectionObject.prototype.resolve = function resolve() {
+ if (this.resolved)
+ return this;
+ if (this.root instanceof Root)
+ this.resolved = true; // only if part of a root
+ return this;
+};
+
+/**
+ * Gets an option value.
+ * @param {string} name Option name
+ * @returns {*} Option value or `undefined` if not set
+ */
+ReflectionObject.prototype.getOption = function getOption(name) {
+ if (this.options)
+ return this.options[name];
+ return undefined;
+};
+
+/**
+ * Sets an option.
+ * @param {string} name Option name
+ * @param {*} value Option value
+ * @param {boolean} [ifNotSet] Sets the option only if it isn't currently set
+ * @returns {ReflectionObject} `this`
+ */
+ReflectionObject.prototype.setOption = function setOption(name, value, ifNotSet) {
+ if (!ifNotSet || !this.options || this.options[name] === undefined)
+ (this.options || (this.options = {}))[name] = value;
+ return this;
+};
+
+/**
+ * Sets multiple options.
+ * @param {Object.} options Options to set
+ * @param {boolean} [ifNotSet] Sets an option only if it isn't currently set
+ * @returns {ReflectionObject} `this`
+ */
+ReflectionObject.prototype.setOptions = function setOptions(options, ifNotSet) {
+ if (options)
+ for (var keys = Object.keys(options), i = 0; i < keys.length; ++i)
+ this.setOption(keys[i], options[keys[i]], ifNotSet);
+ return this;
+};
+
+/**
+ * Converts this instance to its string representation.
+ * @returns {string} Class name[, space, full name]
+ */
+ReflectionObject.prototype.toString = function toString() {
+ var className = this.constructor.className,
+ fullName = this.fullName;
+ if (fullName.length)
+ return className + " " + fullName;
+ return className;
+};
+
+ReflectionObject._configure = function(Root_) {
+ Root = require('./root');
+ util = require('./util');
+};
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/oneof.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/oneof.js
new file mode 100644
index 0000000..c5605c3
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/oneof.js
@@ -0,0 +1,207 @@
+module.exports = OneOf;
+
+// extends ReflectionObject
+var ReflectionObject = require("./object");
+((OneOf.prototype = Object.create(ReflectionObject.prototype)).constructor = OneOf).className = "OneOf";
+
+var Field;
+var util;
+
+/**
+ * Constructs a new oneof instance.
+ * @classdesc Reflected oneof.
+ * @extends ReflectionObject
+ * @constructor
+ * @param {string} name Oneof name
+ * @param {string[]|Object.} [fieldNames] Field names
+ * @param {Object.} [options] Declared options
+ * @param {string} [comment] Comment associated with this field
+ */
+function OneOf(name, fieldNames, options, comment) {
+ if (!Array.isArray(fieldNames)) {
+ options = fieldNames;
+ fieldNames = undefined;
+ }
+ ReflectionObject.call(this, name, options);
+
+ /* istanbul ignore if */
+ if (!(fieldNames === undefined || Array.isArray(fieldNames)))
+ throw TypeError("fieldNames must be an Array");
+
+ /**
+ * Field names that belong to this oneof.
+ * @type {string[]}
+ */
+ this.oneof = fieldNames || []; // toJSON, marker
+
+ /**
+ * Fields that belong to this oneof as an array for iteration.
+ * @type {Field[]}
+ * @readonly
+ */
+ this.fieldsArray = []; // declared readonly for conformance, possibly not yet added to parent
+
+ /**
+ * Comment for this field.
+ * @type {string|null}
+ */
+ this.comment = comment;
+}
+
+/**
+ * Oneof descriptor.
+ * @interface IOneOf
+ * @property {Array.} oneof Oneof field names
+ * @property {Object.} [options] Oneof options
+ */
+
+/**
+ * Constructs a oneof from a oneof descriptor.
+ * @param {string} name Oneof name
+ * @param {IOneOf} json Oneof descriptor
+ * @returns {OneOf} Created oneof
+ * @throws {TypeError} If arguments are invalid
+ */
+OneOf.fromJSON = function fromJSON(name, json) {
+ return new OneOf(name, json.oneof, json.options, json.comment);
+};
+
+/**
+ * Converts this oneof to a oneof descriptor.
+ * @param {IToJSONOptions} [toJSONOptions] JSON conversion options
+ * @returns {IOneOf} Oneof descriptor
+ */
+OneOf.prototype.toJSON = function toJSON(toJSONOptions) {
+ var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
+ return util.toObject([
+ "options" , this.options,
+ "oneof" , this.oneof,
+ "comment" , keepComments ? this.comment : undefined
+ ]);
+};
+
+/**
+ * Adds the fields of the specified oneof to the parent if not already done so.
+ * @param {OneOf} oneof The oneof
+ * @returns {undefined}
+ * @inner
+ * @ignore
+ */
+function addFieldsToParent(oneof) {
+ if (oneof.parent)
+ for (var i = 0; i < oneof.fieldsArray.length; ++i)
+ if (!oneof.fieldsArray[i].parent)
+ oneof.parent.add(oneof.fieldsArray[i]);
+}
+
+/**
+ * Adds a field to this oneof and removes it from its current parent, if any.
+ * @param {Field} field Field to add
+ * @returns {OneOf} `this`
+ */
+OneOf.prototype.add = function add(field) {
+
+ /* istanbul ignore if */
+ if (!(field instanceof Field))
+ throw TypeError("field must be a Field");
+
+ if (field.parent && field.parent !== this.parent)
+ field.parent.remove(field);
+ this.oneof.push(field.name);
+ this.fieldsArray.push(field);
+ field.partOf = this; // field.parent remains null
+ addFieldsToParent(this);
+ return this;
+};
+
+/**
+ * Removes a field from this oneof and puts it back to the oneof's parent.
+ * @param {Field} field Field to remove
+ * @returns {OneOf} `this`
+ */
+OneOf.prototype.remove = function remove(field) {
+
+ /* istanbul ignore if */
+ if (!(field instanceof Field))
+ throw TypeError("field must be a Field");
+
+ var index = this.fieldsArray.indexOf(field);
+
+ /* istanbul ignore if */
+ if (index < 0)
+ throw Error(field + " is not a member of " + this);
+
+ this.fieldsArray.splice(index, 1);
+ index = this.oneof.indexOf(field.name);
+
+ /* istanbul ignore else */
+ if (index > -1) // theoretical
+ this.oneof.splice(index, 1);
+
+ field.partOf = null;
+ return this;
+};
+
+/**
+ * @override
+ */
+OneOf.prototype.onAdd = function onAdd(parent) {
+ ReflectionObject.prototype.onAdd.call(this, parent);
+ var self = this;
+ // Collect present fields
+ for (var i = 0; i < this.oneof.length; ++i) {
+ var field = parent.get(this.oneof[i]);
+ if (field && !field.partOf) {
+ field.partOf = self;
+ self.fieldsArray.push(field);
+ }
+ }
+ // Add not yet present fields
+ addFieldsToParent(this);
+};
+
+/**
+ * @override
+ */
+OneOf.prototype.onRemove = function onRemove(parent) {
+ for (var i = 0, field; i < this.fieldsArray.length; ++i)
+ if ((field = this.fieldsArray[i]).parent)
+ field.parent.remove(field);
+ ReflectionObject.prototype.onRemove.call(this, parent);
+};
+
+/**
+ * Decorator function as returned by {@link OneOf.d} (TypeScript).
+ * @typedef OneOfDecorator
+ * @type {function}
+ * @param {Object} prototype Target prototype
+ * @param {string} oneofName OneOf name
+ * @returns {undefined}
+ */
+
+/**
+ * OneOf decorator (TypeScript).
+ * @function
+ * @param {...string} fieldNames Field names
+ * @returns {OneOfDecorator} Decorator function
+ * @template T extends string
+ */
+OneOf.d = function decorateOneOf() {
+ var fieldNames = new Array(arguments.length),
+ index = 0;
+ while (index < arguments.length)
+ fieldNames[index] = arguments[index++];
+ return function oneOfDecorator(prototype, oneofName) {
+ util.decorateType(prototype.constructor)
+ .add(new OneOf(oneofName, fieldNames));
+ Object.defineProperty(prototype, oneofName, {
+ get: util.oneOfGetter(fieldNames),
+ set: util.oneOfSetter(fieldNames)
+ });
+ };
+};
+
+OneOf._configure = function (){
+ Field = require('./field');
+ util = require('./util');
+};
\ No newline at end of file
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/parse.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/parse.js
new file mode 100644
index 0000000..d7f4389
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/parse.js
@@ -0,0 +1,770 @@
+"use strict";
+module.exports = parse;
+
+parse.filename = null;
+parse.defaults = { keepCase: false };
+
+var tokenize,
+ Root,
+ Type,
+ Field,
+ MapField,
+ OneOf,
+ Enum,
+ Service,
+ Method,
+ types,
+ util;
+
+var base10Re = /^[1-9][0-9]*$/,
+ base10NegRe = /^-?[1-9][0-9]*$/,
+ base16Re = /^0[x][0-9a-fA-F]+$/,
+ base16NegRe = /^-?0[x][0-9a-fA-F]+$/,
+ base8Re = /^0[0-7]+$/,
+ base8NegRe = /^-?0[0-7]+$/,
+ numberRe = /^(?![eE])[0-9]*(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?$/,
+ nameRe = /^[a-zA-Z_][a-zA-Z_0-9]*$/,
+ typeRefRe = /^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)+$/,
+ fqTypeRefRe = /^(?:\.[a-zA-Z][a-zA-Z_0-9]*)+$/;
+
+/**
+ * Result object returned from {@link parse}.
+ * @interface IParserResult
+ * @property {string|undefined} package Package name, if declared
+ * @property {string[]|undefined} imports Imports, if any
+ * @property {string[]|undefined} weakImports Weak imports, if any
+ * @property {string|undefined} syntax Syntax, if specified (either `"proto2"` or `"proto3"`)
+ * @property {Root} root Populated root instance
+ */
+
+/**
+ * Options modifying the behavior of {@link parse}.
+ * @interface IParseOptions
+ * @property {boolean} [keepCase=false] Keeps field casing instead of converting to camel case
+ * @property {boolean} [alternateCommentMode=false] Recognize double-slash comments in addition to doc-block comments.
+ */
+
+/**
+ * Options modifying the behavior of JSON serialization.
+ * @interface IToJSONOptions
+ * @property {boolean} [keepComments=false] Serializes comments.
+ */
+
+/**
+ * Parses the given .proto source and returns an object with the parsed contents.
+ * @param {string} source Source contents
+ * @param {Root} root Root to populate
+ * @param {IParseOptions} [options] Parse options. Defaults to {@link parse.defaults} when omitted.
+ * @returns {IParserResult} Parser result
+ * @property {string} filename=null Currently processing file name for error reporting, if known
+ * @property {IParseOptions} defaults Default {@link IParseOptions}
+ */
+function parse(source, root, options) {
+ /* eslint-disable callback-return */
+ if (!(root instanceof Root)) {
+ options = root;
+ root = new Root();
+ }
+ if (!options)
+ options = parse.defaults;
+
+ var tn = tokenize(source, options.alternateCommentMode || false),
+ next = tn.next,
+ push = tn.push,
+ peek = tn.peek,
+ skip = tn.skip,
+ cmnt = tn.cmnt;
+
+ var head = true,
+ pkg,
+ imports,
+ weakImports,
+ syntax,
+ isProto3 = false;
+
+ var ptr = root;
+
+ var applyCase = options.keepCase ? function(name) { return name; } : util.camelCase;
+
+ /* istanbul ignore next */
+ function illegal(token, name, insideTryCatch) {
+ var filename = parse.filename;
+ if (!insideTryCatch)
+ parse.filename = null;
+ return Error("illegal " + (name || "token") + " '" + token + "' (" + (filename ? filename + ", " : "") + "line " + tn.line + ")");
+ }
+
+ function readString() {
+ var values = [],
+ token;
+ do {
+ /* istanbul ignore if */
+ if ((token = next()) !== "\"" && token !== "'")
+ throw illegal(token);
+
+ values.push(next());
+ skip(token);
+ token = peek();
+ } while (token === "\"" || token === "'");
+ return values.join("");
+ }
+
+ function readValue(acceptTypeRef) {
+ var token = next();
+ switch (token) {
+ case "'":
+ case "\"":
+ push(token);
+ return readString();
+ case "true": case "TRUE":
+ return true;
+ case "false": case "FALSE":
+ return false;
+ }
+ try {
+ return parseNumber(token, /* insideTryCatch */ true);
+ } catch (e) {
+
+ /* istanbul ignore else */
+ if (acceptTypeRef && typeRefRe.test(token))
+ return token;
+
+ /* istanbul ignore next */
+ throw illegal(token, "value");
+ }
+ }
+
+ function readRanges(target, acceptStrings) {
+ var token, start;
+ do {
+ if (acceptStrings && ((token = peek()) === "\"" || token === "'"))
+ target.push(readString());
+ else
+ target.push([ start = parseId(next()), skip("to", true) ? parseId(next()) : start ]);
+ } while (skip(",", true));
+ skip(";");
+ }
+
+ function parseNumber(token, insideTryCatch) {
+ var sign = 1;
+ if (token.charAt(0) === "-") {
+ sign = -1;
+ token = token.substring(1);
+ }
+ switch (token) {
+ case "inf": case "INF": case "Inf":
+ return sign * Infinity;
+ case "nan": case "NAN": case "Nan": case "NaN":
+ return NaN;
+ case "0":
+ return 0;
+ }
+ if (base10Re.test(token))
+ return sign * parseInt(token, 10);
+ if (base16Re.test(token))
+ return sign * parseInt(token, 16);
+ if (base8Re.test(token))
+ return sign * parseInt(token, 8);
+
+ /* istanbul ignore else */
+ if (numberRe.test(token))
+ return sign * parseFloat(token);
+
+ /* istanbul ignore next */
+ throw illegal(token, "number", insideTryCatch);
+ }
+
+ function parseId(token, acceptNegative) {
+ switch (token) {
+ case "max": case "MAX": case "Max":
+ return 536870911;
+ case "0":
+ return 0;
+ }
+
+ /* istanbul ignore if */
+ if (!acceptNegative && token.charAt(0) === "-")
+ throw illegal(token, "id");
+
+ if (base10NegRe.test(token))
+ return parseInt(token, 10);
+ if (base16NegRe.test(token))
+ return parseInt(token, 16);
+
+ /* istanbul ignore else */
+ if (base8NegRe.test(token))
+ return parseInt(token, 8);
+
+ /* istanbul ignore next */
+ throw illegal(token, "id");
+ }
+
+ function parsePackage() {
+
+ /* istanbul ignore if */
+ if (pkg !== undefined)
+ throw illegal("package");
+
+ pkg = next();
+
+ /* istanbul ignore if */
+ if (!typeRefRe.test(pkg))
+ throw illegal(pkg, "name");
+
+ ptr = ptr.define(pkg);
+ skip(";");
+ }
+
+ function parseImport() {
+ var token = peek();
+ var whichImports;
+ switch (token) {
+ case "weak":
+ whichImports = weakImports || (weakImports = []);
+ next();
+ break;
+ case "public":
+ next();
+ // eslint-disable-line no-fallthrough
+ default:
+ whichImports = imports || (imports = []);
+ break;
+ }
+ token = readString();
+ skip(";");
+ whichImports.push(token);
+ }
+
+ function parseSyntax() {
+ skip("=");
+ syntax = readString();
+ isProto3 = syntax === "proto3";
+
+ /* istanbul ignore if */
+ if (!isProto3 && syntax !== "proto2")
+ throw illegal(syntax, "syntax");
+
+ skip(";");
+ }
+
+ function parseCommon(parent, token) {
+ switch (token) {
+
+ case "option":
+ parseOption(parent, token);
+ skip(";");
+ return true;
+
+ case "message":
+ parseType(parent, token);
+ return true;
+
+ case "enum":
+ parseEnum(parent, token);
+ return true;
+
+ case "service":
+ parseService(parent, token);
+ return true;
+
+ case "extend":
+ parseExtension(parent, token);
+ return true;
+ }
+ return false;
+ }
+
+ function ifBlock(obj, fnIf, fnElse) {
+ var trailingLine = tn.line;
+ if (obj) {
+ obj.comment = cmnt(); // try block-type comment
+ obj.filename = parse.filename;
+ }
+ if (skip("{", true)) {
+ var token;
+ while ((token = next()) !== "}")
+ fnIf(token);
+ skip(";", true);
+ } else {
+ if (fnElse)
+ fnElse();
+ skip(";");
+ if (obj && typeof obj.comment !== "string")
+ obj.comment = cmnt(trailingLine); // try line-type comment if no block
+ }
+ }
+
+ function parseType(parent, token) {
+
+ /* istanbul ignore if */
+ if (!nameRe.test(token = next()))
+ throw illegal(token, "type name");
+
+ var type = new Type(token);
+ ifBlock(type, function parseType_block(token) {
+ if (parseCommon(type, token))
+ return;
+
+ switch (token) {
+
+ case "map":
+ parseMapField(type, token);
+ break;
+
+ case "required":
+ case "optional":
+ case "repeated":
+ parseField(type, token);
+ break;
+
+ case "oneof":
+ parseOneOf(type, token);
+ break;
+
+ case "extensions":
+ readRanges(type.extensions || (type.extensions = []));
+ break;
+
+ case "reserved":
+ readRanges(type.reserved || (type.reserved = []), true);
+ break;
+
+ default:
+ /* istanbul ignore if */
+ if (!isProto3 || !typeRefRe.test(token))
+ throw illegal(token);
+
+ push(token);
+ parseField(type, "optional");
+ break;
+ }
+ });
+ parent.add(type);
+ }
+
+ function parseField(parent, rule, extend) {
+ var type = next();
+ if (type === "group") {
+ parseGroup(parent, rule);
+ return;
+ }
+
+ /* istanbul ignore if */
+ if (!typeRefRe.test(type))
+ throw illegal(type, "type");
+
+ var name = next();
+
+ /* istanbul ignore if */
+ if (!nameRe.test(name))
+ throw illegal(name, "name");
+
+ name = applyCase(name);
+ skip("=");
+
+ var field = new Field(name, parseId(next()), type, rule, extend);
+ ifBlock(field, function parseField_block(token) {
+
+ /* istanbul ignore else */
+ if (token === "option") {
+ parseOption(field, token);
+ skip(";");
+ } else
+ throw illegal(token);
+
+ }, function parseField_line() {
+ parseInlineOptions(field);
+ });
+ parent.add(field);
+
+ // JSON defaults to packed=true if not set so we have to set packed=false explicity when
+ // parsing proto2 descriptors without the option, where applicable. This must be done for
+ // all known packable types and anything that could be an enum (= is not a basic type).
+ if (!isProto3 && field.repeated && (types.packed[type] !== undefined || types.basic[type] === undefined))
+ field.setOption("packed", false, /* ifNotSet */ true);
+ }
+
+ function parseGroup(parent, rule) {
+ var name = next();
+
+ /* istanbul ignore if */
+ if (!nameRe.test(name))
+ throw illegal(name, "name");
+
+ var fieldName = util.lcFirst(name);
+ if (name === fieldName)
+ name = util.ucFirst(name);
+ skip("=");
+ var id = parseId(next());
+ var type = new Type(name);
+ type.group = true;
+ var field = new Field(fieldName, id, name, rule);
+ field.filename = parse.filename;
+ ifBlock(type, function parseGroup_block(token) {
+ switch (token) {
+
+ case "option":
+ parseOption(type, token);
+ skip(";");
+ break;
+
+ case "required":
+ case "optional":
+ case "repeated":
+ parseField(type, token);
+ break;
+
+ /* istanbul ignore next */
+ default:
+ throw illegal(token); // there are no groups with proto3 semantics
+ }
+ });
+ parent.add(type)
+ .add(field);
+ }
+
+ function parseMapField(parent) {
+ skip("<");
+ var keyType = next();
+
+ /* istanbul ignore if */
+ if (types.mapKey[keyType] === undefined)
+ throw illegal(keyType, "type");
+
+ skip(",");
+ var valueType = next();
+
+ /* istanbul ignore if */
+ if (!typeRefRe.test(valueType))
+ throw illegal(valueType, "type");
+
+ skip(">");
+ var name = next();
+
+ /* istanbul ignore if */
+ if (!nameRe.test(name))
+ throw illegal(name, "name");
+
+ skip("=");
+ var field = new MapField(applyCase(name), parseId(next()), keyType, valueType);
+ ifBlock(field, function parseMapField_block(token) {
+
+ /* istanbul ignore else */
+ if (token === "option") {
+ parseOption(field, token);
+ skip(";");
+ } else
+ throw illegal(token);
+
+ }, function parseMapField_line() {
+ parseInlineOptions(field);
+ });
+ parent.add(field);
+ }
+
+ function parseOneOf(parent, token) {
+
+ /* istanbul ignore if */
+ if (!nameRe.test(token = next()))
+ throw illegal(token, "name");
+
+ var oneof = new OneOf(applyCase(token));
+ ifBlock(oneof, function parseOneOf_block(token) {
+ if (token === "option") {
+ parseOption(oneof, token);
+ skip(";");
+ } else {
+ push(token);
+ parseField(oneof, "optional");
+ }
+ });
+ parent.add(oneof);
+ }
+
+ function parseEnum(parent, token) {
+
+ /* istanbul ignore if */
+ if (!nameRe.test(token = next()))
+ throw illegal(token, "name");
+
+ var enm = new Enum(token);
+ ifBlock(enm, function parseEnum_block(token) {
+ switch(token) {
+ case "option":
+ parseOption(enm, token);
+ skip(";");
+ break;
+
+ case "reserved":
+ readRanges(enm.reserved || (enm.reserved = []), true);
+ break;
+
+ default:
+ parseEnumValue(enm, token);
+ }
+ });
+ parent.add(enm);
+ }
+
+ function parseEnumValue(parent, token) {
+
+ /* istanbul ignore if */
+ if (!nameRe.test(token))
+ throw illegal(token, "name");
+
+ skip("=");
+ var value = parseId(next(), true),
+ dummy = {};
+ ifBlock(dummy, function parseEnumValue_block(token) {
+
+ /* istanbul ignore else */
+ if (token === "option") {
+ parseOption(dummy, token); // skip
+ skip(";");
+ } else
+ throw illegal(token);
+
+ }, function parseEnumValue_line() {
+ parseInlineOptions(dummy); // skip
+ });
+ parent.add(token, value, dummy.comment);
+ }
+
+ function parseOption(parent, token) {
+ var isCustom = skip("(", true);
+
+ /* istanbul ignore if */
+ if (!typeRefRe.test(token = next()))
+ throw illegal(token, "name");
+
+ var name = token;
+ if (isCustom) {
+ skip(")");
+ name = "(" + name + ")";
+ token = peek();
+ if (fqTypeRefRe.test(token)) {
+ name += token;
+ next();
+ }
+ }
+ skip("=");
+ parseOptionValue(parent, name);
+ }
+
+ function parseOptionValue(parent, name) {
+ if (skip("{", true)) { // { a: "foo" b { c: "bar" } }
+ do {
+ /* istanbul ignore if */
+ if (!nameRe.test(token = next()))
+ throw illegal(token, "name");
+
+ if (peek() === "{")
+ parseOptionValue(parent, name + "." + token);
+ else {
+ skip(":");
+ if (peek() === "{")
+ parseOptionValue(parent, name + "." + token);
+ else
+ setOption(parent, name + "." + token, readValue(true));
+ }
+ } while (!skip("}", true));
+ } else
+ setOption(parent, name, readValue(true));
+ // Does not enforce a delimiter to be universal
+ }
+
+ function setOption(parent, name, value) {
+ if (parent.setOption)
+ parent.setOption(name, value);
+ }
+
+ function parseInlineOptions(parent) {
+ if (skip("[", true)) {
+ do {
+ parseOption(parent, "option");
+ } while (skip(",", true));
+ skip("]");
+ }
+ return parent;
+ }
+
+ function parseService(parent, token) {
+
+ /* istanbul ignore if */
+ if (!nameRe.test(token = next()))
+ throw illegal(token, "service name");
+
+ var service = new Service(token);
+ ifBlock(service, function parseService_block(token) {
+ if (parseCommon(service, token))
+ return;
+
+ /* istanbul ignore else */
+ if (token === "rpc")
+ parseMethod(service, token);
+ else
+ throw illegal(token);
+ });
+ parent.add(service);
+ }
+
+ function parseMethod(parent, token) {
+ var type = token;
+
+ /* istanbul ignore if */
+ if (!nameRe.test(token = next()))
+ throw illegal(token, "name");
+
+ var name = token,
+ requestType, requestStream,
+ responseType, responseStream;
+
+ skip("(");
+ if (skip("stream", true))
+ requestStream = true;
+
+ /* istanbul ignore if */
+ if (!typeRefRe.test(token = next()))
+ throw illegal(token);
+
+ requestType = token;
+ skip(")"); skip("returns"); skip("(");
+ if (skip("stream", true))
+ responseStream = true;
+
+ /* istanbul ignore if */
+ if (!typeRefRe.test(token = next()))
+ throw illegal(token);
+
+ responseType = token;
+ skip(")");
+
+ var method = new Method(name, type, requestType, responseType, requestStream, responseStream);
+ ifBlock(method, function parseMethod_block(token) {
+
+ /* istanbul ignore else */
+ if (token === "option") {
+ parseOption(method, token);
+ skip(";");
+ } else
+ throw illegal(token);
+
+ });
+ parent.add(method);
+ }
+
+ function parseExtension(parent, token) {
+
+ /* istanbul ignore if */
+ if (!typeRefRe.test(token = next()))
+ throw illegal(token, "reference");
+
+ var reference = token;
+ ifBlock(null, function parseExtension_block(token) {
+ switch (token) {
+
+ case "required":
+ case "repeated":
+ case "optional":
+ parseField(parent, token, reference);
+ break;
+
+ default:
+ /* istanbul ignore if */
+ if (!isProto3 || !typeRefRe.test(token))
+ throw illegal(token);
+ push(token);
+ parseField(parent, "optional", reference);
+ break;
+ }
+ });
+ }
+
+ var token;
+ while ((token = next()) !== null) {
+ switch (token) {
+
+ case "package":
+
+ /* istanbul ignore if */
+ if (!head)
+ throw illegal(token);
+
+ parsePackage();
+ break;
+
+ case "import":
+
+ /* istanbul ignore if */
+ if (!head)
+ throw illegal(token);
+
+ parseImport();
+ break;
+
+ case "syntax":
+
+ /* istanbul ignore if */
+ if (!head)
+ throw illegal(token);
+
+ parseSyntax();
+ break;
+
+ case "option":
+
+ /* istanbul ignore if */
+ if (!head)
+ throw illegal(token);
+
+ parseOption(ptr, token);
+ skip(";");
+ break;
+
+ default:
+
+ /* istanbul ignore else */
+ if (parseCommon(ptr, token)) {
+ head = false;
+ continue;
+ }
+
+ /* istanbul ignore next */
+ throw illegal(token);
+ }
+ }
+
+ parse.filename = null;
+ return {
+ "package" : pkg,
+ "imports" : imports,
+ weakImports : weakImports,
+ syntax : syntax,
+ root : root
+ };
+}
+
+/**
+ * Parses the given .proto source and returns an object with the parsed contents.
+ * @name parse
+ * @function
+ * @param {string} source Source contents
+ * @param {IParseOptions} [options] Parse options. Defaults to {@link parse.defaults} when omitted.
+ * @returns {IParserResult} Parser result
+ * @property {string} filename=null Currently processing file name for error reporting, if known
+ * @property {IParseOptions} defaults Default {@link IParseOptions}
+ * @variation 2
+ */
+parse._configure = function (){
+ tokenize = require("./tokenize"),
+ Root = require("./root"),
+ Type = require("./type"),
+ Field = require("./field"),
+ MapField = require("./mapField"),
+ OneOf = require("./oneof"),
+ Enum = require("./enum"),
+ Service = require("./service"),
+ Method = require("./method"),
+ types = require("./types"),
+ util = require("./util");
+}
\ No newline at end of file
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/path.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/path.js
new file mode 100644
index 0000000..9864a0e
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/path.js
@@ -0,0 +1,58 @@
+var path = module.exports;
+
+var isAbsolute =
+/**
+ * Tests if the specified path is absolute.
+ * @param {string} path Path to test
+ * @returns {boolean} `true` if path is absolute
+ */
+ path.isAbsolute = function isAbsolute(path) {
+ return /^(?:\/|\w+:)/.test(path);
+ };
+
+var normalize =
+/**
+ * Normalizes the specified path.
+ * @param {string} path Path to normalize
+ * @returns {string} Normalized path
+ */
+ path.normalize = function normalize(path) {
+ path = path.replace(/\\/g, "/")
+ .replace(/\/{2,}/g, "/");
+ var parts = path.split("/"),
+ absolute = isAbsolute(path),
+ prefix = "";
+ if (absolute)
+ prefix = parts.shift() + "/";
+ for (var i = 0; i < parts.length;) {
+ if (parts[i] === "..") {
+ if (i > 0 && parts[i - 1] !== "..")
+ parts.splice(--i, 2);
+ else if (absolute)
+ parts.splice(i, 1);
+ else
+ ++i;
+ } else if (parts[i] === ".")
+ parts.splice(i, 1);
+ else
+ ++i;
+ }
+ return prefix + parts.join("/");
+ };
+
+/**
+ * Resolves the specified include path against the specified origin path.
+ * @param {string} originPath Path to the origin file
+ * @param {string} includePath Include path relative to origin path
+ * @param {boolean} [alreadyNormalized=false] `true` if both paths are already known to be normalized
+ * @returns {string} Path to the include file
+ */
+path.resolve = function resolve(originPath, includePath, alreadyNormalized) {
+ if (!alreadyNormalized)
+ includePath = normalize(includePath);
+ if (isAbsolute(includePath))
+ return includePath;
+ if (!alreadyNormalized)
+ originPath = normalize(originPath);
+ return (originPath = originPath.replace(/(?:\/|^)[^/]+$/, "")).length ? normalize(originPath + "/" + includePath) : includePath;
+};
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/pool.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/pool.js
new file mode 100644
index 0000000..f916827
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/pool.js
@@ -0,0 +1,47 @@
+module.exports = pool;
+
+/**
+ * An allocator as used by {@link util.pool}.
+ * @typedef PoolAllocator
+ * @type {function}
+ * @param {number} size Buffer size
+ * @returns {Uint8Array} Buffer
+ */
+
+/**
+ * A slicer as used by {@link util.pool}.
+ * @typedef PoolSlicer
+ * @type {function}
+ * @param {number} start Start offset
+ * @param {number} end End offset
+ * @returns {Uint8Array} Buffer slice
+ * @this {Uint8Array}
+ */
+
+/**
+ * A general purpose buffer pool.
+ * @memberof util
+ * @function
+ * @param {PoolAllocator} alloc Allocator
+ * @param {PoolSlicer} slice Slicer
+ * @param {number} [size=8192] Slab size
+ * @returns {PoolAllocator} Pooled allocator
+ */
+function pool(alloc, slice, size) {
+ var SIZE = size || 8192;
+ var MAX = SIZE >>> 1;
+ var slab = null;
+ var offset = SIZE;
+ return function pool_alloc(size) {
+ if (size < 1 || size > MAX)
+ return alloc(size);
+ if (offset + size > SIZE) {
+ slab = alloc(SIZE);
+ offset = 0;
+ }
+ var buf = slice.call(slab, offset, offset += size);
+ if (offset & 7) // align to 32 bit
+ offset = (offset | 7) + 1;
+ return buf;
+ };
+}
\ No newline at end of file
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/reader.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/reader.js
new file mode 100644
index 0000000..6dd93b8
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/reader.js
@@ -0,0 +1,314 @@
+/**
+ * Created by zhangmiao on 2018/3/13.
+ */
+
+module.exports = Reader;
+
+var util = require('./util');
+
+var LongBits;
+var utf8;
+
+var BufferReader;
+
+function indexOutOfRange(reader, writeLength) {
+ return RangeError("index out of range: " + reader.pos + " + " + (writeLength || 1) + " > " + reader.len);
+}
+
+
+function Reader(buffer) {
+
+ /**
+ * Read buffer.
+ * @type {Uint8Array}
+ */
+ this.buf = buffer;
+
+ /**
+ * Read buffer position.
+ * @type {number}
+ */
+ this.pos = 0;
+
+ /**
+ * Read buffer length.
+ * @type {number}
+ */
+ this.len = buffer.length;
+}
+
+var create_array = typeof Uint8Array !== "undefined"
+ ? function create_typed_array(buffer) {
+ if (buffer instanceof Uint8Array || Array.isArray(buffer))
+ return new Reader(buffer);
+ if (typeof ArrayBuffer !== "undefined" && buffer instanceof ArrayBuffer) //增加ArrayBuffer构建
+ return new Reader(new Uint8Array(buffer));
+ throw Error("illegal buffer");
+}
+ /* istanbul ignore next */
+ : function create_array(buffer) {
+ if (Array.isArray(buffer))
+ return new Reader(buffer);
+ throw Error("illegal buffer");
+};
+
+Reader.create = util.Buffer
+ ? function create_buffer_setup(buffer) {
+ return (Reader.create = function create_buffer(buffer) {
+ return util.Buffer.isBuffer(buffer)
+ ? new BufferReader(buffer)
+ /* istanbul ignore next */
+ : create_array(buffer);
+ })(buffer);
+}
+ /* istanbul ignore next */
+ : create_array;
+
+Reader.prototype._slice = util.Array.prototype.subarray || /* istanbul ignore next */ util.Array.prototype.slice;
+
+
+Reader.prototype.uint32 = (function read_uint32_setup() {
+ var value = 4294967295; // optimizer type-hint, tends to deopt otherwise (?!)
+ return function read_uint32() {
+ value = ( this.buf[this.pos] & 127 ) >>> 0; if (this.buf[this.pos++] < 128) return value;
+ value = (value | (this.buf[this.pos] & 127) << 7) >>> 0; if (this.buf[this.pos++] < 128) return value;
+ value = (value | (this.buf[this.pos] & 127) << 14) >>> 0; if (this.buf[this.pos++] < 128) return value;
+ value = (value | (this.buf[this.pos] & 127) << 21) >>> 0; if (this.buf[this.pos++] < 128) return value;
+ value = (value | (this.buf[this.pos] & 15) << 28) >>> 0; if (this.buf[this.pos++] < 128) return value;
+
+ /* istanbul ignore if */
+ if ((this.pos += 5) > this.len) {
+ this.pos = this.len;
+ throw indexOutOfRange(this, 10);
+ }
+ return value;
+ };
+})();
+
+Reader.prototype.int32 = function read_int32() {
+ return this.uint32() | 0;
+};
+
+Reader.prototype.sint32 = function read_sint32() {
+ var value = this.uint32();
+ return value >>> 1 ^ -(value & 1) | 0;
+};
+
+function readLongVarint() {
+ // tends to deopt with local vars for octet etc.
+ var bits = new LongBits(0, 0);
+ var i = 0;
+ if (this.len - this.pos > 4) { // fast route (lo)
+ for (; i < 4; ++i) {
+ // 1st..4th
+ bits.lo = (bits.lo | (this.buf[this.pos] & 127) << i * 7) >>> 0;
+ if (this.buf[this.pos++] < 128)
+ return bits;
+ }
+ // 5th
+ bits.lo = (bits.lo | (this.buf[this.pos] & 127) << 28) >>> 0;
+ bits.hi = (bits.hi | (this.buf[this.pos] & 127) >> 4) >>> 0;
+ if (this.buf[this.pos++] < 128)
+ return bits;
+ i = 0;
+ } else {
+ for (; i < 3; ++i) {
+ /* istanbul ignore if */
+ if (this.pos >= this.len)
+ throw indexOutOfRange(this);
+ // 1st..3th
+ bits.lo = (bits.lo | (this.buf[this.pos] & 127) << i * 7) >>> 0;
+ if (this.buf[this.pos++] < 128)
+ return bits;
+ }
+ // 4th
+ bits.lo = (bits.lo | (this.buf[this.pos++] & 127) << i * 7) >>> 0;
+ return bits;
+ }
+ if (this.len - this.pos > 4) { // fast route (hi)
+ for (; i < 5; ++i) {
+ // 6th..10th
+ bits.hi = (bits.hi | (this.buf[this.pos] & 127) << i * 7 + 3) >>> 0;
+ if (this.buf[this.pos++] < 128)
+ return bits;
+ }
+ } else {
+ for (; i < 5; ++i) {
+ /* istanbul ignore if */
+ if (this.pos >= this.len)
+ throw indexOutOfRange(this);
+ // 6th..10th
+ bits.hi = (bits.hi | (this.buf[this.pos] & 127) << i * 7 + 3) >>> 0;
+ if (this.buf[this.pos++] < 128)
+ return bits;
+ }
+ }
+ /* istanbul ignore next */
+ throw Error("invalid varint encoding");
+}
+
+Reader.prototype.bool = function read_bool() {
+ return this.uint32() !== 0;
+};
+
+
+function readFixed32_end(buf, end) { // note that this uses `end`, not `pos`
+ return (buf[end - 4]
+ | buf[end - 3] << 8
+ | buf[end - 2] << 16
+ | buf[end - 1] << 24) >>> 0;
+}
+
+Reader.prototype.fixed32 = function read_fixed32() {
+
+ /* istanbul ignore if */
+ if (this.pos + 4 > this.len)
+ throw indexOutOfRange(this, 4);
+
+ return readFixed32_end(this.buf, this.pos += 4);
+};
+
+Reader.prototype.sfixed32 = function read_sfixed32() {
+
+ /* istanbul ignore if */
+ if (this.pos + 4 > this.len)
+ throw indexOutOfRange(this, 4);
+
+ return readFixed32_end(this.buf, this.pos += 4) | 0;
+};
+
+/* eslint-disable no-invalid-this */
+
+function readFixed64(/* this: Reader */) {
+
+ /* istanbul ignore if */
+ if (this.pos + 8 > this.len)
+ throw indexOutOfRange(this, 8);
+
+ return new LongBits(readFixed32_end(this.buf, this.pos += 4), readFixed32_end(this.buf, this.pos += 4));
+}
+
+
+Reader.prototype.float = function read_float() {
+
+ /* istanbul ignore if */
+ if (this.pos + 4 > this.len)
+ throw indexOutOfRange(this, 4);
+
+ var value = util.float.readFloatLE(this.buf, this.pos);
+ this.pos += 4;
+ return value;
+};
+
+Reader.prototype.double = function read_double() {
+
+ /* istanbul ignore if */
+ if (this.pos + 8 > this.len)
+ throw indexOutOfRange(this, 4);
+
+ var value = util.float.readDoubleLE(this.buf, this.pos);
+ this.pos += 8;
+ return value;
+};
+
+Reader.prototype.bytes = function read_bytes() {
+ var length = this.uint32(),
+ start = this.pos,
+ end = this.pos + length;
+
+ /* istanbul ignore if */
+ if (end > this.len)
+ throw indexOutOfRange(this, length);
+ this.pos += length;
+ if (Array.isArray(this.buf)) // plain array
+ return this.buf.slice(start, end);
+ return start === end // fix for IE 10/Win8 and others' subarray returning array of size 1
+ ? new this.buf.constructor(0)
+ : this._slice.call(this.buf, start, end);
+};
+
+Reader.prototype.string = function read_string() {
+ var bytes = this.bytes();
+ return utf8.read(bytes, 0, bytes.length);
+};
+
+Reader.prototype.skip = function skip(length) {
+ if (typeof length === "number") {
+ /* istanbul ignore if */
+ if (this.pos + length > this.len)
+ throw indexOutOfRange(this, length);
+ this.pos += length;
+ } else {
+ do {
+ /* istanbul ignore if */
+ if (this.pos >= this.len)
+ throw indexOutOfRange(this);
+ } while (this.buf[this.pos++] & 128);
+ }
+ return this;
+};
+
+Reader.prototype.skipType = function(wireType) {
+ switch (wireType) {
+ case 0:
+ this.skip();
+ break;
+ case 1:
+ this.skip(8);
+ break;
+ case 2:
+ this.skip(this.uint32());
+ break;
+ case 3:
+ do { // eslint-disable-line no-constant-condition
+ if ((wireType = this.uint32() & 7) === 4)
+ break;
+ this.skipType(wireType);
+ } while (true);
+ break;
+ case 5:
+ this.skip(4);
+ break;
+
+ /* istanbul ignore next */
+ default:
+ throw Error("invalid wire type " + wireType + " at offset " + this.pos);
+ }
+ return this;
+};
+
+
+
+//这部分可能用不到
+Reader._configure = function() {
+
+ //util = require('./util');
+ LongBits = require("./longBits");
+ utf8 = require("./utf8");
+
+ var fn = util.Long ? "toLong" : /* istanbul ignore next */ "toNumber";
+ util.merge(Reader.prototype, {
+
+ int64: function read_int64() {
+ return readLongVarint.call(this)[fn](false);
+ },
+
+ uint64: function read_uint64() {
+ return readLongVarint.call(this)[fn](true);
+ },
+
+ sint64: function read_sint64() {
+ return readLongVarint.call(this).zzDecode()[fn](false);
+ },
+
+ fixed64: function read_fixed64() {
+ return readFixed64.call(this)[fn](true);
+ },
+
+ sfixed64: function read_sfixed64() {
+ return readFixed64.call(this)[fn](false);
+ }
+
+ });
+};
+
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/reader_buffer.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/reader_buffer.js
new file mode 100644
index 0000000..9518901
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/reader_buffer.js
@@ -0,0 +1,44 @@
+"use strict";
+module.exports = BufferReader;
+
+// extends Reader
+var Reader = require("./reader");
+(BufferReader.prototype = Object.create(Reader.prototype)).constructor = BufferReader;
+
+var util = require("./util/minimal");
+
+/**
+ * Constructs a new buffer reader instance.
+ * @classdesc Wire format reader using node buffers.
+ * @extends Reader
+ * @constructor
+ * @param {Buffer} buffer Buffer to read from
+ */
+function BufferReader(buffer) {
+ Reader.call(this, buffer);
+
+ /**
+ * Read buffer.
+ * @name BufferReader#buf
+ * @type {Buffer}
+ */
+}
+
+/* istanbul ignore else */
+if (util.Buffer)
+ BufferReader.prototype._slice = util.Buffer.prototype.slice;
+
+/**
+ * @override
+ */
+BufferReader.prototype.string = function read_string_buffer() {
+ var len = this.uint32(); // modifies pos
+ return this.buf.utf8Slice(this.pos, this.pos = Math.min(this.pos + len, this.len));
+};
+
+/**
+ * Reads a sequence of bytes preceeded by its length as a varint.
+ * @name BufferReader#bytes
+ * @function
+ * @returns {Buffer} Value read
+ */
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/root.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/root.js
new file mode 100644
index 0000000..ecf69d4
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/root.js
@@ -0,0 +1,439 @@
+module.exports = Root;
+
+// extends Namespace
+var Namespace = require("./namespace");
+((Root.prototype = Object.create(Namespace.prototype)).constructor = Root).className = "Root";
+
+var Field = require("./field"),
+ Enum = require("./enum"),
+ OneOf = require("./oneof"),
+ util = require("./util");
+
+var Type, // cyclic
+ parse, // might be excluded
+ common; // "
+
+/**
+ * Constructs a new root namespace instance.
+ * @classdesc Root namespace wrapping all types, enums, services, sub-namespaces etc. that belong together.
+ * @extends NamespaceBase
+ * @constructor
+ * @param {Object.} [options] Top level options
+ */
+function Root(options) {
+ Namespace.call(this, "", options);
+
+ /**
+ * Deferred extension fields.
+ * @type {Field[]}
+ */
+ this.deferred = [];
+
+ /**
+ * Resolved file names of loaded files.
+ * @type {string[]}
+ */
+ this.files = [];
+
+ /**
+ * Resolved name of parsered pbString.
+ * @type {string[]}
+ */
+ this.names = [];
+}
+
+/**
+ * Loads a namespace descriptor into a root namespace.
+ * @param {INamespace} json Nameespace descriptor
+ * @param {Root} [root] Root namespace, defaults to create a new one if omitted
+ * @returns {Root} Root namespace
+ */
+Root.fromJSON = function fromJSON(json, root) {
+ json = typeof json === 'string' ? JSON.parse(json) : json;
+ if (!root)
+ root = new Root();
+ if (json.options)
+ root.setOptions(json.options);
+ return root.addJSON(json.nested);
+};
+
+/**
+ * Resolves the path of an imported file, relative to the importing origin.
+ * This method exists so you can override it with your own logic in case your imports are scattered over multiple directories.
+ * @function
+ * @param {string} origin The file name of the importing file
+ * @param {string} target The file name being imported
+ * @returns {string|null} Resolved path to `target` or `null` to skip the file
+ */
+Root.prototype.resolvePath = util.path.resolve;
+
+// A symbol-like function to safely signal synchronous loading
+/* istanbul ignore next */
+function SYNC() {} // eslint-disable-line no-empty-function
+
+function parseFromPbString(pbString, options, callback){
+
+ if (typeof options === "function") {
+ callback = options;
+ options = undefined;
+ }
+ var self = this;
+ if (!callback){
+ return util.asPromise(parseFromPbString, self, pbString, options);
+ }
+
+ var pbObj = null;
+ if(typeof pbString === 'string'){
+ pbObj = JSON.parse(pbString);
+ }else if(typeof pbString === 'object'){
+ pbObj = pbString;
+ }else {
+ //throw Error("pb格式转化失败");
+ console.log("pb格式转化失败");
+ return undefined;
+ }
+
+ var name = pbObj['name'];
+ var pbJsonStr = pbObj['pbJsonStr'];
+
+ function finish(err, root){
+ if(!callback)
+ return;
+ var cb = callback;
+ callback = null;
+ cb(err, root);
+ }
+
+ function process(name, source){
+ try {
+ if (util.isString(source) && source.charAt(0) === "{")
+ source = JSON.parse(source);
+ if (!util.isString(source))
+ self.setOptions(source.options).addJSON(source.nested);
+ else {
+ parse.filename = name;
+ var parsed = parse(source, self, options),
+ resolved;
+ var i = 0;
+ if(parsed.imports){
+ for (; i < parsed.imports.length; ++i){
+ resolved = parsed.imports[i];
+ fetch(resolved);
+ }
+ }
+ if (parsed.weakImports){
+ for (i = 0; i < parsed.weakImports.length; ++i)
+ resolved = parsed.weakImports[i];
+ fetch(resolved, true);
+ }
+ }
+ } catch (err) {
+ finish(err);
+ }
+
+ finish(null, self); // only once anyway
+ }
+
+ function fetch(name){
+ if(self.names.indexOf(name)>-1)
+ return;
+ self.names.push(name);
+ if (name in common){
+ process(name, common[name]);
+ }
+ }
+
+ process(name, pbJsonStr);
+ return undefined;
+}
+
+Root.prototype.parseFromPbString = parseFromPbString;
+
+/**
+ * Loads one or multiple .proto or preprocessed .json files into this root namespace and calls the callback.
+ * @param {string|string[]} filename Names of one or multiple files to load
+ * @param {IParseOptions} options Parse options
+ * @param {LoadCallback} callback Callback function
+ * @returns {undefined}
+ */
+Root.prototype.load = function load(filename, options, callback) {
+ if (typeof options === "function") {
+ callback = options;
+ options = undefined;
+ }
+ var self = this;
+ if (!callback)
+ return util.asPromise(load, self, filename, options);
+
+ var sync = callback === SYNC; // undocumented
+
+ // Finishes loading by calling the callback (exactly once)
+ function finish(err, root) {
+ /* istanbul ignore if */
+ if (!callback)
+ return;
+ var cb = callback;
+ callback = null;
+ if (sync)
+ throw err;
+ cb(err, root);
+ }
+
+ // Processes a single file
+ function process(filename, source) {
+ try {
+ if (util.isString(source) && source.charAt(0) === "{")
+ source = JSON.parse(source);
+ if (!util.isString(source))
+ self.setOptions(source.options).addJSON(source.nested);
+ else {
+ parse.filename = filename;
+ var parsed = parse(source, self, options),
+ resolved,
+ i = 0;
+ if (parsed.imports)
+ for (; i < parsed.imports.length; ++i)
+ if (resolved = self.resolvePath(filename, parsed.imports[i]))
+ fetch(resolved);
+ if (parsed.weakImports)
+ for (i = 0; i < parsed.weakImports.length; ++i)
+ if (resolved = self.resolvePath(filename, parsed.weakImports[i]))
+ fetch(resolved, true);
+ }
+ } catch (err) {
+ finish(err);
+ }
+ if (!sync && !queued)
+ finish(null, self); // only once anyway
+ }
+
+ // Fetches a single file
+ function fetch(filename, weak) {
+
+ // Strip path if this file references a bundled definition
+ var idx = filename.lastIndexOf("google/protobuf/");
+ if (idx > -1) {
+ var altname = filename.substring(idx);
+ if (altname in common)
+ filename = altname;
+ }
+
+ // Skip if already loaded / attempted
+ if (self.files.indexOf(filename) > -1)
+ return;
+ self.files.push(filename);
+
+ // Shortcut bundled definitions
+ if (filename in common) {
+ if (sync)
+ process(filename, common[filename]);
+ else {
+ ++queued;
+ setTimeout(function() {
+ --queued;
+ process(filename, common[filename]);
+ });
+ }
+ return;
+ }
+
+ // Otherwise fetch from disk or network
+ if (sync) {
+ var source;
+ try {
+ source = util.fs.readFileSync(filename).toString("utf8");
+ } catch (err) {
+ if (!weak)
+ finish(err);
+ return;
+ }
+ process(filename, source);
+ } else {
+ ++queued;
+ util.fetch(filename, function(err, source) {
+ --queued;
+ /* istanbul ignore if */
+ if (!callback)
+ return; // terminated meanwhile
+ if (err) {
+ /* istanbul ignore else */
+ if (!weak)
+ finish(err);
+ else if (!queued) // can't be covered reliably
+ finish(null, self);
+ return;
+ }
+ process(filename, source);
+ });
+ }
+ }
+ var queued = 0;
+
+ // Assembling the root namespace doesn't require working type
+ // references anymore, so we can load everything in parallel
+ if (util.isString(filename))
+ filename = [ filename ];
+ for (var i = 0, resolved; i < filename.length; ++i)
+ if (resolved = self.resolvePath("", filename[i]))
+ fetch(resolved);
+
+ if (sync)
+ return self;
+ if (!queued)
+ finish(null, self);
+ return undefined;
+};
+// function load(filename:string, options:IParseOptions, callback:LoadCallback):undefined
+
+/**
+ * Loads one or multiple .proto or preprocessed .json files into this root namespace and calls the callback.
+ * @function Root#load
+ * @param {string|string[]} filename Names of one or multiple files to load
+ * @param {LoadCallback} callback Callback function
+ * @returns {undefined}
+ * @variation 2
+ */
+// function load(filename:string, callback:LoadCallback):undefined
+
+/**
+ * Loads one or multiple .proto or preprocessed .json files into this root namespace and returns a promise.
+ * @function Root#load
+ * @param {string|string[]} filename Names of one or multiple files to load
+ * @param {IParseOptions} [options] Parse options. Defaults to {@link parse.defaults} when omitted.
+ * @returns {Promise} Promise
+ * @variation 3
+ */
+// function load(filename:string, [options:IParseOptions]):Promise
+
+/**
+ * Synchronously loads one or multiple .proto or preprocessed .json files into this root namespace (node only).
+ * @function Root#loadSync
+ * @param {string|string[]} filename Names of one or multiple files to load
+ * @param {IParseOptions} [options] Parse options. Defaults to {@link parse.defaults} when omitted.
+ * @returns {Root} Root namespace
+ * @throws {Error} If synchronous fetching is not supported (i.e. in browsers) or if a file's syntax is invalid
+ */
+Root.prototype.loadSync = function loadSync(filename, options) {
+ if (!util.isNode)
+ throw Error("not supported");
+ return this.load(filename, options, SYNC);
+};
+
+/**
+ * @override
+ */
+Root.prototype.resolveAll = function resolveAll() {
+ if (this.deferred.length)
+ throw Error("unresolvable extensions: " + this.deferred.map(function(field) {
+ return "'extend " + field.extend + "' in " + field.parent.fullName;
+ }).join(", "));
+ return Namespace.prototype.resolveAll.call(this);
+};
+
+// only uppercased (and thus conflict-free) children are exposed, see below
+var exposeRe = /^[A-Z]/;
+
+/**
+ * Handles a deferred declaring extension field by creating a sister field to represent it within its extended type.
+ * @param {Root} root Root instance
+ * @param {Field} field Declaring extension field witin the declaring type
+ * @returns {boolean} `true` if successfully added to the extended type, `false` otherwise
+ * @inner
+ * @ignore
+ */
+function tryHandleExtension(root, field) {
+ var extendedType = field.parent.lookup(field.extend);
+ if (extendedType) {
+ var sisterField = new Field(field.fullName, field.id, field.type, field.rule, undefined, field.options);
+ sisterField.declaringField = field;
+ field.extensionField = sisterField;
+ extendedType.add(sisterField);
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Called when any object is added to this root or its sub-namespaces.
+ * @param {ReflectionObject} object Object added
+ * @returns {undefined}
+ * @private
+ */
+Root.prototype._handleAdd = function _handleAdd(object) {
+ if (object instanceof Field) {
+
+ if (/* an extension field (implies not part of a oneof) */ object.extend !== undefined && /* not already handled */ !object.extensionField)
+ if (!tryHandleExtension(this, object))
+ this.deferred.push(object);
+
+ } else if (object instanceof Enum) {
+
+ if (exposeRe.test(object.name))
+ object.parent[object.name] = object.values; // expose enum values as property of its parent
+
+ } else if (!(object instanceof OneOf)) /* everything else is a namespace */ {
+
+ if (object instanceof Type) // Try to handle any deferred extensions
+ for (var i = 0; i < this.deferred.length;)
+ if (tryHandleExtension(this, this.deferred[i]))
+ this.deferred.splice(i, 1);
+ else
+ ++i;
+ for (var j = 0; j < /* initializes */ object.nestedArray.length; ++j) // recurse into the namespace
+ this._handleAdd(object._nestedArray[j]);
+ if (exposeRe.test(object.name))
+ object.parent[object.name] = object; // expose namespace as property of its parent
+ }
+
+ // The above also adds uppercased (and thus conflict-free) nested types, services and enums as
+ // properties of namespaces just like static code does. This allows using a .d.ts generated for
+ // a static module with reflection-based solutions where the condition is met.
+};
+
+/**
+ * Called when any object is removed from this root or its sub-namespaces.
+ * @param {ReflectionObject} object Object removed
+ * @returns {undefined}
+ * @private
+ */
+Root.prototype._handleRemove = function _handleRemove(object) {
+ if (object instanceof Field) {
+
+ if (/* an extension field */ object.extend !== undefined) {
+ if (/* already handled */ object.extensionField) { // remove its sister field
+ object.extensionField.parent.remove(object.extensionField);
+ object.extensionField = null;
+ } else { // cancel the extension
+ var index = this.deferred.indexOf(object);
+ /* istanbul ignore else */
+ if (index > -1)
+ this.deferred.splice(index, 1);
+ }
+ }
+
+ } else if (object instanceof Enum) {
+
+ if (exposeRe.test(object.name))
+ delete object.parent[object.name]; // unexpose enum values
+
+ } else if (object instanceof Namespace) {
+
+ for (var i = 0; i < /* initializes */ object.nestedArray.length; ++i) // recurse into the namespace
+ this._handleRemove(object._nestedArray[i]);
+
+ if (exposeRe.test(object.name))
+ delete object.parent[object.name]; // unexpose namespaces
+
+ }
+};
+
+Root._configure = function() {
+ Type = require('./type');
+ parse = require('./parse');
+ common = require('./common');
+
+ Field = require("./field");
+ Enum = require("./enum");
+ OneOf = require("./oneof");
+ util = require("./util");
+};
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/roots.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/roots.js
new file mode 100644
index 0000000..70ad660
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/roots.js
@@ -0,0 +1,6 @@
+/**
+ * Created by zhangmiao on 2018/3/13.
+ */
+
+
+module.exports = {};
\ No newline at end of file
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/rpc.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/rpc.js
new file mode 100644
index 0000000..894e5c7
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/rpc.js
@@ -0,0 +1,36 @@
+"use strict";
+
+/**
+ * Streaming RPC helpers.
+ * @namespace
+ */
+var rpc = exports;
+
+/**
+ * RPC implementation passed to {@link Service#create} performing a service request on network level, i.e. by utilizing http requests or websockets.
+ * @typedef RPCImpl
+ * @type {function}
+ * @param {Method|rpc.ServiceMethod,Message<{}>>} method Reflected or static method being called
+ * @param {Uint8Array} requestData Request data
+ * @param {RPCImplCallback} callback Callback function
+ * @returns {undefined}
+ * @example
+ * function rpcImpl(method, requestData, callback) {
+ * if (protobuf.util.lcFirst(method.name) !== "myMethod") // compatible with static code
+ * throw Error("no such method");
+ * asynchronouslyObtainAResponse(requestData, function(err, responseData) {
+ * callback(err, responseData);
+ * });
+ * }
+ */
+
+/**
+ * Node-style callback as used by {@link RPCImpl}.
+ * @typedef RPCImplCallback
+ * @type {function}
+ * @param {Error|null} error Error, if any, otherwise `null`
+ * @param {Uint8Array|null} [response] Response data or `null` to signal end of stream, if there hasn't been an error
+ * @returns {undefined}
+ */
+
+rpc.Service = require("./rpc/service");
diff --git a/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/rpc/service.js b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/rpc/service.js
new file mode 100644
index 0000000..b0c8243
--- /dev/null
+++ b/uni_modules/c-svga/node_modules/svgaplayer-weapp/protobuf_mp/src/rpc/service.js
@@ -0,0 +1,141 @@
+"use strict";
+module.exports = Service;
+var util = require("../util");
+
+// Extends EventEmitter
+(Service.prototype = Object.create(util.EventEmitter.prototype)).constructor = Service;
+
+/**
+ * A service method callback as used by {@link rpc.ServiceMethod|ServiceMethod}.
+ *
+ * Differs from {@link RPCImplCallback} in that it is an actual callback of a service method which may not return `response = null`.
+ * @typedef rpc.ServiceMethodCallback
+ * @template TRes extends Message