main
suixy 6 days ago
commit 4e333fbe16

30
.gitignore vendored

@ -0,0 +1,30 @@
.DS_Store
.history
node_modules/
dist/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
**/*.log
tests/**/coverage/
tests/e2e/reports
selenium-debug.log
# Editor directories and files
.idea
.vscode
.hbuilderx
*.suo
*.ntvs*
*.njsproj
*.sln
*.local
package-lock.json
yarn.lock
pnpm-lock.yaml
# 编译生成的文件
auto-imports.d.ts
components.d.ts

@ -0,0 +1,17 @@
<script>
export default {
onLaunch: function() {
console.log('App Launch')
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style>
/*每个页面公共css */
</style>

@ -0,0 +1,28 @@
import {
request
} from '@/utils/request'
import {
getGlobalData
} from '@/store/index.js'
const clientId = getGlobalData('clientId')
export function loginApi(params) {
return request({
url: '/auth/login',
method: 'POST',
headers: {
isToken: false,
isEncrypt: true,
repeatSubmit: false
},
method: 'post',
data: {
...params,
clientId,
grantType: params.grantType || 'password',
rememberMe: false,
tenantId: "000000",
}
})
}

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="zh-CN">
<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-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/main.js"></script>
</body>
</html>

@ -0,0 +1,24 @@
import App from './App'
// #ifndef VUE3
import Vue from 'vue'
import './uni.promisify.adaptor'
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
// #endif
// #ifdef VUE3
import {
createSSRApp
} from 'vue'
export function createApp() {
const app = createSSRApp(App)
return {
app
}
}
// #endif

@ -0,0 +1,73 @@
{
"name" : "highwayiot-business-management-platform",
"appid" : "__UNI__5F0F000",
"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,
"es6" : true
},
"usingComponents" : true
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "3"
}

@ -0,0 +1,6 @@
{
"dependencies": {
"crypto-js": "^4.2.0",
"jsencrypt": "^3.5.4"
}
}

@ -0,0 +1,23 @@
{
"pages": [ //pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/login/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "uni-app"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"uniIdRouter": {}
}

@ -0,0 +1,40 @@
<template>
<view class="content">
<image class="logo" src="/static/logo.png"></image>
<view class="text-area">
<text class="title">{{title}}</text>
</view>
</view>
</template>
<script setup>
const title = 'hello'
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
</style>

@ -0,0 +1,174 @@
<template>
<view class="bgImg"></view>
<view class="logo"></view>
<view class="form">
<view class="username">
<view class="icon"></view>
<input class="input" autocomplete="off" @input="usernameInput" placeholder="请输入用户名"
placeholder-style="color: rgba(25, 132, 238, 0.6);" />
</view>
<view class="password">
<view class="icon"></view>
<input class="input" autocomplete="off" type="password" @input="passwordInput" placeholder="请输入密码"
placeholder-style="color: rgba(25, 132, 238, 0.6);" />
</view>
<view class="loginBtn" @tap="login"> </view>
<view class="subBtns">
<!-- <text>忘记密码</text> -->
</view>
</view>
</template>
<script setup>
import {
ref
} from 'vue'
import {
setGlobalData,
getGlobalData
} from '@/store/index.js'
import {
loginApi
} from '@/api/login'
const loginForm = ref({})
const usernameInput = (event) => {
loginForm.value.username = event.detail.value
}
const passwordInput = (event) => {
loginForm.value.password = event.detail.value
}
const login = async () => {
const data = await loginApi(loginForm.value)
if (data) {
setGlobalData('token', data.data.access_token)
}
}
</script>
<style scoped lang="scss">
@import "@/uni.scss";
.bgImg {
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100%;
background-image: url(#{$img-url}/login.png);
background-size: 100% 100%;
background-repeat: no-repeat;
}
.logo {
position: absolute;
top: 14vh;
left: 50%;
width: 25vw;
height: 19vw;
transform: translateX(-50%);
background-image: url(#{$img-url}/logo.png);
background-size: 100% 100%;
background-repeat: no-repeat;
}
.form {
position: absolute;
top: calc(14vh + 19vw + 7vh);
left: 50%;
width: 58vw;
transform: translateX(-50%);
padding: 7vh 10vw;
background-color: rgba(255, 255, 255, 0.24);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1rpx solid #fff;
.username {
width: 58vw;
height: 11vw;
background-color: rgba(0, 77, 154, 0.2);
border-radius: 5rpx;
border: 1rpx solid rgba(255, 255, 255, 0.24);
position: relative;
.icon {
position: absolute;
width: 5vw;
height: 5.5vw;
top: 50%;
left: 5vw;
transform: translateY(-50%);
background-image: url(#{$img-url}/username.png);
background-size: 100% 100%;
background-repeat: no-repeat;
}
.input {
position: absolute;
top: 50%;
left: 15vw;
width: 40vw;
height: 10vw;
transform: translateY(-50%);
font-size: 26rpx;
}
}
.password {
width: 58vw;
height: 11vw;
margin-top: 3.7vh;
background-color: rgba(0, 77, 154, 0.2);
border-radius: 5rpx;
border: 1rpx solid rgba(255, 255, 255, 0.24);
position: relative;
.icon {
position: absolute;
width: 4.625vw;
height: 5.375vw;
top: 50%;
left: 5vw;
transform: translateY(-50%);
background-image: url(#{$img-url}/password.png);
background-size: 100% 100%;
background-repeat: no-repeat;
}
.input {
position: absolute;
top: 50%;
left: 15vw;
width: 40vw;
height: 10vw;
transform: translateY(-50%);
font-size: 26rpx;
}
}
.loginBtn {
width: 58vw;
height: 11vw;
margin-top: 7vh;
background: linear-gradient(to top,
rgba(64, 140, 247, 1),
rgba(16, 103, 225, 1));
border-radius: 5rpx;
color: rgba(255, 255, 255, 1);
line-height: 11vw;
text-align: center;
font-size: 34rpx;
}
.subBtns {
width: 58vw;
margin-top: 2vh;
border-radius: 5rpx;
font-size: 24rpx;
}
}
</style>

@ -0,0 +1,21 @@
const globaldata = {
token: '',
encryptHeader: 'encrypt-key',
clientId: '428a8310cd442757ae699df5d894f051',
RSA_PUBLIC_KEY: 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==',
RSA_PRIVATE_KEY: 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE='
}
export const getGlobalData = (key) => {
if (Array.isArray(key)) {
let res = {}
key.forEach(e => {
res[e] = globaldata[e] || ''
})
return res
} else {
return globaldata[key] || ''
}
}
export const setGlobalData = (key, value) => {
globaldata[key] = value
}

@ -0,0 +1,13 @@
uni.addInterceptor({
returnValue (res) {
if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) {
return res;
}
return new Promise((resolve, reject) => {
res.then((res) => {
if (!res) return resolve(res)
return res[0] ? reject(res[0]) : resolve(res[1])
});
});
},
});

@ -0,0 +1,81 @@
/**
* uni-app
*
* uni-app https://ext.dcloud.net.cn使
* 使scss使 import 便App
*
*/
/**
* App使
*
* 使scss scss 使 import
*/
/* 图片地址 */
// $img-url: 'https://hw-bm-1307203087.cos.ap-beijing.myqcloud.com';
$img-url: 'https://frp-off.com:47543/appstatic';
/* 颜色变量 */
/* 行为相关颜色 */
$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;

@ -0,0 +1,66 @@
import CryptoJS from 'crypto-js'
/**
* 随机生成32位的字符串
* @returns {string}
*/
const generateRandomString = () => {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
const charactersLength = characters.length;
for (let i = 0; i < 32; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
};
/**
* 随机生成aes 密钥
* @returns {string}
*/
export const generateAesKey = () => {
return CryptoJS.enc.Utf8.parse(generateRandomString());
};
/**
* 加密base64
* @returns {string}
*/
export const encryptBase64 = (str) => {
return CryptoJS.enc.Base64.stringify(str);
};
/**
* 解密base64
*/
export const decryptBase64 = (str) => {
return CryptoJS.enc.Base64.parse(str);
};
/**
* 使用密钥对数据进行加密
* @param message
* @param aesKey
* @returns {string}
*/
export const encryptWithAes = (message, aesKey) => {
const encrypted = CryptoJS.AES.encrypt(message, aesKey, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString();
};
/**
* 使用密钥对数据进行解密
* @param message
* @param aesKey
* @returns {string}
*/
export const decryptWithAes = (message, aesKey) => {
const decrypted = CryptoJS.AES.decrypt(message, aesKey, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return decrypted.toString(CryptoJS.enc.Utf8);
};

@ -0,0 +1,25 @@
import JSEncrypt from 'jsencrypt';
import {
getGlobalData
} from '@/store/index.js'
const {
RSA_PUBLIC_KEY: publicKey,
RSA_PRIVATE_KEY: privateKey
} = getGlobalData(['RSA_PUBLIC_KEY', 'RSA_PRIVATE_KEY'])
// 加密
export const encrypt = (txt) => {
const encryptor = new JSEncrypt();
encryptor.setPublicKey(publicKey); // 设置公钥
return encryptor.encrypt(txt); // 对数据进行加密
};
// 解密
export const decrypt = (txt) => {
const encryptor = new JSEncrypt();
encryptor.setPrivateKey(privateKey); // 设置私钥
return encryptor.decrypt(txt); // 对数据进行解密
};

File diff suppressed because one or more lines are too long

@ -0,0 +1,88 @@
import {
encryptBase64,
encryptWithAes,
generateAesKey,
decryptWithAes,
decryptBase64
} from '@/utils/crypto';
import {
encrypt,
decrypt
} from '@/utils/jsencrypt';
import {
getGlobalData
} from '@/store/index.js'
const encryptHeader = getGlobalData('encryptHeader');
const baseURL = 'https://frp-off.com:47543'
const getToken = () => {
return getGlobalData('token')
}
export function request(options) {
// 加密
const isEncrypt = options.headers && (options.headers.isEncrypt === 'true' || options.headers.isEncrypt === true);
if (isEncrypt && (options.method === 'post' || options.method === 'put')) {
const aesKey = generateAesKey();
options.headers[encryptHeader] = encrypt(encryptBase64(aesKey));
options.data = typeof options.data === 'object' ? encryptWithAes(JSON.stringify(options.data), aesKey) :
encryptWithAes(options.data, aesKey);
}
// token
let isToken = (options.headers || {}).isToken === false
if (getToken() && !isToken) {
options.headers['Authorization'] = 'Bearer ' + getToken();
}
return new Promise((resolve, reject) => {
uni.request({
url: baseURL + options.url,
method: options.method || 'GET',
data: options.data || {},
header: options.headers || {},
success: res => {
if (res.statusCode === 200) {
let code = res.data.code
let msg = res.data.msg
if (code === 200) {
uni.showToast({
title: msg.length < 10 ? msg : '成功',
icon: 'success',
duration: 2000
})
resolve(res.data)
} else {
if (code === 401) {
uni.showToast({
title: '请重新登录',
icon: 'error',
duration: 2000
})
} else {
uni.showToast({
title: msg.length < 10 ? msg : '网络错误请重试',
icon: 'error',
duration: 2000
})
}
reject(false)
}
} else {
reject(false)
}
},
fail: err => {
uni.showToast({
title: '网络错误请重试',
icon: 'error',
duration: 2000
})
reject(false)
}
})
})
}
Loading…
Cancel
Save