init: 初始化代码仓库

This commit is contained in:
Hamm 2021-08-10 22:37:47 +08:00
commit 8c3742f6e9
31 changed files with 14515 additions and 0 deletions

3
.browserslistrc Normal file
View File

@ -0,0 +1,3 @@
> 1%
last 2 versions
not dead

17
.eslintrc.js Normal file
View File

@ -0,0 +1,17 @@
module.exports = {
root: true,
env: {
node: true
},
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended'
],
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
View 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
View File

@ -0,0 +1,24 @@
# el-vue
## 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
View File

@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

12373
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

30
package.json Normal file
View File

@ -0,0 +1,30 @@
{
"name": "el-vue",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^0.21.1",
"core-js": "^3.6.5",
"element-plus": "^1.0.2-beta.65",
"register-service-worker": "^1.7.1",
"vue": "^3.0.0",
"vue-router": "^4.0.0-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-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^7.0.0",
"sass": "^1.26.5",
"sass-loader": "^8.0.2"
}
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

35
public/index.html Normal file
View File

@ -0,0 +1,35 @@
<!--
* @FilePath: /MacOS/public/index.html
* @Author: admin@hamm.cn
* @Date: 2021-08-05 20:59:02
* @LastEditTime: 2021-08-09 22:47:24
* @LastEditors: admin@hamm.cn
* Written by https://hamm.cn
* @Description:
-->
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<title>Hamm.cn</title>
<meta charset="utf-8">
<meta content='Hamm,凌小云,博客,程序员,代码,开源,产品架构师,code,IT,互联网,软件,开发,网站,系统,维护,技术支持' name='Keywords'>
<meta content="你即将访问的是一个喜欢做产品设计的程序员博客首页,但是里面可能连一篇文章都没有,因为我实在是太懒了,懒得写。" name='Description'>
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="theme-color" content="#ff3385" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="format-detection" content="telephone=no" />
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<link rel="stylesheet" href="//at.alicdn.com/t/font_666204_9eir79vdjt4.css">
<link rel="icon" href="favicon.ico">
</head>
<body>
<noscript>
<strong>No JavaScript</strong>
</noscript>
<div id="app"></div>
</body>
</html>

2
public/robots.txt Normal file
View File

@ -0,0 +1,2 @@
User-agent: *
Disallow:

62
src/App.vue Normal file
View File

@ -0,0 +1,62 @@
<!--
* @FilePath: /MacOS/src/App.vue
* @Author: admin@hamm.cn
* @Date: 2021-08-02 21:45:20
* @LastEditTime: 2021-08-10 22:37:26
* @LastEditors: admin@hamm.cn
* Written by https://hamm.cn
* @Description:
-->
<template>
<div class="app">
<transition name="fade">
<Bg></Bg>
</transition>
<transition name="fade">
<Loading v-if="isLoading" @loaded="loaded"></Loading>
</transition>
<transition name="fade">
<Login v-if="isLogin" @logined="logined"></Login>
</transition>
<transition name="fade">
<DeskTop v-if="isDeskTop"></DeskTop>
</transition>
</div>
</template>
<style scoped>
</style>
<script>
import Bg from "@/view/Bg"
import Loading from "@/view/Loading"
import Login from "@/view/Login"
import DeskTop from "@/view/DeskTop"
export default {
components: {
Bg,
Loading,
Login,
DeskTop
},
data() {
return {
isLoading: true,
isLogin: false,
isDeskTop: false,
}
},
created() { },
methods: {
loaded() {
this.isLoading = false
this.isLogin = true
},
logined() {
console.log("login success")
this.isLogin = false
this.isDeskTop = true
}
}
}
</script>

View File

@ -0,0 +1,84 @@
.fade-enter-active {
animation: fade-in 1s;
}
.fade-leave-active {
animation: fade-out 1s;
}
@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fade-out {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.fade-window-enter-active {
animation: fade-window-in .3s;
}
.fade-window-leave-active {
animation: fade-window-out .5s;
}
@keyframes fade-window-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fade-window-out {
0% {
opacity: 1;
}
100% {
opacity: 0;
left: 100%;
right: 100%;
top: 200%;
}
}
.slide-filter-enter-active {
animation: slide-filter-in 0.3s;
}
.slide-filter-leave-active {
animation: slide-filter-out 0.3s;
}
@keyframes slide-filter-in {
0% {
transform: translate(1000px, 0);
opacity: 0;
}
100% {
transform: translate(0, 0);
opacity: 1;
}
}
@keyframes slide-filter-out {
0% {
transform: translate(0, 0);
opacity: 1;
}
100% {
transform: translate(-1000px, 0);
opacity: 0;
}
}

155
src/asset/css/app.css Normal file
View File

@ -0,0 +1,155 @@
body, html {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
background-color: #000;
}
.space {
flex-grow: 1;
}
.el-dropdown-menu__item {
font-size: 13px!important;
color: #333;
margin: 3px 5px;
border-radius: 5px;
padding: 0px 12px;
display: flex;
align-items: center;
line-height: 2;
}
.el-scrollbar {
width: 200px;
}
.el-dropdown__popper.el-popper[role=tooltip] {
top: 32px !important;
}
.el-dropdown-menu__item:hover {
background-color: #4b9efb!important;
color: white!important;
}
.el-dropdown-menu__item span:hover {
color: white!important;
}
.el-dropdown-menu {
padding: 0!important;
background: transparent!important;
}
.el-dropdown__popper.el-popper[role=tooltip] {
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(20px);
}
.el-dropdown-menu__item.line {
height: 1px;
background: rgba(0, 0, 0, 0.1);
margin: 0px 15px;
}
.el-dropdown-menu__item span {
color: #aaa;
}
.el-popper__arrow, .el-popper__arrow::before {
content: '' !important;
width: 0;
height: 0;
opacity: 0;
display: none !important;
}
.el-tag__close {
position: absolute!important;
right: 3px!important;
top: 6px!important;
}
audio {
position: relative;
z-index: 99999;
}
[v-cloak] {
visibility: hidden !important;
}
body {
display: flex;
align-items: center;
/*定义body的元素垂直居中*/
justify-content: center;
/*定义body的里的元素水平居中*/
}
@font-face {
font-family: 'Gotham-Book';
src: url('../fonts/Gotham-Book.woff2');
}
* {
font-family: 'Gotham-Book';
background-attachment: fixed;
outline: none;
-webkit-text-size-adjust: none;
-moz-text-size-adjust: none;
-ms-text-size-adjust: none;
text-size-adjust: none;
-moz-user-select: none;
/*火狐*/
-webkit-user-select: none;
/*webkit浏览器*/
-ms-user-select: none;
/*IE10*/
-khtml-user-select: none;
/*早期浏览器*/
user-select: none;
}
input, textarea {
-moz-user-select: text;
-webkit-user-select: text;
-ms-user-select: text;
-khtml-user-select: text;
user-select: text;
}
::-webkit-scrollbar {
width: 5px;
/*对垂直流动条有效*/
height: 5px;
/*对水平流动条有效*/
}
/*定义滚动条的轨道颜色、内阴影及圆角*/
::-webkit-scrollbar-track {
background-color: transparent;
border-radius: 5px;
}
/*定义滑块颜色、内阴影及圆角*/
::-webkit-scrollbar-thumb {
border-radius: 5px;
background-color: rgba(0, 0, 0, 0.2);
}
/*定义两端按钮的样式*/
::-webkit-scrollbar-button {
background-color: transparent;
}
/*定义右下角汇合处的样式*/
::-webkit-scrollbar-corner {
background: transparent;
}

BIN
src/asset/fonts/Gotham-Book.woff2 Executable file

Binary file not shown.

BIN
src/asset/fonts/element-icons.ttf Executable file

Binary file not shown.

Binary file not shown.

BIN
src/asset/img/bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

View File

@ -0,0 +1,25 @@
<!--
* @FilePath: /el-vue/src/component/HelloWorld.vue
* @Author: admin@hamm.cn
* @Date: 2021-08-02 21:45:20
* @LastEditTime: 2021-08-03 23:55:43
* @LastEditors: admin@hamm.cn
* Written by https://hamm.cn
* @Description:
-->
<template>
<div>
</div>
</template>
<script>
//! ces
export default {
props: {
msg: String
}
}
</script>
<style scoped>
</style>

34
src/config.js Normal file
View File

@ -0,0 +1,34 @@
/*
* @FilePath: /el-vue/src/config.js
* @Author: admin@hamm.cn
* @Date: 2021-08-02 22:06:29
* @LastEditTime: 2021-08-03 22:14:56
* @LastEditors: admin@hamm.cn
* Written by https://hamm.cn
* @Description:
*/
export default {
debug: true,
apiBaseUrl: "https://api.bbbug.com/api/",
qiyeWechatWebhook: '',
enableErrorReporter: false,
httpStatusCode: {
OK: 200,
MOVED_PERMANENTLY: 301,
FOUND: 302,
NOT_MODIFIED: 304,
BAD_REQUEST: 400,
UNAUTHORIZED: 401,
FORBIDDEN: 403,
NOT_FOUND: 404,
METHOD_NOT_ALLOWED: 405,
INTERNAL_SERVER_ERROR: 500,
BAD_GATEWAY: 502,
SERVICE_UNAVAILABLE: 503,
GATEWAY_TIMEOUT: 504,
},
version: 10000,
defaultErrorMessage: "请求服务器失败,请稍后再试",
requestMissingUrl: "请求缺少url请检查"
}

17
src/helper/api.js Normal file
View File

@ -0,0 +1,17 @@
/*
* @FilePath: /MacOS/src/helper/api.js
* @Author: admin@hamm.cn
* @Date: 2021-08-10 20:53:07
* @LastEditTime: 2021-08-10 20:55:22
* @LastEditors: admin@hamm.cn
* Written by https://hamm.cn
* @Description: API
*/
export default {
closeWindow() {
this.callApi('closeWindow')
},
callApi(action) {
this.$emit('api', action)
}
}

187
src/helper/request.js Normal file
View File

@ -0,0 +1,187 @@
/*
* @Author: admin@hamm.cn
* @Date: 2021-08-02 22:15:37
* @LastEditTime: 2021-08-03 23:56:18
* @LastEditors: admin@hamm.cn
* @FilePath: /el-vue/src/helper/request.js
* Written by https://hamm.cn
* @Description: 网络请求封装库
*/
import axios from 'axios'
import tool from "./tool"
/**
* 高度封装的请求方法
* 支持参数 url,method,header,data,success,error
* @param {object} 请求参数对象
* @param {object} 如需要回调 请原封不动传入
*/
function request(data, object = {}) {
let that = window.app.config.globalProperties
const HTTP_STATUS_CODE = that.config.httpStatusCode
const VERSION = that.config.version
const DEFAULT_ERROR_MESSAGE = that.config.defaultErrorMessage
//开始处理请求地址
const API_BASE_URL = that.config.apiBaseUrl
if (!data.success && object.success) {
data.success = object.success
}
if (!data.error && object.error) {
data.error = object.error
}
if (!data.login && object.login) {
data.login = object.login
}
if (!data.final && object.final) {
data.final = object.final
}
if (!data.url) {
if (data.error) {
let ret = data.error(that.config.requestMissingUrl)
if (!ret) {
that.$message.error(that.config.requestMissingUrl)
}
} else {
that.$message.error()
}
return
}
if (data.url.indexOf("https://") < 0 && data.url.indexOf("http://") < 0) {
//相对地址 追加API_BASE_URL
data.url = API_BASE_URL + data.url
}
//处理请求方法 默认GET
if (!data.method) {
data.method = "get"
}
//开始处理请求Headers
let header = {
'Content-Type': 'application/json',
}
if (data.header) {
for (let i in data.header) {
header[i] = data.header[i]
}
}
//如未指定不需要传TOKEN则默认带上
let access_token = tool.getAccessToken()
if (!data.noToken) {
data.data.access_token = access_token
}
data.data.version = VERSION
data.data.plat = "api"
data.data.user_device = "user_device"
//走不同的请求方法
let result = false;
switch (data.method.toLowerCase()) {
case 'post':
result = axios.post(data.url, data.data, {
headers: header
})
break
case 'put':
axios.put(data.url, data.data, {
headers: header
})
break
case 'delete':
axios.delete(data.url, {
headers: header
})
break
default:
axios.get(data.url, {
headers: header
})
}
console.log(data)
result.then((response) => {
switch (response.data.code) {
case HTTP_STATUS_CODE.OK:
if (data.success) {
let hide = data.success(response.data)
if (!hide) {
that.$message.success(response.data.msg)
}
} else {
that.$message.success(response.data.msg)
}
break
case HTTP_STATUS_CODE.UNAUTHORIZED:
if (data.login) {
data.login()
} else {
localStorage.setItem("path", location.pathname)
that.$router.push("/login")
}
break
default:
if (data.error) {
let hide = data.error(response.data)
if (!hide) {
that.$message.error(response.data.msg)
}
} else {
that.$message.error(response.data.msg)
}
sendRobotMessage(data, response)
}
data.final && data.final()
})
.catch((error) => {
that.config.debug && console.log(error)
if (data.error) {
let ret = data.error(DEFAULT_ERROR_MESSAGE)
if (!ret) {
that.$message.error(DEFAULT_ERROR_MESSAGE)
}
} else {
that.$message.error(DEFAULT_ERROR_MESSAGE)
}
sendRobotMessage(data, error.response)
data.final && data.final()
})
}
/**
* @description: 发送消息到企业微信群
*/
function sendRobotMessage(data, response) {
let that = window.app.config.globalProperties
if (that.config.enableErrorReporter) {
let url = that.config.qiyeWechatWebhook
let responseData = ""
try {
responseData = JSON.stringify(response.data)
} catch (e) {
responseData = response.data
}
if ([503, 504, 502].indexOf(response.status) >= 0) {
return
}
let markdown =
`
# 异常接口告警提示
接口地址**`+ data.url + `**
请求方法**`+ data.method.toUpperCase() + `**
返回状态**` + response.status + `(` + response.statusText + `)` + `**
请求数据
> \``+ (data.data ? JSON.stringify(data.data) : "No Data") + `\`
响应数据
> \``+ responseData + `\`
`
axios.post(url,
{
"msgtype": "markdown",
"markdown": {
"content": markdown
}
}
)
}
}
export default request

66
src/helper/tool.js Normal file
View File

@ -0,0 +1,66 @@
/*
* @Author: admin@hamm.cn
* @Date: 2021-08-03 21:38:43
* @LastEditTime: 2021-08-10 20:33:41
* @LastEditors: admin@hamm.cn
* @FilePath: /MacOS/src/helper/tool.js
* Written by https://hamm.cn
* @Description: 通用方法封装库
*/
import AppModel from "@/model/App"
export default {
/**
* @description: 从localstorage中获取access_token
*/
getAccessToken() {
return localStorage.getItem('AcessToken') || ""
},
saveAccessToken(access_token) {
localStorage.setItem('AcessToken', access_token)
},
getTabApp() {
let json = localStorage.getItem('tab_app') || '[]'
let arr = JSON.parse(json)
if (arr.length == 0) {
return AppModel.getAllAppList()
}
return arr
},
getDeskTopApp() {
let json = localStorage.getItem('desktop_app') || '[]'
let arr = JSON.parse(json)
if (arr.length == 0) {
return AppModel.getAllAppList()
}
return arr
},
formatTime(date, format) {
if (!date) return;
if (!format) format = "yyyy-MM-dd";
switch (typeof date) {
case "string":
date = new Date(date.replace(/-/, "/"));
break;
case "number":
date = new Date(date);
break;
default:
}
var dict = {
"yyyy": date.getFullYear(),
"M": date.getMonth() + 1,
"d": date.getDate(),
"H": date.getHours(),
"m": date.getMinutes(),
"s": date.getSeconds(),
"MM": ("" + (date.getMonth() + 101)).substr(1),
"dd": ("" + (date.getDate() + 100)).substr(1),
"HH": ("" + (date.getHours() + 100)).substr(1),
"mm": ("" + (date.getMinutes() + 100)).substr(1),
"ss": ("" + (date.getSeconds() + 100)).substr(1)
};
return format.replace(/(yyyy|MM?|dd?|HH?|ss?|mm?)/g, function () {
return dict[arguments[0]];
});
}
}

30
src/main.js Normal file
View File

@ -0,0 +1,30 @@
/*
* @FilePath: /MacOS/src/main.js
* @Author: admin@hamm.cn
* @Date: 2021-08-02 21:45:20
* @LastEditTime: 2021-08-10 20:53:40
* @LastEditors: admin@hamm.cn
* Written by https://hamm.cn
* @Description: 入口文件
*/
import { createApp } from 'vue'
import App from './App'
let app = createApp(App)
import ElementPlus from 'element-plus';
import 'element-plus/lib/theme-chalk/index.css';
app.use(ElementPlus)
import "@/asset/css/app.css"
import "@/asset/css/animation.css"
import config from './config'
app.config.globalProperties.config = config
import api from './helper/api'
app.config.globalProperties.api = api
window.app = app
app.mount('#app')

58
src/model/App.js Normal file
View File

@ -0,0 +1,58 @@
/*
* @FilePath: /MacOS/src/model/App.js
* @Author: admin@hamm.cn
* @Date: 2021-08-09 20:51:06
* @LastEditTime: 2021-08-10 22:27:04
* @LastEditors: admin@hamm.cn
* Written by https://hamm.cn
* @Description:
*/
export default {
getAppByKey(key) {
let appList = this.getAllAppList();
for (let app of appList) {
if (app.key == key) {
return app
}
}
return false
},
getAllAppList() {
return [
{
"key": "system_about",
"icon": "icon-question",
"title": "关于本站",
"iconColor": "#fff",
"iconBgColor": "#23282d",
"width": 400,
"height": 250,
"disableResize": true,
"tabbarBgColor": "#333",
"tabbarTextColor": "#fff",
},
{
"key": "app_list",
"icon": "icon-MIS_chanpinshezhi",
"title": "应用中心",
"iconColor": "#fff",
"iconBgColor": "#db5048",
},
{
"key": "user_list",
"icon": "icon-MIS_CRMguanli",
"title": "用户列表",
"iconColor": "#fff",
"iconBgColor": "#398fc1"
},
{
"key": "note_add",
"icon": "icon-MIS_bangongbiji",
"title": "写日记",
"iconColor": "#fff",
"iconBgColor": "#2fc66b"
}
]
}
}

20
src/model/User.js Normal file
View File

@ -0,0 +1,20 @@
/*
* @FilePath: /el-vue/src/model/User.js
* @Author: admin@hamm.cn
* @Date: 2021-08-03 22:18:32
* @LastEditTime: 2021-08-03 23:44:54
* @LastEditors: admin@hamm.cn
* Written by https://hamm.cn
* @Description:
*/
import request from '@/helper/request'
export default {
login(object) {
request({
url: "user/login",
method: "POST",
data: object.data
}, object)
}
};

435
src/view/AppLoader.vue Normal file
View File

@ -0,0 +1,435 @@
<!--
* @FilePath: /MacOS/src/view/AppLoader.vue
* @Author: admin@hamm.cn
* @Date: 2021-08-06 21:34:04
* @LastEditTime: 2021-08-10 22:26:00
* @LastEditors: admin@hamm.cn
* Written by https://hamm.cn
* @Description:
-->
<template>
<div class="moveBg" @mousemove="mouseMove" @mouseup="mouseUp" @mouseleave.stop="mouseLeave"
:style="{pointerEvents:isBoxResizing?'auto':'none'}">
<div class="box"
:style="{left:nowRect.left+'px',top:nowRect.top+'px',bottom:nowRect.bottom+'px',right:nowRect.right+'px'}"
:class="getExtBoxClasses()">
<div class="box-top">
<div class="box-top-left" @mousedown="resizeMouseDown"></div>
<div class="box-top-center" @mousedown="resizeMouseDown"></div>
<div class="box-top-right" @mousedown="resizeMouseDown"></div>
</div>
<div class="box-center">
<div class="box-center-left" @mousedown="resizeMouseDown"></div>
<div class="box-center-center loader" @click="showThisApp">
<div class="app-bar" :style="{backgroundColor:app.tabbarBgColor}" @mousedown.stop="positionMouseDown"
v-on:dblclick="appBarDoubleClicked">
<div class="controll">
<div class="close" @click.stop="close"></div>
<div class="min" @click.stop="close"></div>
<div class="full" :class="app.disableResize?'full-disabled':''" @click="switchFullScreen">
</div>
</div>
<div class="title" :style="{color:app.tabbarTextColor}">{{appData.title||app.title}}</div>
</div>
<div class="app-body">
<template v-if="app.key=='system_about'">
<SystemAbout @api="appEvent"></SystemAbout>
</template>
</div>
</div>
<div class="box-center-right" @mousedown="resizeMouseDown"></div>
</div>
<div class="box-bottom">
<div class="box-bottom-left" @mousedown="resizeMouseDown"></div>
<div class="box-bottom-center" @mousedown="resizeMouseDown"></div>
<div class="box-bottom-right" @mousedown="resizeMouseDown"></div>
</div>
</div>
</div>
</template>
<script>
import AppModel from "@/model/App"
import { defineAsyncComponent } from 'vue'
export default {
components: {
SystemAbout: defineAsyncComponent(() => import('@/view/system/about'))
},
props: {
app: Object,
},
data() {
return {
appData: {
title: ""
},
appList: AppModel.getAllAppList(),
defaultIndex: 10,
activeIndex: 20,
isBoxMoving: false,
startPosition: { x: 0, y: 0 },
nowRect: {
left: 100, right: 100,
top: 100, bottom: 100
},
startRect: {
left: 0, right: 0, top: 0, bottom: 0
},
isBoxResizing: false,
moveDirection: false,
isMaxShowing: false,
isFullScreen: false,
}
},
created() {
console.log(this.app)
if (this.app.width) {
this.nowRect.left = this.nowRect.right = (document.body.clientWidth - this.app.width) / 2
}
if (this.app.height) {
this.nowRect.bottom = (document.body.clientHeight - this.app.height) / 2 + 100
this.nowRect.top = (document.body.clientHeight - this.app.height) / 2 - 100
}
},
methods: {
appEvent(e) {
console.log(e)
},
close() {
this.$emit('close', this.app)
},
showThisApp() {
this.$emit('open', this.app)
},
switchFullScreen() {
if (this.app.disableResize) {
return
}
this.isFullScreen = !this.isFullScreen;
if (this.isFullScreen) {
this.isMaxShowing = true
} else {
this.isMaxShowing = false
}
},
getExtBoxClasses() {
let str = "";
if (!this.isBoxResizing && !this.isBoxMoving) {
str += "box-animation "
}
if (this.isMaxShowing) {
str += "isMaxShowing "
}
if (this.isFullScreen) {
str += "isFullScreen "
}
return str
},
appBarDoubleClicked() {
if (this.app.disableResize) {
return
}
this.isMaxShowing = !this.isMaxShowing
if (!this.isMaxShowing) {
this.isFullScreen = false
}
},
positionMouseDown(e) {
this.showThisApp()
if (this.isFullScreen || this.isMaxShowing) {
return
}
this.startRect = {
left: this.nowRect.left,
right: this.nowRect.right,
top: this.nowRect.top,
bottom: this.nowRect.bottom,
};
this.startPosition.x = e.clientX
this.startPosition.y = e.clientY
this.isBoxMoving = true
},
mouseUp() {
this.isBoxMoving = false
this.isBoxResizing = false
this.moveDirection = false
},
mouseLeave() {
this.isBoxMoving = false
this.isBoxResizing = false
this.moveDirection = false
},
mouseMove(e) {
if (this.isBoxResizing) {
this.isFullScreen = false
this.isMaxShowing = false
switch (this.moveDirection) {
case 'box-top-left':
this.nowRect.top = this.startRect.top + (e.clientY - this.startPosition.y)
this.nowRect.left = this.startRect.left + (e.clientX - this.startPosition.x)
break
case 'box-top-center':
this.nowRect.top = this.startRect.top + (e.clientY - this.startPosition.y)
break
case 'box-top-right':
this.nowRect.top = this.startRect.top + (e.clientY - this.startPosition.y)
this.nowRect.right = this.startRect.right - (e.clientX - this.startPosition.x)
break
case 'box-center-left':
this.nowRect.left = this.startRect.left + (e.clientX - this.startPosition.x)
break
case 'box-bottom-left':
this.nowRect.left = this.startRect.left + (e.clientX - this.startPosition.x)
this.nowRect.bottom = this.startRect.bottom - (e.clientY - this.startPosition.y)
break
case 'box-bottom-center':
this.nowRect.bottom = this.startRect.bottom - (e.clientY - this.startPosition.y)
break
case 'box-center-right':
this.nowRect.right = this.startRect.right - (e.clientX - this.startPosition.x)
break
case 'box-bottom-right':
this.nowRect.right = this.startRect.right - (e.clientX - this.startPosition.x)
this.nowRect.bottom = this.startRect.bottom - (e.clientY - this.startPosition.y)
break
default:
}
return;
}
if (this.isBoxMoving) {
this.isFullScreen = false
this.isMaxShowing = false
this.nowRect.left = this.startRect.left + (e.clientX - this.startPosition.x)
this.nowRect.right = this.startRect.right - (e.clientX - this.startPosition.x)
this.nowRect.top = this.startRect.top + (e.clientY - this.startPosition.y)
this.nowRect.bottom = this.startRect.bottom - (e.clientY - this.startPosition.y)
return
}
},
resizeMouseDown(e) {
if (this.app.disableResize) {
return
}
this.showThisApp()
if (this.isFullScreen || this.isMaxShowing) {
return
}
this.startRect = {
left: this.nowRect.left,
top: this.nowRect.top,
right: this.nowRect.right,
bottom: this.nowRect.bottom,
};
this.startPosition.x = e.clientX
this.startPosition.y = e.clientY
this.isBoxResizing = true
this.moveDirection = e.target.className
},
}
}
</script>
<style scoped>
.moveBg {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.box {
--resize: 5px;
--resize-bg: transparent;
--resize-main: transparent;
--resize-bg-main: transparent;
}
.box {
display: flex;
flex-direction: column;
position: absolute;
pointer-events: auto;
}
.box-top {
display: flex;
flex-direction: row;
}
.box-top-left {
width: var(--resize);
height: var(--resize);
background: var(--resize-bg);
cursor: nw-resize;
}
.box-top-center {
height: var(--resize);
background: var(--resize-bg-main);
cursor: n-resize;
flex-grow: 1;
}
.box-top-right {
width: var(--resize);
height: var(--resize);
background: var(--resize-bg);
cursor: ne-resize;
}
.box-center {
display: flex;
flex-direction: row;
flex-grow: 1;
}
.box-center-left {
width: var(--resize);
height: 100%;
background: var(--resize-bg-main);
cursor: w-resize;
}
.box-center-center {
height: 100%;
flex-grow: 1;
display: flex;
flex-direction: column;
border-radius: 10px;
box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.3);
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(20px);
overflow: hidden;
}
.box-animation {
transition: width 0.1s, height 0.1s, left 0.1s, right 0.1s, top 0.1s, bottom 0.1s;
}
.isMaxShowing {
left: -5px !important;
right: -5px !important;
top: -5px !important;
bottom: 60px !important;
}
.isFullScreen {
position: fixed !important;
z-index: 99999;
bottom: -5px !important;
}
.isMaxShowing .box-center-center,
.isFullScreen .box-center-center {
border-radius: 0px !important;
}
.box-center-right {
width: var(--resize);
height: 100%;
background: var(--resize-bg-main);
cursor: e-resize;
}
.box-bottom {
display: flex;
flex-direction: row;
}
.box-bottom-left {
width: var(--resize);
height: var(--resize);
background: var(--resize-bg);
cursor: sw-resize;
}
.box-bottom-center {
height: var(--resize);
background: var(--resize-bg-main);
cursor: s-resize;
flex-grow: 1;
}
.box-bottom-right {
width: var(--resize);
height: var(--resize);
background: var(--resize-bg);
cursor: se-resize;
}
.loader {
display: flex;
flex-grow: 1;
flex-direction: column;
}
.app-bar {
height: 40px;
background: rgba(255, 255, 255, 0.5);
backdrop-filter: blur(20px);
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.app-bar .controll {
display: flex;
justify-content: center;
align-items: center;
margin-left: 15px;
}
.app-bar .controll div {
border-radius: 100%;
height: 11px;
width: 11px;
margin-right: 8px;
cursor: pointer;
}
.app-bar .title {
flex-grow: 1;
color: #333;
text-align: center;
margin-right: 80px;
font-weight: 500;
text-shadow: none;
font-size: 13px;
cursor: move;
}
.controll .close {
background: #fc605c;
border: 1px solid #fc635d;
}
.controll .min {
background: #fcbb40;
border: 1px solid #f8b438;
}
.controll .full {
background: #34c648;
border: 1px solid #2bc03f;
}
.full-disabled {
background: #ccc !important;
border: 1px solid #ccc !important;
}
.app-body {
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>

39
src/view/Bg.vue Normal file
View File

@ -0,0 +1,39 @@
<!--
* @FilePath: /MacOS/src/view/Bg.vue
* @Author: admin@hamm.cn
* @Date: 2021-08-05 20:59:02
* @LastEditTime: 2021-08-05 22:02:16
* @LastEditors: admin@hamm.cn
* Written by https://hamm.cn
* @Description:
-->
<template>
<div class="bg" :style="{backgroundImage:'url('+bgImage+')'}">
</div>
</template>
<style scoped>
.bg {
background-color: #000;
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 0;
background-size: cover;
background-repeat: no-repeat;
}
</style>
<script>
export default {
data() {
return {
bgImage: require("@/asset/img/bg.jpg")
}
}
}
</script>

478
src/view/DeskTop.vue Normal file
View File

@ -0,0 +1,478 @@
<!--
* @FilePath: /MacOS/src/view/DeskTop.vue
* @Author: admin@hamm.cn
* @Date: 2021-08-02 21:45:20
* @LastEditTime: 2021-08-10 22:27:42
* @LastEditors: admin@hamm.cn
* Written by https://hamm.cn
* @Description:
-->
<template>
<div class="desktop">
<div class="top">
<el-dropdown trigger="click">
<div class="logo"><i class="iconfont icon-apple1"></i></div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="openAppByKey('system_about')">
<div>关于本站</div>
</el-dropdown-item>
<el-dropdown-item class="line"></el-dropdown-item>
<el-dropdown-item>
<div>系统偏好设置</div>
</el-dropdown-item>
<el-dropdown-item>
<div>强制退出...</div>
</el-dropdown-item>
<el-dropdown-item class="line"></el-dropdown-item>
<el-dropdown-item>
<div>锁定屏幕</div>
</el-dropdown-item>
<el-dropdown-item>
<div>重新启动...</div>
</el-dropdown-item>
<el-dropdown-item class="line"></el-dropdown-item>
<el-dropdown-item>
<div>关机...</div>
</el-dropdown-item>
<el-dropdown-item>
<div>退出登录 Hamm...</div>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<div class="menu" v-for="item in menu" :key="item.value">
<el-dropdown trigger="click" placement="bottom-start">
<div class="item">{{item.title}}</div>
<template #dropdown>
<el-dropdown-menu>
<template v-for="subItem in item.sub" :key="subItem.value">
<el-dropdown-item class="line" v-if="subItem.isLine"></el-dropdown-item>
<el-dropdown-item v-else>
<div>{{subItem.title}}</div>
</el-dropdown-item>
</template>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
<div class="space"></div>
<div class="status">
<div class="audio"><i class="iconfont icon-changyongtubiao-xianxingdaochu-zhuanqu-39"></i></div>
<div class="datetime">{{timeString}}</div>
<div class="notification"><i class="iconfont icon-changyongtubiao-xianxingdaochu-zhuanqu-25"></i></div>
</div>
</div>
<div class="body">
<div class="desktop-app">
<div class="app-item" v-for="item in deskTopAppList" :key="item.key" @click="openApp(item)">
<div class="icon" :style="{backgroundColor:item.iconBgColor,color:item.iconColor}"><i class="iconfont"
:class="item.icon"></i></div>
<div class="title">{{item.title}}</div>
</div>
</div>
<template v-for="item in openAppList" :key="item.key">
<transition name="fade-window">
<AppLoader :app="item" @open="openApp" @close="closeApp"></AppLoader>
</transition>
</template>
</div>
<div class="footer">
<div class="space"></div>
<div class="tabbar">
<div class="item"><i style="background-color:#939391" class="iconfont icon-shezhi"></i></div>
<div class="item"><i style="background-color:#257eef" class="iconfont icon-youjian"></i></div>
<div class="item"><i style="background-color: #27abed;" class="iconfont icon-shangpu"></i></div>
<div class="item"><i style="background-color: #2197d8;" class="iconfont icon-BugReport"></i></div>
<div class="item"><i style="background-color: #262626;" class="iconfont icon-naozhong"></i></div>
<div class="item"><i style="background-color: #d8d8d8;color: #298ae9;" class="iconfont icon-zhinanzhen"></i>
</div>
<div class="item"><i style="background-color: #c5202a;color: #fff;" class="iconfont icon-oschina"></i>
</div>
<div class="item"><i style="background-color: #24292e;" class="iconfont icon-github"></i></div>
<div class="item"><i style="background-color: #ffffff;color:#2b9eed ;" class="iconfont icon-vscode"></i>
</div>
<div class="item"><i style="background-color: #217bfb;color: white;" class="iconfont icon-alipay"></i>
</div>
<div class="item"><i style="background-color: #41a4e8" class="iconfont icon-dingtalk"></i></div>
<div class="item"><i style="background-color: #db5048" class="iconfont icon-chrome-fill"></i></div>
<div class="item"><i style="background-color: #126bfb;color: white;" class="iconfont icon-zhihu"></i>
</div>
<div class="item"><i style="background-color: #22cd6a" class="iconfont icon-wechat-fill"></i></div>
<div class="item"><i style="background-color: #000000;" class="iconfont icon-QQ"></i></div>
<div class="item"><i style="background-color: #2cb256;" class="iconfont icon-icon-oschina-circle"></i>
</div>
<div class="item"><i style="background-color: #338ec3" class="iconfont icon-twitter"></i></div>
<div class="item"><i style="background-color: #d42927;" class="iconfont icon-weibo1"></i></div>
<div class="item"><i style="background-color: white;color: #fc0d1b;" class="iconfont icon-Youtube-fill"></i>
</div>
<div class="item"><i style="background-color: #e85349;color: #fff;" class="iconfont icon-google"></i>
</div>
</div>
<div class="space"></div>
</div>
</div>
</template>
<script>
import AppModel from "@/model/App"
import AppLoader from "@/view/AppLoader"
import tool from "@/helper/tool"
export default {
components: {
AppLoader,
},
data() {
return {
menu: [],
timeString: "",
openAppList: [],
deskTopAppList: [],
tabAppList: [],
deskTopMenu: [
{
key: "desktop",
title: "桌面",
sub: [
{
key: "big_icon",
title: "大图标",
},
{
key: "big_icon",
title: "小图标",
},
{
isLine: true
},
{
key: "align_left",
title: "左侧排列",
},
{
key: "align_right",
title: "右侧排列",
},
{
isLine: true
},
{
key: "wall",
title: "更换壁纸...",
}
]
}
]
}
},
created() {
this.menu = this.deskTopMenu
this.loadApp()
this.startTimer()
},
methods: {
startTimer() {
setInterval(() => {
this.timeString = tool.formatTime(new Date(), 'MM-dd HH:mm')
}, 1000)
},
closeApp(app) {
for (let i in this.openAppList) {
if (this.openAppList[i].key == app.key) {
this.openAppList.splice(i, 1);
}
}
},
openApp(app) {
for (let i in this.openAppList) {
if (this.openAppList[i].key == app.key) {
this.openAppList.splice(i, 1);
}
}
this.openAppList.push(app);
},
openAppByKey(key) {
let app = AppModel.getAppByKey(key)
if (app) {
this.openApp(app)
}
},
loadApp() {
this.tabAppList = tool.getTabApp()
this.deskTopAppList = tool.getDeskTopApp()
this.$nextTick(() => {
let children = document.querySelector(".tabbar").children
for (let i = 0; i < children.length; i++) {
children[i].addEventListener("mouseover", () => {
try {
children[i].previousSibling.className = "item nearby"
children[i].nextSibling.className = "item nearby"
children[i].previousSibling.previousSibling.className = "item nearby1"
children[i].nextSibling.nextSibling.className = "item nearby1"
children[i].previousSibling.previousSibling.previousSibling.className = "item nearby2"
children[i].nextSibling.nextSibling.nextSibling.className = "item nearby2"
} catch (e) {
//DOM
}
})
children[i].addEventListener("mouseout", () => {
try {
children[i].previousSibling.className = "item"
children[i].nextSibling.className = "item"
children[i].previousSibling.previousSibling.className = "item"
children[i].nextSibling.nextSibling.className = "item"
children[i].previousSibling.previousSibling.previousSibling.className = "item"
children[i].nextSibling.nextSibling.nextSibling.className = "item"
} catch (e) {
//DOM
}
})
}
})
}
}
}
</script>
<style>
.top .el-dropdown {
color: white !important;
height: 100% !important;
}
</style>
<style scoped>
.desktop {
display: flex;
flex-direction: column;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
color: white;
overflow: hidden;
text-shadow: 0px 2px 2px rgba(0, 0, 0, 0.1);
}
.top {
height: 28px;
background-color: rgba(0, 0, 0, 0.3);
backdrop-filter: blur(20px);
display: flex;
flex-direction: row;
font-size: 14px;
align-items: center;
justify-content: center;
padding: 0px 5px;
z-index: 9999;
}
.space {
flex-grow: 1;
}
.logo {
height: 100%;
align-items: center;
justify-content: center;
padding: 0px 15px;
cursor: pointer;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.logo .el-select {
position: absolute;
opacity: 0;
}
.logo:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.logo .iconfont {
font-size: 16px;
margin-top: -3px;
}
.menu {
display: flex;
flex-direction: row;
font-size: 13px;
height: 100%;
font-weight: 500;
}
.menu .item {
font-size: 13px;
padding: 0px 15px;
display: inline-block;
flex-grow: 1;
cursor: pointer;
display: flex;
height: 100%;
align-items: center;
justify-content: center;
}
.menu .item:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.status {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
height: 100%;
}
.audio .iconfont,
.notification .iconfont {
font-size: 20px;
}
.datetime,
.audio,
.notification {
cursor: pointer;
padding: 0px 10px;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.datetime:hover,
.audio:hover,
.notification:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.body {
flex-grow: 1;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
position: relative;
}
.footer {
position: fixed;
left: 5px;
right: 5px;
bottom: 5px;
justify-content: center;
align-items: center;
display: flex;
flex-direction: row;
z-index: 9999;
}
.footer .tabbar {
background-color: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);
backdrop-filter: blur(20px);
border-radius: 10px;
flex-direction: row;
display: flex;
padding: 2px;
}
.tabbar .item {
padding: 3px;
}
.tabbar .item .iconfont {
cursor: pointer;
border-radius: 20px;
padding: 2px;
display: inline-block;
background-color: rgba(255, 255, 255, 0.1);
border-radius: 10px;
height: 30px;
width: 30px;
text-align: center;
font-size: 24px;
display: flex;
align-items: center;
justify-content: center;
transition: transform .3s, margin .3s;
}
.tabbar .item:hover .iconfont {
transform: scale(2) translateY(-10px);
margin: 0px 15px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
}
.tabbar .nearby .iconfont {
transform: scale(1.6) translateY(-8px);
margin: 0px 12px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
}
.tabbar .nearby1 .iconfont {
transform: scale(1.2) translateY(-6px);
margin: 0px 9px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
}
.tabbar .nearby2 .iconfont {
transform: scale(1.1) translateY(-5px);
margin: 0px 7px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
}
.desktop-app {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-end;
padding: 20px;
}
.app-item {
margin: 5px;
padding: 5px;
flex-direction: column;
text-align: center;
text-shadow: 0px 0px 2px rgb(0 0 0 / 50%);
cursor: pointer;
border-radius: 10px;
border: 2px solid transparent;
}
.app-item .icon {
border-radius: 10px;
width: 50px;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
}
.app-item .iconfont {
font-size: 36px;
}
.app-item .title {
font-size: 12px;
width: 50px;
margin-top: 5px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.app-item:hover {
border: 2px solid rgba(255, 255, 255, 0.5);
}
</style>

104
src/view/Loading.vue Normal file
View File

@ -0,0 +1,104 @@
<!--
* @FilePath: /MacOS/src/view/Loading.vue
* @Author: admin@hamm.cn
* @Date: 2021-08-05 21:00:27
* @LastEditTime: 2021-08-09 22:56:51
* @LastEditors: admin@hamm.cn
* Written by https://hamm.cn
* @Description: 开机进度条页面
-->
<template>
<div class="loading" @click="fullScreen">
<div class="logo"><i class="iconfont icon-apple-fill"></i></div>
<div class="progress" :style="{width:showProgress?'300px':0}">
<div :style="{width:progress+'%'}"></div>
</div>
</div>
</template>
<style scoped>
.loading {
background-color: #000;
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
margin-top: -100px;
z-index: 99999999999;
}
.logo .iconfont {
font-size: 120px;
}
.progress {
margin-top: 50px;
width: 200px;
background-color: rgba(255, 255, 255, .1);
height: 6px;
border-radius: 20px;
overflow: hidden;
position: relative;
}
.progress div {
width: 20%;
border-radius: 20px;
background-color: rgba(255, 255, 255, .2);
position: absolute;
left: 0;
top: 0;
bottom: 0;
}
</style>
<script>
export default {
data() {
return {
progress: 0,
showProgress: false,
}
},
created() {
setTimeout(() => {
this.showProgress = true;
this.updateProgress()
}, 3000)
},
methods: {
fullScreen() {
var docElm = document.documentElement;
if (docElm.requestFullscreen) {
docElm.requestFullscreen();
}
else if (docElm.msRequestFullscreen) {
docElm.msRequestFullscreen();
}
else if (docElm.mozRequestFullScreen) {
docElm.mozRequestFullScreen();
}
else if (docElm.webkitRequestFullScreen) {
docElm.webkitRequestFullScreen();
}
},
updateProgress() {
this.progress += parseInt(Math.random() * 10)
if (this.progress >= 100) {
this.progress = 100
this.showProgress = false
setTimeout(() => this.$emit('loaded'), 1000)
} else {
setTimeout(() => this.updateProgress(), 200)
}
}
}
}
</script>

132
src/view/Login.vue Normal file
View File

@ -0,0 +1,132 @@
<!--
* @FilePath: /MacOS/src/view/login.vue
* @Author: admin@hamm.cn
* @Date: 2021-08-05 20:59:02
* @LastEditTime: 2021-08-05 23:43:39
* @LastEditors: admin@hamm.cn
* Written by https://hamm.cn
* @Description:
-->
<template>
<div class="login">
<div class="head" :style="{backgroundImage:'url('+headImage+')'}"></div>
<div class="message">Login Please</div>
<div class="form">
<div class="item">
<input class="account" placeholder="account here..." type="email" /><i
class="iconfont icon-icon_principal" @click="guest"></i>
</div>
<div class="item">
<input class="password" placeholder="password here..." type="password" /><i
class="iconfont icon-icon_send" @click="guest"></i>
</div>
</div>
</div>
</template>
<style scoped>
.login {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
margin-top: -100px;
z-index: 99999999998;
backdrop-filter: blur(20px);
}
.head {
background-size: 40% auto;
background-position: center center;
height: 150px;
width: 150px;
border-radius: 100%;
box-shadow: 0px 0px 5px 5px rgba(0, 0, 0, 0.1);
margin-top: -50px;
}
.message {
margin-top: 20px;
font-size: 20px;
text-shadow: 0px 0px 2px 2px rgba(0, 0, 0, 0.3);
color: #eee;
margin-bottom: 50px;
}
input {
color: white;
outline: none;
border: none;
margin: 5px;
font-size: 16px;
background-color: rgba(255, 255, 255, 0.3);
padding: 8px 24px;
border-radius: 20px;
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1);
}
::-webkit-input-placeholder {
color: #fff;
}
::-moz-placeholder {
color: #fff;
}
:-ms-input-placeholder {
color: #fff;
}
.form {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
vertical-align: middle;
}
.item {
vertical-align: middle;
}
.item .iconfont {
vertical-align: middle;
display: inline-block;
background-color: rgba(255, 255, 255, 0.3);
font-size: 18px;
border-radius: 100%;
width: 36px;
height: 36px;
text-align: center;
line-height: 36px;
cursor: pointer;
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1);
}
.item .iconfont:hover {
background-color: rgba(255, 255, 255, 0.5);
}
</style>
<script>
import tool from "@/helper/tool"
export default {
data() {
return {
headImage: require("@/asset/img/bg.jpg")
}
},
methods: {
guest() {
tool.saveAccessToken("guest")
this.$emit("logined")
}
}
}
</script>

77
src/view/system/about.vue Normal file
View File

@ -0,0 +1,77 @@
<!--
* @FilePath: /MacOS/src/view/system/about.vue
* @Author: admin@hamm.cn
* @Date: 2021-08-02 21:56:04
* @LastEditTime: 2021-08-10 22:16:52
* @LastEditors: admin@hamm.cn
* Written by https://hamm.cn
* @Description: Index
-->
<template>
<div class="about">
<div class="top">
<i class="iconfont icon-apple1"></i>
<div class="info">
<div class="title">{{about.title}}</div>
<div class="version">{{about.version}}</div>
</div>
</div>
<div class="copyright">{{about.copyright}}</div>
</div>
</template>
<style scoped>
.about {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
color: #333;
text-shadow: none;
font-weight: 300;
}
.top {
display: flex;
flex-direction: row;
flex-grow: 1;
padding: 20px 40px;
}
.title {
font-size: 24px;
}
.iconfont {
font-size: 48px;
margin-right: 20px;
}
.version {
font-size: 14px;
color: #999;
}
.copyright {
font-size: 12px;
color: #999;
padding: 20px;
text-align: center;
}
</style>
<script>
export default {
name: "system_about",
data() {
return {
about: {
title: "MacOS WebUI",
version: "v0.0.1 2021-08-10 22:22",
copyright: "本项目所用MacOS图标版权为Apple.Inc所有,向MacOS致敬!"
},
}
},
created() {
}
}
</script>