提交 33a53258 authored 作者: lidongxu's avatar lidongxu

开发考勤打卡功能

上级 17f51236
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
methods: { methods: {
// 初始化应用 // 初始化应用
initApp() { initApp() {
// 初始化应用配置 // 初始化应用配置
this.initConfig() this.initConfig()
// 检查用户登录状态 // 检查用户登录状态
//#ifdef H5 //#ifdef H5
......
import request from '@/utils/request.js'
/**
* 获取考勤规则详情
*/
export const getAttendanceDetail = (ruleId) => {
return request({
url: `/system/kq_rule/${ruleId}`
})
}
\ No newline at end of file
export * from './map.js'
\ No newline at end of file
import request from '@/utils/request.js'
import {
mapBaseUrl,
mapKey,
coordtype
} from '@/config.js'
import { tansParams } from '@/utils/common.js'
// 所有服务均基于 百度地图
/**
* 逆地理位置编码
*/
export const reverseGeocoding = ({
params
}) => {
const urlParams = tansParams(params)
return request({
baseUrl: mapBaseUrl + `/reverse_geocoding/v3/?ak=${mapKey}&output=json&coordtype=${coordtype}&${urlParams}`
})
}
\ No newline at end of file
...@@ -9,7 +9,7 @@ export function login(username, password, code, uuid) { ...@@ -9,7 +9,7 @@ export function login(username, password, code, uuid) {
uuid uuid
} }
return request({ return request({
'url': '/login', 'url': '/auth/login',
headers: { headers: {
isToken: false isToken: false
}, },
...@@ -21,7 +21,7 @@ export function login(username, password, code, uuid) { ...@@ -21,7 +21,7 @@ export function login(username, password, code, uuid) {
// 注册方法 // 注册方法
export function register(data) { export function register(data) {
return request({ return request({
url: '/register', url: '/auth/register',
headers: { headers: {
isToken: false isToken: false
}, },
...@@ -33,7 +33,7 @@ export function register(data) { ...@@ -33,7 +33,7 @@ export function register(data) {
// 获取用户详细信息 // 获取用户详细信息
export function getInfo() { export function getInfo() {
return request({ return request({
'url': '/getInfo', 'url': '/system/user/getInfo',
'method': 'get' 'method': 'get'
}) })
} }
...@@ -41,7 +41,7 @@ export function getInfo() { ...@@ -41,7 +41,7 @@ export function getInfo() {
// 退出方法 // 退出方法
export function logout() { export function logout() {
return request({ return request({
'url': '/logout', 'url': '/auth/logout',
'method': 'post' 'method': 'post'
}) })
} }
...@@ -49,7 +49,7 @@ export function logout() { ...@@ -49,7 +49,7 @@ export function logout() {
// 获取验证码 // 获取验证码
export function getCodeImg() { export function getCodeImg() {
return request({ return request({
'url': '/captchaImage', 'url': '/auth/captchaImage',
headers: { headers: {
isToken: false isToken: false
}, },
......
<template> <template>
<view class="uni-section"> <view class="uni-section">
<view class="uni-section-header" @click="onClick"> <view class="uni-section-header" @click="onClick">
<view class="uni-section-header__decoration" v-if="type" :class="type" /> <view class="uni-section-header__decoration" v-if="type" :class="type" />
<slot v-else name="decoration"></slot> <slot v-else name="decoration"></slot>
<view class="uni-section-header__content"> <view class="uni-section-header__content">
<text :style="{'font-size':titleFontSize,'color':titleColor}" class="uni-section__content-title" :class="{'distraction':!subTitle}">{{ title }}</text> <text :style="{'font-size':titleFontSize,'color':titleColor}" class="uni-section__content-title"
<text v-if="subTitle" :style="{'font-size':subTitleFontSize,'color':subTitleColor}" class="uni-section-header__content-sub">{{ subTitle }}</text> :class="{'distraction':!subTitle}">{{ title }}</text>
</view> <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"> <view class="uni-section-header__slot-right">
<slot name="right"></slot> <slot name="right"></slot>
</view> </view>
</view> </view>
<view class="uni-section-content" :style="{padding: _padding}"> <view class="uni-section-content" :style="{padding: _padding}">
...@@ -21,7 +23,6 @@ ...@@ -21,7 +23,6 @@
</template> </template>
<script> <script>
/** /**
* Section 标题栏 * Section 标题栏
* @description 标题栏 * @description 标题栏
...@@ -40,7 +41,7 @@ ...@@ -40,7 +41,7 @@
export default { export default {
name: 'UniSection', name: 'UniSection',
emits:['click'], emits: ['click'],
props: { props: {
type: { type: {
type: String, type: String,
...@@ -51,11 +52,11 @@ ...@@ -51,11 +52,11 @@
required: true, required: true,
default: '' default: ''
}, },
titleFontSize: { titleFontSize: {
type: String, type: String,
default: '14px' default: '14px'
}, },
titleColor:{ titleColor: {
type: String, type: String,
default: '#333' default: '#333'
}, },
...@@ -63,28 +64,28 @@ ...@@ -63,28 +64,28 @@
type: String, type: String,
default: '' default: ''
}, },
subTitleFontSize: { subTitleFontSize: {
type: String, type: String,
default: '12px' default: '12px'
}, },
subTitleColor: { subTitleColor: {
type: String, type: String,
default: '#999' default: '#999'
}, },
padding: { padding: {
type: [Boolean, String], type: [Boolean, String],
default: false default: false
} }
}, },
computed:{ computed: {
_padding(){ _padding() {
if(typeof this.padding === 'string'){ if (typeof this.padding === 'string') {
return this.padding return this.padding
} }
return this.padding?'10px':'' return this.padding ? '10px' : ''
} }
}, },
watch: { watch: {
title(newVal) { title(newVal) {
if (uni.report && newVal !== '') { if (uni.report && newVal !== '') {
...@@ -92,76 +93,79 @@ ...@@ -92,76 +93,79 @@
} }
} }
}, },
methods: { methods: {
onClick() { onClick() {
this.$emit('click') this.$emit('click')
} }
} }
} }
</script> </script>
<style lang="scss" > <style lang="scss">
$uni-primary: #2979ff !default; $uni-primary: #2979ff !default;
.uni-section { .uni-section {
background-color: #fff; background-color: #fff;
.uni-section-header {
position: relative; .uni-section-header {
/* #ifndef APP-NVUE */ position: relative;
display: flex; /* #ifndef APP-NVUE */
/* #endif */ display: flex;
flex-direction: row; /* #endif */
align-items: center; flex-direction: row;
padding: 12px 10px; align-items: center;
font-weight: normal; padding: 12px 10px;
font-weight: normal;
&__decoration{
margin-right: 6px; &__decoration {
background-color: $uni-primary; margin-right: 6px;
&.line { background-color: $uni-primary;
width: 4px;
height: 12px; &.line {
border-radius: 10px; width: 4px;
} height: 12px;
border-radius: 10px;
&.circle { }
width: 8px;
height: 8px; &.circle {
border-top-right-radius: 50px; width: 8px;
border-top-left-radius: 50px; height: 8px;
border-bottom-left-radius: 50px; border-top-right-radius: 50px;
border-bottom-right-radius: 50px; border-top-left-radius: 50px;
} border-bottom-left-radius: 50px;
border-bottom-right-radius: 50px;
&.square { }
width: 8px;
height: 8px; &.square {
} width: 8px;
} height: 8px;
}
&__content { }
/* #ifndef APP-NVUE */
display: flex; &__content {
/* #endif */ /* #ifndef APP-NVUE */
flex-direction: column; display: flex;
flex: 1; /* #endif */
color: #333; flex-direction: column;
flex: 1;
.distraction { color: #333;
flex-direction: row;
align-items: center; .distraction {
} flex-direction: row;
&-sub { align-items: center;
margin-top: 2px; }
}
} &-sub {
margin-top: 2px;
&__slot-right{ }
font-size: 14px; }
}
} &__slot-right {
font-size: 14px;
.uni-section-content{ }
font-size: 14px; }
}
.uni-section-content {
font-size: 14px;
}
} }
</style> </style>
\ No newline at end of file
// 应用全局配置 // 应用全局配置
module.exports = { module.exports = {
baseUrl: 'https://vue.ruoyi.vip/prod-api', // baseUrl: 'https://vue.ruoyi.vip/prod-api',
// baseUrl: 'http://localhost:8080', mapBaseUrl: 'https://api.map.baidu.com',
mapKey: 'mryaav7xyp0Z3ItwUT3oMssYAmG8sTSU',
coordtype: 'gcj02', // 坐标类型(小程序获取和百度地图 API 使用类型要对应上)
// baseUrl: 'http://192.168.100.39:8080/api',
// baseUrl: 'http://localhost:8080',
baseUrl: 'http://192.168.140.189:8080', // 局域网请求
// 应用信息 // 应用信息
appInfo: { appInfo: {
// 应用名称 // 应用名称
......
...@@ -14,4 +14,4 @@ const app = new Vue({ ...@@ -14,4 +14,4 @@ const app = new Vue({
...App ...App
}) })
app.$mount() app.$mount()
{ {
"name" : "若依移动端", "name": "若依移动端",
"appid" : "__UNI__25A9D80", "appid": "__UNI__EF8B6D6",
"description" : "", "description": "",
"versionName" : "1.1.0", "versionName": "1.1.0",
"versionCode" : "100", "versionCode": "100",
"transformPx" : false, "transformPx": false,
"app-plus" : { "app-plus": {
"usingComponents" : true, "usingComponents": true,
"nvueCompiler" : "uni-app", "nvueCompiler": "uni-app",
"splashscreen" : { "splashscreen": {
"alwaysShowBeforeRender" : true, "alwaysShowBeforeRender": true,
"waiting" : true, "waiting": true,
"autoclose" : true, "autoclose": true,
"delay" : 0 "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" : {}, "modules": {},
"mp-weixin" : { "distribute": {
"appid" : "wxccd7e2a0911b3397", "android": {
"setting" : { "permissions": [
"urlCheck" : false, "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"es6" : false, "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"minified" : true, "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"postcss" : true "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
}, "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"optimization" : { "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"subPackages" : true "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
}, "<uses-permission android:name=\"android.permission.CAMERA\"/>",
"usingComponents" : true "<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": "wxb22cd2d07f55e295",
"setting": {
"urlCheck": false,
"es6": false,
"minified": true,
"postcss": true
},
"optimization": {
"subPackages": true
},
"usingComponents": true,
"requiredPrivateInfos": [
"chooseAddress",
"getLocation",
"chooseLocation"
],
"permission": {
"scope.userLocation": {
"desc": "你的位置信息将用于考勤打卡定位"
}
}
},
"vueVersion": "2",
"h5": {
"template": "static/index.html",
"devServer": {
"port": 9090,
"https": false
}, },
"vueVersion" : "2", "title": "RuoYi-App",
"h5" : { "router": {
"template" : "static/index.html", "mode": "hash",
"devServer" : { "base": "./"
"port" : 9090,
"https" : false
},
"title" : "RuoYi-App",
"router" : {
"mode" : "hash",
"base" : "./"
}
} }
} }
}
\ No newline at end of file
{ {
"pages": [{ "pages": [
"path": "pages/login", {
"style": { "path": "pages/login",
"navigationBarTitleText": "登录" "style": {
} "navigationBarTitleText": "登录"
}, { }
"path": "pages/register", },
"style": { {
"navigationBarTitleText": "注册" "path": "pages/index",
} "style": {
}, { "navigationStyle": "custom"
"path": "pages/index", }
"style": { },
"navigationBarTitleText": "若依移动端框架", {
"navigationStyle": "custom" "path": "pages/attendance/index",
} "style": {
}, { "navigationBarTitleText": "考勤打卡"
"path": "pages/work/index", }
"style": { },
"navigationBarTitleText": "工作台" {
} "path": "pages/work/index",
}, { "style": {
"path": "pages/mine/index", "navigationBarTitleText": "工作台"
"style": { }
"navigationBarTitleText": "我的" },
}
}, { {
"path": "pages/mine/avatar/index", "path": "pages/register",
"style": { "style": {
"navigationBarTitleText": "修改头像" "navigationBarTitleText": "注册"
} }
}, { },
"path": "pages/mine/info/index", {
"style": { "path": "pages/mine/index",
"navigationBarTitleText": "个人信息" "style": {
} "navigationBarTitleText": "我的"
}, { }
"path": "pages/mine/info/edit", },
"style": { {
"navigationBarTitleText": "编辑资料" "path": "pages/mine/avatar/index",
} "style": {
}, { "navigationBarTitleText": "修改头像"
"path": "pages/mine/pwd/index", }
"style": { },
"navigationBarTitleText": "修改密码" {
} "path": "pages/mine/info/index",
}, { "style": {
"path": "pages/mine/setting/index", "navigationBarTitleText": "个人信息"
"style": { }
"navigationBarTitleText": "应用设置" },
} {
}, { "path": "pages/mine/info/edit",
"path": "pages/mine/help/index", "style": {
"style": { "navigationBarTitleText": "编辑资料"
"navigationBarTitleText": "常见问题" }
} },
}, { {
"path": "pages/mine/about/index", "path": "pages/mine/pwd/index",
"style": { "style": {
"navigationBarTitleText": "关于我们" "navigationBarTitleText": "修改密码"
} }
}, { },
"path": "pages/common/webview/index", {
"style": { "path": "pages/mine/setting/index",
"navigationBarTitleText": "浏览网页" "style": {
} "navigationBarTitleText": "应用设置"
}, { }
"path": "pages/common/textview/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": { "tabBar": {
"color": "#000000", "color": "#000000",
"selectedColor": "#000000", "selectedColor": "#000000",
"borderStyle": "white", "borderStyle": "white",
"backgroundColor": "#ffffff", "backgroundColor": "#ffffff",
"list": [{ "list": [
{
"pagePath": "pages/index", "pagePath": "pages/index",
"iconPath": "static/images/tabbar/home.png", "iconPath": "static/images/tabbar/home.png",
"selectedIconPath": "static/images/tabbar/home_.png", "selectedIconPath": "static/images/tabbar/home_.png",
"text": "首页" "text": "首页"
}, { },
{
"pagePath": "pages/work/index", "pagePath": "pages/work/index",
"iconPath": "static/images/tabbar/work.png", "iconPath": "static/images/tabbar/work.png",
"selectedIconPath": "static/images/tabbar/work_.png", "selectedIconPath": "static/images/tabbar/work_.png",
"text": "工作台" "text": "工作台"
}, { },
{
"pagePath": "pages/mine/index", "pagePath": "pages/mine/index",
"iconPath": "static/images/tabbar/mine.png", "iconPath": "static/images/tabbar/mine.png",
"selectedIconPath": "static/images/tabbar/mine_.png", "selectedIconPath": "static/images/tabbar/mine_.png",
...@@ -97,6 +121,8 @@ ...@@ -97,6 +121,8 @@
"globalStyle": { "globalStyle": {
"navigationBarTextStyle": "black", "navigationBarTextStyle": "black",
"navigationBarTitleText": "RuoYi", "navigationBarTitleText": "RuoYi",
"navigationBarBackgroundColor": "#FFFFFF" "navigationBarBackgroundColor": "#FFFFFF",
"backgroundColor": "#FFFFFF"
} }
}
}
\ No newline at end of file
<template>
<view class="wrap">
<div class="button_wrap">
<button v-for="obj in attTimeKeyList" :class="obj.disabled ? 'workbtn_disabled' : obj.class"
:disabled="obj.disabled">{{ obj.title }}</button>
</div>
</view>
</template>
<script>
import { getAttendanceDetail } from '@/api/attendance'
import { checkStartLessEndTime } from '@/utils/common'
export default {
data() {
return {
attTimeKeyList: [{ // 需要考勤列表
beginKey: 'firBegintime',
beginValue: '',
endKey: 'firEndtime',
endValue: '',
class: 'go_work',
title: '上班打卡',
disabled: false // 是否可以交互
},
{
beginKey: 'secBegintime',
beginValue: '',
endKey: 'secEndtime',
endValue: '',
class: 'after_work',
title: '午班打卡',
disabled: false
},
{
beginKey: 'thiBegintime',
beginValue: '',
endKey: 'thiEndtime',
endValue: '',
class: 'off_work',
title: '下班打卡',
disabled: false
}]
}
},
created() {
this.getRuleInfo()
},
methods: {
async getRuleInfo() {
// 需要提取打卡的时间
const { data } = await getAttendanceDetail(this.$store.getters.user.ruleId)
this.attTimeKeyList.forEach(obj => {
obj['beginValue'] = data[obj.beginKey]
obj['endValue'] = data[obj.endKey]
// 判断服务器时间
obj['disabled'] = checkStartLessEndTime(data[obj.endKey], data.currently)
})
}
}
}
</script>
<style scoped lang="scss">
.wrap {
background-color: #f0f1f3;
height: 100vh;
.button_wrap {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 50rpx;
.go_work,
.after_work,
.off_work,
.workbtn_disabled {
width: 250rpx;
height: 250rpx;
border-radius: 50%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
}
.workbtn_disabled {
background-color: #c7c8c8;
}
.go_work {
background-color: #32cdbf;
}
.after_work {
background-color: #e0bd47;
}
.off_work {
background-color: #5dabed;
}
}
}
</style>
<template> <template>
<view class="content"> <view class="wrap">
<image class="logo" src="@/static/logo.png"></image> <uni-nav-bar dark :fixed="true" shadow background-color="#007AFF" status-bar title="首页" />
<view class="text-area"> <uni-section class="section" title="基础分组" padding>
<text class="title">Hello RuoYi</text> <uni-grid :column="4" :showBorder="false">
</view> <uni-grid-item>
<view class="grid-item-box">
<uni-icons type="list" :size="30" color="#777" />
<text class="text">网点列表</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<uni-icons type="folder-add" :size="30" color="#777" />
<text class="text">新增网点</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<uni-icons type="person-filled" :size="30" color="#777" />
<text class="text">经销商列表</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<uni-icons type="shop-filled" :size="30" color="#777" />
<text class="text">新增二批商</text>
</view>
</uni-grid-item>
</uni-grid>
</uni-section>
<uni-section class="section" title="拜访分组" padding>
<uni-grid :column="4" :showBorder="false">
<uni-grid-item>
<view class="grid-item-box">
<uni-icons type="home" :size="30" color="#777" />
<text class="text">网点拜访</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<uni-icons type="settings" :size="30" color="#777" />
<text class="text">经销商拜访</text>
</view>
</uni-grid-item>
</uni-grid>
</uni-section>
<uni-section class="section" title="日常分组" padding>
<uni-grid :column="4" :showBorder="false">
<uni-grid-item>
<view class="grid-item-box">
<uni-icons type="upload-filled" :size="30" color="#777" />
<text class="text">付费阵列上报</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box" @click="addendanceClick">
<uni-icons type="compose" :size="30" color="#777" />
<text class="text">考勤打卡</text>
</view>
</uni-grid-item>
</uni-grid>
</uni-section>
</view> </view>
</template> </template>
<script> <script>
export default { import { reverseGeocoding } from '@/api/common'
onLoad: function() { export default {
onLoad: function () { },
methods: {
addendanceClick() {
// getLocation 获取经纬度
// chooseLocation 让用户在地图手选位置
uni.getLocation({
success: async (res) => {
const result = await reverseGeocoding({
params: {
location: res.latitude + "," + res.longitude
}
})
// 判断用户位置和获取位置-城市是否一致
if (result.result.addressComponent.city.startsWith(this.$store.getters.user.workCityName)) {
// 跳转到打卡页面
this.$tab.navigateTo('/pages/attendance/index')
} else {
// 不一致,提示
this.$modal.msgError("工作地点与定位地点不同");
}
}
})
} }
} }
}
</script> </script>
<style> <style scoped lang="scss">
.content { .wrap {
display: flex; height: 100vh;
flex-direction: column; background-color: #f7f8fa;
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 { .section {
display: flex; background-color: white;
justify-content: center;
}
.title { .grid-item-box {
font-size: 36rpx; height: 100%;
color: #8f8f94; background-color: white;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
} }
</style> }
</style>
\ No newline at end of file
...@@ -17,23 +17,23 @@ ...@@ -17,23 +17,23 @@
<view class="input-item flex align-center" style="width: 60%;margin: 0px;" v-if="captchaEnabled"> <view class="input-item flex align-center" style="width: 60%;margin: 0px;" v-if="captchaEnabled">
<view class="iconfont icon-code icon"></view> <view class="iconfont icon-code icon"></view>
<input v-model="loginForm.code" type="number" class="input" placeholder="请输入验证码" maxlength="4" /> <input v-model="loginForm.code" type="number" class="input" placeholder="请输入验证码" maxlength="4" />
<view class="login-code"> <view class="login-code">
<image :src="codeUrl" @click="getCode" class="login-code-img"></image> <image :src="codeUrl" @click="getCode" class="login-code-img"></image>
</view> </view>
</view> </view>
<view class="action-btn"> <view class="action-btn">
<button @click="handleLogin" class="login-btn cu-btn block bg-blue lg round">登录</button> <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> <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> </view>
</template> </template>
...@@ -45,25 +45,26 @@ ...@@ -45,25 +45,26 @@
data() { data() {
return { return {
codeUrl: "", codeUrl: "",
captchaEnabled: true, captchaEnabled: false,
// 用户注册开关 // 用户注册开关
register: false, register: false,
globalConfig: getApp().globalData.config, globalConfig: getApp().globalData.config,
loginForm: { loginForm: {
username: "admin", username: "testlql01",
password: "admin123", password: "123456",
code: "", // code: "",
uuid: '' uuid: ''
} }
} }
}, },
created() { created() {
this.getCode() // this.getCode()
}, },
methods: { methods: {
// 用户注册 // 用户注册
handleUserRegister() { handleUserRegister() {
this.$tab.redirectTo(`/pages/register`) this.$tab.redirectTo(`/pages/register`)
}, },
// 隐私协议 // 隐私协议
handlePrivacy() { handlePrivacy() {
...@@ -91,9 +92,11 @@ ...@@ -91,9 +92,11 @@
this.$modal.msgError("请输入您的账号") this.$modal.msgError("请输入您的账号")
} else if (this.loginForm.password === "") { } else if (this.loginForm.password === "") {
this.$modal.msgError("请输入您的密码") this.$modal.msgError("请输入您的密码")
} else if (this.loginForm.code === "" && this.captchaEnabled) { }
this.$modal.msgError("请输入验证码") // else if (this.loginForm.code === "" && this.captchaEnabled) {
} else { // this.$modal.msgError("请输入验证码")
// }
else {
this.$modal.loading("登录中,请耐心等待...") this.$modal.loading("登录中,请耐心等待...")
this.pwdLogin() this.pwdLogin()
} }
...@@ -175,28 +178,28 @@ ...@@ -175,28 +178,28 @@
margin-top: 40px; margin-top: 40px;
height: 45px; height: 45px;
} }
.reg { .reg {
margin-top: 15px; margin-top: 15px;
} }
.xieyi { .xieyi {
color: #333; color: #333;
margin-top: 20px; margin-top: 20px;
} }
.login-code { .login-code {
height: 38px; height: 38px;
float: right; float: right;
.login-code-img { .login-code-img {
height: 38px; height: 38px;
position: absolute; position: absolute;
margin-left: 10px; margin-left: 10px;
width: 200rpx; width: 200rpx;
} }
} }
} }
} }
</style> </style>
<template> <template>
<view class="work-container"> <view class="work-container">
<!-- 轮播图 --> <!-- 轮播图 -->
<uni-swiper-dot class="uni-swiper-dot-box" :info="data" :current="current" field="content"> <uni-swiper-dot class="uni-swiper-dot-box" :info="data" :current="current" field="content">
<swiper class="swiper-box" :current="swiperDotIndex" @change="changeSwiper"> <swiper class="swiper-box" :current="swiperDotIndex" @change="changeSwiper">
...@@ -75,109 +76,115 @@ ...@@ -75,109 +76,115 @@
</template> </template>
<script> <script>
export default { export default {
data() { data() {
return { return {
current: 0, current: 0,
swiperDotIndex: 0, swiperDotIndex: 0,
data: [{ data: [{
image: '/static/images/banner/banner01.jpg' image: '/static/images/banner/banner01.jpg'
},
{
image: '/static/images/banner/banner02.jpg'
},
{
image: '/static/images/banner/banner03.jpg'
}
]
}
},
methods: {
clickBannerItem(item) {
console.info(item)
}, },
changeSwiper(e) { {
this.current = e.detail.current image: '/static/images/banner/banner02.jpg'
}, },
changeGrid(e) { {
this.$modal.showToast('模块建设中~') image: '/static/images/banner/banner03.jpg'
} }
]
}
},
methods: {
clickBannerItem(item) {
console.info(item)
},
changeSwiper(e) {
this.current = e.detail.current
},
changeGrid(e) {
this.$modal.showToast('模块建设中~')
// uni.setTabBarItem({
// index: 1, // tabIndex,tabbar列表的索引,从0开始
// text: '我的消息', // 更新后的文字
// iconPath: '/static/message-icon.png', // 更新后的图标路径
// selectedIconPath: '/static/message-icon-active.png' // 更新后的选中图标路径
// });
} }
} }
}
</script> </script>
<style lang="scss"> <style lang="scss">
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
page { page {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
box-sizing: border-box; box-sizing: border-box;
background-color: #fff; background-color: #fff;
min-height: 100%; min-height: 100%;
height: auto; height: auto;
} }
view { view {
font-size: 14px; font-size: 14px;
line-height: inherit; line-height: inherit;
} }
/* #endif */ /* #endif */
.text { .text {
text-align: center; text-align: center;
font-size: 26rpx; font-size: 26rpx;
margin-top: 10rpx; margin-top: 10rpx;
} }
.grid-item-box { .grid-item-box {
flex: 1; flex: 1;
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
display: flex; display: flex;
/* #endif */ /* #endif */
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 15px 0; padding: 15px 0;
} }
.uni-margin-wrap { .uni-margin-wrap {
width: 690rpx; width: 690rpx;
width: 100%; width: 100%;
; ;
} }
.swiper { .swiper {
height: 300rpx; height: 300rpx;
} }
.swiper-box { .swiper-box {
height: 150px; height: 150px;
} }
.swiper-item { .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 */ /* #ifndef APP-NVUE */
display: flex; margin: 0 auto;
/* #endif */ /* #endif */
flex-direction: column; margin-top: 8px;
justify-content: center;
align-items: center;
color: #fff;
height: 300rpx;
line-height: 300rpx;
} }
@media screen and (min-width: 500px) { .image {
.uni-swiper-dot-box { width: 100%;
width: 400px;
/* #ifndef APP-NVUE */
margin: 0 auto;
/* #endif */
margin-top: 8px;
}
.image {
width: 100%;
}
} }
}
</style> </style>
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
// 登录页面 // 登录页面
const loginPage = "/pages/login" const loginPage = "/pages/login"
// 页面白名单 // 页面白名单
...@@ -17,6 +17,7 @@ function checkWhite(url) { ...@@ -17,6 +17,7 @@ function checkWhite(url) {
// 页面跳转验证拦截器 // 页面跳转验证拦截器
let list = ["navigateTo", "redirectTo", "reLaunch", "switchTab"] let list = ["navigateTo", "redirectTo", "reLaunch", "switchTab"]
list.forEach(item => { list.forEach(item => {
// 全局添加 API 属性等(拦截路由)
uni.addInterceptor(item, { uni.addInterceptor(item, {
invoke(to) { invoke(to) {
if (getToken()) { if (getToken()) {
...@@ -28,6 +29,7 @@ list.forEach(item => { ...@@ -28,6 +29,7 @@ list.forEach(item => {
if (checkWhite(to.url)) { if (checkWhite(to.url)) {
return true return true
} }
console.log(to.url)
uni.reLaunch({ url: loginPage }) uni.reLaunch({ url: loginPage })
return false return false
} }
...@@ -36,4 +38,4 @@ list.forEach(item => { ...@@ -36,4 +38,4 @@ list.forEach(item => {
console.log(err) console.log(err)
} }
}) })
}) })
import store from '@/store'
export default { export default {
// 消息提示 // 消息提示
msg(content) { msg(content) {
...@@ -10,7 +11,8 @@ export default { ...@@ -10,7 +11,8 @@ export default {
msgError(content) { msgError(content) {
uni.showToast({ uni.showToast({
title: content, title: content,
icon: 'error' icon: 'none',
duration: store.getters.delayTime
}) })
}, },
// 成功消息 // 成功消息
...@@ -71,4 +73,4 @@ export default { ...@@ -71,4 +73,4 @@ export default {
closeLoading() { closeLoading() {
uni.hideLoading() uni.hideLoading()
} }
} }
{
"appid": "wx5474d56c6eea0083",
"compileType": "miniprogram",
"libVersion": "3.6.4",
"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
}
}
\ No newline at end of file
{
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"projectname": "ruoyi-uni",
"setting": {
"compileHotReLoad": true
}
}
\ No newline at end of file
const getters = { const getters = {
token: state => state.user.token, token: state => state.user.token,
avatar: state => state.user.avatar, avatar: state => state.user.avatar,
user: state => state.user.user,
name: state => state.user.name, name: state => state.user.name,
roles: state => state.user.roles, roles: state => state.user.roles,
permissions: state => state.user.permissions permissions: state => state.user.permissions,
delayTime: state => 3000 // 延迟弹窗关闭时间
} }
export default getters export default getters
...@@ -12,7 +12,8 @@ const user = { ...@@ -12,7 +12,8 @@ const user = {
name: storage.get(constant.name), name: storage.get(constant.name),
avatar: storage.get(constant.avatar), avatar: storage.get(constant.avatar),
roles: storage.get(constant.roles), roles: storage.get(constant.roles),
permissions: storage.get(constant.permissions) permissions: storage.get(constant.permissions),
user: storage.get(constant.user)
}, },
mutations: { mutations: {
...@@ -34,6 +35,10 @@ const user = { ...@@ -34,6 +35,10 @@ const user = {
SET_PERMISSIONS: (state, permissions) => { SET_PERMISSIONS: (state, permissions) => {
state.permissions = permissions state.permissions = permissions
storage.set(constant.permissions, permissions) storage.set(constant.permissions, permissions)
},
SET_USER: (state, user) => {
state.user = user
storage.set(constant.user, user)
} }
}, },
...@@ -46,8 +51,8 @@ const user = { ...@@ -46,8 +51,8 @@ const user = {
const uuid = userInfo.uuid const uuid = userInfo.uuid
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
login(username, password, code, uuid).then(res => { login(username, password, code, uuid).then(res => {
setToken(res.token) setToken(res.data.access_token)
commit('SET_TOKEN', res.token) commit('SET_TOKEN', res.data.access_token)
resolve() resolve()
}).catch(error => { }).catch(error => {
reject(error) reject(error)
...@@ -70,6 +75,7 @@ const user = { ...@@ -70,6 +75,7 @@ const user = {
} }
commit('SET_NAME', username) commit('SET_NAME', username)
commit('SET_AVATAR', avatar) commit('SET_AVATAR', avatar)
commit('SET_USER', user)
resolve(res) resolve(res)
}).catch(error => { }).catch(error => {
reject(error) reject(error)
...@@ -95,4 +101,4 @@ const user = { ...@@ -95,4 +101,4 @@ const user = {
} }
} }
export default user export default user
/** /**
* 显示消息提示框 * 显示消息提示框
* @param content 提示的标题 * @param content 提示的标题
*/ */
export function toast(content) { export function toast(content) {
uni.showToast({ uni.showToast({
icon: 'none', icon: 'none',
title: content title: content
}) })
} }
/** /**
* 显示模态弹窗 * 显示模态弹窗
* @param content 提示的标题 * @param content 提示的标题
*/ */
export function showConfirm(content) { export function showConfirm(content) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
uni.showModal({ uni.showModal({
title: '提示', title: '提示',
content: content, content: content,
cancelText: '取消', cancelText: '取消',
confirmText: '确定', confirmText: '确定',
success: function(res) { success: function (res) {
resolve(res) resolve(res)
} }
}) })
}) })
} }
/** /**
* 参数处理 * 参数处理
* @param params 参数 * @param params 参数
...@@ -51,4 +51,19 @@ export function tansParams(params) { ...@@ -51,4 +51,19 @@ export function tansParams(params) {
} }
} }
return result return result
}
// 判断时间 1 是否小于时间 2
export function checkStartLessEndTime(startTime, endTime) {
if (startTime === null || startTime?.length === 0 || endTime === null) return true
// 把数组里的空值过滤掉
const startDate = new Date()
startDate.setHours(startTime.split(":")[0])
startDate.setMinutes(startTime.split(":")[1])
startDate.setSeconds(startTime.split(":")[2])
const endDate = new Date()
endDate.setHours(endTime.split(":")[0])
endDate.setMinutes(endTime.split(":")[1])
endDate.setSeconds(endTime.split(":")[2])
return startDate.getTime() - endDate.getTime() < 0
} }
\ No newline at end of file
...@@ -2,7 +2,8 @@ const constant = { ...@@ -2,7 +2,8 @@ const constant = {
avatar: 'vuex_avatar', avatar: 'vuex_avatar',
name: 'vuex_name', name: 'vuex_name',
roles: 'vuex_roles', roles: 'vuex_roles',
permissions: 'vuex_permissions' permissions: 'vuex_permissions',
user: 'vuex_user'
} }
export default constant export default constant
...@@ -70,4 +70,4 @@ const request = config => { ...@@ -70,4 +70,4 @@ const request = config => {
}) })
} }
export default request export default request
...@@ -4,7 +4,7 @@ import constant from './constant' ...@@ -4,7 +4,7 @@ import constant from './constant'
let storageKey = 'storage_data' let storageKey = 'storage_data'
// 存储节点变量名 // 存储节点变量名
let storageNodeKeys = [constant.avatar, constant.name, constant.roles, constant.permissions] let storageNodeKeys = [constant.avatar, constant.name, constant.roles, constant.permissions, constant.user]
const storage = { const storage = {
set: function(key, value) { set: function(key, value) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论