commit e1ad1d4ebe93e23c919b51756d72497c3238ca81
Author: yuanlei <18627959669@163.com>
Date: Fri Mar 28 10:37:56 2025 +0800
初始化
diff --git a/.env.development b/.env.development
new file mode 100644
index 0000000..470abb6
--- /dev/null
+++ b/.env.development
@@ -0,0 +1,16 @@
+# 页面标题
+VITE_APP_TITLE = IM示例工程
+
+# 开发环境配置
+VITE_APP_ENV = 'development'
+
+# 基础地址
+VITE_APP_BASE_URL = 'http://localhost:18081'
+# VITE_APP_BASE_URL = 'https://api.ninecloud.top/msm'
+
+# socket地址
+# VITE_APP_SOCKET_URL = 'ws://localhost:9326'
+VITE_APP_SOCKET_URL = 'wss://api.ninecloud.top/socket/'
+
+# 网站地址
+VITE_APP_WEB_URL = 'https://www.ninecloud.top/udemo/im/index.html'
diff --git a/.env.production b/.env.production
new file mode 100644
index 0000000..36b8984
--- /dev/null
+++ b/.env.production
@@ -0,0 +1,14 @@
+# 页面标题
+VITE_APP_TITLE = 九云商城
+
+# 生产环境配置
+VITE_APP_ENV = 'production'
+
+# 基础地址
+VITE_APP_BASE_URL = 'https://api.ninecloud.top/msm'
+
+# socket地址
+VITE_APP_SOCKET_URL = 'wss://api.ninecloud.top/socket/'
+
+# 网站地址
+VITE_APP_WEB_URL = 'https://www.ninecloud.top/udemo/im/index.html'
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..89bc518
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/.hbuilderx
+/unpackage
\ No newline at end of file
diff --git a/App.vue b/App.vue
new file mode 100644
index 0000000..9740e25
--- /dev/null
+++ b/App.vue
@@ -0,0 +1,104 @@
+
+
+
diff --git a/api/chat.js b/api/chat.js
new file mode 100644
index 0000000..5320148
--- /dev/null
+++ b/api/chat.js
@@ -0,0 +1,35 @@
+import request from "@/utils/request"
+
+// 查询用户所有好友
+export function getUserAllFriend() {
+ return request({
+ url: "/im/friend/getUserAllFriend",
+ method: "get"
+ })
+}
+
+// 查询用户所有群
+export function getUserAllGroup() {
+ return request({
+ url: "/im/group/getUserAllGroup",
+ method: "get"
+ })
+}
+
+// 查询组用户
+export function getGroupUser(id) {
+ return request({
+ url: "/im/groupUser/getGroupUser/"+ id + "?r=" + Math.random(),
+ method: "get"
+ })
+}
+
+
+// 通过唯一会话key获取消息
+export function getMessageByChatKey(data) {
+ return request({
+ url: "/im/message/getMessageByChatKey",
+ method: "post",
+ data: data
+ })
+}
diff --git a/api/login.js b/api/login.js
new file mode 100644
index 0000000..64440cd
--- /dev/null
+++ b/api/login.js
@@ -0,0 +1,62 @@
+import request from '@/utils/request'
+
+// 登录方法
+export function login(type, username, password, smsCode, registerFlag, code, uuid) {
+ const data = {
+ type,
+ username,
+ password,
+ smsCode,
+ registerFlag,
+ code,
+ uuid
+ }
+ return request({
+ url: '/appLogin',
+ headers: {
+ isToken: false
+ },
+ method: 'post',
+ data: data
+ })
+}
+
+// 注册方法
+export function register(data) {
+ return request({
+ url: '/register',
+ headers: {
+ isToken: false
+ },
+ method: 'post',
+ data: data
+ })
+}
+
+// 获取用户详细信息
+export function getInfo() {
+ return request({
+ url: '/getInfo',
+ method: 'get'
+ })
+}
+
+// 退出方法
+export function logout() {
+ return request({
+ url: '/logout',
+ method: 'post'
+ })
+}
+
+// 获取验证码
+export function getCodeImg() {
+ return request({
+ url: '/captchaImage',
+ headers: {
+ isToken: false
+ },
+ method: 'get',
+ timeout: 20000
+ })
+}
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..912b511
--- /dev/null
+++ b/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/main.js b/main.js
new file mode 100644
index 0000000..fafb871
--- /dev/null
+++ b/main.js
@@ -0,0 +1,23 @@
+import { createSSRApp } from 'vue'
+import App from './App'
+// 存储
+import store from '@/store'
+// 路由权限控制
+import '@/permission.js'
+
+// 框架方法
+import frameTool from "@/utils/frameTool";
+// 插件方法
+import pluginTool from "@/plugins/pluginTool.js";
+
+const app = createSSRApp(App)
+
+app.use(store)
+app.use(frameTool)
+app.use(pluginTool)
+
+export function createApp() {
+ return {
+ app
+ }
+}
\ No newline at end of file
diff --git a/manifest.json b/manifest.json
new file mode 100644
index 0000000..973d02f
--- /dev/null
+++ b/manifest.json
@@ -0,0 +1,79 @@
+{
+ "name" : "udemo-im",
+ "appid" : "__UNI__D1DA2B6",
+ "description" : "",
+ "versionName" : "1.0.0",
+ "versionCode" : "100",
+ "transformPx" : false,
+ /* 5+App特有相关 */
+ "app-plus" : {
+ "usingComponents" : true,
+ "nvueStyleCompiler" : "uni-app",
+ "compilerVersion" : 3,
+ "splashscreen" : {
+ "alwaysShowBeforeRender" : true,
+ "waiting" : true,
+ "autoclose" : true,
+ "delay" : 0
+ },
+ /* 模块配置 */
+ "modules" : {},
+ /* 应用发布信息 */
+ "distribute" : {
+ /* android打包配置 */
+ "android" : {
+ "permissions" : [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""
+ ]
+ },
+ /* ios打包配置 */
+ "ios" : {},
+ /* SDK配置 */
+ "sdkConfigs" : {}
+ }
+ },
+ /* 快应用特有相关 */
+ "quickapp" : {},
+ /* 小程序特有相关 */
+ "mp-weixin" : {
+ "appid" : "",
+ "setting" : {
+ "urlCheck" : false
+ },
+ "usingComponents" : true
+ },
+ "mp-alipay" : {
+ "usingComponents" : true
+ },
+ "mp-baidu" : {
+ "usingComponents" : true
+ },
+ "mp-toutiao" : {
+ "usingComponents" : true
+ },
+ "uniStatistics" : {
+ "enable" : false
+ },
+ "vueVersion" : "3",
+ "h5" : {
+ "title" : "im",
+ "router" : {
+ "mode" : "hash",
+ "base" : "/udemo/im/"
+ }
+ }
+}
diff --git a/pages.json b/pages.json
new file mode 100644
index 0000000..4be6b97
--- /dev/null
+++ b/pages.json
@@ -0,0 +1,105 @@
+{
+ "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
+ // 我的
+ {
+ "path": "pages/home/user",
+ "style" : {
+ "navigationBarTitleText": "我的",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path": "uni_modules/vrapile-im/pages/home/chatHome",
+ "style": {
+ "enablePullDownRefresh": false,
+ "navigationBarTitleText": "消息"
+ }
+ },
+ {
+ "path": "uni_modules/vrapile-im/pages/chat/chatFriend",
+ "style": {
+ "enablePullDownRefresh": true,
+ "navigationBarTitleText": "聊天"
+ }
+ }
+ ],
+ "subPackages": [
+ //用户
+ {
+ "root": "pages/user",
+ "pages": [
+ {
+ "path": "login",
+ "style": {
+ "navigationBarTitleText": "登录",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path": "register",
+ "style": {
+ "navigationBarTitleText": "注册",
+ "enablePullDownRefresh": false
+ }
+ }
+ ]
+ },
+ //设置
+ {
+ "root": "pages/setting",
+ "pages": [
+ {
+ "path" : "about",
+ "style" : {
+ "navigationBarTitleText": "关于",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path" : "contact",
+ "style" : {
+ "navigationBarTitleText": "联系我们",
+ "enablePullDownRefresh": false
+ }
+ },
+ {
+ "path" : "setting",
+ "style" : {
+ "navigationBarTitleText": "设置",
+ "enablePullDownRefresh": false
+ }
+ }
+ ]
+ }
+ ],
+ "globalStyle": {
+ "navigationBarTextStyle": "black",
+ "navigationBarTitleText": "IM",
+ "navigationBarBackgroundColor": "#FFFFFF",
+ "h5": {
+ "titleNView": false,
+ "maxWidth": 1190,
+ "navigationBarTextStyle": "black",
+ "navigationBarBackgroundColor": "#FFFFFF"
+ },
+ "backgroundColor": "#F8F8F8"
+ },
+ "tabBar": {
+ "selectedColor": "#0000ff",
+ "list": [
+ {
+ "pagePath": "uni_modules/vrapile-im/pages/home/chatHome",
+ "iconPath": "static/image/tabbar/chat.png",
+ "selectedIconPath": "static/image/tabbar/chat-fill.png",
+ "text": "消息"
+ },
+ {
+ "pagePath": "pages/home/user",
+ "iconPath": "static/image/tabbar/user.png",
+ "selectedIconPath": "static/image/tabbar/user-fill.png",
+ "text": "我的"
+ }
+ ]
+ },
+ "uniIdRouter": {}
+}
diff --git a/pages/home/user.vue b/pages/home/user.vue
new file mode 100644
index 0000000..acab0d7
--- /dev/null
+++ b/pages/home/user.vue
@@ -0,0 +1,158 @@
+
+
+
+
+
+
+
+
+ 设置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/setting/about.vue b/pages/setting/about.vue
new file mode 100644
index 0000000..48abcc1
--- /dev/null
+++ b/pages/setting/about.vue
@@ -0,0 +1,44 @@
+
+
+
+
+
+ 九云 IM Demo
+
+
+
+
+
+ 下载APP
+
+
+
+
+
+
+
+
+ 更新日志
+
+
+
+
+
+
+
+
+
+ 九云科技有限公司《服务协议》
+
+
+ 九云科技 版权所有
+
+
+ Copyright © 2024-2031 NineCloud.
+
+
+ All Rights Reserved
+
+
+
+
diff --git a/pages/setting/contact.vue b/pages/setting/contact.vue
new file mode 100644
index 0000000..0064bc0
--- /dev/null
+++ b/pages/setting/contact.vue
@@ -0,0 +1,81 @@
+
+
+
+
+
+ 微信账号:{{ wechatAccount }}
+
+
+
+
+
+ 联系人
+
+
+ 袁先生
+
+
+
+
+ 联系电话
+
+
+ 18627959669
+
+
+
+
+ 微信号
+
+
+ 18627959669
+
+
+
+
+ 邮箱账号
+
+
+ 18627959669@163.com
+
+
+
+
+
+ 九云科技有限公司《服务协议》
+
+
+ 九云科技 版权所有
+
+
+ Copyright © 2024-2031 NineCloud.
+
+
+ All Rights Reserved
+
+
+
+
+
+
diff --git a/pages/setting/setting.vue b/pages/setting/setting.vue
new file mode 100644
index 0000000..28ef981
--- /dev/null
+++ b/pages/setting/setting.vue
@@ -0,0 +1,75 @@
+
+
+
+
+
+ 公告中心
+
+
+
+
+
+
+
+
+ 修改密码
+
+
+
+
+
+
+
+
+ 联系我们
+
+
+
+
+
+
+
+
+ 清空缓存
+
+
+
+
+
+
+
+
+ 关于
+
+
+
+
+
+
+
+ 退出登录
+
+
+
+
+
+
diff --git a/pages/user/login.vue b/pages/user/login.vue
new file mode 100644
index 0000000..eb23f2b
--- /dev/null
+++ b/pages/user/login.vue
@@ -0,0 +1,259 @@
+
+
+
+
+
+
+
+
+
+ 密码登录
+
+
+ 短信登录
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{verifyText}}
+
+
+
+
+ 忘记密码?
+
+ 登 录
+
+ 没有账号?
+
+ 立即注册
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/user/register.vue b/pages/user/register.vue
new file mode 100644
index 0000000..4aff2ff
--- /dev/null
+++ b/pages/user/register.vue
@@ -0,0 +1,173 @@
+
+
+
+
+ 用户账号
+
+
+
+ 用户姓名
+
+
+
+ 手机号
+
+ +86
+
+
+
+
+ 登录密码
+
+
+
+ 确认密码
+
+
+
+
+ 验证码
+
+ {{verifyText}}
+
+
+
+
+
+
+ 《服务协议》
+
+
+
+ 注 册
+
+ 已有账号?
+ 立即登录
+
+
+
+
+
+
\ No newline at end of file
diff --git a/permission.js b/permission.js
new file mode 100644
index 0000000..03ae2c4
--- /dev/null
+++ b/permission.js
@@ -0,0 +1,96 @@
+import store from '@/store'
+import { getToken } from '@/utils/token'
+import { setNodeId, getNodeId } from '@/utils/nodeId'
+import { diyApi } from '@/utils/queryByDiy';
+import { getLongRandom } from '@/utils/nineTool';
+
+// 登录页面
+const loginPage = "/pages/user/login"
+
+// 页面白名单
+const whiteList = [
+ '/pages/user/login',
+ '/pages/user/register',
+ '/pages/user/forget',
+ '/pages/setting/protocol',
+ '/pages/common/webview/index'
+]
+
+// 检查地址白名单
+function checkWhite(url) {
+ const path = url.split('?')[0]
+ return whiteList.indexOf(path) !== -1
+}
+
+// 保存访问日志
+function saveAccessLog(to, f) {
+ // 开发环境不保存日志
+ if(import.meta.env.VITE_APP_ENV == 'development'){
+ return;
+ }
+ // 生成一个nodeId,用于记录日志
+ let nodeId = getNodeId();
+ if(!nodeId){
+ nodeId = getLongRandom(24)
+ setNodeId(nodeId)
+ }
+ let flag = "udemo_im_other_" + f;
+ // #ifdef MP-WEIXIN
+ flag = "udemo_im_wx_" + f;
+ // #endif
+ // #ifdef H5
+ flag = "udemo_im_h5_" + f;
+ // #endif
+ // #ifdef APP-PLUS
+ flag = "udemo_im_app_" + f;
+ // #endif
+ let data = {
+ flag: flag,
+ fullPath: to.url.split("?")[0],
+ allPath: to.url,
+ menuName: to.tabBarText,
+ userId: store.state.user.userInfo.userId,
+ userName: store.state.user.userInfo.userName,
+ nodeId: nodeId
+ }
+ diyApi("/system/log/insSysAccessLog", data);
+}
+
+// 页面跳转验证拦截器
+let list = ["navigateTo", "redirectTo", "reLaunch", "switchTab"]
+list.forEach(item => {
+ uni.addInterceptor(item, {
+ invoke(to) {
+ if (getToken()) {
+ if (to.url === loginPage) {
+ uni.reLaunch({ url: "/" })
+ }
+ saveAccessLog(to, "generate");
+ return true
+ } else {
+ if (checkWhite(to.url)) {
+ saveAccessLog(to, "white");
+ return true
+ }
+ saveAccessLog(to, "nologin");
+ // 密码登录的,实现自动重新登录
+ let loginInfo = store.state.user.loginInfo;
+ if(loginInfo && loginInfo.loginType == 0){
+ store.dispatch('Login', {
+ loginType: loginInfo.loginType,
+ userName: loginInfo.userName,
+ password: loginInfo.password,
+ registerFlag: "N"
+ }).then(() => {
+ store.dispatch('GetInfo');
+ })
+ return true
+ }
+ return true
+ }
+ },
+ fail(err) {
+ console.error(err)
+ }
+ })
+})
diff --git a/plugins/modal.js b/plugins/modal.js
new file mode 100644
index 0000000..f9fbc68
--- /dev/null
+++ b/plugins/modal.js
@@ -0,0 +1,72 @@
+// 消息提示
+export function msg(content) {
+ uni.showToast({
+ title: content,
+ icon: 'none'
+ })
+}
+// 错误消息
+export function msgError(content) {
+ uni.showToast({
+ title: content,
+ icon: 'error'
+ })
+}
+// 成功消息
+export function msgSuccess(content) {
+ uni.showToast({
+ title: content,
+ icon: 'success'
+ })
+}
+// 隐藏消息
+export function hideMsg(content) {
+ uni.hideToast()
+}
+// 弹出提示
+export function alert(content, title) {
+ uni.showModal({
+ title: title || '系统提示',
+ content: content,
+ showCancel: false
+ })
+}
+// 确认窗体
+export function confirm(content, title) {
+ return new Promise((resolve, reject) => {
+ uni.showModal({
+ title: title || '系统提示',
+ content: content,
+ cancelText: '取消',
+ confirmText: '确定',
+ success: function(res) {
+ if (res.confirm) {
+ resolve(res.confirm)
+ }
+ }
+ })
+ })
+}
+// 提示信息
+export function showToast(option) {
+ if (typeof option === "object") {
+ uni.showToast(option)
+ } else {
+ uni.showToast({
+ title: option,
+ icon: "none",
+ duration: 2500
+ })
+ }
+}
+// 打开遮罩层
+export function loading(content) {
+ uni.showLoading({
+ title: content,
+ icon: 'none'
+ })
+}
+// 关闭遮罩层
+export function closeLoading() {
+ uni.hideLoading()
+}
diff --git a/plugins/pluginTool.js b/plugins/pluginTool.js
new file mode 100644
index 0000000..91c0af2
--- /dev/null
+++ b/plugins/pluginTool.js
@@ -0,0 +1,15 @@
+import * as tab from '@/plugins/tab.js'
+import * as modal from '@/plugins/modal.js'
+
+export default {
+ install(app) {
+ // tab工具
+ Object.keys(tab).forEach((key) => {
+ app.config.globalProperties[key] = tab[key];
+ })
+ // modal工具
+ Object.keys(modal).forEach((key) => {
+ app.config.globalProperties[key] = modal[key];
+ });
+ }
+};
\ No newline at end of file
diff --git a/plugins/tab.js b/plugins/tab.js
new file mode 100644
index 0000000..f3ff2ca
--- /dev/null
+++ b/plugins/tab.js
@@ -0,0 +1,74 @@
+ // 关闭所有页面,打开到应用内的某个页面
+export function reLaunch(url) {
+ return uni.reLaunch({
+ url: url
+ })
+}
+export function reLaunchLogin() {
+ return uni.reLaunch({
+ url: '/pages/user/login'
+ })
+}
+// 跳转到tabBar页面,并关闭其他所有非tabBar页面
+export function switchTab(url) {
+ return uni.switchTab({
+ url: url
+ })
+}
+// 关闭当前页面,跳转到应用内的某个页面
+export function redirectTo(url) {
+ return uni.redirectTo({
+ url: url
+ })
+}
+// 保留当前页面,跳转到应用内的某个页面
+export function navigateTo(url) {
+ return uni.navigateTo({
+ url: url
+ })
+}
+// 保留当前页面,跳转到应用内的某个页面
+export function navigateToLogin() {
+ return uni.navigateTo({
+ url: '/pages/user/login'
+ })
+}
+// 关闭当前页面,返回上一页面或多级页面
+export function navigateBack() {
+ return uni.navigateBack()
+}
+
+export function openUrl(url) {
+ if(!url || typeof url == 'object' || url == '#'){
+ uni.showToast({
+ title: '此功能正开发中,敬请期待!',
+ icon: 'none'
+ })
+ return;
+ }
+ uni.navigateTo({
+ url: url
+ })
+}
+
+export function pageScrollTo(scrollTop, duration=0) {
+ uni.pageScrollTo({
+ scrollTop: scrollTop,
+ duration: duration
+ });
+}
+
+// 复制
+export function setClipboardData(content) {
+ return new Promise((resolve, reject) => {
+ uni.setClipboardData({
+ data: content,
+ success: (res) => {
+ if (res.confirm) {
+ resolve(res.confirm)
+ }
+ }
+ })
+ })
+}
+
diff --git a/static/image/app.png b/static/image/app.png
new file mode 100644
index 0000000..3f63250
Binary files /dev/null and b/static/image/app.png differ
diff --git a/static/image/favicon.ico b/static/image/favicon.ico
new file mode 100644
index 0000000..3a25a29
Binary files /dev/null and b/static/image/favicon.ico differ
diff --git a/static/image/ninecloud-white.png b/static/image/ninecloud-white.png
new file mode 100644
index 0000000..7d80098
Binary files /dev/null and b/static/image/ninecloud-white.png differ
diff --git a/static/image/tabbar/chat-fill.png b/static/image/tabbar/chat-fill.png
new file mode 100644
index 0000000..5001200
Binary files /dev/null and b/static/image/tabbar/chat-fill.png differ
diff --git a/static/image/tabbar/chat.png b/static/image/tabbar/chat.png
new file mode 100644
index 0000000..2872220
Binary files /dev/null and b/static/image/tabbar/chat.png differ
diff --git a/static/image/tabbar/home-fill.png b/static/image/tabbar/home-fill.png
new file mode 100644
index 0000000..97a5446
Binary files /dev/null and b/static/image/tabbar/home-fill.png differ
diff --git a/static/image/tabbar/home.png b/static/image/tabbar/home.png
new file mode 100644
index 0000000..154bec6
Binary files /dev/null and b/static/image/tabbar/home.png differ
diff --git a/static/image/tabbar/type-fill.png b/static/image/tabbar/type-fill.png
new file mode 100644
index 0000000..1788008
Binary files /dev/null and b/static/image/tabbar/type-fill.png differ
diff --git a/static/image/tabbar/type.png b/static/image/tabbar/type.png
new file mode 100644
index 0000000..bff7a03
Binary files /dev/null and b/static/image/tabbar/type.png differ
diff --git a/static/image/tabbar/user-fill.png b/static/image/tabbar/user-fill.png
new file mode 100644
index 0000000..119edbe
Binary files /dev/null and b/static/image/tabbar/user-fill.png differ
diff --git a/static/image/tabbar/user.png b/static/image/tabbar/user.png
new file mode 100644
index 0000000..075faff
Binary files /dev/null and b/static/image/tabbar/user.png differ
diff --git a/static/image/user/cc.png b/static/image/user/cc.png
new file mode 100644
index 0000000..ab9d001
Binary files /dev/null and b/static/image/user/cc.png differ
diff --git a/static/image/user/login-password-blue.png b/static/image/user/login-password-blue.png
new file mode 100644
index 0000000..76debeb
Binary files /dev/null and b/static/image/user/login-password-blue.png differ
diff --git a/static/image/user/login-phone-blue.png b/static/image/user/login-phone-blue.png
new file mode 100644
index 0000000..6fcc3bf
Binary files /dev/null and b/static/image/user/login-phone-blue.png differ
diff --git a/static/image/user/message.png b/static/image/user/message.png
new file mode 100644
index 0000000..5ae809e
Binary files /dev/null and b/static/image/user/message.png differ
diff --git a/static/image/user/uset.png b/static/image/user/uset.png
new file mode 100644
index 0000000..6d4bbea
Binary files /dev/null and b/static/image/user/uset.png differ
diff --git a/static/image/user/yy.png b/static/image/user/yy.png
new file mode 100644
index 0000000..2ffff1b
Binary files /dev/null and b/static/image/user/yy.png differ
diff --git a/static/style/nine-base-001.scss b/static/style/nine-base-001.scss
new file mode 100644
index 0000000..0c44685
--- /dev/null
+++ b/static/style/nine-base-001.scss
@@ -0,0 +1,555 @@
+.text-center{ text-align: center }
+.text-right{ text-align: right }
+.text-left{ text-align: left }
+
+.font-size6{ font-size: 6px }
+.font-size8{ font-size: 8px }
+.font-size10{ font-size: 10px }
+.font-size12{ font-size: 12px }
+.font-size14{ font-size: 14px }
+.font-size16{ font-size: 16px }
+.font-size18{ font-size: 18px }
+.font-size20{ font-size: 20px }
+.font-size22{ font-size: 22px }
+.font-size24{ font-size: 24px }
+.font-size26{ font-size: 26px }
+.font-size28{ font-size: 28px }
+.font-size30{ font-size: 30px }
+.font-size32{ font-size: 32px }
+.font-size34{ font-size: 34px }
+.font-size36{ font-size: 36px }
+.font-size38{ font-size: 38px }
+.font-size40{ font-size: 40px }
+.font-size60{ font-size: 60px }
+.font-size80{ font-size: 80px }
+
+.font-bold{ font-weight: bold }
+
+.color-red{ color: red }
+.color-green{ color: green }
+.color-white{ color: white }
+.color-gray{ color: gray }
+.color-blue{ color: blue }
+.color-yellow{ color: yellow }
+.color-black{ color: black }
+.color-f1f1f1{ color: #f1f1f1 }
+
+.bgcolor-blue{ background-color: blue }
+.bgcolor-red{ background-color: red }
+.bgcolor-pink{ background-color: pink }
+.bgcolor-white{ background-color: white }
+.bgcolor-lightblue{ background-color: lightblue }
+.bgcolor-cce1e6{ background-color: #cce1e6 }
+.bgcolor-787fff{ background-color: #787fff }
+.bgcolor-eef0ff{ background-color: #eef0ff }
+.bgcolor-ff4769{ background-color: #ff4769 }
+.bgcolor-f1f1f1{ background-color: #f1f1f1 }
+
+.border-gray{ border: 3rpx solid gray }
+.border-lightblue{ border: 3rpx solid lightblue }
+.border-pink{ border: 3rpx solid pink }
+.border-blue{ border: 3rpx solid blue }
+.border-red{ border: 3rpx solid red }
+.border-white{ border: 3rpx solid white }
+.border-f1f1f1{ border: 3rpx solid #f1f1f1 }
+.border-cce1e6{ border: 3rpx solid #cce1e6 }
+.border-787fff{ border: 3rpx solid #787fff }
+.border-eef0ff{ border: 3rpx solid #eef0ff }
+.border-ff4769{ border: 3rpx solid #ff4769 }
+.border-f1f1f1{ border: 3rpx solid #f1f1f1 }
+
+.border-radius10{ border-radius: 10rpx }
+
+.position-fixed{ position: fixed }
+.position-absolute{ position: absolute }
+.position-relative{ position: relative }
+
+.top0{ top: 0rpx }
+.top10{ top: 10rpx }
+.top20{ top: 20rpx }
+.top30{ top: 30rpx }
+.top40{ top: 40rpx }
+.top50{ top: 50rpx }
+.top60{ top: 60rpx }
+.top70{ top: 70rpx }
+.top80{ top: 80rpx }
+.top90{ top: 90rpx }
+.top100{ top: 100rpx }
+.top110{ top: 110rpx }
+.top120{ top: 120rpx }
+.top130{ top: 130rpx }
+.top140{ top: 140rpx }
+.top150{ top: 150rpx }
+.top200{ top: 200rpx }
+.left0{ left: 0rpx }
+.left10{ left: 10rpx }
+.left20{ left: 20rpx }
+.left30{ left: 30rpx }
+.left40{ left: 40rpx }
+.left50{ left: 50rpx }
+.left60{ left: 60rpx }
+.right0{ right: 0rpx }
+.right10{ right: 10rpx }
+.right20{ right: 20rpx }
+.right30{ right: 30rpx }
+.right40{ right: 40rpx }
+.right50{ right: 50rpx }
+.right60{ right: 60rpx }
+.bottom0{ bottom: 0rpx }
+.bottom10{ bottom: 10rpx }
+.bottom20{ bottom: 20rpx }
+.bottom30{ bottom: 30rpx }
+.bottom40{ bottom: 40rpx }
+.bottom50{ bottom: 50rpx }
+.bottom60{ bottom: 60rpx }
+.bottom70{ bottom: 70rpx }
+.bottom80{ bottom: 80rpx }
+.bottom90{ bottom: 90rpx }
+.bottom100{ bottom: 100rpx }
+.bottom110{ bottom: 110rpx }
+.bottom120{ bottom: 120rpx }
+.bottom130{ bottom: 130rpx }
+.bottom140{ bottom: 140rpx }
+.bottom150{ bottom: 150rpx }
+.bottom200{ bottom: 200rpx }
+
+.lh20{ line-height: 20rpx }
+.lh25{ line-height: 25rpx }
+.lh30{ line-height: 30rpx }
+.lh35{ line-height: 35rpx }
+.lh40{ line-height: 40rpx }
+.lh50{ line-height: 50rpx }
+
+.pa0{ padding: 0rpx }
+.pa5{ padding: 5rpx }
+.pa10{ padding: 10rpx }
+.pa15{ padding: 15rpx }
+.pa20{ padding: 20rpx }
+.pa25{ padding: 25rpx }
+.pa30{ padding: 30rpx }
+.pa40{ padding: 40rpx }
+.pa45{ padding: 45rpx }
+.pa50{ padding: 50rpx }
+.pa60{ padding: 60rpx }
+.pa70{ padding: 70rpx }
+.pa80{ padding: 80rpx }
+.pa90{ padding: 90rpx }
+.pa100{ padding: 100rpx }
+.pa120{ padding: 120rpx }
+.pa140{ padding: 140rpx }
+.pa160{ padding: 160rpx }
+.pa180{ padding: 180rpx }
+.pa200{ padding: 200rpx }
+.pa250{ padding: 250rpx }
+.pa300{ padding: 300rpx }
+
+.ptb0{ padding-top: 0rpx; padding-bottom: 0rpx }
+.ptb5{ padding-top: 5rpx; padding-bottom: 5rpx }
+.ptb10{ padding-top: 10rpx; padding-bottom: 10rpx }
+.ptb15{ padding-top: 15rpx; padding-bottom: 15rpx }
+.ptb20{ padding-top: 20rpx; padding-bottom: 20rpx }
+.ptb25{ padding-top: 25rpx; padding-bottom: 25rpx }
+.ptb30{ padding-top: 30rpx; padding-bottom: 30rpx }
+.ptb35{ padding-top: 35rpx; padding-bottom: 35rpx }
+.ptb40{ padding-top: 40rpx; padding-bottom: 40rpx }
+.ptb45{ padding-top: 45rpx; padding-bottom: 45rpx }
+.ptb50{ padding-top: 50rpx; padding-bottom: 50rpx }
+.ptb60{ padding-top: 60rpx; padding-bottom: 60rpx }
+.ptb70{ padding-top: 70rpx; padding-bottom: 70rpx }
+.ptb80{ padding-top: 80rpx; padding-bottom: 80rpx }
+.ptb90{ padding-top: 90rpx; padding-bottom: 90rpx }
+.ptb100{ padding-top: 100rpx; padding-bottom: 100rpx }
+.ptb120{ padding-top: 120rpx; padding-bottom: 120rpx }
+.ptb140{ padding-top: 140rpx; padding-bottom: 140rpx }
+.ptb160{ padding-top: 160rpx; padding-bottom: 160rpx }
+.ptb180{ padding-top: 180rpx; padding-bottom: 180rpx }
+.ptb200{ padding-top: 200rpx; padding-bottom: 200rpx }
+.ptb250{ padding-top: 250rpx; padding-bottom: 250rpx }
+.ptb300{ padding-top: 300rpx; padding-bottom: 300rpx }
+
+.plr0{ padding-left: 0rpx; padding-right: 0rpx }
+.plr5{ padding-left: 5rpx; padding-right: 5rpx }
+.plr10{ padding-left: 10rpx; padding-right: 10rpx }
+.plr15{ padding-left: 15rpx; padding-right: 15rpx }
+.plr20{ padding-left: 20rpx; padding-right: 20rpx }
+.plr25{ padding-left: 25rpx; padding-right: 25rpx }
+.plr30{ padding-left: 30rpx; padding-right: 30rpx }
+.plr35{ padding-left: 35rpx; padding-right: 35rpx }
+.plr40{ padding-left: 40rpx; padding-right: 40rpx }
+.plr45{ padding-left: 45rpx; padding-right: 45rpx }
+.plr50{ padding-left: 50rpx; padding-right: 50rpx }
+.plr60{ padding-left: 60rpx; padding-right: 60rpx }
+.plr70{ padding-left: 70rpx; padding-right: 70rpx }
+.plr80{ padding-left: 80rpx; padding-right: 80rpx }
+.plr90{ padding-left: 90rpx; padding-right: 90rpx }
+.plr100{ padding-left: 100rpx; padding-right: 100rpx }
+.plr120{ padding-left: 120rpx; padding-right: 120rpx }
+.plr140{ padding-left: 140rpx; padding-right: 140rpx }
+.plr160{ padding-left: 160rpx; padding-right: 160rpx }
+.plr180{ padding-left: 180rpx; padding-right: 180rpx }
+.plr200{ padding-left: 200rpx; padding-right: 200rpx }
+.plr250{ padding-left: 250rpx; padding-right: 250rpx }
+.plr300{ padding-left: 300rpx; padding-right: 300rpx }
+
+.pt0{ padding-top: 0rpx }
+.pt5{ padding-top: 5rpx }
+.pt10{ padding-top: 10rpx }
+.pt15{ padding-top: 15rpx }
+.pt20{ padding-top: 20rpx }
+.pt25{ padding-top: 25rpx }
+.pt30{ padding-top: 30rpx }
+.pt35{ padding-top: 35rpx }
+.pt40{ padding-top: 40rpx }
+.pt45{ padding-top: 45rpx }
+.pt50{ padding-top: 50rpx }
+.pt60{ padding-top: 60rpx }
+.pt70{ padding-top: 70rpx }
+.pt80{ padding-top: 80rpx }
+.pt90{ padding-top: 90rpx }
+.pt100{ padding-top: 100rpx }
+.pt120{ padding-top: 120rpx }
+.pt140{ padding-top: 140rpx }
+.pt160{ padding-top: 160rpx }
+.pt180{ padding-top: 180rpx }
+.pt200{ padding-top: 200rpx }
+.pt250{ padding-top: 250rpx }
+.pt300{ padding-top: 300rpx }
+
+.pb0{ padding-bottom: 0rpx }
+.pb5{ padding-bottom: 5rpx }
+.pb10{ padding-bottom: 10rpx }
+.pb15{ padding-bottom: 15rpx }
+.pb20{ padding-bottom: 20rpx }
+.pb25{ padding-bottom: 25rpx }
+.pb30{ padding-bottom: 30rpx }
+.pb35{ padding-bottom: 35rpx }
+.pb40{ padding-bottom: 40rpx }
+.pb45{ padding-bottom: 45rpx }
+.pb50{ padding-bottom: 50rpx }
+.pb60{ padding-bottom: 60rpx }
+.pb70{ padding-bottom: 70rpx }
+.pb80{ padding-bottom: 80rpx }
+.pb90{ padding-bottom: 90rpx }
+.pb100{ padding-bottom: 100rpx }
+.pb120{ padding-bottom: 120rpx }
+.pb140{ padding-bottom: 140rpx }
+.pb160{ padding-bottom: 160rpx }
+.pb180{ padding-bottom: 180rpx }
+.pb200{ padding-bottom: 200rpx }
+.pb250{ padding-bottom: 250rpx }
+.pb300{ padding-bottom: 300rpx }
+
+.pl0{ padding-left: 0rpx }
+.pl5{ padding-left: 5rpx }
+.pl10{ padding-left: 10rpx }
+.pl15{ padding-left: 15rpx }
+.pl20{ padding-left: 20rpx }
+.pl25{ padding-left: 25rpx }
+.pl30{ padding-left: 30rpx }
+.pl35{ padding-left: 35rpx }
+.pl40{ padding-left: 40rpx }
+.pl45{ padding-left: 45rpx }
+.pl50{ padding-left: 50rpx }
+.pl60{ padding-left: 60rpx }
+.pl70{ padding-left: 70rpx }
+.pl80{ padding-left: 80rpx }
+.pl90{ padding-left: 90rpx }
+.pl100{ padding-left: 100rpx }
+.pl120{ padding-left: 120rpx }
+.pl140{ padding-left: 140rpx }
+.pl160{ padding-left: 160rpx }
+.pl180{ padding-left: 180rpx }
+.pl200{ padding-left: 200rpx }
+.pl250{ padding-left: 250rpx }
+.pl300{ padding-left: 300rpx }
+
+.pr0{ padding-right: 0rpx }
+.pr5{ padding-right: 5rpx }
+.pr10{ padding-right: 10rpx }
+.pr15{ padding-right: 15rpx }
+.pr20{ padding-right: 20rpx }
+.pr25{ padding-right: 25rpx }
+.pr30{ padding-right: 30rpx }
+.pr35{ padding-right: 35rpx }
+.pr40{ padding-right: 40rpx }
+.pr45{ padding-right: 45rpx }
+.pr50{ padding-right: 50rpx }
+.pr60{ padding-right: 60rpx }
+.pr70{ padding-right: 70rpx }
+.pr80{ padding-right: 80rpx }
+.pr90{ padding-right: 90rpx }
+.pr100{ padding-right: 100rpx }
+.pr120{ padding-right: 120rpx }
+.pr140{ padding-right: 140rpx }
+.pr160{ padding-right: 160rpx }
+.pr180{ padding-right: 180rpx }
+.pr200{ padding-right: 200rpx }
+.pr250{ padding-right: 250rpx }
+.pr300{ padding-right: 300rpx }
+
+.ma0{ margin: 0rpx }
+.ma5{ margin: 5rpx }
+.ma10{ margin: 10rpx }
+.ma15{ margin: 15rpx }
+.ma20{ margin: 20rpx }
+.ma25{ margin: 25rpx }
+.ma30{ margin: 30rpx }
+.ma35{ margin: 35rpx }
+.ma40{ margin: 40rpx }
+.ma45{ margin: 45rpx }
+.ma50{ margin: 50rpx }
+.ma60{ margin: 60rpx }
+.ma70{ margin: 70rpx }
+.ma80{ margin: 80rpx }
+.ma90{ margin: 90rpx }
+.ma100{ margin: 100rpx }
+.ma120{ margin: 120rpx }
+.ma140{ margin: 140rpx }
+.ma160{ margin: 160rpx }
+.ma180{ margin: 180rpx }
+.ma200{ margin: 200rpx }
+.ma250{ margin: 250rpx }
+.ma300{ margin: 300rpx }
+
+.mlr0{ margin-left: 0rpx; margin-right: 0rpx }
+.mlr5{ margin-left: 5rpx; margin-right: 5rpx }
+.mlr10{ margin-left: 10rpx; margin-right: 10rpx }
+.mlr15{ margin-left: 15rpx; margin-right: 15rpx }
+.mlr20{ margin-left: 20rpx; margin-right: 20rpx }
+.mlr25{ margin-left: 25rpx; margin-right: 25rpx }
+.mlr30{ margin-left: 30rpx; margin-right: 30rpx }
+.mlr35{ margin-left: 35rpx; margin-right: 35rpx }
+.mlr40{ margin-left: 40rpx; margin-right: 40rpx }
+.mlr45{ margin-left: 45rpx; margin-right: 45rpx }
+.mlr50{ margin-left: 50rpx; margin-right: 50rpx }
+.mlr50{ margin-left: 50rpx; margin-right: 50rpx }
+.mlr60{ margin-left: 60rpx; margin-right: 60rpx }
+.mlr70{ margin-left: 70rpx; margin-right: 70rpx }
+.mlr80{ margin-left: 80rpx; margin-right: 80rpx }
+.mlr90{ margin-left: 90rpx; margin-right: 90rpx }
+.mlr100{ margin-left: 100rpx; margin-right: 100rpx }
+.mlr120{ margin-left: 120rpx; margin-right: 120rpx }
+.mlr140{ margin-left: 140rpx; margin-right: 140rpx }
+.mlr160{ margin-left: 160rpx; margin-right: 160rpx }
+.mlr180{ margin-left: 180rpx; margin-right: 180rpx }
+.mlr200{ margin-left: 200rpx; margin-right: 200rpx }
+.mlr250{ margin-left: 250rpx; margin-right: 250rpx }
+.mlr300{ margin-left: 300rpx; margin-right: 300rpx }
+
+.mtb0{ margin-top: 0rpx; margin-bottom: 0rpx }
+.mtb5{ margin-top: 5rpx; margin-bottom: 5rpx }
+.mtb10{ margin-top: 10rpx; margin-bottom: 10rpx }
+.mtb15{ margin-top: 15rpx; margin-bottom: 15rpx }
+.mtb20{ margin-top: 20rpx; margin-bottom: 20rpx }
+.mtb25{ margin-top: 25rpx; margin-bottom: 25rpx }
+.mtb30{ margin-top: 30rpx; margin-bottom: 30rpx }
+.mtb35{ margin-top: 35rpx; margin-bottom: 35rpx }
+.mtb40{ margin-top: 40rpx; margin-bottom: 40rpx }
+.mtb45{ margin-top: 45rpx; margin-bottom: 45rpx }
+.mtb50{ margin-top: 50rpx; margin-bottom: 50rpx }
+.mtb60{ margin-top: 60rpx; margin-bottom: 60rpx }
+.mtb70{ margin-top: 70rpx; margin-bottom: 70rpx }
+.mtb80{ margin-top: 80rpx; margin-bottom: 80rpx }
+.mtb90{ margin-top: 90rpx; margin-bottom: 90rpx }
+.mtb100{ margin-top: 100rpx; margin-bottom: 100rpx }
+.mtb120{ margin-top: 120rpx; margin-bottom: 120rpx }
+.mtb140{ margin-top: 140rpx; margin-bottom: 140rpx }
+.mtb160{ margin-top: 160rpx; margin-bottom: 160rpx }
+.mtb180{ margin-top: 180rpx; margin-bottom: 180rpx }
+.mtb200{ margin-top: 200rpx; margin-bottom: 200rpx }
+.mtb250{ margin-top: 250rpx; margin-bottom: 250rpx }
+.mtb300{ margin-top: 300rpx; margin-bottom: 300rpx }
+
+.mt0{ margin-top: 0rpx }
+.mt5{ margin-top: 5rpx }
+.mt10{ margin-top: 10rpx }
+.mt12{ margin-top: 10rpx }
+.mt15{ margin-top: 15rpx }
+.mt20{ margin-top: 20rpx }
+.mt25{ margin-top: 25rpx }
+.mt30{ margin-top: 30rpx }
+.mt35{ margin-top: 35rpx }
+.mt40{ margin-top: 40rpx }
+.mt45{ margin-top: 45rpx }
+.mt50{ margin-top: 50rpx }
+.mt60{ margin-top: 60rpx }
+.mt65{ margin-top: 65rpx }
+.mt70{ margin-top: 70rpx }
+.mt80{ margin-top: 80rpx }
+.mt90{ margin-top: 90rpx }
+.mt100{ margin-top: 100rpx }
+.mt120{ margin-top: 120rpx }
+.mt140{ margin-top: 140rpx }
+.mt160{ margin-top: 160rpx }
+.mt180{ margin-top: 180rpx }
+.mt200{ margin-top: 200rpx }
+.mt250{ margin-top: 250rpx }
+.mt300{ margin-top: 300rpx }
+
+.mt-1{ margin-top: -1rpx }
+.mt-5{ margin-top: -5rpx }
+.mt-10{ margin-top: -10rpx }
+.mt-15{ margin-top: -15rpx }
+.mt-20{ margin-top: -20rpx }
+.mt-25{ margin-top: -25rpx }
+.mt-30{ margin-top: -30rpx }
+.mt-35{ margin-top: -35rpx }
+.mt-40{ margin-top: -40rpx }
+.mt-45{ margin-top: -45rpx }
+.mt-50{ margin-top: -50rpx }
+.mt-60{ margin-top: -60rpx }
+.mt-70{ margin-top: -70rpx }
+.mt-80{ margin-top: -80rpx }
+.mt-90{ margin-top: -90rpx }
+.mt-100{ margin-top: -100rpx }
+.mt-120{ margin-top: -120rpx }
+.mt-140{ margin-top: -140rpx }
+.mt-160{ margin-top: -160rpx }
+.mt-180{ margin-top: -180rpx }
+.mt-200{ margin-top: -200rpx }
+.mt-250{ margin-top: -250rpx }
+.mt-300{ margin-top: -300rpx }
+
+.mb0{ margin-bottom: 0rpx }
+.mb5{ margin-bottom: 5rpx }
+.mb10{ margin-bottom: 10rpx }
+.mb15{ margin-bottom: 15rpx }
+.mb20{ margin-bottom: 20rpx }
+.mb25{ margin-bottom: 25rpx }
+.mb30{ margin-bottom: 30rpx }
+.mb35{ margin-bottom: 35rpx }
+.mb40{ margin-bottom: 40rpx }
+.mb45{ margin-bottom: 45rpx }
+.mb50{ margin-bottom: 50rpx }
+.mb60{ margin-bottom: 60rpx }
+.mb70{ margin-bottom: 70rpx }
+.mb80{ margin-bottom: 80rpx }
+.mb90{ margin-bottom: 90rpx }
+.mb100{ margin-bottom: 100rpx }
+.mb120{ margin-bottom: 120rpx }
+.mb140{ margin-bottom: 140rpx }
+.mb160{ margin-bottom: 160rpx }
+.mb180{ margin-bottom: 180rpx }
+.mb200{ margin-bottom: 200rpx }
+.mb250{ margin-bottom: 250rpx }
+.mb300{ margin-bottom: 300rpx }
+
+.mb-1{ margin-bottom: -1rpx }
+.mb-5{ margin-bottom: -5rpx }
+.mb-10{ margin-bottom: -10rpx }
+.mb-15{ margin-bottom: -15rpx }
+.mb-20{ margin-bottom: -20rpx }
+.mb-25{ margin-bottom: -25rpx }
+.mb-30{ margin-bottom: -30rpx }
+.mb-35{ margin-bottom: -35rpx }
+.mb-40{ margin-bottom: -40rpx }
+.mb-45{ margin-bottom: -45rpx }
+.mb-50{ margin-bottom: -50rpx }
+.mb-60{ margin-bottom: -60rpx }
+.mb-70{ margin-bottom: -70rpx }
+.mb-80{ margin-bottom: -80rpx }
+.mb-90{ margin-bottom: -90rpx }
+.mb-100{ margin-bottom: -100rpx }
+.mb-120{ margin-bottom: -120rpx }
+.mb-140{ margin-bottom: -140rpx }
+.mb-160{ margin-bottom: -160rpx }
+.mb-180{ margin-bottom: -180rpx }
+.mb-200{ margin-bottom: -200rpx }
+.mb-250{ margin-bottom: -250rpx }
+.mb-300{ margin-bottom: -300rpx }
+
+.ml0{ margin-left: 0rpx }
+.ml5{ margin-left: 5rpx }
+.ml10{ margin-left: 10rpx }
+.ml15{ margin-left: 15rpx }
+.ml20{ margin-left: 20rpx }
+.ml25{ margin-left: 25rpx }
+.ml30{ margin-left: 30rpx }
+.ml35{ margin-left: 35rpx }
+.ml40{ margin-left: 40rpx }
+.ml45{ margin-left: 45rpx }
+.ml50{ margin-left: 50rpx }
+.ml60{ margin-left: 60rpx }
+.ml70{ margin-left: 70rpx }
+.ml80{ margin-left: 80rpx }
+.ml90{ margin-left: 90rpx }
+.ml100{ margin-left: 100rpx }
+.ml120{ margin-left: 120rpx }
+.ml140{ margin-left: 140rpx }
+.ml160{ margin-left: 160rpx }
+.ml180{ margin-left: 180rpx }
+.ml200{ margin-left: 200rpx }
+.ml250{ margin-left: 250rpx }
+.ml300{ margin-left: 300rpx }
+
+.ml-1{ margin-left: -1rpx }
+.ml-5{ margin-left: -5rpx }
+.ml-10{ margin-left: -10rpx }
+.ml-15{ margin-left: -15rpx }
+.ml-20{ margin-left: -20rpx }
+.ml-25{ margin-left: -25rpx }
+.ml-30{ margin-left: -30rpx }
+.ml-35{ margin-left: -35rpx }
+.ml-40{ margin-left: -40rpx }
+.ml-45{ margin-left: -45rpx }
+.ml-50{ margin-left: -50rpx }
+.ml-60{ margin-left: -60rpx }
+.ml-70{ margin-left: -70rpx }
+.ml-80{ margin-left: -80rpx }
+.ml-90{ margin-left: -90rpx }
+.ml-100{ margin-left: -100rpx }
+.ml-120{ margin-left: -120rpx }
+.ml-140{ margin-left: -140rpx }
+.ml-160{ margin-left: -160rpx }
+.ml-180{ margin-left: -180rpx }
+.ml-200{ margin-left: -200rpx }
+.ml-250{ margin-left: -250rpx }
+.ml-300{ margin-left: -300rpx }
+
+.mr0{ margin-right: 0rpx }
+.mr5{ margin-right: 5rpx }
+.mr10{ margin-right: 10rpx }
+.mr15{ margin-right: 15rpx }
+.mr20{ margin-right: 20rpx }
+.mr25{ margin-right: 25rpx }
+.mr30{ margin-right: 30rpx }
+.mr35{ margin-right: 35rpx }
+.mr40{ margin-right: 40rpx }
+.mr45{ margin-right: 45rpx }
+.mr50{ margin-right: 50rpx }
+.mr60{ margin-right: 60rpx }
+.mr70{ margin-right: 70rpx }
+.mr80{ margin-right: 80rpx }
+.mr90{ margin-right: 90rpx }
+.mr100{ margin-right: 100rpx }
+.mr120{ margin-right: 120rpx }
+.mr140{ margin-right: 140rpx }
+.mr160{ margin-right: 160rpx }
+.mr180{ margin-right: 180rpx }
+.mr200{ margin-right: 200rpx }
+.mr250{ margin-right: 250rpx }
+.mr300{ margin-right: 300rpx }
+
+.mr-1{ margin-right: -1rpx }
+.mr-5{ margin-right: -5rpx }
+.mr-10{ margin-right: -10rpx }
+.mr-15{ margin-right: -15rpx }
+.mr-20{ margin-right: -20rpx }
+.mr-25{ margin-right: -25rpx }
+.mr-30{ margin-right: -30rpx }
+.mr-35{ margin-right: -35rpx }
+.mr-40{ margin-right: -40rpx }
+.mr-45{ margin-right: -45rpx }
+.mr-50{ margin-right: -50rpx }
+.mr-60{ margin-right: -60rpx }
+.mr-70{ margin-right: -70rpx }
+.mr-80{ margin-right: -80rpx }
+.mr-90{ margin-right: -90rpx }
+.mr-100{ margin-right: -100rpx }
+.mr-120{ margin-right: -120rpx }
+.mr-140{ margin-right: -140rpx }
+.mr-160{ margin-right: -160rpx }
+.mr-180{ margin-right: -180rpx }
+.mr-200{ margin-right: -200rpx }
+.mr-250{ margin-right: -250rpx }
+.mr-300{ margin-right: -300rpx }
\ No newline at end of file
diff --git a/static/style/nine-base-002.scss b/static/style/nine-base-002.scss
new file mode 100644
index 0000000..4ce38eb
--- /dev/null
+++ b/static/style/nine-base-002.scss
@@ -0,0 +1,136 @@
+.height100{
+ height: 100%;
+}
+.width25{
+ width: 25%;
+}
+.width30{
+ width: 30%;
+}
+.width45{
+ width: 45%;
+}
+.width46{
+ width: 46%;
+}
+.width47{
+ width: 47%;
+}
+.width48{
+ width: 48%;
+}
+.width49{
+ width: 49%;
+}
+.width50{
+ width: 50%;
+}
+.width80{
+ width: 80%;
+}
+.width90{
+ width: 90%;
+}
+.width100{
+ width: 100%;
+}
+
+.test{ border: 3rpx solid red}
+.test-red{ border: 3rpx solid red}
+.test-blue{ border: 3rpx solid blue}
+.test-green{ border: 3rpx solid green}
+.test-white{ border: 3rpx solid white}
+.test-box{ box-sizing: border-box; border: 3rpx solid red}
+.test-box-red{ box-sizing: border-box; border: 3rpx solid red}
+.test-box-blue{ box-sizing: border-box; border: 3rpx solid blue}
+.test-box-green{ box-sizing: border-box; border: 3rpx solid green}
+.test-box-white{ box-sizing: border-box; border: 3rpx solid white}
+
+.float{ float: left; }
+.float-left{ float: left; }
+.float-right{ float: right; }
+
+// 允许文本复制
+.nine-user-select {
+ cursor: auto;
+ -webkit-user-select: text;
+ user-select: text;
+}
+
+.display-flex-row{
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+.display-flex-column{
+ display: flex;
+ flex-direction: column;
+}
+.display-flex-column-center{
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+}
+.display-flex-row-between{
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+}
+.display-flex-row-center{
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+}
+.display-flex-row-around{
+ display: flex;
+ flex-direction: row;
+ justify-content: space-around;
+ align-items: center;
+}
+.display-flex-column-between{
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ align-items: center;
+}
+.display-flex-column-around{
+ display: flex;
+ flex-direction: column;
+ justify-content: space-around;
+ align-items: center;
+}
+.justify-content-center{
+ justify-content: center
+}
+.flex1{
+ flex: 1
+}
+
+
+.text-nowrap{
+ white-space:nowrap;
+}
+.text-ellipsis{
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+// 放大缩小比例
+.transform-scale05{
+ transform: scale(0.5);
+}
+.transform-scale06{
+ transform: scale(0.6);
+}
+.transform-scale07{
+ transform: scale(0.7);
+}
+.transform-scale08{
+ transform: scale(0.8);
+}
+.transform-scale09{
+ transform: scale(0.9);
+}
\ No newline at end of file
diff --git a/static/style/nine-btn-001.scss b/static/style/nine-btn-001.scss
new file mode 100644
index 0000000..daf61f9
--- /dev/null
+++ b/static/style/nine-btn-001.scss
@@ -0,0 +1,27 @@
+// 边框蓝,字体蓝,用于获取短信验证码按钮
+.nine-btn-verify-001{
+ border-radius: 10rpx;
+ color: #1e1eff;
+ border: 3rpx solid #1e1eff;
+}
+// 保存按钮
+.nine-btn-save-001{
+ padding: 20rpx;
+ border-radius: 10rpx;
+ color: #fff;
+ background-color: #0000ff;
+ text-align: center;
+}
+// 退出登录
+.nine-btn-login-out-001{
+ padding: 20rpx;
+ border-radius: 10rpx;
+ color: red;
+ background: #fff;
+ text-align: center;
+}
+// 灰色横线
+.nine-line-001{
+ height: 1rpx;
+ border-top: 1rpx solid #d9d9d9;
+}
\ No newline at end of file
diff --git a/static/style/nine-chat-friend-001.scss b/static/style/nine-chat-friend-001.scss
new file mode 100644
index 0000000..4ceda16
--- /dev/null
+++ b/static/style/nine-chat-friend-001.scss
@@ -0,0 +1 @@
+/* 可重写内部/uni_modules/vrapile-im/static/style/nine-chat-friend-001.scss样式 */
diff --git a/static/style/nine-chat-home-001.scss b/static/style/nine-chat-home-001.scss
new file mode 100644
index 0000000..bab177d
--- /dev/null
+++ b/static/style/nine-chat-home-001.scss
@@ -0,0 +1 @@
+/* 可重写内部/uni_modules/vrapile-im/static/style/nine-chat-home-001.scss样式 */
diff --git a/static/style/nine-image-001.scss b/static/style/nine-image-001.scss
new file mode 100644
index 0000000..fdd71d9
--- /dev/null
+++ b/static/style/nine-image-001.scss
@@ -0,0 +1,36 @@
+.image35{
+ width: 35rpx;
+ height: 35rpx;
+}
+.image40{
+ width: 40rpx;
+ height: 40rpx;
+}
+.image50{
+ width: 40rpx;
+ height: 40rpx;
+}
+.image70{
+ width: 70rpx;
+ height: 70rpx;
+}
+.image80{
+ width: 70rpx;
+ height: 70rpx;
+}
+.image90{
+ width: 90rpx;
+ height: 90rpx;
+}
+.image150{
+ width: 150rpx;
+ height: 150rpx;
+}
+.image200{
+ width: 200rpx;
+ height: 200rpx;
+}
+.image400{
+ width: 400rpx;
+ height: 400rpx;
+}
\ No newline at end of file
diff --git a/static/style/nine-list-001.scss b/static/style/nine-list-001.scss
new file mode 100644
index 0000000..4780b21
--- /dev/null
+++ b/static/style/nine-list-001.scss
@@ -0,0 +1,9 @@
+.nine-list-001{
+ padding: 10rpx;
+}
+.nine-list-001-item{
+ background-color: #fff;
+ margin: 10rpx 0;
+ padding: 10rpx 30rpx;
+ border-radius: 10rpx;
+}
\ No newline at end of file
diff --git a/static/style/nine-nav-001.scss b/static/style/nine-nav-001.scss
new file mode 100644
index 0000000..7ddfb98
--- /dev/null
+++ b/static/style/nine-nav-001.scss
@@ -0,0 +1,39 @@
+.nine-nav-001{
+ display: flex;
+ flex-direction: column;
+ padding: 10rpx;
+ flex: 1;
+ height: 100%;
+ overflow-y: auto;
+}
+.nine-nav-001-item{
+ background: #fff;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-between;
+ margin-top: 5rpx;
+ padding: 20rpx 15rpx;
+ border-radius: 1rpx;
+ border-style: solid;
+ border-width: 0px;
+}
+.nine-nav-001-item-left{
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ padding: 2rpx 10rpx;
+}
+.nine-nav-001-item-left-text{
+ font-size: 16px;
+ padding-left: 20rpx;
+}
+.nine-nav-001-item-right{
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+.nine-nav-001-item-right-image{
+ width: 16rpx;
+ height: 35rpx;
+}
\ No newline at end of file
diff --git a/store/getters.js b/store/getters.js
new file mode 100644
index 0000000..95053e9
--- /dev/null
+++ b/store/getters.js
@@ -0,0 +1,8 @@
+const getters = {
+ token: state => state.user.token,
+ userInfo: state => state.user.userInfo,
+ loginInfo: state => state.user.loginInfo,
+ avatar: state => state.user.avatar,
+ name: state => state.user.name
+}
+export default getters
diff --git a/store/index.js b/store/index.js
new file mode 100644
index 0000000..2e6be07
--- /dev/null
+++ b/store/index.js
@@ -0,0 +1,15 @@
+// import Vue from 'vue'
+import Vuex from 'vuex'
+import user from '@/store/modules/user'
+import getters from './getters'
+
+// Vue.use(Vuex)
+
+const store = new Vuex.Store({
+ modules: {
+ user
+ },
+ getters
+})
+
+export default store
diff --git a/store/modules/user.js b/store/modules/user.js
new file mode 100644
index 0000000..12eeb2d
--- /dev/null
+++ b/store/modules/user.js
@@ -0,0 +1,94 @@
+import store from '@/store'
+import storage from '@/utils/storage'
+import constant from '@/utils/constant'
+import { login, logout, getInfo } from '@/api/login'
+import { getToken, setToken, removeToken } from '@/utils/token'
+
+const user = {
+ state: {
+ token: getToken(),
+ userInfo: storage.get(constant.userInfo),
+ loginInfo: storage.get(constant.loginInfo),
+ name: storage.get(constant.name),
+ avatar: storage.get(constant.avatar)
+ },
+
+ mutations: {
+ SET_TOKEN: (state, token) => {
+ state.token = token
+ },
+ SET_USER_INFO: (state, userInfo) => {
+ state.userInfo = userInfo
+ storage.set(constant.userInfo, userInfo)
+ },
+ SET_LOGIN_INFO: (state, loginInfo) => {
+ state.loginInfo = loginInfo
+ storage.set(constant.loginInfo, loginInfo)
+ },
+ SET_NAME: (state, name) => {
+ state.name = name
+ storage.set(constant.name, name)
+ },
+ SET_AVATAR: (state, avatar) => {
+ state.avatar = avatar
+ storage.set(constant.avatar, avatar)
+ }
+ },
+
+ actions: {
+ // 登录
+ Login({ commit }, userInfo) {
+ const loginType = userInfo.loginType
+ const userName = userInfo.userName
+ const password = userInfo.password
+ const smsCode = userInfo.smsCode
+ const registerFlag = userInfo.registerFlag
+ const code = userInfo.code
+ const uuid = userInfo.uuid
+ return new Promise((resolve, reject) => {
+ login(loginType, userName, password, smsCode, registerFlag, code, uuid).then(res => {
+ setToken(res.data.token)
+ commit('SET_TOKEN', res.data.token)
+ commit('SET_LOGIN_INFO', userInfo) // 保存登录信息,后续可以自动登录
+ resolve()
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+
+ // 获取用户信息
+ GetInfo({ commit, state }) {
+ return new Promise((resolve, reject) => {
+ getInfo().then(res => {
+ const user = res.data.user
+ const avatar = (user == null || user.avatar == "" || user.avatar == null) ? "/static/image/user/yy.png" : user.avatar
+ const userName = (user == null || user.userName == "" || user.userName == null) ? "" : user.userName
+ commit('SET_USER_INFO', user)
+ commit('SET_NAME', userName)
+ commit('SET_AVATAR', avatar)
+ resolve(res)
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+
+ // 退出系统
+ LogOut({ commit, state }) {
+ return new Promise((resolve, reject) => {
+ logout(state.token).then(() => {
+ commit('SET_TOKEN', '')
+ commit('SET_USER_INFO', {})
+ removeToken()
+ storage.clean()
+ resolve()
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ }
+ }
+}
+
+export default user
diff --git a/uni.scss b/uni.scss
new file mode 100644
index 0000000..b9249e9
--- /dev/null
+++ b/uni.scss
@@ -0,0 +1,76 @@
+/**
+ * 这里是uni-app内置的常用样式变量
+ *
+ * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
+ * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
+ *
+ */
+
+/**
+ * 如果你是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:#c8c7cc;
+
+/* 尺寸变量 */
+
+/* 文字尺寸 */
+$uni-font-size-sm:12px;
+$uni-font-size-base:14px;
+$uni-font-size-lg:16px;
+
+/* 图片尺寸 */
+$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/uni-icons/changelog.md b/uni_modules/uni-icons/changelog.md
new file mode 100644
index 0000000..0261131
--- /dev/null
+++ b/uni_modules/uni-icons/changelog.md
@@ -0,0 +1,42 @@
+## 2.0.10(2024-06-07)
+- 优化 uni-app x 中,size 属性的类型
+## 2.0.9(2024-01-12)
+fix: 修复图标大小默认值错误的问题
+## 2.0.8(2023-12-14)
+- 修复 项目未使用 ts 情况下,打包报错的bug
+## 2.0.7(2023-12-14)
+- 修复 size 属性为 string 时,不加单位导致尺寸异常的bug
+## 2.0.6(2023-12-11)
+- 优化 兼容老版本icon类型,如 top ,bottom 等
+## 2.0.5(2023-12-11)
+- 优化 兼容老版本icon类型,如 top ,bottom 等
+## 2.0.4(2023-12-06)
+- 优化 uni-app x 下示例项目图标排序
+## 2.0.3(2023-12-06)
+- 修复 nvue下引入组件报错的bug
+## 2.0.2(2023-12-05)
+-优化 size 属性支持单位
+## 2.0.1(2023-12-05)
+- 新增 uni-app x 支持定义图标
+## 1.3.5(2022-01-24)
+- 优化 size 属性可以传入不带单位的字符串数值
+## 1.3.4(2022-01-24)
+- 优化 size 支持其他单位
+## 1.3.3(2022-01-17)
+- 修复 nvue 有些图标不显示的bug,兼容老版本图标
+## 1.3.2(2021-12-01)
+- 优化 示例可复制图标名称
+## 1.3.1(2021-11-23)
+- 优化 兼容旧组件 type 值
+## 1.3.0(2021-11-19)
+- 新增 更多图标
+- 优化 自定义图标使用方式
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-icons](https://uniapp.dcloud.io/component/uniui/uni-icons)
+## 1.1.7(2021-11-08)
+## 1.2.0(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.1.5(2021-05-12)
+- 新增 组件示例地址
+## 1.1.4(2021-02-05)
+- 调整为uni_modules目录规范
diff --git a/uni_modules/uni-icons/components/uni-icons/uni-icons.uvue b/uni_modules/uni-icons/components/uni-icons/uni-icons.uvue
new file mode 100644
index 0000000..8740559
--- /dev/null
+++ b/uni_modules/uni-icons/components/uni-icons/uni-icons.uvue
@@ -0,0 +1,91 @@
+
+
+ {{unicode}}
+
+
+
+
+
+
diff --git a/uni_modules/uni-icons/components/uni-icons/uni-icons.vue b/uni_modules/uni-icons/components/uni-icons/uni-icons.vue
new file mode 100644
index 0000000..7da5356
--- /dev/null
+++ b/uni_modules/uni-icons/components/uni-icons/uni-icons.vue
@@ -0,0 +1,110 @@
+
+
+ {{unicode}}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-icons/components/uni-icons/uniicons.css b/uni_modules/uni-icons/components/uni-icons/uniicons.css
new file mode 100644
index 0000000..0a6b6fe
--- /dev/null
+++ b/uni_modules/uni-icons/components/uni-icons/uniicons.css
@@ -0,0 +1,664 @@
+
+.uniui-cart-filled:before {
+ content: "\e6d0";
+}
+
+.uniui-gift-filled:before {
+ content: "\e6c4";
+}
+
+.uniui-color:before {
+ content: "\e6cf";
+}
+
+.uniui-wallet:before {
+ content: "\e6b1";
+}
+
+.uniui-settings-filled:before {
+ content: "\e6ce";
+}
+
+.uniui-auth-filled:before {
+ content: "\e6cc";
+}
+
+.uniui-shop-filled:before {
+ content: "\e6cd";
+}
+
+.uniui-staff-filled:before {
+ content: "\e6cb";
+}
+
+.uniui-vip-filled:before {
+ content: "\e6c6";
+}
+
+.uniui-plus-filled:before {
+ content: "\e6c7";
+}
+
+.uniui-folder-add-filled:before {
+ content: "\e6c8";
+}
+
+.uniui-color-filled:before {
+ content: "\e6c9";
+}
+
+.uniui-tune-filled:before {
+ content: "\e6ca";
+}
+
+.uniui-calendar-filled:before {
+ content: "\e6c0";
+}
+
+.uniui-notification-filled:before {
+ content: "\e6c1";
+}
+
+.uniui-wallet-filled:before {
+ content: "\e6c2";
+}
+
+.uniui-medal-filled:before {
+ content: "\e6c3";
+}
+
+.uniui-fire-filled:before {
+ content: "\e6c5";
+}
+
+.uniui-refreshempty:before {
+ content: "\e6bf";
+}
+
+.uniui-location-filled:before {
+ content: "\e6af";
+}
+
+.uniui-person-filled:before {
+ content: "\e69d";
+}
+
+.uniui-personadd-filled:before {
+ content: "\e698";
+}
+
+.uniui-arrowthinleft:before {
+ content: "\e6d2";
+}
+
+.uniui-arrowthinup:before {
+ content: "\e6d3";
+}
+
+.uniui-arrowthindown:before {
+ content: "\e6d4";
+}
+
+.uniui-back:before {
+ content: "\e6b9";
+}
+
+.uniui-forward:before {
+ content: "\e6ba";
+}
+
+.uniui-arrow-right:before {
+ content: "\e6bb";
+}
+
+.uniui-arrow-left:before {
+ content: "\e6bc";
+}
+
+.uniui-arrow-up:before {
+ content: "\e6bd";
+}
+
+.uniui-arrow-down:before {
+ content: "\e6be";
+}
+
+.uniui-arrowthinright:before {
+ content: "\e6d1";
+}
+
+.uniui-down:before {
+ content: "\e6b8";
+}
+
+.uniui-bottom:before {
+ content: "\e6b8";
+}
+
+.uniui-arrowright:before {
+ content: "\e6d5";
+}
+
+.uniui-right:before {
+ content: "\e6b5";
+}
+
+.uniui-up:before {
+ content: "\e6b6";
+}
+
+.uniui-top:before {
+ content: "\e6b6";
+}
+
+.uniui-left:before {
+ content: "\e6b7";
+}
+
+.uniui-arrowup:before {
+ content: "\e6d6";
+}
+
+.uniui-eye:before {
+ content: "\e651";
+}
+
+.uniui-eye-filled:before {
+ content: "\e66a";
+}
+
+.uniui-eye-slash:before {
+ content: "\e6b3";
+}
+
+.uniui-eye-slash-filled:before {
+ content: "\e6b4";
+}
+
+.uniui-info-filled:before {
+ content: "\e649";
+}
+
+.uniui-reload:before {
+ content: "\e6b2";
+}
+
+.uniui-micoff-filled:before {
+ content: "\e6b0";
+}
+
+.uniui-map-pin-ellipse:before {
+ content: "\e6ac";
+}
+
+.uniui-map-pin:before {
+ content: "\e6ad";
+}
+
+.uniui-location:before {
+ content: "\e6ae";
+}
+
+.uniui-starhalf:before {
+ content: "\e683";
+}
+
+.uniui-star:before {
+ content: "\e688";
+}
+
+.uniui-star-filled:before {
+ content: "\e68f";
+}
+
+.uniui-calendar:before {
+ content: "\e6a0";
+}
+
+.uniui-fire:before {
+ content: "\e6a1";
+}
+
+.uniui-medal:before {
+ content: "\e6a2";
+}
+
+.uniui-font:before {
+ content: "\e6a3";
+}
+
+.uniui-gift:before {
+ content: "\e6a4";
+}
+
+.uniui-link:before {
+ content: "\e6a5";
+}
+
+.uniui-notification:before {
+ content: "\e6a6";
+}
+
+.uniui-staff:before {
+ content: "\e6a7";
+}
+
+.uniui-vip:before {
+ content: "\e6a8";
+}
+
+.uniui-folder-add:before {
+ content: "\e6a9";
+}
+
+.uniui-tune:before {
+ content: "\e6aa";
+}
+
+.uniui-auth:before {
+ content: "\e6ab";
+}
+
+.uniui-person:before {
+ content: "\e699";
+}
+
+.uniui-email-filled:before {
+ content: "\e69a";
+}
+
+.uniui-phone-filled:before {
+ content: "\e69b";
+}
+
+.uniui-phone:before {
+ content: "\e69c";
+}
+
+.uniui-email:before {
+ content: "\e69e";
+}
+
+.uniui-personadd:before {
+ content: "\e69f";
+}
+
+.uniui-chatboxes-filled:before {
+ content: "\e692";
+}
+
+.uniui-contact:before {
+ content: "\e693";
+}
+
+.uniui-chatbubble-filled:before {
+ content: "\e694";
+}
+
+.uniui-contact-filled:before {
+ content: "\e695";
+}
+
+.uniui-chatboxes:before {
+ content: "\e696";
+}
+
+.uniui-chatbubble:before {
+ content: "\e697";
+}
+
+.uniui-upload-filled:before {
+ content: "\e68e";
+}
+
+.uniui-upload:before {
+ content: "\e690";
+}
+
+.uniui-weixin:before {
+ content: "\e691";
+}
+
+.uniui-compose:before {
+ content: "\e67f";
+}
+
+.uniui-qq:before {
+ content: "\e680";
+}
+
+.uniui-download-filled:before {
+ content: "\e681";
+}
+
+.uniui-pyq:before {
+ content: "\e682";
+}
+
+.uniui-sound:before {
+ content: "\e684";
+}
+
+.uniui-trash-filled:before {
+ content: "\e685";
+}
+
+.uniui-sound-filled:before {
+ content: "\e686";
+}
+
+.uniui-trash:before {
+ content: "\e687";
+}
+
+.uniui-videocam-filled:before {
+ content: "\e689";
+}
+
+.uniui-spinner-cycle:before {
+ content: "\e68a";
+}
+
+.uniui-weibo:before {
+ content: "\e68b";
+}
+
+.uniui-videocam:before {
+ content: "\e68c";
+}
+
+.uniui-download:before {
+ content: "\e68d";
+}
+
+.uniui-help:before {
+ content: "\e679";
+}
+
+.uniui-navigate-filled:before {
+ content: "\e67a";
+}
+
+.uniui-plusempty:before {
+ content: "\e67b";
+}
+
+.uniui-smallcircle:before {
+ content: "\e67c";
+}
+
+.uniui-minus-filled:before {
+ content: "\e67d";
+}
+
+.uniui-micoff:before {
+ content: "\e67e";
+}
+
+.uniui-closeempty:before {
+ content: "\e66c";
+}
+
+.uniui-clear:before {
+ content: "\e66d";
+}
+
+.uniui-navigate:before {
+ content: "\e66e";
+}
+
+.uniui-minus:before {
+ content: "\e66f";
+}
+
+.uniui-image:before {
+ content: "\e670";
+}
+
+.uniui-mic:before {
+ content: "\e671";
+}
+
+.uniui-paperplane:before {
+ content: "\e672";
+}
+
+.uniui-close:before {
+ content: "\e673";
+}
+
+.uniui-help-filled:before {
+ content: "\e674";
+}
+
+.uniui-paperplane-filled:before {
+ content: "\e675";
+}
+
+.uniui-plus:before {
+ content: "\e676";
+}
+
+.uniui-mic-filled:before {
+ content: "\e677";
+}
+
+.uniui-image-filled:before {
+ content: "\e678";
+}
+
+.uniui-locked-filled:before {
+ content: "\e668";
+}
+
+.uniui-info:before {
+ content: "\e669";
+}
+
+.uniui-locked:before {
+ content: "\e66b";
+}
+
+.uniui-camera-filled:before {
+ content: "\e658";
+}
+
+.uniui-chat-filled:before {
+ content: "\e659";
+}
+
+.uniui-camera:before {
+ content: "\e65a";
+}
+
+.uniui-circle:before {
+ content: "\e65b";
+}
+
+.uniui-checkmarkempty:before {
+ content: "\e65c";
+}
+
+.uniui-chat:before {
+ content: "\e65d";
+}
+
+.uniui-circle-filled:before {
+ content: "\e65e";
+}
+
+.uniui-flag:before {
+ content: "\e65f";
+}
+
+.uniui-flag-filled:before {
+ content: "\e660";
+}
+
+.uniui-gear-filled:before {
+ content: "\e661";
+}
+
+.uniui-home:before {
+ content: "\e662";
+}
+
+.uniui-home-filled:before {
+ content: "\e663";
+}
+
+.uniui-gear:before {
+ content: "\e664";
+}
+
+.uniui-smallcircle-filled:before {
+ content: "\e665";
+}
+
+.uniui-map-filled:before {
+ content: "\e666";
+}
+
+.uniui-map:before {
+ content: "\e667";
+}
+
+.uniui-refresh-filled:before {
+ content: "\e656";
+}
+
+.uniui-refresh:before {
+ content: "\e657";
+}
+
+.uniui-cloud-upload:before {
+ content: "\e645";
+}
+
+.uniui-cloud-download-filled:before {
+ content: "\e646";
+}
+
+.uniui-cloud-download:before {
+ content: "\e647";
+}
+
+.uniui-cloud-upload-filled:before {
+ content: "\e648";
+}
+
+.uniui-redo:before {
+ content: "\e64a";
+}
+
+.uniui-images-filled:before {
+ content: "\e64b";
+}
+
+.uniui-undo-filled:before {
+ content: "\e64c";
+}
+
+.uniui-more:before {
+ content: "\e64d";
+}
+
+.uniui-more-filled:before {
+ content: "\e64e";
+}
+
+.uniui-undo:before {
+ content: "\e64f";
+}
+
+.uniui-images:before {
+ content: "\e650";
+}
+
+.uniui-paperclip:before {
+ content: "\e652";
+}
+
+.uniui-settings:before {
+ content: "\e653";
+}
+
+.uniui-search:before {
+ content: "\e654";
+}
+
+.uniui-redo-filled:before {
+ content: "\e655";
+}
+
+.uniui-list:before {
+ content: "\e644";
+}
+
+.uniui-mail-open-filled:before {
+ content: "\e63a";
+}
+
+.uniui-hand-down-filled:before {
+ content: "\e63c";
+}
+
+.uniui-hand-down:before {
+ content: "\e63d";
+}
+
+.uniui-hand-up-filled:before {
+ content: "\e63e";
+}
+
+.uniui-hand-up:before {
+ content: "\e63f";
+}
+
+.uniui-heart-filled:before {
+ content: "\e641";
+}
+
+.uniui-mail-open:before {
+ content: "\e643";
+}
+
+.uniui-heart:before {
+ content: "\e639";
+}
+
+.uniui-loop:before {
+ content: "\e633";
+}
+
+.uniui-pulldown:before {
+ content: "\e632";
+}
+
+.uniui-scan:before {
+ content: "\e62a";
+}
+
+.uniui-bars:before {
+ content: "\e627";
+}
+
+.uniui-checkbox:before {
+ content: "\e62b";
+}
+
+.uniui-checkbox-filled:before {
+ content: "\e62c";
+}
+
+.uniui-shop:before {
+ content: "\e62f";
+}
+
+.uniui-headphones:before {
+ content: "\e630";
+}
+
+.uniui-cart:before {
+ content: "\e631";
+}
diff --git a/uni_modules/uni-icons/components/uni-icons/uniicons.ttf b/uni_modules/uni-icons/components/uni-icons/uniicons.ttf
new file mode 100644
index 0000000..14696d0
Binary files /dev/null and b/uni_modules/uni-icons/components/uni-icons/uniicons.ttf differ
diff --git a/uni_modules/uni-icons/components/uni-icons/uniicons_file.ts b/uni_modules/uni-icons/components/uni-icons/uniicons_file.ts
new file mode 100644
index 0000000..98e93aa
--- /dev/null
+++ b/uni_modules/uni-icons/components/uni-icons/uniicons_file.ts
@@ -0,0 +1,664 @@
+
+export type IconsData = {
+ id : string
+ name : string
+ font_family : string
+ css_prefix_text : string
+ description : string
+ glyphs : Array
+}
+
+export type IconsDataItem = {
+ font_class : string
+ unicode : string
+}
+
+
+export const fontData = [
+ {
+ "font_class": "arrow-down",
+ "unicode": "\ue6be"
+ },
+ {
+ "font_class": "arrow-left",
+ "unicode": "\ue6bc"
+ },
+ {
+ "font_class": "arrow-right",
+ "unicode": "\ue6bb"
+ },
+ {
+ "font_class": "arrow-up",
+ "unicode": "\ue6bd"
+ },
+ {
+ "font_class": "auth",
+ "unicode": "\ue6ab"
+ },
+ {
+ "font_class": "auth-filled",
+ "unicode": "\ue6cc"
+ },
+ {
+ "font_class": "back",
+ "unicode": "\ue6b9"
+ },
+ {
+ "font_class": "bars",
+ "unicode": "\ue627"
+ },
+ {
+ "font_class": "calendar",
+ "unicode": "\ue6a0"
+ },
+ {
+ "font_class": "calendar-filled",
+ "unicode": "\ue6c0"
+ },
+ {
+ "font_class": "camera",
+ "unicode": "\ue65a"
+ },
+ {
+ "font_class": "camera-filled",
+ "unicode": "\ue658"
+ },
+ {
+ "font_class": "cart",
+ "unicode": "\ue631"
+ },
+ {
+ "font_class": "cart-filled",
+ "unicode": "\ue6d0"
+ },
+ {
+ "font_class": "chat",
+ "unicode": "\ue65d"
+ },
+ {
+ "font_class": "chat-filled",
+ "unicode": "\ue659"
+ },
+ {
+ "font_class": "chatboxes",
+ "unicode": "\ue696"
+ },
+ {
+ "font_class": "chatboxes-filled",
+ "unicode": "\ue692"
+ },
+ {
+ "font_class": "chatbubble",
+ "unicode": "\ue697"
+ },
+ {
+ "font_class": "chatbubble-filled",
+ "unicode": "\ue694"
+ },
+ {
+ "font_class": "checkbox",
+ "unicode": "\ue62b"
+ },
+ {
+ "font_class": "checkbox-filled",
+ "unicode": "\ue62c"
+ },
+ {
+ "font_class": "checkmarkempty",
+ "unicode": "\ue65c"
+ },
+ {
+ "font_class": "circle",
+ "unicode": "\ue65b"
+ },
+ {
+ "font_class": "circle-filled",
+ "unicode": "\ue65e"
+ },
+ {
+ "font_class": "clear",
+ "unicode": "\ue66d"
+ },
+ {
+ "font_class": "close",
+ "unicode": "\ue673"
+ },
+ {
+ "font_class": "closeempty",
+ "unicode": "\ue66c"
+ },
+ {
+ "font_class": "cloud-download",
+ "unicode": "\ue647"
+ },
+ {
+ "font_class": "cloud-download-filled",
+ "unicode": "\ue646"
+ },
+ {
+ "font_class": "cloud-upload",
+ "unicode": "\ue645"
+ },
+ {
+ "font_class": "cloud-upload-filled",
+ "unicode": "\ue648"
+ },
+ {
+ "font_class": "color",
+ "unicode": "\ue6cf"
+ },
+ {
+ "font_class": "color-filled",
+ "unicode": "\ue6c9"
+ },
+ {
+ "font_class": "compose",
+ "unicode": "\ue67f"
+ },
+ {
+ "font_class": "contact",
+ "unicode": "\ue693"
+ },
+ {
+ "font_class": "contact-filled",
+ "unicode": "\ue695"
+ },
+ {
+ "font_class": "down",
+ "unicode": "\ue6b8"
+ },
+ {
+ "font_class": "bottom",
+ "unicode": "\ue6b8"
+ },
+ {
+ "font_class": "download",
+ "unicode": "\ue68d"
+ },
+ {
+ "font_class": "download-filled",
+ "unicode": "\ue681"
+ },
+ {
+ "font_class": "email",
+ "unicode": "\ue69e"
+ },
+ {
+ "font_class": "email-filled",
+ "unicode": "\ue69a"
+ },
+ {
+ "font_class": "eye",
+ "unicode": "\ue651"
+ },
+ {
+ "font_class": "eye-filled",
+ "unicode": "\ue66a"
+ },
+ {
+ "font_class": "eye-slash",
+ "unicode": "\ue6b3"
+ },
+ {
+ "font_class": "eye-slash-filled",
+ "unicode": "\ue6b4"
+ },
+ {
+ "font_class": "fire",
+ "unicode": "\ue6a1"
+ },
+ {
+ "font_class": "fire-filled",
+ "unicode": "\ue6c5"
+ },
+ {
+ "font_class": "flag",
+ "unicode": "\ue65f"
+ },
+ {
+ "font_class": "flag-filled",
+ "unicode": "\ue660"
+ },
+ {
+ "font_class": "folder-add",
+ "unicode": "\ue6a9"
+ },
+ {
+ "font_class": "folder-add-filled",
+ "unicode": "\ue6c8"
+ },
+ {
+ "font_class": "font",
+ "unicode": "\ue6a3"
+ },
+ {
+ "font_class": "forward",
+ "unicode": "\ue6ba"
+ },
+ {
+ "font_class": "gear",
+ "unicode": "\ue664"
+ },
+ {
+ "font_class": "gear-filled",
+ "unicode": "\ue661"
+ },
+ {
+ "font_class": "gift",
+ "unicode": "\ue6a4"
+ },
+ {
+ "font_class": "gift-filled",
+ "unicode": "\ue6c4"
+ },
+ {
+ "font_class": "hand-down",
+ "unicode": "\ue63d"
+ },
+ {
+ "font_class": "hand-down-filled",
+ "unicode": "\ue63c"
+ },
+ {
+ "font_class": "hand-up",
+ "unicode": "\ue63f"
+ },
+ {
+ "font_class": "hand-up-filled",
+ "unicode": "\ue63e"
+ },
+ {
+ "font_class": "headphones",
+ "unicode": "\ue630"
+ },
+ {
+ "font_class": "heart",
+ "unicode": "\ue639"
+ },
+ {
+ "font_class": "heart-filled",
+ "unicode": "\ue641"
+ },
+ {
+ "font_class": "help",
+ "unicode": "\ue679"
+ },
+ {
+ "font_class": "help-filled",
+ "unicode": "\ue674"
+ },
+ {
+ "font_class": "home",
+ "unicode": "\ue662"
+ },
+ {
+ "font_class": "home-filled",
+ "unicode": "\ue663"
+ },
+ {
+ "font_class": "image",
+ "unicode": "\ue670"
+ },
+ {
+ "font_class": "image-filled",
+ "unicode": "\ue678"
+ },
+ {
+ "font_class": "images",
+ "unicode": "\ue650"
+ },
+ {
+ "font_class": "images-filled",
+ "unicode": "\ue64b"
+ },
+ {
+ "font_class": "info",
+ "unicode": "\ue669"
+ },
+ {
+ "font_class": "info-filled",
+ "unicode": "\ue649"
+ },
+ {
+ "font_class": "left",
+ "unicode": "\ue6b7"
+ },
+ {
+ "font_class": "link",
+ "unicode": "\ue6a5"
+ },
+ {
+ "font_class": "list",
+ "unicode": "\ue644"
+ },
+ {
+ "font_class": "location",
+ "unicode": "\ue6ae"
+ },
+ {
+ "font_class": "location-filled",
+ "unicode": "\ue6af"
+ },
+ {
+ "font_class": "locked",
+ "unicode": "\ue66b"
+ },
+ {
+ "font_class": "locked-filled",
+ "unicode": "\ue668"
+ },
+ {
+ "font_class": "loop",
+ "unicode": "\ue633"
+ },
+ {
+ "font_class": "mail-open",
+ "unicode": "\ue643"
+ },
+ {
+ "font_class": "mail-open-filled",
+ "unicode": "\ue63a"
+ },
+ {
+ "font_class": "map",
+ "unicode": "\ue667"
+ },
+ {
+ "font_class": "map-filled",
+ "unicode": "\ue666"
+ },
+ {
+ "font_class": "map-pin",
+ "unicode": "\ue6ad"
+ },
+ {
+ "font_class": "map-pin-ellipse",
+ "unicode": "\ue6ac"
+ },
+ {
+ "font_class": "medal",
+ "unicode": "\ue6a2"
+ },
+ {
+ "font_class": "medal-filled",
+ "unicode": "\ue6c3"
+ },
+ {
+ "font_class": "mic",
+ "unicode": "\ue671"
+ },
+ {
+ "font_class": "mic-filled",
+ "unicode": "\ue677"
+ },
+ {
+ "font_class": "micoff",
+ "unicode": "\ue67e"
+ },
+ {
+ "font_class": "micoff-filled",
+ "unicode": "\ue6b0"
+ },
+ {
+ "font_class": "minus",
+ "unicode": "\ue66f"
+ },
+ {
+ "font_class": "minus-filled",
+ "unicode": "\ue67d"
+ },
+ {
+ "font_class": "more",
+ "unicode": "\ue64d"
+ },
+ {
+ "font_class": "more-filled",
+ "unicode": "\ue64e"
+ },
+ {
+ "font_class": "navigate",
+ "unicode": "\ue66e"
+ },
+ {
+ "font_class": "navigate-filled",
+ "unicode": "\ue67a"
+ },
+ {
+ "font_class": "notification",
+ "unicode": "\ue6a6"
+ },
+ {
+ "font_class": "notification-filled",
+ "unicode": "\ue6c1"
+ },
+ {
+ "font_class": "paperclip",
+ "unicode": "\ue652"
+ },
+ {
+ "font_class": "paperplane",
+ "unicode": "\ue672"
+ },
+ {
+ "font_class": "paperplane-filled",
+ "unicode": "\ue675"
+ },
+ {
+ "font_class": "person",
+ "unicode": "\ue699"
+ },
+ {
+ "font_class": "person-filled",
+ "unicode": "\ue69d"
+ },
+ {
+ "font_class": "personadd",
+ "unicode": "\ue69f"
+ },
+ {
+ "font_class": "personadd-filled",
+ "unicode": "\ue698"
+ },
+ {
+ "font_class": "personadd-filled-copy",
+ "unicode": "\ue6d1"
+ },
+ {
+ "font_class": "phone",
+ "unicode": "\ue69c"
+ },
+ {
+ "font_class": "phone-filled",
+ "unicode": "\ue69b"
+ },
+ {
+ "font_class": "plus",
+ "unicode": "\ue676"
+ },
+ {
+ "font_class": "plus-filled",
+ "unicode": "\ue6c7"
+ },
+ {
+ "font_class": "plusempty",
+ "unicode": "\ue67b"
+ },
+ {
+ "font_class": "pulldown",
+ "unicode": "\ue632"
+ },
+ {
+ "font_class": "pyq",
+ "unicode": "\ue682"
+ },
+ {
+ "font_class": "qq",
+ "unicode": "\ue680"
+ },
+ {
+ "font_class": "redo",
+ "unicode": "\ue64a"
+ },
+ {
+ "font_class": "redo-filled",
+ "unicode": "\ue655"
+ },
+ {
+ "font_class": "refresh",
+ "unicode": "\ue657"
+ },
+ {
+ "font_class": "refresh-filled",
+ "unicode": "\ue656"
+ },
+ {
+ "font_class": "refreshempty",
+ "unicode": "\ue6bf"
+ },
+ {
+ "font_class": "reload",
+ "unicode": "\ue6b2"
+ },
+ {
+ "font_class": "right",
+ "unicode": "\ue6b5"
+ },
+ {
+ "font_class": "scan",
+ "unicode": "\ue62a"
+ },
+ {
+ "font_class": "search",
+ "unicode": "\ue654"
+ },
+ {
+ "font_class": "settings",
+ "unicode": "\ue653"
+ },
+ {
+ "font_class": "settings-filled",
+ "unicode": "\ue6ce"
+ },
+ {
+ "font_class": "shop",
+ "unicode": "\ue62f"
+ },
+ {
+ "font_class": "shop-filled",
+ "unicode": "\ue6cd"
+ },
+ {
+ "font_class": "smallcircle",
+ "unicode": "\ue67c"
+ },
+ {
+ "font_class": "smallcircle-filled",
+ "unicode": "\ue665"
+ },
+ {
+ "font_class": "sound",
+ "unicode": "\ue684"
+ },
+ {
+ "font_class": "sound-filled",
+ "unicode": "\ue686"
+ },
+ {
+ "font_class": "spinner-cycle",
+ "unicode": "\ue68a"
+ },
+ {
+ "font_class": "staff",
+ "unicode": "\ue6a7"
+ },
+ {
+ "font_class": "staff-filled",
+ "unicode": "\ue6cb"
+ },
+ {
+ "font_class": "star",
+ "unicode": "\ue688"
+ },
+ {
+ "font_class": "star-filled",
+ "unicode": "\ue68f"
+ },
+ {
+ "font_class": "starhalf",
+ "unicode": "\ue683"
+ },
+ {
+ "font_class": "trash",
+ "unicode": "\ue687"
+ },
+ {
+ "font_class": "trash-filled",
+ "unicode": "\ue685"
+ },
+ {
+ "font_class": "tune",
+ "unicode": "\ue6aa"
+ },
+ {
+ "font_class": "tune-filled",
+ "unicode": "\ue6ca"
+ },
+ {
+ "font_class": "undo",
+ "unicode": "\ue64f"
+ },
+ {
+ "font_class": "undo-filled",
+ "unicode": "\ue64c"
+ },
+ {
+ "font_class": "up",
+ "unicode": "\ue6b6"
+ },
+ {
+ "font_class": "top",
+ "unicode": "\ue6b6"
+ },
+ {
+ "font_class": "upload",
+ "unicode": "\ue690"
+ },
+ {
+ "font_class": "upload-filled",
+ "unicode": "\ue68e"
+ },
+ {
+ "font_class": "videocam",
+ "unicode": "\ue68c"
+ },
+ {
+ "font_class": "videocam-filled",
+ "unicode": "\ue689"
+ },
+ {
+ "font_class": "vip",
+ "unicode": "\ue6a8"
+ },
+ {
+ "font_class": "vip-filled",
+ "unicode": "\ue6c6"
+ },
+ {
+ "font_class": "wallet",
+ "unicode": "\ue6b1"
+ },
+ {
+ "font_class": "wallet-filled",
+ "unicode": "\ue6c2"
+ },
+ {
+ "font_class": "weibo",
+ "unicode": "\ue68b"
+ },
+ {
+ "font_class": "weixin",
+ "unicode": "\ue691"
+ }
+] as IconsDataItem[]
+
+// export const fontData = JSON.parse(fontDataJson)
diff --git a/uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js b/uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js
new file mode 100644
index 0000000..1cd11e1
--- /dev/null
+++ b/uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js
@@ -0,0 +1,649 @@
+
+export const fontData = [
+ {
+ "font_class": "arrow-down",
+ "unicode": "\ue6be"
+ },
+ {
+ "font_class": "arrow-left",
+ "unicode": "\ue6bc"
+ },
+ {
+ "font_class": "arrow-right",
+ "unicode": "\ue6bb"
+ },
+ {
+ "font_class": "arrow-up",
+ "unicode": "\ue6bd"
+ },
+ {
+ "font_class": "auth",
+ "unicode": "\ue6ab"
+ },
+ {
+ "font_class": "auth-filled",
+ "unicode": "\ue6cc"
+ },
+ {
+ "font_class": "back",
+ "unicode": "\ue6b9"
+ },
+ {
+ "font_class": "bars",
+ "unicode": "\ue627"
+ },
+ {
+ "font_class": "calendar",
+ "unicode": "\ue6a0"
+ },
+ {
+ "font_class": "calendar-filled",
+ "unicode": "\ue6c0"
+ },
+ {
+ "font_class": "camera",
+ "unicode": "\ue65a"
+ },
+ {
+ "font_class": "camera-filled",
+ "unicode": "\ue658"
+ },
+ {
+ "font_class": "cart",
+ "unicode": "\ue631"
+ },
+ {
+ "font_class": "cart-filled",
+ "unicode": "\ue6d0"
+ },
+ {
+ "font_class": "chat",
+ "unicode": "\ue65d"
+ },
+ {
+ "font_class": "chat-filled",
+ "unicode": "\ue659"
+ },
+ {
+ "font_class": "chatboxes",
+ "unicode": "\ue696"
+ },
+ {
+ "font_class": "chatboxes-filled",
+ "unicode": "\ue692"
+ },
+ {
+ "font_class": "chatbubble",
+ "unicode": "\ue697"
+ },
+ {
+ "font_class": "chatbubble-filled",
+ "unicode": "\ue694"
+ },
+ {
+ "font_class": "checkbox",
+ "unicode": "\ue62b"
+ },
+ {
+ "font_class": "checkbox-filled",
+ "unicode": "\ue62c"
+ },
+ {
+ "font_class": "checkmarkempty",
+ "unicode": "\ue65c"
+ },
+ {
+ "font_class": "circle",
+ "unicode": "\ue65b"
+ },
+ {
+ "font_class": "circle-filled",
+ "unicode": "\ue65e"
+ },
+ {
+ "font_class": "clear",
+ "unicode": "\ue66d"
+ },
+ {
+ "font_class": "close",
+ "unicode": "\ue673"
+ },
+ {
+ "font_class": "closeempty",
+ "unicode": "\ue66c"
+ },
+ {
+ "font_class": "cloud-download",
+ "unicode": "\ue647"
+ },
+ {
+ "font_class": "cloud-download-filled",
+ "unicode": "\ue646"
+ },
+ {
+ "font_class": "cloud-upload",
+ "unicode": "\ue645"
+ },
+ {
+ "font_class": "cloud-upload-filled",
+ "unicode": "\ue648"
+ },
+ {
+ "font_class": "color",
+ "unicode": "\ue6cf"
+ },
+ {
+ "font_class": "color-filled",
+ "unicode": "\ue6c9"
+ },
+ {
+ "font_class": "compose",
+ "unicode": "\ue67f"
+ },
+ {
+ "font_class": "contact",
+ "unicode": "\ue693"
+ },
+ {
+ "font_class": "contact-filled",
+ "unicode": "\ue695"
+ },
+ {
+ "font_class": "down",
+ "unicode": "\ue6b8"
+ },
+ {
+ "font_class": "bottom",
+ "unicode": "\ue6b8"
+ },
+ {
+ "font_class": "download",
+ "unicode": "\ue68d"
+ },
+ {
+ "font_class": "download-filled",
+ "unicode": "\ue681"
+ },
+ {
+ "font_class": "email",
+ "unicode": "\ue69e"
+ },
+ {
+ "font_class": "email-filled",
+ "unicode": "\ue69a"
+ },
+ {
+ "font_class": "eye",
+ "unicode": "\ue651"
+ },
+ {
+ "font_class": "eye-filled",
+ "unicode": "\ue66a"
+ },
+ {
+ "font_class": "eye-slash",
+ "unicode": "\ue6b3"
+ },
+ {
+ "font_class": "eye-slash-filled",
+ "unicode": "\ue6b4"
+ },
+ {
+ "font_class": "fire",
+ "unicode": "\ue6a1"
+ },
+ {
+ "font_class": "fire-filled",
+ "unicode": "\ue6c5"
+ },
+ {
+ "font_class": "flag",
+ "unicode": "\ue65f"
+ },
+ {
+ "font_class": "flag-filled",
+ "unicode": "\ue660"
+ },
+ {
+ "font_class": "folder-add",
+ "unicode": "\ue6a9"
+ },
+ {
+ "font_class": "folder-add-filled",
+ "unicode": "\ue6c8"
+ },
+ {
+ "font_class": "font",
+ "unicode": "\ue6a3"
+ },
+ {
+ "font_class": "forward",
+ "unicode": "\ue6ba"
+ },
+ {
+ "font_class": "gear",
+ "unicode": "\ue664"
+ },
+ {
+ "font_class": "gear-filled",
+ "unicode": "\ue661"
+ },
+ {
+ "font_class": "gift",
+ "unicode": "\ue6a4"
+ },
+ {
+ "font_class": "gift-filled",
+ "unicode": "\ue6c4"
+ },
+ {
+ "font_class": "hand-down",
+ "unicode": "\ue63d"
+ },
+ {
+ "font_class": "hand-down-filled",
+ "unicode": "\ue63c"
+ },
+ {
+ "font_class": "hand-up",
+ "unicode": "\ue63f"
+ },
+ {
+ "font_class": "hand-up-filled",
+ "unicode": "\ue63e"
+ },
+ {
+ "font_class": "headphones",
+ "unicode": "\ue630"
+ },
+ {
+ "font_class": "heart",
+ "unicode": "\ue639"
+ },
+ {
+ "font_class": "heart-filled",
+ "unicode": "\ue641"
+ },
+ {
+ "font_class": "help",
+ "unicode": "\ue679"
+ },
+ {
+ "font_class": "help-filled",
+ "unicode": "\ue674"
+ },
+ {
+ "font_class": "home",
+ "unicode": "\ue662"
+ },
+ {
+ "font_class": "home-filled",
+ "unicode": "\ue663"
+ },
+ {
+ "font_class": "image",
+ "unicode": "\ue670"
+ },
+ {
+ "font_class": "image-filled",
+ "unicode": "\ue678"
+ },
+ {
+ "font_class": "images",
+ "unicode": "\ue650"
+ },
+ {
+ "font_class": "images-filled",
+ "unicode": "\ue64b"
+ },
+ {
+ "font_class": "info",
+ "unicode": "\ue669"
+ },
+ {
+ "font_class": "info-filled",
+ "unicode": "\ue649"
+ },
+ {
+ "font_class": "left",
+ "unicode": "\ue6b7"
+ },
+ {
+ "font_class": "link",
+ "unicode": "\ue6a5"
+ },
+ {
+ "font_class": "list",
+ "unicode": "\ue644"
+ },
+ {
+ "font_class": "location",
+ "unicode": "\ue6ae"
+ },
+ {
+ "font_class": "location-filled",
+ "unicode": "\ue6af"
+ },
+ {
+ "font_class": "locked",
+ "unicode": "\ue66b"
+ },
+ {
+ "font_class": "locked-filled",
+ "unicode": "\ue668"
+ },
+ {
+ "font_class": "loop",
+ "unicode": "\ue633"
+ },
+ {
+ "font_class": "mail-open",
+ "unicode": "\ue643"
+ },
+ {
+ "font_class": "mail-open-filled",
+ "unicode": "\ue63a"
+ },
+ {
+ "font_class": "map",
+ "unicode": "\ue667"
+ },
+ {
+ "font_class": "map-filled",
+ "unicode": "\ue666"
+ },
+ {
+ "font_class": "map-pin",
+ "unicode": "\ue6ad"
+ },
+ {
+ "font_class": "map-pin-ellipse",
+ "unicode": "\ue6ac"
+ },
+ {
+ "font_class": "medal",
+ "unicode": "\ue6a2"
+ },
+ {
+ "font_class": "medal-filled",
+ "unicode": "\ue6c3"
+ },
+ {
+ "font_class": "mic",
+ "unicode": "\ue671"
+ },
+ {
+ "font_class": "mic-filled",
+ "unicode": "\ue677"
+ },
+ {
+ "font_class": "micoff",
+ "unicode": "\ue67e"
+ },
+ {
+ "font_class": "micoff-filled",
+ "unicode": "\ue6b0"
+ },
+ {
+ "font_class": "minus",
+ "unicode": "\ue66f"
+ },
+ {
+ "font_class": "minus-filled",
+ "unicode": "\ue67d"
+ },
+ {
+ "font_class": "more",
+ "unicode": "\ue64d"
+ },
+ {
+ "font_class": "more-filled",
+ "unicode": "\ue64e"
+ },
+ {
+ "font_class": "navigate",
+ "unicode": "\ue66e"
+ },
+ {
+ "font_class": "navigate-filled",
+ "unicode": "\ue67a"
+ },
+ {
+ "font_class": "notification",
+ "unicode": "\ue6a6"
+ },
+ {
+ "font_class": "notification-filled",
+ "unicode": "\ue6c1"
+ },
+ {
+ "font_class": "paperclip",
+ "unicode": "\ue652"
+ },
+ {
+ "font_class": "paperplane",
+ "unicode": "\ue672"
+ },
+ {
+ "font_class": "paperplane-filled",
+ "unicode": "\ue675"
+ },
+ {
+ "font_class": "person",
+ "unicode": "\ue699"
+ },
+ {
+ "font_class": "person-filled",
+ "unicode": "\ue69d"
+ },
+ {
+ "font_class": "personadd",
+ "unicode": "\ue69f"
+ },
+ {
+ "font_class": "personadd-filled",
+ "unicode": "\ue698"
+ },
+ {
+ "font_class": "personadd-filled-copy",
+ "unicode": "\ue6d1"
+ },
+ {
+ "font_class": "phone",
+ "unicode": "\ue69c"
+ },
+ {
+ "font_class": "phone-filled",
+ "unicode": "\ue69b"
+ },
+ {
+ "font_class": "plus",
+ "unicode": "\ue676"
+ },
+ {
+ "font_class": "plus-filled",
+ "unicode": "\ue6c7"
+ },
+ {
+ "font_class": "plusempty",
+ "unicode": "\ue67b"
+ },
+ {
+ "font_class": "pulldown",
+ "unicode": "\ue632"
+ },
+ {
+ "font_class": "pyq",
+ "unicode": "\ue682"
+ },
+ {
+ "font_class": "qq",
+ "unicode": "\ue680"
+ },
+ {
+ "font_class": "redo",
+ "unicode": "\ue64a"
+ },
+ {
+ "font_class": "redo-filled",
+ "unicode": "\ue655"
+ },
+ {
+ "font_class": "refresh",
+ "unicode": "\ue657"
+ },
+ {
+ "font_class": "refresh-filled",
+ "unicode": "\ue656"
+ },
+ {
+ "font_class": "refreshempty",
+ "unicode": "\ue6bf"
+ },
+ {
+ "font_class": "reload",
+ "unicode": "\ue6b2"
+ },
+ {
+ "font_class": "right",
+ "unicode": "\ue6b5"
+ },
+ {
+ "font_class": "scan",
+ "unicode": "\ue62a"
+ },
+ {
+ "font_class": "search",
+ "unicode": "\ue654"
+ },
+ {
+ "font_class": "settings",
+ "unicode": "\ue653"
+ },
+ {
+ "font_class": "settings-filled",
+ "unicode": "\ue6ce"
+ },
+ {
+ "font_class": "shop",
+ "unicode": "\ue62f"
+ },
+ {
+ "font_class": "shop-filled",
+ "unicode": "\ue6cd"
+ },
+ {
+ "font_class": "smallcircle",
+ "unicode": "\ue67c"
+ },
+ {
+ "font_class": "smallcircle-filled",
+ "unicode": "\ue665"
+ },
+ {
+ "font_class": "sound",
+ "unicode": "\ue684"
+ },
+ {
+ "font_class": "sound-filled",
+ "unicode": "\ue686"
+ },
+ {
+ "font_class": "spinner-cycle",
+ "unicode": "\ue68a"
+ },
+ {
+ "font_class": "staff",
+ "unicode": "\ue6a7"
+ },
+ {
+ "font_class": "staff-filled",
+ "unicode": "\ue6cb"
+ },
+ {
+ "font_class": "star",
+ "unicode": "\ue688"
+ },
+ {
+ "font_class": "star-filled",
+ "unicode": "\ue68f"
+ },
+ {
+ "font_class": "starhalf",
+ "unicode": "\ue683"
+ },
+ {
+ "font_class": "trash",
+ "unicode": "\ue687"
+ },
+ {
+ "font_class": "trash-filled",
+ "unicode": "\ue685"
+ },
+ {
+ "font_class": "tune",
+ "unicode": "\ue6aa"
+ },
+ {
+ "font_class": "tune-filled",
+ "unicode": "\ue6ca"
+ },
+ {
+ "font_class": "undo",
+ "unicode": "\ue64f"
+ },
+ {
+ "font_class": "undo-filled",
+ "unicode": "\ue64c"
+ },
+ {
+ "font_class": "up",
+ "unicode": "\ue6b6"
+ },
+ {
+ "font_class": "top",
+ "unicode": "\ue6b6"
+ },
+ {
+ "font_class": "upload",
+ "unicode": "\ue690"
+ },
+ {
+ "font_class": "upload-filled",
+ "unicode": "\ue68e"
+ },
+ {
+ "font_class": "videocam",
+ "unicode": "\ue68c"
+ },
+ {
+ "font_class": "videocam-filled",
+ "unicode": "\ue689"
+ },
+ {
+ "font_class": "vip",
+ "unicode": "\ue6a8"
+ },
+ {
+ "font_class": "vip-filled",
+ "unicode": "\ue6c6"
+ },
+ {
+ "font_class": "wallet",
+ "unicode": "\ue6b1"
+ },
+ {
+ "font_class": "wallet-filled",
+ "unicode": "\ue6c2"
+ },
+ {
+ "font_class": "weibo",
+ "unicode": "\ue68b"
+ },
+ {
+ "font_class": "weixin",
+ "unicode": "\ue691"
+ }
+]
+
+// export const fontData = JSON.parse(fontDataJson)
diff --git a/uni_modules/uni-icons/package.json b/uni_modules/uni-icons/package.json
new file mode 100644
index 0000000..6b681b4
--- /dev/null
+++ b/uni_modules/uni-icons/package.json
@@ -0,0 +1,89 @@
+{
+ "id": "uni-icons",
+ "displayName": "uni-icons 图标",
+ "version": "2.0.10",
+ "description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "icon",
+ "图标"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": "^3.2.14"
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+"dcloudext": {
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
+ "type": "component-vue"
+ },
+ "uni_modules": {
+ "dependencies": ["uni-scss"],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y",
+ "alipay": "n"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y",
+ "app-uvue": "y"
+ },
+ "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",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y",
+ "钉钉": "y",
+ "快手": "y",
+ "飞书": "y",
+ "京东": "y"
+ },
+ "快应用": {
+ "华为": "y",
+ "联盟": "y"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-icons/readme.md b/uni_modules/uni-icons/readme.md
new file mode 100644
index 0000000..86234ba
--- /dev/null
+++ b/uni_modules/uni-icons/readme.md
@@ -0,0 +1,8 @@
+## Icons 图标
+> **组件名:uni-icons**
+> 代码块: `uIcons`
+
+用于展示 icons 图标 。
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-icons)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
diff --git a/uni_modules/uni-scss/changelog.md b/uni_modules/uni-scss/changelog.md
new file mode 100644
index 0000000..b863bb0
--- /dev/null
+++ b/uni_modules/uni-scss/changelog.md
@@ -0,0 +1,8 @@
+## 1.0.3(2022-01-21)
+- 优化 组件示例
+## 1.0.2(2021-11-22)
+- 修复 / 符号在 vue 不同版本兼容问题引起的报错问题
+## 1.0.1(2021-11-22)
+- 修复 vue3中scss语法兼容问题
+## 1.0.0(2021-11-18)
+- init
diff --git a/uni_modules/uni-scss/index.scss b/uni_modules/uni-scss/index.scss
new file mode 100644
index 0000000..1744a5f
--- /dev/null
+++ b/uni_modules/uni-scss/index.scss
@@ -0,0 +1 @@
+@import './styles/index.scss';
diff --git a/uni_modules/uni-scss/package.json b/uni_modules/uni-scss/package.json
new file mode 100644
index 0000000..7cc0ccb
--- /dev/null
+++ b/uni_modules/uni-scss/package.json
@@ -0,0 +1,82 @@
+{
+ "id": "uni-scss",
+ "displayName": "uni-scss 辅助样式",
+ "version": "1.0.3",
+ "description": "uni-sass是uni-ui提供的一套全局样式 ,通过一些简单的类名和sass变量,实现简单的页面布局操作,比如颜色、边距、圆角等。",
+ "keywords": [
+ "uni-scss",
+ "uni-ui",
+ "辅助样式"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": "^3.1.0"
+ },
+ "dcloudext": {
+ "category": [
+ "JS SDK",
+ "通用 SDK"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "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",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "n",
+ "联盟": "n"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-scss/readme.md b/uni_modules/uni-scss/readme.md
new file mode 100644
index 0000000..b7d1c25
--- /dev/null
+++ b/uni_modules/uni-scss/readme.md
@@ -0,0 +1,4 @@
+`uni-sass` 是 `uni-ui`提供的一套全局样式 ,通过一些简单的类名和`sass`变量,实现简单的页面布局操作,比如颜色、边距、圆角等。
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-sass)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
diff --git a/uni_modules/uni-scss/styles/index.scss b/uni_modules/uni-scss/styles/index.scss
new file mode 100644
index 0000000..ffac4fe
--- /dev/null
+++ b/uni_modules/uni-scss/styles/index.scss
@@ -0,0 +1,7 @@
+@import './setting/_variables.scss';
+@import './setting/_border.scss';
+@import './setting/_color.scss';
+@import './setting/_space.scss';
+@import './setting/_radius.scss';
+@import './setting/_text.scss';
+@import './setting/_styles.scss';
diff --git a/uni_modules/uni-scss/styles/setting/_border.scss b/uni_modules/uni-scss/styles/setting/_border.scss
new file mode 100644
index 0000000..12a11c3
--- /dev/null
+++ b/uni_modules/uni-scss/styles/setting/_border.scss
@@ -0,0 +1,3 @@
+.uni-border {
+ border: 1px $uni-border-1 solid;
+}
\ No newline at end of file
diff --git a/uni_modules/uni-scss/styles/setting/_color.scss b/uni_modules/uni-scss/styles/setting/_color.scss
new file mode 100644
index 0000000..1ededd9
--- /dev/null
+++ b/uni_modules/uni-scss/styles/setting/_color.scss
@@ -0,0 +1,66 @@
+
+// TODO 暂时不需要 class ,需要用户使用变量实现 ,如果使用类名其实并不推荐
+// @mixin get-styles($k,$c) {
+// @if $k == size or $k == weight{
+// font-#{$k}:#{$c}
+// }@else{
+// #{$k}:#{$c}
+// }
+// }
+$uni-ui-color:(
+ // 主色
+ primary: $uni-primary,
+ primary-disable: $uni-primary-disable,
+ primary-light: $uni-primary-light,
+ // 辅助色
+ success: $uni-success,
+ success-disable: $uni-success-disable,
+ success-light: $uni-success-light,
+ warning: $uni-warning,
+ warning-disable: $uni-warning-disable,
+ warning-light: $uni-warning-light,
+ error: $uni-error,
+ error-disable: $uni-error-disable,
+ error-light: $uni-error-light,
+ info: $uni-info,
+ info-disable: $uni-info-disable,
+ info-light: $uni-info-light,
+ // 中性色
+ main-color: $uni-main-color,
+ base-color: $uni-base-color,
+ secondary-color: $uni-secondary-color,
+ extra-color: $uni-extra-color,
+ // 背景色
+ bg-color: $uni-bg-color,
+ // 边框颜色
+ border-1: $uni-border-1,
+ border-2: $uni-border-2,
+ border-3: $uni-border-3,
+ border-4: $uni-border-4,
+ // 黑色
+ black:$uni-black,
+ // 白色
+ white:$uni-white,
+ // 透明
+ transparent:$uni-transparent
+) !default;
+@each $key, $child in $uni-ui-color {
+ .uni-#{"" + $key} {
+ color: $child;
+ }
+ .uni-#{"" + $key}-bg {
+ background-color: $child;
+ }
+}
+.uni-shadow-sm {
+ box-shadow: $uni-shadow-sm;
+}
+.uni-shadow-base {
+ box-shadow: $uni-shadow-base;
+}
+.uni-shadow-lg {
+ box-shadow: $uni-shadow-lg;
+}
+.uni-mask {
+ background-color:$uni-mask;
+}
diff --git a/uni_modules/uni-scss/styles/setting/_radius.scss b/uni_modules/uni-scss/styles/setting/_radius.scss
new file mode 100644
index 0000000..9a0428b
--- /dev/null
+++ b/uni_modules/uni-scss/styles/setting/_radius.scss
@@ -0,0 +1,55 @@
+@mixin radius($r,$d:null ,$important: false){
+ $radius-value:map-get($uni-radius, $r) if($important, !important, null);
+ // Key exists within the $uni-radius variable
+ @if (map-has-key($uni-radius, $r) and $d){
+ @if $d == t {
+ border-top-left-radius:$radius-value;
+ border-top-right-radius:$radius-value;
+ }@else if $d == r {
+ border-top-right-radius:$radius-value;
+ border-bottom-right-radius:$radius-value;
+ }@else if $d == b {
+ border-bottom-left-radius:$radius-value;
+ border-bottom-right-radius:$radius-value;
+ }@else if $d == l {
+ border-top-left-radius:$radius-value;
+ border-bottom-left-radius:$radius-value;
+ }@else if $d == tl {
+ border-top-left-radius:$radius-value;
+ }@else if $d == tr {
+ border-top-right-radius:$radius-value;
+ }@else if $d == br {
+ border-bottom-right-radius:$radius-value;
+ }@else if $d == bl {
+ border-bottom-left-radius:$radius-value;
+ }
+ }@else{
+ border-radius:$radius-value;
+ }
+}
+
+@each $key, $child in $uni-radius {
+ @if($key){
+ .uni-radius-#{"" + $key} {
+ @include radius($key)
+ }
+ }@else{
+ .uni-radius {
+ @include radius($key)
+ }
+ }
+}
+
+@each $direction in t, r, b, l,tl, tr, br, bl {
+ @each $key, $child in $uni-radius {
+ @if($key){
+ .uni-radius-#{"" + $direction}-#{"" + $key} {
+ @include radius($key,$direction,false)
+ }
+ }@else{
+ .uni-radius-#{$direction} {
+ @include radius($key,$direction,false)
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-scss/styles/setting/_space.scss b/uni_modules/uni-scss/styles/setting/_space.scss
new file mode 100644
index 0000000..3c89528
--- /dev/null
+++ b/uni_modules/uni-scss/styles/setting/_space.scss
@@ -0,0 +1,56 @@
+
+@mixin fn($space,$direction,$size,$n) {
+ @if $n {
+ #{$space}-#{$direction}: #{$size*$uni-space-root}px
+ } @else {
+ #{$space}-#{$direction}: #{-$size*$uni-space-root}px
+ }
+}
+@mixin get-styles($direction,$i,$space,$n){
+ @if $direction == t {
+ @include fn($space, top,$i,$n);
+ }
+ @if $direction == r {
+ @include fn($space, right,$i,$n);
+ }
+ @if $direction == b {
+ @include fn($space, bottom,$i,$n);
+ }
+ @if $direction == l {
+ @include fn($space, left,$i,$n);
+ }
+ @if $direction == x {
+ @include fn($space, left,$i,$n);
+ @include fn($space, right,$i,$n);
+ }
+ @if $direction == y {
+ @include fn($space, top,$i,$n);
+ @include fn($space, bottom,$i,$n);
+ }
+ @if $direction == a {
+ @if $n {
+ #{$space}:#{$i*$uni-space-root}px;
+ } @else {
+ #{$space}:#{-$i*$uni-space-root}px;
+ }
+ }
+}
+
+@each $orientation in m,p {
+ $space: margin;
+ @if $orientation == m {
+ $space: margin;
+ } @else {
+ $space: padding;
+ }
+ @for $i from 0 through 16 {
+ @each $direction in t, r, b, l, x, y, a {
+ .uni-#{$orientation}#{$direction}-#{$i} {
+ @include get-styles($direction,$i,$space,true);
+ }
+ .uni-#{$orientation}#{$direction}-n#{$i} {
+ @include get-styles($direction,$i,$space,false);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-scss/styles/setting/_styles.scss b/uni_modules/uni-scss/styles/setting/_styles.scss
new file mode 100644
index 0000000..689afec
--- /dev/null
+++ b/uni_modules/uni-scss/styles/setting/_styles.scss
@@ -0,0 +1,167 @@
+/* #ifndef APP-NVUE */
+
+$-color-white:#fff;
+$-color-black:#000;
+@mixin base-style($color) {
+ color: #fff;
+ background-color: $color;
+ border-color: mix($-color-black, $color, 8%);
+ &:not([hover-class]):active {
+ background: mix($-color-black, $color, 10%);
+ border-color: mix($-color-black, $color, 20%);
+ color: $-color-white;
+ outline: none;
+ }
+}
+@mixin is-color($color) {
+ @include base-style($color);
+ &[loading] {
+ @include base-style($color);
+ &::before {
+ margin-right:5px;
+ }
+ }
+ &[disabled] {
+ &,
+ &[loading],
+ &:not([hover-class]):active {
+ color: $-color-white;
+ border-color: mix(darken($color,10%), $-color-white);
+ background-color: mix($color, $-color-white);
+ }
+ }
+
+}
+@mixin base-plain-style($color) {
+ color:$color;
+ background-color: mix($-color-white, $color, 90%);
+ border-color: mix($-color-white, $color, 70%);
+ &:not([hover-class]):active {
+ background: mix($-color-white, $color, 80%);
+ color: $color;
+ outline: none;
+ border-color: mix($-color-white, $color, 50%);
+ }
+}
+@mixin is-plain($color){
+ &[plain] {
+ @include base-plain-style($color);
+ &[loading] {
+ @include base-plain-style($color);
+ &::before {
+ margin-right:5px;
+ }
+ }
+ &[disabled] {
+ &,
+ &:active {
+ color: mix($-color-white, $color, 40%);
+ background-color: mix($-color-white, $color, 90%);
+ border-color: mix($-color-white, $color, 80%);
+ }
+ }
+ }
+}
+
+
+.uni-btn {
+ margin: 5px;
+ color: #393939;
+ border:1px solid #ccc;
+ font-size: 16px;
+ font-weight: 200;
+ background-color: #F9F9F9;
+ // TODO 暂时处理边框隐藏一边的问题
+ overflow: visible;
+ &::after{
+ border: none;
+ }
+
+ &:not([type]),&[type=default] {
+ color: #999;
+ &[loading] {
+ background: none;
+ &::before {
+ margin-right:5px;
+ }
+ }
+
+
+
+ &[disabled]{
+ color: mix($-color-white, #999, 60%);
+ &,
+ &[loading],
+ &:active {
+ color: mix($-color-white, #999, 60%);
+ background-color: mix($-color-white,$-color-black , 98%);
+ border-color: mix($-color-white, #999, 85%);
+ }
+ }
+
+ &[plain] {
+ color: #999;
+ background: none;
+ border-color: $uni-border-1;
+ &:not([hover-class]):active {
+ background: none;
+ color: mix($-color-white, $-color-black, 80%);
+ border-color: mix($-color-white, $-color-black, 90%);
+ outline: none;
+ }
+ &[disabled]{
+ &,
+ &[loading],
+ &:active {
+ background: none;
+ color: mix($-color-white, #999, 60%);
+ border-color: mix($-color-white, #999, 85%);
+ }
+ }
+ }
+ }
+
+ &:not([hover-class]):active {
+ color: mix($-color-white, $-color-black, 50%);
+ }
+
+ &[size=mini] {
+ font-size: 16px;
+ font-weight: 200;
+ border-radius: 8px;
+ }
+
+
+
+ &.uni-btn-small {
+ font-size: 14px;
+ }
+ &.uni-btn-mini {
+ font-size: 12px;
+ }
+
+ &.uni-btn-radius {
+ border-radius: 999px;
+ }
+ &[type=primary] {
+ @include is-color($uni-primary);
+ @include is-plain($uni-primary)
+ }
+ &[type=success] {
+ @include is-color($uni-success);
+ @include is-plain($uni-success)
+ }
+ &[type=error] {
+ @include is-color($uni-error);
+ @include is-plain($uni-error)
+ }
+ &[type=warning] {
+ @include is-color($uni-warning);
+ @include is-plain($uni-warning)
+ }
+ &[type=info] {
+ @include is-color($uni-info);
+ @include is-plain($uni-info)
+ }
+}
+/* #endif */
diff --git a/uni_modules/uni-scss/styles/setting/_text.scss b/uni_modules/uni-scss/styles/setting/_text.scss
new file mode 100644
index 0000000..a34d08f
--- /dev/null
+++ b/uni_modules/uni-scss/styles/setting/_text.scss
@@ -0,0 +1,24 @@
+@mixin get-styles($k,$c) {
+ @if $k == size or $k == weight{
+ font-#{$k}:#{$c}
+ }@else{
+ #{$k}:#{$c}
+ }
+}
+
+@each $key, $child in $uni-headings {
+ /* #ifndef APP-NVUE */
+ .uni-#{$key} {
+ @each $k, $c in $child {
+ @include get-styles($k,$c)
+ }
+ }
+ /* #endif */
+ /* #ifdef APP-NVUE */
+ .container .uni-#{$key} {
+ @each $k, $c in $child {
+ @include get-styles($k,$c)
+ }
+ }
+ /* #endif */
+}
diff --git a/uni_modules/uni-scss/styles/setting/_variables.scss b/uni_modules/uni-scss/styles/setting/_variables.scss
new file mode 100644
index 0000000..557d3d7
--- /dev/null
+++ b/uni_modules/uni-scss/styles/setting/_variables.scss
@@ -0,0 +1,146 @@
+// @use "sass:math";
+@import '../tools/functions.scss';
+// 间距基础倍数
+$uni-space-root: 2 !default;
+// 边框半径默认值
+$uni-radius-root:5px !default;
+$uni-radius: () !default;
+// 边框半径断点
+$uni-radius: map-deep-merge(
+ (
+ 0: 0,
+ // TODO 当前版本暂时不支持 sm 属性
+ // 'sm': math.div($uni-radius-root, 2),
+ null: $uni-radius-root,
+ 'lg': $uni-radius-root * 2,
+ 'xl': $uni-radius-root * 6,
+ 'pill': 9999px,
+ 'circle': 50%
+ ),
+ $uni-radius
+);
+// 字体家族
+$body-font-family: 'Roboto', sans-serif !default;
+// 文本
+$heading-font-family: $body-font-family !default;
+$uni-headings: () !default;
+$letterSpacing: -0.01562em;
+$uni-headings: map-deep-merge(
+ (
+ 'h1': (
+ size: 32px,
+ weight: 300,
+ line-height: 50px,
+ // letter-spacing:-0.01562em
+ ),
+ 'h2': (
+ size: 28px,
+ weight: 300,
+ line-height: 40px,
+ // letter-spacing: -0.00833em
+ ),
+ 'h3': (
+ size: 24px,
+ weight: 400,
+ line-height: 32px,
+ // letter-spacing: normal
+ ),
+ 'h4': (
+ size: 20px,
+ weight: 400,
+ line-height: 30px,
+ // letter-spacing: 0.00735em
+ ),
+ 'h5': (
+ size: 16px,
+ weight: 400,
+ line-height: 24px,
+ // letter-spacing: normal
+ ),
+ 'h6': (
+ size: 14px,
+ weight: 500,
+ line-height: 18px,
+ // letter-spacing: 0.0125em
+ ),
+ 'subtitle': (
+ size: 12px,
+ weight: 400,
+ line-height: 20px,
+ // letter-spacing: 0.00937em
+ ),
+ 'body': (
+ font-size: 14px,
+ font-weight: 400,
+ line-height: 22px,
+ // letter-spacing: 0.03125em
+ ),
+ 'caption': (
+ 'size': 12px,
+ 'weight': 400,
+ 'line-height': 20px,
+ // 'letter-spacing': 0.03333em,
+ // 'text-transform': false
+ )
+ ),
+ $uni-headings
+);
+
+
+
+// 主色
+$uni-primary: #2979ff !default;
+$uni-primary-disable:lighten($uni-primary,20%) !default;
+$uni-primary-light: lighten($uni-primary,25%) !default;
+
+// 辅助色
+// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。
+$uni-success: #18bc37 !default;
+$uni-success-disable:lighten($uni-success,20%) !default;
+$uni-success-light: lighten($uni-success,25%) !default;
+
+$uni-warning: #f3a73f !default;
+$uni-warning-disable:lighten($uni-warning,20%) !default;
+$uni-warning-light: lighten($uni-warning,25%) !default;
+
+$uni-error: #e43d33 !default;
+$uni-error-disable:lighten($uni-error,20%) !default;
+$uni-error-light: lighten($uni-error,25%) !default;
+
+$uni-info: #8f939c !default;
+$uni-info-disable:lighten($uni-info,20%) !default;
+$uni-info-light: lighten($uni-info,25%) !default;
+
+// 中性色
+// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。
+$uni-main-color: #3a3a3a !default; // 主要文字
+$uni-base-color: #6a6a6a !default; // 常规文字
+$uni-secondary-color: #909399 !default; // 次要文字
+$uni-extra-color: #c7c7c7 !default; // 辅助说明
+
+// 边框颜色
+$uni-border-1: #F0F0F0 !default;
+$uni-border-2: #EDEDED !default;
+$uni-border-3: #DCDCDC !default;
+$uni-border-4: #B9B9B9 !default;
+
+// 常规色
+$uni-black: #000000 !default;
+$uni-white: #ffffff !default;
+$uni-transparent: rgba($color: #000000, $alpha: 0) !default;
+
+// 背景色
+$uni-bg-color: #f7f7f7 !default;
+
+/* 水平间距 */
+$uni-spacing-sm: 8px !default;
+$uni-spacing-base: 15px !default;
+$uni-spacing-lg: 30px !default;
+
+// 阴影
+$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5) !default;
+$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2) !default;
+$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5) !default;
+
+// 蒙版
+$uni-mask: rgba($color: #000000, $alpha: 0.4) !default;
diff --git a/uni_modules/uni-scss/styles/tools/functions.scss b/uni_modules/uni-scss/styles/tools/functions.scss
new file mode 100644
index 0000000..ac6f63e
--- /dev/null
+++ b/uni_modules/uni-scss/styles/tools/functions.scss
@@ -0,0 +1,19 @@
+// 合并 map
+@function map-deep-merge($parent-map, $child-map){
+ $result: $parent-map;
+ @each $key, $child in $child-map {
+ $parent-has-key: map-has-key($result, $key);
+ $parent-value: map-get($result, $key);
+ $parent-type: type-of($parent-value);
+ $child-type: type-of($child);
+ $parent-is-map: $parent-type == map;
+ $child-is-map: $child-type == map;
+
+ @if (not $parent-has-key) or ($parent-type != $child-type) or (not ($parent-is-map and $child-is-map)){
+ $result: map-merge($result, ( $key: $child ));
+ }@else {
+ $result: map-merge($result, ( $key: map-deep-merge($parent-value, $child) ));
+ }
+ }
+ @return $result;
+};
diff --git a/uni_modules/uni-scss/theme.scss b/uni_modules/uni-scss/theme.scss
new file mode 100644
index 0000000..80ee62f
--- /dev/null
+++ b/uni_modules/uni-scss/theme.scss
@@ -0,0 +1,31 @@
+// 间距基础倍数
+$uni-space-root: 2;
+// 边框半径默认值
+$uni-radius-root:5px;
+// 主色
+$uni-primary: #2979ff;
+// 辅助色
+$uni-success: #4cd964;
+// 警告色
+$uni-warning: #f0ad4e;
+// 错误色
+$uni-error: #dd524d;
+// 描述色
+$uni-info: #909399;
+// 中性色
+$uni-main-color: #303133;
+$uni-base-color: #606266;
+$uni-secondary-color: #909399;
+$uni-extra-color: #C0C4CC;
+// 背景色
+$uni-bg-color: #f5f5f5;
+// 边框颜色
+$uni-border-1: #DCDFE6;
+$uni-border-2: #E4E7ED;
+$uni-border-3: #EBEEF5;
+$uni-border-4: #F2F6FC;
+
+// 常规色
+$uni-black: #000000;
+$uni-white: #ffffff;
+$uni-transparent: rgba($color: #000000, $alpha: 0);
diff --git a/uni_modules/uni-scss/variables.scss b/uni_modules/uni-scss/variables.scss
new file mode 100644
index 0000000..1c062d4
--- /dev/null
+++ b/uni_modules/uni-scss/variables.scss
@@ -0,0 +1,62 @@
+@import './styles/setting/_variables.scss';
+// 间距基础倍数
+$uni-space-root: 2;
+// 边框半径默认值
+$uni-radius-root:5px;
+
+// 主色
+$uni-primary: #2979ff;
+$uni-primary-disable:mix(#fff,$uni-primary,50%);
+$uni-primary-light: mix(#fff,$uni-primary,80%);
+
+// 辅助色
+// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。
+$uni-success: #18bc37;
+$uni-success-disable:mix(#fff,$uni-success,50%);
+$uni-success-light: mix(#fff,$uni-success,80%);
+
+$uni-warning: #f3a73f;
+$uni-warning-disable:mix(#fff,$uni-warning,50%);
+$uni-warning-light: mix(#fff,$uni-warning,80%);
+
+$uni-error: #e43d33;
+$uni-error-disable:mix(#fff,$uni-error,50%);
+$uni-error-light: mix(#fff,$uni-error,80%);
+
+$uni-info: #8f939c;
+$uni-info-disable:mix(#fff,$uni-info,50%);
+$uni-info-light: mix(#fff,$uni-info,80%);
+
+// 中性色
+// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。
+$uni-main-color: #3a3a3a; // 主要文字
+$uni-base-color: #6a6a6a; // 常规文字
+$uni-secondary-color: #909399; // 次要文字
+$uni-extra-color: #c7c7c7; // 辅助说明
+
+// 边框颜色
+$uni-border-1: #F0F0F0;
+$uni-border-2: #EDEDED;
+$uni-border-3: #DCDCDC;
+$uni-border-4: #B9B9B9;
+
+// 常规色
+$uni-black: #000000;
+$uni-white: #ffffff;
+$uni-transparent: rgba($color: #000000, $alpha: 0);
+
+// 背景色
+$uni-bg-color: #f7f7f7;
+
+/* 水平间距 */
+$uni-spacing-sm: 8px;
+$uni-spacing-base: 15px;
+$uni-spacing-lg: 30px;
+
+// 阴影
+$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5);
+$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2);
+$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5);
+
+// 蒙版
+$uni-mask: rgba($color: #000000, $alpha: 0.4);
diff --git a/uni_modules/vrapile-im/changelog.md b/uni_modules/vrapile-im/changelog.md
new file mode 100644
index 0000000..131479a
--- /dev/null
+++ b/uni_modules/vrapile-im/changelog.md
@@ -0,0 +1,40 @@
+## 1.1.9(2025-03-27)
+示例工程接口配置,改为通过环境变量实现
+## 1.1.8(2025-03-26)
+上传示例工程
+## 1.1.7(2025-03-26)
+更新已知问题
+## 1.1.6(2025-03-25)
+将demo插件使用示例工程上传
+## 1.1.5(2025-03-18)
+修复已知问题
+## 1.1.4(2025-03-18)
+聊天页下拉刷新,查看更多历史功能
+## 1.1.3(2025-03-18)
+优化已知问题
+## 1.1.2(2025-03-18)
+解决页面组件内部store监听bug,解决问题:发送消息后没有自动滚动到最底部,也没有已读当前人
+## 1.1.1(2025-03-18)
+更新插件演示程序
+## 1.1.0(2025-02-26)
+修复已知问题
+## 1.0.9(2025-02-26)
+修复已知问题
+## 1.0.8(2025-02-26)
+将demo放在组件中,细节继续调试
+## 1.0.7(2025-02-26)
+功能还在调试中,敬请期待...
+## 1.0.6(2025-02-21)
+开发中...
+## 1.0.5(2025-02-21)
+开发中...
+## 1.0.4(2025-02-21)
+开发中
+## 1.0.3(2025-02-21)
+开发中
+## 1.0.2(2025-02-21)
+开发中
+## 1.0.1(2025-02-21)
+开发中
+## 1.0.0(2025-02-21)
+开发中,敬请期待
diff --git a/uni_modules/vrapile-im/components/vrapile-im/vrapile-im.vue b/uni_modules/vrapile-im/components/vrapile-im/vrapile-im.vue
new file mode 100644
index 0000000..a50a980
--- /dev/null
+++ b/uni_modules/vrapile-im/components/vrapile-im/vrapile-im.vue
@@ -0,0 +1,5 @@
+
+
+ vrapile-im页面组件,此文件不会被引用
+
+
diff --git a/uni_modules/vrapile-im/package.json b/uni_modules/vrapile-im/package.json
new file mode 100644
index 0000000..4da7903
--- /dev/null
+++ b/uni_modules/vrapile-im/package.json
@@ -0,0 +1,86 @@
+{
+ "id": "vrapile-im",
+ "displayName": "im页面组件",
+ "version": "1.1.9",
+ "description": "实现WebSocket连接/好友/群组/新消息/历史消息,都是全局配置并本地化存储,已调试兼容H5/微信小程序/安卓App/PC多端同步通讯",
+ "keywords": [
+ "IM页面组件,websocket应用"
+],
+ "repository": "",
+ "engines": {
+ "HBuilderX": "^3.94"
+ },
+ "dcloudext": {
+ "type": "component-vue",
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "插件不采集任何数据",
+ "permissions": "无"
+ },
+ "npmurl": ""
+ },
+ "uni_modules": {
+ "dependencies": [
+ "uni-icons"
+ ],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y",
+ "alipay": "y"
+ },
+ "client": {
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ },
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y",
+ "app-uvue": "u",
+ "app-harmony": "y"
+ },
+ "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",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y",
+ "钉钉": "y",
+ "快手": "y",
+ "飞书": "y",
+ "京东": "y"
+ },
+ "快应用": {
+ "华为": "y",
+ "联盟": "y"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/vrapile-im/pages/chat/chatFriend.vue b/uni_modules/vrapile-im/pages/chat/chatFriend.vue
new file mode 100644
index 0000000..e73583b
--- /dev/null
+++ b/uni_modules/vrapile-im/pages/chat/chatFriend.vue
@@ -0,0 +1,335 @@
+
+
+
+
+
+ 没有更多消息了
+
+
+ 查看更多消息
+
+
+
+
+
+
+
+
+
+ {{getUserName(item.fromId, item.fromName)}}
+ {{formatTime(item.sendTime)}}
+ {{item.content}}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/vrapile-im/pages/home/chatHome.vue b/uni_modules/vrapile-im/pages/home/chatHome.vue
new file mode 100644
index 0000000..6f16c44
--- /dev/null
+++ b/uni_modules/vrapile-im/pages/home/chatHome.vue
@@ -0,0 +1,184 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.messageNum < 100 ? item.messageNum : 99 }}
+
+
+
+
+ {{ item.name }}
+
+
+ {{ item.messageShow || " " }}
+
+
+
+
+ {{ item.messageTime || '\xa0' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/vrapile-im/pages_init.json b/uni_modules/vrapile-im/pages_init.json
new file mode 100644
index 0000000..c277650
--- /dev/null
+++ b/uni_modules/vrapile-im/pages_init.json
@@ -0,0 +1,20 @@
+{
+ "pages": [
+ // 消息
+ {
+ "path": "uni_modules/vrapile-im/pages/home/chatHome",
+ "style": {
+ "navigationBarTitleText": "消息",
+ "enablePullDownRefresh": false
+ }
+ },
+ // 聊天
+ {
+ "path": "uni_modules/vrapile-im/pages/chat/chatFriend",
+ "style": {
+ "navigationBarTitleText": "聊天",
+ "enablePullDownRefresh": true
+ }
+ }
+ ]
+}
diff --git a/uni_modules/vrapile-im/readme.md b/uni_modules/vrapile-im/readme.md
new file mode 100644
index 0000000..14116ed
--- /dev/null
+++ b/uni_modules/vrapile-im/readme.md
@@ -0,0 +1,105 @@
+## 组件说明
+1. 此组件为页面组件,实现了Socket连接/好友/群组/新消息/历史消息,且都是全局配置全局本地化存储,兼容H5/微信小程序/安卓App(其他平台未做调试)
+
+2. 此组件中已提供示例工程,其中的接口和websocket服务,仅供各位开发者调试使用,正式发布需自行实现接口和websocket服务。
+
+
+## 自行准备内容
+
+1. WebSocket服务,替换.env.development下VITE_APP_SOCKET_URL地址
+
+ websocket需要实现连接,实现心跳检测/离线消息/在线消息/已读回执4种消息类型
+
+2. 接口服务,实现聊天/api/chat.js和/api/login.js里面的方法
+
+
+## 引用说明
+
+### 1. 路由说明
+
+导入组件后,在pages.json中会自动注册组件,若未注册可手动添加
+``` javascript
+{
+ "path": "uni_modules/vrapile-im/pages/home/chatHome",
+ "style": {
+ "enablePullDownRefresh": false,
+ "navigationBarTitleText": "消息"
+ }
+},
+{
+ "path": "uni_modules/vrapile-im/pages/chat/chatFriend",
+ "style": {
+ "enablePullDownRefresh": false,
+ "navigationBarTitleText": "聊天"
+ }
+}
+```
+
+可在导航中配置IM消息页面
+
+``` javascript
+"tabBar": {
+ "selectedColor": "#0000ff",
+ "list": [
+ {
+ "pagePath": "uni_modules/vrapile-im/pages/home/chatHome",
+ "iconPath": "static/image/tabbar/chat.png",
+ "selectedIconPath": "static/image/tabbar/chat-fill.png",
+ "text": "消息"
+ },
+ {
+ "pagePath": "pages/home/user",
+ "iconPath": "static/image/tabbar/user.png",
+ "selectedIconPath": "static/image/tabbar/user-fill.png",
+ "text": "我的"
+ }
+ ]
+},
+```
+
+### 2. 页面样式修改
+ 页面样式在/uni_modules/vrapile-im/static/style/下的nine-chat-home-001.scss和nine-chat-friend-001.scss中,
+
+ 可通过重写/static/style/下的nine-chat-home-001.scss和nine-chat-friend-001.scss,将原样式替换
+
+
+## 演示说明
+
+以下共用一个后端,全部互通
+
+
+
+示例工程运行效果:
+
+https://www.ninecloud.top/udemo/im/index.html
+
+
+
+
+
+
+
+演示商城H5效果:
+
+https://www.ninecloud.top/unine/index.html
+
+
+
+H5中可下载安卓App
+
+
+
+
+演示PC前端(与此组件无关,可用于多端消息互相发送测试):
+
+https://www.ninecloud.top/msw/index
+
+
+
+
+
+注:新注册账号,默认添加【visitor】为好友,默认加入【客服专用群】群
+
+因此,可用访客/注册账号登录以上任意系统,可任意发送消息,皆能同步显示
+
+(*以上系统皆可用访客账号/密码:visitor/visitor*)
\ No newline at end of file
diff --git a/uni_modules/vrapile-im/static/image/emoji.png b/uni_modules/vrapile-im/static/image/emoji.png
new file mode 100644
index 0000000..62091e2
Binary files /dev/null and b/uni_modules/vrapile-im/static/image/emoji.png differ
diff --git a/uni_modules/vrapile-im/static/image/message.png b/uni_modules/vrapile-im/static/image/message.png
new file mode 100644
index 0000000..5ae809e
Binary files /dev/null and b/uni_modules/vrapile-im/static/image/message.png differ
diff --git a/uni_modules/vrapile-im/static/image/more.png b/uni_modules/vrapile-im/static/image/more.png
new file mode 100644
index 0000000..0833011
Binary files /dev/null and b/uni_modules/vrapile-im/static/image/more.png differ
diff --git a/uni_modules/vrapile-im/static/image/voice.png b/uni_modules/vrapile-im/static/image/voice.png
new file mode 100644
index 0000000..bfd3e81
Binary files /dev/null and b/uni_modules/vrapile-im/static/image/voice.png differ
diff --git a/uni_modules/vrapile-im/static/image/yy.png b/uni_modules/vrapile-im/static/image/yy.png
new file mode 100644
index 0000000..2ffff1b
Binary files /dev/null and b/uni_modules/vrapile-im/static/image/yy.png differ
diff --git a/uni_modules/vrapile-im/static/style/nine-chat-friend-001.scss b/uni_modules/vrapile-im/static/style/nine-chat-friend-001.scss
new file mode 100644
index 0000000..c1c1346
--- /dev/null
+++ b/uni_modules/vrapile-im/static/style/nine-chat-friend-001.scss
@@ -0,0 +1,165 @@
+html, body, #app{
+ height: 100%;
+ background-color: #f1f1f1;
+}
+.nine-content-001{
+ display: flex;
+ flex-direction: column;
+ width: 750rpx;
+ height: calc(100vh - 0px);
+ margin: 0;
+ padding: 0;
+ background-color: #f1f1f1;
+}
+.chat-body {
+ /* #ifdef MP-WEIXIN */
+ background-color: #fff;
+ /* #endif */
+}
+.chat-body-main{
+ padding-top: 20rpx;
+ padding-left: 20rpx;
+ padding-right: 20rpx;
+ box-sizing: border-box;
+ -webkit-overflow-scrolling: touch;
+ padding-bottom: 100rpx;
+}
+.chat-body-history{
+ width: 100%;
+ height: 90rpx;
+ line-height: 90rpx;
+ font-size: 24rpx;
+ color: grey;
+ text-align: center;
+}
+.chat-body-history-have{
+ color: rgb(79, 172, 249);
+}
+.chat-conversation{
+ display: flex;
+ align-items: flex-start;
+ padding: 20rpx 5rpx;
+ word-break: break-all;
+}
+.chat-conversation-text{
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ margin: 0 20rpx;
+}
+.chat-conversation-text-time{
+ font-size: 10px;
+ color: gray;
+}
+.chat-conversation-text-text{
+ position: relative;
+ display: flex;
+ align-items: center;
+ max-width: 70%;
+ min-height: 45rpx;
+ padding: 15rpx 20rpx;
+ border-radius: 10rpx;
+ background-color: #FFF;
+ /* #ifdef MP-WEIXIN */
+ background-color: #f1f1f1;
+ /* #endif */
+}
+.chat-conversation-text-text::after {
+ content: '';
+ position: absolute;
+ top: 16rpx;
+ left: -35rpx;
+ border-width: 19rpx;
+ border-style: solid;
+ border-top-color: transparent;
+ border-left-color: transparent;
+ border-right-color: #FFF;
+ /* #ifdef MP-WEIXIN */
+ border-right-color: #f1f1f1;
+ /* #endif */
+ border-bottom-color: transparent;
+}
+.chat-conversation-mine{
+ align-items: flex-start;
+ flex-direction: row-reverse;
+}
+.chat-conversation-mine .chat-conversation-text{
+ align-items: flex-end;
+}
+.chat-conversation-mine .chat-conversation-text-time{
+ text-align: right;
+}
+.chat-conversation-mine .chat-conversation-text-text{
+ background: #9ede86 !important;
+}
+.chat-conversation-mine .chat-conversation-text-text::after {
+ left: auto !important;
+ right: -35rpx !important;
+ border-left-color: #9ede86 !important;
+ border-right-color: transparent !important;
+}
+.chat-conversation-image{
+}
+.chat-conversation-image-image{
+ width: 80rpx;
+ height: 80rpx;
+ padding: 5rpx;
+ border-radius: 10rpx;
+}
+
+.chat-footer {
+ position: fixed;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ height: 100rpx;
+ background-color: #fff;
+ display: flex;
+ /* #ifdef MP-WEIXIN */
+ border-top: 1rpx solid #f1f1f1;
+ /* #endif */
+}
+.chat-footer-send{
+ flex-grow: 1;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 10rpx;
+}
+.chat-footer-send-image{
+ padding: 0 10rpx;
+ width: 60rpx;
+ height: 60rpx;
+}
+.chat-footer-send-input{
+ flex-grow: 1;
+ text-align: left;
+ padding: 15rpx;
+ border-radius: 5rpx;
+ background-color: #f9f9f9;
+}
+.chat-footer-send-say{
+ flex-grow: 1;
+ text-align: center;
+ padding: 20rpx;
+ border-radius: 5rpx;
+ background-color: #f9f9f9;
+}
+.chat-footer-send-button{
+ line-height: 65rpx;
+ margin: 0 10rpx;
+ color: #FFFFFF;
+ background-color: #0000ff;
+ border-radius: 10rpx;
+}
+.chat-footer-send-button-span{
+ padding: 0 25rpx;
+}
+
+// 允许文本复制
+.nine-user-select {
+ cursor: auto;
+ -webkit-user-select: text;
+ user-select: text;
+}
\ No newline at end of file
diff --git a/uni_modules/vrapile-im/static/style/nine-chat-home-001.scss b/uni_modules/vrapile-im/static/style/nine-chat-home-001.scss
new file mode 100644
index 0000000..20c165f
--- /dev/null
+++ b/uni_modules/vrapile-im/static/style/nine-chat-home-001.scss
@@ -0,0 +1,112 @@
+html, body, #app{
+ height: 100%;
+ background-color: #f1f1f1;
+}
+.nine-content-002{
+ display: flex;
+ flex-direction: column;
+ width: 750rpx;
+ height: calc(100vh - 50px);
+ /* #ifndef H5 */
+ height: calc(100vh - 0px);
+ /* #endif */
+ margin: 0;
+ padding: 0;
+ background-color: #f1f1f1;
+}
+
+.chat-search{
+ display: flex;
+ align-items: center;
+ padding: 5rpx;
+ background-color: #ffffff;
+}
+.chat-search-image{
+ height: 45rpx;
+ line-height: 45rpx;
+ padding: 10rpx;
+ background-color: #f8f8f8;
+}
+.chat-search-input{
+ width: 100%;
+ height: 45rpx;
+ line-height: 45rpx;
+ padding: 10rpx;
+ font-size: 16px;
+ background-color: #f8f8f8;
+}
+
+.chat-list{
+ flex: 1;
+ padding: 0;
+ overflow-y: auto;
+}
+.chat-list-item{
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin: 2rpx 0;
+ padding: 15rpx 10rpx;
+ border-radius: 10rpx;
+ background-color: #ffffff;
+}
+.chat-list-item-left{
+ position: relative;
+ width: 84rpx;
+ height: 84rpx;
+}
+.chat-list-item-left-image{
+ width: 82rpx;
+ height: 82rpx;
+ border: 1rpx solid #f1f1f1;
+ border-radius: 5rpx;
+}
+.chat-list-item-left-mark{
+ position: absolute;
+ width: 30rpx;
+ top: -13rpx;
+ right: -13rpx;
+ padding: 1rpx;
+ border-radius: 50%;
+ font-size: 12px;
+ color: white;
+ background-color: red;
+ text-align: center;
+}
+
+.chat-list-item-center{
+ width: 450rpx;
+ margin: 0 20rpx;
+}
+.chat-list-item-center-top{
+ width: 450rpx;
+ font-size: 16px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+.chat-list-item-center-bottom{
+ width: 450rpx;
+ font-size: 12px;
+ color: #969696;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+
+.chat-list-item-right{
+ width: 130rpx;
+ color: #a7a7a7;
+}
+.chat-list-item-right-top{
+ font-size: 12px;
+ text-align: right;
+}
+.chat-list-item-right-bottom{
+ padding-top: 15rpx;
+ text-align: right;
+}
+.chat-list-item-right-bottom-image{
+ width: 25rpx;
+ height: 30rpx;
+}
\ No newline at end of file
diff --git a/uni_modules/vrapile-im/store/getters.js b/uni_modules/vrapile-im/store/getters.js
new file mode 100644
index 0000000..7ec169e
--- /dev/null
+++ b/uni_modules/vrapile-im/store/getters.js
@@ -0,0 +1,11 @@
+const getters = {
+ chatList: state => state.chat.chatList,
+ friendList: state => state.chat.friendList,
+ groupList: state => state.chat.groupList,
+ userObject: state => state.chat.userObject,
+ groupObject: state => state.chat.groupObject,
+
+ websocket: state => state.socket.websocket,
+ websocketData: state => state.socket.websocketData
+}
+export default getters
diff --git a/uni_modules/vrapile-im/store/index.js b/uni_modules/vrapile-im/store/index.js
new file mode 100644
index 0000000..babbcd7
--- /dev/null
+++ b/uni_modules/vrapile-im/store/index.js
@@ -0,0 +1,16 @@
+import Vuex from 'vuex'
+import socket from '@/uni_modules/vrapile-im/store/modules/socket'
+import chat from '@/uni_modules/vrapile-im/store/modules/chat'
+import getters from './getters'
+
+// Vue.use(Vuex)
+
+const store = new Vuex.Store({
+ modules: {
+ chat,
+ socket
+ },
+ getters
+})
+
+export default store
diff --git a/uni_modules/vrapile-im/store/modules/chat.js b/uni_modules/vrapile-im/store/modules/chat.js
new file mode 100644
index 0000000..5e83eaa
--- /dev/null
+++ b/uni_modules/vrapile-im/store/modules/chat.js
@@ -0,0 +1,138 @@
+import storage from '@/uni_modules/vrapile-im/utils/storage'
+import constant from '@/uni_modules/vrapile-im/utils/constant'
+import { getChatKey } from '@/uni_modules/vrapile-im/utils/tiosocket';
+
+ // 外部需提供获取用户好友,获取用户所有群,以及群中所有用户三个接口
+import { getUserAllFriend, getUserAllGroup, getGroupUser } from '@/api/chat'
+
+const chat = {
+ state: {
+ friendList: storage.get(constant.friendList) || [],
+ groupList: storage.get(constant.groupList) || [],
+ userObject: storage.get(constant.userObject) || {},
+ groupObject: storage.get(constant.groupObject) || {},
+ chatList: storage.get(constant.chatList) || []
+ },
+
+ mutations: {
+ // 清空聊天列表
+ CLEAN_CHAT_LIST: (state) => {
+ state.chatList = new Array();
+ storage.set(constant.chatList, state.chatList)
+ },
+ // 存储好友聊天列表
+ SET_CHAT_FRIEND_LIST: (state, data) => {
+ state.friendList = data;
+ storage.set(constant.friendList, data)
+
+ for(let item of data){
+ item["key"] = getChatKey(item["type"], item["friendId"], item["userId"])
+ item["haveHistory"] = 1;
+ item["id"] = item["friendId"];
+ item["name"] = item["remarkName"] || item["nickName"];
+ item["messageNum"] = 0;
+ item["messageList"] = [];
+ item["messageShow"] = "";
+ item["messageLast"] = {};
+ state.chatList.push(item)
+ }
+ storage.set(constant.chatList, state.chatList)
+ },
+ // 存储群聊列表
+ SET_CHAT_GROUP_LIST: (state, data) => {
+ state.groupList = data;
+ storage.set(constant.groupList, data)
+
+ for(let item of data){
+ item["key"] = getChatKey(item["type"], item["id"], item["userId"])
+ item["haveHistory"] = 1;
+ item["id"] = item["id"];
+ item["name"] = item["remarkName"] || item["name"]
+ item["messageNum"] = 0;
+ item["messageList"] = [];
+ item["messageShow"] = "";
+ item["messageLast"] = {};
+ state.chatList.push(item)
+ }
+ storage.set(constant.chatList, state.chatList)
+ },
+ // 存储用户对象,方便寻找用户名,头像等
+ SET_USER_OBJECT: (state, userObject) => {
+ state.userObject[userObject.userId] = userObject;
+ storage.set(constant.userObject, state.userObject)
+ },
+ // 存储群组对象,方便寻找群组名,头像等
+ SET_GROUP_OBJECT: (state, groupObject) => {
+ state.groupObject[groupObject.id] = groupObject;
+ storage.set(constant.groupObject, state.groupObject)
+ }
+ },
+
+ actions: {
+ // 获取登录用户所有聊天列表
+ GetChatList({ commit, state }, params) {
+ return new Promise((resolve, reject) => {
+ commit('CLEAN_CHAT_LIST');
+ // 查询好友
+ getUserAllFriend().then(res => {
+ let list = []
+ for(let item of res.data){
+ list.push({type: 0, ...item, userId: params.userId})
+ commit('SET_USER_OBJECT', item)
+ }
+ commit('SET_CHAT_FRIEND_LIST', list)
+
+ // 查询群组
+ getUserAllGroup().then(res1 => {
+ let list = []
+ for(let item1 of res1.data){
+ list.push({type: 1, ...item1, userId: params.userId})
+ // 查询群组人员
+ getGroupUser(item1.id).then(res2 => {
+ for(let user of res2.data){
+ commit('SET_USER_OBJECT', user)
+ }
+ resolve(res2)
+ });
+ commit('SET_GROUP_OBJECT', item1)
+ }
+ commit('SET_CHAT_GROUP_LIST', list)
+ }).catch(error => {
+ reject(error)
+ })
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ }
+ },
+
+ getters: {
+ getUserAvatar: (state) => (userId, defaultAvatar) => {
+ if(state.userObject[userId] && state.userObject[userId]["avatar"]){
+ return state.userObject[userId]["avatar"]
+ }
+ return defaultAvatar || '/uni_modules/vrapile-im/static/image/yy.png';
+ },
+ getGroupAvatar: (state) => (groupId, defaultAvatar) => {
+ if(state.groupObject[groupId] && state.groupObject[groupId]["avatar"]){
+ return state.groupObject[groupId]["avatar"]
+ }
+ return defaultAvatar || '/uni_modules/vrapile-im/static/image/yy.png';
+ },
+ getUserName: (state) => (userId, defaultName) => {
+ if(state.userObject[userId]){
+ return state.userObject[userId]["remarkName"] || state.userObject[userId]["nickName"] || defaultName
+ }
+ return defaultName || "无名";
+ },
+ getGroupName: (state) => (groupId, defaultName) => {
+ if(state.groupObject[groupId]){
+ return state.groupObject[userId]["remarkName"] || state.groupObject[userId]["name"] || defaultName
+ }
+ return defaultName || "无名";
+ }
+ }
+}
+
+export default chat
diff --git a/uni_modules/vrapile-im/store/modules/socket.js b/uni_modules/vrapile-im/store/modules/socket.js
new file mode 100644
index 0000000..fe68749
--- /dev/null
+++ b/uni_modules/vrapile-im/store/modules/socket.js
@@ -0,0 +1,116 @@
+import store from '@/uni_modules/vrapile-im/store'
+import storage from '@/uni_modules/vrapile-im/utils/storage'
+import constant from '@/uni_modules/vrapile-im/utils/constant'
+import { formatDate } from '@/uni_modules/vrapile-im/utils/nineTool';
+import { TioSocket, getChatKey } from '@/uni_modules/vrapile-im/utils/tiosocket';
+
+const socket = {
+ state: {
+ websocket: storage.get(constant.websocket),
+ websocketData: storage.get(constant.websocketData)
+ },
+
+ mutations: {
+ // 存储登录链接
+ SET_SOCKET: (state, socket) => {
+ state.websocket = socket;
+ storage.set(constant.websocket, socket)
+ },
+ // 添加socket消息
+ ADD_MESSAGE: (state, message) => {
+ state.websocketData.push(message)
+ storage.set(constant.websocketData, state.websocketData)
+
+ // 添加消息
+ for(let i=0;i {
+ // 删除未读消息
+ for(let i=0;i {
+ let unReadNum = 0
+ for(let i=0;i 0){
+ uni.setTabBarBadge({
+ index: getApp().globalData.msgTabBarIndex,
+ text: String(unReadNum),
+ fail: (e) => {
+ // console.log(e)
+ }
+ })
+ }else{
+ uni.removeTabBarBadge({
+ index: getApp().globalData.msgTabBarIndex
+ })
+ }
+ }catch(e){
+
+ }
+ },
+ // 清空消息
+ CLEAN_MESSAGE: (state, message) => {
+ state.websocketData = new Array();
+ storage.set(constant.websocketData, new Array())
+ }
+ },
+
+ actions: {
+ // 连接websocket
+ ConnSocket({ commit, state }, params) {
+ return new Promise((resolve, reject) => {
+ let url = params.url;
+ let heartbeatTimeout = 50000; // 心跳超时时间,单位:毫秒
+ let reconnInterval = 5000; // 重连间隔时间,单位:毫秒
+ let paramStr = "app=unine&token=" + params.token
+ let socket = new TioSocket(url, paramStr, heartbeatTimeout, reconnInterval);
+ socket.connect(false);
+ })
+ }
+ }
+}
+
+export default socket
diff --git a/uni_modules/vrapile-im/utils/cache.js b/uni_modules/vrapile-im/utils/cache.js
new file mode 100644
index 0000000..a248213
--- /dev/null
+++ b/uni_modules/vrapile-im/utils/cache.js
@@ -0,0 +1,26 @@
+const sessionCache = 'vrapile-im-session-cache'
+const localCache = 'vrapile-im-local-cache'
+
+export function getSessionCache() {
+ return uni.getStorageSync(sessionCache)
+}
+
+export function setSessionCache(cache) {
+ return uni.setStorageSync(sessionCache, cache)
+}
+
+export function removeSessionCache() {
+ return uni.removeStorageSync(sessionCache)
+}
+
+export function getLocalCache() {
+ return uni.getStorageSync(localCache)
+}
+
+export function setLocalCache(cache) {
+ return uni.setStorageSync(localCache, cache)
+}
+
+export function removeLocalCache() {
+ return uni.removeStorageSync(localCache)
+}
diff --git a/uni_modules/vrapile-im/utils/constant.js b/uni_modules/vrapile-im/utils/constant.js
new file mode 100644
index 0000000..1158b94
--- /dev/null
+++ b/uni_modules/vrapile-im/utils/constant.js
@@ -0,0 +1,6 @@
+const constant = {
+ websocket: 'vuex_vrapile_im_websocket',
+ websocketData: 'vuex_vrapile_im_websocket_data'
+}
+
+ export default constant
diff --git a/uni_modules/vrapile-im/utils/errorCode.js b/uni_modules/vrapile-im/utils/errorCode.js
new file mode 100644
index 0000000..d2111ee
--- /dev/null
+++ b/uni_modules/vrapile-im/utils/errorCode.js
@@ -0,0 +1,6 @@
+export default {
+ '401': '认证失败,无法访问系统资源',
+ '403': '当前操作没有权限',
+ '404': '访问资源不存在',
+ 'default': '系统未知错误,请反馈给管理员'
+}
diff --git a/uni_modules/vrapile-im/utils/nineTool.js b/uni_modules/vrapile-im/utils/nineTool.js
new file mode 100644
index 0000000..843ec96
--- /dev/null
+++ b/uni_modules/vrapile-im/utils/nineTool.js
@@ -0,0 +1,348 @@
+
+export function isNull(o) {
+ if(o === 0 || o === "0"){
+ return false;
+ }
+ if(o == "undefined" || o == null || o == ""){
+ return true;
+ }
+ return false;
+}
+export function isPhone(o) {
+ if(/^1[23456789]\d{9}$/.test(o)){
+ return true;
+ }
+ return false;
+}
+export function isMail(o) {
+ if(/^([a-z0-9A-Z]+[-|\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\.)+[a-zA-Z]{2,}$/.test(o)){
+ return true;
+ }
+ return false;
+}
+export function isNumber(value) {
+ return !isNaN(parseFloat(value)) && isFinite(value)
+}
+export function isLetter(o) {
+ if(/^[A-Za-z]+$/.test(o)){
+ return true;
+ }
+ return false;
+}
+export function isNumberOrLetter(o) {
+ if(/^[A-Za-z0-9]+$/.test(o)){
+ return true;
+ }
+ return false;
+}
+
+// 日期格式化
+export function parseTime(time, pattern) {
+ if (arguments.length === 0 || !time) {
+ return null
+ }
+ const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
+ let date
+ if (typeof time === 'object') {
+ date = time
+ } else {
+ if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
+ time = parseInt(time)
+ } else if (typeof time === 'string') {
+ time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), '');
+ }
+ if ((typeof time === 'number') && (time.toString().length === 10)) {
+ time = time * 1000
+ }
+ date = new Date(time)
+ }
+ const formatObj = {
+ y: date.getFullYear(),
+ m: date.getMonth() + 1,
+ d: date.getDate(),
+ h: date.getHours(),
+ i: date.getMinutes(),
+ s: date.getSeconds(),
+ a: date.getDay()
+ }
+ const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
+ let value = formatObj[key]
+ // Note: getDay() returns 0 on Sunday
+ if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
+ if (result.length > 0 && value < 10) {
+ value = '0' + value
+ }
+ return value || 0
+ })
+ return time_str
+}
+
+export function formatDate(time, option) {
+ if (('' + time).length === 10) {
+ time = parseInt(time) * 1000
+ } else {
+ time = +time
+ }
+
+ if (option) {
+ return parseTime(time, option)
+ }
+
+ const d = new Date(time)
+ const now = Date.now()
+
+ const diff = (now - d) / 1000
+
+ if (diff < 30) {
+ return '刚刚'
+ } else if (diff < 3600) {
+ // less 1 hour
+ return Math.ceil(diff / 60) + '分钟前'
+ } else if (diff < 3600 * 24) {
+ return Math.ceil(diff / 3600) + '小时前'
+ } else if (diff < 3600 * 24 * 2) {
+ return '1天前'
+ } else if (diff < 3600 * 24 * 3) {
+ return '2天前'
+ } else if (diff < 3600 * 24 * 4) {
+ return '3天前'
+ } else if (diff < 3600 * 24 * 5) {
+ return '4天前'
+ } else if (diff < 3600 * 24 * 6) {
+ return '5天前'
+ } else if (diff < 3600 * 24 * 7) {
+ return '6天前'
+ } else if (diff < 3600 * 24 * 8) {
+ return '7天前'
+ }
+ if(diff < 3600 * 24 * 365) {
+ return (
+ (d.getMonth()*1 + 1) +
+ '月' +
+ d.getDate() +
+ '日'
+ )
+ } else {
+ return (
+ d.getFullYear() +
+ '年' +
+ (d.getMonth()*1 + 1) +
+ '月'
+ )
+ }
+}
+
+export function formatTime(time, option) {
+ if (('' + time).length === 10) {
+ time = parseInt(time) * 1000
+ } else {
+ time = +time
+ }
+
+ if (option) {
+ return parseTime(time, option)
+ }
+
+ const d = new Date(time)
+ const now = Date.now()
+
+ const diff = (now - d) / 1000
+
+ return (
+ d.getFullYear() +
+ '-' +
+ ((d.getMonth()*1 + 1) + "").padStart(2,0) +
+ '-' +
+ (d.getDate() + '').padStart(2,0) +
+ ' ' +
+ (d.getHours() + '').padStart(2,0) +
+ ':' +
+ (d.getMinutes() + '').padStart(2,0) +
+ ':' +
+ (d.getSeconds() + '').padStart(2,0)
+ )
+}
+
+// number:要格式化的数字,
+// decimals:保留几位小数, 默认0位
+// dec_point:小数点符号, 默认 .
+// thousands_sep:千分位符号 默认 ,
+// tail_add: 小数点后面数据是否添加0补足位数, 默认空字符
+// null_default: 如果为空的值, 默认空字符
+function numberFormat(number, decimals, dec_point, thousands_sep, tail_add="", null_default="") {
+ number = (number + '').replace(/[^0-9+-Ee.]/g, '');
+ var n = !isFinite(+number) ? 0 : +number,
+ prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
+ sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
+ dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
+ s = '',
+ toFixedFix = function (n, prec) {
+ var k = Math.pow(10, prec);
+ return '' + Math.round(n * k) / k;
+ };
+
+ s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.');
+ var re = /(-?\d+)(\d{3})/;
+ if(sep.length > 0){
+ 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(tail_add);
+ }
+ if((s[1] || '').length == 0){
+ return s[0]
+ }
+ return s.join(dec);
+}
+// number:要格式化的数字,
+// decimals:保留几位小数, 默认0位
+// dec_point:小数点符号, 默认 .
+// thousands_sep:千分位符号 默认 ,
+// tail_add: 小数点后面数据是否添加0补足位数, 默认空字符
+// null_default: 如果为空的值, 默认空字符
+export function formatNumber(number, decimals, tail_add, thousands_sep, dec_point, null_default) {
+ if(isNull(number) || isNull(String(number).trim())){return null_default;}
+ if(!isNumber(String(number).trim())){return number;}
+ number = String(number).trim();
+ return numberFormat(number, decimals, tail_add, thousands_sep, dec_point, null_default);
+}
+// thousands_sep:千分位符号 默认空字符
+export function formatPercent(number, decimals, tail_add, thousands_sep="", dec_point, null_default) {
+ if(isNull(number) || isNull(String(number).trim().replaceAll(",", ""))){return null_default;}
+ if(!isNumber(String(number).trim().replaceAll(",", ""))){return number;}
+ number = String(number).trim().replaceAll(",", "");
+ let value = numberFormat(number*100, decimals, tail_add, thousands_sep, dec_point, null_default);
+ if(value){
+ return value + "%";
+ }
+ return "";
+}
+
+// get brower
+export function GetCurrentBrowser () {
+ let ua = navigator.userAgent.toLocaleLowerCase()
+ let browserType = null
+ if (ua.match(/msie/) != null || ua.match(/trident/) != null) {
+ browserType = 'IE'
+ } else if (ua.match(/firefox/) != null) {
+ browserType = 'firefox'
+ } else if (ua.match(/ucbrowser/) != null) {
+ browserType = 'UC'
+ } else if (ua.match(/opera/) != null || ua.match(/opr/) != null) {
+ browserType = 'opera'
+ } else if (ua.match(/bidubrowser/) != null) {
+ browserType = 'baidu'
+ } else if (ua.match(/metasr/) != null) {
+ browserType = 'sougou'
+ } else if (ua.match(/tencenttraveler/) != null || ua.match(/qqbrowse/) != null) {
+ browserType = 'QQ'
+ } else if (ua.match(/maxthon/) != null) {
+ browserType = 'maxthon'
+ } else if (ua.match(/chrome/) != null) {
+ var is360 = _mime('type', 'application/vnd.chromium.remoting-viewer')
+ if (is360) {
+ browserType = '360'
+ } else {
+ browserType = 'chrome'
+ }
+ } else if (ua.match(/safari/) != null) {
+ browserType = 'Safari'
+ } else {
+ browserType = 'others'
+ }
+ return browserType
+}
+
+function _mime (option, value) {
+ var mimeTypes = navigator.mimeTypes
+ for (var mt in mimeTypes) {
+ if (mimeTypes[mt][option] === value) {
+ return true
+ }
+ }
+ return false
+}
+
+// get os
+export function GetOs () {
+ let sUserAgent = navigator.userAgent.toLocaleLowerCase()
+ let isWin = (navigator.platform.toLocaleLowerCase() == 'win32') || (navigator.platform.toLocaleLowerCase() === 'windows')
+ let isMac = (navigator.platform.toLocaleLowerCase() === 'mac68k') || (navigator.platform.toLocaleLowerCase() === 'macppc')
+ || (navigator.platform === 'macintosh') || (navigator.platform.toLocaleLowerCase() === 'macintel')
+ if (isMac) return 'Mac'
+ var isUnix = (navigator.platform === 'x11') && !isWin && !isMac
+ if (isUnix) return 'Unix'
+ var isLinux = (String(navigator.platform.toLocaleLowerCase()).indexOf('linux') > -1)
+ if (isLinux) return 'Linux'
+ if (isWin) {
+ var isWin2K = sUserAgent.indexOf('windows nt 5.0') > -1 || sUserAgent.indexOf('windows 2000') > -1
+ if (isWin2K) return 'Win2000'
+ var isWinXP = sUserAgent.indexOf('windows nt 5.1') > -1 || sUserAgent.indexOf('windows xp') > -1
+ if (isWinXP) return 'WinXP'
+ var isWin2003 = sUserAgent.indexOf('windows nt 5.2') > -1 || sUserAgent.indexOf('windows 2003') > -1
+ if (isWin2003) return 'Win2003'
+ var isWinVista = sUserAgent.indexOf('windows nt 6.0') > -1 || sUserAgent.indexOf('windows vista') > -1
+ if (isWinVista) return 'WinVista'
+ var isWin7 = sUserAgent.indexOf('windows nt 6.1') > -1 || sUserAgent.indexOf('windows 7') > -1
+ if (isWin7) return 'Win7'
+ var isWin8 = sUserAgent.indexOf('windows nt 6.2') > -1 || sUserAgent.indexOf('windows 8') > -1
+ if (isWin8) return 'Win8'
+ var isWin10 = sUserAgent.indexOf('windows nt 10.0') > -1 || sUserAgent.indexOf('windows nt 6.4') > -1 || sUserAgent.indexOf('windows 10') > -1
+ if (isWin10) return 'Win10'
+ var isSimulator = sUserAgent.indexOf('linux') > -1 && sUserAgent.indexOf('android') > -1
+ if (isSimulator) return 'Win手机模拟器'
+ return navigator.platform
+ }
+ if (sUserAgent.indexOf('android') > -1) return 'Android'
+ if (sUserAgent.indexOf('iphone') > -1) return 'iPhone'
+ if (sUserAgent.indexOf('symbianos') > -1) return 'SymbianOS'
+ if (sUserAgent.indexOf('windows phone') > -1) return 'Windows Phone'
+ if (sUserAgent.indexOf('ipad') > -1) return 'iPad'
+ if (sUserAgent.indexOf('ipod') > -1) return 'iPod'
+ return navigator.platform
+}
+
+export function getRandom(len){
+ let data = Math.random() + "";
+ let index = 2;
+ while(data[index] == 0){
+ index++;
+ }
+ return data.substr(index, len);
+}
+
+export function getLongRandom(len){
+ if(len <= 16){
+ return getRandom(len)
+ }
+ let data = Math.random() + "";
+ let index = 2;
+ while(data[index] == 0){
+ index++;
+ }
+ return parseTime(Date.now(), '{y}{m}{d}{h}{i}{s}') + "" + data.substr(index, len-16);
+}
+
+export function moveInArray(array, fromIndex, toIndex) {
+ const element = array.splice(fromIndex, 1)[0];
+ array.splice(toIndex, 0, element);
+}
+
+export function jsonCharBigInt(s){
+ if(typeof s !== 'string'){
+ return s
+ }
+ let re = /([\\]?['|"]{1})(\w+[\\]?['|"]{1}[ |\n|r|\t]*:[ |\n|r|\t]*)([-]?\d{15,})/g
+ return s.replaceAll(re, "$1$2$1$3$1")
+}
+
+export function jsonParse(s){
+ if(typeof s !== 'string'){
+ return s
+ }
+ let re = /([\\]?['|"]{1})(\w+[\\]?['|"]{1}[ |\n|r|\t]*:[ |\n|r|\t]*)([-]?\d{15,})/g
+ return JSON.parse(s.replaceAll(re, "$1$2$1$3$1"))
+}
\ No newline at end of file
diff --git a/uni_modules/vrapile-im/utils/storage.js b/uni_modules/vrapile-im/utils/storage.js
new file mode 100644
index 0000000..88dc1ed
--- /dev/null
+++ b/uni_modules/vrapile-im/utils/storage.js
@@ -0,0 +1,33 @@
+import constant from './constant'
+
+// 存储变量名
+let storageKey = 'vrapile_im_socket_storage_data'
+
+// 存储节点变量名
+let storageNodeKeys = [constant.chatList, constant.friendList, constant.groupList,
+ constant.userObject, constant.groupObject, constant.websocket, constant.websocketData]
+
+const storage = {
+ set: function(key, value) {
+ if (storageNodeKeys.indexOf(key) != -1) {
+ let tmp = uni.getStorageSync(storageKey)
+ tmp = tmp ? tmp : {}
+ tmp[key] = value
+ uni.setStorageSync(storageKey, tmp)
+ }
+ },
+ get: function(key) {
+ let storageData = uni.getStorageSync(storageKey) || {}
+ return storageData[key] || ""
+ },
+ remove: function(key) {
+ let storageData = uni.getStorageSync(storageKey) || {}
+ delete storageData[key]
+ uni.setStorageSync(storageKey, storageData)
+ },
+ clean: function() {
+ uni.removeStorageSync(storageKey)
+ }
+}
+
+export default storage
diff --git a/uni_modules/vrapile-im/utils/tiosocket.js b/uni_modules/vrapile-im/utils/tiosocket.js
new file mode 100644
index 0000000..58bfc0d
--- /dev/null
+++ b/uni_modules/vrapile-im/utils/tiosocket.js
@@ -0,0 +1,181 @@
+import store from '@/uni_modules/vrapile-im/store'
+
+/**
+ * @param {*} url wss or ws
+ * @param {*} paramStr 加在ws url后面的请求参数,形如:name=张三&id=12
+ * @param {*} heartbeatTimeout 心跳时间 单位:毫秒
+ * @param {*} reconnInterval 重连间隔时间 单位:毫秒
+ */
+export class TioSocket {
+ constructor(url, paramStr, heartbeatTimeout, reconnInterval) {
+ this.firstUrl = url;
+ this.reconnUrl = url;
+ if (paramStr) {
+ this.firstUrl += '?' + paramStr;
+ this.reconnUrl += '?' + paramStr + "&reconnect=true";
+ } else {
+ this.reconnUrl += "?reconnect=true";
+ }
+
+ this.closeByUser = false;
+ this.lockReconnect = false;
+ this.reconnectCount = 0;
+
+ // 最后连接时间
+ this.lastConnectTime = new Date().getTime();
+ // 重连时间
+ this.reconnInterval = reconnInterval;
+ // 心跳时间
+ this.heartbeatTimeout = heartbeatTimeout;
+
+ this.ws = null;
+
+ this.connect = function(isReconnect) {
+ // 这里连接的时候,先关闭,避免出现多个连接
+ uni.closeSocket({
+ success:() => {
+ this.ws = uni.connectSocket({
+ url: this.firstUrl,
+ success(res) {
+ console.log("WebSocket成功关闭,连接成功")
+ },
+ fail(err) {
+ console.log("WebSocket成功关闭,连接失败:" + err)
+ }
+ });
+ },
+ fail:() => {
+ this.ws = uni.connectSocket({
+ url: this.firstUrl,
+ success(res) {
+ console.log("WebSocket关闭失败,连接成功")
+ },
+ fail(err) {
+ console.log("WebSocket关闭失败,连接失败:" + err)
+ }
+ });
+ }
+ })
+
+ this.ws.onOpen((e) => {
+ if(!isReconnect){
+ uni.sendSocketMessage({
+ data: JSON.stringify({code:1})
+ })
+ store.commit('CLEAN_MESSAGE', {})
+ }
+ this.reset();
+ })
+
+ store.commit('SET_SOCKET', this)
+ this.ws.onMessage((e) => {
+ let data = JSON.parse(e.data);
+ if(data.code == 2){
+ store.commit('ADD_MESSAGE', data.message)
+ }
+ this.reset();
+ })
+
+ this.ws.onClose((e) => {
+ console.error("WebSocket关闭了:" + JSON.stringify(e))
+ this.clearAllTimeoutTask();
+ })
+
+ this.ws.onError((e) => {
+ console.error("WebSocket错误了:" + JSON.stringify(e))
+ this.clearAllTimeoutTask();
+ if(!this.closeByUser){
+ this.reconn();
+ }
+ })
+
+ return this.ws
+ }
+
+ this.reconn = () => {
+ // 重连次数,防止疯狂重连导致系统挂掉
+ if(this.reconnectCount++ > 10){ return;}
+ // 防止多个方法调用,多处重连
+ if (this.lockReconnect) { return;}
+ this.lockReconnect = true;
+ this.reconnIntervalTask = setTimeout(() => {
+ this.ws = this.connect(true)
+ this.lockReconnect = false;
+ }, this.reconnInterval)
+ }
+
+ this.ping = () => {
+ uni.sendSocketMessage({
+ data: JSON.stringify({code:0})
+ })
+ };
+
+ this.send = (data) => {
+ uni.sendSocketMessage({
+ data: data
+ })
+ };
+
+ this.close = (bool) => {
+ this.lockReconnect = false;
+ this.closeByUser = bool;
+ uni.closeSocket({
+ success:() => {
+ console.info("WebSocket关闭成功")
+ }
+ })
+ };
+
+ this.reset = () => {
+ this.clearAllTimeoutTask();
+ // 重置重连次数
+ this.reconnectCount = 0;
+ // 重置最后连接时间
+ this.lastConnectTime = new Date().getTime();
+ // 启动心跳任务
+ this.pingIntervalTask = setTimeout(() => {
+ this.ping();
+ }, this.heartbeatTimeout);
+ }
+
+ this.clearAllTimeoutTask = () => {
+ // 清除重连任务
+ if (this.reconnIntervalTask) {
+ clearTimeout(this.reconnIntervalTask);
+ }
+ // 清除心跳任务
+ if(this.pingIntervalTask){
+ clearTimeout(this.pingIntervalTask)
+ }
+ }
+
+ this.getReadyState = () => {
+ // CONNECTING:值为0,表示正在连接。
+ // OPEN:值为1,表示连接成功,可以通信了。
+ // CLOSING:值为2,表示连接正在关闭。
+ // CLOSED:值为3,表示连接已经关闭,或者打开连接失败。
+ return this.ws.readyState;
+ }
+
+ }
+}
+
+/**
+ * 获取聊天唯一Key
+ * type 0-私聊,1-群里
+ * chatId 聊天对象,好友ID或群聊ID
+ * fromId 发消息人ID
+ *
+*/
+export function getChatKey(type, chatId, fromId) {
+ // 私聊
+ if(type == 0){
+ if(chatId*1 < fromId*1){
+ return "im:message:friend-" + chatId + "-" + fromId
+ }else{
+ return "im:message:friend-" + fromId + "-" + chatId
+ }
+ }else{
+ return "im:message:group-" + chatId
+ }
+}
diff --git a/utils/cache.js b/utils/cache.js
new file mode 100644
index 0000000..62c3ca1
--- /dev/null
+++ b/utils/cache.js
@@ -0,0 +1,26 @@
+const sessionCache = 'session-cache'
+const localCache = 'local-cache'
+
+export function getSessionCache() {
+ return uni.getStorageSync(sessionCache)
+}
+
+export function setSessionCache(cache) {
+ return uni.setStorageSync(sessionCache, cache)
+}
+
+export function removeSessionCache() {
+ return uni.removeStorageSync(sessionCache)
+}
+
+export function getLocalCache() {
+ return uni.getStorageSync(localCache)
+}
+
+export function setLocalCache(cache) {
+ return uni.setStorageSync(localCache, cache)
+}
+
+export function removeLocalCache() {
+ return uni.removeStorageSync(localCache)
+}
diff --git a/utils/constant.js b/utils/constant.js
new file mode 100644
index 0000000..b75a236
--- /dev/null
+++ b/utils/constant.js
@@ -0,0 +1,8 @@
+const constant = {
+ avatar: 'vuex_avatar',
+ name: 'vuex_name',
+ userInfo: 'vuex_user_info',
+ loginInfo: 'vuex_login_info'
+}
+
+ export default constant
diff --git a/utils/errorCode.js b/utils/errorCode.js
new file mode 100644
index 0000000..d2111ee
--- /dev/null
+++ b/utils/errorCode.js
@@ -0,0 +1,6 @@
+export default {
+ '401': '认证失败,无法访问系统资源',
+ '403': '当前操作没有权限',
+ '404': '访问资源不存在',
+ 'default': '系统未知错误,请反馈给管理员'
+}
diff --git a/utils/frameTool.js b/utils/frameTool.js
new file mode 100644
index 0000000..150a7ca
--- /dev/null
+++ b/utils/frameTool.js
@@ -0,0 +1,15 @@
+
+import * as nineTool from "@/utils/nineTool.js";
+import { diyApi, diyApiGet } from '@/utils/queryByDiy.js';
+
+export default {
+ install(app) {
+ // 九云工具
+ Object.keys(nineTool).forEach((key) => {
+ app.config.globalProperties[key] = nineTool[key];
+ });
+ // 自定义查询工具
+ app.config.globalProperties.diyApi = diyApi
+ app.config.globalProperties.diyApiGet = diyApiGet
+ }
+};
diff --git a/utils/nineTool.js b/utils/nineTool.js
new file mode 100644
index 0000000..b8d13c8
--- /dev/null
+++ b/utils/nineTool.js
@@ -0,0 +1,348 @@
+
+export function isNull(o) {
+ if(o === 0 || o === "0"){
+ return false;
+ }
+ if(o == "undefined" || o == null || o == ""){
+ return true;
+ }
+ return false;
+}
+export function isPhone(o) {
+ if(/^1[23456789]\d{9}$/.test(o)){
+ return true;
+ }
+ return false;
+}
+export function isMail(o) {
+ if(/^([a-z0-9A-Z]+[-|\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\.)+[a-zA-Z]{2,}$/.test(o)){
+ return true;
+ }
+ return false;
+}
+export function isNumber(value) {
+ return !isNaN(parseFloat(value)) && isFinite(value)
+}
+export function isLetter(o) {
+ if(/^[A-Za-z]+$/.test(o)){
+ return true;
+ }
+ return false;
+}
+export function isNumberOrLetter(o) {
+ if(/^[A-Za-z0-9]+$/.test(o)){
+ return true;
+ }
+ return false;
+}
+
+// 日期格式化
+export function parseTime(time, pattern) {
+ if (arguments.length === 0 || !time) {
+ return null
+ }
+ const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
+ let date
+ if (typeof time === 'object') {
+ date = time
+ } else {
+ if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
+ time = parseInt(time)
+ } else if (typeof time === 'string') {
+ time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), '');
+ }
+ if ((typeof time === 'number') && (time.toString().length === 10)) {
+ time = time * 1000
+ }
+ date = new Date(time)
+ }
+ const formatObj = {
+ y: date.getFullYear(),
+ m: date.getMonth() + 1,
+ d: date.getDate(),
+ h: date.getHours(),
+ i: date.getMinutes(),
+ s: date.getSeconds(),
+ a: date.getDay()
+ }
+ const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
+ let value = formatObj[key]
+ // Note: getDay() returns 0 on Sunday
+ if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
+ if (result.length > 0 && value < 10) {
+ value = '0' + value
+ }
+ return value || 0
+ })
+ return time_str
+}
+
+export function formatDate(time, option) {
+ if (('' + time).length === 10) {
+ time = parseInt(time) * 1000
+ } else {
+ time = +time
+ }
+
+ if (option) {
+ return parseTime(time, option)
+ }
+
+ const d = new Date(time)
+ const now = Date.now()
+
+ const diff = (now - d) / 1000
+
+ if (diff < 30) {
+ return '刚刚'
+ } else if (diff < 3600) {
+ // less 1 hour
+ return Math.ceil(diff / 60) + '分钟前'
+ } else if (diff < 3600 * 24) {
+ return Math.ceil(diff / 3600) + '小时前'
+ } else if (diff < 3600 * 24 * 2) {
+ return '1天前'
+ } else if (diff < 3600 * 24 * 3) {
+ return '2天前'
+ } else if (diff < 3600 * 24 * 4) {
+ return '3天前'
+ } else if (diff < 3600 * 24 * 5) {
+ return '4天前'
+ } else if (diff < 3600 * 24 * 6) {
+ return '5天前'
+ } else if (diff < 3600 * 24 * 7) {
+ return '6天前'
+ } else if (diff < 3600 * 24 * 8) {
+ return '7天前'
+ }
+ if(diff < 3600 * 24 * 365) {
+ return (
+ (d.getMonth()*1 + 1) +
+ '月' +
+ d.getDate() +
+ '日'
+ )
+ } else {
+ return (
+ d.getFullYear() +
+ '年' +
+ (d.getMonth()*1 + 1) +
+ '月'
+ )
+ }
+}
+
+export function formatTime(time, option) {
+ if (('' + time).length === 10) {
+ time = parseInt(time) * 1000
+ } else {
+ time = +time
+ }
+
+ if (option) {
+ return parseTime(time, option)
+ }
+
+ const d = new Date(time)
+ const now = Date.now()
+
+ const diff = (now - d) / 1000
+
+ return (
+ d.getFullYear() +
+ '-' +
+ ((d.getMonth()*1 + 1) + "").padStart(2,0) +
+ '-' +
+ (d.getDate() + '').padStart(2,0) +
+ ' ' +
+ (d.getHours() + '').padStart(2,0) +
+ ':' +
+ (d.getMinutes() + '').padStart(2,0) +
+ ':' +
+ (d.getSeconds() + '').padStart(2,0)
+ )
+}
+
+// number:要格式化的数字,
+// decimals:保留几位小数, 默认0位
+// dec_point:小数点符号, 默认 .
+// thousands_sep:千分位符号 默认 ,
+// tail_add: 小数点后面数据是否添加0补足位数, 默认空字符
+// null_default: 如果为空的值, 默认空字符
+function numberFormat(number, decimals, tail_add="", thousands_sep, dec_point, null_default="") {
+ number = (number + '').replace(/[^0-9+-Ee.]/g, '');
+ var n = !isFinite(+number) ? 0 : +number,
+ prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
+ sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
+ dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
+ s = '',
+ toFixedFix = function (n, prec) {
+ var k = Math.pow(10, prec);
+ return '' + Math.round(n * k) / k;
+ };
+
+ s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.');
+ var re = /(-?\d+)(\d{3})/;
+ if(sep.length > 0){
+ 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(tail_add);
+ }
+ if((s[1] || '').length == 0){
+ return s[0]
+ }
+ return s.join(dec);
+}
+// number:要格式化的数字,
+// decimals:保留几位小数, 默认0位
+// dec_point:小数点符号, 默认 .
+// thousands_sep:千分位符号 默认 ,
+// tail_add: 小数点后面数据是否添加0补足位数, 默认空字符
+// null_default: 如果为空的值, 默认空字符
+export function formatNumber(number, decimals, tail_add, thousands_sep, dec_point, null_default) {
+ if(isNull(number) || isNull(String(number).trim())){return null_default;}
+ if(!isNumber(String(number).trim())){return number;}
+ number = String(number).trim();
+ return numberFormat(number, decimals, tail_add, thousands_sep, dec_point, null_default);
+}
+// thousands_sep:千分位符号 默认空字符
+export function formatPercent(number, decimals, tail_add, thousands_sep="", dec_point, null_default) {
+ if(isNull(number) || isNull(String(number).trim().replaceAll(",", ""))){return null_default;}
+ if(!isNumber(String(number).trim().replaceAll(",", ""))){return number;}
+ number = String(number).trim().replaceAll(",", "");
+ let value = numberFormat(number*100, decimals, tail_add, thousands_sep, dec_point, null_default);
+ if(value){
+ return value + "%";
+ }
+ return "";
+}
+
+// get brower
+export function GetCurrentBrowser () {
+ let ua = navigator.userAgent.toLocaleLowerCase()
+ let browserType = null
+ if (ua.match(/msie/) != null || ua.match(/trident/) != null) {
+ browserType = 'IE'
+ } else if (ua.match(/firefox/) != null) {
+ browserType = 'firefox'
+ } else if (ua.match(/ucbrowser/) != null) {
+ browserType = 'UC'
+ } else if (ua.match(/opera/) != null || ua.match(/opr/) != null) {
+ browserType = 'opera'
+ } else if (ua.match(/bidubrowser/) != null) {
+ browserType = 'baidu'
+ } else if (ua.match(/metasr/) != null) {
+ browserType = 'sougou'
+ } else if (ua.match(/tencenttraveler/) != null || ua.match(/qqbrowse/) != null) {
+ browserType = 'QQ'
+ } else if (ua.match(/maxthon/) != null) {
+ browserType = 'maxthon'
+ } else if (ua.match(/chrome/) != null) {
+ var is360 = _mime('type', 'application/vnd.chromium.remoting-viewer')
+ if (is360) {
+ browserType = '360'
+ } else {
+ browserType = 'chrome'
+ }
+ } else if (ua.match(/safari/) != null) {
+ browserType = 'Safari'
+ } else {
+ browserType = 'others'
+ }
+ return browserType
+}
+
+function _mime (option, value) {
+ var mimeTypes = navigator.mimeTypes
+ for (var mt in mimeTypes) {
+ if (mimeTypes[mt][option] === value) {
+ return true
+ }
+ }
+ return false
+}
+
+// get os
+export function GetOs () {
+ let sUserAgent = navigator.userAgent.toLocaleLowerCase()
+ let isWin = (navigator.platform.toLocaleLowerCase() == 'win32') || (navigator.platform.toLocaleLowerCase() === 'windows')
+ let isMac = (navigator.platform.toLocaleLowerCase() === 'mac68k') || (navigator.platform.toLocaleLowerCase() === 'macppc')
+ || (navigator.platform === 'macintosh') || (navigator.platform.toLocaleLowerCase() === 'macintel')
+ if (isMac) return 'Mac'
+ var isUnix = (navigator.platform === 'x11') && !isWin && !isMac
+ if (isUnix) return 'Unix'
+ var isLinux = (String(navigator.platform.toLocaleLowerCase()).indexOf('linux') > -1)
+ if (isLinux) return 'Linux'
+ if (isWin) {
+ var isWin2K = sUserAgent.indexOf('windows nt 5.0') > -1 || sUserAgent.indexOf('windows 2000') > -1
+ if (isWin2K) return 'Win2000'
+ var isWinXP = sUserAgent.indexOf('windows nt 5.1') > -1 || sUserAgent.indexOf('windows xp') > -1
+ if (isWinXP) return 'WinXP'
+ var isWin2003 = sUserAgent.indexOf('windows nt 5.2') > -1 || sUserAgent.indexOf('windows 2003') > -1
+ if (isWin2003) return 'Win2003'
+ var isWinVista = sUserAgent.indexOf('windows nt 6.0') > -1 || sUserAgent.indexOf('windows vista') > -1
+ if (isWinVista) return 'WinVista'
+ var isWin7 = sUserAgent.indexOf('windows nt 6.1') > -1 || sUserAgent.indexOf('windows 7') > -1
+ if (isWin7) return 'Win7'
+ var isWin8 = sUserAgent.indexOf('windows nt 6.2') > -1 || sUserAgent.indexOf('windows 8') > -1
+ if (isWin8) return 'Win8'
+ var isWin10 = sUserAgent.indexOf('windows nt 10.0') > -1 || sUserAgent.indexOf('windows nt 6.4') > -1 || sUserAgent.indexOf('windows 10') > -1
+ if (isWin10) return 'Win10'
+ var isSimulator = sUserAgent.indexOf('linux') > -1 && sUserAgent.indexOf('android') > -1
+ if (isSimulator) return 'Win手机模拟器'
+ return navigator.platform
+ }
+ if (sUserAgent.indexOf('android') > -1) return 'Android'
+ if (sUserAgent.indexOf('iphone') > -1) return 'iPhone'
+ if (sUserAgent.indexOf('symbianos') > -1) return 'SymbianOS'
+ if (sUserAgent.indexOf('windows phone') > -1) return 'Windows Phone'
+ if (sUserAgent.indexOf('ipad') > -1) return 'iPad'
+ if (sUserAgent.indexOf('ipod') > -1) return 'iPod'
+ return navigator.platform
+}
+
+export function getRandom(len){
+ let data = Math.random() + "";
+ let index = 2;
+ while(data[index] == 0){
+ index++;
+ }
+ return data.substr(index, len);
+}
+
+export function getLongRandom(len){
+ if(len <= 16){
+ return getRandom(len)
+ }
+ let data = Math.random() + "";
+ let index = 2;
+ while(data[index] == 0){
+ index++;
+ }
+ return parseTime(Date.now(), '{y}{m}{d}{h}{i}{s}') + "" + data.substr(index, len-16);
+}
+
+export function moveInArray(array, fromIndex, toIndex) {
+ const element = array.splice(fromIndex, 1)[0];
+ array.splice(toIndex, 0, element);
+}
+
+export function jsonCharBigInt(s){
+ if(typeof s !== 'string'){
+ return s
+ }
+ let re = /([\\]?['|"]{1})(\w+[\\]?['|"]{1}[ |\n|r|\t]*:[ |\n|r|\t]*)([-]?\d{15,})/g
+ return s.replaceAll(re, "$1$2$1$3$1")
+}
+
+export function jsonParse(s){
+ if(typeof s !== 'string'){
+ return s
+ }
+ let re = /([\\]?['|"]{1})(\w+[\\]?['|"]{1}[ |\n|r|\t]*:[ |\n|r|\t]*)([-]?\d{15,})/g
+ return JSON.parse(s.replaceAll(re, "$1$2$1$3$1"))
+}
\ No newline at end of file
diff --git a/utils/nodeId.js b/utils/nodeId.js
new file mode 100644
index 0000000..cceab2e
--- /dev/null
+++ b/utils/nodeId.js
@@ -0,0 +1,13 @@
+const NodeIdKey = 'App-Node-Id'
+
+export function getNodeId() {
+ return uni.getStorageSync(NodeIdKey)
+}
+
+export function setNodeId(nodeId) {
+ return uni.setStorageSync(NodeIdKey, nodeId)
+}
+
+export function removeNodeId() {
+ return uni.removeStorageSync(NodeIdKey)
+}
diff --git a/utils/queryByDiy.js b/utils/queryByDiy.js
new file mode 100644
index 0000000..bbc19ed
--- /dev/null
+++ b/utils/queryByDiy.js
@@ -0,0 +1,17 @@
+import request from '@/utils/request'
+
+export function diyApi(url, data = {}, method = "POST", contentType = 'json') {
+ return request({
+ 'url': url,
+ 'method': method,
+ 'data': data
+ })
+}
+
+export function diyApiGet(url, data = {}, method = "GET", contentType = 'json') {
+ return request({
+ 'url': url,
+ 'method': method,
+ 'params': data
+ })
+}
\ No newline at end of file
diff --git a/utils/request.js b/utils/request.js
new file mode 100644
index 0000000..37bf244
--- /dev/null
+++ b/utils/request.js
@@ -0,0 +1,106 @@
+import store from '@/store'
+import { getToken } from '@/utils/token'
+import errorCode from '@/utils/errorCode'
+import { getSessionCache, setSessionCache } from '@/utils/cache'
+import { toast, showConfirm, tansParams } from '@/utils/requestTool'
+
+let timeout = 10000
+const baseUrl = import.meta.env.VITE_APP_BASE_URL
+
+const request = config => {
+ // 是否需要设置 token
+ const isToken = (config.headers || {}).isToken === false
+ // 是否需要防止数据重复提交
+ const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
+ config.header = config.header || {}
+ if (getToken() && !isToken) {
+ config.header['Authorization'] = 'Vrapile ' + getToken()
+ }
+ // get请求映射params参数
+ if (config.params) {
+ let url = config.url + '?' + tansParams(config.params)
+ url = url.slice(0, -1)
+ config.url = url
+ }
+ if (!isRepeatSubmit) {
+ const requestObj = {
+ url: config.url,
+ data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
+ time: new Date().getTime()
+ }
+ const sessionObj = getSessionCache()
+ if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
+ setSessionCache(requestObj)
+ } else {
+ const s_url = sessionObj.url; // 请求地址
+ const s_data = sessionObj.data; // 请求数据
+ const s_time = sessionObj.time; // 请求时间
+ const interval = 1000; // 间隔时间(ms),小于此时间视为重复提交
+ if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
+ const message = '数据正在处理,请勿重复提交:' + s_url;
+ console.warn(`[${s_url}]: ` + message)
+ return Promise.reject(new Error(message))
+ } else {
+ setSessionCache(requestObj)
+ }
+ }
+ }
+ return new Promise((resolve, reject) => {
+ uni.request({
+ method: config.method || 'get',
+ timeout: config.timeout || timeout,
+ url: config.baseUrl || baseUrl + config.url,
+ data: config.data,
+ header: config.header,
+ dataType: 'json'
+ }).then(res => {
+ const code = res.data.code || res.data.status || 200
+ const msg = errorCode[code] || res.data.msg || errorCode['default']
+
+ if (code === 401) {
+ // 密码登录的,实现自动重新登录
+ let loginInfo = store.state.user.loginInfo;
+ if(loginInfo && loginInfo.loginType == 0){
+ store.dispatch('Login', {
+ loginType: loginInfo.loginType,
+ userName: loginInfo.userName,
+ password: loginInfo.password,
+ registerFlag: "N"
+ }).then(() => {
+ store.dispatch('GetInfo');
+ })
+ reject('无效的会话,或者会话已过期,已重新登录。')
+ }else{
+ showConfirm('登录状态已过期,您可以继续留在该页面,或者重新登录?').then(res => {
+ if (res.confirm) {
+ uni.reLaunch({ url: '/pages/user/login' })
+ }
+ })
+ reject('无效的会话,或者会话已过期,请重新登录。')
+ }
+ } else if (code === 500) {
+ toast(msg)
+ reject('500')
+ } else if (code !== 200) {
+ toast(msg)
+ reject(code)
+ }
+ resolve(res.data)
+ }).catch(error => {
+ let { message } = error
+ if (message && message === 'Network Error') {
+ message = '后端接口连接异常'
+ } else if (message && message.includes('timeout')) {
+ message = '系统接口请求超时'
+ } else if (message && message.includes('Request failed with status code')) {
+ message = '系统接口' + message.substr(message.length - 3) + '异常'
+ }else{
+ message = '系统繁忙'
+ }
+ toast(message)
+ reject(error)
+ })
+ })
+}
+
+export default request
diff --git a/utils/requestTool.js b/utils/requestTool.js
new file mode 100644
index 0000000..00d4137
--- /dev/null
+++ b/utils/requestTool.js
@@ -0,0 +1,54 @@
+/**
+* 显示消息提示框
+* @param content 提示的标题
+*/
+export function toast(content) {
+ uni.showToast({
+ icon: 'none',
+ title: content
+ })
+}
+
+/**
+* 显示模态弹窗
+* @param content 提示的标题
+*/
+export function showConfirm(content) {
+ return new Promise((resolve, reject) => {
+ uni.showModal({
+ title: '提示',
+ content: content,
+ cancelText: '取消',
+ confirmText: '确定',
+ success: function(res) {
+ resolve(res)
+ }
+ })
+ })
+}
+
+/**
+* 参数处理
+* @param params 参数
+*/
+export function tansParams(params) {
+ let result = ''
+ for (const propName of Object.keys(params)) {
+ const value = params[propName]
+ var part = encodeURIComponent(propName) + "="
+ if (value !== null && value !== "" && typeof (value) !== "undefined") {
+ if (typeof value === 'object') {
+ for (const key of Object.keys(value)) {
+ if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') {
+ let params = propName + '[' + key + ']'
+ var subPart = encodeURIComponent(params) + "="
+ result += subPart + encodeURIComponent(value[key]) + "&"
+ }
+ }
+ } else {
+ result += part + encodeURIComponent(value) + "&"
+ }
+ }
+ }
+ return result
+}
\ No newline at end of file
diff --git a/utils/storage.js b/utils/storage.js
new file mode 100644
index 0000000..1ab33d1
--- /dev/null
+++ b/utils/storage.js
@@ -0,0 +1,32 @@
+import constant from './constant'
+
+// 存储变量名
+let storageKey = 'storage_data'
+
+// 存储节点变量名
+let storageNodeKeys = [constant.avatar, constant.name, constant.userInfo, constant.loginInfo]
+
+const storage = {
+ set: function(key, value) {
+ if (storageNodeKeys.indexOf(key) != -1) {
+ let tmp = uni.getStorageSync(storageKey)
+ tmp = tmp ? tmp : {}
+ tmp[key] = value
+ uni.setStorageSync(storageKey, tmp)
+ }
+ },
+ get: function(key) {
+ let storageData = uni.getStorageSync(storageKey) || {}
+ return storageData[key] || ""
+ },
+ remove: function(key) {
+ let storageData = uni.getStorageSync(storageKey) || {}
+ delete storageData[key]
+ uni.setStorageSync(storageKey, storageData)
+ },
+ clean: function() {
+ uni.removeStorageSync(storageKey)
+ }
+}
+
+export default storage
diff --git a/utils/token.js b/utils/token.js
new file mode 100644
index 0000000..9a7cc04
--- /dev/null
+++ b/utils/token.js
@@ -0,0 +1,13 @@
+const TokenKey = 'App-Token'
+
+export function getToken() {
+ return uni.getStorageSync(TokenKey)
+}
+
+export function setToken(token) {
+ return uni.setStorageSync(TokenKey, token)
+}
+
+export function removeToken() {
+ return uni.removeStorageSync(TokenKey)
+}