提交 ee74a7a3 authored 作者: lidongxu's avatar lidongxu

小卤促销平台欢迎页和登录页包括快速获取手机号作为判断是否登录的凭证

上级 77522525
<script>
import config from './config'
import store from '@/store'
import { getToken } from '@/utils/auth'
export default {
......@@ -14,7 +13,7 @@
this.initConfig()
// 检查用户登录状态
//#ifdef H5
this.checkLogin()
// this.checkLogin()
//#endif
},
initConfig() {
......@@ -31,4 +30,4 @@
<style lang="scss">
@import '@/static/scss/index.scss'
</style>
</style>
......@@ -4,9 +4,10 @@ module.exports = {
mapBaseUrl: 'https://api.map.baidu.com',
mapKey: 'mryaav7xyp0Z3ItwUT3oMssYAmG8sTSU',
coordtype: 'gcj02', // 坐标类型(小程序获取和百度地图 API 使用类型要对应上)
baseUrl: 'http://192.168.100.39:8080',
// baseUrl: 'http://localhost:8080',
// baseUrl: 'http://192.168.140.189:8080', // 局域网请求
baseUrl: 'http://192.168.140.189:8080', // 局域网请求
// baseUrl: 'http://sfa.test.wxl66.cn:85/api', // 上线测试
// baseUrl: 'http://111.198.15.68:85/api',
// 应用信息
appInfo: {
// 应用名称
......
......@@ -3,8 +3,23 @@ import App from './App'
import store from './store' // store
import plugins from './plugins' // plugins
import './permission' // permission
import * as auth from './utils/auth.js'
Vue.use(plugins)
// 获取 access_token
const appid = 'wx5d89065bb4725557'
const secret = '7395e91baf6b49ca9b84b1301989f77e'
// 发起请求
uni.request({
url: `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${secret}`,
success: function (res) {
auth.setAccessToken(res.data.access_token)
},
fail: function () {
console.log('请求 access-token 失败');
}
});
Vue.config.productionTip = false
Vue.prototype.$store = store
......
{
"name": "若依移动端",
"appid": "__UNI__EF8B6D6",
"description": "",
"versionName": "1.1.0",
"versionCode": "100",
"transformPx": false,
"app-plus": {
"usingComponents": true,
"nvueCompiler": "uni-app",
"splashscreen": {
"alwaysShowBeforeRender": true,
"waiting": true,
"autoclose": true,
"delay": 0
"name" : "若依移动端",
"appid" : "__UNI__EF8B6D6",
"description" : "",
"versionName" : "1.1.0",
"versionCode" : "100",
"transformPx" : false,
"app-plus" : {
"usingComponents" : true,
"nvueCompiler" : "uni-app",
"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" : {}
}
},
"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": "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
"quickapp" : {},
"mp-weixin" : {
"appid" : "wx5d89065bb4725557",
"setting" : {
"urlCheck" : false,
"es6" : false,
"minified" : true,
"postcss" : true
},
"optimization" : {
"subPackages" : true
},
"usingComponents" : true,
"requiredPrivateInfos" : [ "chooseAddress", "getLocation", "chooseLocation" ],
"permission" : {
"scope.userLocation" : {
"desc" : "你的位置信息将用于考勤打卡定位"
}
}
},
"title": "RuoYi-App",
"router": {
"mode": "hash",
"base": "./"
"vueVersion" : "2",
"h5" : {
"template" : "static/index.html",
"devServer" : {
"port" : 9090,
"https" : false
},
"title" : "RuoYi-App",
"router" : {
"mode" : "hash",
"base" : "./"
}
}
}
}
\ No newline at end of file
}
......@@ -9,15 +9,15 @@
{
"path": "pages/start",
"style": {
"navigationBarTitleText": "欢迎使用-小卤通"
}
},
{
"path": "pages/index",
"style": {
"navigationStyle": "custom"
"navigationBarTitleText": "欢迎使用-小卤促销员平台"
}
},
{
"path": "pages/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/attendance/index",
"style": {
......@@ -97,6 +97,14 @@
}
}
],
"subPackages": [
{
"root": "page_subject",
"pages": [
]
}
],
"tabBar": {
"color": "#000000",
"selectedColor": "#000000",
......
<template>
<view class="wrap">
<div class="button_wrap">
<div v-for="obj in attTimeKeyList" class="btn_item"
:class="(obj.timeOut || obj.ready) ? 'workbtn_disabled' : obj.class" :disabled="obj.disabled || obj.ready"
@click="attendanceClickFn(obj.type)">
<span>{{ obj.title }}</span>
<span v-if="obj.timeOut && !obj.ready" class="over">请补卡</span>
<span v-if="obj.ready" class="right">已打卡</span>
<span v-if="!obj.timeOut && !obj.ready" >{{ obj.beginValue }}</span>
<div v-for="obj in attTimeKeyList" class="btn_item" :class="{ 'active': !obj.timeOut && !obj.ready }"
@click="attendanceClickFn(obj)">
<!-- 动画层 -->
<div :class="{ 'ani': !obj.timeOut && !obj.ready }"></div>
<!-- 内容层 -->
<div class="content" :class="(obj.timeOut || obj.ready) ? 'workbtn_disabled' : obj.class">
<span>{{ obj.title }}</span>
<span v-if="obj.timeOut && !obj.ready" class="over">请补卡</span>
<span v-if="obj.ready" class="right">已打卡</span>
<span v-if="!obj.timeOut && !obj.ready">{{ obj.beginValue }}</span>
</div>
</div>
</div>
<uni-list class="list_wrap">
......@@ -19,7 +23,7 @@
<template v-slot:body>
<div class="item_body">
<div class="item" v-for="obj in item.kqTimeList">
<text class="time">{{ parseTime(obj.kqTime, '{h}:{i}:{s}') }}</text>
<text class="time">{{ obj.kqTime ? parseTime(obj.kqTime, '{h}:{i}:{s}') : '暂未打卡' }}</text>
<text class="title">{{ attendanceDict[obj.kqType] }}打卡</text>
</div>
</div>
......@@ -40,7 +44,7 @@
<script>
import { getAttendanceDetailAPI, addAttendanceAPI, getAttendanceListAPI } from '@/api/attendance'
import { checkStartLessEndTime, parseTime, isSameDay, zeroTo24 } from '@/utils/common'
import { checkStartLessEndTime, parseTime, isSameDay, zeroTo24, checkTimeIsBetween } from '@/utils/common'
export default {
data() {
return {
......@@ -50,7 +54,8 @@ export default {
1: '上班',
2: '午班',
3: '下班'
}
},
currently: '' // 服务器当前时间(格式:时:分:秒.毫秒)
}
},
created() {
......@@ -110,34 +115,48 @@ export default {
}
this.attTimeKeyList = list
// 保存服务器时间
this.currently = data.currently.split(".")[0]
// 考勤打卡记录
this.getAttendanceListFn()
},
// 考勤打卡
async attendanceClickFn(type) {
const { addressComponent, location } = await this.$store.getters.location
async attendanceClickFn(attObj) {
const { addressComponent, location } = this.$store.getters.location
const { lng, lat } = location
const { province, city, district, street } = addressComponent
await addAttendanceAPI({
"kqLocal": [
lng,
lat
],
"kqProvinc": province,
"kqCity": city,
"kqCounty": district,
"kqAddress": street,
"kqPicurl": "https://www.baidu.com",
"kqType": type
})
// 考勤打卡记录
this.getAttendanceListFn()
if (attObj.timeOut) {
// 超过打卡时间
return this.$modal.msgError('超过了打卡时间')
}
// 判断它打卡时间范围是否合法(在开始之后,结束之前)
if (checkTimeIsBetween(attObj.beginValue, attObj.endValue, this.currently)) {
await addAttendanceAPI({
"kqLocal": [
lng,
lat
],
"kqProvinc": province,
"kqCity": city,
"kqCounty": district,
"kqAddress": street,
"kqPicurl": "https://www.baidu.com",
"kqType": attObj.type
})
this.$modal.msgSuccess('打卡成功')
// 考勤打卡记录
this.getAttendanceListFn()
} else {
this.$modal.msgError('打卡还未开始')
}
},
// 获取考勤列表
async getAttendanceListFn() {
const { data: { current, data } } = await getAttendanceListAPI()
const list = []
// 如果有打卡时间,则从后台获取结构数据
// 如果有打卡时间,则转换后台的结构数据
if (Object.keys(data).length > 0) {
Object.entries(data).forEach(([key, value]) => {
const attTime = [] // 打卡时间
......@@ -152,20 +171,18 @@ export default {
kqTimeList: attTime
})
})
// 考勤记录
this.attendanceList = list
// 判断有没有今日的打卡记录
if (isSameDay(this.attendanceList[0].time, current)) {
// 根据记录决定今日哪个按钮应该关闭
this.attTimeKeyList.forEach((obj, index) => {
// 从按钮数组里去已打卡时间数组里取出,打卡时间对象
const readyObj = this.attendanceList[0].kqTimeList[index]
if (readyObj) {
// 如果找到了,证明已经打过卡了
obj.ready = true
}
})
}
// 默认第 0 条就是今日打卡的记录,判断是否打卡
this.attTimeKeyList.forEach((obj, index) => {
// 从按钮数组里去已打卡时间数组里取出,打卡时间对象
const readyObj = this.attendanceList[0].kqTimeList[index]
if (readyObj.kqTime) {
// 如果找到了打卡时间,证明已经打过卡了
obj.ready = true
}
})
}
}
}
......@@ -189,82 +206,99 @@ export default {
flex: 1;
.btn_item {
display: flex;
flex-direction: column;
justify-content: center;
gap: 0 !important;
width: 250rpx;
height: 250rpx;
border-radius: 50%;
align-items: center;
color: white;
transition: all 0.1s linear;
position: relative;
transition: all 0.1s linear;
.over {
font-size: 28rpx;
color: #d9322c;
margin-top: 10rpx;
}
.ani,
.content {
width: 100%;
height: 100%;
position: absolute;
border-radius: 50%;
display: flex;
flex-direction: column;
justify-content: center;
gap: 0 !important;
align-items: center;
color: white;
.right{
font-size: 28rpx;
color: #32cdbf;
margin-top: 10rpx;
}
&.workbtn_disabled {
background-color: #c7c8c8;
color: rgb(160, 156, 156);
}
.content {
.over {
font-size: 28rpx;
color: #d9322c;
margin-top: 10rpx;
}
&.go_work {
background-color: #32cdbf;
}
.right {
font-size: 28rpx;
color: #32cdbf;
margin-top: 10rpx;
}
&.after_work {
background-color: #e0bd47;
}
&.workbtn_disabled {
background-color: #c7c8c8;
color: rgb(160, 156, 156);
}
&.go_work {
background-color: #32cdbf;
}
&.after_work {
background-color: #e0bd47;
}
&.off_work {
background-color: #5dabed;
&.off_work {
background-color: #5dabed;
}
}
// 打卡按钮动画
&.go_work,
&.after_work, &.off_work {
&::before,
&::after {
content: ' ';
width: 250rpx;
height: 250rpx;
.ani {
&:before,
&:after {
content: '';
width: 100%;
height: 100%;
border-radius: 50%;
position: absolute;
animation: eff68 1.4s linear infinite;
// animation: eff68 5s linear infinite;
}
&::after {
animation-delay: 0.7s;
&:after {
animation-delay: .7s;
// animation-delay: 2.5s;
}
@keyframes eff68 {
0% {
box-shadow: 0 0 0 0px #0093E9;
opacity: 0.2;
// box-shadow: 0 0 0 0px #0093E9;
background-color: rgba(0, 147, 233, 0.2);
transform: scale(1);
// opacity: 0.2;
}
100% {
box-shadow: 0 0 0 20px #0093E9;
opacity: 0;
// box-shadow: 0 0 0 20px #0093E9;
background-color: rgba(0, 147, 233, 0);
transform: scale(1.4);
// opacity: 0;
}
}
}
&:active {
transform: scale(0.8);
}
// 打卡按钮动画
&.active:active {
transform: scale(0.8);
}
}
}
......
......@@ -75,7 +75,8 @@ export default {
return this.$modal.msgError("您无需打卡");
} else {
// 有工作城市
if (this.$store.getters.location.addressComponent) {
console.log(this.$store.getters)
if (this.$store.getters.user.workCityName) {
// 定位城市是否一致
if (this.$store.getters.location.addressComponent.city.startsWith(this.$store.getters.user.workCityName)) {
// 跳转到打卡页面
......
<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 style="width: 400rpx;height: 200rpx;"
: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>
<button open-type="getPhoneNumber"
@getphonenumber="getPhoneNumber"
class="login-btn cu-btn block bg-blue lg round">手机号登录</button>
</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>
<text @click="$refs.agreementDialog.open()"
class="text-blue">《用户协议》</text>
</view>
</view>
<uni-popup ref="agreementDialog"
type="dialog">
<uni-popup-dialog type="info"
confirmText="同意"
:showClose="false"
title="用户协议">
<ul class="agreement_ul">
<li>1.当前小程序仅限王小卤-促销员活动上报使用</li>
<li>2.小程序需经您同意,获取您的手机号登录当前系统</li>
<li>3.您的手机号仅用于系统登录,领导联系"</li>
</ul>
</uni-popup-dialog>
</uni-popup>
</view>
</template>
<script>
import { getCodeImg } from '@/api/login'
import { getAccessToken } from '../utils/auth';
import storage from '../utils/storage'
import constant from '../utils/constant';
export default {
data() {
return {
codeUrl: "",
captchaEnabled: false,
// 用户注册开关
register: false,
globalConfig: getApp().globalData.config,
loginForm: {
username: "wangxiaolu_ceshi2",
password: "123456",
// code: "",
uuid: ''
}
globalConfig: getApp().globalData.config
}
},
created() {
// this.getCode()
},
methods: {
// 用户注册
handleUserRegister() {
this.$tab.redirectTo(`/pages/register`)
},
// 隐私协议
handlePrivacy() {
let site = this.globalConfig.appInfo.agreements[0]
this.$tab.navigateTo(`/pages/common/webview/index?title=${site.title}&url=${site.url}`)
},
// 用户协议
handleUserAgrement() {
let site = this.globalConfig.appInfo.agreements[1]
this.$tab.navigateTo(`/pages/common/webview/index?title=${site.title}&url=${site.url}`)
},
// 获取图形验证码
getCode() {
getCodeImg().then(res => {
this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled
if (this.captchaEnabled) {
this.codeUrl = 'data:image/gif;base64,' + res.img
this.loginForm.uuid = res.uuid
// 手机号登录
getPhoneNumber(e) {
this.$modal.loading("登录中,请耐心等待...")
// 通过微信小程序 API 获取手机号
uni.request({
url: `https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=${getAccessToken()}`,
method: 'POST',
data: {
code: e.detail.code
},
success: (res) => {
console.log('后端解密手机号成功,手机号为:', res);
storage.set(constant.loginPhone, res.data.phone_info.phoneNumber)
this.$modal.closeLoading()
this.$tab.reLaunch('/pages/index')
},
fail: function () {
console.log('后端解密手机号失败');
}
})
},
// 登录方法
async handleLogin() {
if (this.loginForm.username === "") {
this.$modal.msgError("请输入您的账号")
} else if (this.loginForm.password === "") {
this.$modal.msgError("请输入您的密码")
}
// else if (this.loginForm.code === "" && this.captchaEnabled) {
// this.$modal.msgError("请输入验证码")
// }
else {
this.$modal.loading("登录中,请耐心等待...")
this.pwdLogin()
}
},
// 密码登录
async pwdLogin() {
this.$store.dispatch('Login', this.loginForm).then(() => {
this.$modal.closeLoading()
this.loginSuccess()
}).catch(() => {
if (this.captchaEnabled) {
this.getCode()
}
})
},
// 登录成功后,处理函数
async loginSuccess(result) {
// 设置用户信息
await this.$store.dispatch('GetInfo')
await this.getAuth()
this.$tab.reLaunch('/pages/index')
});
},
// // 登录成功后,处理函数
// async loginSuccess(result) {
// // 设置用户信息
// await this.$store.dispatch('GetInfo')
// await this.getAuth()
// this.$tab.reLaunch('/pages/index')
// },
// 登录成功后,开始获取各种权限
async getAuth() {
// 获取地址位置
......@@ -132,6 +89,13 @@ page {
background-color: #ffffff;
}
// 用户协议弹窗
.agreement_ul {
li {
margin-top: 20rpx;
}
}
.normal-login-container {
width: 100%;
......@@ -145,9 +109,6 @@ page {
border-radius: 4px;
}
.title {
margin-left: 10px;
}
}
.login-form-content {
......
<template>
<image src="@/static/start.jpg" alt="" class="start_img"/>
<image src="https://6c6f-lowcode-6gzlaqs9e1bbd9c1-1325462268.tcb.qcloud.la/muban/%E5%B0%8F%E7%A8%8B%E5%BA%8F-%E7%99%BB%E5%BD%95%E6%B5%B7%E6%8A%A5.jpeg?sign=6edb65e761a2d01c1427aed47a7a2d74&t=1730958952" alt="" class="start_img"/>
</template>
<script>
import storage from '../utils/storage.js'
import constant from '../utils/constant.js'
export default {
mounted(){
setTimeout(() => {
this.$tab.redirectTo('pages/login')
// this.$tab.redirectTo('/page_subject/pages/login')
console.log(storage.get(constant.loginPhone))
if (storage.get(constant.loginPhone)) {
// 有存储过之前的登录手机号
this.$tab.switchTab('/pages/index')
} else {
this.$tab.redirectTo('/pages/login')
}
}, 2500)
}
}
......
import { getToken } from '@/utils/auth'
import storage from './utils/storage'
import constant from './utils/constant'
// 登录页面
const loginPage = "/pages/login"
......@@ -20,7 +22,7 @@ list.forEach(item => {
// 全局添加 API 属性等(拦截路由)
uni.addInterceptor(item, {
invoke(to) {
if (getToken()) {
if (storage.get(constant.loginPhone)) {
if (to.url === loginPage) {
uni.reLaunch({ url: "/" })
}
......
static/logo.png

3.5 KB | W: | H:

static/logo.png

183.4 KB | W: | H:

static/logo.png
static/logo.png
static/logo.png
static/logo.png
  • 2-up
  • Swipe
  • Onion skin
差异被折叠。
......@@ -7,6 +7,6 @@ const getters = {
roles: state => state.user.roles,
permissions: state => state.user.permissions,
delayTime: state => 3000, // 延迟弹窗关闭时间
location: (state) => state.map.location
location: (state) => state.map.location,
}
export default getters
## 1.9.5(2024-10-15)
- 修复 微信小程序中的getSystemInfo警告
## 1.9.4(2024-10-12)
- 修复 微信小程序中的getSystemInfo警告
## 1.9.3(2024-10-12)
- 修复 微信小程序中的getSystemInfo警告
## 1.9.2(2024-09-21)
- 修复 uni-popup在android上的重复点击弹出位置不正确的bug
## 1.9.1(2024-04-02)
- 修复 uni-popup-dialog vue3下使用value无法进行绑定的bug(双向绑定兼容旧写法)
## 1.9.0(2024-03-28)
- 修复 uni-popup-dialog 双向绑定时初始化逻辑修正
## 1.8.9(2024-03-20)
- 修复 uni-popup-dialog 数据输入时修正为双向绑定
## 1.8.8(2024-02-20)
- 修复 uni-popup 在微信小程序下出现文字向上闪动的bug
## 1.8.7(2024-02-02)
- 新增 uni-popup-dialog 新增属性focus:input模式下,是否自动自动聚焦
## 1.8.6(2024-01-30)
- 新增 uni-popup-dialog 新增属性maxLength:限制输入框字数
## 1.8.5(2024-01-26)
- 新增 uni-popup-dialog 新增属性showClose:控制关闭按钮的显示
## 1.8.4(2023-11-15)
- 新增 uni-popup 支持uni-app-x 注意暂时仅支持 `maskClick` `@open` `@close`
## 1.8.3(2023-04-17)
- 修复 uni-popup 重复打开时的 bug
## 1.8.2(2023-02-02)
......
......@@ -10,14 +10,15 @@
</view>
<view v-else class="uni-dialog-content">
<slot>
<input class="uni-dialog-input" v-model="val" :type="inputType" :placeholder="placeholderText" :focus="focus" >
<input class="uni-dialog-input" :maxlength="maxlength" v-model="val" :type="inputType"
:placeholder="placeholderText" :focus="focus">
</slot>
</view>
<view class="uni-dialog-button-group">
<view class="uni-dialog-button" @click="closeDialog">
<view class="uni-dialog-button" v-if="showClose" @click="closeDialog">
<text class="uni-dialog-button-text">{{closeText}}</text>
</view>
<view class="uni-dialog-button uni-border-left" @click="onOk">
<view class="uni-dialog-button" :class="showClose?'uni-border-left':''" @click="onOk">
<text class="uni-dialog-button-text uni-button-color">{{okText}}</text>
</view>
</view>
......@@ -28,16 +29,19 @@
<script>
import popup from '../uni-popup/popup.js'
import {
initVueI18n
initVueI18n
} from '@dcloudio/uni-i18n'
import messages from '../uni-popup/i18n/index.js'
const { t } = initVueI18n(messages)
const {
t
} = initVueI18n(messages)
/**
* PopUp 弹出层-对话框样式
* @description 弹出层-对话框样式
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
* @property {String} value input 模式下的默认值
* @property {String} placeholder input 模式下输入提示
* @property {Boolean} focus input模式下是否自动聚焦,默认为true
* @property {String} type = [success|warning|info|error] 主题样式
* @value success 成功
* @value warning 提示
......@@ -46,8 +50,10 @@
* @property {String} mode = [base|input] 模式、
* @value base 基础对话框
* @value input 可输入对话框
* @showClose {Boolean} 是否显示关闭按钮
* @property {String} content 对话框内容
* @property {Boolean} beforeClose 是否拦截取消事件
* @property {Number} maxlength 输入
* @event {Function} confirm 点击确认按钮触发
* @event {Function} close 点击取消按钮触发
*/
......@@ -55,16 +61,30 @@
export default {
name: "uniPopupDialog",
mixins: [popup],
emits:['confirm','close'],
props: {
inputType:{
type: String,
default: 'text'
emits: ['confirm', 'close', 'update:modelValue', 'input'],
props: {
inputType: {
type: String,
default: 'text'
},
showClose: {
type: Boolean,
default: true
},
// #ifdef VUE2
value: {
type: [String, Number],
default: ''
},
// #endif
// #ifdef VUE3
modelValue: {
type: [Number, String],
default: ''
},
// #endif
placeholder: {
type: [String, Number],
default: ''
......@@ -88,20 +108,27 @@
beforeClose: {
type: Boolean,
default: false
},
cancelText:{
type: String,
default: ''
},
confirmText:{
type: String,
default: ''
},
cancelText: {
type: String,
default: ''
},
confirmText: {
type: String,
default: ''
},
maxlength: {
type: Number,
default: -1,
},
focus: {
type: Boolean,
default: true,
}
},
data() {
return {
dialogType: 'error',
focus: false,
val: ""
}
},
......@@ -129,7 +156,21 @@
}
},
value(val) {
this.val = val
if (this.maxlength != -1 && this.mode === 'input') {
this.val = val.slice(0, this.maxlength);
} else {
this.val = val
}
},
val(val) {
// #ifdef VUE2
// TODO 兼容 vue2
this.$emit('input', val);
// #endif
// #ifdef VUE3
// TODO 兼容 vue3
this.$emit('update:modelValue', val);
// #endif
}
},
created() {
......@@ -138,25 +179,25 @@
// this.popup.closeMask()
if (this.mode === 'input') {
this.dialogType = 'info'
this.val = this.value
this.val = this.value;
// #ifdef VUE3
this.val = this.modelValue;
// #endif
} else {
this.dialogType = this.type
}
},
mounted() {
this.focus = true
},
methods: {
/**
* 点击确认按钮
*/
onOk() {
if (this.mode === 'input'){
if (this.mode === 'input') {
this.$emit('confirm', this.val)
}else{
} else {
this.$emit('confirm')
}
if(this.beforeClose) return
if (this.beforeClose) return
this.popup.close()
},
/**
......@@ -164,17 +205,17 @@
*/
closeDialog() {
this.$emit('close')
if(this.beforeClose) return
if (this.beforeClose) return
this.popup.close()
},
close(){
close() {
this.popup.close()
}
}
}
</script>
<style lang="scss" >
<style lang="scss">
.uni-popup-dialog {
width: 300px;
border-radius: 11px;
......@@ -272,4 +313,4 @@
.uni-popup__info {
color: #909399;
}
</style>
</style>
......@@ -47,7 +47,7 @@
{
text: '支付宝',
icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/d684ae40-50be-11eb-8ff1-d5dcf8779628.png',
name: 'wx'
name: 'ali'
},
{
text: 'QQ',
......
<template>
<view class="popup-root" v-if="isOpen" v-show="isShow" @click="clickMask">
<view @click.stop>
<slot></slot>
</view>
</view>
</template>
<script>
type CloseCallBack = ()=> void;
let closeCallBack:CloseCallBack = () :void => {};
export default {
emits:["close","clickMask"],
data() {
return {
isShow:false,
isOpen:false
}
},
props: {
maskClick: {
type: Boolean,
default: true
},
},
watch: {
// 设置show = true 时,如果没有 open 需要设置为 open
isShow:{
handler(isShow) {
// console.log("isShow",isShow)
if(isShow && this.isOpen == false){
this.isOpen = true
}
},
immediate:true
},
// 设置isOpen = true 时,如果没有 isShow 需要设置为 isShow
isOpen:{
handler(isOpen) {
// console.log("isOpen",isOpen)
if(isOpen && this.isShow == false){
this.isShow = true
}
},
immediate:true
}
},
methods:{
open(){
// ...funs : CloseCallBack[]
// if(funs.length > 0){
// closeCallBack = funs[0]
// }
this.isOpen = true;
},
clickMask(){
if(this.maskClick == true){
this.$emit('clickMask')
this.close()
}
},
close(): void{
this.isOpen = false;
this.$emit('close')
closeCallBack()
},
hiden(){
this.isShow = false
},
show(){
this.isShow = true
}
}
}
</script>
<style>
.popup-root {
position: fixed;
top: 0;
left: 0;
width: 750rpx;
height: 100%;
flex: 1;
background-color: rgba(0, 0, 0, 0.3);
justify-content: center;
align-items: center;
z-index: 99;
}
</style>
\ No newline at end of file
......@@ -5,7 +5,7 @@
:duration="duration" :show="showTrans" @click="onTap" />
<uni-transition key="2" :mode-class="ani" name="content" :styles="transClass" :duration="duration"
:show="showTrans" @click="onTap">
<view class="uni-popup__wrapper" :style="{ backgroundColor: bg }" :class="[popupstyle]" @click="clear">
<view class="uni-popup__wrapper" :style="getStyles" :class="[popupstyle]" @click="clear">
<slot />
</view>
</uni-transition>
......@@ -39,6 +39,7 @@
* @property {Boolean} isMaskClick = [true|false] 蒙版点击是否关闭弹窗
* @property {String} backgroundColor 主窗口背景色
* @property {String} maskBackgroundColor 蒙版颜色
* @property {String} borderRadius 设置圆角(左上、右上、右下和左下) 示例:"10px 10px 10px 10px"
* @property {Boolean} safeArea 是否适配底部安全区
* @event {Function} change 打开关闭弹窗触发,e={show: false}
* @event {Function} maskClick 点击遮罩触发
......@@ -86,6 +87,9 @@
type: String,
default: 'rgba(0, 0, 0, 0.4)'
},
borderRadius:{
type: String,
}
},
watch: {
......@@ -157,16 +161,25 @@
backgroundColor: 'rgba(0, 0, 0, 0.4)'
},
transClass: {
backgroundColor: 'transparent',
borderRadius: this.borderRadius || "0",
position: 'fixed',
left: 0,
right: 0
},
maskShow: true,
mkclick: true,
popupstyle: this.isDesktop ? 'fixforpc-top' : 'top'
popupstyle: 'top'
}
},
computed: {
getStyles() {
let res = { backgroundColor: this.bg };
if (this.borderRadius || "0") {
res = Object.assign(res, { borderRadius: this.borderRadius })
}
return res;
},
isDesktop() {
return this.popupWidth >= 500 && this.popupHeight >= 500
},
......@@ -179,6 +192,17 @@
},
mounted() {
const fixSize = () => {
// #ifdef MP-WEIXIN
const {
windowWidth,
windowHeight,
windowTop,
safeArea,
screenHeight,
safeAreaInsets
} = uni.getWindowInfo()
// #endif
// #ifndef MP-WEIXIN
const {
windowWidth,
windowHeight,
......@@ -187,6 +211,7 @@
screenHeight,
safeAreaInsets
} = uni.getSystemInfoSync()
// #endif
this.popupWidth = windowWidth
this.popupHeight = windowHeight + (windowTop || 0)
// TODO fix by mehaotian 是否适配底部安全区 ,目前微信ios 、和 app ios 计算有差异,需要框架修复
......@@ -221,6 +246,12 @@
this.setH5Visible()
},
// #endif
activated() {
this.setH5Visible(!this.showPopup);
},
deactivated() {
this.setH5Visible(true);
},
created() {
// this.mkclick = this.isMaskClick || this.maskClick
if (this.isMaskClick === null && this.maskClick === null) {
......@@ -240,10 +271,10 @@
this.maskClass.backgroundColor = this.maskBackgroundColor
},
methods: {
setH5Visible() {
setH5Visible(visible = true) {
// #ifdef H5
// fix by mehaotian 处理 h5 滚动穿透的问题
document.getElementsByTagName('body')[0].style.overflow = 'visible'
document.getElementsByTagName('body')[0].style.overflow = visible ? "visible" : "hidden";
// #endif
},
/**
......@@ -323,13 +354,15 @@
position: 'fixed',
left: 0,
right: 0,
backgroundColor: this.bg
backgroundColor: this.bg,
borderRadius:this.borderRadius || "0"
}
// TODO 兼容 type 属性 ,后续会废弃
if (type) return
this.showPopup = true
this.showTrans = true
this.$nextTick(() => {
this.showPoptrans()
if (this.messageChild && this.type === 'message') {
this.messageChild.timerClose()
}
......@@ -347,19 +380,25 @@
right: 0,
bottom: 0,
paddingBottom: this.safeAreaInsets + 'px',
backgroundColor: this.bg
backgroundColor: this.bg,
borderRadius:this.borderRadius || "0",
}
// TODO 兼容 type 属性 ,后续会废弃
if (type) return
this.showPopup = true
this.showTrans = true
this.showPoptrans()
},
/**
* 中间弹出样式处理
*/
center(type) {
this.popupstyle = 'center'
this.ani = ['zoom-out', 'fade']
//微信小程序下,组合动画会出现文字向上闪动问题,再此做特殊处理
// #ifdef MP-WEIXIN
this.ani = ['fade']
// #endif
// #ifndef MP-WEIXIN
this.ani = ['zoom-out', 'fade']
// #endif
this.transClass = {
position: 'fixed',
/* #ifndef APP-NVUE */
......@@ -371,12 +410,12 @@
right: 0,
top: 0,
justifyContent: 'center',
alignItems: 'center'
alignItems: 'center',
borderRadius:this.borderRadius || "0"
}
// TODO 兼容 type 属性 ,后续会废弃
if (type) return
this.showPopup = true
this.showTrans = true
this.showPoptrans()
},
left(type) {
this.popupstyle = 'left'
......@@ -387,6 +426,7 @@
bottom: 0,
top: 0,
backgroundColor: this.bg,
borderRadius:this.borderRadius || "0",
/* #ifndef APP-NVUE */
display: 'flex',
flexDirection: 'column'
......@@ -394,8 +434,7 @@
}
// TODO 兼容 type 属性 ,后续会废弃
if (type) return
this.showPopup = true
this.showTrans = true
this.showPoptrans()
},
right(type) {
this.popupstyle = 'right'
......@@ -406,6 +445,7 @@
right: 0,
top: 0,
backgroundColor: this.bg,
borderRadius:this.borderRadius || "0",
/* #ifndef APP-NVUE */
display: 'flex',
flexDirection: 'column'
......@@ -413,8 +453,13 @@
}
// TODO 兼容 type 属性 ,后续会废弃
if (type) return
this.showPopup = true
this.showTrans = true
this.showPoptrans()
},
showPoptrans(){
this.$nextTick(()=>{
this.showPopup = true
this.showTrans = true
})
}
}
}
......
{
"id": "uni-popup",
"displayName": "uni-popup 弹出层",
"version": "1.8.3",
"version": "1.9.5",
"description": " Popup 组件,提供常用的弹层",
"keywords": [
"uni-ui",
......@@ -46,7 +46,8 @@
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
"aliyun": "y",
"alipay": "n"
},
"client": {
"App": {
......
## 1.3.3(2024-04-23)
- 修复 当元素会受变量影响自动隐藏的bug
## 1.3.2(2023-05-04)
- 修复 NVUE 平台报错的问题
## 1.3.1(2021-11-23)
- 修复 init 方法初始化问题
## 1.3.0(2021-11-19)
......
<template>
<view v-if="isShow||onceRender" v-show="isShow" ref="ani" :animation="animationData" :class="customClass" :style="transformStyles" @click="onClick"><slot></slot></view>
<!-- #ifndef APP-NVUE -->
<view v-show="isShow" ref="ani" :animation="animationData" :class="customClass" :style="transformStyles" @click="onClick"><slot></slot></view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<view v-if="isShow" ref="ani" :animation="animationData" :class="customClass" :style="transformStyles" @click="onClick"><slot></slot></view>
<!-- #endif -->
</template>
<script>
......@@ -249,7 +254,7 @@ export default {
},
animationType(type) {
return {
fade: type ? 1 : 0,
fade: type ? 0 : 1,
'slide-top': `translateY(${type ? '0' : '-100%'})`,
'slide-right': `translateX(${type ? '0' : '100%'})`,
'slide-bottom': `translateY(${type ? '0' : '100%'})`,
......
{
"id": "uni-transition",
"displayName": "uni-transition 过渡动画",
"version": "1.3.1",
"version": "1.3.3",
"description": "元素的简单过渡动画",
"keywords": [
"uni-ui",
......@@ -17,11 +17,7 @@
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
......@@ -38,7 +34,8 @@
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": ["uni-scss"],
......@@ -46,7 +43,8 @@
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
"aliyun": "y",
"alipay": "n"
},
"client": {
"App": {
......
// 用户的 Token 值
const TokenKey = 'App-Token'
export function getToken() {
......@@ -10,4 +11,18 @@ export function setToken(token) {
export function removeToken() {
return uni.removeStorageSync(TokenKey)
}
}
// 小程序的 AccessToken 值
const AccessTokenKey = 'App-AccessToken'
export function getAccessToken() {
return uni.getStorageSync(AccessTokenKey)
}
export function setAccessToken(token) {
return uni.setStorageSync(AccessTokenKey, token)
}
export function removeAccessToken() {
return uni.removeStorageSync(AccessTokenKey)
}
......@@ -67,6 +67,24 @@ export function checkStartLessEndTime(startTime, endTime) {
endDate.setSeconds(endTime.split(":")[2])
return startDate.getTime() - endDate.getTime() < 0
}
// 判断某个时间是否在指定时间范围中间
export function checkTimeIsBetween(startTime, endTime, time) {
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])
const checkDate = new Date()
checkDate.setHours(time.split(":")[0])
checkDate.setMinutes(time.split(":")[1])
checkDate.setSeconds(time.split(":")[2])
return startDate.getTime() - checkDate.getTime() < 0 && checkDate.getTime() - endDate.getTime() < 0
}
// 日期格式化
export function parseTime(time, pattern) {
......
......@@ -5,7 +5,9 @@ const constant = {
permissions: 'vuex_permissions',
user: 'vuex_user',
// 地理相关
location: 'vuex_location'
location: 'vuex_location',
// 登录使用手机号
loginPhone: 'vuex_login_phone',
}
export default constant
......@@ -4,7 +4,7 @@ import constant from './constant'
let storageKey = 'storage_data'
// 存储节点变量名
let storageNodeKeys = [constant.avatar, constant.name, constant.roles, constant.permissions, constant.user, constant.location]
let storageNodeKeys = [constant.avatar, constant.name, constant.roles, constant.permissions, constant.user, constant.location, constant.loginPhone]
const storage = {
set: function(key, value) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论