初始化
21
.env.development
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# 页面标题
|
||||||
|
VITE_APP_TITLE = 寻驾
|
||||||
|
|
||||||
|
# 租户id
|
||||||
|
VITE_APP_TENANT_ID = 10001
|
||||||
|
|
||||||
|
VITE_APP_PHONE = 18056811878
|
||||||
|
|
||||||
|
# 开发环境配置
|
||||||
|
VITE_APP_ENV = 'development'
|
||||||
|
|
||||||
|
# 寻驾/开发环境
|
||||||
|
VITE_APP_BASE_API = 'https://cloud.ahduima.com/'
|
||||||
|
# VITE_APP_BASE_API = 'https://xj.ahduima.com/'
|
||||||
|
# VITE_APP_BASE_API = 'http://localhost:8889/'
|
||||||
|
#
|
||||||
|
VITE_WEB_BASE_URL = 'https://xj.ahduima.com'
|
||||||
|
# VITE_WEB_BASE_URL = 'https://xj.ahduima.com'
|
||||||
|
# VITE_APP_BASE_API = 'http://localhost:8889/'
|
||||||
|
# 资源地址
|
||||||
|
VITE_RESOURSE_URL = 'http://huodong.ahduima.com'
|
||||||
19
.env.production
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# 页面标题
|
||||||
|
VITE_APP_TITLE = 寻驾
|
||||||
|
# 租户id
|
||||||
|
VITE_APP_TENANT_ID = 10001
|
||||||
|
|
||||||
|
VITE_APP_PHONE = 18056811878
|
||||||
|
|
||||||
|
# 开发环境配置
|
||||||
|
VITE_APP_ENV = 'production'
|
||||||
|
|
||||||
|
#开发环境
|
||||||
|
# VITE_APP_BASE_API = 'https://xj.ahduima.com/'
|
||||||
|
VITE_APP_BASE_API = 'https://cloud.ahduima.com/'
|
||||||
|
|
||||||
|
#
|
||||||
|
VITE_WEB_BASE_URL = 'https://xj.ahduima.com'
|
||||||
|
|
||||||
|
# 资源地址
|
||||||
|
VITE_RESOURSE_URL = 'http://huodong.ahduima.com'
|
||||||
23
.gitignore
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
.DS_Store
|
||||||
|
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
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.local
|
||||||
|
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
20
index.html
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<script>
|
||||||
|
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
|
||||||
|
CSS.supports('top: constant(a)'))
|
||||||
|
document.write(
|
||||||
|
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
|
||||||
|
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
|
||||||
|
</script>
|
||||||
|
<title></title>
|
||||||
|
<!--preload-links-->
|
||||||
|
<!--app-context-->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"><!--app-html--></div>
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
47
package.json
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"name": "xj-manage-h5",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"dev:h5": "uni",
|
||||||
|
"dev": "uni -p mp-weixin",
|
||||||
|
"dev:dy": "uni -p mp-toutiao",
|
||||||
|
"build:h5": "uni build",
|
||||||
|
"build": "uni build -p mp-weixin",
|
||||||
|
"build:dy": "uni build -p mp-toutiao",
|
||||||
|
"build-test:mp-weixin": "uni --mode test -p mp-weixin"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@dcloudio/uni-app": "3.0.0-alpha-4080720251125001",
|
||||||
|
"@dcloudio/uni-app-harmony": "3.0.0-alpha-4080720251125001",
|
||||||
|
"@dcloudio/uni-app-plus": "3.0.0-alpha-4080720251125001",
|
||||||
|
"@dcloudio/uni-components": "3.0.0-alpha-4080720251125001",
|
||||||
|
"@dcloudio/uni-h5": "3.0.0-alpha-4080720251125001",
|
||||||
|
"@dcloudio/uni-mp-alipay": "3.0.0-alpha-4080720251125001",
|
||||||
|
"@dcloudio/uni-mp-baidu": "3.0.0-alpha-4080720251125001",
|
||||||
|
"@dcloudio/uni-mp-harmony": "3.0.0-alpha-4080720251125001",
|
||||||
|
"@dcloudio/uni-mp-jd": "3.0.0-alpha-4080720251125001",
|
||||||
|
"@dcloudio/uni-mp-kuaishou": "3.0.0-alpha-4080720251125001",
|
||||||
|
"@dcloudio/uni-mp-lark": "3.0.0-alpha-4080720251125001",
|
||||||
|
"@dcloudio/uni-mp-qq": "3.0.0-alpha-4080720251125001",
|
||||||
|
"@dcloudio/uni-mp-toutiao": "3.0.0-alpha-4080720251125001",
|
||||||
|
"@dcloudio/uni-mp-weixin": "3.0.0-alpha-4080720251125001",
|
||||||
|
"@dcloudio/uni-mp-xhs": "3.0.0-alpha-4080720251125001",
|
||||||
|
"@dcloudio/uni-quickapp-webview": "3.0.0-alpha-4080720251125001",
|
||||||
|
"pinia": "2.0.36",
|
||||||
|
"pinia-plugin-persist-uni": "^1.2.0",
|
||||||
|
"vue": "^3.4.21",
|
||||||
|
"vue-i18n": "^9.1.9"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@dcloudio/types": "^3.4.8",
|
||||||
|
"@dcloudio/uni-automator": "3.0.0-alpha-4080720251125001",
|
||||||
|
"@dcloudio/uni-cli-shared": "3.0.0-alpha-4080720251125001",
|
||||||
|
"@dcloudio/uni-stacktracey": "3.0.0-alpha-4080720251125001",
|
||||||
|
"@dcloudio/vite-plugin-uni": "3.0.0-alpha-4080720251125001",
|
||||||
|
"@vue/runtime-core": "^3.4.21",
|
||||||
|
"postcss": "^8.5.6",
|
||||||
|
"sass": "^1.63.6",
|
||||||
|
"sass-loader": "^13.3.2",
|
||||||
|
"vite": "5.2.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
28
project.config.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"appid": "wx26785eb35bd950b0",
|
||||||
|
"compileType": "miniprogram",
|
||||||
|
"libVersion": "3.3.3",
|
||||||
|
"packOptions": {
|
||||||
|
"ignore": [],
|
||||||
|
"include": []
|
||||||
|
},
|
||||||
|
"setting": {
|
||||||
|
"coverView": true,
|
||||||
|
"es6": true,
|
||||||
|
"postcss": true,
|
||||||
|
"minified": true,
|
||||||
|
"enhance": true,
|
||||||
|
"showShadowRootInWxmlPanel": true,
|
||||||
|
"packNpmRelationList": [],
|
||||||
|
"babelSetting": {
|
||||||
|
"ignore": [],
|
||||||
|
"disablePlugins": [],
|
||||||
|
"outputPath": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"condition": {},
|
||||||
|
"editorSetting": {
|
||||||
|
"tabIndent": "insertSpaces",
|
||||||
|
"tabSize": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
7
project.private.config.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
|
||||||
|
"projectname": "xunjia-applet",
|
||||||
|
"setting": {
|
||||||
|
"compileHotReLoad": true
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/App.vue
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<script setup>
|
||||||
|
import config from './config'
|
||||||
|
import { getToken } from '@/utils/auth'
|
||||||
|
import { useConfigStore } from '@/store'
|
||||||
|
import { getCurrentInstance } from "vue"
|
||||||
|
import { onLaunch } from '@dcloudio/uni-app'
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance()
|
||||||
|
|
||||||
|
onLaunch(() => {
|
||||||
|
initApp()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 初始化应用
|
||||||
|
function initApp() {
|
||||||
|
// 初始化应用配置
|
||||||
|
initConfig()
|
||||||
|
// 检查用户登录状态
|
||||||
|
//#ifdef H5
|
||||||
|
checkLogin()
|
||||||
|
//#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
function initConfig() {
|
||||||
|
useConfigStore().setConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkLogin() {
|
||||||
|
if (!getToken()) {
|
||||||
|
proxy.$tab.reLaunch('/pages/login')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '@/static/scss/index.scss';
|
||||||
|
</style>
|
||||||
59
src/api/login.js
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 登录方法
|
||||||
|
export function login(username, password, code, uuid) {
|
||||||
|
const data = {
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
code,
|
||||||
|
uuid
|
||||||
|
}
|
||||||
|
return request({
|
||||||
|
'url': '/login',
|
||||||
|
headers: {
|
||||||
|
isToken: false
|
||||||
|
},
|
||||||
|
'method': 'post',
|
||||||
|
'data': data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册方法
|
||||||
|
export function register(data) {
|
||||||
|
return request({
|
||||||
|
url: '/register',
|
||||||
|
headers: {
|
||||||
|
isToken: false
|
||||||
|
},
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户详细信息
|
||||||
|
export function getInfo() {
|
||||||
|
return request({
|
||||||
|
'url': '/getInfo',
|
||||||
|
'method': 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 退出方法
|
||||||
|
export function logout() {
|
||||||
|
return request({
|
||||||
|
'url': '/logout',
|
||||||
|
'method': 'post'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取验证码
|
||||||
|
export function getCodeImg() {
|
||||||
|
return request({
|
||||||
|
'url': '/captchaImage',
|
||||||
|
headers: {
|
||||||
|
isToken: false
|
||||||
|
},
|
||||||
|
method: 'get',
|
||||||
|
timeout: 20000
|
||||||
|
})
|
||||||
|
}
|
||||||
52
src/api/system/dict/data.js
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询字典数据列表
|
||||||
|
export function listData(query) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询字典数据详细
|
||||||
|
export function getData(dictCode) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data/' + dictCode,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据字典类型查询字典数据信息
|
||||||
|
export function getDicts(dictType) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data/type/' + dictType,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增字典数据
|
||||||
|
export function addData(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改字典数据
|
||||||
|
export function updateData(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除字典数据
|
||||||
|
export function delData(dictCode) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data/' + dictCode,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
60
src/api/system/dict/type.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询字典类型列表
|
||||||
|
export function listType(query) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询字典类型详细
|
||||||
|
export function getType(dictId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type/' + dictId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增字典类型
|
||||||
|
export function addType(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改字典类型
|
||||||
|
export function updateType(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除字典类型
|
||||||
|
export function delType(dictId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type/' + dictId,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刷新字典缓存
|
||||||
|
export function refreshCache() {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type/refreshCache',
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取字典选择框列表
|
||||||
|
export function optionselect() {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type/optionselect',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
41
src/api/system/user.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import upload from '@/utils/upload'
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 用户密码重置
|
||||||
|
export function updateUserPwd(oldPassword, newPassword) {
|
||||||
|
const data = {
|
||||||
|
oldPassword,
|
||||||
|
newPassword
|
||||||
|
}
|
||||||
|
return request({
|
||||||
|
url: '/system/user/profile/updatePwd',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询用户个人信息
|
||||||
|
export function getUserProfile() {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/profile',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改用户个人信息
|
||||||
|
export function updateUserProfile(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/profile',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户头像上传
|
||||||
|
export function uploadAvatar(data) {
|
||||||
|
return upload({
|
||||||
|
url: '/system/user/profile/avatar',
|
||||||
|
name: data.name,
|
||||||
|
filePath: data.filePath
|
||||||
|
})
|
||||||
|
}
|
||||||
167
src/components/uni-section/uni-section.vue
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
<template>
|
||||||
|
<view class="uni-section">
|
||||||
|
<view class="uni-section-header" @click="onClick">
|
||||||
|
<view class="uni-section-header__decoration" v-if="type" :class="type" />
|
||||||
|
<slot v-else name="decoration"></slot>
|
||||||
|
|
||||||
|
<view class="uni-section-header__content">
|
||||||
|
<text :style="{'font-size':titleFontSize,'color':titleColor}" class="uni-section__content-title" :class="{'distraction':!subTitle}">{{ title }}</text>
|
||||||
|
<text v-if="subTitle" :style="{'font-size':subTitleFontSize,'color':subTitleColor}" class="uni-section-header__content-sub">{{ subTitle }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="uni-section-header__slot-right">
|
||||||
|
<slot name="right"></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="uni-section-content" :style="{padding: _padding}">
|
||||||
|
<slot />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Section 标题栏
|
||||||
|
* @description 标题栏
|
||||||
|
* @property {String} type = [line|circle|square] 标题装饰类型
|
||||||
|
* @value line 竖线
|
||||||
|
* @value circle 圆形
|
||||||
|
* @value square 正方形
|
||||||
|
* @property {String} title 主标题
|
||||||
|
* @property {String} titleFontSize 主标题字体大小
|
||||||
|
* @property {String} titleColor 主标题字体颜色
|
||||||
|
* @property {String} subTitle 副标题
|
||||||
|
* @property {String} subTitleFontSize 副标题字体大小
|
||||||
|
* @property {String} subTitleColor 副标题字体颜色
|
||||||
|
* @property {String} padding 默认插槽 padding
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'UniSection',
|
||||||
|
emits:['click'],
|
||||||
|
props: {
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
titleFontSize: {
|
||||||
|
type: String,
|
||||||
|
default: '14px'
|
||||||
|
},
|
||||||
|
titleColor:{
|
||||||
|
type: String,
|
||||||
|
default: '#333'
|
||||||
|
},
|
||||||
|
subTitle: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
subTitleFontSize: {
|
||||||
|
type: String,
|
||||||
|
default: '12px'
|
||||||
|
},
|
||||||
|
subTitleColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#999'
|
||||||
|
},
|
||||||
|
padding: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed:{
|
||||||
|
_padding(){
|
||||||
|
if(typeof this.padding === 'string'){
|
||||||
|
return this.padding
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.padding?'10px':''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
title(newVal) {
|
||||||
|
if (uni.report && newVal !== '') {
|
||||||
|
uni.report('title', newVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onClick() {
|
||||||
|
this.$emit('click')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" >
|
||||||
|
$uni-primary: #2979ff !default;
|
||||||
|
|
||||||
|
.uni-section {
|
||||||
|
background-color: #fff;
|
||||||
|
.uni-section-header {
|
||||||
|
position: relative;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 10px;
|
||||||
|
font-weight: normal;
|
||||||
|
|
||||||
|
&__decoration{
|
||||||
|
margin-right: 6px;
|
||||||
|
background-color: $uni-primary;
|
||||||
|
&.line {
|
||||||
|
width: 4px;
|
||||||
|
height: 12px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.circle {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-top-right-radius: 50px;
|
||||||
|
border-top-left-radius: 50px;
|
||||||
|
border-bottom-left-radius: 50px;
|
||||||
|
border-bottom-right-radius: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.square {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
color: #333;
|
||||||
|
|
||||||
|
.distraction {
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
&-sub {
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__slot-right{
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-section-content{
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
26
src/config.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// 应用全局配置
|
||||||
|
export default {
|
||||||
|
baseUrl: 'https://vue.ruoyi.vip/prod-api',
|
||||||
|
// baseUrl: 'http://localhost:8080',
|
||||||
|
// 应用信息
|
||||||
|
appInfo: {
|
||||||
|
// 应用名称
|
||||||
|
name: '小程序管理后台',
|
||||||
|
// 应用版本
|
||||||
|
version: '1.2.0',
|
||||||
|
// 应用logo
|
||||||
|
logo: '/static/logo.png',
|
||||||
|
// 官方网站
|
||||||
|
// 政策协议
|
||||||
|
agreements: [
|
||||||
|
{
|
||||||
|
title: '隐私政策',
|
||||||
|
url: 'https://ruoyi.vip/protocol.html'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '用户服务协议',
|
||||||
|
url: 'https://ruoyi.vip/protocol.html'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
14
src/main.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { createSSRApp } from 'vue';
|
||||||
|
import App from './App';
|
||||||
|
import store from './store'; // store
|
||||||
|
import { install } from './plugins'; // plugins
|
||||||
|
import './permission'; // permission
|
||||||
|
|
||||||
|
export function createApp() {
|
||||||
|
const app = createSSRApp(App);
|
||||||
|
app.use(store);
|
||||||
|
install(app);
|
||||||
|
return {
|
||||||
|
app
|
||||||
|
};
|
||||||
|
}
|
||||||
96
src/manifest.json
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
{
|
||||||
|
"name": "小程序管理后台",
|
||||||
|
"appid": "__UNI__59447F7",
|
||||||
|
"description": "",
|
||||||
|
"versionName": "1.0.1",
|
||||||
|
"versionCode": "101",
|
||||||
|
"transformPx": false,
|
||||||
|
"app-plus": {
|
||||||
|
"usingComponents": true,
|
||||||
|
"nvueStyleCompiler": "uni-app",
|
||||||
|
"compilerVersion": 3,
|
||||||
|
"splashscreen": {
|
||||||
|
"alwaysShowBeforeRender": true,
|
||||||
|
"waiting": true,
|
||||||
|
"autoclose": true,
|
||||||
|
"delay": 0
|
||||||
|
},
|
||||||
|
"modules": {},
|
||||||
|
"distribute": {
|
||||||
|
"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": {},
|
||||||
|
"sdkConfigs": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"quickapp": {},
|
||||||
|
"mp-weixin": {
|
||||||
|
"appid": "wx26785eb35bd950b0",
|
||||||
|
"setting": {
|
||||||
|
"urlCheck": true,
|
||||||
|
"minified": true,
|
||||||
|
"es6": true,
|
||||||
|
"postcss": true
|
||||||
|
},
|
||||||
|
"usingComponents": true,
|
||||||
|
"permission": {
|
||||||
|
"scope.userLocation": {
|
||||||
|
"desc": "根据城市获取不同题库"
|
||||||
|
},
|
||||||
|
"scope.userInfo": {
|
||||||
|
"desc": "用于用户登录和身份验证"
|
||||||
|
},
|
||||||
|
"scope.phoneNumber": {
|
||||||
|
"desc": "用于用户登录和身份验证"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"privacy": {
|
||||||
|
"requiredPrivateInfos": ["getPhoneNumber"],
|
||||||
|
"usePrivacyCheck": true
|
||||||
|
},
|
||||||
|
"plugins": {
|
||||||
|
"WechatSI": {
|
||||||
|
"version": "0.3.6",
|
||||||
|
"provider": "wx069ba97219f66d99"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mp-alipay": {
|
||||||
|
"usingComponents": true
|
||||||
|
},
|
||||||
|
"mp-baidu": {
|
||||||
|
"usingComponents": true
|
||||||
|
},
|
||||||
|
"mp-toutiao": {
|
||||||
|
"usingComponents": true,
|
||||||
|
"appid": "ttbbd1cd6c24e1c00801",
|
||||||
|
"setting": {
|
||||||
|
"es6": true,
|
||||||
|
"postcss": true,
|
||||||
|
"minified": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniStatistics": {
|
||||||
|
"enable": false
|
||||||
|
},
|
||||||
|
"vueVersion": "3",
|
||||||
|
"fallbackLocale": "zh-Hans",
|
||||||
|
"locale": "zh-Hans"
|
||||||
|
}
|
||||||
18
src/package.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"id": "yan-qr",
|
||||||
|
"name": "动态生成二维码",
|
||||||
|
"displayName": "动态生成二维码",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "动态生成二维码",
|
||||||
|
"keywords": [
|
||||||
|
"二维码",
|
||||||
|
"生成二维码",
|
||||||
|
"动态二维码"
|
||||||
|
],
|
||||||
|
"dcloudext": {
|
||||||
|
"category": [
|
||||||
|
"前端组件",
|
||||||
|
"通用组件"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
119
src/pages.json
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
{
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "pages/login",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "登录"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/register",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "注册"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "小程序管理后台"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/work/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "工作台"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/mine/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "我的"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/mine/avatar/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "修改头像"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/mine/info/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "个人信息"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/mine/info/edit",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "编辑资料"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/mine/pwd/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "修改密码"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/mine/setting/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "应用设置"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/mine/help/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "常见问题"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/mine/about/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "关于我们"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/common/webview/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "浏览网页"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/common/textview/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "浏览文本"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tabBar": {
|
||||||
|
"color": "#000000",
|
||||||
|
"selectedColor": "#000000",
|
||||||
|
"borderStyle": "white",
|
||||||
|
"backgroundColor": "#ffffff",
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"pagePath": "pages/index",
|
||||||
|
"iconPath": "static/images/tabbar/home.png",
|
||||||
|
"selectedIconPath": "static/images/tabbar/home_.png",
|
||||||
|
"text": "首页"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pagePath": "pages/work/index",
|
||||||
|
"iconPath": "static/images/tabbar/work.png",
|
||||||
|
"selectedIconPath": "static/images/tabbar/work_.png",
|
||||||
|
"text": "工作台"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pagePath": "pages/mine/index",
|
||||||
|
"iconPath": "static/images/tabbar/mine.png",
|
||||||
|
"selectedIconPath": "static/images/tabbar/mine_.png",
|
||||||
|
"text": "我的"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"globalStyle": {
|
||||||
|
"navigationBarTextStyle": "black",
|
||||||
|
"navigationBarTitleText": "小程序管理后台",
|
||||||
|
"navigationBarBackgroundColor": "#FFFFFF"
|
||||||
|
}
|
||||||
|
}
|
||||||
43
src/pages/common/textview/index.vue
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<uni-card class="view-title" :title="title">
|
||||||
|
<text class="uni-body view-content">{{ content }}</text>
|
||||||
|
</uni-card>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
title: '',
|
||||||
|
content: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad(options) {
|
||||||
|
this.title = options.title
|
||||||
|
this.content = options.content
|
||||||
|
uni.setNavigationBarTitle({
|
||||||
|
title: options.title
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
page {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-title {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-content {
|
||||||
|
font-size: 26rpx;
|
||||||
|
padding: 12px 5px 0;
|
||||||
|
color: #333;
|
||||||
|
line-height: 24px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
34
src/pages/common/webview/index.vue
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<template>
|
||||||
|
<view v-if="params.url">
|
||||||
|
<web-view :webview-styles="webviewStyles" :src="`${params.url}`"></web-view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
params: {},
|
||||||
|
webviewStyles: {
|
||||||
|
progress: {
|
||||||
|
color: "#FF3333"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
src: {
|
||||||
|
type: [String],
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad(event) {
|
||||||
|
this.params = event
|
||||||
|
if (event.title) {
|
||||||
|
uni.setNavigationBarTitle({
|
||||||
|
title: event.title
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
36
src/pages/index.vue
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<template>
|
||||||
|
<view class="content">
|
||||||
|
<image class="logo" src="@/static/logo.png"></image>
|
||||||
|
<view class="text-area">
|
||||||
|
<text class="title">Hello RuoYi</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.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>
|
||||||
213
src/pages/login.vue
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
<template>
|
||||||
|
<view class="normal-login-container">
|
||||||
|
<view class="logo-content align-center justify-center flex">
|
||||||
|
<image style="width: 100rpx;height: 100rpx;" :src="globalConfig.appInfo.logo" mode="widthFix">
|
||||||
|
</image>
|
||||||
|
<text class="title">若依移动端登录</text>
|
||||||
|
</view>
|
||||||
|
<view class="login-form-content">
|
||||||
|
<view class="input-item flex align-center">
|
||||||
|
<view class="iconfont icon-user icon"></view>
|
||||||
|
<input v-model="loginForm.username" class="input" type="text" placeholder="请输入账号" maxlength="30" />
|
||||||
|
</view>
|
||||||
|
<view class="input-item flex align-center">
|
||||||
|
<view class="iconfont icon-password icon"></view>
|
||||||
|
<input v-model="loginForm.password" type="password" class="input" placeholder="请输入密码" maxlength="20" />
|
||||||
|
</view>
|
||||||
|
<view class="input-item flex align-center" style="width: 60%;margin: 0px;" v-if="captchaEnabled">
|
||||||
|
<view class="iconfont icon-code icon"></view>
|
||||||
|
<input v-model="loginForm.code" type="number" class="input" placeholder="请输入验证码" maxlength="4" />
|
||||||
|
<view class="login-code">
|
||||||
|
<image :src="codeUrl" @click="getCode" class="login-code-img"></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="action-btn">
|
||||||
|
<button @click="handleLogin" class="login-btn cu-btn block bg-blue lg round">登录</button>
|
||||||
|
</view>
|
||||||
|
<view class="reg text-center" v-if="register">
|
||||||
|
<text class="text-grey1">没有账号?</text>
|
||||||
|
<text @click="handleUserRegister" class="text-blue">立即注册</text>
|
||||||
|
</view>
|
||||||
|
<view class="xieyi text-center">
|
||||||
|
<text class="text-grey1">登录即代表同意</text>
|
||||||
|
<text @click="handleUserAgrement" class="text-blue">《用户协议》</text>
|
||||||
|
<text @click="handlePrivacy" class="text-blue">《隐私协议》</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, getCurrentInstance } from "vue"
|
||||||
|
import { onLoad } from "@dcloudio/uni-app"
|
||||||
|
import { getToken } from '@/utils/auth'
|
||||||
|
import { getCodeImg } from '@/api/login'
|
||||||
|
import { useConfigStore, useUserStore } from '@/store'
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance()
|
||||||
|
const globalConfig = useConfigStore().config
|
||||||
|
const codeUrl = ref("")
|
||||||
|
// 验证码开关
|
||||||
|
const captchaEnabled = ref(true)
|
||||||
|
// 用户注册开关
|
||||||
|
const register = ref(false)
|
||||||
|
const loginForm = ref({
|
||||||
|
username: "admin",
|
||||||
|
password: "admin123",
|
||||||
|
code: "",
|
||||||
|
uuid: ""
|
||||||
|
})
|
||||||
|
|
||||||
|
// 用户注册
|
||||||
|
function handleUserRegister() {
|
||||||
|
proxy.$tab.redirectTo(`/pages/register`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 隐私协议
|
||||||
|
function handlePrivacy() {
|
||||||
|
let site = globalConfig.appInfo.agreements[0]
|
||||||
|
proxy.$tab.navigateTo(`/pages/common/webview/index?title=${site.title}&url=${site.url}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户协议
|
||||||
|
function handleUserAgrement() {
|
||||||
|
let site = globalConfig.appInfo.agreements[1]
|
||||||
|
proxy.$tab.navigateTo(`/pages/common/webview/index?title=${site.title}&url=${site.url}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取图形验证码
|
||||||
|
function getCode() {
|
||||||
|
getCodeImg().then(res => {
|
||||||
|
captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled
|
||||||
|
if (captchaEnabled.value) {
|
||||||
|
codeUrl.value = 'data:image/gif;base64,' + res.img
|
||||||
|
loginForm.value.uuid = res.uuid
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 登录方法
|
||||||
|
async function handleLogin() {
|
||||||
|
if (loginForm.value.username === "") {
|
||||||
|
proxy.$modal.msgError("请输入账号")
|
||||||
|
} else if (loginForm.value.password === "") {
|
||||||
|
proxy.$modal.msgError("请输入密码")
|
||||||
|
} else if (loginForm.value.code === "" && captchaEnabled.value) {
|
||||||
|
proxy.$modal.msgError("请输入验证码")
|
||||||
|
} else {
|
||||||
|
proxy.$modal.loading("登录中,请耐心等待...")
|
||||||
|
pwdLogin()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 密码登录
|
||||||
|
async function pwdLogin() {
|
||||||
|
useUserStore().login(loginForm.value).then(() => {
|
||||||
|
proxy.$modal.closeLoading()
|
||||||
|
loginSuccess()
|
||||||
|
}).catch(() => {
|
||||||
|
if (captchaEnabled.value) {
|
||||||
|
getCode()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 登录成功后,处理函数
|
||||||
|
function loginSuccess(result) {
|
||||||
|
// 设置用户信息
|
||||||
|
useUserStore().getInfo().then(res => {
|
||||||
|
proxy.$tab.reLaunch('/pages/index')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoad(() => {
|
||||||
|
//#ifdef H5
|
||||||
|
if (getToken()) {
|
||||||
|
proxy.$tab.switchTab('/pages/index')
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
|
})
|
||||||
|
|
||||||
|
getCode()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
page {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.normal-login-container {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.logo-content {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 21px;
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 15%;
|
||||||
|
|
||||||
|
image {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form-content {
|
||||||
|
text-align: center;
|
||||||
|
margin: 20px auto;
|
||||||
|
margin-top: 15%;
|
||||||
|
width: 80%;
|
||||||
|
|
||||||
|
.input-item {
|
||||||
|
margin: 20px auto;
|
||||||
|
background-color: #f5f6f7;
|
||||||
|
height: 45px;
|
||||||
|
border-radius: 20px;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 38rpx;
|
||||||
|
margin-left: 10px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 20px;
|
||||||
|
text-align: left;
|
||||||
|
padding-left: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn {
|
||||||
|
margin-top: 40px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reg {
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xieyi {
|
||||||
|
color: #333;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-code {
|
||||||
|
height: 38px;
|
||||||
|
float: right;
|
||||||
|
|
||||||
|
.login-code-img {
|
||||||
|
height: 38px;
|
||||||
|
position: absolute;
|
||||||
|
margin-left: 10px;
|
||||||
|
width: 200rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
71
src/pages/mine/about/index.vue
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<template>
|
||||||
|
<view class="about-container">
|
||||||
|
<view class="header-section text-center">
|
||||||
|
<image style="width: 150rpx;height: 150rpx;" src="/static/logo200.png" mode="widthFix">
|
||||||
|
</image>
|
||||||
|
<uni-title type="h2" title="若依移动端"></uni-title>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="content-section">
|
||||||
|
<view class="menu-list">
|
||||||
|
<view class="list-cell list-cell-arrow">
|
||||||
|
<view class="menu-item-box">
|
||||||
|
<view>版本信息</view>
|
||||||
|
<view class="text-right">v{{version}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="list-cell list-cell-arrow">
|
||||||
|
<view class="menu-item-box">
|
||||||
|
<view>官方邮箱</view>
|
||||||
|
<view class="text-right">ruoyi@xx.com</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="list-cell list-cell-arrow">
|
||||||
|
<view class="menu-item-box">
|
||||||
|
<view>服务热线</view>
|
||||||
|
<view class="text-right">400-999-9999</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="list-cell list-cell-arrow">
|
||||||
|
<view class="menu-item-box">
|
||||||
|
<view>公司网站</view>
|
||||||
|
<view class="text-right">
|
||||||
|
<uni-link :href="url" :text="url" showUnderLine="false"></uni-link>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="copyright">
|
||||||
|
<view>Copyright © 2025 ruoyi.vip All Rights Reserved.</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { useConfigStore } from '@/store'
|
||||||
|
|
||||||
|
const url = useConfigStore().config.appInfo.site_url
|
||||||
|
const version = useConfigStore().config.appInfo.version
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
page {
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copyright {
|
||||||
|
margin-top: 50rpx;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 60rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-section {
|
||||||
|
display: flex;
|
||||||
|
padding: 30rpx 0 0;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
618
src/pages/mine/avatar/index.vue
Normal file
@@ -0,0 +1,618 @@
|
|||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<view class="page-body uni-content-info">
|
||||||
|
<view class='cropper-content'>
|
||||||
|
<view v-if="isShowImg" class="uni-corpper" :style="'width:'+cropperInitW+'px;height:'+cropperInitH+'px;background:#000'">
|
||||||
|
<view class="uni-corpper-content" :style="'width:'+cropperW+'px;height:'+cropperH+'px;left:'+cropperL+'px;top:'+cropperT+'px'">
|
||||||
|
<image :src="imageSrc" :style="'width:'+cropperW+'px;height:'+cropperH+'px'"></image>
|
||||||
|
<view class="uni-corpper-crop-box" @touchstart.stop="contentStartMove" @touchmove.stop="contentMoveing" @touchend.stop="contentTouchEnd"
|
||||||
|
:style="'left:'+cutL+'px;top:'+cutT+'px;right:'+cutR+'px;bottom:'+cutB+'px'">
|
||||||
|
<view class="uni-cropper-view-box">
|
||||||
|
<view class="uni-cropper-dashed-h"></view>
|
||||||
|
<view class="uni-cropper-dashed-v"></view>
|
||||||
|
<view class="uni-cropper-line-t" data-drag="top" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
|
||||||
|
<view class="uni-cropper-line-r" data-drag="right" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
|
||||||
|
<view class="uni-cropper-line-b" data-drag="bottom" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
|
||||||
|
<view class="uni-cropper-line-l" data-drag="left" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
|
||||||
|
<view class="uni-cropper-point point-t" data-drag="top" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
|
||||||
|
<view class="uni-cropper-point point-tr" data-drag="topTight"></view>
|
||||||
|
<view class="uni-cropper-point point-r" data-drag="right" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
|
||||||
|
<view class="uni-cropper-point point-rb" data-drag="rightBottom" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
|
||||||
|
<view class="uni-cropper-point point-b" data-drag="bottom" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
|
||||||
|
<view class="uni-cropper-point point-bl" data-drag="bottomLeft"></view>
|
||||||
|
<view class="uni-cropper-point point-l" data-drag="left" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
|
||||||
|
<view class="uni-cropper-point point-lt" data-drag="leftTop"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class='cropper-config'>
|
||||||
|
<button type="primary reverse" @click="getImage" style='margin-top: 30rpx;'> 选择头像 </button>
|
||||||
|
<button type="warn" @click="getImageInfo" style='margin-top: 30rpx;'> 提交 </button>
|
||||||
|
</view>
|
||||||
|
<canvas canvas-id="myCanvas" :style="'position:absolute;border: 1px solid red; width:'+imageW+'px;height:'+imageH+'px;top:-9999px;left:-9999px;'"></canvas>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import config from '@/config'
|
||||||
|
import { useUserStore } from '@/store'
|
||||||
|
import { uploadAvatar } from "@/api/system/user"
|
||||||
|
|
||||||
|
const baseUrl = config.baseUrl
|
||||||
|
let sysInfo = uni.getSystemInfoSync()
|
||||||
|
let SCREEN_WIDTH = sysInfo.screenWidth
|
||||||
|
let PAGE_X, // 手按下的x位置
|
||||||
|
PAGE_Y, // 手按下y的位置
|
||||||
|
PR = sysInfo.pixelRatio, // dpi
|
||||||
|
T_PAGE_X, // 手移动的时候x的位置
|
||||||
|
T_PAGE_Y, // 手移动的时候Y的位置
|
||||||
|
CUT_L, // 初始化拖拽元素的left值
|
||||||
|
CUT_T, // 初始化拖拽元素的top值
|
||||||
|
CUT_R, // 初始化拖拽元素的
|
||||||
|
CUT_B, // 初始化拖拽元素的
|
||||||
|
CUT_W, // 初始化拖拽元素的宽度
|
||||||
|
CUT_H, // 初始化拖拽元素的高度
|
||||||
|
IMG_RATIO, // 图片比例
|
||||||
|
IMG_REAL_W, // 图片实际的宽度
|
||||||
|
IMG_REAL_H, // 图片实际的高度
|
||||||
|
DRAFG_MOVE_RATIO = 1, //移动时候的比例,
|
||||||
|
INIT_DRAG_POSITION = 100, // 初始化屏幕宽度和裁剪区域的宽度之差,用于设置初始化裁剪的宽度
|
||||||
|
DRAW_IMAGE_W = sysInfo.screenWidth // 设置生成的图片宽度
|
||||||
|
|
||||||
|
export default {
|
||||||
|
/**
|
||||||
|
* 页面的初始数据
|
||||||
|
*/
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
imageSrc: useUserStore().avatar,
|
||||||
|
isShowImg: false,
|
||||||
|
// 初始化的宽高
|
||||||
|
cropperInitW: SCREEN_WIDTH,
|
||||||
|
cropperInitH: SCREEN_WIDTH,
|
||||||
|
// 动态的宽高
|
||||||
|
cropperW: SCREEN_WIDTH,
|
||||||
|
cropperH: SCREEN_WIDTH,
|
||||||
|
// 动态的left top值
|
||||||
|
cropperL: 0,
|
||||||
|
cropperT: 0,
|
||||||
|
|
||||||
|
transL: 0,
|
||||||
|
transT: 0,
|
||||||
|
|
||||||
|
// 图片缩放值
|
||||||
|
scaleP: 0,
|
||||||
|
imageW: 0,
|
||||||
|
imageH: 0,
|
||||||
|
|
||||||
|
// 裁剪框 宽高
|
||||||
|
cutL: 0,
|
||||||
|
cutT: 0,
|
||||||
|
cutB: SCREEN_WIDTH,
|
||||||
|
cutR: '100%',
|
||||||
|
qualityWidth: DRAW_IMAGE_W,
|
||||||
|
innerAspectRadio: DRAFG_MOVE_RATIO
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 生命周期函数--监听页面初次渲染完成
|
||||||
|
*/
|
||||||
|
onReady: function () {
|
||||||
|
this.loadImage()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setData: function (obj) {
|
||||||
|
let that = this
|
||||||
|
Object.keys(obj).forEach(function (key) {
|
||||||
|
that.$set(that.$data, key, obj[key])
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getImage: function () {
|
||||||
|
var _this = this
|
||||||
|
uni.chooseImage({
|
||||||
|
success: function (res) {
|
||||||
|
_this.setData({
|
||||||
|
imageSrc: res.tempFilePaths[0],
|
||||||
|
})
|
||||||
|
_this.loadImage()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
loadImage: function () {
|
||||||
|
var _this = this
|
||||||
|
|
||||||
|
uni.getImageInfo({
|
||||||
|
src: _this.imageSrc,
|
||||||
|
success: function success(res) {
|
||||||
|
IMG_RATIO = 1 / 1
|
||||||
|
if (IMG_RATIO >= 1) {
|
||||||
|
IMG_REAL_W = SCREEN_WIDTH
|
||||||
|
IMG_REAL_H = SCREEN_WIDTH / IMG_RATIO
|
||||||
|
} else {
|
||||||
|
IMG_REAL_W = SCREEN_WIDTH * IMG_RATIO
|
||||||
|
IMG_REAL_H = SCREEN_WIDTH
|
||||||
|
}
|
||||||
|
let minRange = IMG_REAL_W > IMG_REAL_H ? IMG_REAL_W : IMG_REAL_H
|
||||||
|
INIT_DRAG_POSITION = minRange > INIT_DRAG_POSITION ? INIT_DRAG_POSITION : minRange
|
||||||
|
// 根据图片的宽高显示不同的效果 保证图片可以正常显示
|
||||||
|
if (IMG_RATIO >= 1) {
|
||||||
|
let cutT = Math.ceil((SCREEN_WIDTH / IMG_RATIO - (SCREEN_WIDTH / IMG_RATIO - INIT_DRAG_POSITION)) / 2)
|
||||||
|
let cutB = cutT
|
||||||
|
let cutL = Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH + INIT_DRAG_POSITION) / 2)
|
||||||
|
let cutR = cutL
|
||||||
|
_this.setData({
|
||||||
|
cropperW: SCREEN_WIDTH,
|
||||||
|
cropperH: SCREEN_WIDTH / IMG_RATIO,
|
||||||
|
// 初始化left right
|
||||||
|
cropperL: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH) / 2),
|
||||||
|
cropperT: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH / IMG_RATIO) / 2),
|
||||||
|
cutL: cutL,
|
||||||
|
cutT: cutT,
|
||||||
|
cutR: cutR,
|
||||||
|
cutB: cutB,
|
||||||
|
// 图片缩放值
|
||||||
|
imageW: IMG_REAL_W,
|
||||||
|
imageH: IMG_REAL_H,
|
||||||
|
scaleP: IMG_REAL_W / SCREEN_WIDTH,
|
||||||
|
qualityWidth: DRAW_IMAGE_W,
|
||||||
|
innerAspectRadio: IMG_RATIO
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let cutL = Math.ceil((SCREEN_WIDTH * IMG_RATIO - (SCREEN_WIDTH * IMG_RATIO)) / 2)
|
||||||
|
let cutR = cutL
|
||||||
|
let cutT = Math.ceil((SCREEN_WIDTH - INIT_DRAG_POSITION) / 2)
|
||||||
|
let cutB = cutT
|
||||||
|
_this.setData({
|
||||||
|
cropperW: SCREEN_WIDTH * IMG_RATIO,
|
||||||
|
cropperH: SCREEN_WIDTH,
|
||||||
|
// 初始化left right
|
||||||
|
cropperL: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH * IMG_RATIO) / 2),
|
||||||
|
cropperT: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH) / 2),
|
||||||
|
|
||||||
|
cutL: cutL,
|
||||||
|
cutT: cutT,
|
||||||
|
cutR: cutR,
|
||||||
|
cutB: cutB,
|
||||||
|
// 图片缩放值
|
||||||
|
imageW: IMG_REAL_W,
|
||||||
|
imageH: IMG_REAL_H,
|
||||||
|
scaleP: IMG_REAL_W / SCREEN_WIDTH,
|
||||||
|
qualityWidth: DRAW_IMAGE_W,
|
||||||
|
innerAspectRadio: IMG_RATIO
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_this.setData({
|
||||||
|
isShowImg: true
|
||||||
|
})
|
||||||
|
uni.hideLoading()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 拖动时候触发的touchStart事件
|
||||||
|
contentStartMove(e) {
|
||||||
|
PAGE_X = e.touches[0].pageX
|
||||||
|
PAGE_Y = e.touches[0].pageY
|
||||||
|
},
|
||||||
|
|
||||||
|
// 拖动时候触发的touchMove事件
|
||||||
|
contentMoveing(e) {
|
||||||
|
var _this = this
|
||||||
|
var dragLengthX = (PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
|
||||||
|
var dragLengthY = (PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
|
||||||
|
// 左移
|
||||||
|
if (dragLengthX > 0) {
|
||||||
|
if (this.cutL - dragLengthX < 0) dragLengthX = this.cutL
|
||||||
|
} else {
|
||||||
|
if (this.cutR + dragLengthX < 0) dragLengthX = -this.cutR
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dragLengthY > 0) {
|
||||||
|
if (this.cutT - dragLengthY < 0) dragLengthY = this.cutT
|
||||||
|
} else {
|
||||||
|
if (this.cutB + dragLengthY < 0) dragLengthY = -this.cutB
|
||||||
|
}
|
||||||
|
this.setData({
|
||||||
|
cutL: this.cutL - dragLengthX,
|
||||||
|
cutT: this.cutT - dragLengthY,
|
||||||
|
cutR: this.cutR + dragLengthX,
|
||||||
|
cutB: this.cutB + dragLengthY
|
||||||
|
})
|
||||||
|
|
||||||
|
PAGE_X = e.touches[0].pageX
|
||||||
|
PAGE_Y = e.touches[0].pageY
|
||||||
|
},
|
||||||
|
|
||||||
|
contentTouchEnd() {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取图片
|
||||||
|
getImageInfo() {
|
||||||
|
var _this = this
|
||||||
|
uni.showLoading({
|
||||||
|
title: '图片生成中...',
|
||||||
|
})
|
||||||
|
// 将图片写入画布
|
||||||
|
const ctx = uni.createCanvasContext('myCanvas')
|
||||||
|
ctx.drawImage(_this.imageSrc, 0, 0, IMG_REAL_W, IMG_REAL_H)
|
||||||
|
ctx.draw(true, () => {
|
||||||
|
// 获取画布要裁剪的位置和宽度 均为百分比 * 画布中图片的宽度 保证了在微信小程序中裁剪的图片模糊 位置不对的问题 canvasT = (_this.cutT / _this.cropperH) * (_this.imageH / pixelRatio)
|
||||||
|
var canvasW = ((_this.cropperW - _this.cutL - _this.cutR) / _this.cropperW) * IMG_REAL_W
|
||||||
|
var canvasH = ((_this.cropperH - _this.cutT - _this.cutB) / _this.cropperH) * IMG_REAL_H
|
||||||
|
var canvasL = (_this.cutL / _this.cropperW) * IMG_REAL_W
|
||||||
|
var canvasT = (_this.cutT / _this.cropperH) * IMG_REAL_H
|
||||||
|
uni.canvasToTempFilePath({
|
||||||
|
x: canvasL,
|
||||||
|
y: canvasT,
|
||||||
|
width: canvasW,
|
||||||
|
height: canvasH,
|
||||||
|
destWidth: canvasW,
|
||||||
|
destHeight: canvasH,
|
||||||
|
quality: 0.5,
|
||||||
|
canvasId: 'myCanvas',
|
||||||
|
success: function (res) {
|
||||||
|
uni.hideLoading()
|
||||||
|
let data = {name: 'avatarfile', filePath: res.tempFilePath}
|
||||||
|
uploadAvatar(data).then(response => {
|
||||||
|
useUserStore().SET_AVATAR(baseUrl + response.imgUrl)
|
||||||
|
uni.showToast({ title: "修改成功", icon: 'success' })
|
||||||
|
uni.navigateBack()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 设置大小的时候触发的touchStart事件
|
||||||
|
dragStart(e) {
|
||||||
|
T_PAGE_X = e.touches[0].pageX
|
||||||
|
T_PAGE_Y = e.touches[0].pageY
|
||||||
|
CUT_L = this.cutL
|
||||||
|
CUT_R = this.cutR
|
||||||
|
CUT_B = this.cutB
|
||||||
|
CUT_T = this.cutT
|
||||||
|
},
|
||||||
|
|
||||||
|
// 设置大小的时候触发的touchMove事件
|
||||||
|
dragMove(e) {
|
||||||
|
var _this = this
|
||||||
|
var dragType = e.target.dataset.drag
|
||||||
|
switch (dragType) {
|
||||||
|
case 'right':
|
||||||
|
var dragLength = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
|
||||||
|
if (CUT_R + dragLength < 0) dragLength = -CUT_R
|
||||||
|
this.setData({
|
||||||
|
cutR: CUT_R + dragLength
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case 'left':
|
||||||
|
var dragLength = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
|
||||||
|
if (CUT_L - dragLength < 0) dragLength = CUT_L
|
||||||
|
if ((CUT_L - dragLength) > (this.cropperW - this.cutR)) dragLength = CUT_L - (this.cropperW - this.cutR)
|
||||||
|
this.setData({
|
||||||
|
cutL: CUT_L - dragLength
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case 'top':
|
||||||
|
var dragLength = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
|
||||||
|
if (CUT_T - dragLength < 0) dragLength = CUT_T
|
||||||
|
if ((CUT_T - dragLength) > (this.cropperH - this.cutB)) dragLength = CUT_T - (this.cropperH - this.cutB)
|
||||||
|
this.setData({
|
||||||
|
cutT: CUT_T - dragLength
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case 'bottom':
|
||||||
|
var dragLength = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
|
||||||
|
if (CUT_B + dragLength < 0) dragLength = -CUT_B
|
||||||
|
this.setData({
|
||||||
|
cutB: CUT_B + dragLength
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case 'rightBottom':
|
||||||
|
var dragLengthX = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
|
||||||
|
var dragLengthY = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
|
||||||
|
|
||||||
|
if (CUT_B + dragLengthY < 0) dragLengthY = -CUT_B
|
||||||
|
if (CUT_R + dragLengthX < 0) dragLengthX = -CUT_R
|
||||||
|
let cutB = CUT_B + dragLengthY
|
||||||
|
let cutR = CUT_R + dragLengthX
|
||||||
|
|
||||||
|
this.setData({
|
||||||
|
cutB: cutB,
|
||||||
|
cutR: cutR
|
||||||
|
})
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.cropper-config {
|
||||||
|
padding: 20rpx 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cropper-content {
|
||||||
|
min-height: 750rpx;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-corpper {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-corpper-content {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-corpper-content image {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0 !important;
|
||||||
|
max-width: none !important;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 0 !important;
|
||||||
|
max-height: none !important;
|
||||||
|
image-orientation: 0deg !important;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 移动图片效果 */
|
||||||
|
.uni-cropper-drag-box {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
cursor: move;
|
||||||
|
background: rgba(0, 0, 0, 0.6);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内部的信息 */
|
||||||
|
.uni-corpper-crop-box {
|
||||||
|
position: absolute;
|
||||||
|
background: rgba(255, 255, 255, 0.3);
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-corpper-crop-box .uni-cropper-view-box {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: visible;
|
||||||
|
outline: 1rpx solid #69f;
|
||||||
|
outline-color: rgba(102, 153, 255, .75)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 横向虚线 */
|
||||||
|
.uni-cropper-dashed-h {
|
||||||
|
position: absolute;
|
||||||
|
top: 33.33333333%;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 33.33333333%;
|
||||||
|
border-top: 1rpx dashed rgba(255, 255, 255, 0.5);
|
||||||
|
border-bottom: 1rpx dashed rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 纵向虚线 */
|
||||||
|
.uni-cropper-dashed-v {
|
||||||
|
position: absolute;
|
||||||
|
left: 33.33333333%;
|
||||||
|
top: 0;
|
||||||
|
width: 33.33333333%;
|
||||||
|
height: 100%;
|
||||||
|
border-left: 1rpx dashed rgba(255, 255, 255, 0.5);
|
||||||
|
border-right: 1rpx dashed rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 四个方向的线 为了之后的拖动事件*/
|
||||||
|
.uni-cropper-line-t {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #69f;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 1rpx;
|
||||||
|
opacity: 0.1;
|
||||||
|
cursor: n-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-cropper-line-t::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
right: 0rpx;
|
||||||
|
width: 100%;
|
||||||
|
-webkit-transform: translate3d(0, -50%, 0);
|
||||||
|
transform: translate3d(0, -50%, 0);
|
||||||
|
bottom: 0;
|
||||||
|
height: 41rpx;
|
||||||
|
background: transparent;
|
||||||
|
z-index: 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-cropper-line-r {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
background-color: #69f;
|
||||||
|
top: 0;
|
||||||
|
right: 0rpx;
|
||||||
|
width: 1rpx;
|
||||||
|
opacity: 0.1;
|
||||||
|
height: 100%;
|
||||||
|
cursor: e-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-cropper-line-r::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 50%;
|
||||||
|
width: 41rpx;
|
||||||
|
-webkit-transform: translate3d(-50%, 0, 0);
|
||||||
|
transform: translate3d(-50%, 0, 0);
|
||||||
|
bottom: 0;
|
||||||
|
height: 100%;
|
||||||
|
background: transparent;
|
||||||
|
z-index: 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-cropper-line-b {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #69f;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 1rpx;
|
||||||
|
opacity: 0.1;
|
||||||
|
cursor: s-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-cropper-line-b::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
right: 0rpx;
|
||||||
|
width: 100%;
|
||||||
|
-webkit-transform: translate3d(0, -50%, 0);
|
||||||
|
transform: translate3d(0, -50%, 0);
|
||||||
|
bottom: 0;
|
||||||
|
height: 41rpx;
|
||||||
|
background: transparent;
|
||||||
|
z-index: 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-cropper-line-l {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
background-color: #69f;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 1rpx;
|
||||||
|
opacity: 0.1;
|
||||||
|
height: 100%;
|
||||||
|
cursor: w-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-cropper-line-l::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 50%;
|
||||||
|
width: 41rpx;
|
||||||
|
-webkit-transform: translate3d(-50%, 0, 0);
|
||||||
|
transform: translate3d(-50%, 0, 0);
|
||||||
|
bottom: 0;
|
||||||
|
height: 100%;
|
||||||
|
background: transparent;
|
||||||
|
z-index: 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-cropper-point {
|
||||||
|
width: 5rpx;
|
||||||
|
height: 5rpx;
|
||||||
|
background-color: #69f;
|
||||||
|
opacity: .75;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.point-t {
|
||||||
|
top: -3rpx;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -3rpx;
|
||||||
|
cursor: n-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.point-tr {
|
||||||
|
top: -3rpx;
|
||||||
|
left: 100%;
|
||||||
|
margin-left: -3rpx;
|
||||||
|
cursor: n-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.point-r {
|
||||||
|
top: 50%;
|
||||||
|
left: 100%;
|
||||||
|
margin-left: -3rpx;
|
||||||
|
margin-top: -3rpx;
|
||||||
|
cursor: n-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.point-rb {
|
||||||
|
left: 100%;
|
||||||
|
top: 100%;
|
||||||
|
-webkit-transform: translate3d(-50%, -50%, 0);
|
||||||
|
transform: translate3d(-50%, -50%, 0);
|
||||||
|
cursor: n-resize;
|
||||||
|
width: 36rpx;
|
||||||
|
height: 36rpx;
|
||||||
|
background-color: #69f;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1112;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.point-b {
|
||||||
|
left: 50%;
|
||||||
|
top: 100%;
|
||||||
|
margin-left: -3rpx;
|
||||||
|
margin-top: -3rpx;
|
||||||
|
cursor: n-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.point-bl {
|
||||||
|
left: 0%;
|
||||||
|
top: 100%;
|
||||||
|
margin-left: -3rpx;
|
||||||
|
margin-top: -3rpx;
|
||||||
|
cursor: n-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.point-l {
|
||||||
|
left: 0%;
|
||||||
|
top: 50%;
|
||||||
|
margin-left: -3rpx;
|
||||||
|
margin-top: -3rpx;
|
||||||
|
cursor: n-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.point-lt {
|
||||||
|
left: 0%;
|
||||||
|
top: 0%;
|
||||||
|
margin-left: -3rpx;
|
||||||
|
margin-top: -3rpx;
|
||||||
|
cursor: n-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 裁剪框预览内容 */
|
||||||
|
.uni-cropper-viewer {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-cropper-viewer image {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
108
src/pages/mine/help/index.vue
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
<template>
|
||||||
|
<view class="help-container">
|
||||||
|
<view v-for="(item, findex) in list" :key="findex" :title="item.title" class="list-title">
|
||||||
|
<view class="text-title">
|
||||||
|
<view :class="item.icon"></view>{{ item.title }}
|
||||||
|
</view>
|
||||||
|
<view class="childList">
|
||||||
|
<view v-for="(child, zindex) in item.childList" :key="zindex" class="question" hover-class="hover"
|
||||||
|
@click="handleText(child)">
|
||||||
|
<view class="text-item">{{ child.title }}</view>
|
||||||
|
<view class="line" v-if="zindex !== item.childList.length - 1"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, getCurrentInstance } from "vue"
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance()
|
||||||
|
|
||||||
|
const list = ref([{
|
||||||
|
icon: 'iconfont icon-github',
|
||||||
|
title: '若依问题',
|
||||||
|
childList: [{
|
||||||
|
title: '若依开源吗?',
|
||||||
|
content: '开源'
|
||||||
|
}, {
|
||||||
|
title: '若依可以商用吗?',
|
||||||
|
content: '可以'
|
||||||
|
}, {
|
||||||
|
title: '若依官网地址多少?',
|
||||||
|
content: 'http://ruoyi.vip'
|
||||||
|
}, {
|
||||||
|
title: '若依文档地址多少?',
|
||||||
|
content: 'http://doc.ruoyi.vip'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'iconfont icon-help',
|
||||||
|
title: '其他问题',
|
||||||
|
childList: [{
|
||||||
|
title: '如何退出登录?',
|
||||||
|
content: '请点击[我的] - [应用设置] - [退出登录]即可退出登录',
|
||||||
|
}, {
|
||||||
|
title: '如何修改用户头像?',
|
||||||
|
content: '请点击[我的] - [选择头像] - [点击提交]即可更换用户头像',
|
||||||
|
}, {
|
||||||
|
title: '如何修改登录密码?',
|
||||||
|
content: '请点击[我的] - [应用设置] - [修改密码]即可修改登录密码',
|
||||||
|
}]
|
||||||
|
}])
|
||||||
|
|
||||||
|
function handleText(item) {
|
||||||
|
proxy.$tab.navigateTo(`/pages/common/textview/index?title=${item.title}&content=${item.content}`)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
page {
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-container {
|
||||||
|
margin-bottom: 100rpx;
|
||||||
|
padding: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-title {
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.childList {
|
||||||
|
background: #ffffff;
|
||||||
|
box-shadow: 0px 0px 10rpx rgba(193, 193, 193, 0.2);
|
||||||
|
border-radius: 16rpx;
|
||||||
|
margin-top: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line {
|
||||||
|
width: 100%;
|
||||||
|
height: 1rpx;
|
||||||
|
background-color: #F5F5F5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-title {
|
||||||
|
color: #303133;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-left: 10rpx;
|
||||||
|
|
||||||
|
.iconfont {
|
||||||
|
font-size: 16px;
|
||||||
|
margin-right: 10rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-item {
|
||||||
|
font-size: 28rpx;
|
||||||
|
padding: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question {
|
||||||
|
color: #606266;
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
187
src/pages/mine/index.vue
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
<template>
|
||||||
|
<view class="mine-container" :style="{height: `${windowHeight}px`}">
|
||||||
|
<!--顶部个人信息栏-->
|
||||||
|
<view class="header-section">
|
||||||
|
<view class="flex padding justify-between">
|
||||||
|
<view class="flex align-center">
|
||||||
|
<view v-if="!avatar" class="cu-avatar xl round bg-white">
|
||||||
|
<view class="iconfont icon-people text-gray icon"></view>
|
||||||
|
</view>
|
||||||
|
<image v-if="avatar" @click="handleToAvatar" :src="avatar" class="cu-avatar xl round" mode="widthFix">
|
||||||
|
</image>
|
||||||
|
<view v-if="!name" @click="handleToLogin" class="login-tip">
|
||||||
|
点击登录
|
||||||
|
</view>
|
||||||
|
<view v-if="name" @click="handleToInfo" class="user-info">
|
||||||
|
<view class="u_title">
|
||||||
|
用户名:{{ name }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view @click="handleToInfo" class="flex align-center">
|
||||||
|
<text>个人信息</text>
|
||||||
|
<view class="iconfont icon-right"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="content-section">
|
||||||
|
<view class="mine-actions grid col-4 text-center">
|
||||||
|
<view class="action-item" @click="handleJiaoLiuQun">
|
||||||
|
<view class="iconfont icon-friendfill text-pink icon"></view>
|
||||||
|
<text class="text">交流群</text>
|
||||||
|
</view>
|
||||||
|
<view class="action-item" @click="handleBuilding">
|
||||||
|
<view class="iconfont icon-service text-blue icon"></view>
|
||||||
|
<text class="text">在线客服</text>
|
||||||
|
</view>
|
||||||
|
<view class="action-item" @click="handleBuilding">
|
||||||
|
<view class="iconfont icon-community text-mauve icon"></view>
|
||||||
|
<text class="text">反馈社区</text>
|
||||||
|
</view>
|
||||||
|
<view class="action-item" @click="handleBuilding">
|
||||||
|
<view class="iconfont icon-dianzan text-green icon"></view>
|
||||||
|
<text class="text">点赞我们</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="menu-list">
|
||||||
|
<view class="list-cell list-cell-arrow" @click="handleToEditInfo">
|
||||||
|
<view class="menu-item-box">
|
||||||
|
<view class="iconfont icon-user menu-icon"></view>
|
||||||
|
<view>编辑资料</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="list-cell list-cell-arrow" @click="handleHelp">
|
||||||
|
<view class="menu-item-box">
|
||||||
|
<view class="iconfont icon-help menu-icon"></view>
|
||||||
|
<view>常见问题</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="list-cell list-cell-arrow" @click="handleAbout">
|
||||||
|
<view class="menu-item-box">
|
||||||
|
<view class="iconfont icon-aixin menu-icon"></view>
|
||||||
|
<view>关于我们</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="list-cell list-cell-arrow" @click="handleToSetting">
|
||||||
|
<view class="menu-item-box">
|
||||||
|
<view class="iconfont icon-setting menu-icon"></view>
|
||||||
|
<view>应用设置</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { useUserStore } from '@/store'
|
||||||
|
import { computed , getCurrentInstance } from "vue"
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance()
|
||||||
|
const name = useUserStore().name
|
||||||
|
const avatar = computed(() => useUserStore().avatar)
|
||||||
|
const windowHeight = computed(() => uni.getSystemInfoSync().windowHeight - 50)
|
||||||
|
|
||||||
|
function handleToInfo() {
|
||||||
|
proxy.$tab.navigateTo('/pages/mine/info/index')
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleToEditInfo() {
|
||||||
|
proxy.$tab.navigateTo('/pages/mine/info/edit')
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleToSetting() {
|
||||||
|
proxy.$tab.navigateTo('/pages/mine/setting/index')
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleToLogin() {
|
||||||
|
proxy.$tab.reLaunch('/pages/login')
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleToAvatar() {
|
||||||
|
proxy.$tab.navigateTo('/pages/mine/avatar/index')
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleHelp() {
|
||||||
|
proxy.$tab.navigateTo('/pages/mine/help/index')
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleAbout() {
|
||||||
|
proxy.$tab.navigateTo('/pages/mine/about/index')
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleJiaoLiuQun() {
|
||||||
|
proxy.$modal.showToast('QQ群:①133713780(满)、②146013835(满)、③189091635')
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleBuilding() {
|
||||||
|
proxy.$modal.showToast('模块建设中~')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
page {
|
||||||
|
background-color: #f5f6f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mine-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
|
||||||
|
.header-section {
|
||||||
|
padding: 15px 15px 45px 15px;
|
||||||
|
background-color: #3c96f3;
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
.login-tip {
|
||||||
|
font-size: 18px;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cu-avatar {
|
||||||
|
border: 2px solid #eaeaea;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info {
|
||||||
|
margin-left: 15px;
|
||||||
|
|
||||||
|
.u_title {
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-section {
|
||||||
|
position: relative;
|
||||||
|
top: -50px;
|
||||||
|
|
||||||
|
.mine-actions {
|
||||||
|
margin: 15px 15px;
|
||||||
|
padding: 20px 0px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: white;
|
||||||
|
|
||||||
|
.action-item {
|
||||||
|
.icon {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
display: block;
|
||||||
|
font-size: 13px;
|
||||||
|
margin: 8px 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
124
src/pages/mine/info/edit.vue
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<view class="example">
|
||||||
|
<uni-forms ref="form" :model="user" labelWidth="80px">
|
||||||
|
<uni-forms-item label="用户昵称" name="nickName">
|
||||||
|
<uni-easyinput v-model="user.nickName" placeholder="请输入昵称" />
|
||||||
|
</uni-forms-item>
|
||||||
|
<uni-forms-item label="手机号码" name="phonenumber">
|
||||||
|
<uni-easyinput v-model="user.phonenumber" placeholder="请输入手机号码" />
|
||||||
|
</uni-forms-item>
|
||||||
|
<uni-forms-item label="邮箱" name="email">
|
||||||
|
<uni-easyinput v-model="user.email" placeholder="请输入邮箱" />
|
||||||
|
</uni-forms-item>
|
||||||
|
<uni-forms-item label="性别" name="sex" required>
|
||||||
|
<uni-data-checkbox v-model="user.sex" :localdata="sexs" />
|
||||||
|
</uni-forms-item>
|
||||||
|
</uni-forms>
|
||||||
|
<button type="primary" @click="submit">提交</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { getUserProfile } from "@/api/system/user"
|
||||||
|
import { updateUserProfile } from "@/api/system/user"
|
||||||
|
import { ref , getCurrentInstance } from "vue"
|
||||||
|
import { onReady } from "@dcloudio/uni-app"
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance()
|
||||||
|
const user = ref({
|
||||||
|
nickName: "",
|
||||||
|
phonenumber: "",
|
||||||
|
email: "",
|
||||||
|
sex: ""
|
||||||
|
})
|
||||||
|
const sexs = [{
|
||||||
|
text: '男',
|
||||||
|
value: "0"
|
||||||
|
}, {
|
||||||
|
text: '女',
|
||||||
|
value: "1"
|
||||||
|
}]
|
||||||
|
const rules = ref({
|
||||||
|
nickName: {
|
||||||
|
rules: [{
|
||||||
|
required: true,
|
||||||
|
errorMessage: '用户昵称不能为空'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
phonenumber: {
|
||||||
|
rules: [{
|
||||||
|
required: true,
|
||||||
|
errorMessage: '手机号码不能为空'
|
||||||
|
}, {
|
||||||
|
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
|
||||||
|
errorMessage: '请输入正确的手机号码'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
rules: [{
|
||||||
|
required: true,
|
||||||
|
errorMessage: '邮箱地址不能为空'
|
||||||
|
}, {
|
||||||
|
format: 'email',
|
||||||
|
errorMessage: '请输入正确的邮箱地址'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function getUser() {
|
||||||
|
getUserProfile().then(response => {
|
||||||
|
user.value = response.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function submit(ref) {
|
||||||
|
proxy.$refs.form.validate().then(res => {
|
||||||
|
updateUserProfile(user.value).then(response => {
|
||||||
|
proxy.$modal.msgSuccess("修改成功")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onReady(() => {
|
||||||
|
proxy.$refs.form.setRules(rules.value)
|
||||||
|
})
|
||||||
|
|
||||||
|
getUser()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
page {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example {
|
||||||
|
padding: 15px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.segmented-control {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-group {
|
||||||
|
margin-top: 15px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 35px;
|
||||||
|
line-height: 35px;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
37
src/pages/mine/info/index.vue
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<uni-list>
|
||||||
|
<uni-list-item showExtraIcon="true" :extraIcon="{type: 'person-filled'}" title="昵称" :rightText="user.nickName" />
|
||||||
|
<uni-list-item showExtraIcon="true" :extraIcon="{type: 'phone-filled'}" title="手机号码" :rightText="user.phonenumber" />
|
||||||
|
<uni-list-item showExtraIcon="true" :extraIcon="{type: 'email-filled'}" title="邮箱" :rightText="user.email" />
|
||||||
|
<uni-list-item showExtraIcon="true" :extraIcon="{type: 'auth-filled'}" title="岗位" :rightText="postGroup" />
|
||||||
|
<uni-list-item showExtraIcon="true" :extraIcon="{type: 'staff-filled'}" title="角色" :rightText="roleGroup" />
|
||||||
|
<uni-list-item showExtraIcon="true" :extraIcon="{type: 'calendar-filled'}" title="创建日期" :rightText="user.createTime" />
|
||||||
|
</uni-list>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { getUserProfile } from "@/api/system/user"
|
||||||
|
import { ref, reactive } from "vue"
|
||||||
|
|
||||||
|
const user = ref({})
|
||||||
|
const roleGroup = ref("")
|
||||||
|
const postGroup = ref("")
|
||||||
|
|
||||||
|
function getUser() {
|
||||||
|
getUserProfile().then(response => {
|
||||||
|
user.value = response.data
|
||||||
|
roleGroup.value = response.roleGroup
|
||||||
|
postGroup.value = response.postGroup
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getUser()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
page {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
79
src/pages/mine/pwd/index.vue
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
<template>
|
||||||
|
<view class="pwd-retrieve-container">
|
||||||
|
<uni-forms ref="form" :value="user" labelWidth="80px">
|
||||||
|
<uni-forms-item name="oldPassword" label="旧密码">
|
||||||
|
<uni-easyinput type="password" v-model="user.oldPassword" placeholder="请输入旧密码" />
|
||||||
|
</uni-forms-item>
|
||||||
|
<uni-forms-item name="newPassword" label="新密码">
|
||||||
|
<uni-easyinput type="password" v-model="user.newPassword" placeholder="请输入新密码" />
|
||||||
|
</uni-forms-item>
|
||||||
|
<uni-forms-item name="confirmPassword" label="确认密码">
|
||||||
|
<uni-easyinput type="password" v-model="user.confirmPassword" placeholder="请确认新密码" />
|
||||||
|
</uni-forms-item>
|
||||||
|
<button type="primary" @click="submit">提交</button>
|
||||||
|
</uni-forms>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { updateUserPwd } from "@/api/system/user"
|
||||||
|
import { ref, reactive , getCurrentInstance } from "vue"
|
||||||
|
import { onReady } from "@dcloudio/uni-app"
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance()
|
||||||
|
const user = reactive({
|
||||||
|
oldPassword: undefined,
|
||||||
|
newPassword: undefined,
|
||||||
|
confirmPassword: undefined
|
||||||
|
})
|
||||||
|
const rules = ref({
|
||||||
|
oldPassword: {
|
||||||
|
rules: [{
|
||||||
|
required: true,
|
||||||
|
errorMessage: '旧密码不能为空'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
newPassword: {
|
||||||
|
rules: [{
|
||||||
|
required: true,
|
||||||
|
errorMessage: '新密码不能为空',
|
||||||
|
}, {
|
||||||
|
minLength: 6,
|
||||||
|
maxLength: 20,
|
||||||
|
errorMessage: '长度在 6 到 20 个字符'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
confirmPassword: {
|
||||||
|
rules: [{
|
||||||
|
required: true,
|
||||||
|
errorMessage: '确认密码不能为空'
|
||||||
|
}, {
|
||||||
|
validateFunction: (rule, value, data) => user.newPassword === value,
|
||||||
|
errorMessage: '两次输入的密码不一致'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onReady(() => {
|
||||||
|
proxy.$refs.form.setRules(rules.value)
|
||||||
|
})
|
||||||
|
|
||||||
|
function submit() {
|
||||||
|
proxy.$refs.form.validate().then(res => {
|
||||||
|
updateUserPwd(user.oldPassword, user.newPassword).then(response => {
|
||||||
|
proxy.$modal.msgSuccess("修改成功")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
page {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pwd-retrieve-container {
|
||||||
|
padding-top: 36rpx;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
78
src/pages/mine/setting/index.vue
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<template>
|
||||||
|
<view class="setting-container" :style="{height: `${windowHeight}px`}">
|
||||||
|
<view class="menu-list">
|
||||||
|
<view class="list-cell list-cell-arrow" @click="handleToPwd">
|
||||||
|
<view class="menu-item-box">
|
||||||
|
<view class="iconfont icon-password menu-icon"></view>
|
||||||
|
<view>修改密码</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="list-cell list-cell-arrow" @click="handleToUpgrade">
|
||||||
|
<view class="menu-item-box">
|
||||||
|
<view class="iconfont icon-refresh menu-icon"></view>
|
||||||
|
<view>检查更新</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="list-cell list-cell-arrow" @click="handleCleanTmp">
|
||||||
|
<view class="menu-item-box">
|
||||||
|
<view class="iconfont icon-clean menu-icon"></view>
|
||||||
|
<view>清理缓存</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="cu-list menu">
|
||||||
|
<view class="cu-item item-box">
|
||||||
|
<view class="content text-center" @click="handleLogout">
|
||||||
|
<text class="text-black">退出登录</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { useUserStore } from '@/store'
|
||||||
|
import { ref, computed , getCurrentInstance } from "vue"
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance()
|
||||||
|
const windowHeight = computed(() => uni.getSystemInfoSync().windowHeight - 50)
|
||||||
|
|
||||||
|
function handleToPwd() {
|
||||||
|
proxy.$tab.navigateTo('/pages/mine/pwd/index')
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleToUpgrade() {
|
||||||
|
proxy.$modal.showToast('模块建设中~')
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCleanTmp() {
|
||||||
|
proxy.$modal.showToast('模块建设中~')
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleLogout() {
|
||||||
|
proxy.$modal.confirm('确定注销并退出系统吗?').then(() => {
|
||||||
|
useUserStore().logOut().then(() => {}).finally(()=>{
|
||||||
|
proxy.$tab.reLaunch('/pages/index')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page {
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-box {
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
margin: 30rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
color: #303133;
|
||||||
|
font-size: 32rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
187
src/pages/register.vue
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
<template>
|
||||||
|
<view class="normal-login-container">
|
||||||
|
<view class="logo-content align-center justify-center flex">
|
||||||
|
<image style="width: 100rpx;height: 100rpx;" :src="globalConfig.appInfo.logo" mode="widthFix">
|
||||||
|
</image>
|
||||||
|
<text class="title">若依移动端注册</text>
|
||||||
|
</view>
|
||||||
|
<view class="login-form-content">
|
||||||
|
<view class="input-item flex align-center">
|
||||||
|
<view class="iconfont icon-user icon"></view>
|
||||||
|
<input v-model="registerForm.username" class="input" type="text" placeholder="请输入账号" maxlength="30" />
|
||||||
|
</view>
|
||||||
|
<view class="input-item flex align-center">
|
||||||
|
<view class="iconfont icon-password icon"></view>
|
||||||
|
<input v-model="registerForm.password" type="password" class="input" placeholder="请输入密码" maxlength="20" />
|
||||||
|
</view>
|
||||||
|
<view class="input-item flex align-center">
|
||||||
|
<view class="iconfont icon-password icon"></view>
|
||||||
|
<input v-model="registerForm.confirmPassword" type="password" class="input" placeholder="请输入重复密码" maxlength="20" />
|
||||||
|
</view>
|
||||||
|
<view class="input-item flex align-center" style="width: 60%;margin: 0px;" v-if="captchaEnabled">
|
||||||
|
<view class="iconfont icon-code icon"></view>
|
||||||
|
<input v-model="registerForm.code" type="number" class="input" placeholder="请输入验证码" maxlength="4" />
|
||||||
|
<view class="login-code">
|
||||||
|
<image :src="codeUrl" @click="getCode" class="login-code-img"></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="action-btn">
|
||||||
|
<button @click="handleRegister()" class="register-btn cu-btn block bg-blue lg round">注册</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="xieyi text-center">
|
||||||
|
<text @click="handleUserLogin" class="text-blue">使用已有账号登录</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { getCodeImg, register } from '@/api/login'
|
||||||
|
import { ref, getCurrentInstance } from "vue"
|
||||||
|
import { useConfigStore } from '@/store'
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance()
|
||||||
|
const globalConfig = useConfigStore().config
|
||||||
|
const codeUrl = ref("")
|
||||||
|
// 验证码开关
|
||||||
|
const captchaEnabled = ref(true)
|
||||||
|
const registerForm = ref({
|
||||||
|
username: "",
|
||||||
|
password: "",
|
||||||
|
confirmPassword: "",
|
||||||
|
code: "",
|
||||||
|
uuid: ""
|
||||||
|
})
|
||||||
|
|
||||||
|
// 用户登录
|
||||||
|
function handleUserLogin() {
|
||||||
|
proxy.$tab.navigateTo(`/pages/login`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取图形验证码
|
||||||
|
function getCode() {
|
||||||
|
getCodeImg().then(res => {
|
||||||
|
captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled
|
||||||
|
if (captchaEnabled.value) {
|
||||||
|
codeUrl.value = 'data:image/gif;base64,' + res.img
|
||||||
|
registerForm.value.uuid = res.uuid
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册方法
|
||||||
|
async function handleRegister() {
|
||||||
|
if (registerForm.value.username === "") {
|
||||||
|
proxy.$modal.msgError("请输入您的账号")
|
||||||
|
} else if (registerForm.value.password === "") {
|
||||||
|
proxy.$modal.msgError("请输入您的密码")
|
||||||
|
} else if (registerForm.value.confirmPassword === "") {
|
||||||
|
proxy.$modal.msgError("请再次输入您的密码")
|
||||||
|
} else if (registerForm.value.password !== registerForm.value.confirmPassword) {
|
||||||
|
proxy.$modal.msgError("两次输入的密码不一致")
|
||||||
|
} else if (registerForm.value.code === "" && captchaEnabled.value) {
|
||||||
|
proxy.$modal.msgError("请输入验证码")
|
||||||
|
} else {
|
||||||
|
proxy.$modal.loading("注册中,请耐心等待...")
|
||||||
|
userRegister()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户注册
|
||||||
|
async function userRegister() {
|
||||||
|
register(registerForm.value).then(res => {
|
||||||
|
proxy.$modal.closeLoading()
|
||||||
|
uni.showModal({
|
||||||
|
title: "系统提示",
|
||||||
|
content: "恭喜你,您的账号 " + registerForm.value.username + " 注册成功!",
|
||||||
|
success: function (res) {
|
||||||
|
if (res.confirm) {
|
||||||
|
uni.redirectTo({ url: `/pages/login` })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).catch(() => {
|
||||||
|
if (captchaEnabled.value) {
|
||||||
|
getCode()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getCode()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
page {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.normal-login-container {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.logo-content {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 21px;
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 15%;
|
||||||
|
|
||||||
|
image {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form-content {
|
||||||
|
text-align: center;
|
||||||
|
margin: 20px auto;
|
||||||
|
margin-top: 15%;
|
||||||
|
width: 80%;
|
||||||
|
|
||||||
|
.input-item {
|
||||||
|
margin: 20px auto;
|
||||||
|
background-color: #f5f6f7;
|
||||||
|
height: 45px;
|
||||||
|
border-radius: 20px;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 38rpx;
|
||||||
|
margin-left: 10px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 20px;
|
||||||
|
text-align: left;
|
||||||
|
padding-left: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-btn {
|
||||||
|
margin-top: 40px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xieyi {
|
||||||
|
color: #333;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-code {
|
||||||
|
height: 38px;
|
||||||
|
float: right;
|
||||||
|
|
||||||
|
.login-code-img {
|
||||||
|
height: 38px;
|
||||||
|
position: absolute;
|
||||||
|
margin-left: 10px;
|
||||||
|
width: 200rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
171
src/pages/work/index.vue
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
<template>
|
||||||
|
<view class="work-container">
|
||||||
|
<!-- 轮播图 -->
|
||||||
|
<uni-swiper-dot class="uni-swiper-dot-box" :info="data" :current="current" field="content">
|
||||||
|
<swiper class="swiper-box" :current="swiperDotIndex" @change="changeSwiper">
|
||||||
|
<swiper-item v-for="(item, index) in data" :key="index">
|
||||||
|
<view class="swiper-item" @click="clickBannerItem(item)">
|
||||||
|
<image :src="item.image" mode="aspectFill" :draggable="false" />
|
||||||
|
</view>
|
||||||
|
</swiper-item>
|
||||||
|
</swiper>
|
||||||
|
</uni-swiper-dot>
|
||||||
|
|
||||||
|
<!-- 宫格组件 -->
|
||||||
|
<uni-section title="系统管理" type="line"></uni-section>
|
||||||
|
<view class="grid-body">
|
||||||
|
<uni-grid :column="4" :showBorder="false" @change="changeGrid">
|
||||||
|
<uni-grid-item>
|
||||||
|
<view class="grid-item-box">
|
||||||
|
<uni-icons type="person-filled" size="30"></uni-icons>
|
||||||
|
<text class="text">用户管理</text>
|
||||||
|
</view>
|
||||||
|
</uni-grid-item>
|
||||||
|
<uni-grid-item>
|
||||||
|
<view class="grid-item-box">
|
||||||
|
<uni-icons type="staff-filled" size="30"></uni-icons>
|
||||||
|
<text class="text">角色管理</text>
|
||||||
|
</view>
|
||||||
|
</uni-grid-item>
|
||||||
|
<uni-grid-item>
|
||||||
|
<view class="grid-item-box">
|
||||||
|
<uni-icons type="color" size="30"></uni-icons>
|
||||||
|
<text class="text">菜单管理</text>
|
||||||
|
</view>
|
||||||
|
</uni-grid-item>
|
||||||
|
<uni-grid-item>
|
||||||
|
<view class="grid-item-box">
|
||||||
|
<uni-icons type="settings-filled" size="30"></uni-icons>
|
||||||
|
<text class="text">部门管理</text>
|
||||||
|
</view>
|
||||||
|
</uni-grid-item>
|
||||||
|
<uni-grid-item>
|
||||||
|
<view class="grid-item-box">
|
||||||
|
<uni-icons type="heart-filled" size="30"></uni-icons>
|
||||||
|
<text class="text">岗位管理</text>
|
||||||
|
</view>
|
||||||
|
</uni-grid-item>
|
||||||
|
<uni-grid-item>
|
||||||
|
<view class="grid-item-box">
|
||||||
|
<uni-icons type="bars" size="30"></uni-icons>
|
||||||
|
<text class="text">字典管理</text>
|
||||||
|
</view>
|
||||||
|
</uni-grid-item>
|
||||||
|
<uni-grid-item>
|
||||||
|
<view class="grid-item-box">
|
||||||
|
<uni-icons type="gear-filled" size="30"></uni-icons>
|
||||||
|
<text class="text">参数设置</text>
|
||||||
|
</view>
|
||||||
|
</uni-grid-item>
|
||||||
|
<uni-grid-item>
|
||||||
|
<view class="grid-item-box">
|
||||||
|
<uni-icons type="chat-filled" size="30"></uni-icons>
|
||||||
|
<text class="text">通知公告</text>
|
||||||
|
</view>
|
||||||
|
</uni-grid-item>
|
||||||
|
<uni-grid-item>
|
||||||
|
<view class="grid-item-box">
|
||||||
|
<uni-icons type="wallet-filled" size="30"></uni-icons>
|
||||||
|
<text class="text">日志管理</text>
|
||||||
|
</view>
|
||||||
|
</uni-grid-item>
|
||||||
|
</uni-grid>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, getCurrentInstance } from "vue"
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance()
|
||||||
|
const current = ref(0)
|
||||||
|
const swiperDotIndex = ref(0)
|
||||||
|
const data = ref([{ image: '/static/images/banner/banner01.jpg' }, { image: '/static/images/banner/banner02.jpg' }, { image: '/static/images/banner/banner03.jpg' }])
|
||||||
|
|
||||||
|
function clickBannerItem(item) {
|
||||||
|
console.info(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeSwiper(e) {
|
||||||
|
current.value = e.detail.current
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeGrid(e) {
|
||||||
|
proxy.$modal.showToast('模块建设中~')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
page {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: #fff;
|
||||||
|
min-height: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
view {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
.text {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 26rpx;
|
||||||
|
margin-top: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-item-box {
|
||||||
|
flex: 1;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-margin-wrap {
|
||||||
|
width: 690rpx;
|
||||||
|
width: 100%;
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swiper {
|
||||||
|
height: 300rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swiper-box {
|
||||||
|
height: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swiper-item {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
color: #fff;
|
||||||
|
height: 300rpx;
|
||||||
|
line-height: 300rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 500px) {
|
||||||
|
.uni-swiper-dot-box {
|
||||||
|
width: 400px;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
margin: 0 auto;
|
||||||
|
/* #endif */
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
39
src/permission.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { getToken } from '@/utils/auth'
|
||||||
|
|
||||||
|
// 登录页面
|
||||||
|
const loginPage = "/pages/login"
|
||||||
|
|
||||||
|
// 页面白名单
|
||||||
|
const whiteList = [
|
||||||
|
'/pages/login', '/pages/register', '/pages/common/webview/index'
|
||||||
|
]
|
||||||
|
|
||||||
|
// 检查地址白名单
|
||||||
|
function checkWhite(url) {
|
||||||
|
const path = url.split('?')[0]
|
||||||
|
return whiteList.indexOf(path) !== -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面跳转验证拦截器
|
||||||
|
let list = ["navigateTo", "redirectTo", "reLaunch", "switchTab"]
|
||||||
|
list.forEach(item => {
|
||||||
|
uni.addInterceptor(item, {
|
||||||
|
invoke(to) {
|
||||||
|
if (getToken()) {
|
||||||
|
if (to.url === loginPage) {
|
||||||
|
uni.reLaunch({ url: "/" })
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
if (checkWhite(to.url)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
uni.reLaunch({ url: loginPage })
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail(err) {
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
60
src/plugins/auth.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import { useUserStore } from '@/store'
|
||||||
|
|
||||||
|
function authPermission(permission) {
|
||||||
|
const all_permission = "*:*:*"
|
||||||
|
const permissions = useUserStore().permissions
|
||||||
|
if (permission && permission.length > 0) {
|
||||||
|
return permissions.some(v => {
|
||||||
|
return all_permission === v || v === permission
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function authRole(role) {
|
||||||
|
const super_admin = "admin"
|
||||||
|
const roles = useUserStore().roles
|
||||||
|
if (role && role.length > 0) {
|
||||||
|
return roles.some(v => {
|
||||||
|
return super_admin === v || v === role
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
// 验证用户是否具备某权限
|
||||||
|
hasPermi(permission) {
|
||||||
|
return authPermission(permission)
|
||||||
|
},
|
||||||
|
// 验证用户是否含有指定权限,只需包含其中一个
|
||||||
|
hasPermiOr(permissions) {
|
||||||
|
return permissions.some(item => {
|
||||||
|
return authPermission(item)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 验证用户是否含有指定权限,必须全部拥有
|
||||||
|
hasPermiAnd(permissions) {
|
||||||
|
return permissions.every(item => {
|
||||||
|
return authPermission(item)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 验证用户是否具备某角色
|
||||||
|
hasRole(role) {
|
||||||
|
return authRole(role)
|
||||||
|
},
|
||||||
|
// 验证用户是否含有指定角色,只需包含其中一个
|
||||||
|
hasRoleOr(roles) {
|
||||||
|
return roles.some(item => {
|
||||||
|
return authRole(item)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 验证用户是否含有指定角色,必须全部拥有
|
||||||
|
hasRoleAnd(roles) {
|
||||||
|
return roles.every(item => {
|
||||||
|
return authRole(item)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/plugins/index.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import tab from './tab'
|
||||||
|
import auth from './auth'
|
||||||
|
import modal from './modal'
|
||||||
|
|
||||||
|
export function install(app) {
|
||||||
|
// 页签操作
|
||||||
|
app.config.globalProperties.$tab = tab
|
||||||
|
// 认证对象
|
||||||
|
app.config.globalProperties.$auth = auth
|
||||||
|
// 模态框对象
|
||||||
|
app.config.globalProperties.$modal = modal
|
||||||
|
}
|
||||||
78
src/plugins/modal.js
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
export default {
|
||||||
|
// 消息提示
|
||||||
|
msg(content) {
|
||||||
|
uni.showToast({
|
||||||
|
title: content,
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 错误消息
|
||||||
|
msgError(content) {
|
||||||
|
uni.showToast({
|
||||||
|
title: content,
|
||||||
|
icon: 'error'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 成功消息
|
||||||
|
msgSuccess(content) {
|
||||||
|
uni.showToast({
|
||||||
|
title: content,
|
||||||
|
icon: 'success'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 隐藏消息
|
||||||
|
hideMsg(content) {
|
||||||
|
uni.hideToast()
|
||||||
|
},
|
||||||
|
// 弹出提示
|
||||||
|
alert(content, title) {
|
||||||
|
uni.showModal({
|
||||||
|
title: title || '系统提示',
|
||||||
|
content: content,
|
||||||
|
showCancel: false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 确认窗体
|
||||||
|
confirm(content, title) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.showModal({
|
||||||
|
title: title || '系统提示',
|
||||||
|
content: content,
|
||||||
|
cancelText: '取消',
|
||||||
|
confirmText: '确定',
|
||||||
|
success: function(res) {
|
||||||
|
if (res.confirm) {
|
||||||
|
resolve(res.confirm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 提示信息
|
||||||
|
showToast(option) {
|
||||||
|
if (typeof option === "object") {
|
||||||
|
uni.showToast(option)
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: option,
|
||||||
|
icon: "none",
|
||||||
|
duration: 2500
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 打开遮罩层
|
||||||
|
loading(content) {
|
||||||
|
uni.showLoading({
|
||||||
|
title: content,
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 关闭遮罩层
|
||||||
|
closeLoading() {
|
||||||
|
try {
|
||||||
|
uni.hideLoading()
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/plugins/tab.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
export default {
|
||||||
|
// 关闭所有页面,打开到应用内的某个页面
|
||||||
|
reLaunch(url) {
|
||||||
|
return uni.reLaunch({
|
||||||
|
url: url
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 跳转到tabBar页面,并关闭其他所有非tabBar页面
|
||||||
|
switchTab(url) {
|
||||||
|
return uni.switchTab({
|
||||||
|
url: url
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 关闭当前页面,跳转到应用内的某个页面
|
||||||
|
redirectTo(url) {
|
||||||
|
return uni.redirectTo({
|
||||||
|
url: url
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 保留当前页面,跳转到应用内的某个页面
|
||||||
|
navigateTo(url) {
|
||||||
|
return uni.navigateTo({
|
||||||
|
url: url
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 关闭当前页面,返回上一页面或多级页面
|
||||||
|
navigateBack() {
|
||||||
|
return uni.navigateBack()
|
||||||
|
}
|
||||||
|
}
|
||||||
0
src/readme.md
Normal file
BIN
src/static/favicon.ico
Normal file
|
After Width: | Height: | Size: 17 KiB |
90
src/static/font/iconfont.css
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: "iconfont";
|
||||||
|
src: url('@/static/font/iconfont.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconfont {
|
||||||
|
font-family: "iconfont" !important;
|
||||||
|
font-size: 16px;
|
||||||
|
display: inline-block;
|
||||||
|
font-style: normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-user:before {
|
||||||
|
content: "\e7ae";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-password:before {
|
||||||
|
content: "\e8b2";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-code:before {
|
||||||
|
content: "\e699";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-setting:before {
|
||||||
|
content: "\e6cc";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-share:before {
|
||||||
|
content: "\e739";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-edit:before {
|
||||||
|
content: "\e60c";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-version:before {
|
||||||
|
content: "\e63f";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-service:before {
|
||||||
|
content: "\e6ff";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-friendfill:before {
|
||||||
|
content: "\e726";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-community:before {
|
||||||
|
content: "\e741";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-people:before {
|
||||||
|
content: "\e736";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-dianzan:before {
|
||||||
|
content: "\ec7f";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-right:before {
|
||||||
|
content: "\e7eb";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-logout:before {
|
||||||
|
content: "\e61d";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-help:before {
|
||||||
|
content: "\e616";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-github:before {
|
||||||
|
content: "\e628";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-aixin:before {
|
||||||
|
content: "\e601";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-clean:before {
|
||||||
|
content: "\e607";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-refresh:before {
|
||||||
|
content: "\e604";
|
||||||
|
}
|
||||||
|
|
||||||
BIN
src/static/font/iconfont.ttf
Normal file
BIN
src/static/images/banner/banner01.jpg
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
src/static/images/banner/banner02.jpg
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
src/static/images/banner/banner03.jpg
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
src/static/images/profile.jpg
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
src/static/images/tabbar/home.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
src/static/images/tabbar/home_.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
src/static/images/tabbar/mine.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
src/static/images/tabbar/mine_.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
src/static/images/tabbar/work.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
src/static/images/tabbar/work_.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
20
src/static/index.html
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
|
<meta name="renderer" content="webkit">
|
||||||
|
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||||
|
<link rel="shortcut icon" type="image/x-icon" href="<%= BASE_URL %>static/favicon.ico">
|
||||||
|
<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>
|
||||||
|
<link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>
|
||||||
|
<strong>本站点必须要开启JavaScript才能运行.</strong>
|
||||||
|
</noscript>
|
||||||
|
<div id="app"></div>
|
||||||
|
</html>
|
||||||
BIN
src/static/logo.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
src/static/logo200.png
Normal file
|
After Width: | Height: | Size: 7.8 KiB |
5142
src/static/scss/colorui.css
Normal file
90
src/static/scss/global.scss
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
.text-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-13 {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-12 {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-11 {
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-grey1 {
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
.text-grey2 {
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-cell-arrow::before {
|
||||||
|
content: ' ';
|
||||||
|
height: 10px;
|
||||||
|
width: 10px;
|
||||||
|
border-width: 2px 2px 0 0;
|
||||||
|
border-color: #c0c0c0;
|
||||||
|
border-style: solid;
|
||||||
|
-webkit-transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
|
||||||
|
transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -6px;
|
||||||
|
right: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-cell {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: #fff;
|
||||||
|
color: #333;
|
||||||
|
padding: 26rpx 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-cell:first-child {
|
||||||
|
border-radius: 8rpx 8rpx 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-cell:last-child {
|
||||||
|
border-radius: 0 0 8rpx 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-cell::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
border-bottom: 1px solid #eaeef1;
|
||||||
|
-webkit-transform: scaleY(0.5) translateZ(0);
|
||||||
|
transform: scaleY(0.5) translateZ(0);
|
||||||
|
transform-origin: 0 100%;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.menu-list {
|
||||||
|
margin: 15px 15px;
|
||||||
|
|
||||||
|
.menu-item-box {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.menu-icon {
|
||||||
|
color: #007AFF;
|
||||||
|
font-size: 16px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-right {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: 34rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
src/static/scss/index.scss
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// global
|
||||||
|
@import "./global.scss";
|
||||||
|
// color-ui
|
||||||
|
@import "@/static/scss/colorui.css";
|
||||||
|
// iconfont
|
||||||
|
@import "@/static/font/iconfont.css";
|
||||||
9
src/store/index.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { createPinia } from 'pinia'
|
||||||
|
import { useUserStore } from './modules/user'
|
||||||
|
import { useConfigStore } from './modules/config'
|
||||||
|
|
||||||
|
const pinia = createPinia()
|
||||||
|
|
||||||
|
export default pinia
|
||||||
|
|
||||||
|
export { useUserStore, useConfigStore }
|
||||||
13
src/store/modules/config.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
export const useConfigStore = defineStore('config', () => {
|
||||||
|
const config = ref()
|
||||||
|
const setConfig = (val) => {
|
||||||
|
config.value = val
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
config,
|
||||||
|
setConfig
|
||||||
|
}
|
||||||
|
})
|
||||||
56
src/store/modules/dict.js
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import { defineStore } from "pinia"
|
||||||
|
|
||||||
|
const useDictStore = defineStore("dict", {
|
||||||
|
state: () => ({
|
||||||
|
dict: new Array(),
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
// 获取字典
|
||||||
|
getDict(_key) {
|
||||||
|
if (_key == null && _key == "") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
for (let i = 0; i < this.dict.length; i++) {
|
||||||
|
if (this.dict[i].key == _key) {
|
||||||
|
return this.dict[i].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 设置字典
|
||||||
|
setDict(_key, value) {
|
||||||
|
if (_key !== null && _key !== "") {
|
||||||
|
this.dict.push({
|
||||||
|
key: _key,
|
||||||
|
value: value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 删除字典
|
||||||
|
removeDict(_key) {
|
||||||
|
var bln = false;
|
||||||
|
try {
|
||||||
|
for (let i = 0; i < this.dict.length; i++) {
|
||||||
|
if (this.dict[i].key == _key) {
|
||||||
|
this.dict.splice(i, 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
bln = false;
|
||||||
|
}
|
||||||
|
return bln;
|
||||||
|
},
|
||||||
|
// 清空字典
|
||||||
|
cleanDict() {
|
||||||
|
this.dict = new Array();
|
||||||
|
},
|
||||||
|
// 初始字典
|
||||||
|
initDict() {},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default useDictStore
|
||||||
117
src/store/modules/user.js
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import config from '@/config'
|
||||||
|
import storage from '@/utils/storage'
|
||||||
|
import constant from '@/utils/constant'
|
||||||
|
import { isHttp, isEmpty } from "@/utils/validate"
|
||||||
|
import { getInfo, login, logout } from '@/api/login'
|
||||||
|
import { getToken, removeToken, setToken } from '@/utils/auth'
|
||||||
|
import defAva from '@/static/images/profile.jpg'
|
||||||
|
|
||||||
|
const baseUrl = config.baseUrl
|
||||||
|
|
||||||
|
export const useUserStore = defineStore('user', () => {
|
||||||
|
const token = ref(getToken())
|
||||||
|
const id = ref(storage.get(constant.id))
|
||||||
|
const name = ref(storage.get(constant.name))
|
||||||
|
const avatar = ref(storage.get(constant.avatar))
|
||||||
|
const roles = ref(storage.get(constant.roles))
|
||||||
|
const permissions = ref(storage.get(constant.permissions))
|
||||||
|
|
||||||
|
const SET_TOKEN = (val) => {
|
||||||
|
token.value = val
|
||||||
|
}
|
||||||
|
const SET_ID = (val) => {
|
||||||
|
id.value = val
|
||||||
|
storage.set(constant.id, val)
|
||||||
|
}
|
||||||
|
const SET_NAME = (val) => {
|
||||||
|
name.value = val
|
||||||
|
storage.set(constant.name, val)
|
||||||
|
}
|
||||||
|
const SET_AVATAR = (val) => {
|
||||||
|
avatar.value = val
|
||||||
|
storage.set(constant.avatar, val)
|
||||||
|
}
|
||||||
|
const SET_ROLES = (val) => {
|
||||||
|
roles.value = val
|
||||||
|
storage.set(constant.roles, val)
|
||||||
|
}
|
||||||
|
const SET_PERMISSIONS = (val) => {
|
||||||
|
permissions.value = val
|
||||||
|
storage.set(constant.permissions, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 登录
|
||||||
|
const loginAction = (userInfo) => {
|
||||||
|
const username = userInfo.username.trim()
|
||||||
|
const password = userInfo.password
|
||||||
|
const code = userInfo.code
|
||||||
|
const uuid = userInfo.uuid
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
login(username, password, code, uuid).then(res => {
|
||||||
|
setToken(res.token)
|
||||||
|
SET_TOKEN(res.token)
|
||||||
|
resolve()
|
||||||
|
}).catch(error => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户信息
|
||||||
|
const getInfoAction = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
getInfo().then(res => {
|
||||||
|
const user = res.user
|
||||||
|
let avatar = user.avatar || ""
|
||||||
|
if (!isHttp(avatar)) {
|
||||||
|
avatar = (isEmpty(avatar)) ? defAva : baseUrl + avatar
|
||||||
|
}
|
||||||
|
const userid = (isEmpty(user) || isEmpty(user.userId)) ? "" : user.userId
|
||||||
|
const username = (isEmpty(user) || isEmpty(user.userName)) ? "" : user.userName
|
||||||
|
if (res.roles && res.roles.length > 0) {
|
||||||
|
SET_ROLES(res.roles)
|
||||||
|
SET_PERMISSIONS(res.permissions)
|
||||||
|
} else {
|
||||||
|
SET_ROLES(['ROLE_DEFAULT'])
|
||||||
|
}
|
||||||
|
SET_ID(userid)
|
||||||
|
SET_NAME(username)
|
||||||
|
SET_AVATAR(avatar)
|
||||||
|
resolve(res)
|
||||||
|
}).catch(error => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 退出系统
|
||||||
|
const logOutAction = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
logout(token.value).then(() => {
|
||||||
|
SET_TOKEN('')
|
||||||
|
SET_ROLES([])
|
||||||
|
SET_PERMISSIONS([])
|
||||||
|
removeToken()
|
||||||
|
storage.clean()
|
||||||
|
resolve()
|
||||||
|
}).catch(error => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
token,
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
avatar,
|
||||||
|
roles,
|
||||||
|
permissions,
|
||||||
|
SET_AVATAR,
|
||||||
|
login: loginAction,
|
||||||
|
getInfo: getInfoAction,
|
||||||
|
logOut: logOutAction
|
||||||
|
}
|
||||||
|
})
|
||||||
74
src/uni.scss
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
* 这里是uni-app内置的常用样式变量
|
||||||
|
*
|
||||||
|
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
|
||||||
|
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
|
||||||
|
*
|
||||||
|
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 行为相关颜色 */
|
||||||
|
$uni-color-primary: #2196F3;
|
||||||
|
$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:24rpx;
|
||||||
|
$uni-font-size-base:28rpx;
|
||||||
|
$uni-font-size-lg:32rpx;
|
||||||
|
|
||||||
|
/* 图片尺寸 */
|
||||||
|
$uni-img-size-sm:40rpx;
|
||||||
|
$uni-img-size-base:52rpx;
|
||||||
|
$uni-img-size-lg:80rpx;
|
||||||
|
|
||||||
|
/* Border Radius */
|
||||||
|
$uni-border-radius-sm: 4rpx;
|
||||||
|
$uni-border-radius-base: 6rpx;
|
||||||
|
$uni-border-radius-lg: 12rpx;
|
||||||
|
$uni-border-radius-circle: 50%;
|
||||||
|
|
||||||
|
/* 水平间距 */
|
||||||
|
$uni-spacing-row-sm: 10px;
|
||||||
|
$uni-spacing-row-base: 20rpx;
|
||||||
|
$uni-spacing-row-lg: 30rpx;
|
||||||
|
|
||||||
|
/* 垂直间距 */
|
||||||
|
$uni-spacing-col-sm: 8rpx;
|
||||||
|
$uni-spacing-col-base: 16rpx;
|
||||||
|
$uni-spacing-col-lg: 24rpx;
|
||||||
|
|
||||||
|
/* 透明度 */
|
||||||
|
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
|
||||||
|
|
||||||
|
/* 文章场景相关 */
|
||||||
|
$uni-color-title: #2C405A; // 文章标题颜色
|
||||||
|
$uni-font-size-title:40rpx;
|
||||||
|
$uni-color-subtitle: #555555; // 二级标题颜色
|
||||||
|
$uni-font-size-subtitle:36rpx;
|
||||||
|
$uni-color-paragraph: #3F536E; // 文章段落颜色
|
||||||
|
$uni-font-size-paragraph:30rpx;
|
||||||
13
src/utils/auth.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
const TokenKey = 'App-Token'
|
||||||
|
|
||||||
|
export function getToken() {
|
||||||
|
return uni.getStorageSync(TokenKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setToken(token) {
|
||||||
|
return uni.setStorageSync(TokenKey, token)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeToken() {
|
||||||
|
return uni.removeStorageSync(TokenKey)
|
||||||
|
}
|
||||||
54
src/utils/common.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* 显示消息提示框
|
||||||
|
* @param content 提示的标题
|
||||||
|
*/
|
||||||
|
export function toast(content) {
|
||||||
|
uni.showToast({
|
||||||
|
icon: 'none',
|
||||||
|
title: content
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示模态弹窗
|
||||||
|
* @param content 提示的标题
|
||||||
|
*/
|
||||||
|
export function showConfirm(content) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.showModal({
|
||||||
|
title: '提示',
|
||||||
|
content: content,
|
||||||
|
cancelText: '取消',
|
||||||
|
confirmText: '确定',
|
||||||
|
success: function(res) {
|
||||||
|
resolve(res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数处理
|
||||||
|
* @param params 参数
|
||||||
|
*/
|
||||||
|
export function tansParams(params) {
|
||||||
|
let result = ''
|
||||||
|
for (const propName of Object.keys(params)) {
|
||||||
|
const value = params[propName]
|
||||||
|
var part = encodeURIComponent(propName) + "="
|
||||||
|
if (value !== null && value !== "" && typeof (value) !== "undefined") {
|
||||||
|
if (typeof value === 'object') {
|
||||||
|
for (const key of Object.keys(value)) {
|
||||||
|
if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') {
|
||||||
|
let params = propName + '[' + key + ']'
|
||||||
|
var subPart = encodeURIComponent(params) + "="
|
||||||
|
result += subPart + encodeURIComponent(value[key]) + "&"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result += part + encodeURIComponent(value) + "&"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
9
src/utils/constant.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
const constant = {
|
||||||
|
avatar: 'user_avatar',
|
||||||
|
id: 'user_id',
|
||||||
|
name: 'user_name',
|
||||||
|
roles: 'user_roles',
|
||||||
|
permissions: 'user_permissions'
|
||||||
|
}
|
||||||
|
|
||||||
|
export default constant
|
||||||
25
src/utils/dict.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import useDictStore from "@/store/modules/dict"
|
||||||
|
import { getDicts } from "@/api/system/dict/data"
|
||||||
|
import { ref, toRefs } from "vue"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取字典数据
|
||||||
|
*/
|
||||||
|
export function useDict(...args) {
|
||||||
|
const res = ref({})
|
||||||
|
return (() => {
|
||||||
|
args.forEach((dictType, index) => {
|
||||||
|
res.value[dictType] = []
|
||||||
|
const dicts = useDictStore().getDict(dictType)
|
||||||
|
if (dicts) {
|
||||||
|
res.value[dictType] = dicts
|
||||||
|
} else {
|
||||||
|
getDicts(dictType).then((resp) => {
|
||||||
|
res.value[dictType] = resp.data.map((p) => ({ label: p.dictLabel, value: p.dictValue, elTagType: p.listClass, elTagClass: p.cssClass }))
|
||||||
|
useDictStore().setDict(dictType, res.value[dictType])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return toRefs(res.value)
|
||||||
|
})()
|
||||||
|
}
|
||||||
6
src/utils/errorCode.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
'401': '认证失败,无法访问系统资源',
|
||||||
|
'403': '当前操作没有权限',
|
||||||
|
'404': '访问资源不存在',
|
||||||
|
'default': '系统未知错误,请反馈给管理员'
|
||||||
|
}
|
||||||
51
src/utils/permission.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import store from '@/store'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字符权限校验
|
||||||
|
* @param {Array} value 校验值
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
export function checkPermi(value) {
|
||||||
|
if (value && value instanceof Array && value.length > 0) {
|
||||||
|
const permissions = store.getters && store.getters.permissions
|
||||||
|
const permissionDatas = value
|
||||||
|
const all_permission = "*:*:*"
|
||||||
|
|
||||||
|
const hasPermission = permissions.some(permission => {
|
||||||
|
return all_permission === permission || permissionDatas.includes(permission)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!hasPermission) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色权限校验
|
||||||
|
* @param {Array} value 校验值
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
export function checkRole(value) {
|
||||||
|
if (value && value instanceof Array && value.length > 0) {
|
||||||
|
const roles = store.getters && store.getters.roles
|
||||||
|
const permissionRoles = value
|
||||||
|
const super_admin = "admin"
|
||||||
|
|
||||||
|
const hasRole = roles.some(role => {
|
||||||
|
return super_admin === role || permissionRoles.includes(role)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!hasRole) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
console.error(`need roles! Like checkRole="['admin','editor']"`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
68
src/utils/request.js
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import config from '@/config'
|
||||||
|
import { getToken } from '@/utils/auth'
|
||||||
|
import errorCode from '@/utils/errorCode'
|
||||||
|
import { useUserStore } from '@/store/modules/user'
|
||||||
|
import { toast, showConfirm, tansParams } from '@/utils/common'
|
||||||
|
|
||||||
|
let timeout = 10000
|
||||||
|
const baseUrl = config.baseUrl
|
||||||
|
|
||||||
|
const request = config => {
|
||||||
|
// 是否需要设置 token
|
||||||
|
const isToken = (config.headers || {}).isToken === false
|
||||||
|
config.header = config.header || {}
|
||||||
|
if (getToken() && !isToken) {
|
||||||
|
config.header['Authorization'] = 'Bearer ' + getToken()
|
||||||
|
}
|
||||||
|
// get请求映射params参数
|
||||||
|
if (config.params) {
|
||||||
|
let url = config.url + '?' + tansParams(config.params)
|
||||||
|
url = url.slice(0, -1)
|
||||||
|
config.url = url
|
||||||
|
}
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.request({
|
||||||
|
method: config.method || 'get',
|
||||||
|
timeout: config.timeout || timeout,
|
||||||
|
url: config.baseUrl || baseUrl + config.url,
|
||||||
|
data: config.data,
|
||||||
|
header: config.header,
|
||||||
|
dataType: 'json'
|
||||||
|
}).then(response => {
|
||||||
|
const res = response
|
||||||
|
const code = res.data.code || 200
|
||||||
|
const msg = errorCode[code] || res.data.msg || errorCode['default']
|
||||||
|
if (code === 401) {
|
||||||
|
showConfirm('登录状态已过期,您可以继续留在该页面,或者重新登录?').then(res => {
|
||||||
|
if (res.confirm) {
|
||||||
|
useUserStore().logOut().then(res => {
|
||||||
|
uni.reLaunch({ url: '/pages/login' })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
reject('无效的会话,或者会话已过期,请重新登录。')
|
||||||
|
} else if (code === 500) {
|
||||||
|
toast(msg)
|
||||||
|
reject('500')
|
||||||
|
} else if (code !== 200) {
|
||||||
|
toast(msg)
|
||||||
|
reject(code)
|
||||||
|
}
|
||||||
|
resolve(res.data)
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
let { message } = error
|
||||||
|
if (message === 'Network Error') {
|
||||||
|
message = '后端接口连接异常'
|
||||||
|
} else if (message.includes('timeout')) {
|
||||||
|
message = '系统接口请求超时'
|
||||||
|
} else if (message.includes('Request failed with status code')) {
|
||||||
|
message = '系统接口' + message.substr(message.length - 3) + '异常'
|
||||||
|
}
|
||||||
|
toast(message)
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default request
|
||||||
32
src/utils/storage.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import constant from './constant'
|
||||||
|
|
||||||
|
// 存储变量名
|
||||||
|
let storageKey = 'storage_data'
|
||||||
|
|
||||||
|
// 存储节点变量名
|
||||||
|
let storageNodeKeys = [constant.avatar, constant.id, constant.name, constant.roles, constant.permissions]
|
||||||
|
|
||||||
|
const storage = {
|
||||||
|
set: function(key, value) {
|
||||||
|
if (storageNodeKeys.indexOf(key) != -1) {
|
||||||
|
let tmp = uni.getStorageSync(storageKey)
|
||||||
|
tmp = tmp ? tmp : {}
|
||||||
|
tmp[key] = value
|
||||||
|
uni.setStorageSync(storageKey, tmp)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
get: function(key) {
|
||||||
|
let storageData = uni.getStorageSync(storageKey) || {}
|
||||||
|
return storageData[key] || ""
|
||||||
|
},
|
||||||
|
remove: function(key) {
|
||||||
|
let storageData = uni.getStorageSync(storageKey) || {}
|
||||||
|
delete storageData[key]
|
||||||
|
uni.setStorageSync(storageKey, storageData)
|
||||||
|
},
|
||||||
|
clean: function() {
|
||||||
|
uni.removeStorageSync(storageKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default storage
|
||||||
70
src/utils/upload.js
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import { useUserStore } from '@/store'
|
||||||
|
import config from '@/config'
|
||||||
|
import { getToken } from '@/utils/auth'
|
||||||
|
import errorCode from '@/utils/errorCode'
|
||||||
|
import { toast, showConfirm, tansParams } from '@/utils/common'
|
||||||
|
|
||||||
|
let timeout = 10000
|
||||||
|
const baseUrl = config.baseUrl
|
||||||
|
|
||||||
|
export default function upload(config) {
|
||||||
|
// 是否需要设置 token
|
||||||
|
const isToken = (config.headers || {}).isToken === false
|
||||||
|
config.header = config.header || {}
|
||||||
|
if (getToken() && !isToken) {
|
||||||
|
config.header['Authorization'] = 'Bearer ' + getToken()
|
||||||
|
}
|
||||||
|
// get请求映射params参数
|
||||||
|
if (config.params) {
|
||||||
|
let url = config.url + '?' + tansParams(config.params)
|
||||||
|
url = url.slice(0, -1)
|
||||||
|
config.url = url
|
||||||
|
}
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.uploadFile({
|
||||||
|
timeout: config.timeout || timeout,
|
||||||
|
url: baseUrl + config.url,
|
||||||
|
filePath: config.filePath,
|
||||||
|
name: config.name || 'file',
|
||||||
|
header: config.header,
|
||||||
|
formData: config.formData,
|
||||||
|
success: (res) => {
|
||||||
|
let result = JSON.parse(res.data)
|
||||||
|
const code = result.code || 200
|
||||||
|
const msg = errorCode[code] || result.msg || errorCode['default']
|
||||||
|
if (code === 200) {
|
||||||
|
resolve(result)
|
||||||
|
} else if (code == 401) {
|
||||||
|
showConfirm("登录状态已过期,您可以继续留在该页面,或者重新登录?").then(res => {
|
||||||
|
if (res.confirm) {
|
||||||
|
useUserStore().logOut().then(res => {
|
||||||
|
uni.reLaunch({ url: '/pages/login/login' })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
reject('无效的会话,或者会话已过期,请重新登录。')
|
||||||
|
} else if (code === 500) {
|
||||||
|
toast(msg)
|
||||||
|
reject('500')
|
||||||
|
} else if (code !== 200) {
|
||||||
|
toast(msg)
|
||||||
|
reject(code)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (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.substr(message.length - 3) + '异常'
|
||||||
|
}
|
||||||
|
toast(message)
|
||||||
|
reject(error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
114
src/utils/validate.js
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
/**
|
||||||
|
* 路径匹配器
|
||||||
|
* @param {string} pattern
|
||||||
|
* @param {string} path
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
export function isPathMatch(pattern, path) {
|
||||||
|
const regexPattern = pattern.replace(/\//g, '\\/').replace(/\*\*/g, '.*').replace(/\*/g, '[^\\/]*')
|
||||||
|
const regex = new RegExp(`^${regexPattern}$`)
|
||||||
|
return regex.test(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断value字符串是否为空
|
||||||
|
* @param {string} value
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
export function isEmpty(value) {
|
||||||
|
if (value == null || value == "" || value == undefined || value == "undefined") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断url是否是http或https
|
||||||
|
* @param {string} url
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
export function isHttp(url) {
|
||||||
|
return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断path是否为外链
|
||||||
|
* @param {string} path
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
export function isExternal(path) {
|
||||||
|
return /^(https?:|mailto:|tel:)/.test(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} str
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
export function validUsername(str) {
|
||||||
|
const valid_map = ['admin', 'editor']
|
||||||
|
return valid_map.indexOf(str.trim()) >= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} url
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
export function validURL(url) {
|
||||||
|
const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
|
||||||
|
return reg.test(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} str
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
export function validLowerCase(str) {
|
||||||
|
const reg = /^[a-z]+$/
|
||||||
|
return reg.test(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} str
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
export function validUpperCase(str) {
|
||||||
|
const reg = /^[A-Z]+$/
|
||||||
|
return reg.test(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} str
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
export function validAlphabets(str) {
|
||||||
|
const reg = /^[A-Za-z]+$/
|
||||||
|
return reg.test(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} email
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
export function validEmail(email) {
|
||||||
|
const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
||||||
|
return reg.test(email)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} str
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
export function isString(str) {
|
||||||
|
return typeof str === 'string' || str instanceof String
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array} arg
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
export function isArray(arg) {
|
||||||
|
if (typeof Array.isArray === 'undefined') {
|
||||||
|
return Object.prototype.toString.call(arg) === '[object Array]'
|
||||||
|
}
|
||||||
|
return Array.isArray(arg)
|
||||||
|
}
|
||||||
14
vite.config.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import uni from '@dcloudio/vite-plugin-uni'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
uni()
|
||||||
|
],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
// 确保uni-app使用内置的Vue版本
|
||||||
|
'vue': '@dcloudio/uni-h5-vue'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||