Browse Source

初始化

master
袁磊 4 weeks ago
commit
e1ad1d4ebe
  1. 16
      .env.development
  2. 14
      .env.production
  3. 2
      .gitignore
  4. 104
      App.vue
  5. 35
      api/chat.js
  6. 62
      api/login.js
  7. 21
      index.html
  8. 23
      main.js
  9. 79
      manifest.json
  10. 105
      pages.json
  11. 158
      pages/home/user.vue
  12. 44
      pages/setting/about.vue
  13. 81
      pages/setting/contact.vue
  14. 75
      pages/setting/setting.vue
  15. 259
      pages/user/login.vue
  16. 173
      pages/user/register.vue
  17. 96
      permission.js
  18. 72
      plugins/modal.js
  19. 15
      plugins/pluginTool.js
  20. 74
      plugins/tab.js
  21. BIN
      static/image/app.png
  22. BIN
      static/image/favicon.ico
  23. BIN
      static/image/ninecloud-white.png
  24. BIN
      static/image/tabbar/chat-fill.png
  25. BIN
      static/image/tabbar/chat.png
  26. BIN
      static/image/tabbar/home-fill.png
  27. BIN
      static/image/tabbar/home.png
  28. BIN
      static/image/tabbar/type-fill.png
  29. BIN
      static/image/tabbar/type.png
  30. BIN
      static/image/tabbar/user-fill.png
  31. BIN
      static/image/tabbar/user.png
  32. BIN
      static/image/user/cc.png
  33. BIN
      static/image/user/login-password-blue.png
  34. BIN
      static/image/user/login-phone-blue.png
  35. BIN
      static/image/user/message.png
  36. BIN
      static/image/user/uset.png
  37. BIN
      static/image/user/yy.png
  38. 555
      static/style/nine-base-001.scss
  39. 136
      static/style/nine-base-002.scss
  40. 27
      static/style/nine-btn-001.scss
  41. 1
      static/style/nine-chat-friend-001.scss
  42. 1
      static/style/nine-chat-home-001.scss
  43. 36
      static/style/nine-image-001.scss
  44. 9
      static/style/nine-list-001.scss
  45. 39
      static/style/nine-nav-001.scss
  46. 8
      store/getters.js
  47. 15
      store/index.js
  48. 94
      store/modules/user.js
  49. 76
      uni.scss
  50. 42
      uni_modules/uni-icons/changelog.md
  51. 91
      uni_modules/uni-icons/components/uni-icons/uni-icons.uvue
  52. 110
      uni_modules/uni-icons/components/uni-icons/uni-icons.vue
  53. 664
      uni_modules/uni-icons/components/uni-icons/uniicons.css
  54. BIN
      uni_modules/uni-icons/components/uni-icons/uniicons.ttf
  55. 664
      uni_modules/uni-icons/components/uni-icons/uniicons_file.ts
  56. 649
      uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js
  57. 89
      uni_modules/uni-icons/package.json
  58. 8
      uni_modules/uni-icons/readme.md
  59. 8
      uni_modules/uni-scss/changelog.md
  60. 1
      uni_modules/uni-scss/index.scss
  61. 82
      uni_modules/uni-scss/package.json
  62. 4
      uni_modules/uni-scss/readme.md
  63. 7
      uni_modules/uni-scss/styles/index.scss
  64. 3
      uni_modules/uni-scss/styles/setting/_border.scss
  65. 66
      uni_modules/uni-scss/styles/setting/_color.scss
  66. 55
      uni_modules/uni-scss/styles/setting/_radius.scss
  67. 56
      uni_modules/uni-scss/styles/setting/_space.scss
  68. 167
      uni_modules/uni-scss/styles/setting/_styles.scss
  69. 24
      uni_modules/uni-scss/styles/setting/_text.scss
  70. 146
      uni_modules/uni-scss/styles/setting/_variables.scss
  71. 19
      uni_modules/uni-scss/styles/tools/functions.scss
  72. 31
      uni_modules/uni-scss/theme.scss
  73. 62
      uni_modules/uni-scss/variables.scss
  74. 40
      uni_modules/vrapile-im/changelog.md
  75. 5
      uni_modules/vrapile-im/components/vrapile-im/vrapile-im.vue
  76. 86
      uni_modules/vrapile-im/package.json
  77. 335
      uni_modules/vrapile-im/pages/chat/chatFriend.vue
  78. 184
      uni_modules/vrapile-im/pages/home/chatHome.vue
  79. 20
      uni_modules/vrapile-im/pages_init.json
  80. 105
      uni_modules/vrapile-im/readme.md
  81. BIN
      uni_modules/vrapile-im/static/image/emoji.png
  82. BIN
      uni_modules/vrapile-im/static/image/message.png
  83. BIN
      uni_modules/vrapile-im/static/image/more.png
  84. BIN
      uni_modules/vrapile-im/static/image/voice.png
  85. BIN
      uni_modules/vrapile-im/static/image/yy.png
  86. 165
      uni_modules/vrapile-im/static/style/nine-chat-friend-001.scss
  87. 112
      uni_modules/vrapile-im/static/style/nine-chat-home-001.scss
  88. 11
      uni_modules/vrapile-im/store/getters.js
  89. 16
      uni_modules/vrapile-im/store/index.js
  90. 138
      uni_modules/vrapile-im/store/modules/chat.js
  91. 116
      uni_modules/vrapile-im/store/modules/socket.js
  92. 26
      uni_modules/vrapile-im/utils/cache.js
  93. 6
      uni_modules/vrapile-im/utils/constant.js
  94. 6
      uni_modules/vrapile-im/utils/errorCode.js
  95. 348
      uni_modules/vrapile-im/utils/nineTool.js
  96. 33
      uni_modules/vrapile-im/utils/storage.js
  97. 181
      uni_modules/vrapile-im/utils/tiosocket.js
  98. 26
      utils/cache.js
  99. 8
      utils/constant.js
  100. 6
      utils/errorCode.js

16
.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'

14
.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'

2
.gitignore

@ -0,0 +1,2 @@
/.hbuilderx
/unpackage

104
App.vue

@ -0,0 +1,104 @@
<script>
import store from '@/store'
import socketStore from '@/uni_modules/vrapile-im/store'
import { getToken } from '@/utils/token'
export default {
globalData: {
// appId
appId: "nine-demo-im",
//
platform: "android",
//
msgTabBarIndex: 0,
//
version: "1.0.0",
//
systemInfo: {},
},
onLaunch(options) {
//
this.initConfig(options);
},
onShow() {
// websocket
this.initWebSocket();
},
onHide() {
},
methods: {
initConfig(options) {
//
this.globalData.systemInfo = uni.getSystemInfoSync()
this.globalData.platform = this.globalData.systemInfo.platform
// #ifdef APP-PLUS
plus.runtime.getProperty(plus.runtime.appid, (wgtinfo) => {
if(wgtinfo.version){
this.globalData.version = wgtinfo.version;
}else{
//
this.globalData.version = plus.runtime.version;
}
});
// #endif
},
initWebSocket(){
if(getToken()){
// #ifdef APP-PLUS
// appwebsocket
socketStore.dispatch('GetChatList', {userId: store.state.user.userInfo.userId}).then( res => {
socketStore.dispatch('ConnSocket', { url: import.meta.env.VITE_APP_SOCKET_URL, token: getToken() });
});
// #endif
// #ifndef APP-PLUS
if(!socketStore.state.socket.websocket
|| !socketStore.state.socket.websocket.getReadyState
|| socketStore.state.socket.websocket.getReadyState() != 1){
socketStore.dispatch('GetChatList', {userId: store.state.user.userInfo.userId}).then( res => {
socketStore.dispatch('ConnSocket', { url: import.meta.env.VITE_APP_SOCKET_URL, token: getToken() });
});
}
// #endif
}
}
}
}
</script>
<style lang="scss">
html, body, #app{
height: 100%;
background-color: #f1f1f1;
}
.nine-content-001{
padding: 0;
margin: 0;
width: 750rpx;
height: calc(100vh - 0px);
background-color: #f1f1f1;
display: flex;
flex-direction: column;
}
.nine-content-002{
padding: 0;
margin: 0;
width: 750rpx;
height: calc(100vh - 50px);
/* #ifndef H5 */
height: calc(100vh - 0px);
/* #endif */
background-color: #f1f1f1;
display: flex;
flex-direction: column;
}
// uni.showModal
.uni-modal__bd{
text-align: left
}
@import './static/style/nine-image-001.scss';
@import './static/style/nine-btn-001.scss';
@import './static/style/nine-list-001.scss';
@import './static/style/nine-nav-001.scss';
@import './static/style/nine-base-002.scss';
@import './static/style/nine-base-001.scss';
</style>

35
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
})
}

62
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
})
}

21
index.html

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<!--preload-links-->
<!--app-context-->
<link rel="icon" href="/static/image/favicon.ico">
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/main.js"></script>
</body>
</html>

23
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
}
}

79
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" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
/* 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/"
}
}
}

105
pages.json

@ -0,0 +1,105 @@
{
"pages": [ //pageshttps://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": {}
}

158
pages/home/user.vue

@ -0,0 +1,158 @@
<template>
<view class="nine-content-002">
<view class="user-header">
<view class="user-header-top">
<view class="user-header-top-info">
<view class="user-header-top-info-logo">
<image class="user-header-top-info-logo-image" :src="userInfo.avatar || '/static/image/user/yy.png'"></image>
</view>
<view class="user-header-top-info-name">
<view v-if="userInfo.userId" class="user-header-top-info-name-username">
{{userInfo.userName}}
</view>
<view v-else class="user-header-top-info-name-username"
@click="openUrl('/pages/user/login')">未登录</view>
</view>
</view>
<view v-if="userInfo.userId" class="user-header-top-message">
<image class="user-header-top-message-image" src="/static/image/user/message.png"></image>
</view>
</view>
<view class="user-header-recommend">
<span v-if="userInfo.userId">昵称{{userInfo.nickName}}</span>
<span v-else>昵称</span>
<span class="pr10">普通用户</span>
</view>
<view class="user-header-member">
<view v-if="userInfo.userId" class="user-header-member-rank">
等级{{array[1]}}
</view>
<view v-else class="user-header-member-rank">
等级
</view>
<view class="user-header-member-note">
会员等级越高权益越高
</view>
</view>
</view>
<view class="nine-nav-001 pa5">
<view class="nine-nav-001-item mt10" @click="openUrl('/pages/setting/setting')">
<view class="nine-nav-001-item-left">
<image class="image35" mode="scaleToFill" src="/static/image/user/uset.png"></image>
<text class="nine-nav-001-item-left-text">设置</text>
</view>
<view class="nine-nav-001-item-right">
<image class="nine-nav-001-item-right-image" mode="scaleToFill" src="/static/image/user/cc.png">
</image>
</view>
</view>
</view>
</view>
</template>
<script>
import store from '@/store'
import storage from '@/utils/storage'
import constant from '@/utils/constant'
import { getToken } from '@/utils/token'
export default {
data() {
return {
array: [
"普通会员",
"高级会员",
"超级会员"
],
userInfo: {},
}
},
onLoad(options){
this.userInfo = store.state.user.userInfo;
}
}
</script>
<style scoped>
.user{
display: flex;
flex-direction: column;
height: 100vh;
background-color: #f1f1f1;
}
.user-header {
width: 100%;
background-color: #00aaff;
position: relative;
}
.user-header-top {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.user-header-top-info{
display: flex;
flex-direction: row;
padding: 20rpx 40rpx 10rpx 40rpx;
}
.user-header-top-info-logo{
}
.user-header-top-info-logo-image{
width: 165rpx;
height: 165rpx;
border-radius: 50%;
will-change: transform;
}
.user-header-top-info-name{
padding: 20rpx;
}
.user-header-top-info-name-username{
font-size: 20px;
}
.user-header-top-message{
}
.user-header-top-message-image{
padding-right: 40rpx;
padding-top: 40rpx;
width: 45rpx;
height: 55rpx;
}
.user-header-recommend{
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 10rpx 30rpx 70rpx 40rpx;
font-size: 12px;
}
.user-header-member{
position: absolute;
height: 40rpx;
bottom: 0rpx;
left: 40rpx;
right: 40rpx;
padding: 10rpx;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
background-color: #474747;
border-top-left-radius: 10rpx;
border-top-right-radius: 10rpx;
}
.user-header-member-rank{
padding: 10rpx 10rpx;
font-size: 10px;
color: #ffaa00;
}
.user-header-member-note{
font-size: 10px;
padding: 8rpx 20rpx;
color: #919191;
background-color: #2e2e2e;
border-radius: 80rpx;
}
</style>

44
pages/setting/about.vue

@ -0,0 +1,44 @@
<template>
<view class="nine-content-001">
<view class="text-center ptb120">
<image class="image150" src="/static/image/app.png" mode="scaleToFill" ></image>
<view class="font-bold font-size20 mt10">
九云 IM Demo
</view>
</view>
<view class="nine-nav-001">
<view class="nine-nav-001-item ma10 ptb25">
<view class="nine-nav-001-item-left">
<text class="nine-nav-001-item-left-text">下载APP</text>
</view>
<view class="nine-nav-001-item-right">
<image class="nine-nav-001-item-right-image" mode="scaleToFill" src="/static/image/user/cc.png">
</image>
</view>
</view>
<view class="nine-nav-001-item ma10 ptb25">
<view class="nine-nav-001-item-left">
<text class="nine-nav-001-item-left-text">更新日志</text>
</view>
<view class="nine-nav-001-item-right">
<image class="nine-nav-001-item-right-image" mode="scaleToFill" src="/static/image/user/cc.png">
</image>
</view>
</view>
</view>
<view class="ptb30">
<view class="text-center color-blue font-size15">
九云科技有限公司服务协议
</view>
<view class="text-center font-size15">
九云科技 版权所有
</view>
<view class="text-center font-size15">
Copyright © 2024-2031 NineCloud.
</view>
<view class="text-center font-size15">
All Rights Reserved
</view>
</view>
</view>
</template>

81
pages/setting/contact.vue

@ -0,0 +1,81 @@
<template>
<view class="nine-content-001">
<view class="text-center ptb120">
<image class="image400" :src="wechatUrl" mode="scaleToFill" ></image>
<view class="font-size18 mt10">
微信账号{{ wechatAccount }}
</view>
</view>
<view class="nine-nav-001">
<view class="nine-nav-001-item ma10 ptb25">
<view class="nine-nav-001-item-left">
<text class="nine-nav-001-item-left-text">联系人</text>
</view>
<view class="nine-nav-001-item-right">
<text class="nine-nav-001-item-left-text">袁先生</text>
</view>
</view>
<view class="nine-nav-001-item ma10 ptb25">
<view class="nine-nav-001-item-left">
<text class="nine-nav-001-item-left-text">联系电话</text>
</view>
<view class="nine-nav-001-item-right">
<text class="nine-nav-001-item-left-text color-blue" @click="callPhone('18627959669')">18627959669</text>
</view>
</view>
<view class="nine-nav-001-item ma10 ptb25">
<view class="nine-nav-001-item-left">
<text class="nine-nav-001-item-left-text">微信号</text>
</view>
<view class="nine-nav-001-item-right">
<text class="nine-nav-001-item-left-text">18627959669</text>
</view>
</view>
<view class="nine-nav-001-item ma10 ptb25">
<view class="nine-nav-001-item-left">
<text class="nine-nav-001-item-left-text">邮箱账号</text>
</view>
<view class="nine-nav-001-item-right">
<text class="nine-nav-001-item-left-text">18627959669@163.com</text>
</view>
</view>
</view>
<view class="ptb30">
<view class="text-center color-blue font-size15">
九云科技有限公司服务协议
</view>
<view class="text-center font-size15">
九云科技 版权所有
</view>
<view class="text-center font-size15">
Copyright © 2024-2031 NineCloud.
</view>
<view class="text-center font-size15">
All Rights Reserved
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
wechatUrl: "https://fs.ninecloud.top/uniapp/unine/vrapile.png",
wechatAccount: "Vrapile",
};
},
onLoad() {
},
onShow(){
},
methods: {
callPhone(phoneNumber) {
uni.makePhoneCall({
phoneNumber: phoneNumber
});
}
}
};
</script>

75
pages/setting/setting.vue

@ -0,0 +1,75 @@
<template>
<view class="nine-content-001">
<!-- 功能列表 -->
<view class="nine-nav-001"><view class="nine-nav-001-item mt10">
<view class="nine-nav-001-item-left">
<text class="nine-nav-001-item-left-text">公告中心</text>
</view>
<view class="nine-nav-001-item-right">
<image class="nine-nav-001-item-right-image" mode="scaleToFill" src="/static/image/user/cc.png">
</image>
</view>
</view>
<view v-if="userInfo.userId" class="nine-nav-001-item mt10">
<view class="nine-nav-001-item-left">
<text class="nine-nav-001-item-left-text">修改密码</text>
</view>
<view class="nine-nav-001-item-right">
<image class="nine-nav-001-item-right-image" mode="scaleToFill" src="/static/image/user/cc.png">
</image>
</view>
</view>
<view class="nine-nav-001-item mt10" @click="openUrl('/pages/setting/contact')">
<view class="nine-nav-001-item-left">
<text class="nine-nav-001-item-left-text">联系我们</text>
</view>
<view class="nine-nav-001-item-right">
<image class="nine-nav-001-item-right-image" mode="scaleToFill" src="/static/image/user/cc.png">
</image>
</view>
</view>
<view class="nine-nav-001-item">
<view class="nine-nav-001-item-left">
<text class="nine-nav-001-item-left-text">清空缓存</text>
</view>
<view class="nine-nav-001-item-right">
<image class="nine-nav-001-item-right-image" mode="scaleToFill" src="/static/image/user/cc.png">
</image>
</view>
</view>
<view class="nine-nav-001-item" @click="openUrl('/pages/setting/about')">
<view class="nine-nav-001-item-left">
<text class="nine-nav-001-item-left-text">关于</text>
</view>
<view class="nine-nav-001-item-right">
<image class="nine-nav-001-item-right-image" mode="scaleToFill" src="/static/image/user/cc.png">
</image>
</view>
</view>
<view v-if="userInfo.userId" class="nine-btn-login-out-001 mt50" @click="logoutClick">
退出登录
</view>
</view>
</view>
</template>
<script>
import store from '@/store'
export default {
data() {
return {
userInfo: {},
};
},
onShow(){
this.userInfo = this.$store.state.user.userInfo;
},
methods: {
logoutClick() {
this.$store.dispatch('LogOut').then(res => {
this.reLaunchLogin();
})
}
}
};
</script>

259
pages/user/login.vue

@ -0,0 +1,259 @@
<template>
<view class="nine-content-001">
<view class="login">
<view class="login-logo">
<image class="login-logo-image" lazy-load="true" src="/static/image/ninecloud-white.png"></image>
</view>
<view class="login-block">
<view class="login-type">
<span @click="onNavBarTap(0)" :class="loginType == 0?'login-type-span-alive login-type-span':'login-type-span'">
密码登录
</span>
<span @click="onNavBarTap(1)" :class="loginType == 1?'login-type-span-alive login-type-span':'login-type-span'">
短信登录
</span>
</view>
<view class="login-phone">
<image class="login-phone-image" src="/static/image/user/login-phone-blue.png"></image>
<input class="login-phone-input input" :focus="isFocus=='username'" name="phone" placeholder="请输入您的账号/手机号" v-model="userName" @confirm="loginClick"/>
</view>
<view class="nine-line-001 mlr30"></view>
<view v-if="loginType == 0" class="login-phone">
<image class="login-phone-image" src="/static/image/user/login-password-blue.png"></image>
<input class="login-phone-input input" :focus="isFocus=='password'" password placeholder="请输入您的密码" v-model="password" @confirm="loginClick"/>
</view>
<view v-if="loginType == 1" class="login-verify">
<view class="display-flex-row">
<image class="login-verify-image" src="/static/image/user/login-password-blue.png"></image>
<input class="login-verify-input input" :focus="isFocus=='verify'" placeholder="请输入验证码" v-model="verifyCode" @confirm="loginClick"/>
</view>
<view class="nine-btn-verify-001 font-size12 text-nowrap pa10" @click="verifyClick">
{{verifyText}}
</view>
</view>
<view class="nine-line-001 mlr30"></view>
<view class="ma15 mr30 text-right color-blue" @click="forgetClick">
忘记密码?
</view>
<view class="nine-btn-save-001 ma20" @click="loginClick"> </view>
<!--#ifndef MP-WEIXIN-->
<view class="text-center ma20">没有账号?
<span class="ml10 color-blue" @click="registerClick">
立即注册
</span>
</view>
<!--#endif-->
</view>
</view>
</view>
</template>
<script>
import store from '@/store'
import socketStore from '@/uni_modules/vrapile-im/store'
import { getToken } from '@/utils/token'
export default {
data() {
return {
loginType: 0,
userName: "",
password: "",
verifyTimer: null,
verifyCode: "",
verifyTime: 0,
verifyText: "发送验证码",
isFocus: ""
}
},
// onBackPress(e){
// return true;
// },
onUnload() {
if(this.verifyTimer) {
clearTimeout(this.verifyTimer);
this.verifyTimer = null;
this.verifyTime = 0;
}
},
onShow(){
let loginInfo = this.$store.state.user.loginInfo;
this.loginType = loginInfo.loginType || 0;
this.userName = loginInfo.userName;
this.password = loginInfo.password;
if(!this.userName){
this.usernamefocus();
}else if(this.loginType == 0){
this.passwordfocus();
}else{
this.verifyfocus();
}
},
methods: {
onNavBarTap (index) {
this.loginType = index;
},
verifyClick(){
if(this.verifyTime != 0){
return;
}
if(!this.isPhone(this.userName)){
this.msg("必须为有效手机号");
return;
}
this.verifyTime = 60;
this.verifyText = this.verifyTime + " S";
this.verifyTimer = setInterval(() => {
this.timeInterval();
}, 1000)
this.diyApiGet('/captchaSms', {phone: this.userName}).catch(error => {
if(this.verifyTimer) {
clearTimeout(this.verifyTimer);
this.verifyTimer = null;
this.verifyTime = 0;
}
this.verifyText = "发送验证码";
});
},
timeInterval() {
this.verifyTime--;
if (this.verifyTime > 0) {
this.verifyText = this.verifyTime + " S";
}else{
if(this.verifyTimer) {
clearInterval(this.verifyTimer);
this.verifyTimer = null;
}
this.verifyText = "发送验证码";
}
},
loginClick(){
if(!this.userName){
this.usernamefocus();
return;
}
if(this.loginType==0 && !this.password){
this.passwordfocus();
return;
}
if(this.loginType==1 && !this.verifyCode){
this.verifyfocus();
return;
}
this.loading("正在登录...");
store.dispatch('Login', {
loginType: this.loginType,
userName: this.userName.trim(),
password: this.password,
smsCode: this.verifyCode,
registerFlag: "Y"
}).then(() => {
this.loginSuccess()
}).catch(() => {
})
},
loginSuccess() {
store.dispatch('GetInfo').then(res => {
socketStore.dispatch('GetChatList', {userId: store.state.user.userInfo.userId}).then(res=>{
socketStore.dispatch('ConnSocket', { url: import.meta.env.VITE_APP_SOCKET_URL, token: getToken() });
});
this.reLaunch('/pages/home/user')
this.closeLoading()
}).catch(()=>{
this.closeLoading()
})
},
registerClick() {
this.navigateTo('/pages/user/register')
},
forgetClick() {
// this.navigateTo('/pages/user/forget')
},
usernamefocus() {
this.isFocus = "username";
},
passwordfocus() {
this.isFocus = "password";
},
verifyfocus() {
this.isFocus = "verify";
}
}
}
</script>
<style scoped>
.login{
width: 750rpx;
height: 100vh;
background-color: #55aaff;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding-bottom: 50rpx;
}
.login-logo{
width: 650rpx;
opacity: 0.9;
}
.login-logo-image{
width: 600rpx;
height: 160rpx;
}
.login-block{
width: 630rpx;
background-color: #FFFFFF;
border-radius: 10rpx;
margin: 40rpx 0 150rpx 0;
padding: 15rpx;
}
.login-type{
margin: 20rpx;
display: flex;
justify-content: space-around;
}
.login-type-span{
width: 280rpx;
padding: 15rpx 0;
font-size: 20px;
border-radius: 10rpx;
text-align: center;
color: gray;
background-color: #ebf7ff;
}
.login-type-span-alive{
color: #fff;
background-color: #55aaff;
}
.login-phone{
display: flex;
align-items: center;
margin: 30rpx;
padding: 20rpx 20rpx 0 0rpx;
}
.login-verify{
display: flex;
align-items: center;
justify-content: space-between;
margin: 30rpx;
padding-top: 20rpx;
}
.login-phone-image,
.login-verify-image{
padding: 10rpx;
height: 40rpx;
width: 40rpx;
}
.login-phone-input,
.login-verify-input{
padding: 10rpx;
width: 100%;
}
</style>

173
pages/user/register.vue

@ -0,0 +1,173 @@
<template>
<view class="nine-content-001">
<view class="nine-list-001">
<view class="nine-list-001-item">
<span>用户账号</span>
<input class="mt10" placeholder="请输入用户账号" v-model="userName"/>
</view>
<view class="nine-list-001-item">
<span>用户姓名</span>
<input class="mt10" placeholder="请输入用户姓名" v-model="nickName"/>
</view>
<view class="nine-list-001-item">
<span>手机号</span>
<view class="display-flex-row">
<span class="mt10 mr20 color-gray">+86</span>
<input class="mt10" placeholder="请输入手机号" v-model="phone"/>
</view>
</view>
<view class="nine-list-001-item">
<span>登录密码</span>
<input class="mt10" password placeholder="请输入登录密码" v-model="password"/>
</view>
<view class="nine-list-001-item">
<span>确认密码</span>
<input class="mt10" password placeholder="请再次输入登录密码" v-model="password2"/>
</view>
<view class="nine-list-001-item">
<view class="display-flex-row-between">
<span>验证码</span>
<view class="nine-btn-verify-001 plr10 ptb5" @click="verifyClick">
<span>{{verifyText}}</span>
</view>
</view>
<input class="mt10" placeholder="请输入验证码" v-model="verifyCode"/>
</view>
<view class="display-flex-row pt20 pb10 justify-content-center">
<label class="display-flex-row">
<checkbox class="transform-scale07" :value="protocolFlag" :checked="protocolFlag==1" @click="checkBoxClick"/>
已阅读并同意
</label>
<span class="color-blue" @click="protocolClick">服务协议</span>
</view>
<view class="nine-btn-save-001 ma20" @click="registerClick">
</view>
<view class="text-center">已有账号?
<span class="ml10 color-blue" @click="loginClick">立即登录</span>
</view>
</view>
</view>
</template>
<script>
import store from "@/store"
export default {
data() {
return {
userName: "",
nickName: "",
phone: "",
password: "",
password2: "",
protocolFlag: "0",
verifyTimer: null,
verifyCode: "",
verifyTime: 0,
verifyText: "发送验证码"
}
},
methods: {
checkBoxClick(){
this.protocolFlag = String(1 - Number(this.protocolFlag));
},
registerClick(){
if(!this.userName){
this.msg("用户账号不允许为空");
return;
}
if(!this.isNumberOrLetter(this.userName)){
this.msg("用户账号只能是字母/数字组合");
return;
}
if(!this.nickName){
this.msg("用户姓名不允许为空");
return;
}
if(!this.phone){
this.msg("手机号不允许为空");
return;
}
if(!this.isPhone(this.phone)){
this.msg("必须为有效手机号");
return;
}
if(!this.verifyCode){
this.msg("验证码不允许为空");
return;
}
if(!this.password){
this.msg("登录密码不允许为空");
return;
}
if(!this.password2){
this.msg("确认密码不允许为空");
return;
}
if(this.password != this.password2){
this.msg("两次输入的登录密码不一致");
return;
}
if(this.protocolFlag == 0){
this.msg("请勾选服务协议");
return;
}
this.diyApi('/appRegister', {
userType: "app_user",
userName: this.userName.trim(),
nickName: this.nickName,
phone: this.phone,
password: this.password,
smsCode: this.verifyCode
}).then(res => {
store.commit('SET_LOGIN_INFO', {
...this.$store.state.user.loginInfo,
loginType: 0,
userName: this.userName,
password: this.password
})
this.msg("注册成功");
setTimeout(() => {
this.navigateToLogin();
}, 1500);
})
},
loginClick(){
this.navigateToLogin();
},
protocolClick(){
// this.navigateTo("/pages/setting/protocol")
},
verifyClick(){
if(this.verifyTime == 0){
if(!this.phone){
this.msg("必须为有效手机号");
return;
}
this.diyApiGet('/captchaSms', {phone: this.phone}).then(res => {
this.verifyTime = 60;
this.verifyText = this.verifyTime + " S";
this.verifyTimer = setInterval(() => {
this.timeInterval();
}, 1000)
})
}
},
timeInterval() {
this.verifyTime--;
if (this.verifyTime > 0) {
this.verifyText = this.verifyTime + " S";
}else{
if(this.verifyTimer) {
clearInterval(this.verifyTimer);
this.verifyTimer = null;
}
this.verifyText = "发送验证码";
}
},
}
}
</script>

96
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)
}
})
})

72
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()
}

15
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];
});
}
};

74
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)
}
}
})
})
}

BIN
static/image/app.png

After

Width: 100  |  Height: 100  |  Size: 14 KiB

BIN
static/image/favicon.ico

BIN
static/image/ninecloud-white.png

After

Width: 189  |  Height: 48  |  Size: 5.9 KiB

BIN
static/image/tabbar/chat-fill.png

After

Width: 156  |  Height: 156  |  Size: 7.5 KiB

BIN
static/image/tabbar/chat.png

After

Width: 156  |  Height: 156  |  Size: 7.2 KiB

BIN
static/image/tabbar/home-fill.png

After

Width: 156  |  Height: 156  |  Size: 7.1 KiB

BIN
static/image/tabbar/home.png

After

Width: 156  |  Height: 156  |  Size: 9.6 KiB

BIN
static/image/tabbar/type-fill.png

After

Width: 156  |  Height: 156  |  Size: 20 KiB

BIN
static/image/tabbar/type.png

After

Width: 156  |  Height: 156  |  Size: 28 KiB

BIN
static/image/tabbar/user-fill.png

After

Width: 156  |  Height: 156  |  Size: 15 KiB

BIN
static/image/tabbar/user.png

After

Width: 156  |  Height: 156  |  Size: 17 KiB

BIN
static/image/user/cc.png

After

Width: 27  |  Height: 46  |  Size: 1.7 KiB

BIN
static/image/user/login-password-blue.png

After

Width: 54  |  Height: 58  |  Size: 5.2 KiB

BIN
static/image/user/login-phone-blue.png

After

Width: 40  |  Height: 56  |  Size: 3.3 KiB

BIN
static/image/user/message.png

After

Width: 53  |  Height: 60  |  Size: 5.4 KiB

BIN
static/image/user/uset.png

After

Width: 68  |  Height: 64  |  Size: 6.5 KiB

BIN
static/image/user/yy.png

After

Width: 45  |  Height: 45  |  Size: 7.1 KiB

555
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 }

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

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

1
static/style/nine-chat-friend-001.scss

@ -0,0 +1 @@
/* 可重写内部/uni_modules/vrapile-im/static/style/nine-chat-friend-001.scss样式 */

1
static/style/nine-chat-home-001.scss

@ -0,0 +1 @@
/* 可重写内部/uni_modules/vrapile-im/static/style/nine-chat-home-001.scss样式 */

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

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

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

8
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

15
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

94
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

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

42
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目录规范

91
uni_modules/uni-icons/components/uni-icons/uni-icons.uvue

@ -0,0 +1,91 @@
<template>
<text class="uni-icons" :style="styleObj">
<slot>{{unicode}}</slot>
</text>
</template>
<script>
import { fontData, IconsDataItem } from './uniicons_file'
/**
* Icons 图标
* @description 用于展示 icon 图标
* @tutorial https://ext.dcloud.net.cn/plugin?id=28
* @property {Number,String} size 图标大小
* @property {String} type 图标图案,参考示例
* @property {String} color 图标颜色
* @property {String} customPrefix 自定义图标
* @event {Function} click 点击 Icon 触发事件
*/
export default {
name: "uni-icons",
props: {
type: {
type: String,
default: ''
},
color: {
type: String,
default: '#333333'
},
size: {
type: [Number, String],
default: 16
},
fontFamily: {
type: String,
default: ''
}
},
data() {
return {};
},
computed: {
unicode() : string {
let codes = fontData.find((item : IconsDataItem) : boolean => { return item.font_class == this.type })
if (codes !== null) {
return codes.unicode
}
return ''
},
iconSize() : string {
const size = this.size
if (typeof size == 'string') {
const reg = /^[0-9]*$/g
return reg.test(size as string) ? '' + size + 'px' : '' + size;
// return '' + this.size
}
return this.getFontSize(size as number)
},
styleObj() : UTSJSONObject {
if (this.fontFamily !== '') {
return { color: this.color, fontSize: this.iconSize, fontFamily: this.fontFamily }
}
return { color: this.color, fontSize: this.iconSize }
}
},
created() { },
methods: {
/**
* 字体大小
*/
getFontSize(size : number) : string {
return size + 'px';
},
},
}
</script>
<style scoped>
@font-face {
font-family: UniIconsFontFamily;
src: url('./uniicons.ttf');
}
.uni-icons {
font-family: UniIconsFontFamily;
font-size: 18px;
font-style: normal;
color: #333;
}
</style>

110
uni_modules/uni-icons/components/uni-icons/uni-icons.vue

@ -0,0 +1,110 @@
<template>
<!-- #ifdef APP-NVUE -->
<text :style="styleObj" class="uni-icons" @click="_onClick">{{unicode}}</text>
<!-- #endif -->
<!-- #ifndef APP-NVUE -->
<text :style="styleObj" class="uni-icons" :class="['uniui-'+type,customPrefix,customPrefix?type:'']" @click="_onClick">
<slot></slot>
</text>
<!-- #endif -->
</template>
<script>
import { fontData } from './uniicons_file_vue.js';
const getVal = (val) => {
const reg = /^[0-9]*$/g
return (typeof val === 'number' || reg.test(val)) ? val + 'px' : val;
}
// #ifdef APP-NVUE
var domModule = weex.requireModule('dom');
import iconUrl from './uniicons.ttf'
domModule.addRule('fontFace', {
'fontFamily': "uniicons",
'src': "url('" + iconUrl + "')"
});
// #endif
/**
* Icons 图标
* @description 用于展示 icons 图标
* @tutorial https://ext.dcloud.net.cn/plugin?id=28
* @property {Number} size 图标大小
* @property {String} type 图标图案参考示例
* @property {String} color 图标颜色
* @property {String} customPrefix 自定义图标
* @event {Function} click 点击 Icon 触发事件
*/
export default {
name: 'UniIcons',
emits: ['click'],
props: {
type: {
type: String,
default: ''
},
color: {
type: String,
default: '#333333'
},
size: {
type: [Number, String],
default: 16
},
customPrefix: {
type: String,
default: ''
},
fontFamily: {
type: String,
default: ''
}
},
data() {
return {
icons: fontData
}
},
computed: {
unicode() {
let code = this.icons.find(v => v.font_class === this.type)
if (code) {
return code.unicode
}
return ''
},
iconSize() {
return getVal(this.size)
},
styleObj() {
if (this.fontFamily !== '') {
return `color: ${this.color}; font-size: ${this.iconSize}; font-family: ${this.fontFamily};`
}
return `color: ${this.color}; font-size: ${this.iconSize};`
}
},
methods: {
_onClick() {
this.$emit('click')
}
}
}
</script>
<style lang="scss">
/* #ifndef APP-NVUE */
@import './uniicons.css';
@font-face {
font-family: uniicons;
src: url('./uniicons.ttf');
}
/* #endif */
.uni-icons {
font-family: uniicons;
text-decoration: none;
text-align: center;
}
</style>

664
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";
}

BIN
uni_modules/uni-icons/components/uni-icons/uniicons.ttf

664
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<IconsDataItem>
}
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<IconsDataItem>(fontDataJson)

649
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<IconsDataItem>(fontDataJson)

89
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"
}
}
}
}
}

8
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

8
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

1
uni_modules/uni-scss/index.scss

@ -0,0 +1 @@
@import './styles/index.scss';

82
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"
}
}
}
}
}

4
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

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

3
uni_modules/uni-scss/styles/setting/_border.scss

@ -0,0 +1,3 @@
.uni-border {
border: 1px $uni-border-1 solid;
}

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

55
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)
}
}
}
}

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

167
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 */

24
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 */
}

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

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

31
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);

62
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);

40
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)
开发中,敬请期待

5
uni_modules/vrapile-im/components/vrapile-im/vrapile-im.vue

@ -0,0 +1,5 @@
<template>
<view>
vrapile-im页面组件此文件不会被引用
</view>
</template>

86
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"
}
}
}
}
}

335
uni_modules/vrapile-im/pages/chat/chatFriend.vue

@ -0,0 +1,335 @@
<template>
<view class="nine-content-001">
<view class="chat-body">
<view class="chat-body-main">
<view v-if="chatObject.haveHistory==0" class="chat-body-history">
没有更多消息了
</view>
<view v-else class="chat-body-history chat-body-history-have" @click="handleHistoryMessage()">
查看更多消息
</view>
<view class="chat-body-message">
<view v-for="(item, index) in messageList" :key="index">
<view class="chat-conversation" :class="item.fromId == userInfo.userId?'chat-conversation-mine':''">
<view class="chat-conversation-image">
<image class="chat-conversation-image-image" v-if="item.fromId != userInfo.userId" :src="getUserAvatar(item.fromId, item.avatar)"></image>
<image class="chat-conversation-image-image" v-else :src="userInfo.avatar || defaultAvatar"></image>
</view>
<view class="chat-conversation-text">
<view class="chat-conversation-text-time" v-if="item.sendType == 1 && item.fromId != userInfo.userId">{{getUserName(item.fromId, item.fromName)}}</view>
<view class="chat-conversation-text-time">{{formatTime(item.sendTime)}}</view>
<view class="chat-conversation-text-text nine-user-select">{{item.content}}</view>
</view>
</view>
</view>
</view>
</view>
</view>
<view class="chat-footer">
<view class="chat-footer-send">
<view @click="handleVoice" class="chat-footer-send-voice">
<image class="chat-footer-send-image" :src="iconVoice"></image>
</view>
<view v-if="isVoice" @longpress="handleSay" class="chat-footer-send-say">
<span>按住 说话</span>
</view>
<view v-else class="chat-footer-send-input">
<input @confirm="handleSend" class="input" v-model="inputText" />
</view>
<view @click="handleEmoji" class="chat-footer-send-emoji">
<image class="chat-footer-send-image" :src="iconEmoji"></image>
</view>
<view v-if="inputText" @click="handleSend" class="chat-footer-send-button">
<span class="chat-footer-send-button-span">发送</span>
</view>
<view v-else @click="handleMore" class="chat-footer-send-more">
<image class="chat-footer-send-image" :src="iconMore"></image>
</view>
</view>
</view>
</view>
</template>
<script>
import { mapState } from 'vuex'
import store from '@/uni_modules/vrapile-im/store'
import { getChatKey } from '@/uni_modules/vrapile-im/utils/tiosocket';
// storekey
import storeOut from '@/store'
import { getMessageByChatKey } from '@/api/chat'
export default {
data() {
return {
userInfo: {},
chatObject: {},
messageList: [],
noHistory: true,
isVoice: false,
inputText: "",
// key
key: null,
//
defaultAvatar: '/uni_modules/vrapile-im/static/image/yy.png',
//
iconMessage: "/uni_modules/vrapile-im/static/image/message.png",
//
iconVoice: "/uni_modules/vrapile-im/static/image/voice.png",
//
iconEmoji: "/uni_modules/vrapile-im/static/image/emoji.png",
//
iconMore: "/uni_modules/vrapile-im/static/image/more.png",
}
},
computed: {
...mapState({
websocketData: state => store.state.socket.websocketData
}),
getChatList() {
return store.state.chat.chatList;
},
getUserAvatar() {
return (userId, defaultAvatar) => {
return store.getters.getUserAvatar(userId, defaultAvatar);
}
},
getUserName() {
return (userId, defaultName) => {
return store.getters.getUserName(userId, defaultName);
}
}
},
onLoad(options){
this.userInfo = storeOut.state.user.userInfo;
if(!this.userInfo.userId){
this.navigateToLogin();
}
try{
this.key = options.data;
}catch(e){
this.switchTab("/uni_modules/vrapile-im/pages/home/chatHome");
}
},
//
onPullDownRefresh() {
if(this.chatObject.haveHistory==1){
this.handleHistoryMessage();
}
setTimeout(() => {
uni.stopPullDownRefresh();
}, 500);
},
onShow(){
for(let i=0; i < this.getChatList.length; i++){
if(this.getChatList[i]["key"] == this.key){
this.chatObject = this.getChatList[i];
uni.setNavigationBarTitle({
title: this.chatObject.name || "好友"
})
this.messageList = this.getChatList[i].messageList;
this.scrollToBottom();
if(this.messageList.length == 0 && this.chatObject.haveHistory==1){
this.handleHistoryMessage();
}else{
this.handleRead();
}
break;
}
}
},
//
watch: {
websocketData: {
handler(newVal, oldval) {
if(newVal && newVal.length > 0
&& (newVal[newVal.length-1]["toId"] == this.userInfo.userId
|| newVal[newVal.length-1]["fromId"] == this.userInfo.userId)){
this.scrollToBottom();
this.handleRead();
}
},
immediate: true,
deep: true
}
},
methods: {
//
scrollToBottom() {
setTimeout(() => {
uni.pageScrollTo({
scrollTop: 2000000,
duration : 10
})
}, 500);
},
//
handleVoice() {
this.isVoice = !this.isVoice;
},
//
handleSay() {
let sendInfo = {
code: 2,
message: {
// 0-|1-|2-|3-|4-
messageType: 0,
//id
toId: this.chatObject.id,
//
fromId: this.userInfo.userId,
//
fromName: this.userInfo.userName,
//
content: "您发送了一条语音消息",
//0-|1-
sendType: this.chatObject.type,
//
extend: null
},
};
uni.sendSocketMessage({
data: JSON.stringify(sendInfo)
})
},
//
handleEmoji() {
let sendInfo = {
code: 2,
message: {
// 0-|1-|2-|3-|4-
messageType: 0,
//id
toId: this.chatObject.id,
//
fromId: this.userInfo.userId,
//
fromName: this.userInfo.userName,
//
content: "您发送了一个表情消息",
//0-|1-
sendType: this.chatObject.type,
//
extend: null
},
};
uni.sendSocketMessage({
data: JSON.stringify(sendInfo)
})
},
//
handleMore() {
let sendInfo = {
code: 2,
message: {
// 0-|1-|2-|3-|4-
messageType: 0,
//id
toId: this.chatObject.id,
//
fromId: this.userInfo.userId,
//
fromName: this.userInfo.userName,
//
content: "您发送了一个更多的消息",
//0-|1-
sendType: this.chatObject.type,
//
extend: null
},
};
uni.sendSocketMessage({
data: JSON.stringify(sendInfo)
})
},
//
handleRead() {
let sendInfo = {
code: 3,
message: {
//id
toId: this.chatObject.id,
//
userId: this.userInfo.userId,
//0-|1-
sendType: this.chatObject.type,
},
};
uni.sendSocketMessage({
data: JSON.stringify(sendInfo)
})
store.commit('READ_MESSAGE', this.key);
store.commit('COUNT_MESSAGE');
},
//
handleSend() {
if(!this.inputText){
return;
}
let sendInfo = {
code: 2,
message: {
// 0-|1-|2-|3-|4-
messageType: 0,
//id
toId: this.chatObject.id,
//
fromId: this.userInfo.userId,
//
fromName: this.userInfo.userName,
//
content: this.inputText,
//0-|1-
sendType: this.chatObject.type,
//
extend: null
},
};
uni.sendSocketMessage({
data: JSON.stringify(sendInfo)
})
this.inputText = "";
},
//
handleHistoryMessage(){
let limit = this.chatObject["messageList"].length + 10;
getMessageByChatKey({
type: this.chatObject.type,
key: this.chatObject["key"],
groupId: this.chatObject.id,
limit: limit
}).then(res => {
if(res.data.length > 0){
this.messageList = res.data.reverse();
this.chatObject["messageList"] = this.messageList;
let lastMessage = res.data[res.data.length-1];
this.chatObject["messageLast"] = lastMessage;
if(lastMessage["sendType"] == 0){
this.chatObject["messageShow"] = lastMessage["content"];
}else{
this.chatObject["messageShow"] = store.getters.getUserName(lastMessage["fromId"], lastMessage["fromName"]) + ": " + lastMessage["content"]
}
this.chatObject["messageTime"] = this.formatDate(lastMessage["sendTime"]);
}
if(res.data.length < limit){
this.chatObject["haveHistory"] = 0;
}
for(let i=0; i < this.getChatList.length; i++){
if(this.getChatList[i]["key"] == this.key){
this.$set(this.getChatList, i, this.chatObject)
break;
}
}
this.scrollToBottom();
});
}
}
}
</script>
<style scoped>
/* 重写外部nine-chat-friend-001.scss可实现样式改变 */
@import '/uni_modules/vrapile-im/static/style/nine-chat-friend-001.scss';
@import '/static/style/nine-chat-friend-001.scss';
</style>

184
uni_modules/vrapile-im/pages/home/chatHome.vue

@ -0,0 +1,184 @@
<template>
<view class="nine-content-002">
<view class="chat-search">
<input class="chat-search-input" v-model="searchVal"/>
<uni-icons class="chat-search-image" type="search" size="24"></uni-icons>
</view>
<view class="chat-list">
<view class="chat-list-item" v-for="(item,index) in getChatFilterList" :key="index" @click="goToChat(item.key)">
<view class="chat-list-item-left">
<image class="chat-list-item-left-image" mode="scaleToFill" v-if="item.fromId != userInfo.userId" :src="getUserAvatar(item.fromId, item.avatar)"></image>
<image class="chat-list-item-left-image" mode="scaleToFill" v-else :src="userInfo.avatar || defaultAvatar"></image>
<view v-if="item.messageNum > 0" class="chat-list-item-left-mark">
{{ item.messageNum < 100 ? item.messageNum : 99 }}
</view>
</view>
<view class="chat-list-item-center">
<view class="chat-list-item-center-top">
{{ item.name }}
</view>
<view class="chat-list-item-center-bottom">
{{ item.messageShow || "&nbsp;" }}
</view>
</view>
<view class="chat-list-item-right">
<view class="chat-list-item-right-top">
{{ item.messageTime || '\xa0' }}
</view>
<view class="chat-list-item-right-bottom">
<image class="chat-list-item-right-bottom-image" mode="scaleToFill" :src="iconMessage">
</image>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import { mapState } from 'vuex'
import store from '@/uni_modules/vrapile-im/store'
import { getChatKey } from '@/uni_modules/vrapile-im/utils/tiosocket';
// storewebsockettokentokenkey
import storeOut from '@/store'
import { getToken } from '@/utils/token'
import { getMessageByChatKey } from '@/api/chat'
export default {
data() {
return {
userInfo: {},
searchVal: "",
//
defaultAvatar: '/uni_modules/vrapile-im/static/image/yy.png',
//
iconMessage: "/uni_modules/vrapile-im/static/image/message.png"
}
},
computed: {
...mapState({
websocketData: state => store.state.socket.websocketData
}),
getChatList() {
return store.state.chat.chatList;
},
getChatFilterList() {
let list = JSON.parse(JSON.stringify(store.state.chat.chatList))
list.sort((a, b) => {
if(a.messageNum > 0 && b.messageNum > 0){
return b.messageLast.sendTime - a.messageLast.sendTime
}
if(a.messageList.length == 0 || b.messageList.length == 0){
return b.messageList.length - a.messageList.length
}
if(a.messageNum == 0 && b.messageNum == 0){
return b.messageLast.sendTime - a.messageLast.sendTime
}
return b.messageNum - a.messageNum
})
if(this.searchVal){
return list.filter(item => {
if(item.name && item.name.includes(this.searchVal)
|| item.remarkName && item.remarkName.includes(this.searchVal)
|| item.userName && item.userName.includes(this.searchVal)){
return item;
}
for(let message of item.messageList){
if(message.content && message.content.includes(this.searchVal)){
return item;
}
}
});
}
return list;
},
getUserAvatar() {
return (userId, defaultAvatar) => {
return store.getters.getUserAvatar(userId, defaultAvatar);
}
}
},
onLoad(options){
this.userInfo = storeOut.state.user.userInfo;
},
onShow(){
setTimeout(()=>{
this.dealUnReadMessage();
store.commit('COUNT_MESSAGE');
}, 500)
setTimeout(()=>{
this.noListDo();
}, 3000)
},
activated(){
store.commit('COUNT_MESSAGE');
},
//
watch: {
websocketData: {
handler(newVal, oldval) {
for(let i=0;i<this.getChatList.length;i++){
this.$set(this.getChatList, i, this.getChatList[i])
}
},
immediate: true,
deep: true
}
},
methods: {
//
dealUnReadMessage() {
for(let i=0;i<this.getChatList.length;i++){
if(this.getChatList[i]["messageList"].length == 0 && this.getChatList[i]["haveHistory"] == 1){
this.handleHistoryMessage(i, false);
}
}
},
// socket
noListDo(){
if(storeOut.state.user.userInfo.userId && (!this.getChatList || this.getChatList.length == 0)){
store.dispatch('GetChatList', {userId: storeOut.state.user.userInfo.userId}).then(res => {
store.dispatch('ConnSocket', { url: import.meta.env.VITE_APP_SOCKET_URL, token: getToken() });
});
}
},
//
handleHistoryMessage(i, scrollFlag){
let limit = this.getChatList[i]["messageList"].length + 10;
getMessageByChatKey({
type: this.getChatList[i].type,
key: this.getChatList[i]["key"],
groupId: this.getChatList[i].id,
limit: limit
}).then(res => {
if(res.data.length > 0){
this.getChatList[i]["messageList"] = res.data.reverse();
let lastMessage = res.data[res.data.length-1];
this.getChatList[i]["messageLast"] = lastMessage;
if(lastMessage["sendType"] == 0){
this.getChatList[i]["messageShow"] = lastMessage["content"];
}else{
this.getChatList[i]["messageShow"] = store.getters.getUserName(lastMessage["fromId"], lastMessage["fromName"]) + ": " + lastMessage["content"]
}
this.getChatList[i]["messageTime"] = this.formatDate(lastMessage["sendTime"]);
}
if(res.data.length < limit){
this.getChatList[i]["haveHistory"] = 0;
}
this.$set(this.getChatList, i, this.getChatList[i])
});
},
//
goToChat(key) {
this.navigateTo("/uni_modules/vrapile-im/pages/chat/chatFriend?data=" + key)
}
}
}
</script>
<style scoped>
/* 重写外部nine-chat-home-001.scss可实现样式改变 */
@import '/uni_modules/vrapile-im/static/style/nine-chat-home-001.scss';
@import '/static/style/nine-chat-home-001.scss';
</style>

20
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
}
}
]
}

105
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,将原样式替换
## 演示说明
以下共用一个后端,全部互通
<br>
示例工程运行效果:
<a href="https://www.ninecloud.top/udemo/im/index.html" target="_blank">https://www.ninecloud.top/udemo/im/index.html</a>
<img src="https://fs.ninecloud.top/uniapp/udemo/im/qrcode.png" width="300">
<br>
<br>
演示商城H5效果:
<a href="https://www.ninecloud.top/unine/index.html" target="_blank">https://www.ninecloud.top/unine/index.html</a>
<img src="https://fs.ninecloud.top/uniapp/unine/qrcode.png" width="300">
<font color="gray">H5中可下载安卓App</font>
<br>
<br>
演示PC前端(与此组件无关,可用于多端消息互相发送测试):
<a href="https://www.ninecloud.top/msw/index" target="_blank">https://www.ninecloud.top/msw/index</a>
<br>
<br>
注:新注册账号,默认添加【visitor】为好友,默认加入【客服专用群】群
因此,可用访客/注册账号登录以上任意系统,可任意发送消息,皆能同步显示
(*以上系统皆可用访客账号/密码:visitor/visitor*)

BIN
uni_modules/vrapile-im/static/image/emoji.png

After

Width: 72  |  Height: 71  |  Size: 9.4 KiB

BIN
uni_modules/vrapile-im/static/image/message.png

After

Width: 53  |  Height: 60  |  Size: 5.4 KiB

BIN
uni_modules/vrapile-im/static/image/more.png

After

Width: 72  |  Height: 71  |  Size: 8.2 KiB

BIN
uni_modules/vrapile-im/static/image/voice.png

After

Width: 72  |  Height: 72  |  Size: 9.5 KiB

BIN
uni_modules/vrapile-im/static/image/yy.png

After

Width: 45  |  Height: 45  |  Size: 7.1 KiB

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

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

11
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

16
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

138
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

116
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<store.state.chat.chatList.length;i++){
let item = store.state.chat.chatList[i];
let key = getChatKey(message["sendType"], message["toId"], message["fromId"])
if(store.state.chat.chatList[i]["key"] == key){
store.state.chat.chatList[i]["messageList"].push(message)
store.state.chat.chatList[i]["messageTime"] = formatDate(message["sendTime"]);
store.state.chat.chatList[i]["messageLast"] = message;
store.state.chat.chatList[i]["haveHistory"] = 1;
// 自己发送的消息,总消息数是否加1,如果不加,取消下方注释内容
// if(store.state.user.userInfo.userId && store.state.user.userInfo.userId != message["fromId"]){
store.state.chat.chatList[i]["messageNum"] += 1;
// }
if(store.state.chat.chatList[i]["type"] == 0){
store.state.chat.chatList[i]["messageShow"] = message["content"];
}else{
store.state.chat.chatList[i]["messageShow"] = store.getters.getUserName(message["fromId"], message["fromName"]) + ": " + message["content"]
}
storage.set(constant.chatList, store.state.chat.chatList);
break;
}
}
store.commit('COUNT_MESSAGE');
},
// 回执已读消息
READ_MESSAGE: (state, k) => {
// 删除未读消息
for(let i=0;i<state.websocketData.length;i++){
let key = getChatKey(state.websocketData[i]["sendType"], state.websocketData[i]["toId"], state.websocketData[i]["fromId"])
if(key == k){
state.websocketData.splice(i, 1);
i--;
}
}
storage.set(constant.websocketData, state.websocketData)
// 重置已读消息数量
for(let i=0;i<store.state.chat.chatList.length;i++){
if(store.state.chat.chatList[i].key == k){
store.state.chat.chatList[i].messageNum = 0;
storage.set(constant.chatList, store.state.chat.chatList)
break;
}
}
store.commit('COUNT_MESSAGE');
},
// 统计消息总数
COUNT_MESSAGE: (state) => {
let unReadNum = 0
for(let i=0;i<store.state.chat.chatList.length;i++){
unReadNum += store.state.chat.chatList[i].messageNum*1;
}
try{
if(unReadNum > 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

26
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)
}

6
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

6
uni_modules/vrapile-im/utils/errorCode.js

@ -0,0 +1,6 @@
export default {
'401': '认证失败,无法访问系统资源',
'403': '当前操作没有权限',
'404': '访问资源不存在',
'default': '系统未知错误,请反馈给管理员'
}

348
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"))
}

33
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

181
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
}
}

26
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)
}

8
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

6
utils/errorCode.js

@ -0,0 +1,6 @@
export default {
'401': '认证失败,无法访问系统资源',
'403': '当前操作没有权限',
'404': '访问资源不存在',
'default': '系统未知错误,请反馈给管理员'
}

Some files were not shown because too many files changed in this diff

|||||||
100:0
Loading…
Cancel
Save