初始化
This commit is contained in:
commit
a90cb0cf86
3
.browserslistrc
Normal file
3
.browserslistrc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
> 1%
|
||||||
|
last 2 versions
|
||||||
|
not dead
|
5
.editorconfig
Normal file
5
.editorconfig
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[*.{js,jsx,ts,tsx,vue}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
11
.env.development
Normal file
11
.env.development
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# 开发环境配置
|
||||||
|
# ENV = 'development'
|
||||||
|
|
||||||
|
# 路由懒加载
|
||||||
|
# VUE_CLI_BABEL_TRANSPILE_MODULES = true
|
||||||
|
|
||||||
|
# pei你看雪博客/开发环境/websocket地址
|
||||||
|
VUE_APP_SOCKET = 'wss://pnkx.top/websocket/websocket'
|
||||||
|
|
||||||
|
# 若依管理系统/开发环境
|
||||||
|
VUE_APP_BASE_API = 'https://pnkx.top/prod-api'
|
8
.env.production
Normal file
8
.env.production
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# 生产环境配置
|
||||||
|
ENV = 'production'
|
||||||
|
|
||||||
|
# pei你看雪博客/开发环境/websocket地址
|
||||||
|
VUE_APP_SOCKET = 'ws://localhost:8068/websocket'
|
||||||
|
|
||||||
|
# 若依管理系统/开发环境
|
||||||
|
VUE_APP_BASE_API = '/prod-api'
|
7
.env.staging
Normal file
7
.env.staging
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
NODE_ENV = production
|
||||||
|
|
||||||
|
# 测试环境配置
|
||||||
|
ENV = 'staging'
|
||||||
|
|
||||||
|
# 若依管理系统/测试环境
|
||||||
|
VUE_APP_BASE_API = '/stage-api'
|
17
.eslintrc.js
Normal file
17
.eslintrc.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
env: {
|
||||||
|
node: true
|
||||||
|
},
|
||||||
|
extends: [
|
||||||
|
'plugin:vue/essential',
|
||||||
|
'@vue/standard'
|
||||||
|
],
|
||||||
|
parserOptions: {
|
||||||
|
parser: 'babel-eslint'
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||||
|
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
|
||||||
|
}
|
||||||
|
}
|
23
.gitignore
vendored
Normal file
23
.gitignore
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
/dist
|
||||||
|
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
24
README.md
Normal file
24
README.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# code
|
||||||
|
|
||||||
|
## Project setup
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and hot-reloads for development
|
||||||
|
```
|
||||||
|
npm run serve
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and minifies for production
|
||||||
|
```
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lints and fixes files
|
||||||
|
```
|
||||||
|
npm run lint
|
||||||
|
```
|
||||||
|
|
||||||
|
### Customize configuration
|
||||||
|
See [Configuration Reference](https://cli.vuejs.org/config/).
|
5
babel.config.js
Normal file
5
babel.config.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
'@vue/cli-plugin-babel/preset'
|
||||||
|
]
|
||||||
|
}
|
27663
package-lock.json
generated
Normal file
27663
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
42
package.json
Normal file
42
package.json
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"name": "code",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vue-cli-service serve",
|
||||||
|
"build": "vue-cli-service build",
|
||||||
|
"lint": "vue-cli-service lint",
|
||||||
|
"start": "node index.js",
|
||||||
|
"server": "nodemon index.js --ignore client"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^0.21.1",
|
||||||
|
"core-js": "^3.6.5",
|
||||||
|
"element-ui": "^2.13.2",
|
||||||
|
"es6-promise": "^4.2.8",
|
||||||
|
"js-cookie": "^2.2.1",
|
||||||
|
"node-sass": "^4.14.1",
|
||||||
|
"sass-loader": "^8.0.0",
|
||||||
|
"vue": "^2.6.11",
|
||||||
|
"vue-router": "^3.2.0",
|
||||||
|
"vuex": "^3.4.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vue/cli-plugin-babel": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-router": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-vuex": "~4.5.0",
|
||||||
|
"@vue/cli-service": "~4.5.0",
|
||||||
|
"@vue/eslint-config-standard": "^5.1.2",
|
||||||
|
"babel-eslint": "^10.1.0",
|
||||||
|
"eslint": "^6.7.2",
|
||||||
|
"eslint-plugin-import": "^2.20.2",
|
||||||
|
"eslint-plugin-node": "^11.1.0",
|
||||||
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
|
"eslint-plugin-standard": "^4.0.0",
|
||||||
|
"eslint-plugin-vue": "^6.2.2",
|
||||||
|
"less": "^3.0.4",
|
||||||
|
"less-loader": "^7.3.0",
|
||||||
|
"vue-template-compiler": "^2.6.11"
|
||||||
|
}
|
||||||
|
}
|
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 73 KiB |
18
public/index.html
Normal file
18
public/index.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||||
|
<title>chat</title>
|
||||||
|
<script src="https://pv.sohu.com/cityjson?ie=utf-8"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>
|
||||||
|
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||||
|
</noscript>
|
||||||
|
<div id="app"></div>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
</body>
|
||||||
|
</html>
|
18
src/App.vue
Normal file
18
src/App.vue
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<template>
|
||||||
|
<div id="app">
|
||||||
|
<router-view/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
html, body{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-image: url('./assets/main-bg.png');
|
||||||
|
background-size: 100% 100%;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
</style>
|
35
src/api/index.js
Normal file
35
src/api/index.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import request from '../utils/request'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送信息
|
||||||
|
*/
|
||||||
|
export function sendMessage(params) {
|
||||||
|
return request({
|
||||||
|
url: '/customer/sendMessage',
|
||||||
|
method: 'post',
|
||||||
|
data: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录聊天室
|
||||||
|
*/
|
||||||
|
export function loginChat(params) {
|
||||||
|
return request({
|
||||||
|
url: '/customer/loginChat',
|
||||||
|
method: 'post',
|
||||||
|
data: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退出聊天室
|
||||||
|
*/
|
||||||
|
export function signOut(params) {
|
||||||
|
return request({
|
||||||
|
url: '/customer/signOut',
|
||||||
|
method: 'post',
|
||||||
|
data: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
BIN
src/assets/logo.png
Normal file
BIN
src/assets/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
BIN
src/assets/main-bg.png
Normal file
BIN
src/assets/main-bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 104 KiB |
16
src/main.js
Normal file
16
src/main.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import Vue from 'vue';
|
||||||
|
import App from './App.vue';
|
||||||
|
import router from './router';
|
||||||
|
import store from './store';
|
||||||
|
import ElementUI from 'element-ui';
|
||||||
|
import 'element-ui/lib/theme-chalk/index.css';
|
||||||
|
import axios from 'axios';
|
||||||
|
Vue.prototype.$axios = axios;
|
||||||
|
Vue.use(ElementUI);
|
||||||
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
router,
|
||||||
|
store,
|
||||||
|
render: h => h(App)
|
||||||
|
}).$mount('#app')
|
34
src/router/index.js
Normal file
34
src/router/index.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import VueRouter from 'vue-router'
|
||||||
|
|
||||||
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
|
const routes = [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
name: 'index',
|
||||||
|
component: () => import("../views/Index")
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const router = new VueRouter({
|
||||||
|
routes
|
||||||
|
})
|
||||||
|
|
||||||
|
// 导航守卫
|
||||||
|
// 使用 router.beforeEach 注册一个全局前置守卫,判断用户是否登陆
|
||||||
|
router.beforeEach((to, from, next) => {
|
||||||
|
if (to.path === '/login') {
|
||||||
|
next();
|
||||||
|
} else {
|
||||||
|
let token = localStorage.getItem('Authorization');
|
||||||
|
|
||||||
|
if (token === 'null' || token === '') {
|
||||||
|
next('/login');
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router
|
36
src/settings.js
Normal file
36
src/settings.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
module.exports = {
|
||||||
|
title: '若依管理系统',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 侧边栏主题 深色主题theme-dark,浅色主题theme-light
|
||||||
|
*/
|
||||||
|
sideTheme: 'theme-dark',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否系统布局配置
|
||||||
|
*/
|
||||||
|
showSettings: false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否显示 tagsView
|
||||||
|
*/
|
||||||
|
tagsView: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否固定头部
|
||||||
|
*/
|
||||||
|
fixedHeader: false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否显示logo
|
||||||
|
*/
|
||||||
|
sidebarLogo: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string | array} 'production' | ['production', 'development']
|
||||||
|
* @description Need show err logs component.
|
||||||
|
* The default is only used in the production env
|
||||||
|
* If you want to also use it in dev, you can pass ['production', 'development']
|
||||||
|
*/
|
||||||
|
errorLog: 'production'
|
||||||
|
}
|
15
src/store/index.js
Normal file
15
src/store/index.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import Vuex from 'vuex'
|
||||||
|
|
||||||
|
Vue.use(Vuex)
|
||||||
|
|
||||||
|
export default new Vuex.Store({
|
||||||
|
state: {
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
},
|
||||||
|
modules: {
|
||||||
|
}
|
||||||
|
})
|
15
src/utils/auth.js
Normal file
15
src/utils/auth.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import Cookies from 'js-cookie'
|
||||||
|
|
||||||
|
const TokenKey = 'Admin-Token'
|
||||||
|
|
||||||
|
export function getToken() {
|
||||||
|
return Cookies.get(TokenKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setToken(token) {
|
||||||
|
return Cookies.set(TokenKey, token)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeToken() {
|
||||||
|
return Cookies.remove(TokenKey)
|
||||||
|
}
|
68
src/utils/compressImage.js
Normal file
68
src/utils/compressImage.js
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// 压缩图片
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
export function compressImage (file, config) {
|
||||||
|
const read = new FileReader();
|
||||||
|
read.readAsDataURL(file);
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
read.onload = function (e) {
|
||||||
|
let img = new Image();
|
||||||
|
img.src = e.target.result;
|
||||||
|
img.onload = function () {
|
||||||
|
// 默认按比例压缩
|
||||||
|
let w = 0;
|
||||||
|
let h = 0;
|
||||||
|
if (img.width > 100) {
|
||||||
|
w = config.width || img.width * config.proportion;
|
||||||
|
h = config.height || img.height * config.proportion;
|
||||||
|
} else {
|
||||||
|
w = img.width;
|
||||||
|
h = img.height;
|
||||||
|
}
|
||||||
|
// 生成canvas
|
||||||
|
let canvas = document.createElement('canvas');
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
let base64;
|
||||||
|
// 创建属性节点
|
||||||
|
canvas.setAttribute('width', w);
|
||||||
|
canvas.setAttribute('height', h);
|
||||||
|
ctx.drawImage(this, 0, 0, w, h);
|
||||||
|
|
||||||
|
base64 = canvas.toDataURL(file['type'], config.quality);
|
||||||
|
|
||||||
|
// 回调函数返回file的值(将base64编码转成file)
|
||||||
|
// files = dataURLtoFile(base64) // 如果后台接收类型为base64的话这一步可以省略
|
||||||
|
|
||||||
|
// 回调函数返回file的值(将base64转为二进制)
|
||||||
|
let fileBinary = dataURLtoBlob(base64);
|
||||||
|
|
||||||
|
resolve(fileBinary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
// 将base64转为二进制
|
||||||
|
function dataURLtoBlob (dataurl) {
|
||||||
|
let arr = dataurl.split(',');
|
||||||
|
let mime = arr[0].match(/:(.*?);/)[1];
|
||||||
|
let bstr = atob(arr[1]);
|
||||||
|
let n = bstr.length;
|
||||||
|
let u8arr = new Uint8Array(n);
|
||||||
|
while (n--) {
|
||||||
|
u8arr[n] = bstr.charCodeAt(n)
|
||||||
|
}
|
||||||
|
return new Blob([u8arr], { type: mime })
|
||||||
|
}
|
||||||
|
|
||||||
|
// base64转码(将base64编码转回file文件) 此方法我没用到
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
function dataURLtoFile (dataurl) {
|
||||||
|
let arr = dataurl.split(',');
|
||||||
|
let mime = arr[0].match(/:(.*?);/)[1];
|
||||||
|
let bstr = atob(arr[1]);
|
||||||
|
let n = bstr.length;
|
||||||
|
let u8arr = new Uint8Array(n);
|
||||||
|
while (n--) {
|
||||||
|
u8arr[n] = bstr.charCodeAt(n)
|
||||||
|
}
|
||||||
|
return new File([u8arr], { type: mime })
|
||||||
|
}
|
6
src/utils/errorCode.js
Normal file
6
src/utils/errorCode.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
'401': '认证失败,无法访问系统资源',
|
||||||
|
'403': '当前操作没有权限',
|
||||||
|
'404': '访问资源不存在',
|
||||||
|
'default': '系统未知错误,请反馈给管理员'
|
||||||
|
}
|
104
src/utils/request.js
Normal file
104
src/utils/request.js
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
import { Notification, MessageBox, Message } from 'element-ui'
|
||||||
|
import store from '@/store'
|
||||||
|
import { getToken } from '@/utils/auth'
|
||||||
|
import errorCode from '@/utils/errorCode'
|
||||||
|
|
||||||
|
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
|
||||||
|
// 创建axios实例
|
||||||
|
console.log('url', process.env.VUE_APP_BASE_API)
|
||||||
|
const service = axios.create({
|
||||||
|
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||||
|
baseURL: process.env.VUE_APP_BASE_API,
|
||||||
|
// 超时
|
||||||
|
timeout: 300000
|
||||||
|
})
|
||||||
|
// request拦截器
|
||||||
|
service.interceptors.request.use(config => {
|
||||||
|
// 是否需要设置 token
|
||||||
|
const isToken = (config.headers || {}).isToken === false
|
||||||
|
if (getToken() && !isToken) {
|
||||||
|
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||||
|
}
|
||||||
|
// get请求映射params参数
|
||||||
|
if (config.method === 'get' && config.params) {
|
||||||
|
let url = config.url + '?';
|
||||||
|
for (const propName of Object.keys(config.params)) {
|
||||||
|
const value = config.params[propName];
|
||||||
|
var part = encodeURIComponent(propName) + "=";
|
||||||
|
if (value !== null && typeof(value) !== "undefined") {
|
||||||
|
if (typeof value === 'object') {
|
||||||
|
for (const key of Object.keys(value)) {
|
||||||
|
let params = propName + '[' + key + ']';
|
||||||
|
var subPart = encodeURIComponent(params) + "=";
|
||||||
|
url += subPart + encodeURIComponent(value[key]) + "&";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
url += part + encodeURIComponent(value) + "&";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
url = url.slice(0, -1);
|
||||||
|
config.params = {};
|
||||||
|
config.url = url;
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
}, error => {
|
||||||
|
console.log(error)
|
||||||
|
Promise.reject(error)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 响应拦截器
|
||||||
|
service.interceptors.response.use(res => {
|
||||||
|
// 未设置状态码则默认成功状态
|
||||||
|
const code = res.data.code || 200;
|
||||||
|
// 获取错误信息
|
||||||
|
const msg = errorCode[code] || res.data.msg || errorCode['default']
|
||||||
|
if (code === 401) {
|
||||||
|
/*MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
|
||||||
|
confirmButtonText: '重新登录',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
store.dispatch('LogOut').then(() => {
|
||||||
|
location.href = '/index';
|
||||||
|
})
|
||||||
|
})*/
|
||||||
|
} else if (code === 500) {
|
||||||
|
Message({
|
||||||
|
message: '网络异常,请稍候再试',
|
||||||
|
type: 'error'
|
||||||
|
})
|
||||||
|
return Promise.reject(new Error(msg))
|
||||||
|
} else if (code !== 200) {
|
||||||
|
Notification.error({
|
||||||
|
title: '网络异常,请刷新当前页面'
|
||||||
|
})
|
||||||
|
return Promise.reject('error')
|
||||||
|
} else {
|
||||||
|
return res.data
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log('err' + error)
|
||||||
|
let { message } = error;
|
||||||
|
if (message === "Network Error") {
|
||||||
|
message = "网络异常,请刷新当前页面";
|
||||||
|
}
|
||||||
|
else if (message.includes("timeout")) {
|
||||||
|
message = "请求超时,请刷新当前页面";
|
||||||
|
}
|
||||||
|
else if (message.includes("Request failed with status code")) {
|
||||||
|
message = "网络异常,请刷新当前页面";
|
||||||
|
}
|
||||||
|
Message({
|
||||||
|
message: '请求超时,请刷新当前页面',
|
||||||
|
type: 'error',
|
||||||
|
duration: 5 * 1000
|
||||||
|
})
|
||||||
|
return Promise.reject(error)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export default service
|
675
src/views/Index.vue
Normal file
675
src/views/Index.vue
Normal file
@ -0,0 +1,675 @@
|
|||||||
|
<template>
|
||||||
|
<div id="chat-room">
|
||||||
|
<div v-if="chatFlag" class="chat-room">
|
||||||
|
<div :style="chat" class="chat">
|
||||||
|
<div class="record" ref="record">
|
||||||
|
<div class="phone-info">
|
||||||
|
<div class="phone-online-number">
|
||||||
|
{{`在线人数(${memberList.length})`}}
|
||||||
|
</div>
|
||||||
|
<i class="el-icon-edit-outline" @click="openInfo"/>
|
||||||
|
</div>
|
||||||
|
<div class="record-one" :class="one.userId === myId ? 'is-me' : ''"
|
||||||
|
v-for="one in recordList.slice(recordList.length - 50, recordList.length)"
|
||||||
|
:key="one.userId">
|
||||||
|
<div class="left">
|
||||||
|
<el-avatar :size="36" shape="square" :src="userHeader(one.userId)">
|
||||||
|
<img src="https://cube.elemecdn.com/e/fd/0fc7d20532fdaf769a25683617711png.png"/>
|
||||||
|
</el-avatar>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<div class="nick-name">{{one.nickName}}</div>
|
||||||
|
<div class="message" v-html="one.message"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="input-box">
|
||||||
|
<div class="textarea" contenteditable
|
||||||
|
ref="message" @keyup.enter="sendMessage"></div>
|
||||||
|
<div class="button">
|
||||||
|
<el-button
|
||||||
|
:loading="sendMessageLoading"
|
||||||
|
size="mini"
|
||||||
|
@click="sendMessage"
|
||||||
|
type="primary">
|
||||||
|
发 送
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div :style="roomInfo" class="room-info">
|
||||||
|
<div class="user-info">
|
||||||
|
<i class="el-icon-arrow-left return" @click="returnChat"/>
|
||||||
|
<div class="message-board-right">
|
||||||
|
<div class="your-header">
|
||||||
|
<el-image
|
||||||
|
class="header-picture"
|
||||||
|
:src="userInfo.userHeader"
|
||||||
|
fit="scale-down">
|
||||||
|
<div slot="error" class="image-slot">
|
||||||
|
请上传头像
|
||||||
|
</div>
|
||||||
|
</el-image>
|
||||||
|
</div>
|
||||||
|
<div class="customer-name">
|
||||||
|
<div class="label">昵称:</div>
|
||||||
|
<div class="name">
|
||||||
|
<el-tooltip :content="userInfo.nickName" placement="top" effect="light">
|
||||||
|
<span>{{userInfo.nickName}}</span>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="customer-mail">
|
||||||
|
<div class="label">邮箱: </div>
|
||||||
|
<div class="name">
|
||||||
|
<el-tooltip :content="userInfo.userMailbox" placement="top" effect="light">
|
||||||
|
<span>{{userInfo.userMailbox}}</span>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="button">
|
||||||
|
<el-button type="danger" size="mini" @click="signOut">退出</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="member">
|
||||||
|
<div class="online-number">
|
||||||
|
{{`在线人数(${memberList.length})`}}
|
||||||
|
</div>
|
||||||
|
<div class="member-list">
|
||||||
|
<div class="member-one" v-for="one in memberList" :key="one.nickName">
|
||||||
|
<el-avatar :size="24" shape="square" :src="one.userHeader">
|
||||||
|
<img src="https://cube.elemecdn.com/e/fd/0fc7d20532fdaf769a25683617711png.png"/>
|
||||||
|
</el-avatar>
|
||||||
|
<div class="nick-name">{{one.nickName}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-dialog
|
||||||
|
:title="title"
|
||||||
|
:visible.sync="loginVisible"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:show-close="false"
|
||||||
|
:modal="false"
|
||||||
|
width="fit-content">
|
||||||
|
<div class="login">
|
||||||
|
<div class="your-header">
|
||||||
|
<el-image
|
||||||
|
class="header-picture"
|
||||||
|
:src="userInfo.userHeader"
|
||||||
|
fit="scale-down">
|
||||||
|
<div slot="error" class="image-slot">
|
||||||
|
请上传头像
|
||||||
|
</div>
|
||||||
|
</el-image>
|
||||||
|
<i @click="deleteHeader" class="el-icon-circle-close close-icon" v-if="userInfo.userHeader"/>
|
||||||
|
<input v-if="!userInfo.userHeader" type="file" id="headerPhoto" capture="camera" accept="image/*" @change="uploadHeader($event)"/>
|
||||||
|
</div>
|
||||||
|
<div class="customer-name">
|
||||||
|
<div class="label">昵称:</div>
|
||||||
|
<div class="name">
|
||||||
|
<el-input size="mini"
|
||||||
|
v-model="userInfo.nickName"
|
||||||
|
@keyup.enter="loginChat"
|
||||||
|
placeholder="请输入您的昵称"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="customer-mail">
|
||||||
|
<div class="label">邮箱: </div>
|
||||||
|
<div class="name">
|
||||||
|
<el-input size="mini"
|
||||||
|
v-model="userInfo.userMailbox"
|
||||||
|
@keyup.enter="loginChat"
|
||||||
|
placeholder="请输入您的邮箱"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="button">
|
||||||
|
<el-button type="primary" size="mini" @click="loginChat">登录</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { sendMessage, signOut, loginChat } from "../api/index.js";
|
||||||
|
import { compressImage } from '@/utils/compressImage'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'index',
|
||||||
|
data() {
|
||||||
|
let userInfo;
|
||||||
|
let chatFlag = false;
|
||||||
|
let loginVisible = true;
|
||||||
|
if (sessionStorage.getItem('loginInfo') === null || sessionStorage.getItem('loginInfo') === '') {
|
||||||
|
userInfo = {
|
||||||
|
userHeader: '',
|
||||||
|
nickName: '',
|
||||||
|
userMailbox: '',
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
userInfo = JSON.parse(sessionStorage.getItem('loginInfo'))
|
||||||
|
this.initWebSocket(userInfo);
|
||||||
|
chatFlag = true;
|
||||||
|
loginVisible = false;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
//聊天样式
|
||||||
|
chat: '',
|
||||||
|
//个人信息样式
|
||||||
|
roomInfo: '',
|
||||||
|
//发送信息加载标志
|
||||||
|
sendMessageLoading: false,
|
||||||
|
//聊天室
|
||||||
|
chatFlag: chatFlag,
|
||||||
|
//弹框标题
|
||||||
|
title: '登录',
|
||||||
|
//个人信息
|
||||||
|
userInfo: userInfo,
|
||||||
|
//聊天信息内容
|
||||||
|
recordList: [],
|
||||||
|
//在线人数
|
||||||
|
memberList: [],
|
||||||
|
//登录框
|
||||||
|
loginVisible: loginVisible,
|
||||||
|
//压缩配置
|
||||||
|
config: {
|
||||||
|
proportion: 0.4,
|
||||||
|
quality: 0.8
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
myId() {
|
||||||
|
return 'chat' + this.userInfo.nickName + returnCitySN['cip']
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
recordList() {
|
||||||
|
this.$nextTick(function(){
|
||||||
|
const p = this.$refs.record;
|
||||||
|
if (p) {
|
||||||
|
p.scrollTop = p.scrollHeight;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* 返回聊天
|
||||||
|
*/
|
||||||
|
returnChat() {
|
||||||
|
this.chat = 'display: flex!important;'
|
||||||
|
this.roomInfo = 'display: none!important;'
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 打开信息
|
||||||
|
*/
|
||||||
|
openInfo() {
|
||||||
|
this.chat = 'display: none!important;'
|
||||||
|
this.roomInfo = 'display: flex!important;'
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 返回个人头像
|
||||||
|
*/
|
||||||
|
userHeader(id) {
|
||||||
|
let header;
|
||||||
|
this.memberList.forEach(item => {
|
||||||
|
if (id === item.userId) {
|
||||||
|
header = item.userHeader
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return header
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 发送信息
|
||||||
|
*/
|
||||||
|
sendMessage() {
|
||||||
|
if (!this.$refs.message.innerHTML.replace(/<div><br><\/div>/g, '')) {
|
||||||
|
this.$message.error('发送内容不能为空,请重新输入');
|
||||||
|
this.$refs.message.innerHTML = '';
|
||||||
|
} else {
|
||||||
|
let params = {
|
||||||
|
userId: 'chat' + this.userInfo.nickName + returnCitySN['cip'],
|
||||||
|
message: this.$refs.message.innerHTML.replace(/<div><br><\/div>/g, ''),
|
||||||
|
};
|
||||||
|
sendMessage(params).then(res => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.$refs.message.innerHTML = ''
|
||||||
|
this.sendMessageLoading = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 退出登录
|
||||||
|
*/
|
||||||
|
signOut() {
|
||||||
|
let params = {
|
||||||
|
userId: 'chat' + this.userInfo.nickName + returnCitySN['cip'],
|
||||||
|
userHeader: this.userInfo.userHeader,
|
||||||
|
nickName: this.userInfo.nickName,
|
||||||
|
userMailbox: this.userInfo.userMailbox,
|
||||||
|
};
|
||||||
|
signOut(params).then(res => {
|
||||||
|
this.memberList = res.data;
|
||||||
|
this.onbeforeunload();
|
||||||
|
this.recordList = [];
|
||||||
|
this.memberList = [];
|
||||||
|
sessionStorage.setItem('loginInfo', '');
|
||||||
|
this.userInfo = {
|
||||||
|
userHeader: '',
|
||||||
|
nickName: '',
|
||||||
|
userMailbox: '',
|
||||||
|
};
|
||||||
|
this.chatFlag = false;
|
||||||
|
this.loginVisible = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 登录
|
||||||
|
*/
|
||||||
|
loginChat() {
|
||||||
|
const reg = /^[a-zA-Z0-9]+([-_.][a-zA-Z0-9]+)*@[a-zA-Z0-9]+([-_.][a-zA-Z0-9]+)*\.[a-z]{2,}$/
|
||||||
|
if (this.userInfo.userHeader === '') {
|
||||||
|
this.$message.error('请上传您的头像')
|
||||||
|
} else if (this.userInfo.nickName === '') {
|
||||||
|
this.$message.error('请输入你的昵称')
|
||||||
|
} else if (this.userInfo.userMailbox === '' || !reg.test(this.userInfo.userMailbox)) {
|
||||||
|
this.$message.error('请输入正确格式的邮箱')
|
||||||
|
} else {
|
||||||
|
this.loginVisible = false;
|
||||||
|
this.chatFlag = true;
|
||||||
|
sessionStorage.setItem('loginInfo', JSON.stringify(this.userInfo));
|
||||||
|
this.initWebSocket();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 初始化webSocket
|
||||||
|
*/
|
||||||
|
initWebSocket (userInfo) {
|
||||||
|
// WebSocket
|
||||||
|
if ('WebSocket' in window) {
|
||||||
|
if (userInfo) {
|
||||||
|
this.websocket = new WebSocket(`${process.env.VUE_APP_SOCKET}/${'chat' + userInfo.nickName + returnCitySN['cip']}`);
|
||||||
|
} else {
|
||||||
|
this.websocket = new WebSocket(`${process.env.VUE_APP_SOCKET}/${'chat' + this.userInfo.nickName + returnCitySN['cip']}`);
|
||||||
|
}
|
||||||
|
// 连接错误
|
||||||
|
this.websocket.onerror = this.setErrorMessage;
|
||||||
|
// 连接成功
|
||||||
|
this.websocket.onopen = this.setOnopenMessage;
|
||||||
|
// 收到消息的回调
|
||||||
|
this.websocket.onmessage = this.setOnmessageMessage;
|
||||||
|
// 连接关闭的回调
|
||||||
|
this.websocket.onclose = this.setOncloseMessage;
|
||||||
|
} else {
|
||||||
|
alert('当前浏览器 Not support websocket')
|
||||||
|
}
|
||||||
|
// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
|
||||||
|
window.onbeforeunload = this.onbeforeunload;
|
||||||
|
},
|
||||||
|
setErrorMessage () {
|
||||||
|
console.log('WebSocket连接发生错误 状态码:' + this.websocket.readyState)
|
||||||
|
},
|
||||||
|
setOnopenMessage () {
|
||||||
|
console.log('WebSocket连接成功 状态码:' + this.websocket.readyState);
|
||||||
|
let params = {
|
||||||
|
userId: 'chat' + this.userInfo.nickName + returnCitySN['cip'],
|
||||||
|
userHeader: this.userInfo.userHeader,
|
||||||
|
nickName: this.userInfo.nickName,
|
||||||
|
userMailbox: this.userInfo.userMailbox,
|
||||||
|
};
|
||||||
|
loginChat(params).then(res => {
|
||||||
|
if (res.data.length > 0) {
|
||||||
|
this.memberList = res.data.filter(item => {
|
||||||
|
return item.userHeader !== undefined
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.$message.error('网络异常,请清理缓存刷新当前页面')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setOnmessageMessage (event) {
|
||||||
|
// 根据服务器推送的消息做自己的业务处理
|
||||||
|
if (JSON.parse(event.data).webSocket === 'message') {
|
||||||
|
this.recordList.push(JSON.parse(event.data))
|
||||||
|
} else if (JSON.parse(event.data).webSocket === 'login') {
|
||||||
|
let flag = true;
|
||||||
|
this.memberList.forEach(item => {
|
||||||
|
if (JSON.parse(event.data).userId === item.userId) {
|
||||||
|
flag = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (flag) {
|
||||||
|
this.memberList.push(JSON.parse(event.data))
|
||||||
|
}
|
||||||
|
} else if (JSON.parse(event.data).webSocket === 'signOut') {
|
||||||
|
this.memberList = this.memberList.filter(item => {
|
||||||
|
return item.userId !== JSON.parse(event.data).userId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setOncloseMessage () {
|
||||||
|
console.log('WebSocket连接关闭 状态码:' + this.websocket.readyState)
|
||||||
|
},
|
||||||
|
onbeforeunload () {
|
||||||
|
this.closeWebSocket();
|
||||||
|
},
|
||||||
|
closeWebSocket () {
|
||||||
|
this.websocket.close()
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 删除头像
|
||||||
|
*/
|
||||||
|
deleteHeader() {
|
||||||
|
this.userInfo.userHeader = '';
|
||||||
|
},
|
||||||
|
blobToDataURL(blob,cb) {
|
||||||
|
let reader = new FileReader();
|
||||||
|
reader.onload = function (evt) {
|
||||||
|
let base64 = evt.target.result;
|
||||||
|
cb(base64)
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(blob);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 上传头像
|
||||||
|
*/
|
||||||
|
uploadHeader(e) {
|
||||||
|
if(e.target.files[0]){
|
||||||
|
compressImage(e.target.files[0], this.config)
|
||||||
|
.then(result => { // result 为压缩后二进制文件
|
||||||
|
this.blobToDataURL(result, (base64Url) => {
|
||||||
|
this.userInfo.userHeader = base64Url;
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
this.onbeforeunload()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@media screen and (max-width: 1000px) {
|
||||||
|
.chat-room {
|
||||||
|
height: 94%!important;
|
||||||
|
width: 94%!important;
|
||||||
|
.user-info{
|
||||||
|
.return{
|
||||||
|
display: flex!important;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
padding: 0.8rem 0.5rem;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.phone-info{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
color: #909090;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
i{
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.room-info{
|
||||||
|
display: none!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.phone-info{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#chat-room{
|
||||||
|
display: flex;
|
||||||
|
height: 90vh;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.login{
|
||||||
|
display: flex;
|
||||||
|
padding: 1rem 4rem;
|
||||||
|
height: 100%;
|
||||||
|
flex-flow: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
.customer-name, .customer-mail{
|
||||||
|
height: 2rem;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 1rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.label{
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.name{
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 10rem;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.button{
|
||||||
|
padding-top: 1rem;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.your-header{
|
||||||
|
width: 6rem;
|
||||||
|
height: 6rem;
|
||||||
|
border: 1px solid #999;
|
||||||
|
border-radius: 5px;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
#headerPhoto{
|
||||||
|
width: 7rem;
|
||||||
|
position: absolute;
|
||||||
|
transform: scale(0.7);
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
::v-deep .image-slot{
|
||||||
|
font-size: 0.4rem;
|
||||||
|
transform: scale(0.8);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.close-icon{
|
||||||
|
position: absolute;
|
||||||
|
margin: -5rem -5rem 0 0;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
.header-picture{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
img{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.chat-room{
|
||||||
|
display: flex;
|
||||||
|
height: 40rem;
|
||||||
|
width: 60rem;
|
||||||
|
border: 1px solid #d9d9d9;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
box-shadow: 4px 6px 2px #00000066;
|
||||||
|
.chat{
|
||||||
|
flex: 7;
|
||||||
|
border-right: 1px solid #d9d9d9;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
.record{
|
||||||
|
flex: 5;
|
||||||
|
border-bottom: 1px solid #d9d9d9;
|
||||||
|
height: 28rem;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 1rem 1rem 0 1rem;
|
||||||
|
.record-one{
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
.left{
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
.right{
|
||||||
|
.nick-name{
|
||||||
|
color: #999;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
.message{
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.is-me{
|
||||||
|
flex-flow:row-reverse!important;
|
||||||
|
.message{
|
||||||
|
-moz-border-radius-topright: 0;
|
||||||
|
}
|
||||||
|
.right{
|
||||||
|
.nick-name{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.message{
|
||||||
|
margin-left: 0!important;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
background-color: #1E6EFF;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
.message:before{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.input-box{
|
||||||
|
flex: 2;
|
||||||
|
padding: 1rem;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
.textarea{
|
||||||
|
flex: 8;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
.button{
|
||||||
|
flex: 2;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.room-info{
|
||||||
|
flex: 3;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
.user-info{
|
||||||
|
flex: 2;
|
||||||
|
border-bottom: 1px solid #d9d9d9;
|
||||||
|
.return{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.message-board-right{
|
||||||
|
display: flex;
|
||||||
|
padding: 1rem;
|
||||||
|
flex-flow: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
.customer-name, .customer-mail{
|
||||||
|
height: 2rem;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.label{
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.name{
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 10rem;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.button{
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.your-header{
|
||||||
|
width: 6rem;
|
||||||
|
height: 6rem;
|
||||||
|
border: 1px solid #999;
|
||||||
|
border-radius: 5px;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
#headerPhoto{
|
||||||
|
width: 7rem;
|
||||||
|
position: absolute;
|
||||||
|
transform: scale(0.7);
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
::v-deep .image-slot{
|
||||||
|
font-size: 0.4rem;
|
||||||
|
transform: scale(0.8);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.close-icon{
|
||||||
|
position: absolute;
|
||||||
|
margin: -5rem -5rem 0 0;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
.header-picture{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
img{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
.member{
|
||||||
|
flex: 5;
|
||||||
|
padding: 1rem;
|
||||||
|
.online-number{
|
||||||
|
|
||||||
|
}
|
||||||
|
.member-list{
|
||||||
|
.member-one{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
.nick-name{
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
111
vue.config.js
Normal file
111
vue.config.js
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
'use strict'
|
||||||
|
const path = require('path')
|
||||||
|
const defaultSettings = require('./src/settings.js')
|
||||||
|
|
||||||
|
function resolve(dir) {
|
||||||
|
return path.join(__dirname, dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = defaultSettings.title || 'pei你看雪博客管理系统' // 标题
|
||||||
|
|
||||||
|
const port = process.env.port || process.env.npm_config_port || 80 // 端口
|
||||||
|
|
||||||
|
// vue.config.js 配置说明
|
||||||
|
//官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions
|
||||||
|
// 这里只列一部分,具体配置参考文档
|
||||||
|
module.exports = {
|
||||||
|
// 部署生产环境和开发环境下的URL。
|
||||||
|
// 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上
|
||||||
|
// 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
|
||||||
|
publicPath: process.env.NODE_ENV === "production" ? "./" : "/",
|
||||||
|
// 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致)(默认dist)
|
||||||
|
outputDir: 'dist',
|
||||||
|
// 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下)
|
||||||
|
assetsDir: 'static',
|
||||||
|
// 是否开启eslint保存检测,有效值:ture | false | 'error'
|
||||||
|
// lintOnSave: process.env.NODE_ENV === 'development',
|
||||||
|
lintOnSave: false,
|
||||||
|
// 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
|
||||||
|
productionSourceMap: false,
|
||||||
|
// webpack-dev-server 相关配置
|
||||||
|
devServer: {
|
||||||
|
host: '0.0.0.0',
|
||||||
|
port: port,
|
||||||
|
open: true,
|
||||||
|
proxy: {
|
||||||
|
// detail: https://cli.vuejs.org/config/#devserver-proxy
|
||||||
|
[process.env.VUE_APP_BASE_API]: {
|
||||||
|
target: `http://localhost:8068`,
|
||||||
|
changeOrigin: true,
|
||||||
|
pathRewrite: {
|
||||||
|
['^' + process.env.VUE_APP_BASE_API]: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
disableHostCheck: true
|
||||||
|
},
|
||||||
|
configureWebpack: {
|
||||||
|
name: name,
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': resolve('src')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
chainWebpack(config) {
|
||||||
|
config.plugins.delete('preload') // TODO: need test
|
||||||
|
config.plugins.delete('prefetch') // TODO: need test
|
||||||
|
|
||||||
|
// set svg-sprite-loader
|
||||||
|
config.module
|
||||||
|
.rule('svg')
|
||||||
|
.exclude.add(resolve('src/assets/icons'))
|
||||||
|
.end()
|
||||||
|
config.module
|
||||||
|
.rule('icons')
|
||||||
|
.test(/\.svg$/)
|
||||||
|
.include.add(resolve('src/assets/icons'))
|
||||||
|
.end()
|
||||||
|
.use('svg-sprite-loader')
|
||||||
|
.loader('svg-sprite-loader')
|
||||||
|
.options({
|
||||||
|
symbolId: 'icon-[name]'
|
||||||
|
})
|
||||||
|
.end()
|
||||||
|
|
||||||
|
config
|
||||||
|
.when(process.env.NODE_ENV !== 'development',
|
||||||
|
config => {
|
||||||
|
config
|
||||||
|
.optimization.splitChunks({
|
||||||
|
chunks: 'all',
|
||||||
|
cacheGroups: {
|
||||||
|
libs: {
|
||||||
|
name: 'chunk-libs',
|
||||||
|
test: /[\\/]node_modules[\\/]/,
|
||||||
|
priority: 10,
|
||||||
|
chunks: 'initial' // only package third parties that are initially dependent
|
||||||
|
},
|
||||||
|
elementUI: {
|
||||||
|
name: 'chunk-elementUI', // split elementUI into a single package
|
||||||
|
priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
|
||||||
|
test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
|
||||||
|
},
|
||||||
|
commons: {
|
||||||
|
name: 'chunk-commons',
|
||||||
|
test: resolve('src/components'), // can customize your rules
|
||||||
|
minChunks: 3, // minimum common number
|
||||||
|
priority: 5,
|
||||||
|
reuseExistingChunk: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
config.optimization.runtimeChunk('single'),
|
||||||
|
{
|
||||||
|
from: path.resolve(__dirname, './public/robots.txt'), //防爬虫文件
|
||||||
|
to: './', //到根目录下
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
26
web-腾讯云.bat
Normal file
26
web-腾讯云.bat
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
::设置服务器ip、账号、密码
|
||||||
|
set serverip=120.53.247.15
|
||||||
|
set serveruser=root
|
||||||
|
set userpwd=phy0316.
|
||||||
|
|
||||||
|
::设置上传路径
|
||||||
|
set uploadpathsup=/usr/local/src/phy/chat/
|
||||||
|
|
||||||
|
::更新开始
|
||||||
|
echo dist clean start...
|
||||||
|
rd/s/q dist
|
||||||
|
echo dist clean finished!
|
||||||
|
|
||||||
|
echo npm run build:prod start...
|
||||||
|
cmd /c "npm run build"
|
||||||
|
echo build:prod finished!
|
||||||
|
|
||||||
|
echo prod update start...
|
||||||
|
pscp -l %serveruser% -pw "%userpwd%" -r ".\dist" %serveruser%@%serverip%:%uploadpathsup%
|
||||||
|
echo prod update finished!
|
||||||
|
::更新结束
|
||||||
|
|
||||||
|
echo update finished!
|
||||||
|
pause
|
Loading…
Reference in New Issue
Block a user