源文件

This commit is contained in:
gyq
2024-05-23 14:39:33 +08:00
commit a1128dd791
2997 changed files with 500069 additions and 0 deletions

8
jeepay-ui-uapp-face/.gitignore vendored Normal file
View File

@@ -0,0 +1,8 @@
/.hbuilderx/launch.json
# 编译完成的文件 不需要提交
/unpackage
/node_modules
/env.development.js

View File

@@ -0,0 +1,28 @@
<script>
export default {
onLaunch: function () {
console.log('App Launch')
},
onShow: function () {
console.log('App Show')
},
onHide: function () {
console.log('App Hide')
},
}
</script>
<style>
/*每个页面公共css */
.page-wrapper {
padding: 0.1rpx;
min-height: 100vh;
background: url('/static/indexImg/index-bg.png') no-repeat center center;
background-size: 100% 100%;
}
/* 适配支付宝小程序 input 全局背景设为透明色 */
input {
background-color: transparent !important;
}
</style>

View File

@@ -0,0 +1,14 @@
该文件夹内放置: 项目自建资源, 比如 公共样式文件, 和 工具包等文件。
目录结构:
commons
style
utils
知识点: 样式文件不应该放置到 static文件夹内css、less/scss 等资源不要放在 static 目录下,建议这些公用的资源放在自建的 common 目录下。), 详见:
https://uniapp.dcloud.net.cn/tutorial/project.html

View File

View File

@@ -0,0 +1,15 @@
/***
* 单位换算 分转元
* data, 原始数据
* list 需要装换的 数组 object的 key
* */
function yuan(data, list = []) {
const obj = data
list.forEach((v) => {
obj[v] = (obj[v] / 100).toFixed(2)
})
return obj
}
export default { yuan }

View File

@@ -0,0 +1,49 @@
const payModel = {
WECHAT: {
title: '微信',
imgUrl: '/static/orderImg/wechat.svg', //微信
bgColor: '#09BB07',
rgba: 'rgba(9,187,7,0.8)'
},
ALIPAY: {
title: '支付宝',
imgUrl: '/static/orderImg/zfb.svg', //支付宝
bgColor: '#458FFF',
rgba: 'rgba(69,143,255,0.8)'
},
YSFPAY: {
title: '云闪付',
imgUrl: '/static/orderImg/ysf.svg', // 云闪付
bgColor: '#FF5B4C',
rgba: 'rgba(255,91,76,0.8)'
},
UNIONPAY: {
title: '银联',
imgUrl: '/static/orderImg/union-pay.svg', // 银联
bgColor: '#0D131A',
rgba: 'rgba(13,19,26,0.8)'
},
OTHER: {
title: '其他',
imgUrl: '/static/orderImg/default-pay.svg', //其他
bgColor: '#5F36C4',
rgba: 'rgba(95,54,196,0.8)'
},
}
const payState = {
0: { text: '订单生成', color: '#2980FD' },
1: { text: '支付中', color: '#FFAA33' },
2: { text: '支付成功', color: '#09BB07' },
3: { text: '支付失败', color: '#CB2972' },
4: { text: '已撤销', color: '#808080' },
5: { text: '已退款', color: '#FF5B4C' },
6: { text: '订单关闭', color: '#D9D9D9' },
}
const payImg = (key) => payModel[key] || {}
const payStateMap = (key) => payState[key] || {}
export default {
payImg,
payStateMap,
}

View File

@@ -0,0 +1,72 @@
/**
* 加解密工具包
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/5/16 17:35
*/
import { SM4 } from 'gm-crypto'
import appConfig from '@/config/appConfig.js'
let HEX_KEY = null
// 字符串转16进制
function str2hex(str) {
var val = ''
for (var i = 0; i < str.length; i++) {
if (val == '')
val = str.charCodeAt(i).toString(16)
else
val += str.charCodeAt(i).toString(16)
}
val += ''
return val
}
// 获取hex秘钥
function getHexKey(){
if(!HEX_KEY){
HEX_KEY = str2hex(appConfig.encryptKey)
}
return HEX_KEY
}
// 解密 (http响应数据 做通用处理)
export function sm4DecryptByResData(data){
if(!data){
return data
}
let res = SM4.decrypt(data, getHexKey(), {
inputEncoding: 'base64',
outputEncoding: 'utf8'
})
if(!res){
return res
}
return JSON.parse(res)['originData']
}
// 加密 (http响应数据 做通用处理)
export function sm4EncryptByReqData(data){
if(!data){
return data
}
// 加密处理
let encryptData = SM4.encrypt(JSON.stringify(data), getHexKey(), {
inputEncoding: 'utf8',
outputEncoding: 'base64'
})
return {encryptData : encryptData}
}

View File

@@ -0,0 +1,62 @@
/**
* 提示信息公共文件
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2022/11/14 15:29
*/
const model = {
// uni.showToast的封装
// 参数: 标题、 显示时长(单位: 秒) 扩展参数
// 返回: promise对象 当提示消失后调用 resolve()
showToast: (title, duration = 1.5, extObject) => {
return new Promise((resolve, reject) => {
uni.showToast(Object.assign({ title: title, icon: 'none', mask: true, duration: (duration * 1000) }, extObject))
setTimeout(resolve, (duration * 1000));
})
},
// success类型的提示
showSuccessToast: (title, duration) => {
return model.showToast(title, duration, {icon: 'success'})
},
// error类型的提示
showErrorToast: (title, duration) => {
return model.showToast(title, duration, {icon: 'error'})
},
showLoading: (title = '请稍后' ) => {
return uni.showLoading({ title: title, mask: true })
},
hideLoading: () => {
return uni.hideLoading()
},
// 返回 Promise 点击确定和取消
// APP安卓原生提示比较丑 APP 不推荐使用该函数 。
showModal: (title, confirmText = '确定', cancalText = '取消', extObject) => {
return new Promise((resolve, reject) => {
uni.showModal( Object.assign({
title: title,
confirmText: confirmText,
showCancel: cancalText ? true : false,
cancelText: cancalText,
success: function(r) {
if (r.confirm) {
resolve()
}else if (r.cancel) {
reject()
}
}
}, extObject ));
});
},
}
export default model

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,164 @@
/**
* 存储管理对象
* 目标:将现有系统的所有需要存储的数据,统一管理
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2022/04/13 07:18
*/
import appConfig from '@/config/appConfig.js'
// 应用级vue级别缓存 当存在时则读取此值, 否则读取storage中的值。 vue线程内的缓存不必要每次读取应用数据影响性能
const appCache = {
tokenVal: null, // token取值
currentUser: null, // 当前商户信息
}
const model = {
// 退出清空所有的缓存数据。 (不包含 环境相关)
cleanByLogout: () => {
// 1. 清空app级别缓存。
Object.keys(appCache).forEach((k) => (appCache[k] = null))
let envName = model.env() // 获取到当前的环境变量
uni.clearStorageSync() // 清除所有的缓存信息
model.env(envName) // 重置env
},
// 获取和放置token
token: (val, isDelete = false) => {
if (isDelete) {
appCache.tokenVal = ''
return uni.removeStorageSync(appConfig.tokenKey)
}
if (val) {
// 有值,为放置
appCache.tokenVal = val
uni.setStorageSync(appConfig.tokenKey, val)
} else {
// 否则为获取
if (!appCache.tokenVal) {
//缓存取不到,获取应用本地信息
appCache.tokenVal = uni.getStorageSync(appConfig.tokenKey)
}
return appCache.tokenVal
}
},
// 已经登录的用户记录
loggedInUser: (addUserName = null, removeUserName = null) => {
let key = 'loggedInUserList'
// 删除
if (removeUserName) {
let nameList = uni.getStorageSync(key) || []
if (nameList.length <= 0) {
//不存在数据
return false
}
let hasUserIndex = nameList.indexOf(removeUserName)
if (hasUserIndex >= 0) {
nameList.splice(hasUserIndex, 1) //删除
uni.setStorageSync(key, nameList)
}
return false
}
// 有新插入的记录
if (addUserName) {
let nameList = uni.getStorageSync(key) || []
let hasUser = false
for (let i = 0; i < nameList.length; i++) {
if (nameList[i] == addUserName) {
hasUser = true
}
}
// 包含记录
if (hasUser) {
return false
}
// 最多存储 5 个
if (nameList.length >= 5) {
nameList.splice(0, 1) //删除第一个
}
nameList.push(addUserName)
uni.setStorageSync(key, nameList)
//获取
} else {
return uni.getStorageSync(key) || [] //默认空数组
}
},
// 用户信息
userInfo: (currentUserInfo) => {
if (currentUserInfo) {
// 仅保存基础数据
let saveUser = {
sysUserId: currentUserInfo.sysUserId, // 用户ID
realname: currentUserInfo.realname, // 用户姓名
avatarUrl: currentUserInfo.avatarUrl, // 头像
telphone: currentUserInfo.telphone, // 手机号
userType: currentUserInfo.userType, // 用户类型
workState: currentUserInfo.workState, // 用户上班状态
mchNo: currentUserInfo.sysUserId, // 商户No
mchShortName: currentUserInfo.shortName, // 商户简称
mchType: currentUserInfo.mchType, // 商户类型
mchLevel: currentUserInfo.mchLevel, // 商户级别
entIdList: currentUserInfo.entIdList, // 权限集合List
}
uni.setStorageSync('currentUserInfo', saveUser) // 改变存储
appCache.currentUser = null
}
if (!appCache.currentUser) {
// 获取缓存数据
appCache.currentUser = uni.getStorageSync('currentUserInfo')
}
return appCache.currentUser
},
// 项目环境变量:(测试、 生产的切换)
env: (envMode) => {
if (envMode) {
uni.setStorageSync(appConfig.storeEnvEnumKey, envMode) // 改变存储
}
return uni.getStorageSync(appConfig.storeEnvEnumKey)
},
// 网站信息
siteInfos: (siteInfos) => {
if (siteInfos) {
uni.setStorageSync('siteInfos', siteInfos) // 改变存储
}
return uni.getStorageSync('siteInfos')
},
// unipush2 cid
uniPush2Cid: (uniPush2Cid) => {
if (uniPush2Cid) {
uni.setStorageSync('uniPush2Cid', uniPush2Cid) // 改变存储
}
return uni.getStorageSync('uniPush2Cid')
},
faceModel: (faceM) => {
if (faceM) return uni.setStorageSync('faceModel', faceM) //写入数据
return uni.getStorageSync('faceModel') //读取数据
},
deviceNo: (deviceNo) => {
if (deviceNo) return uni.setStorageSync('deviceNo', deviceNo) //写入设备号
return uni.getStorageSync('deviceNo') //读取设备号
},
}
export default model

View File

@@ -0,0 +1,19 @@
import dayjs from 'dayjs' //时间格式库
// 时间校验 用于筛选 开始 时间不能大于结束 开始结束时间必选 时间 返回值 true 和 false
export const startAndEndTime = (start, end) => {
if (!start || !end) {
uni.showToast({
title: '请选择开始或结束时间',
icon: 'none',
})
return false
}
if (dayjs(start).isAfter(end)) {
uni.showToast({
title: '开始时间不能大于结束时间',
icon: 'none',
})
return false
}
return true
}

View File

@@ -0,0 +1,54 @@
/**
* 任务执行器
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2022/11/15 16:30
*/
const model = {
// 任务启动工具, 每 xxs调用一次 知道多次x次为止。
// 注意: 启动后将立马调用一次, 而不是1s后再调用。
// 参数:
// allCount: 全部的次数 支持promise 并不一定是 秒)
// stepSecond 步伐(单位: 秒)
// callbackFunc 回调函数, 支持返回 boolean 或者 promise ,
// 注意: boolean类型 true 进入下一次循环, false: 停止任务。
// promise类型 then 进入下一次循环, catch 停止任务。
startTimeoutTask: (stepSecond, allCount, callbackFunc) => {
// 不存在回调函数
if(!callbackFunc){
return false;
}
let callbackResult = callbackFunc(allCount)
// 明确返回false, 说明不再循环
if(callbackResult === false){
return false
}
// 不包含剩余次数了。
if(allCount <= 0){
return false
}
// promise
if(typeof callbackResult == 'object'){
callbackResult.then(() => {
setTimeout(() => model.startTimeoutTask(stepSecond, --allCount, callbackFunc), (stepSecond * 1000) )
})
}else{ // 其他boolean类型 或返回不明确, 继续下一次任务。
setTimeout(() => model.startTimeoutTask(stepSecond, --allCount, callbackFunc), (stepSecond * 1000) )
}
}
}
export default model

View File

@@ -0,0 +1,25 @@
var plugin = requirePlugin("WechatSI")
const innerAudioContext = wx.createInnerAudioContext({ useWebAudioImplement: true })
innerAudioContext.onError(function (res) {
console.log(res);
console.log("语音播放失败");
})
export default function(message) {
plugin.textToSpeech({
lang: "zh_CN",
tts: true,
content: message,
success: function(res) {
console.log("succ tts", res.filename)
innerAudioContext.src = res.filename;
innerAudioContext.play();
},
fail: function(res) {
console.log("fail tts", res)
}
})
}

View File

@@ -0,0 +1,37 @@
<template>
<view class="button-wrapper" hover-class="hover-button" hover-stay-time="50" :style="{
backgroundColor: bgColor, color: color, borderColor: bdColor, fontSize: size +'rpx' }" @tap="emits('click')">
<slot />
</view>
</template>
<script setup>
const props = defineProps({
bgColor: { type: String, default: '' },
color: { type: String, default: '' },
bdColor: { type: String, default: '' },
size: { type: Number }
})
const emits = defineEmits(['click'])
</script>
<style lang="scss" scoped>
.button-wrapper {
display: flex;
justify-content: center;
align-items: center;
margin: 0 auto;
width: 90%;
height: 110rpx;
background-color: $v-primary;
color: #fff;
border-radius: 14rpx;
font-size: 32rpx;
border: 1rpx solid transparent;
// background-color: transparent;
}
.hover-button {
opacity: 0.5;
}
</style>

View File

@@ -0,0 +1,60 @@
<template>
<swiper class="swiper" :style="{ '--banner-height': height }" circular :indicator-dots="true" autoplay
:interval="4000" :duration="500">
<block v-for="(v, i) in list" :key="i">
<swiper-item>
<image :src="v.imgUrl" mode="aspectFill" />
</swiper-item>
</block>
</swiper>
<!-- 等待商家付款 -->
<!-- #ifdef MP-WEIXIN -->
<view class="wait-mch">
<view class="wait-title">请等待商家发起收款</view>
</view>
<!-- #endif -->
</template>
<script setup>
const props = defineProps({
list: { type: Array, default: [] },
// interval: { type: [String, Number] }, 暂时写死轮播时间
height: { type: String, default: '88vh' }
})
</script>
<style lang="scss" scoped>
.uni-margin-wrap {
width: 100%;
}
.swiper {
height: var(--banner-height) !important;
}
.swiper-item {
display: block;
height: calc(100% - 150rpx)
}
image {
width: 100%;
height: 100%;
}
.wait-mch{
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 150rpx;
border-radius: 32rpx 32rpx;
.wait-title{
font-size: 45rpx;
font-weight: 700;
color:$v-primary;
letter-spacing: 2px;
}
}
</style>

View File

@@ -0,0 +1,66 @@
<template>
<view class="l-input-wrapper">
<view class="l-input-title">{{ title }}</view>
<input :type="type" :placeholder="place" :password="password" placeholder-class="l-input-place"
v-model="vdata.inputValue" @input="inputChange" />
</view>
</template>
<script setup>
import { reactive, ref } from 'vue'
const props = defineProps({
title: { type: String }, //标题
require: { type: Boolean, default: false }, //是否必填 默认 否
place: { type: String }, // placeholder
type: { type: String, default: 'text' }, //input 类型
value: { type: [String, Number], default: '' }, //双向绑定的值
REG: {}, //正则表达式
password: { type: Boolean, default: false },//是否密码模式 默认false
})
const emits = defineEmits(['update:value'])
const vdata = reactive({
inputValue: props.value,
})
const inputChange = (e) => {
emits('update:value', vdata.inputValue)
}
const check = () => {
if (props.require && !vdata.inputValue) return errorTips('不能为空')
if (props.REG && !props.REG.test(vdata.inputValue)) return errorTips('填写不正确')
return true
}
const errorTips = (err) => {
uni.showToast({
title: props.title + err,
icon: 'none',
})
}
defineExpose({ check })
</script>
<style lang="scss" scoped>
.l-input-wrapper {
margin: 50rpx;
height: 100rpx;
border-bottom: 1rpx solid #666;
input {
font-size: 24rpx;
height: 50%;
background-color: transparent !important;
}
.l-input-title {
margin-bottom: 10rpx;
font-size: 24rpx;
font-weight: 700;
}
}
::v-deep .l-input-place {
font-size: 32rpx;
color: #666;
}
</style>

View File

@@ -0,0 +1,129 @@
<template>
<!-- 切换模式卡片 -->
<uni-popup type="center" ref="refSwitchModel" @maskClick="emits('makClose')">
<view class="switch-model">
<view class="title">切换模式</view>
<view class="sun-text">如需设置收银机兼容 请点击设置按钮设置</view>
<view class="sub-title">独立收银模式<view class="model-tag" v-if="!vdata.pos">当前正在使用</view>
</view>
<view class="tips">接入电源后即可使用后屏输入收款金额前屏支持刷脸支付和扫码支付</view>
<view class="sub-title">POS模式<view class="model-tag" v-if="vdata.pos">当前正在使用</view>
</view>
<view class="tips">需要连接收银机或PC使用即插即用收款将会进入您的现有收银软件账户</view>
<view class="pay-model" hover-class="hover-model" hover-stay-time="50" @tap="switchFaceMdoel">
<image src="/static/iconImg/switch-model-ali.svg" mode="scaleToFill" />
切换至{{ !vdata.pos ? 'POS' : '独立收银' }}模式
</view>
</view>
</uni-popup>
</template>
<script setup>
import { ref, reactive } from "vue"
import storageManage from '@/commons/utils/storageManage.js'
const emits = defineEmits(['open', 'makClose', 'switch', 'update:value'])
const refSwitchModel = ref(null)
const vdata = reactive({
pos: false
})
const open = () => {
if (storageManage.faceModel() == 'pos') {
vdata.pos = true
} else {
vdata.pos = false
}
refSwitchModel.value.open()
}
const switchFaceMdoel = () => {
uni.showModal({
title: '提示',
content: `是否切换为${!vdata.pos ? 'POS' : '独立收银'}模式?`,
showCancel: true,
success: ({ confirm, cancel }) => {
if (confirm) {
if (!vdata.pos) {
storageManage.faceModel('pos')
emits('update:value', 'pos')
} else {
storageManage.faceModel('cashier')
emits('update:value', 'cashier')
}
refSwitchModel.value.close()
}
}
})
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
.switch-model {
padding: 0.1rpx 20rpx;
padding-bottom: 30rpx;
width: 75vw;
min-height: 300rpx;
border-radius: 14rpx;
background-color: #fff;
.title {
margin: 30rpx 0;
text-align: center;
font-weight: 600;
font-size: 32rpx;
}
.sun-text{
margin: 15rpx 0;
margin-bottom: 30rpx;
font-size: 22rpx;
text-align: center;
color: #666;
}
.sub-title {
font-size: 28rpx;
font-weight: 600;
.model-tag {
float: right;
background-color: $v-primary;
color: #fff;
padding: 5rpx 10rpx;
border-radius: 5rpx;
font-size: 14rpx;
}
}
.tips {
color: #595959;
font-size: 15rpx;
margin: 20rpx 0;
line-height: 2;
}
.pay-model {
display: flex;
justify-content: center;
align-items: center;
margin: 0 auto;
height: 60rpx;
border: 1rpx solid $v-primary;
border-radius: 5rpx;
background-color: rgba(241, 255, 245, .3);
;
color: $v-primary;
font-size: 18rpx;
letter-spacing: 2rpx;
image {
margin-right: 8rpx;
width: 20rpx;
height: 20rpx;
}
}
.hover-model {
background-color: #bebbbb;
color: #fff;
}
}
</style>

View File

@@ -0,0 +1,26 @@
const appConfig = {
// 项目名称
appName: '刷脸小程序',
// token取值key
tokenKey: 'iToken',
// 环境变量相关
env: {},
// 环境变量常量
ENV_ENUM: {
DEVELOPMENT: 'development', // 本地调试地址
TEST: 'test', // 测试地址
DEMO: 'demo', // 演示环境
PRODUCTION: 'production' // 生产环境
},
storeEnvEnumKey: 'currentEnvEnum', // 本地存储的envkey的值
encryptKey: '1234567890123456' // http数据加解密的key
}
export default appConfig;

42
jeepay-ui-uapp-face/env/config.js vendored Normal file
View File

@@ -0,0 +1,42 @@
/**
* ENV 的封装
* 由于uniapp 无法设置.env等打包属性实现线上线下多版本配置属性的无缝切换。
* process.env.NODE_ENV 将在打包环境通过编译器进行替换, 线上打包后无法获取到 process对象。 所以将配置属性统一封装到appConfig中。
*
* 环境地址环境枚举详见: appConfig.js
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2021/12/16 17:57
*/
import appConfig from '@/config/appConfig.js'
// uni-app 暂时不支持动态import导包app报错, 需要将所有的env全部导入 = = 、
import development from './env.development.js'
import test from './env.test.js'
import demo from './env.demo.js'
import production from './env.production.js'
const allEnvMap = {
development: development,
test: test,
demo: demo,
production: production,
}
// 获取当前环境变量
const processEnv = process.env.NODE_ENV
// 改变env环境
function changeEnv(envMode) {
appConfig.env = allEnvMap[envMode || processEnv]
// // 动态导包的方式设置全局env配置项目 : 当参数不存在, 那么获取node环境
// import(`./env.${envMode || processEnv}.js`).then(module => {
// appConfig.env = module.default
// }).catch(() => {
// appConfig.env = production //当出现错误, 比如本地没有复制dev文件时 默认使用生产环境
// })
}
export default { changeEnv: changeEnv }

3
jeepay-ui-uapp-face/env/env.demo.js vendored Normal file
View File

@@ -0,0 +1,3 @@
export default {
'JEEPAY_BASE_URL': 'https://mch.s.jeepay.com' // 请求URL (演示环境)
}

View File

@@ -0,0 +1,5 @@
export default {
// 'JEEPAY_BASE_URL': 'https://mch.s.jeepay.vip' // 请求URL测试地址
// 'JEEPAY_BASE_URL': 'http://192.168.0.168:9218' // 请求URL朱小·
'JEEPAY_BASE_URL': 'http://192.168.0.188:9218' // 请求URL (晓宇)
}

View File

@@ -0,0 +1,3 @@
export default {
'JEEPAY_BASE_URL': 'http://localhost:9218' // 请求URL开发地址
}

View File

@@ -0,0 +1,3 @@
export default {
'JEEPAY_BASE_URL': 'https://mch.jeepay.vip' // 请求URL生产环境
}

3
jeepay-ui-uapp-face/env/env.test.js vendored Normal file
View File

@@ -0,0 +1,3 @@
export default {
'JEEPAY_BASE_URL': 'https://mch.s.jeepay.vip' // 请求URL测试地址
}

View File

@@ -0,0 +1,110 @@
/**
* api接口管理 全部以$开头
* @author terrfly
* @site https://www.jeequan.com
* @date 2021/12/17 09:57
*/
import http from './http.js';
import { Base64 } from 'js-base64';
export const req = {
list: (uri, params) => {
return http.req(uri, params, 'GET', false);
},
add: (uri, data) => {
return http.req(uri, data, 'POST', false);
},
getById: (uri, bizId) => {
return http.req(`${uri}/${bizId}`, {}, 'GET', false);
},
updateById: (uri, bizId, data) => {
return http.req(`${uri}/${bizId}`, data, 'PUT', false);
},
delById: (uri, bizId) => {
return http.req(`${uri}/${bizId}`, {}, 'DELETE', false);
},
};
// 登录
export const $login = (v) => {
// 登录类型
let lt = '';
// #ifdef H5 || MP-WEIXIN || MP-ALIPAY
lt = Base64.encode('FACEAPP');
// #endif
let data = {
ia: Base64.encode(v.username),
ip: Base64.encode(v.pwd),
lt: lt,
};
return http.req('/api/anon/auth/validate', data, 'POST');
};
/** 支付订单列表 */
export const API_URL_PAY_ORDER_LIST = '/api/payOrder';
/* 订单退款 */
export function $payOrderRefund(vdata) {
return http.req(
'/api/payOrder/refunds/' + vdata.payOrderId,
{
refundAmount: vdata.refundAmountNum,
refundReason: vdata.refundReason,
refundPassword: Base64.encode(vdata.refundPassword),
},
'POST'
);
}
/* 获取个人信息 */
export function $userInfo(cid1, cid2) {
return http.req('/api/current/user', { cid1, cid2 }, 'GET');
}
// 首页 交易数据
export const $indexPayment = () => {
return http.req(
'/api/mainChart/payDayCount',
{ queryDateRange: 'today' },
'GET'
);
};
// 上下班 打卡接口
export const $workRecords = (workState) => {
return http.req('/api/user/workRecords', { workState: workState }, 'POST');
};
// 获取交班列表
export const $handover = () => {
return http.req('/api/user/workRecords/stats', {}, 'GET');
};
/* 支付接口*/
export function $appPay(amount, authCode) {
let data = { amount, wayCode: 'AUTO_BAR', authCode };
return http.req('/api/pay/app', data, 'POST');
}
// 支付方式统计
export const $payTypeStat = (data) => {
return http.req('/api/statistic', data, 'GET');
};
// 总支付方式统计
export const $payTypeStatAll = (data) => {
return http.req('/api/statistic/total', data, 'GET');
};
// 交班列表
export const $handoverList = (params) => {
return http.req('/api/user/workRecords', params, 'GET');
};
// 交班详情
export const $getHandoverById = (id) => {
return req.getById('/api/user/workRecords', id);
};
// 获取公司信息 技术支持电话
export const $getCompanyInfos = () => {
return http.req('/api/anon/siteInfos?queryConfig=1', {}, 'GET');
};
// 获取刷脸设备广告
export const $adBannerList = (params) => {
return http.req('/api/advert/faceDevice',params,'GET')
};

View File

@@ -0,0 +1,184 @@
/**
* HTTP的封装 基于uni.request
* 包括: 通用响应结果的处理 和 业务的增删改查函数
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2021/12/16 18:35
*/
// 导入全局属性
import appConfig from '@/config/appConfig.js';
import storageManage from '@/commons/utils/storageManage.js';
import { sm4DecryptByResData } from '@/commons/utils/encryptUtil.js';
import infoBox from "@/commons/utils/infoBox.js"
// 多少 ms 以内, 不提示loading
const loadingShowTime = 200;
// 通用处理逻辑
function commonsProcess(showLoading, httpReqCallback) {
// 判断是否请求完成(用作 是否loading
// 包括: 'ing', 'ingLoading', 'finish'
let reqState = 'ing';
// 是否已经提示的错误信息
let isShowErrorToast = false;
// 请求完成, 需要处理的动作
let reqFinishFunc = () => {
if (reqState == 'ingLoading') {
// 关闭loading弹层
uni.hideLoading();
}
reqState = 'finish'; // 请求完毕
};
// 明确显示loading
if (showLoading) {
// xx ms内响应完成不提示loading
setTimeout(() => {
if (reqState == 'ing') {
reqState = 'ingLoading';
uni.showLoading();
}
}, loadingShowTime);
}
return httpReqCallback()
.then((httpData) => {
reqFinishFunc(); // 请求完毕的动作
// 从http响应数据中解构响应数据 [ 响应码、 bodyData ]
let { statusCode, data } = httpData;
// 避免混淆重新命名
let bodyData = data;
if (statusCode == 401) {
// 清楚 token
storageManage.token(null, true);
// 提示信息
isShowErrorToast = true;
uni
.showToast({
title: '请登录',
icon: 'none',
duration: 3000,
})
.then(() => {
uni.reLaunch({
url: '/pages/login/login',
});
});
return Promise.reject(bodyData); // 跳转到catch函数
}
// http响应码不正确
if (statusCode != 200) {
isShowErrorToast = true;
uni.showToast({
title: '服务器异常',
});
return Promise.reject(bodyData); // 跳转到catch函数
}
// 业务响应异常
if (bodyData.code != 0) {
isShowErrorToast = true;
return Promise.reject(bodyData);
}
// 加密数据
if (!bodyData.data && bodyData.encryptData) {
return Promise.resolve({
bizData: sm4DecryptByResData(bodyData.encryptData),
code: bodyData.code,
});
}
// 构造请求成功的响应数据
return Promise.resolve({
bizData: bodyData.data,
code: bodyData.code,
});
})
.catch((res) => {
reqFinishFunc(); // 请求完毕的动作
// 如果没有提示错误, 那么此处提示 异常。
if (!isShowErrorToast) {
uni.showToast({
title: `请求网络异常`,
icon: 'none',
});
}else if(res.code != 0){
setTimeout(()=>{
infoBox.showToast(res.msg)
},200)
}
return Promise.reject(res);
})
.finally(() => {
// finally 是 then结束后再执行, 此处不适用。 需要在请求完成后立马调用: reqFinishFunc()
});
}
// 默认 显示loading(控制 xxs 内 不提示loading )
function req(uri, data, method = 'GET', showLoading = true, extParams = {}) {
// 放置token
let headerObject = {};
headerObject[appConfig.tokenKey] = storageManage.token();
headerObject.facedevice = JSON.stringify({
deviceNo: storageManage.deviceNo(), //写入设备号
//#ifdef MP-WEIXIN
provider: 'wxpayQWPro', //微信刷脸支付
//#endif
//#ifdef MP-ALIPAY
provider: 'alipayQT', //支付宝刷脸支付
//#endif
});
return commonsProcess(showLoading, () => {
return uni.request(
Object.assign(
{
url: appConfig.env.JEEPAY_BASE_URL + uri,
data: data,
method: method,
header: headerObject,
},
extParams
)
);
});
}
// 上传
function upload(uri, data, file, showLoading = true, extParams = {}) {
// 放置token
let headerObject = {};
headerObject[appConfig.tokenKey] = storageManage.token();
return commonsProcess(showLoading, () => {
return uni
.uploadFile(
Object.assign(
{
url: appConfig.env.JEEPAY_BASE_URL + uri,
formData: data,
name: 'file',
filePath: file.path,
header: headerObject,
},
extParams
)
)
.then((httpData) => {
// uni.upload 返回bodyData 的是 string类型。 需要解析。
httpData.data = JSON.parse(httpData.data);
return Promise.resolve(httpData);
});
});
}
export default {
req: req,
upload: upload,
};

View 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="/main.js"></script>
</body>
</html>

View File

@@ -0,0 +1,33 @@
// 设置env配置文件
import envConfig from '@/env/config.js'
// 全局配置项
import appConfig from '@/config/appConfig.js'
import storageManage from '@/commons/utils/storageManage.js'
import dataMap from './commons/utils/dataMap'
import infoBox from './commons/utils/infoBox'
// 设置node环境
envConfig.changeEnv(storageManage.env())
import App from './App'
// #ifndef VUE3
import Vue from 'vue'
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App,
})
app.$mount()
// #endif
// #ifdef VUE3
import { createSSRApp } from 'vue'
export function createApp() {
const app = createSSRApp(App)
uni.$J = { dataMap, ...infoBox }
return {
app,
}
}
// #endif

View File

@@ -0,0 +1,84 @@
{
"name" : "计全收银",
"appid" : "__UNI__B050E00",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
/* 5+App */
"app-plus" : {
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* */
"modules" : {},
/* */
"distribute" : {
/* android */
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
/* ios */
"ios" : {},
/* SDK */
"sdkConfigs" : {}
}
},
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "wx4710a1619fbb3714",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true,
"plugins" : {
"WechatSI" : {
"version" : "0.3.4",
"provider" : "wx069ba97219f66d99"
}
}
},
"mp-alipay" : {
"usingComponents" : true,
"appid" : "2019101868469623"
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "3",
"h5" : {
"router" : {
"base" : ""
}
}
}

View File

@@ -0,0 +1,17 @@
{
"name": "jeepay-ui-uapp-face",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"dayjs": "^1.11.7",
"gm-crypto": "^0.1.8",
"js-base64": "^3.7.4"
}
}

View File

@@ -0,0 +1,135 @@
{
"pages": [
//pages数组中第一项表示应用启动页参考https://uniapp.dcloud.io/collocation/pages
// #ifdef H5 || MP-WEIXIN
{
"path": "pages/index/index",
"style": {
"navigationStyle": "custom"
}
},
// #endif
// #ifdef MP-ALIPAY
{
"path": "pages/aliIndex/index",
"style": {
"navigationStyle": "custom",
"mp-alipay": {
"transparentTitle": "always",
"titlePenetrate": "YES",
"navigationBarBackgroundColor": "titlePenetrate"
}
}
},
// #endif
{
"path": "pages/login/login",
"style": {
"navigationStyle": "custom",
"mp-alipay": {
"transparentTitle": "always",
"titlePenetrate": "YES",
"navigationBarBackgroundColor": "titlePenetrate"
}
}
},
{
"path": "pages/handover/handover",
"style": {
"navigationBarTitleText": "交班统计",
"navigationBarBackgroundColor": "#fff"
}
},
{
"path": "pages/handover/handoverList",
"style": {
"navigationBarTitleText": "交班记录",
"navigationBarBackgroundColor": "#fff"
}
},
{
"path": "pages/order/order",
"style": {
"navigationStyle": "custom",
"mp-alipay": {
"transparentTitle": "always",
"titlePenetrate": "YES"
}
}
},
{
"path": "pages/order/orderDetails",
"style": {
"navigationBarTitleText": "订单详情",
"navigationBarBackgroundColor": "#fff"
}
},
{
"path": "pages/orderRefund/orderRefund",
"style": {
"navigationBarTitleText": "退款",
"navigationBarBackgroundColor": "#fff"
}
},
// #ifdef H5 || MP-WEIXIN
{
"path": "pages/payment/payment",
"style": {
"navigationBarTitleText": "",
"navigationBarBackgroundColor": "#F5F8F6"
}
},
{
"path": "pages/payWait/payWait",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/paySuc/paySuc",
"style": {
"navigationStyle": "custom"
}
},
// #endif
{
"path": "pages/stat/stat",
"style": {
"navigationBarTitleText": "营收统计"
}
},
// #ifdef H5 || MP-WEIXIN
{
"path": "pages/front/front",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/frontPay/frontPay",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/payModel/payModel",
"style": {
"navigationStyle": "custom"
}
}
// #endif
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "",
// #ifdef H5 || MP-WEIXIN
"navigationBarBackgroundColor": "#F8F8F8",
// #endif
// #ifdef MP-ALIPAY
"navigationBarBackgroundColor": "#FFFFFF", //或者设置为#FFFFFF支付宝小程序才能在导航上显示黑色文字
// #endif
"backgroundColor": "#F8F8F8"
},
"uniIdRouter": {}
}

View File

@@ -0,0 +1,403 @@
<template>
<view class="index-wrapper">
<poster id="ali-poster" posid="idle_pos" :audible="true" style="width: 100%; height: 88vh"
onSuccess="onDisplaySuccess" onFail="onDisplayFail" onChange="onPosterChange"
v-if="!vdata.userInfo.realname || !vdata.adList.length" />
<JeepayBanner v-else :list="vdata.adList" :interval="vdata.changeTime" />
<!-- <view style="width: 100%; height: 88vh"></view> -->
<view class="idnex-wrapper">
<view class="left">
<view class="tips-title">请等待商家发起收款</view>
<view class="store-name">付款给{{ vdata.userInfo.realname }}</view>
</view>
<view class="right">
<view class="more-but log-in" hover-class="hover-more" hover-stay-time="50" v-if="!vdata.userInfo.realname"
@tap="toLogin">请登录</view>
</view>
</view>
</view>
<uni-drawer ref="refShowRight" mode="right" @change="change">
<view class="list-wrapper" :style="{ '--text-color': calcWorkState().value == 1 ? ' #108ee9' : 'tomato' }">
<blocke v-for="(v, i) in vdata.navList" :key="i">
<view class="list-item" hover-class="hover-more" hover-stay-time="50" @tap="tapNav(v)"
v-if="v.value.includes(vdata.modelType)">
{{ v.title }}
<view class="list-item-right">
<view class="face-model" v-if="v.title == '切换模式'">当前模式{{ vdata.modelType == 'pos' ? 'POS' : '独立收银' }}模式
</view>
<image src="/static/right.svg" mode="scaleToFill" v-if="i != vdata.navList.length - 1" />
<image src="/static/logout.svg" mode="scaleToFill" v-else />
</view>
</view>
</blocke>
</view>
</uni-drawer>
<SwitchModelCard ref="refSwitch" @makClose="open" v-model:value="vdata.modelType" />
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app'
import { computed, onMounted, reactive, ref } from 'vue'
import { req, $appPay, $workRecords, $userInfo, API_URL_PAY_ORDER_LIST, $adBannerList } from '@/http/apiManager'
import storageManage from '@/commons/utils/storageManage.js'
// 生命周期 进入页面
onLoad(() => {
if (storageManage.token()) {
getAd()
}
})
// 初始化 modelType
if (!storageManage.faceModel()) {
storageManage.faceModel('cashier')
}
const refShowRight = ref(null)
const refSwitch = ref(null)
const vdata = reactive({
userInfo: storageManage.userInfo(), //取出用户信息
navList: [
{ title: '订单', url: '/pages/order/order', value: 'cashier' },
{ title: '统计', url: '/pages/stat/stat', value: 'cashier' },
{ title: `${calcWorkState().value == 1 ? '上班' : '下班'}打卡`, fun: working, value: 'cashier' },
{ title: '交班', url: '/pages/handover/handover', value: 'cashier' },
{ title: '切换模式', fun: switchModel, value: 'cashierpos' },
{ title: '系统设置', fun: () => { my.ix.startApp({ appName: 'settings' }) }, value: 'cashierpos' },
{ title: '刷新广告数据', fun: getAd, value: 'cashierpos' },
{ title: '退出登录', fun: loginOut, value: 'cashier' }
],
modelType: storageManage.faceModel(), //取出本地存储的模式类型
adList:[]
})
my.ix.onKeyEventChange(r => {
// console.log('r', r)
const timeStamp = new Date().getTime()
switch (r.keyCode) {
case 134:
if (!storageManage.token()) return uni.$J.showErrorToast('请先登录')
if (vdata.isShow) return my.ix.startApp({ appName: 'settings' })
open()
break
case 132:
if (storageManage.faceModel() && storageManage.faceModel() == 'pos') return posCashier()
break
case 131: //收款按键
if (storageManage.faceModel() && storageManage.faceModel() == 'pos') return posCashier()
my.ix
.startApp({
appId: '2021002172674746',
appName: 'cashier',
bizNo: timeStamp,
totalAmount: r.amount,
showScanPayResult: true,
scanLoadingTimeout: '10'
})
.then(res => {
my.ix.writeHID({
protocol: 'barcode',
value: res.barCode,
success: r => {
console.log('r', r)
},
fail: err => {
console.log('err', err)
}
})
$appPay(res.totalAmount, res.barCode).then(r => {
findOrderState(r.bizData)
console.log('支付后结果', r)
//扫码付支付成功主动调起结果页
if (res.codeType == 'C' && r.bizData.orderState == 2) {
my.ix.startApp({
appName: 'scanPayResult',
bizNo: timeStamp,
totalAmount: res.totalAmount,
success: r => {
console.log(r)
}
})
}
})
})
.catch(err => {
console.log('err', err)
})
break
case 133:
close()
break
}
})
// 展示成功回调
const onDisplaySuccess = () => {
console.log('poster display success')
}
// 展示失败回调
const onDisplayFail = e => {
console.log('poster display fail, error = ' + e.detail.error)
}
// 广告可用性变化回调
const onPosterChange = e => {
console.log('poster availability changed, now has poster = ' + e.detail.hasPoster)
}
// 打开抽屉
const open = () => {
refShowRight.value.open()
}
// 关闭抽屉
const close = () => {
refShowRight.value.close()
}
// pos 收银模式
function posCashier() {
const timeStamp = new Date().getTime()
my.ix
.startApp({
appId: '2021002172674746',
appName: 'cashier',
bizNo: timeStamp,
showScanPayResult: true,
scanLoadingTimeout: '10'
})
.then(res => {
my.ix.writeHID({
protocol: 'barcode',
value: res.barCode,
success: r => {
console.log('r', r)
},
fail: err => {
console.log('err', err)
}
})
})
}
// 退出等领域
function loginOut() {
uni.showModal({
title: '提示',
content: '是否确认退出登录',
showCancel: true,
success: ({ confirm, cancel }) => {
if (confirm) {
storageManage.cleanByLogout()
uni.reLaunch({
url: '/pages/login/login'
})
}
}
})
}
// 打卡函数
function working() {
uni.showModal({
title: `提示:${calcWorkState().value == 1 ? '上班' : '下班'}打卡`,
content: '是否确认打卡?',
showCancel: true,
success: ({ confirm, cancel }) => {
if (confirm) {
$workRecords(calcWorkState().value).then(res => {
uni.showToast({
title: '打卡成功',
icon: 'success',
mask: true
})
// 重新请求用户信息
$userInfo().then(({ bizData }) => {
// 更新用户数据
storageManage.userInfo(bizData)
// 更新用户数据
vdata.userInfo = bizData
vdata.navList[2].title = (calcWorkState().value == 1 ? '上班' : '下班') + '打卡'
})
})
}
}
})
}
// 切换模式函数、
function switchModel() {
refShowRight.value.close()
refSwitch.value.open()
}
/****
* @param {v} Object url 跳转地址 fun 执行函数
* */
const tapNav = v => {
if (v.url)
return uni.navigateTo({
url: v.url
})
v.fun()
}
// 计算状态上班还是下班 0 未知 1上班 2下班
function calcWorkState() {
return computed(() => {
const state = storageManage.userInfo().workState
return state == 0 ? '1' : state == 1 ? 2 : 1
})
}
// 定向到登录页
const toLogin = () => uni.reLaunch({ url: '/pages/login/login' })
function findOrderState(val) {
switch (val.orderState) {
case 2:
break
case 3:
uni.$J.showToast('支付失败' + val.errMsg)
break
case 4:
uni.$J.showToast('订单撤销')
break
case 1:
// 支付中 进行查单操作
console.log('订单状态1进行查单 操作 ')
findOrder(val.payOrderId)
break
}
}
let num = 1
function findOrder(payOrderId) {
if (num > 20)
return uni.showModal({
title: '确认订单状态',
content: '订单状态查询失败 请与客户确认订单状态 点击确认跳转订单列表页面',
showCancel: true,
success: ({ confirm, cancel }) => {
if (confirm) {
uni.navigateTo({
url: '/pages/order/order'
})
}
}
})
uni.$J.showToast(`支付中正在进行第${num}次订单查询`).then(res => {
req.getById(API_URL_PAY_ORDER_LIST, payOrderId).then(({ bizData }) => {
num += 1
console.log('查单结果', bizData)
bizData.orderState = bizData.state
findOrderState(bizData)
})
})
}
function getAd() {
$adBannerList().then(({ bizData }) => {
if(!bizData){
vdata.adList =[]
uni.showToast({title:'请求广告数据成功',icon:'success'})
return false
}
vdata.adList = bizData?.appContent ? JSON.parse(bizData.appContent) : []
vdata.changeTime = bizData.changeTime
uni.showToast({title:'请求广告数据成功',icon:'success'})
})
}
// 抽屉打开状态
const change = (e) => {
vdata.isShow = e
}
</script>
<style lang="scss" scoped>
.idnex-wrapper {
padding: 30rpx;
box-sizing: border-box;
height: 11.8vh;
display: flex;
justify-content: space-between;
align-items: center;
color: #108ee9;
.tips-title {
font-size: 38rpx;
margin-bottom: 20rpx;
}
.store-name {
color: #2c2c2c;
font-size: 22rpx;
}
.more-but {
display: flex;
align-items: center;
justify-content: center;
min-width: 80rpx;
height: 50rpx;
border-radius: 7rpx;
background-color: rgba($color: #108ee9, $alpha: 0.3);
view {
width: 4rpx;
height: 4rpx;
border-radius: 50%;
background-color: #108ee9;
}
view:nth-child(2) {
margin: 0 4rpx;
}
}
}
.list-wrapper {
margin-top: 100rpx;
.list-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx 10rpx 30rpx 30rpx;
box-sizing: border-box;
background-color: rgba($color: #108ee9, $alpha: 0.05);
color: #108ee9;
image {
width: 60rpx;
height: 40rpx;
}
.list-item-right {
flex: 1;
display: flex;
justify-content: flex-end;
align-items: center;
.face-model {
font-size: 24rpx;
}
}
}
.list-item:nth-child(3) {
color: var(--text-color);
}
.list-item:nth-child(8) {
position: absolute;
left: 0;
right: 0;
bottom: 0;
color: tomato;
background-color: rgba(255, 99, 71, 0.05);
image {
svg {
fill: tomato !important;
}
}
}
}
.hover-more {
background-color: rgba($color: #000000, $alpha: 0.07) !important;
}
.log-in {
display: flex;
justify-content: center;
align-items: center;
padding: 5rpx 15rpx;
}
</style>

View File

@@ -0,0 +1,97 @@
<template>
<view class="front-wrapper">
<view class="tips-title" v-if="!vdata.adList.length">等待商家发起收款</view>
<JeepayBanner v-else :list="vdata.adList" :interval="vdata.changeTime" height="calc(100vh - 150rpx)" />
</view>
</template>
<script setup>
import { reactive, ref } from 'vue'
import { onReady, onLoad } from '@dcloudio/uni-app'
import storageManage from '@/commons/utils/storageManage.js'
import { $adBannerList } from '@/http/apiManager'
import envConfig from '@/env/config.js'
// 接收 后屏 通讯 去支付页面
onReady(() => {
wxfaceapp.onRemoteMessage(function (res) {
const content = JSON.parse(res.content)
if (content.type == 'toPay')
return uni.navigateTo({
url: '/pages/frontPay/frontPay',
})
if (content.type == 'adBanner') {
envConfig.changeEnv(content.env)
console.log('content.env', content.env)
envConfig.changeEnv(content.env)
storageManage.token(content.token) //存入token
return getAd()
}
})
// 关闭扫码器
wxfaceapp.stopCodeScanner({})
})
const vdata = reactive({})
function getAd () {
$adBannerList().then(({ bizData }) => {
if (!bizData) return vdata.adList = []
vdata.adList = JSON.parse(bizData.appContent) || []
vdata.changeTime = bizData.changeTime
})
}
</script>
<style lang="scss" scoped>
.front-wrapper {
// padding: 0.01rpx;
width: 100%;
}
.swiper {
height: 100%;
}
.swiper-item {
display: block;
height: 100%;
line-height: 300rpx;
text-align: center;
}
.swiper-list {
margin-top: 40rpx;
margin-bottom: 0;
}
.uni-common-mt {
margin-top: 60rpx;
position: relative;
}
.info {
position: absolute;
right: 20rpx;
}
.uni-padding-wrap {
width: 550rpx;
padding: 0 100rpx;
}
.tips-title {
display: flex;
justify-content: center;
align-items: center;
margin: 160rpx auto;
width: 85%;
height: 180rpx;
font-size: 32rpx;
font-weight: 600;
letter-spacing: 2rpx;
color: #fff;
border-radius: 14rpx;
background-color: rgba($color: #64ec46, $alpha: .7);
}
</style>

View File

@@ -0,0 +1,207 @@
<template>
<!-- <view class="front-wrapper">
<view class="pay-amount" v-if="vdata.isShow">
请支付<view>{{ vdata.amount }}()</view>
</view>
<view class="pay-but">
<JButton @tap="facePay">使用刷脸支付</JButton>
</view>
<view class="pay-tips">请将付款码对准右下角识别区距离10厘米左右</view>
</view> -->
<view class="wait-pay-top" v-if="vdata.isShow">
<view class="pay-info">
<view class="pay-num">{{ vdata.amount }}</view>
<view class="pay-wait-title">请支付</view>
</view>
</view>
<view class="face-button" @tap="facePay">
<image src="/static/fronyImg/face-icon.svg" mode="scaleToFill" />
刷脸支付
</view>
<view class="face-scan-tips">
<view class="scan-title">
<image src="/static/fronyImg/scan-code.svg" mode="scaleToFill" />
扫码支付
</view>
<view class="sub-tips"> 请将付款码对准右下角识别区距离10厘米左右 <image src="/static/fronyImg/icon-down.svg" mode="scaleToFill" /> </view>
</view>
</template>
<script setup>
import { reactive, ref } from 'vue'
import { onReady, onLoad } from '@dcloudio/uni-app'
onLoad(() => {
vdata.isShow = true
//接受 后屏信息
wxfaceapp.onRemoteMessage(function (res) {
console.log('后屏消息', res)
analysisMsg(JSON.parse(res.content))
})
wxfaceapp.startCodeScanner({
success: (res) => {
console.log('打开扫码器成功')
console.log(res.replyCode)
console.log(res.reply)
//声明监听扫码器 使用 扫码器 扫描 后 调用 扫码器 回调事件 获取支付code
wxfaceapp.listenCodePayment({
success(res) {
//被扫码回调事件
wxfaceapp.onCodePayEvent(function (r) {
console.log('onCodePayEvent code scanned = ' + r)
console.log('扫码器', r)
postMsg(r)
})
},
})
},
fail: (res) => {
console.log('打开扫码器失败')
console.log(res.replyCode)
console.log(res.reply)
},
})
})
/**
* 页面初始化完成 监听数据串口 输入事件
* */
// onReady(() => {
// wxfaceapp.startSerialPortObserver({
// success: (r) => {
// console.log('开启监听串口输入成功', r)
// },
// fail: (err) => {
// console.log('开启监听串口输入失败:', err)
// },
// })
// })
const vdata = reactive({
amount: '0.00',
isShow: true,
})
// 微信刷脸 刷脸成功后 使用回调 换取支付code
const facePay = () => {
wxfaceapp.facePay({
requireFaceCode: true, //是否需要获取付款码返回给小程序
success(res) {
console.log('success [launchFaceApp]')
console.log('前屏刷脸结果', res)
wxfaceapp.onFacePayPassEvent(function (r) {
console.log('微信支付回调', r)
postMsg(r)
})
},
fail(res) {
console.log('fail [launchFaceApp]')
console.log(res.replyCode)
console.log(res.reply)
},
})
}
// 发送给后屏
const postMsg = (content) => {
wxfaceapp.postMsg({
targetAppid: 'wx4710a1619fbb3714',
content: JSON.stringify(content),
success(res) {
console.log('sendMsgResult suc', res)
},
fail(res) {
console.log('sendMsgResult failed error = ' + res)
},
})
}
/*
* 解析后屏 发送的消息
* type 值 amount 金额 toBanner 去广告页面
*
* */
function analysisMsg(msg) {
console.log('msg', msg)
switch (msg.type) {
case 'amount':
vdata.amount = msg.amount
break
case 'toBanner':
wxfaceapp.stopCodeScanner({})
uni.navigateTo({
url: '/pages/front/front',
})
break
case 'hideAmount':
vdata.isShow = false
break
}
}
</script>
<style lang="scss" scoped>
.wait-pay-top {
display: flex;
justify-content: center;
align-items: center;
height: 60vh;
background: url('/static/fronyImg/front-bg.svg') no-repeat center / cover;
.pay-info {
transform: translateY(-80rpx);
color: #fff;
.pay-num {
font-weight: 700;
font-size: 62rpx;
font-family: wechat sans;
}
.pay-wait-title {
text-align: center;
font-size: 32rpx;
color: rgba($color: #fff, $alpha: 0.5);
}
}
}
.face-button {
background-color: $v-primary;
display: flex;
justify-content: center;
align-items: center;
margin: 65rpx 40rpx;
height: 120rpx;
border-radius: 15rpx;
color: #fff;
font-size: 32rpx;
box-shadow: 0 50rpx 50rpx -50rpx rgba(0, 206, 107, 0.5);
image {
width: 50rpx;
margin-right: 10rpx;
}
}
.face-scan-tips {
box-sizing: border-box;
padding: 20rpx 0;
padding-top: 40rpx;
margin-top: 20rpx;
height: calc(100vh - 60vh - 250rpx);
background-color: rgba($color: $v-primary, $alpha: 0.2);
.scan-title {
display: flex;
justify-content: center;
align-items: center;
font-size: 32rpx;
color: $v-primary;
image {
width: 50rpx;
height: 50rpx;
margin-right: 10rpx;
}
}
.sub-tips {
margin-top: 25rpx;
display: flex;
justify-content: center;
align-items: center;
color: #666;
font-size: 22rpx;
image {
width: 25rpx;
height: 25rpx;
}
}
}
</style>

View File

@@ -0,0 +1,135 @@
<template>
<!-- 门店展示 暂时接口不满足 -->
<!-- <view class="hand-item">
<view class="hand-title">门店</view>
<view class="hand-info">小伙计</view>
</view> -->
<view class="hand-item">
<view class="hand-title">收银员</view>
<view class="hand-info">{{ vdata.realname || vdata.userInfo.realname }}</view>
</view>
<view class="hand-item">
<view class="hand-title">上班时间</view>
<view class="hand-info">{{ vdata.workStartTime }}</view>
</view>
<view class="hand-item">
<view class="hand-title">下班时间</view>
<view class="hand-info">{{ vdata.workEndTime }}</view>
</view>
<view class="line"></view>
<view class="hand-item">
<view class="hand-title">收款金额</view>
<view class="hand-info">{{ vdata.payAmount }}</view>
</view>
<view class="hand-item">
<view class="hand-title">收款笔数</view>
<view class="hand-info">{{ vdata.payCount }}</view>
</view>
<view class="hand-item">
<view class="hand-title">退款金额</view>
<view class="hand-info">{{ vdata.refundAmount }}</view>
</view>
<view class="hand-item">
<view class="hand-title">退款笔数</view>
<view class="hand-info">{{ vdata.refundCount }}</view>
</view>
<view class="footer-but" v-if="vdata.userInfo.realname">
<view @tap="handHandover">交班</view>
<view class="record" @tap="toHandoverList">交班记录</view>
</view>
</template>
<script setup>
import { $handover, $workRecords, $getHandoverById } from '@/http/apiManager'
import { reactive, ref } from 'vue'
import storageManage from '@/commons/utils/storageManage.js'
import { onLoad } from '@dcloudio/uni-app'
import cal from '@/commons/utils/cal.js'
import dayjs from 'dayjs'
onLoad((options) => {
getHandoverInfo(options.id)
})
const vdata = reactive({
userInfo: storageManage.userInfo(),
})
const getHandoverInfo = (id) => {
if (id) {
uni.setNavigationBarTitle({
title: '交班详情',
})
$getHandoverById(id).then(({ bizData }) => {
bizData = cal.yuan(bizData, ['refundAmount', 'payAmount'])
Object.assign(vdata, bizData)
console.log(bizData)
})
return
}
$handover().then(({ bizData }) => {
bizData = cal.yuan(bizData, ['refundAmount', 'payAmount'])
Object.assign(vdata, bizData)
})
}
const handHandover = () => {
uni.showModal({
title: '是否确认交班?',
content: '交班自动下班 并 退出登录',
showCancel: true,
success: ({ confirm, cancel }) => {
if (confirm) {
$workRecords('2').then((res) => {
uni.$J.showToast('交班成功即将退登录').then((r) => {
storageManage.cleanByLogout()
uni.reLaunch({
url: '/pages/login/login',
})
})
})
}
},
})
}
const toHandoverList = () => uni.navigateTo({ url: '/pages/handover/handoverList' })
</script>
<style lang="scss" scoped>
.hand-item {
display: flex;
justify-content: space-between;
padding: 30rpx;
font-size: 28rpx;
// border-bottom: 1rpx solid #ededed;
.hand-info {
color: #bbb;
}
}
.line {
height: 15rpx;
background-color: #ededed;
}
.footer-but {
display: flex;
justify-content: space-around;
margin-top: 60rpx;
view {
flex: 0 0 30%;
display: flex;
justify-content: center;
align-items: center;
height: 70rpx;
background-color: $v-primary;
border-radius: 14rpx;
color: #fff;
font-size: 22rpx;
}
.record {
background-color: rgba($color: $v-primary, $alpha: 0.7);
}
}
</style>

View File

@@ -0,0 +1,155 @@
<template>
<view class="page-wrapper">
<view class="custom-content">
<view class="start-time" :style="{ color: vdata.startTime ? '#000' : '#666' }" @tap="refStartTime.show">{{
vdata.startTime || '请选择开始时间'
}}</view>
<view class="endTime-time" :style="{ color: vdata.endTime ? '#000' : '#666' }" @tap="refEndTime.show">{{
vdata.endTime || '请选择结束时间'
}}</view>
</view>
<block v-for="v in vdata.list" :key="v.id">
<view class="list-main" @tap="toDetails(v.id)">
<view class="left">
<view class="title">{{ v.realname }}</view>
<view class="time">{{ v.workStartTime }}</view>
</view>
<view class="line"></view>
<view class="right">
<view class="amount title">{{ (v.successAmount / 100).toFixed(2) }}</view>
<view class="time">{{ v.workEndTime || '未下班' }}</view>
</view>
</view>
</block>
<view class="list-null" v-if="!vdata.hasNext">暂无更多数据</view>
</view>
<xp-picker mode="ymdhi" ref="refStartTime" @confirm="timeConfirm($event, 'startTime')">
<view></view>
</xp-picker>
<xp-picker mode="ymdhi" ref="refEndTime" @confirm="timeConfirm($event, 'endTime')">
<view></view>
</xp-picker>
</template>
<script setup>
import { reactive, ref } from 'vue'
import { onLoad, onReachBottom, onUnload } from '@dcloudio/uni-app'
import { $handoverList } from '@/http/apiManager'
import dayjs from 'dayjs'
const refStartTime = ref(null)
const refEndTime = ref(null)
const vdata = reactive({
list: [],
hasNext: true,
})
const params = {
pageSize: 10,
pageNumber: 1,
queryDateRange: '',
}
const getList = () => {
if (!vdata.hasNext) return
$handoverList(params).then(({ bizData }) => {
vdata.list.push(...bizData.records)
vdata.hasNext = bizData.hasNext
})
}
getList()
onReachBottom(() => {
params.pageNumber += 1
getList()
})
/**
* @param {e} Object 组件原生 回调 时间戳 日期
* @param {key} String vdata 对象的 key 值 赋值使用
* */
const timeConfirm = (e, key) => {
vdata[key] = dayjs(e.timestamp).format('YYYY-MM-DD hh:mm')
if (key == 'endTime' || (vdata.endTime != undefined && dayjs(vdata.startTime).isAfter(vdata.endTime))) {
console.log('进入请求')
params.queryDateRange = `customDateTime_${vdata.startTime + ':00'}_${vdata.endTime + ':00'}`
vdata.list = []
params.pageNumber = 1
vdata.hasNext = true
getList()
}
}
/**
* @param {id} String 用于 和后端交互请求详情
* */
const toDetails = (id) => {
uni.navigateTo({
url: '/pages/handover/handover?id=' + id,
})
}
</script>
<style lang="scss" scoped>
.list-main {
display: flex;
justify-content: space-between;
padding: 15rpx;
margin: 30rpx;
background-color: #fff;
border-radius: 14rpx;
.title {
font-size: 22rpx;
font-weight: 600;
margin-bottom: 10rpx;
}
.amount {
color: $v-primary;
}
.line {
align-self: flex-end;
}
.right {
text-align: right;
}
.time,
.line {
color: #ccc;
}
}
.custom-content {
display: flex;
justify-content: space-around;
margin-top: 30rpx;
view {
flex: 0 0 30%;
padding: 10rpx 0;
background-color: #ded7d7;
text-align: center;
border-radius: 10rpx;
font-size: 16rpx;
}
}
.list-null {
display: flex;
justify-content: space-between;
align-items: center;
color: #666;
margin: 30rpx 0;
padding: 0 30rpx;
font-size: 24rpx;
font-weight: 600;
&::after,
&::before {
content: '';
display: block;
width: 35%;
height: 2rpx;
background-color: #ededed;
}
}
</style>

View File

@@ -0,0 +1,492 @@
<template>
<view class="page-wrapper">
<uni-nav-bar statusBar :border="false" leftWidth="50%" backgroundColor="transparent">
<template #left>
<view class="user-info">
<image :src="vdata.userInfo.avatarUrl" mode="scaleToFill" />
<view class="user-nickname">{{ vdata.userInfo.realname }}</view>
</view>
</template>
</uni-nav-bar>
<!-- 卡片部分 -->
<view class="index-card">
<view class="index-content">
<view class="index-main">
<view class="index-num">{{ vdata.indexData.payAmount }}</view>
<view class="index-title">今日总收益()</view>
</view>
<view class="index-main">
<view class="index-num">{{ vdata.indexData.refundAmount }}</view>
<view class="index-title">退款金额()</view>
</view>
</view>
<view class="index-card-footer">
<view>收益详情</view>
<view @tap="more">查看更多 ></view>
</view>
</view>
<!-- 发起收款 -->
<view class="pay-card" @tap="jumpPage('/pages/payment/payment')">
<image src="/static/indexImg/pay.png" mode="scaleToFill" />
<view class="pay-text">发起收款</view>
</view>
<!-- nav 导航部分 -->
<view class="index-nav">
<view class="nav-content">
<block v-for="(v, i) in navList" :key="i">
<view class="nav-main" @tap="jumpPage(v.url)">
<image :src="v.img" mode="scaleToFill" />
<view class="nav-title">{{ v.navTitle }}</view>
</view>
</block>
</view>
<view class="but-content">
<view>
<JButton @tap="switchOpen" bgColor="rgba(0, 200, 0,0.15)" color="#00C800" bdColor="#00C800" :size="24">切换收款模式
</JButton>
</view>
<view>
<JButton @tap="open"
:bgColor="vdata.userInfo.workState == 2 ? 'rgba(0, 128, 255,0.15)' : 'rgba(255, 0, 43,0.15)'"
:color="vdata.userInfo.workState == 2 ? '#0080FF' : '#FF002B'"
:bdColor="vdata.userInfo.workState == 2 ? '#0080FF' : '#FF002B'" :size="24">{{
vdata.userInfo.workState == 1 ? '下班' : vdata.userInfo.workState == 2 ? '上班' : '上班' }}打卡</JButton>
</view>
<view>
<JButton bgColor="rgba(255, 170, 0,0.15)" color="#FFAA00" bdColor="#FFAA00" :size="24" @tap='getFrontAd'>刷新前屏广告
</JButton>
</view>
</view>
<view style="height: 20rpx"></view>
<JButton @tap="loginOut" bgColor="transparent" bdColor="rgba(0,0,0,0.1)" color="#FF002B">退出登录</JButton>
</view>
</view>
<uni-popup ref="refWorker" type="center">
<view class="worker-content">
<view class="title">{{ vdata.userInfo.workState == 1 ? '下班' : vdata.userInfo.workState == 2 ? '上班' : '上班' }}打卡
</view>
<view class="worker-time">请确认打卡时间{{ dayjs().format('YYYY-MM-DD hh:mm') }}</view>
<view class="footer-but">
<view @tap="close">取消</view>
<view class="confirm"
@tap="confirmWorker(vdata.userInfo.workState == 1 ? '2' : vdata.userInfo.workState == 2 ? '1' : '1')">确认 </view>
</view>
</view>
</uni-popup>
<uni-popup ref="refSwitch" type="center">
<view class="switch-model">
<view class="title">切换模式</view>
<view class="sub-title">独立收银模式<view class="model-tag">当前正在使用</view>
</view>
<view class="tips">接入电源后即可使用后屏输入收款金额前屏支持刷脸支付和扫码支付</view>
<view class="sub-title">POS模式</view>
<view class="tips">需要连接收银机或PC使用即插即用收款将会进入您的现有收银软件账户</view>
<view class="pay-model" hover-class="hover-model" hover-stay-time="50" @tap="toPos">
<image src="/static/iconImg/switch-model.svg" mode="scaleToFill" />
切换至POS模式
</view>
</view>
</uni-popup>
</template>
<script setup>
import { reactive, ref } from 'vue'
import { $indexPayment, $workRecords, $userInfo, $adBannerList } from '@/http/apiManager'
import { onLoad, onReady, onUnload, onShow } from '@dcloudio/uni-app'
import storageManage from '@/commons/utils/storageManage.js'
import cal from '@/commons/utils/cal.js'
import dayjs from 'dayjs'
onLoad(() => {
getFrontAd()
if (storageManage.faceModel() && storageManage.faceModel() == 'pos') return uni.reLaunch({ url: '/pages/payModel/payModel' })
})
onShow(() => {
getIndexDate()
})
const refWorker = ref(null)
const refSwitch = ref(null)
// 导航栏列表
const navList = [
{
img: '/static/indexImg/order.png',
url: '/pages/order/order',
navTitle: '订单',
},
{
img: '/static/indexImg/handover.png',
url: '/pages/handover/handover',
navTitle: '交班',
},
{
img: '/static/indexImg/statics.png',
url: '/pages/stat/stat',
navTitle: '统计',
},
]
const vdata = reactive({
userInfo: storageManage.userInfo(), //取出用户信息
indexData: {},
})
// 查询 当天 收益情况
const getIndexDate = () => {
$indexPayment().then(({ bizData }) => {
const { dayCount } = bizData
vdata.indexData = cal.yuan(dayCount, ['payAmount', 'refundAmount']) //分转元
})
}
const open = () => refWorker.value.open()
const close = () => refWorker.value.close()
const switchOpen = () => refSwitch.value.open()
// 确认打卡
const confirmWorker = (state) => {
$workRecords(state).then((res) => {
uni.showToast({
title: '打卡成功',
icon: 'success|none',
mask: true,
})
// 请求用户信息
return $userInfo().then(({ bizData }) => {
// 更新用户数据
storageManage.userInfo(bizData)
// 更新用户数据
vdata.userInfo = bizData
//跳转首页
close()
})
})
}
const loginOut = () => {
uni.showModal({
title: '确认推出登录吗',
content: '',
showCancel: true,
success: ({ confirm, cancel }) => {
if (confirm) {
storageManage.cleanByLogout()
uni.reLaunch({
url: '/pages/login/login',
})
}
},
})
}
const toFront = () => uni.navigateTo({ url: '/pages/front/front' })
const jumpPage = (url) => uni.navigateTo({ url })
uni.addInterceptor('navigateTo', {
invoke(args) {
if (vdata.userInfo.workState != 1 && args.url == '/pages/handover/handover') {
uni.showModal({
title: '提示',
content: '当前状态为,未上班状态,不能进入交班页面,点击确认按钮打卡上班。 ',
showCancel: true,
success: ({ confirm, cancel }) => {
if (confirm) {
refWorker.value.open()
}
},
})
return false
}
},
})
const toPos = () => {
uni.showModal({
title: '提示',
content: '是否切换为 POS模式',
showCancel: true,
success: ({ confirm, cancel }) => {
if (confirm) {
storageManage.faceModel('pos')
uni.reLaunch({ url: '/pages/payModel/payModel' })
}
},
})
}
const more = () => {
uni.navigateTo({ url: '/pages/stat/stat' })
}
const getFrontAd = () => {
const content = { type: 'adBanner', token: storageManage.token(), env: storageManage.env() }
wxfaceapp.postMsg({
targetAppid: 'wx4710a1619fbb3714',
content: JSON.stringify(content),
success(res) {
uni.$J.showToast('通知前屏获取广告成功')
console.log('通信成功', res)
},
fail(res) {
console.log('通信失败 ', res)
},
})
}
onUnload(() => {
uni.removeInterceptor('navigateTo')
})
</script>
<style lang="scss" scoped>
.page-wrapper {
position: relative;
min-height: 100vh;
background: url('/static/indexImg/index-bg.png') no-repeat center center;
background-size: 100% 100%;
}
.user-info {
display: flex;
align-items: center;
image {
width: 50rpx;
height: 50rpx;
}
.user-nickname {
margin-left: 20rpx;
font-weight: 700;
font-size: 22rpx;
}
}
// 收益卡片
.index-card {
margin: 30rpx;
background: url('/static/indexImg/databg.png') no-repeat center center;
background-size: 100% 100%;
border-radius: 22rpx;
.index-content {
display: flex;
justify-content: space-around;
.index-main {
display: flex;
flex-direction: column;
align-items: center;
margin: 50rpx;
color: #fff;
.index-num {
margin-bottom: 15rpx;
font-size: 45rpx;
font-weight: 700;
}
.index-title {
font-size: 24rpx;
color: rgba($color: #fff, $alpha: 0.6);
}
}
}
.index-card-footer {
display: flex;
justify-content: space-between;
padding: 20rpx;
view {
font-size: 24rpx;
color: rgba($color: #fff, $alpha: 0.6);
}
}
}
// 发起收款
.pay-card {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin: 30rpx 30rpx;
margin-top: 60rpx;
height: 145rpx;
background: url('/static/indexImg/paybg.png') no-repeat center center;
background-size: 100% 100%;
color: #fff;
border-radius: 22rpx;
image {
width: 50rpx;
height: 50rpx;
margin-bottom: 20rpx;
}
.pay-text {
font-weight: 900;
font-size: 22rpx;
}
}
// nav 导航
.index-nav {
position: absolute;
bottom: 30rpx;
left: 0;
right: 0;
// background-color: tomato;
background-color: transparent;
.nav-content {
display: flex;
padding: 0 30rpx;
justify-content: space-between;
margin-bottom: 50rpx;
.nav-main {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 25%;
height: 180rpx;
background-size: 100% 100%;
border-radius: 15rpx;
color: #fff;
&:nth-child(1) {
background: url('/static/indexImg/orderbg.png') no-repeat center center;
}
&:nth-child(2) {
background: url('/static/indexImg/handoverbg.png') no-repeat center center;
}
&:nth-child(3) {
background: url('/static/indexImg/staticsbg.png') no-repeat center center;
}
image {
width: 65rpx;
height: 65rpx;
margin-bottom: 15rpx;
}
.nav-title {
font-weight: 600;
font-size: 22rpx;
}
}
}
}
.worker-content {
padding: 0.1rpx;
width: 420rpx;
background-color: #fff;
border-radius: 14rpx;
.title {
margin: 20rpx 0;
text-align: center;
font-size: 22rpx;
}
.worker-time {
transform: translateY(25rpx);
margin-left: 20rpx;
font-size: 18rpx;
}
.footer-but {
display: flex;
justify-content: space-around;
padding: 0 30rpx;
margin: 40rpx 0;
margin-top: 65rpx;
view {
flex: 0 0 35%;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
letter-spacing: 2rpx;
height: 55rpx;
background-color: rgba($color: #35d757, $alpha: 0.6);
border-radius: 14rpx;
}
.confirm {
background-color: #35d757;
}
}
}
.but-content {
display: flex;
justify-content: space-between;
width: 100%;
padding: 0 30rpx;
box-sizing: border-box;
view {
flex: 1;
}
}
.switch-model {
padding: 0.1rpx 20rpx;
padding-bottom: 30rpx;
width: 470rpx;
min-height: 300rpx;
border-radius: 14rpx;
background-color: #fff;
.title {
margin: 30rpx 0;
text-align: center;
font-weight: 600;
font-size: 18rpx;
}
.sub-title {
font-size: 18px;
font-weight: 600;
.model-tag {
float: right;
background-color: #27dc70;
color: #fff;
padding: 5rpx 10rpx;
border-radius: 5rpx;
font-size: 14rpx;
}
}
.tips {
color: #595959;
font-size: 15rpx;
margin: 20rpx 0;
line-height: 2;
}
.pay-model {
display: flex;
justify-content: center;
align-items: center;
margin: 0 auto;
height: 60rpx;
border: 1rpx solid #1ab345;
border-radius: 5rpx;
background-color: rgba(241, 255, 245, 0.3);
color: #1ab245;
font-size: 18rpx;
letter-spacing: 2rpx;
image {
margin-right: 8rpx;
width: 20rpx;
height: 20rpx;
}
}
.hover-model {
background-color: #1ab345;
color: #fff;
}
}</style>

View File

@@ -0,0 +1,151 @@
<!--
环境变量切换组件
@author terrfly
@site https://www.jeequan.com
@date 2022/04/12 10:14
-->
<template>
<view>
<!-- 当包含环境变量 && 不是生产环境时 -->
<view
class="login-test"
v-if="
vdata.currentEnvEnum &&
vdata.currentEnvEnum != appConfig.ENV_ENUM.PRODUCTION
"
><text>{{ vdata.currentEnvEnum }}</text></view
>
<!-- 切换环境提示 -->
<uni-popup ref="uniPopupRef" :mask-click="false" :open="true">
<view class="uni-popup-dialog">
<image
@tap="uniClose"
class="uni-dialog-close"
src="/static/indexImg/del.svg"
mode="scaleToFill"
/>
<view class="uni-dialog-button-box">
<view
class="uni-dialog-button"
style="border-bottom: 2rpx solid #e1e1e1"
@click="changeEnvFunc(appConfig.ENV_ENUM.DEVELOPMENT)"
><text>开发环境</text></view
>
<view
class="uni-dialog-button"
style="border-bottom: 2rpx solid #e1e1e1"
@click="changeEnvFunc(appConfig.ENV_ENUM.TEST)"
><text>测试环境</text></view
>
<view
class="uni-dialog-button"
style="border-bottom: 2rpx solid #e1e1e1"
@click="changeEnvFunc(appConfig.ENV_ENUM.DEMO)"
><text>演示环境</text></view
>
<view
class="uni-dialog-button"
@click="changeEnvFunc(appConfig.ENV_ENUM.PRODUCTION)"
><text>生产环境</text></view
>
</view>
</view>
</uni-popup>
</view>
</template>
<script setup>
import { reactive, ref, onMounted } from 'vue'
import appConfig from '@/config/appConfig.js'
import envConfig from '@/env/config.js'
import storageManage from '@/commons/utils/storageManage.js'
const uniPopupRef = ref()
// emit
const emit = defineEmits(['change'])
const vdata = reactive({
currentEnvEnum: '', // 当前环境变量
count: 0, // 当前点击次数
})
onMounted(() => {
vdata.currentEnvEnum = storageManage.env()
})
// 父组件的点击事件
function tapFunc() {
vdata.count++
if (vdata.count >= 10) {
vdata.count = 0
uniPopupRef.value.open()
}
}
// 改变环境函数
function changeEnvFunc(envMode) {
vdata.currentEnvEnum = envMode //显示信息
envConfig.changeEnv(envMode) //更改请求包
storageManage.env(envMode) // 改变存储
uniPopupRef.value.close() //弹层关闭
}
// 关闭弹窗
function uniClose() {
uniPopupRef.value.close()
}
defineExpose({ tapFunc })
</script>
<style lang="scss" scoped>
.uni-popup-dialog {
position: relative;
box-sizing: border-box;
width: 500rpx;
height: 600rpx;
overflow: hidden;
border-radius: 30rpx;
background-color: #ffffff;
display: flex;
flex-direction: column;
justify-content: space-around;
.uni-dialog-close {
position: absolute;
top: 20rpx;
right: 20rpx;
width: 50rpx;
height: 50rpx;
}
.uni-dialog-button-box {
width: 100%;
box-sizing: border-box;
display: flex;
justify-content: space-around;
flex-direction: column;
text-align: center;
padding: 0 40rpx;
.uni-dialog-button {
width: 100%;
height: 150rpx;
line-height: 150rpx;
text {
font-size: 40rpx;
}
}
}
}
.login-test {
position: absolute;
bottom: 70rpx;
width: 100%;
text-align: center;
text {
color: #666f80;
}
}
</style>

View File

@@ -0,0 +1,115 @@
<template>
<view class="login-header">
<image src="/static/logo.png" mode="scaleToFill" @tap="switchEnv" />
<view class="login-title">计全收银Pro</view>
</view>
<LoginInput title="账号" place="请输入登录名/手机号" require ref="refAccount" v-model:value="vdata.username" />
<LoginInput title="密码" password place="请输入密码" require type="password" ref="refPwd" v-model:value="vdata.pwd" />
<view class="button-main">
<JButton @click="submit">登录</JButton>
</view>
<!-- #ifdef MP-ALIPAY -->
<view class="support-content">
<view class="sup-title">技术支持</view>
<view class="phone-number">{{ vdata.phone || '18611727422' }}</view>
</view>
<!-- #endif -->
<EnvChangeTips ref="refEnv" />
</template>
<script setup>
import { onMounted, reactive, ref } from 'vue'
import { $login, $userInfo, $getCompanyInfos } from '@/http/apiManager'
import EnvChangeTips from './components/EnvChangeTips.vue'
import storageManage from '@/commons/utils/storageManage.js'
const refAccount = ref(null)
const refPwd = ref(null)
const refEnv = ref(null)
const vdata = reactive({})
onMounted(() => {
// #ifdef MP-WEIXIN
wxfaceapp.checkWxFacePayOsInfo({
success(res) {
console.log('success [checkWxFacePayOsInfo]', res)
storageManage.deviceNo(res.osSerialNumber) //本地存储写入 设备号
console.log(storageManage.deviceNo())
},
fail(err) {
console.log('fail [checkWxFacePayOsInfo]', err)
},
})
// #endif
// #ifdef MP-ALIPAY
my.ix.getSysProp({
key: 'ro.serialno',
success: (r) => {
console.log('r', r)
storageManage.deviceNo(r.value) //本地存储写入 设备号
},
})
// #endif
$getCompanyInfos().then(({ bizData }) => {
const { siteInfo } = bizData
vdata.phone = siteInfo.companyTel
})
})
const submit = () => {
console.log('submit')
if (refAccount.value.check() && refPwd.value.check()) {
$login(vdata).then(({ bizData }) => {
// 保存 token
storageManage.token(bizData.iToken)
// 请求用户信息
return $userInfo().then(({ bizData }) => {
// 保存用户数据
storageManage.userInfo(bizData)
// 存储设备号
// #ifdef MP-WEIXIN
//跳转首页
uni.reLaunch({
url: '/pages/index/index',
})
// #endif
// #ifdef MP-ALIPAY
console.log('执行')
uni.reLaunch({
url: '/pages/aliIndex/index',
})
// #endif
})
})
}
}
const switchEnv = () => refEnv.value.tapFunc()
</script>
<style lang="scss" scoped>
.login-header {
display: flex;
flex-direction: column;
align-items: center;
image {
margin-top: 80rpx;
width: 260rpx;
height: 260rpx;
}
.login-title {
margin-bottom: 50rpx;
font-weight: 700;
font-size: 46rpx;
}
}
.button-main {
margin-top: 80rpx;
}
.support-content {
display: flex;
justify-content: center;
margin-top: 50rpx;
font-size: 30rpx;
font-weight: 500;
}
</style>

View File

@@ -0,0 +1,102 @@
<template>
<view class="card-wrapper" @tap="emits('click')">
<view class="img-box" :style="{ backgroundColor: payImg(wayCodeType).bgColor }">
<image :src="payImg(wayCodeType).imgUrl" mode="scaleToFill" />
</view>
<view class="card-info">
<view class="card-title">
<view class="title">收款</view>
<view class="num">+{{ (amount / 100).toFixed(2) }}</view>
</view>
<view class="order-number">
<view class="order-title">订单编号</view>
{{ payOrderId }}
</view>
<view class="card-time">
<view class="created-time">{{ createdAt }}</view>
<view class="card-state" :style="{ backgroundColor: payState(state).color }">{{ payState(state).text }}</view>
</view>
</view>
</view>
</template>
<script setup>
const emits = defineEmits(['click'])
const props = defineProps({
payOrderId: { type: String }, //订单编号
createdAt: { type: String }, //创建 时间
amount: { type: [String, Number] }, //收款金额
wayCodeType: { type: String }, // 支付方式
state: { type: [String, Number] }, // 状态
})
const payImg = uni.$J.dataMap.payImg
const payState = uni.$J.dataMap.payStateMap
</script>
<style lang="scss" scoped>
.card-wrapper {
display: flex;
margin: 30rpx;
padding: 20rpx 0 20rpx 20rpx;
background-color: #fff;
border-radius: 15rpx;
.img-box {
flex-shrink: 0;
display: flex;
justify-content: center;
align-items: center;
margin-right: 30rpx;
width: 20%;
border-radius: 14rpx;
image {
width: 80%;
height: 80%;
}
}
.card-info {
flex: 1;
.card-title {
display: flex;
justify-content: space-between;
font-size: 28rpx;
font-weight: 600;
.num {
margin-right: 20rpx;
color: rgba(45, 218, 119, 1);
}
}
.order-number {
display: flex;
margin: 20rpx 0;
font-size: 18rpx;
color: rgba(102, 102, 102, 1);
}
.card-time {
display: flex;
justify-content: space-between;
.created-time {
font-size: 18rpx;
color: rgba(179, 179, 179, 1);
}
.card-state {
padding: 8rpx 30rpx;
background-color: rgba(45, 218, 119, 1);
border-radius: 20rpx 0 0 20rpx;
font-size: 12rpx;
color: #fff;
letter-spacing: 2rpx;
}
}
}
}
</style>

View File

@@ -0,0 +1,173 @@
<template>
<uni-drawer ref="refDrawer" mode="right">
<uni-nav-bar statusBar :border="false" backgroundColor="transparent" />
<view class="title">根据时间筛选</view>
<view class="time-wrapper">
<view class="time-star" @tap="refStarTime.show" :style="{ color: vdata.starTime ? '#000' : '#999' }">{{ vdata.starTime || '开始时间' }}</view>
---
<view class="time-end" @tap="refEndTime.show" :style="{ color: vdata.endTime ? '#000' : '#999' }">{{ vdata.endTime || '结束时间' }}</view>
</view>
<view class="title">支付方式</view>
<view class="pay-model">
<block v-for="v in payModelList" :key="v.value">
<view class="model-item" :class="{ 'selected-item': vdata.payModel.includes(v.value) }" @tap="selectedItem(v.value, 'payModel')">{{ v.label }}</view>
</block>
</view>
<view class="title">订单状态</view>
<view class="state-list pay-model">
<block v-for="v in stateList" :key="v.value">
<view class="state-item model-item" :class="{ 'selected-item': vdata.payState.includes(v.value) }" @tap="selectedItem(v.value, 'payState')">{{ v.label }}</view>
</block>
</view>
<view class="footer-button">
<view @tap="reset">重置</view>
<view class="confirm" @tap="confirm">确认</view>
</view>
</uni-drawer>
<xp-picker ref="refStarTime" mode="ymdhi" v-model="vdata.starTime" @confirm="confirmStart"><view></view></xp-picker>
<xp-picker ref="refEndTime" mode="ymdhi" v-model="vdata.endTime" @confirm="confirmEnd"><view></view></xp-picker>
</template>
<script setup>
import { inject, onMounted, reactive, ref } from 'vue'
import { startAndEndTime } from '@/commons/utils/timeInspect'
import dayjs from 'dayjs'
const params = inject('params') //引入 父级注入的依赖
const emits = defineEmits(['confirm'])
const payModelList = [
{ label: '云闪付', value: 'YSFPAY' },
{ label: '支付宝', value: 'ALIPAY' },
{ label: '银联', value: 'UNIONPAY' },
{ label: '微信', value: 'WECHAT' },
{ label: '其他', value: 'OTHER' },
]
const stateList = [
{ label: '订单生成', value: '0' },
{ label: '支付中', value: '1' },
{ label: '支付成功', value: '2' },
{ label: '支付失败', value: '3' },
{ label: '已撤销', value: '4' },
{ label: '已退款', value: '5' },
{ label: '订单关闭', value: '6' },
]
const vdata = reactive({
starTime: '',
endTime: '',
payModel: [],
payState: [],
})
const refStarTime = ref(null)
const refEndTime = ref(null)
const refDrawer = ref(null)
const open = () => {
refDrawer.value.open()
}
const close = () => {
refDrawer.value.close()
}
const confirmStart = (e) => {
vdata.starTime = dayjs(e.timestamp).format('YYYY-MM-DD hh:mm')
console.log(e)
}
const confirmEnd = (e) => {
vdata.endTime = dayjs(e.timestamp).format('YYYY-MM-DD hh:mm')
}
const selectedItem = (v, key) => {
if (vdata[key].includes(v))
return vdata[key].splice(
vdata[key].findIndex((item) => item == v),
1
)
vdata[key].push(v)
}
const confirm = () => {
if (vdata.starTime || vdata.endTime) {
if (!startAndEndTime(vdata.starTime, vdata.endTime)) return
params.queryDateRange = `customDateTime_${vdata.starTime + ':00'}_${vdata.endTime + ':00'}`
}
params.unionOrderState = vdata.payState.join(',')
params.unionWayCodeType = vdata.payModel.join(',')
emits('confirm')
close()
}
const reset = () => {
vdata.starTime = ''
vdata.endTime = ''
vdata.payModel = []
vdata.payState = []
}
defineExpose({ open, close })
</script>
<style lang="scss" scoped>
.title {
margin-top: 20rpx;
margin-left: 30rpx;
font-size: 24rpx;
font-weight: 600;
letter-spacing: 2rpx;
}
.time-wrapper {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20rpx;
font-size: 16rpx;
letter-spacing: 2rpx;
.time-star,
.time-end {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
margin: 0 30rpx;
height: 50rpx;
background-color: rgb(235, 227, 227);
border-radius: 10rpx;
}
}
.pay-model {
display: flex;
flex-wrap: wrap;
padding: 10rpx;
.model-item {
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
margin: 20rpx;
height: 50rpx;
width: 24%;
font-size: 16rpx;
letter-spacing: 2rpx;
background-color: rgba($color: #000000, $alpha: 0.15);
border-radius: 10rpx;
}
}
.footer-button {
display: flex;
justify-content: space-around;
padding: 30rpx;
margin-top: 80rpx;
color: #fff;
font-size: 18rpx;
letter-spacing: 2rpx;
view {
display: flex;
align-items: center;
justify-content: center;
width: 220rpx;
height: 60rpx;
border-radius: 10rpx;
background-color: rgba($color: #666666, $alpha: 0.3);
}
.confirm {
background-color: $v-primary;
}
}
.selected-item {
background-color: $v-primary !important;
color: #fff;
}
</style>

View File

@@ -0,0 +1,138 @@
<template>
<view class="page-content">
<!-- #ifdef MP-WEIXIN -->
<uni-nav-bar statusBar :border="false" leftIcon="left" fixed title="订单列表" backgroundColor="#f5f7f5"
@clickLeft="navBack" />
<!-- #endif -->
<!--#ifdef MP-ALIPAY -->
<uni-nav-bar statusBar :border="false" title="订单列表" fixed backgroundColor="#f5f7f5" @clickLeft="navBack" />
<!-- #endif -->
<view class="order-search-content">
<view class="order-search">
<image src="/static/iconImg/icon-search.svg" mode="scaleToFill" />
<input type="text" v-model="vdata.unionOrderId" confirm-type="search" @confirm="search"
placeholder="请输入订单号查询" />
</view>
<image class="screen" src="/static/iconImg/icon-screen.svg" mode="scaleToFill" @tap="refScreen.open" />
</view>
<!-- 卡片部分 -->
<block v-for="v in vdata.orderList" :key="v.payOrderId">
<OrderCard v-bind="v" @click="toDetails(v.payOrderId)" />
</block>
<view class="list-null" v-if="!vdata.hasNext">暂无更多数据</view>
</view>
<OrderScreen ref="refScreen" @confirm="search" />
</template>
<script setup>
import { provide, reactive, ref } from 'vue'
import { onLoad, onReachBottom, onUnload } from '@dcloudio/uni-app'
import { req, API_URL_PAY_ORDER_LIST } from '@/http/apiManager.js'
import OrderScreen from './components/OrderScreen'
import OrderCard from './components/OrderCard.vue'
const refScreen = ref(null)
const vdata = reactive({
orderList: [],
unionOrderId: '',
hasNext: true,
})
const params = { pageSize: 10, pageNumber: 1, queryDateRange: '' }
provide('params', params)
const getList = () => {
if (!vdata.hasNext) return
req.list(API_URL_PAY_ORDER_LIST, params).then(({ bizData }) => {
vdata.orderList.push(...bizData.records)
vdata.hasNext = bizData.hasNext
})
}
getList()
const search = () => {
params.unionOrderId = vdata.unionOrderId
vdata.orderList = []
params.pageNumber = 1
vdata.hasNext = true
getList()
}
onReachBottom(() => {
params.pageNumber += 1
getList()
})
// 跳转详情页
const toDetails = (orderId) => uni.navigateTo({ url: '/pages/order/orderDetails?orderId=' + orderId })
uni.$on('ORDER_LIST', (data) => {
console.log('刷新列表');
vdata.orderList = []
params.pageNumber = 1
getList()
})
const navBack = () => {
uni.navigateBack()
}
onUnload(() => {
uni.$off('ORDER_LIST')
})
</script>
<style lang="scss" scoped>
.page-content {
padding: 0.1rpx;
min-height: calc(100vh - 5rpx);
background-color: #f5f7f5;
.order-search-content {
display: flex;
align-items: center;
.order-search {
flex: 1;
display: flex;
align-items: center;
margin: 30rpx;
margin-bottom: 0;
height: 80rpx;
background-color: #fff;
border-radius: 15rpx;
image {
margin-left: 20rpx;
width: 35rpx;
height: 35rpx;
}
input {
width: 100%;
height: 100%;
font-size: 22rpx;
margin-left: 20rpx;
}
}
.screen {
margin-right: 30rpx;
transform: translateY(15rpx);
width: 50rpx;
height: 50rpx;
}
}
}
.list-null {
display: flex;
justify-content: space-between;
align-items: center;
color: #666;
margin: 30rpx 0;
padding: 0 30rpx;
font-size: 24rpx;
font-weight: 600;
&::after,
&::before {
content: "";
display: block;
width: 35%;
height: 2rpx;
background-color: #ededed;
}
}
</style>

View File

@@ -0,0 +1,133 @@
<template>
<view class="details-header-card">
<view class="order-num">
<view class="img-box" :style="{ backgroundColor: payModel(vdata.wayCodeType).bgColor }">
<image :src="payModel(vdata.wayCodeType).imgUrl" mode="scaleToFill" />
</view>
<view class="payment">{{ (vdata.amount / 100).toFixed(2) }}</view>
</view>
<view class="card-text">收款金额</view>
<view class="refund" v-if="vdata.refundState != 2" @tap="toRefund">退款</view>
</view>
<view class="line" style="height: 20rpx"></view>
<view class="order-info">
<view class="title">订单金额</view>
<view class="info">{{ (vdata.amount / 100).toFixed(2) }}</view>
</view>
<view class="order-info">
<view class="title">退款金额</view>
<view class="info">{{ (vdata.refundAmount / 100).toFixed(2) }}</view>
</view>
<view class="order-info">
<view class="title">订单号</view>
<view class="info">{{ vdata.payOrderId }}</view>
</view>
<view class="order-info">
<view class="title">订单时间</view>
<view class="info">{{ vdata.createdAt }}</view>
</view>
<view class="line"></view>
<view class="order-info">
<view class="title">支付方式</view>
<view class="info">{{ payModel(vdata.wayCodeType).title }}</view>
</view>
<view class="order-info">
<view class="title">订单状态</view>
<view class="info">{{ payState(vdata.state).text }}</view>
</view>
<view class="line"></view>
<view class="order-info">
<view class="title">门店名称</view>
<view class="info">{{ vdata.storeName }}</view>
</view>
<view class="order-info">
<view class="title">操作员名称</view>
<view class="info">{{ vdata.storeUserName }}</view>
</view>
</template>
<script setup>
import { reactive, ref } from 'vue'
import { onLoad, onUnload } from '@dcloudio/uni-app'
import { req, API_URL_PAY_ORDER_LIST } from '@/http/apiManager.js'
onLoad((options) => {
getDetails(options.orderId)
})
const vdata = reactive({})
const payModel = uni.$J.dataMap.payImg
const payState = uni.$J.dataMap.payStateMap
const getDetails = (id) => {
req.getById(API_URL_PAY_ORDER_LIST, id).then(({ bizData }) => {
Object.assign(vdata, bizData)
})
}
const toRefund = (oderId) => uni.navigateTo({ url: '/pages/orderRefund/orderRefund?orderId=' + vdata.payOrderId })
uni.$on('ORDER_DETAILS', (data) => {
getDetails(vdata.payOrderId)
})
onUnload(() => {
uni.$off('ORDER_DETAILS')
})
</script>
<style lang="scss" scoped>
.details-header-card {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 280rpx;
.order-num {
display: flex;
align-items: center;
.img-box {
display: flex;
justify-content: center;
align-items: center;
margin-right: 20rpx;
width: 80rpx;
height: 80rpx;
border-radius: 14rpx;
image {
width: 80%;
height: 80%;
}
}
.payment {
display: flex;
justify-content: center;
text-align: center;
font-size: 40rpx;
font-weight: 700;
color: rgba(45, 218, 119, 1);
}
}
.card-text {
margin-top: 30rpx;
color: #666;
font-size: 24rpx;
}
}
.line {
width: 100%;
height: 2rpx;
background-color: #ededed;
}
.order-info {
display: flex;
justify-content: space-between;
margin: 30rpx 20rpx;
font-size: 22rpx;
.info {
color: #666;
}
}
.refund {
padding: 15rpx 30rpx;
background-color: tomato;
margin-top: 30rpx;
border-radius: 14rpx;
color: rgba($color: #fff, $alpha: 0.7);
font-size: 20rpx;
}
</style>

View File

@@ -0,0 +1,218 @@
<template>
<view class="refund-amount">
<view class="amount">{{ (vdata.amount / 100).toFixed(2) }}</view>
<view class="title">收款金额</view>
</view>
<view class="refund">
<view>已退金额</view>
<view>{{ (vdata.refundAmount / 100).toFixed(2) }}</view>
</view>
<view class="refund">
<view>可退金额</view>
<view>{{ ((vdata.amount - vdata.refundAmount) / 100).toFixed(2) }}</view>
</view>
<view class="line"></view>
<view class="input-title">输入退款金额</view>
<view class="input-refund">
<input type="digit" placeholder="请输入退款金额" v-model="vdata.refundAmountNum" />
<view class="input-but" @tap="sumOrReset">
{{ vdata.refundAmountNum ? '取消' : '全额' }}
</view>
</view>
<view class="remarks-input">
<view class="remarks">退款原因:</view>
<input type="text" placeholder="请输入退款原因" maxlength="50" v-model="vdata.refundReason" />
</view>
<view class="refund-button" @tap="open">退款</view>
<uni-popup ref="refPopup" type="center">
<view class="refund-pwd">
<view class="title">退款密码</view>
<view class="input-box">
<input type="number" maxlength="6" password v-model="vdata.refundPassword" focus
style="flex-grow: 1; width: 100%" />
</view>
<view class="button-box">
<view @tap="close">取消</view>
<view class="confirm" @tap="confirmRefund">确认</view>
</view>
</view>
</uni-popup>
</template>
<script setup>
import { reactive, ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { req, API_URL_PAY_ORDER_LIST, $payOrderRefund } from '@/http/apiManager.js'
onLoad((options) => {
getDetails(options.orderId)
})
const vdata = reactive({})
const refPopup = ref(null)
const getDetails = (id) => {
req.getById(API_URL_PAY_ORDER_LIST, id).then(({ bizData }) => {
Object.assign(vdata, bizData)
})
}
const sumOrReset = () => {
return vdata.refundAmountNum ? (vdata.refundAmountNum = '') : (vdata.refundAmountNum = ((vdata.amount - vdata.refundAmount) / 100).toFixed(2))
}
const open = () => {
if (!vdata.refundReason) return errText('请输入退款原因')
refPopup.value.open()
}
const close = () => refPopup.value.close()
const confirmRefund = () => {
if (!vdata.refundPassword) return errText('请输入密码')
uni.showLoading({
title: '请稍等',
mask: true,
})
$payOrderRefund(vdata)
.then((res) => {
uni.showLoading()
uni.$emit('ORDER_DETAILS')
uni.$emit('ORDER_LIST')
uni.$J.showToast('退款成功').then((res) => {
close()
uni.navigateBack()
})
})
.catch((err) => {
uni.hideLoading()
})
}
const errText = (title) => uni.showToast({ title, icon: 'none' })
</script>
<style lang="scss" scoped>
.refund-amount {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.amount {
margin-top: 30rpx;
font-size: 40rpx;
font-weight: 600;
color: rgba(45, 218, 119, 1);
}
.title {
margin-top: 30rpx;
font-size: 18rpx;
}
}
.refund {
display: flex;
justify-content: space-between;
padding: 30rpx;
font-size: 24rpx;
}
.line {
width: 100%;
height: 10rpx;
background-color: #ededed;
}
.input-title {
margin: 30rpx 0;
text-align: center;
}
.input-refund {
display: flex;
align-items: center;
background-color: #ededed;
padding: 10rpx 30rpx;
input {
flex: 1;
text-align: center;
}
.input-but {
color: $v-primary;
}
}
.remarks-input {
display: flex;
margin: 20rpx 0;
padding: 10rpx 30rpx;
height: 160rpx;
background-color: #ededed;
/* #ifdef MP-ALIPAY */
input {
transform: translateY(-7rpx);
}
/* #endif */
}
.refund-button {
display: flex;
justify-content: center;
align-items: center;
margin: 0 auto;
width: 260rpx;
height: 60rpx;
background-color: rgba(242, 77, 77, 1);
color: #fff;
font-size: 22rpx;
letter-spacing: 2rpx;
border-radius: 14rpx;
}
.refund-pwd {
padding: 15rpx;
width: 420rpx;
height: 260rpx;
border-radius: 14rpx;
background-color: #fff;
.title {
margin-bottom: 50rpx;
font-size: 20rpx;
text-align: center;
}
.input-box {
margin: 0 auto;
width: 90%;
border-bottom: 1rpx solid #000;
input {
padding: 10rpx 0;
font-size: 24rpx;
}
}
.button-box {
display: flex;
justify-content: space-around;
margin-top: 60rpx;
view {
flex: 0 0 38%;
height: 55rpx;
display: flex;
justify-content: center;
align-items: center;
font-size: 24rpx;
color: $v-primary;
border-radius: 14rpx;
}
.confirm {
background-color: $v-primary;
color: #fff;
}
}
}
</style>

View File

@@ -0,0 +1,249 @@
<template>
<view class="model-wrapper">
<view class="model-content">
<view class="title">您已切换至POS模式 </view>
<view class="sub-text">请在收银设备上输入收款金额</view>
<view class="sub-title">独立收银模式
</view>
<view class="tips">接入电源后即可使用后屏输入收款金额前屏支持刷脸支付和扫码支付</view>
<view class="sub-title">POS模式<view class="model-tag">当前正在使用</view>
</view>
<view class="tips">需要连接收银机或PC使用即插即用收款将会进入您的现有收银软件账户</view>
<view class="pay-model" hover-class="hover-model" hover-stay-time="50" @tap="switchCashier">
<image src="/static/iconImg/switch-model.svg" mode="scaleToFill" />
切换至独立收银模式
</view>
</view>
<view class="selected-cas-model">
<view class="cas-title">设置收银机刷脸兼容模式</view>
<view class="cas-sub-tips">请注意此设置可能会影响收银机刷脸收款请在专业人员指导下设置</view>
<view class="cas-sub-tips">如需设置收银机扫码兼容模式 请在系统设置中设置</view>
<radio-group @change="radioChange">
<view class="radio-wrapper">
<label class="radio">
<radio value="n" checked="true" />code+n
</label>
<label class="radio">
<radio value="r" />code+r
</label>
<label class="radio">
<radio value="rn" />code+rn
</label>
<label class="radio">
<radio value="" />code
</label>
</view>
</radio-group>
</view>
</view>
</template>
<script setup>
import { onLoad, onReady } from '@dcloudio/uni-app'
import storageManage from '@/commons/utils/storageManage.js'
/***
*前后屏 通信 通知前屏 跳转到待支付页面
* */
onLoad(() => {
wxfaceapp.postMsg({
targetAppid: 'wx4710a1619fbb3714',
content: JSON.stringify({ type: 'toPay' }),
success(res) {
console.log('通信成功', res)
},
fail(res) {
console.log('通信失败 ', res)
},
})
})
let code = '\n'
/**
* 页面初始化完成 监听 前屏 向后屏通信 将支付码 写入数据串口
* */
onReady(() => {
wxfaceapp.onRemoteMessage(function (res) {
const data = JSON.parse(res.content)
if (data.faceCode) {
wxfaceapp.writeToSerialPort({
msgToFlush: data.faceCode + code,
success(res) {
console.log('success [writeToSerialPort]', res)
},
fail(res) {
console.log('fail [writeToSerialPort]', res)
},
})
}
})
postFrontMsg({ type: 'hideAmount' })
})
const switchCashier = () => {
uni.showModal({
title: '提示',
content: '是否切换为 独立收银模式?',
showCancel: true,
success: ({ confirm, cancel }) => {
if (confirm) {
storageManage.faceModel('cashier')
postFrontMsg({ type: 'toBanner' })
uni.reLaunch({ url: '/pages/index/index' })
}
},
})
}
function postFrontMsg(content) {
wxfaceapp.postMsg({
targetAppid: 'wx4710a1619fbb3714',
content: JSON.stringify(content),
success(res) {
console.log('通信成功', res)
},
fail(res) {
console.log('通信失败 ', res)
},
})
}
const radioChange = (e) => {
const v = e.detail.value
switch (v) {
case 'r':
code = '\r'
break
case 'n':
code = '\n'
break
case 'rn':
code = '\r\n'
break
default:
code = ''
}
}
</script>
<style lang="scss" scoped>
.model-wrapper {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 15vh;
min-height: 100vh;
.model-content {
width: 70%;
.title {
text-align: center;
font-weight: 600;
font-size: 29rpx;
}
.sub-text {
line-height: 3;
font-weight: 600;
font-size: 20rpx;
text-align: center;
}
.switch-but {
display: flex;
justify-content: center;
align-items: center;
margin: 0 auto;
margin-top: 60rpx;
width: 60%;
height: 50rpx;
border: 1rpx solid rgba($color: #000000, $alpha: 0.1);
border-radius: 5rpx;
background-color: rgba($color: #409eff, $alpha: 0.175);
color: #409eff;
font-size: 18rpx;
font-weight: 600;
letter-spacing: 2rpx;
}
}
}
.sub-title {
font-size: 18px;
font-weight: 600;
.model-tag {
float: right;
background-color: #27DC70;
color: #fff;
padding: 5rpx 10rpx;
border-radius: 5rpx;
font-size: 14rpx;
}
}
.tips {
color: #595959;
font-size: 15rpx;
margin: 20rpx 0;
line-height: 2;
}
.pay-model {
display: flex;
justify-content: center;
align-items: center;
margin: 0 auto;
margin-top: 60rpx;
height: 60rpx;
border: 1rpx solid #1AB345;
border-radius: 5rpx;
background-color: rgba(241, 255, 245, .3);
;
color: #1AB245;
font-size: 18rpx;
letter-spacing: 2rpx;
image {
margin-right: 8rpx;
width: 20rpx;
height: 20rpx;
}
}
.hover-model {
background-color: #1AB345;
color: #fff;
}
.selected-cas-model {
margin-top: 5vh;
.cas-title {
width: 100vw;
padding-top: 30rpx;
text-align: center;
font-size: 28rpx;
font-weight: 600;
border-top: 2rpx solid #ededed;
}
.cas-sub-tips {
margin-top: 20rpx;
color: #666;
font-size: 24rpx;
text-align: center;
}
.radio-wrapper {
display: flex;
justify-content: space-around;
margin-top: 30rpx;
}
}
</style>

View File

@@ -0,0 +1,70 @@
<template>
<view class="page-wrapper">
<view class="pay-main">
<view class="pay-title">支付成功</view>
<view class="pay-amount">支付金额{{ vdata.amount }}</view>
</view>
<view class="but-box">
<JButton @tap="toIndexPage(true)">返回首页{{ vdata.num }}</JButton>
</view>
</view>
</template>
<script setup>
import { reactive, ref } from 'vue'
import { onLoad, onUnload } from '@dcloudio/uni-app'
onLoad((options) => {
console.log('支付成功页', options)
vdata.amount = options.amount
vdata.num = 10
toIndexPage()
})
const vdata = reactive({
num: 10,
})
let timeOut = undefined
function toIndexPage(flag) {
if (flag || vdata.num <= 0) {
clearTimeout(timeOut)
return uni.redirectTo({
url: '/pages/index/index',
})
}
timeOut = setTimeout(() => {
vdata.num -= 1
toIndexPage()
}, 1000)
}
</script>
<style lang="scss" scoped>
.page-wrapper {
padding: 0.1rpx;
min-height: calc(100vh - 2rpx);
}
.pay-main {
padding: 0.1rpx;
margin: 180rpx auto;
width: 80%;
background: linear-gradient(135deg, rgba(86, 222, 114, 1) 0%, rgba(58, 233, 174, 1) 100%);
color: #fff;
border-radius: 14rpx;
.pay-title {
margin: 30rpx 0;
text-align: center;
font-size: 42rpx;
font-weight: 600;
letter-spacing: 3rpx;
}
.pay-amount {
text-align: center;
font-size: 28rpx;
font-weight: 600;
margin-bottom: 30rpx;
}
}
.but-box {
transform: translateY(200rpx);
}
</style>

View File

@@ -0,0 +1,143 @@
<template>
<view class="page-wrapper">
<view class="pay-wait">
<view class="pay-number">
<text class="icon"></text>
{{ vdata.payment }}
</view>
等待用户付款
</view>
<view class="but-content">
<JButton @tap="cancel">取消付款</JButton>
</view>
</view>
</template>
<script setup>
import { reactive, ref } from 'vue'
import { req, $appPay, API_URL_PAY_ORDER_LIST } from '@/http/apiManager'
import wxTextToSpeach from '@/commons/utils/wxTextToSpeach'
import { onLoad, onReady } from '@dcloudio/uni-app'
onLoad((options) => {
vdata.payment = options.payment
})
onReady(() => {
wxfaceapp.onRemoteMessage(function (res) {
console.log('刷脸结果:' + res.content)
const data = JSON.parse(res.content)
$appPay(vdata.payment, data.faceCode || data.code).then((r) => {
console.log('支付后结果', r)
findOrderState(r.bizData)
})
})
postFront({ type: 'amount', amount: vdata.payment }) // 通知 支付页面 支付金额
})
const vdata = reactive({
payment: '0.00',
})
const cancel = () => {
postFront({ type: 'toBanner' })
uni.navigateBack()
}
const postFront = (content) => {
wxfaceapp.postMsg({
targetAppid: 'wx4710a1619fbb3714',
content: JSON.stringify(content),
success(res) {
console.log('通信成功', res)
},
fail(res) {
console.log('通信失败 ', res)
},
})
}
function findOrderState(val) {
switch (val.orderState) {
case 2:
if (val.payDataType == 'aliapp' || val.wayCode == 'ALIPAY') {
wxTextToSpeach(`支付宝支付成功金额${vdata.payment}`)
}
if (val.payDataType == 'ysfapp' || val.wayCode == 'YSFPAY') {
wxTextToSpeach(`云闪付支付成功金额${vdata.payment}`)
}
uni.$J.showToast('支付成功').then((res) => {
uni.redirectTo({
url: '/pages/paySuc/paySuc?amount=' + vdata.payment,
})
postFront({ type: 'toBanner' }) //支付成功后 返回支付页面
})
break
case 3:
uni.$J.showToast('支付失败' + val.errMsg)
break
case 4:
uni.$J.showToast('订单撤销')
break
case 1:
// 支付中 进行查单操作
console.log('订单状态1进行查单 操作 ')
findOrder(val.payOrderId)
break
}
}
let num = 1
function findOrder(payOrderId) {
if (num > 15)
return uni.showModal({
title: '确认订单状态',
content: '订单状态查询失败 请与客户确认订单状态 点击确认跳转订单列表页面',
showCancel: true,
success: ({ confirm, cancel }) => {
if (confirm) {
uni.navigateTo({
url: '/pages/order/order',
})
}
},
})
uni.$J.showToast(`支付中正在进行第${num}次订单查询`).then((res) => {
req.getById(API_URL_PAY_ORDER_LIST, payOrderId).then(({ bizData }) => {
num += 1
console.log('查单结果', bizData)
bizData.orderState = bizData.state
findOrderState(bizData)
})
})
}
</script>
<style lang="scss" scoped>
.page-wrapper {
padding: 0.1rpx 30rpx;
.pay-wait {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-top: 140rpx;
height: 220rpx;
background: linear-gradient(135deg, rgba(86, 222, 114, 1) 0%, rgba(58, 233, 174, 1) 100%);
border-radius: 15rpx;
color: #fff;
.pay-number {
display: flex;
align-items: flex-end;
margin-bottom: 15rpx;
font-size: 60rpx;
font-weight: 700;
.icon {
transform: translateY(-7rpx);
font-size: 28rpx;
}
}
}
.but-content {
transform: translateY(400rpx);
}
}
</style>

View File

@@ -0,0 +1,138 @@
<template>
<view class="page-wrapper">
<view class="pay-number">
<view class="pay-icon"></view>
{{ vdata.payment }}
</view>
<view class="keyboard-list">
<block v-for="v in keyboardList" :key="v.value">
<view class="keyboard-item" hover-class="hover-button" hover-stay-time="50" @tap="changeKey(v.value)">
<image v-if="v.value == 'del'" :src="v.key" mode="scaleToFill" />
<text v-else>{{ v.key }}</text>
</view>
</block>
</view>
<view class="pay-submit" hover-class="hover-submit" hover-stay-time="50" @tap="jumpPage">
<image src="/static/indexImg/pay.png" mode="scaleToFill" />
普通收款
</view>
</view>
</template>
<script setup>
import { reactive, ref } from 'vue'
const keyboardList = [
{ key: '1', value: '1' },
{ key: '2', value: '2' },
{ key: '3', value: '3' },
{ key: '4', value: '4' },
{ key: '5', value: '5' },
{ key: '6', value: '6' },
{ key: '7', value: '7' },
{ key: '8', value: '8' },
{ key: '9', value: '9' },
{ key: '.', value: '.' },
{ key: '0', value: '0' },
{ key: '/static/iconImg/escB.png', value: 'del' },
]
const vdata = reactive({
payment: '0.00',
})
const changeKey = (v) => {
if (v == 'del') {
vdata.payment = vdata.payment.slice(0, vdata.payment.length - 1)
if (vdata.payment == '') vdata.payment = '0.00'
return
}
if (vdata.payment == '0.00' && (v == '.' || v == '0')) return (vdata.payment = '0.')
if (vdata.payment == '0.00') return (vdata.payment = v)
if (vdata.payment.includes('.') && v == '.') return uni.$J.showToast('只能包含一位小数点')
if (vdata.payment.includes('.') && vdata.payment.split('.')[1].length == 2) return uni.$J.showToast('只能包含小数点后两位')
return (vdata.payment += v)
}
const jumpPage = () => {
wxfaceapp.postMsg({
targetAppid: 'wx4710a1619fbb3714',
content: JSON.stringify({ type: 'toPay' }),
success(res) {
console.log('通信成功', res)
},
fail(res) {
console.log('通信失败 ', res)
},
})
uni.navigateTo({ url: '/pages/payWait/payWait?payment=' + vdata.payment })
}
</script>
<style lang="scss" scoped>
.page-wrapper {
padding: 0.1rpx 30rpx;
min-height: calc(100vh - 5rpx);
background: url('/static/indexImg/index-bg.png') no-repeat center center;
background-size: 100% 100%;
.pay-number {
margin-top: 60rpx;
display: flex;
justify-content: center;
align-items: center;
height: 180rpx;
background-color: #35d757;
border-radius: 22rpx;
font-size: 60rpx;
color: #fff;
font-weight: 600;
.pay-icon {
font-size: 28rpx;
transform: translateY(30%);
}
}
}
.keyboard-list {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
margin-top: 60rpx;
.keyboard-item {
flex: 0 0 31.5%;
display: flex;
justify-content: center;
align-items: center;
margin-top: 15rpx;
height: 110rpx;
font-weight: 700;
font-size: 36rpx;
border-radius: 22rpx;
background-color: #fff;
image {
width: 40rpx;
height: 30rpx;
}
}
}
.pay-submit {
display: flex;
justify-content: center;
align-items: center;
margin-top: 70rpx;
background-color: #35d757;
border-radius: 22rpx;
height: 120rpx;
color: #fff;
font-weight: 700;
image {
margin-right: 10rpx;
width: 35rpx;
height: 35rpx;
transform: translateY(5rpx);
}
}
.hover-button {
background-color: rgba($color: #ccc, $alpha: 0.3) !important;
}
.hover-submit {
opacity: 0.5;
}
</style>

View File

@@ -0,0 +1,131 @@
<template>
<view class="type-card" :style="{ backgroundColor: rgba }">
<view class="type-header" :style="{ backgroundColor: bgColor }" @tap="emits('upOrDown')">
<view> {{ typeName }} </view>
<view class="type-num">{{ (allAmount / 100).toFixed(2) }} /{{ allCount }}
<image src="/static/iconImg/down.svg" style="transition: 0.3s linear" :class="{ 'img-up': !isShow }"
mode="scaleToFill" />
</view>
</view>
<view class="type-main" :style="{ maxHeight: isShow ? '40vh' : '0' }">
<view class="type-item">
<view class="type-num">
<view> {{ (allAmount / 100).toFixed(2) }}</view>
<view class="title"> 成交金额 </view>
</view>
</view>
<view class="type-item">
<view class="type-num">
<view> {{ ((payAmount - refundAmount) / 100).toFixed(2) }}</view>
<view class="title"> 实收金额</view>
</view>
</view>
<view class="type-item">
<view class="type-num">
<view> {{ payCount }}/{{ allCount }}</view>
<view class="title"> 成交笔数/总笔数 </view>
</view>
</view>
<view class="type-item">
<view class="type-num">
<view> {{ (refundAmount / 100).toFixed(2) }}</view>
<view class="title"> 退款金额</view>
</view>
</view>
<view class="type-item">
<view class="type-num">
<view> {{ refundCount }}</view>
<view class="title"> 退款笔数 </view>
</view>
</view>
<view class="type-item">
<view class="type-num">
<view> {{ round }}%</view>
<view class="title"> 成功率</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { reactive, ref } from 'vue'
const emits = defineEmits(['upOrDown'])
const props = defineProps({
typeName: { type: String },
allCount: { type: [String, Number] },
allAmount: { type: [String, Number] },
bgColor: { type: String },
rgba: { type: String },
isShow: { type: Boolean },
refundAmount: { type: [String, Number] },
round: { type: [String, Number] },
payCount: { type: [String, Number] },
payAmount: { type: [String, Number] },
refundCount: { type: [String, Number] },
})
</script>
<style lang="scss" scoped>
.type-card {
position: relative;
z-index: 10;
margin: 0 auto;
box-sizing: border-box;
width: 95%;
border-radius: 14rpx;
overflow: hidden;
.type-header {
padding: 25rpx 20rpx;
display: flex;
justify-content: space-between;
align-items: center;
color: #fff;
font-size: 24rpx;
font-weight: 600;
.type-num {
display: flex;
align-items: center;
}
image {
margin-left: 10rpx;
width: 30rpx;
height: 30rpx;
}
}
.type-main {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
padding: 0 20rpx;
overflow: hidden;
// max-height: 0;
transition: 0.3s linear;
.type-item {
flex: 0 0 30%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 20rpx 0;
text-align: center;
color: #fff;
.title {
margin-top: 10rpx;
color: rgba($color: #fff, $alpha: 0.6);
}
}
}
}
.img-up {
transform: rotate(-180deg);
}</style>

View File

@@ -0,0 +1,230 @@
<template>
<view class="stat-wrapper">
<view class="time-header">
<block v-for="(v, i) in timeList" :key="i">
<view class="time-item" :class="{ 'selected-time': v.value == vdata.selectedTime }" @tap="switchTime(v.value)">{{ v.label }}</view>
</block>
</view>
<view class="custom-content" :class="{ 'selected-custom': vdata.selectedTime == 'custom' }">
<view class="start-time" :style="{ color: vdata.startTime ? '#000' : '#666' }" @tap="refStartTime.show">{{ vdata.startTime || '请选择开始时间' }}</view>
<view class="endTime-time" :style="{ color: vdata.endTime ? '#000' : '#666' }" @tap="refEndTime.show">{{ vdata.endTime || '请选择结束时间' }}</view>
</view>
<view class="amount-list">
<view class="amount-item">
<view class="amount-num">{{ (vdata.payStat.allAmount / 100).toFixed(2) }}</view>
成交金额
</view>
<view class="amount-item">
<view class="amount-num">{{ (vdata.payStat.payAmount / 100).toFixed(2) }}</view>
实收金额
</view>
<view class="amount-item">
<view class="amount-num">{{ vdata.payStat.payCount }} /{{ vdata.payStat.allCount }} </view>
成交笔数/总笔数
</view>
<view class="amount-item">
<view class="amount-num">{{ (vdata.payStat.refundAmount / 100).toFixed(2) }}</view>
退款金额
</view>
<view class="amount-item">
<view class="amount-num">{{ vdata.payStat.refundCount }}</view>
退款笔数
</view>
<view class="amount-item">
<view class="amount-num">{{ vdata.payStat.round }} %</view>
成功率
</view>
</view>
<view class="pay-title"> 支付方式 </view>
<block v-for="(v, i) in vdata.payList" :key="v.wayType">
<PayTypeCard v-bind="v" @upOrDown="upOrDown(v)" />
</block>
<view style="height: 60rpx"></view>
</view>
<xp-picker mode="ymdhi" ref="refStartTime" @confirm="timeConfirm($event, 'startTime')">
<view></view>
</xp-picker>
<xp-picker mode="ymdhi" ref="refEndTime" @confirm="timeConfirm($event, 'endTime')">
<view></view>
</xp-picker>
</template>
<script setup>
import { reactive, ref } from 'vue'
import { $payTypeStat, $payTypeStatAll } from '@/http/apiManager'
import PayTypeCard from './components/PayTypeCard'
import dayjs from 'dayjs'
const timeList = [
{ label: '昨天', value: 'yesterday' },
{ label: '今天', value: 'today' },
{ label: '近7天', value: 'near2now_7' },
{ label: '近30天', value: 'near2yesterday_30' },
{ label: '自定义', value: 'custom' },
]
const vdata = reactive({
selectedTime: 'today',
payList: [],
payStat: {},
})
const refStartTime = ref(null)
const refEndTime = ref(null)
const params = {
method: 'wayCodeType',
queryDateRange: 'today',
}
const getPayType = () => {
$payTypeStat(params).then(({ bizData }) => {
bizData.records.forEach((v, i) => {
v.bgColor = uni.$J.dataMap.payImg(v.wayType).bgColor
v.rgba = uni.$J.dataMap.payImg(v.wayType).rgba
v.typeName = uni.$J.dataMap.payImg(v.wayType).title
if (i == 0) return (v.isShow = true)
v.isShow = false
})
vdata.payList = bizData.records
})
}
getPayType()
const getStatAll = () => {
$payTypeStatAll(params).then(({ bizData }) => {
vdata.payStat = bizData
})
}
getStatAll()
/****
* 切换 卡片收起 展开状态
* @param {v} Object 点击的卡片全部数据
* */
const upOrDown = (v) => {
v.isShow = true
vdata.payList.forEach((ite) => {
if (ite.wayType != v.wayType) {
ite.isShow = false
}
})
}
/***
* 切换时间选择器
* @param {val} STring 时间选择的 value 值
* val = custom 需要展示自定义 时间选择框
* */
const switchTime = (val) => {
vdata.selectedTime = val
if (val == 'custom') return
params.queryDateRange = val
getStatAll()
getPayType()
}
/**
* @param {e} Object 组件原生 回调 时间戳 日期
* @param {key} String vdata 对象的 key 值 赋值使用
* */
const timeConfirm = (e, key) => {
vdata[key] = dayjs(e.timestamp).format('YYYY-MM-DD hh:mm')
if (key == 'endTime' || (vdata.endTime != undefined && dayjs(vdata.startTime).isAfter(vdata.endTime))) {
params.queryDateRange = `customDateTime_${vdata.startTime + ':00'}_${vdata.endTime + ':00'}`
getStatAll()
getPayType()
}
}
</script>
<style lang="scss" scoped>
.stat-wrapper {
min-height: 100vh;
background-color: #ebf2ed;
.time-header {
display: flex;
justify-content: space-between;
padding: 20rpx;
view {
flex: 0 0 18%;
display: flex;
justify-content: center;
align-items: center;
height: 45rpx;
border-radius: 14rpx;
background-color: #d9dfda;
font-size: 18rpx;
color: #666;
}
.selected-time {
background-color: $v-primary;
color: #fff;
}
}
}
.title {
font-size: 18rpx;
color: rgba($color: #fff, $alpha: 0.6);
}
.stat-num {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #fff;
margin: 0 auto;
margin-top: 35rpx;
width: 65%;
height: 120rpx;
border-radius: 22rpx 22rpx 0 0;
background-color: $v-primary;
.num {
font-size: 35rpx;
font-weight: 600;
}
}
.amount-list {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
align-items: center;
margin: 0 auto;
margin-top: 30rpx;
padding: 15rpx 0;
width: 92%;
// height: 110rpx;
background-color: $v-primary;
border-radius: 14rpx;
.amount-item {
flex: 0 0 33%;
margin: 15rpx 0;
text-align: center;
white-space: nowrap;
color: rgba($color: #fff, $alpha: 0.6);
font-size: 20rpx;
.amount-num {
margin-bottom: 15rpx;
color: #fff !important;
}
}
}
.pay-title {
margin-top: 35rpx;
margin-bottom: 15rpx;
margin-left: 30rpx;
font-size: 22rpx;
font-weight: 600;
}
.custom-content {
display: flex;
justify-content: space-around;
overflow: hidden;
margin-top: 30rpx;
margin-bottom: 60rpx;
max-height: 0;
transition: 0.3s linear;
view {
flex: 0 0 30%;
padding: 10rpx 0;
background-color: #ded7d7;
text-align: center;
border-radius: 10rpx;
font-size: 16rpx;
}
}
.selected-custom {
max-height: 20vh;
}
</style>

View File

@@ -0,0 +1,10 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.33301 28.3333V36.6667H11.6663" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M28.333 36.6667H36.6663V28.3333" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M28.333 3.33333H36.6663V11.6667" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11.6663 3.33333H3.33301V11.6667" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.333 28.3333C13.333 28.3333 15.833 30.8333 19.9997 30.8333C24.1663 30.8333 26.6663 28.3333 26.6663 28.3333" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M19.9997 11.6667V19.1667C19.9997 20.8333 18.333 22.5 16.6663 22.5H15.833" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M28.333 11.6667V13.3333" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11.667 11.6667V13.3333" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,16 @@
<svg width="800" height="779" viewBox="0 0 800 779" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_235_336)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M800 -195H0V518.989C-101.363 546.561 -164 584.552 -164 626.5C-164 710.723 88.5114 779 400 779C711.489 779 964 710.723 964 626.5C964 584.552 901.363 546.561 800 518.989V-195Z" fill="url(#paint0_linear_235_336)"/>
<rect x="81.6445" y="-521.865" width="713.01" height="713.01" rx="110" transform="rotate(30 81.6445 -521.865)" fill="#75EC81" fill-opacity="0.5"/>
<circle cx="582" cy="251" r="435" fill="#75EC81" fill-opacity="0.2"/>
</g>
<defs>
<linearGradient id="paint0_linear_235_336" x1="14.5" y1="481" x2="796" y2="347.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#6AE576"/>
<stop offset="1" stop-color="#5DC972"/>
</linearGradient>
<clipPath id="clip0_235_336">
<rect width="800" height="779" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 930 B

View File

@@ -0,0 +1,4 @@
<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="13" cy="13" r="12" stroke="#263E2A" stroke-width="2"/>
<path d="M8 11L13 17L18 11" stroke="#263E2A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 281 B

View File

@@ -0,0 +1,9 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.3333 5H6.66667C5.74619 5 5 5.74619 5 6.66667V13.3333" stroke="#60D073" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.3333 35H6.66667C5.74619 35 5 34.2538 5 33.3333V26.6667" stroke="#60D073" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M26.667 35H33.3337C34.2542 35 35.0003 34.2538 35.0003 33.3333V26.6667" stroke="#60D073" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M26.667 5H33.3337C34.2542 5 35.0003 5.74619 35.0003 6.66667V13.3333" stroke="#60D073" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M20 13.3333V26.6667" stroke="#60D073" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M26.667 13.3333V26.6667" stroke="#60D073" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.333 13.3333V26.6667" stroke="#60D073" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,3 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M37 20C37 29.3889 29.3888 37 20 37C10.6112 37 3 29.3889 3 20C3 10.6111 10.6112 3 20 3C29.3888 3 37 10.6111 37 20ZM40 20C40 31.0457 31.0457 40 20 40C8.95435 40 0 31.0457 0 20C0 8.95435 8.95435 0 20 0C31.0457 0 40 8.95435 40 20ZM30.0381 16.459C30.6541 17.071 30.6541 18.0632 30.0381 18.6753L21.1337 27.5225L21.1154 27.541C20.4994 28.1531 19.5006 28.1531 18.8846 27.541L9.96204 18.6755C9.34595 18.0637 9.34595 17.0713 9.96204 16.4592C10.578 15.8472 11.5767 15.8472 12.1926 16.4592L19.9999 24.2163L27.8074 16.459C28.4233 15.8469 29.422 15.8469 30.0381 16.459Z" fill="white" fill-opacity="0.8"/>
</svg>

After

Width:  |  Height:  |  Size: 743 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 667 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 26" class="design-iconfont">
<path d="M105.569,19.679a2.623,2.623,0,0,1,.591-1.654l5.915-7.263a.605.605,0,0,0,.139-.382V9.321a.617.617,0,0,0-.623-.612H94.983a.617.617,0,0,0-.623.612v1.06a.6.6,0,0,0,.139.38l5.917,7.263a2.625,2.625,0,0,1,.591,1.655v8.2a.609.609,0,0,0,.343.547l4.223,2.075V19.679ZM94.98,6.672h16.606a2.676,2.676,0,0,1,2.7,2.65v1.06a2.623,2.623,0,0,1-.591,1.654L107.784,19.3a.605.605,0,0,0-.139.382V30.836a1.828,1.828,0,0,1-.886,1.562,1.9,1.9,0,0,1-1.818.081l-4.523-2.222a2.646,2.646,0,0,1-1.492-2.37v-8.2a.605.605,0,0,0-.139-.382l-5.911-7.265a2.621,2.621,0,0,1-.591-1.655V9.322a2.676,2.676,0,0,1,2.7-2.65Z" transform="translate(-92.284 -6.671)" fill="#666f80"/>
</svg>

After

Width:  |  Height:  |  Size: 741 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 26" class="design-iconfont">
<path d="M81.569,59.244,76.042,53.73a11.238,11.238,0,1,0-1.4,1.213l5.611,5.6a.926.926,0,0,0,1.575-.648A.905.905,0,0,0,81.569,59.244ZM58.684,45.982a9.328,9.328,0,1,1,9.328,9.305A9.331,9.331,0,0,1,58.684,45.982Z" transform="translate(-56.832 -34.816)" fill="#666f80"/>
</svg>

After

Width:  |  Height:  |  Size: 361 B

View File

@@ -0,0 +1,6 @@
<svg fill="#108ee9" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 24" class="design-iconfont">
<path d="M21.5 9.5H3.5" stroke="#108ee9" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M15.5 3.5L21.5 9.5" stroke="#108ee9" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3.89941 14.5H21.8994" stroke="#108ee9" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3.89941 14.5L9.89944 20.5" stroke="#108ee9" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 569 B

View File

@@ -0,0 +1,6 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 24" class="design-iconfont">
<path d="M21.5 9.5H3.5" stroke="#1AB245" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M15.5 3.5L21.5 9.5" stroke="#1AB245" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3.89941 14.5H21.8994" stroke="#1AB245" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3.89941 14.5L9.89944 20.5" stroke="#1AB245" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 566 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 818 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1676338057026" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6605" id="mx_n_1676338057027" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="1024"><path d="M868 732h-70.3c-4.8 0-9.3 2.1-12.3 5.8-7 8.5-14.5 16.7-22.4 24.5-32.6 32.5-70.5 58.1-112.7 75.9-43.6 18.4-90 27.8-137.9 27.8-47.9 0-94.3-9.4-137.9-27.8-42.2-17.8-80.1-43.4-112.7-75.9-32.6-32.5-58.1-70.4-76-112.5C167.3 606.2 158 559.9 158 512s9.4-94.2 27.8-137.8c17.8-42.1 43.4-80 76-112.5s70.5-58.1 112.7-75.9c43.6-18.4 90-27.8 137.9-27.8 47.9 0 94.3 9.3 137.9 27.8 42.2 17.8 80.1 43.4 112.7 75.9 7.9 7.9 15.3 16.1 22.4 24.5 3 3.7 7.6 5.8 12.3 5.8H868c6.3 0 10.2-7 6.7-12.3C798 160.5 663.8 81.6 511.3 82 271.7 82.6 79.6 277.1 82 516.4 84.4 751.9 276.2 942 512.4 942c152.1 0 285.7-78.8 362.3-197.7 3.4-5.3-0.4-12.3-6.7-12.3z m88.9-226.3L815 393.7c-5.3-4.2-13-0.4-13 6.3v76H488c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h314v76c0 6.7 7.8 10.5 13 6.3l141.9-112c4.1-3.2 4.1-9.4 0-12.6z" fill="tomato" p-id="6606"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 28 28" class="design-iconfont">
<defs>
<clipPath id="yfo5thovea">
<path data-name="矩形 4048" transform="translate(510 811)" stroke="#707070" fill="#666f80" d="M0 0H28V28H0z"/>
</clipPath>
</defs>
<g data-name="蒙版组 226" transform="translate(-510 -811)" clip-path="url(#yfo5thovea)">
<path d="M21.25,0H9A3.5,3.5,0,0,0,5.5,3.5,3.5,3.5,0,0,0,2,7V24.5A3.5,3.5,0,0,0,5.5,28H17.75a3.5,3.5,0,0,0,3.5-3.5,3.5,3.5,0,0,0,3.5-3.5V3.5A3.5,3.5,0,0,0,21.25,0Zm0,22.75V7a3.5,3.5,0,0,0-3.5-3.5H7.25A1.75,1.75,0,0,1,9,1.75H21.25A1.75,1.75,0,0,1,23,3.5V21A1.75,1.75,0,0,1,21.25,22.75ZM3.75,7A1.75,1.75,0,0,1,5.5,5.25H17.75A1.75,1.75,0,0,1,19.5,7V24.5a1.75,1.75,0,0,1-1.75,1.75H5.5A1.75,1.75,0,0,1,3.75,24.5Z" transform="translate(510.625 811)" fill="#666f80"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 842 B

View File

@@ -0,0 +1,3 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" class="design-iconfont">
<path fill-rule="evenodd" clip-rule="evenodd" d="M34.7722 34.8391C34.7722 32.4452 34.7722 31.2482 35.2381 30.3339C35.6479 29.5296 36.3018 28.8757 37.1061 28.4659C38.0204 28 39.2174 28 41.6113 28H58.3885C60.7824 28 61.9793 28 62.8937 28.4659C63.698 28.8757 64.3519 29.5296 64.7617 30.3339C65.2276 31.2482 65.2276 32.4452 65.2276 34.8391V49.7737H71.7626C73.7458 49.7737 74.6595 52.2403 73.1549 53.5323L52.728 70.8852C51.1257 72.3744 48.8741 72.3744 47.2717 70.8852L26.8448 53.5323C25.3402 52.2403 26.254 49.7737 28.2372 49.7737H34.7722V34.8391ZM43.8757 38.2446C44.5296 37.6936 45.5014 37.7829 46.0464 38.4441L49.9999 43.241L53.9534 38.4441C54.4983 37.7829 55.4702 37.6936 56.1241 38.2446C56.778 38.7956 56.8663 39.7783 56.3214 40.4394L53.1443 44.2943H56.1978C57.0536 44.2943 57.7473 44.9522 57.7473 45.7637C57.7473 46.5752 57.0536 47.233 56.1978 47.233H51.6028V50.44H56.1978C57.0536 50.44 57.7473 51.0978 57.7473 51.9093C57.7473 52.7208 57.0536 53.3786 56.1978 53.3786H51.6028V58.2397C51.6028 59.0955 50.8851 59.7892 49.9999 59.7892C49.1146 59.7892 48.3969 59.0955 48.3969 58.2397V53.3786H43.8019C42.9462 53.3786 42.2524 52.7208 42.2524 51.9093C42.2524 51.0978 42.9462 50.44 43.8019 50.44H48.3969V47.233H43.8019C42.9462 47.233 42.2524 46.5752 42.2524 45.7637C42.2524 44.9522 42.9462 44.2943 43.8019 44.2943H46.8554L43.6783 40.4394C43.1334 39.7783 43.2217 38.7956 43.8757 38.2446Z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 28 28" class="design-iconfont">
<defs>
<clipPath id="z7louo04ca">
<path data-name="矩形 4047" transform="translate(341 461)" stroke="#707070" fill="#666f80" d="M0 0H28V28H0z"/>
</clipPath>
</defs>
<g data-name="蒙版组 225" transform="translate(-341 -461)" clip-path="url(#z7louo04ca)">
<path data-name="联合 7" d="M10.793,20.639a10.507,10.507,0,0,1-7.647-8.393H4.929a8.75,8.75,0,0,0,15.323,3.82.864.864,0,0,1,.828-.328.873.873,0,0,1,.52,1.442,10.5,10.5,0,0,1-10.807,3.459Zm12-7.044L19.35,9.467A.45.45,0,0,1,19.289,9a.44.44,0,0,1,.4-.255h2.39A8.749,8.749,0,0,0,6.752,4.93a.87.87,0,0,1-.828.328A.873.873,0,0,1,5.4,3.816a10.5,10.5,0,0,1,18.454,4.93h2.709a.448.448,0,0,1,.4.255.441.441,0,0,1-.061.467l-3.438,4.127a.44.44,0,0,1-.336.159A.427.427,0,0,1,22.793,13.594ZM.437,12.246a.447.447,0,0,1-.4-.25A.452.452,0,0,1,.1,11.528L3.543,7.4a.431.431,0,0,1,.668,0l3.442,4.127A.452.452,0,0,1,7.715,12a.447.447,0,0,1-.4.25Z" fill="#666f80" transform="translate(341.497 464.506)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@@ -0,0 +1,3 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" class="design-iconfont">
<path d="M43.0813 55.8192C42.8478 55.9372 42.6086 55.9935 42.3182 55.9935C41.6689 55.9935 41.1393 55.645 40.843 55.1223L40.7235 54.8921L36.0707 44.8894C36.0138 44.7715 36.0138 44.6592 36.0138 44.5413C36.0138 44.0748 36.3669 43.7263 36.8396 43.7263C37.0163 43.7263 37.1928 43.7826 37.3694 43.9005L42.8478 47.7386C43.2578 47.9688 43.7306 48.1431 44.2601 48.1431C44.5562 48.1431 44.8468 48.0868 45.143 47.9688L70.833 36.6908C66.2372 31.3412 58.6399 27.8516 50.0349 27.8516C36.0138 27.8516 24.584 37.2135 24.584 48.7783C24.584 55.0551 28.001 60.7529 33.3601 64.591C33.7699 64.8832 34.0661 65.4059 34.0661 65.9284C34.0661 66.1026 34.0091 66.2769 33.9466 66.4511C33.5367 68.0189 32.8248 70.5813 32.8248 70.6939C32.7678 70.8678 32.7049 71.0984 32.7049 71.3342C32.7049 71.8007 33.0581 72.1492 33.5308 72.1492C33.7074 72.1492 33.884 72.0929 34.0035 71.9749L39.5389 68.7776C39.9491 68.547 40.4218 68.3728 40.8945 68.3728C41.1278 68.3728 41.424 68.4291 41.6576 68.4908C44.2487 69.244 47.0792 69.6542 49.9665 69.6542C63.9877 69.6542 75.4173 60.2922 75.4173 48.7275C75.4173 45.2379 74.3581 41.928 72.5301 39.0174L43.2578 55.7012L43.0813 55.8192Z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,11 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" class="design-iconfont">
<path d="M43.8121 41.2126C43.453 40.6482 42.6933 40.4676 42.1064 40.8102C41.5144 41.1558 41.3225 41.9029 41.6776 42.4788L42.7495 41.8531C41.6776 42.4788 41.6779 42.4793 41.6782 42.4797L41.6788 42.4807L41.68 42.4827L41.6827 42.487L41.689 42.497C41.6937 42.5042 41.6991 42.5127 41.7055 42.5223C41.7181 42.5416 41.7342 42.5654 41.7538 42.5931C41.7928 42.6485 41.8461 42.7203 41.914 42.8029C42.0488 42.9667 42.2471 43.1809 42.5118 43.3955C43.0426 43.8259 43.8785 44.2855 44.9994 44.2855L56.2492 44.2855V49.3369L54.7491 50.7965L50.8963 47.0478L50.8902 47.0417L50.8832 47.0349C50.3951 46.5599 49.6036 46.5599 49.1155 47.0349L44.3656 51.6564C43.8774 52.1313 43.8774 52.9014 44.3656 53.3763C44.8537 53.8513 45.6452 53.8513 46.1333 53.3763L49.9993 49.6149L53.8654 53.3765C54.3535 53.8515 55.145 53.8515 55.6331 53.3765C55.6379 53.3719 55.6426 53.3672 55.6473 53.3625L66.3829 42.917C66.8711 42.4421 66.8711 41.672 66.3829 41.1971C65.8948 40.7221 65.1033 40.7221 64.6152 41.1971L58.7492 46.9045V43.073L58.7492 43.0693L58.7491 43.0614C58.749 43.0314 58.7476 43.0016 58.7452 42.9721C58.6945 42.3458 58.156 41.8528 57.4992 41.8528C57.4906 41.8528 57.4821 41.8529 57.4736 41.8531L44.9995 41.8531C44.6204 41.8531 44.3313 41.7046 44.1122 41.5269C44.0019 41.4375 43.9189 41.3475 43.8662 41.2834C43.8403 41.252 43.8234 41.2287 43.8155 41.2176L43.8121 41.2126Z" fill="#fff"/>
<path d="M41.7495 45.2582C42.4398 45.2582 42.9995 45.8028 42.9995 46.4744V58.1499C42.9995 58.8216 42.4398 59.3661 41.7495 59.3661C41.0592 59.3661 40.4995 58.8216 40.4995 58.1499V46.4744C40.4995 45.8028 41.0592 45.2582 41.7495 45.2582Z" fill="#fff"/>
<path d="M56.2492 55.231V54.7962L58.7492 52.3638V55.231C58.7492 55.8605 58.7189 56.4596 58.5942 56.9862C58.4643 57.535 58.2151 58.0767 57.7277 58.5051C57.2529 58.9223 56.6741 59.1238 56.0983 59.2305C55.5287 59.3361 54.8634 59.366 54.1243 59.366C53.4339 59.366 52.8743 58.8215 52.8743 58.1498C52.8743 57.4781 53.4339 56.9336 54.1243 56.9336C54.8226 56.9336 55.2979 56.9027 55.6306 56.8411C55.9571 56.7806 56.0424 56.7085 56.052 56.7C56.057 56.6956 56.0676 56.686 56.0838 56.6561C56.1022 56.622 56.1305 56.5566 56.1581 56.4401C56.217 56.1914 56.2492 55.8176 56.2492 55.231Z" fill="#fff"/>
<path d="M78.9988 40.88C79.6891 40.88 80.2487 41.4245 80.2487 42.0961V43.7988L81.7487 43.7988C82.439 43.7988 82.9987 44.3433 82.9987 45.015C82.9987 45.6867 82.439 46.2312 81.7487 46.2312H80.2487V55.231C80.2487 55.8606 80.2185 56.4597 80.0938 56.9863C79.9639 57.535 79.7147 58.0768 79.2272 58.5051C78.7525 58.9223 78.1737 59.1239 77.5979 59.2306C77.0282 59.3362 76.363 59.3661 75.6238 59.3661C74.9335 59.3661 74.3739 58.8216 74.3739 58.1499C74.3739 57.4782 74.9335 56.9337 75.6238 56.9337C76.3222 56.9337 76.7975 56.9028 77.1301 56.8412C77.4567 56.7806 77.5419 56.7085 77.5516 56.7001C77.5566 56.6957 77.5671 56.686 77.5833 56.6561C77.6018 56.6221 77.6301 56.5567 77.6577 56.4402C77.7166 56.1915 77.7488 55.8177 77.7488 55.231V46.2312L69.499 46.2312C68.8086 46.2312 68.249 45.6867 68.249 45.015C68.249 44.3433 68.8086 43.7988 69.499 43.7988L77.7488 43.7988V42.0961C77.7488 41.4245 78.3084 40.88 78.9988 40.88Z" fill="#fff"/>
<path d="M18.5 43.0691C18.5 42.3974 19.0596 41.8529 19.7499 41.8529H34.9996C35.69 41.8529 36.2496 42.3974 36.2496 43.0691C36.2496 43.7408 35.69 44.2853 34.9996 44.2853H19.7499C19.0596 44.2853 18.5 43.7408 18.5 43.0691Z" fill="#fff"/>
<path d="M17 49.3933C17 48.7216 17.5596 48.1771 18.25 48.1771H36.2496C36.94 48.1771 37.4996 48.7216 37.4996 49.3933C37.4996 50.065 36.94 50.6095 36.2496 50.6095H18.25C17.5596 50.6095 17 50.065 17 49.3933Z" fill="#fff"/>
<path d="M70.8828 48.2903C70.3947 47.8153 69.6032 47.8153 69.1151 48.2903C68.6269 48.7652 68.6269 49.5353 69.1151 50.0102L72.865 53.6588C73.3531 54.1338 74.1446 54.1338 74.6327 53.6588C75.1209 53.1838 75.1209 52.4138 74.6327 51.9388L70.8828 48.2903Z" fill="#fff"/>
<path d="M63.9991 58.1499V47.2558L66.499 44.8234V58.1499C66.499 58.8216 65.9394 59.3661 65.249 59.3661C64.5587 59.3661 63.9991 58.8216 63.9991 58.1499Z" fill="#fff"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M24.1348 50.7541L24.1294 50.7655L24.1117 50.8031C24.096 50.8366 24.0726 50.8866 24.0427 50.9511C23.9829 51.0803 23.8969 51.2675 23.7936 51.4975C23.5866 51.9582 23.3114 52.5866 23.0372 53.261C22.7618 53.9384 22.4936 54.6468 22.2962 55.2711C22.0858 55.9364 21.9999 56.3739 21.9999 56.5686C21.9999 56.6312 22.0099 56.659 22.0121 56.6648C22.0143 56.6705 22.0167 56.6752 22.0241 56.6835C22.0454 56.7072 22.111 56.7611 22.2588 56.816C22.4022 56.8694 22.5633 56.9015 22.7009 56.9185C22.7664 56.9266 22.8191 56.9305 22.8517 56.9322C22.8675 56.933 22.878 56.9333 22.8825 56.9335H32.8643C32.8684 56.9333 32.8762 56.933 32.8874 56.9323C32.9161 56.9305 32.9643 56.9266 33.0248 56.9179C33.1523 56.8997 33.301 56.8654 33.4326 56.8089C33.5634 56.7528 33.6339 56.6938 33.6703 56.6469C33.6947 56.6154 33.7497 56.5348 33.7497 56.3254C33.7497 55.6417 33.5655 55.2161 33.4243 54.9843C33.3511 54.8642 33.2836 54.7867 33.2457 54.7474C33.2327 54.734 33.2233 54.7252 33.2185 54.7208C32.6933 54.3122 32.5934 53.5687 32.9997 53.0416C33.4139 52.5043 34.1974 52.3954 34.7497 52.7984L33.9997 53.7714C34.7497 52.7984 34.7502 52.7988 34.7508 52.7993L34.752 52.8002L34.7545 52.802L34.7598 52.8059L34.7715 52.8147C34.7797 52.8209 34.789 52.8281 34.7991 52.8361C34.8194 52.8522 34.8434 52.8718 34.8705 52.8951C34.9246 52.9416 34.9914 53.003 35.0661 53.0804C35.2157 53.2349 35.3982 53.4539 35.575 53.7442C35.9338 54.3334 36.2496 55.1848 36.2496 56.3254C36.2496 57.0281 36.0389 57.6316 35.6649 58.1132C35.3029 58.5793 34.8422 58.8624 34.4417 59.0343C34.0421 59.2059 33.6595 59.2856 33.3886 59.3244C33.2499 59.3442 33.1321 59.3545 33.0446 59.3599C33.0007 59.3626 32.9639 59.3641 32.9353 59.3649C32.921 59.3653 32.9087 59.3655 32.8986 59.3657L32.885 59.3658L32.8794 59.3658L32.877 59.3658H32.8758C32.8752 59.3658 32.8747 59.3658 32.8747 58.1497V59.3658H22.8749V58.2083C22.8749 59.3658 22.8739 59.3658 22.8739 59.3658L22.8707 59.3658L22.8658 59.3658L22.8534 59.3657C22.8441 59.3656 22.8326 59.3654 22.8192 59.3651C22.7923 59.3644 22.7574 59.3632 22.7154 59.361C22.6319 59.3565 22.5185 59.348 22.3848 59.3314C22.124 59.299 21.7539 59.2323 21.366 59.088C20.9826 58.9454 20.5169 58.7028 20.1398 58.2819C19.741 57.8368 19.5 57.2561 19.5 56.5686C19.5 55.9728 19.6953 55.2245 19.9068 54.5558C20.1312 53.8461 20.4255 53.0723 20.7126 52.3662C21.0009 51.6572 21.2882 51.001 21.503 50.523C21.6106 50.2836 21.7005 50.0879 21.7637 49.9515C21.7953 49.8833 21.8203 49.8298 21.8375 49.793L21.8574 49.7507L21.8649 49.735C21.8649 49.735 21.865 49.7348 22.9999 50.2444L21.8649 49.735C22.1542 49.1251 22.8969 48.8587 23.5237 49.1402C24.1505 49.4216 24.424 50.1442 24.1348 50.7541ZM33.2473 54.7426L33.2485 54.7435L33.2473 54.7426Z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -0,0 +1,16 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" class="design-iconfont">
<g clip-path="url(#734tbgb32__clip0_29_2294)">
<mask id="734tbgb32__8a4ttlqjna" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="25" y="25" width="49" height="49">
<path fill="#fff" d="M25 25H74V74H25z"/>
</mask>
<g mask="url(#734tbgb32__8a4ttlqjna)" fill="#fff">
<path d="M35.6701 29H64.4375C68.1368 29.0159 71.1224 32.0285 71.105 35.7279V57.5075C71.0893 57.5075 69.7111 57.3867 63.2878 55.3734C62.2062 55.0059 60.8833 54.515 59.4054 53.9664C58.61 53.6697 57.7674 53.3574 56.8933 53.0398C58.461 50.2655 59.6317 47.2851 60.3714 44.1856H52.1577V41.2036H62.2141V39.5394H52.1604V34.5676H48.0575C47.3382 34.5676 47.3382 35.2842 47.3382 35.2842V39.5394H37.1637V41.2036H47.3356V44.1856H38.9356V45.8499H55.2237C54.6279 47.921 53.8272 49.8661 52.877 51.6301C47.5929 49.8714 41.9544 48.4486 38.4132 49.3254C36.1452 49.8871 34.6857 50.8925 33.83 51.9451C29.8951 56.7751 32.717 64.1068 41.0251 64.1068C45.9391 64.1068 50.672 61.3426 54.3391 56.7909C59.7991 59.4369 71.0604 63.9781 71.105 63.9965V64.2721C71.1224 67.9715 68.1368 70.9841 64.4375 71H35.6701C31.9704 70.9841 28.984 67.9719 29 64.2721V35.7279C28.984 32.0281 31.9704 29.0159 35.6701 29Z"/>
<path d="M35.0612 53.3343C31.8587 56.151 33.775 61.2986 40.2535 61.2986C44.0177 61.2986 47.782 58.8705 50.7377 54.9829C46.5325 52.9117 42.9703 51.4312 39.1221 51.8145C38.08 51.9195 36.1296 52.3841 35.0612 53.337V53.3343Z"/>
</g>
</g>
<defs>
<clipPath id="734tbgb32__clip0_29_2294">
<path fill="#fff" transform="translate(29 29)" d="M0 0H42V42H0z"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1676337440815" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5270" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="1024"><path d="M604.7488 513.659733l-196.292267 196.9024a36.872533 36.872533 0 0 0-1.041066 50.978134 33.8048 33.8048 0 0 0 48.810666 1.019733l218.2144-218.478933c16.648533-16.669867 16.64-43.677867-0.0256-60.330667L455.466667 264.917333a33.493333 33.493333 0 0 0-48.349867 1.041067 36.5312 36.5312 0 0 0 1.041067 50.496l196.590933 197.201067z" fill="#108ee9" p-id="5271"></path></svg>

After

Width:  |  Height:  |  Size: 705 B

View File

@@ -0,0 +1,81 @@
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场https://ext.dcloud.net.cn上很多三方插件均使用了这些样式变量
* 如果你是插件开发者建议你使用scss预处理并在插件代码中直接使用这些变量无需 import 这个文件方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者插件使用者你可以通过修改这些变量来定制自己的插件主题实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
*/
/* 主题色相关 MP-ALIPAY 支付宝小程序主题色 MP-WEIXIN 微信小程序主题色*/
/* #ifdef H5 || MP-WEIXIN */
$v-primary: #35d757;
/* #endif */
/* #ifdef H5 || MP-ALIPAY */
$v-primary: #108ee9;
/* #endif */
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
/* 文字基本颜色 */
$uni-text-color: #333; //基本色
$uni-text-color-inverse: #fff; //反色
$uni-text-color-grey: #999; //辅助灰色,如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable: #c0c0c0;
/* 背景颜色 */
$uni-bg-color: #ffffff;
$uni-bg-color-grey: #f8f8f8;
$uni-bg-color-hover: #f1f1f1; //点击状态颜色
$uni-bg-color-mask: rgba(0, 0, 0, 0.4); //遮罩颜色
/* 边框颜色 */
$uni-border-color: #c8c7cc;
/* 尺寸变量 */
/* 文字尺寸 */
$uni-font-size-sm: 12px;
$uni-font-size-base: 14px;
$uni-font-size-lg: 16;
/* 图片尺寸 */
$uni-img-size-sm: 20px;
$uni-img-size-base: 26px;
$uni-img-size-lg: 40px;
/* Border Radius */
$uni-border-radius-sm: 2px;
$uni-border-radius-base: 3px;
$uni-border-radius-lg: 6px;
$uni-border-radius-circle: 50%;
/* 水平间距 */
$uni-spacing-row-sm: 5px;
$uni-spacing-row-base: 10px;
$uni-spacing-row-lg: 15px;
/* 垂直间距 */
$uni-spacing-col-sm: 4px;
$uni-spacing-col-base: 8px;
$uni-spacing-col-lg: 12px;
/* 透明度 */
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
/* 文章场景相关 */
$uni-color-title: #2c405a; // 文章标题颜色
$uni-font-size-title: 20px;
$uni-color-subtitle: #555555; // 二级标题颜色
$uni-font-size-subtitle: 26px;
$uni-color-paragraph: #3f536e; // 文章段落颜色
$uni-font-size-paragraph: 15px;

View File

@@ -0,0 +1,13 @@
## 1.2.12021-11-22
- 修复 vue3中个别scss变量无法找到的问题
## 1.2.02021-11-19
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-drawer](https://uniapp.dcloud.io/component/uniui/uni-drawer)
## 1.1.12021-07-30
- 优化 vue3下事件警告的问题
## 1.1.02021-07-13
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.0.72021-05-12
- 新增 组件示例地址
## 1.0.62021-02-04
- 调整为uni_modules目录规范

View File

@@ -0,0 +1,45 @@
// #ifdef H5
export default {
name: 'Keypress',
props: {
disable: {
type: Boolean,
default: false
}
},
mounted () {
const keyNames = {
esc: ['Esc', 'Escape'],
tab: 'Tab',
enter: 'Enter',
space: [' ', 'Spacebar'],
up: ['Up', 'ArrowUp'],
left: ['Left', 'ArrowLeft'],
right: ['Right', 'ArrowRight'],
down: ['Down', 'ArrowDown'],
delete: ['Backspace', 'Delete', 'Del']
}
const listener = ($event) => {
if (this.disable) {
return
}
const keyName = Object.keys(keyNames).find(key => {
const keyName = $event.key
const value = keyNames[key]
return value === keyName || (Array.isArray(value) && value.includes(keyName))
})
if (keyName) {
// 避免和其他按键事件冲突
setTimeout(() => {
this.$emit(keyName, {})
}, 0)
}
}
document.addEventListener('keyup', listener)
// this.$once('hook:beforeDestroy', () => {
// document.removeEventListener('keyup', listener)
// })
},
render: () => {}
}
// #endif

View File

@@ -0,0 +1,183 @@
<template>
<view v-if="visibleSync" :class="{ 'uni-drawer--visible': showDrawer }" class="uni-drawer" @touchmove.stop.prevent="clear">
<view class="uni-drawer__mask" :class="{ 'uni-drawer__mask--visible': showDrawer && mask }" @tap="close('mask')" />
<view class="uni-drawer__content" :class="{'uni-drawer--right': rightMode,'uni-drawer--left': !rightMode, 'uni-drawer__content--visible': showDrawer}" :style="{width:drawerWidth+'%'}">
<slot />
</view>
<!-- #ifdef H5 -->
<keypress @esc="close('mask')" />
<!-- #endif -->
</view>
</template>
<script>
// #ifdef H5
import keypress from './keypress.js'
// #endif
/**
* Drawer 抽屉
* @description 抽屉侧滑菜单
* @tutorial https://ext.dcloud.net.cn/plugin?id=26
* @property {Boolean} mask = [true | false] 是否显示遮罩
* @property {Boolean} maskClick = [true | false] 点击遮罩是否关闭
* @property {Boolean} mode = [left | right] Drawer 滑出位置
* @value left 从左侧滑出
* @value right 从右侧侧滑出
* @property {Number} width 抽屉的宽度 ,仅 vue 页面生效
* @event {Function} close 组件关闭时触发事件
*/
export default {
name: 'UniDrawer',
components: {
// #ifdef H5
keypress
// #endif
},
emits:['change'],
props: {
/**
* 显示模式(左、右),只在初始化生效
*/
mode: {
type: String,
default: ''
},
/**
* 蒙层显示状态
*/
mask: {
type: Boolean,
default: true
},
/**
* 遮罩是否可点击关闭
*/
maskClick:{
type: Boolean,
default: true
},
/**
* 抽屉宽度
*/
width: {
type: Number,
default: 80
}
},
data() {
return {
visibleSync: false,
showDrawer: false,
rightMode: false,
watchTimer: null,
drawerWidth: 220
}
},
created() {
// #ifndef APP-NVUE
this.drawerWidth = this.width
// #endif
this.rightMode = this.mode === 'right'
},
methods: {
clear(){},
close(type) {
// fixed by mehaotian 抽屉尚未完全关闭或遮罩禁止点击时不触发以下逻辑
if((type === 'mask' && !this.maskClick) || !this.visibleSync) return
this._change('showDrawer', 'visibleSync', false)
},
open() {
// fixed by mehaotian 处理重复点击打开的事件
if(this.visibleSync) return
this._change('visibleSync', 'showDrawer', true)
},
_change(param1, param2, status) {
this[param1] = status
if (this.watchTimer) {
clearTimeout(this.watchTimer)
}
this.watchTimer = setTimeout(() => {
this[param2] = status
this.$emit('change',status)
}, status ? 50 : 300)
}
}
}
</script>
<style lang="scss" scoped>
$uni-mask: rgba($color: #000000, $alpha: 0.4) ;
// 抽屉宽度
$drawer-width: 220px;
.uni-drawer {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
overflow: hidden;
z-index: 999;
}
.uni-drawer__content {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
position: absolute;
top: 0;
width: $drawer-width;
bottom: 0;
background-color: $uni-bg-color;
transition: transform 0.3s ease;
}
.uni-drawer--left {
left: 0;
/* #ifdef APP-NVUE */
transform: translateX(-$drawer-width);
/* #endif */
/* #ifndef APP-NVUE */
transform: translateX(-100%);
/* #endif */
}
.uni-drawer--right {
right: 0;
/* #ifdef APP-NVUE */
transform: translateX($drawer-width);
/* #endif */
/* #ifndef APP-NVUE */
transform: translateX(100%);
/* #endif */
}
.uni-drawer__content--visible {
transform: translateX(0px);
}
.uni-drawer__mask {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
opacity: 0;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: $uni-mask;
transition: opacity 0.3s;
}
.uni-drawer__mask--visible {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
opacity: 1;
}
</style>

View File

@@ -0,0 +1,87 @@
{
"id": "uni-drawer",
"displayName": "uni-drawer 抽屉",
"version": "1.2.1",
"description": "抽屉式导航,用于展示侧滑菜单,侧滑导航。",
"keywords": [
"uni-ui",
"uniui",
"drawer",
"抽屉",
"侧滑导航"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": ["uni-scss"],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@@ -0,0 +1,10 @@
## Drawer 抽屉
> **组件名uni-drawer**
> 代码块: `uDrawer`
抽屉侧滑菜单。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-drawer)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

View File

@@ -0,0 +1,22 @@
## 1.3.52022-01-24
- 优化 size 属性可以传入不带单位的字符串数值
## 1.3.42022-01-24
- 优化 size 支持其他单位
## 1.3.32022-01-17
- 修复 nvue 有些图标不显示的bug兼容老版本图标
## 1.3.22021-12-01
- 优化 示例可复制图标名称
## 1.3.12021-11-23
- 优化 兼容旧组件 type 值
## 1.3.02021-11-19
- 新增 更多图标
- 优化 自定义图标使用方式
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-icons](https://uniapp.dcloud.io/component/uniui/uni-icons)
## 1.1.72021-11-08
## 1.2.02021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.52021-05-12
- 新增 组件示例地址
## 1.1.42021-02-05
- 调整为uni_modules目录规范

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,96 @@
<template>
<!-- #ifdef APP-NVUE -->
<text :style="{ color: color, 'font-size': iconSize }" class="uni-icons" @click="_onClick">{{unicode}}</text>
<!-- #endif -->
<!-- #ifndef APP-NVUE -->
<text :style="{ color: color, 'font-size': iconSize }" class="uni-icons" :class="['uniui-'+type,customPrefix,customPrefix?type:'']" @click="_onClick"></text>
<!-- #endif -->
</template>
<script>
import icons from './icons.js';
const getVal = (val) => {
const reg = /^[0-9]*$/g
return (typeof val === 'number' || reg.test(val) )? val + 'px' : val;
}
// #ifdef APP-NVUE
var domModule = weex.requireModule('dom');
import iconUrl from './uniicons.ttf'
domModule.addRule('fontFace', {
'fontFamily': "uniicons",
'src': "url('"+iconUrl+"')"
});
// #endif
/**
* Icons 图标
* @description 用于展示 icons 图标
* @tutorial https://ext.dcloud.net.cn/plugin?id=28
* @property {Number} size 图标大小
* @property {String} type 图标图案,参考示例
* @property {String} color 图标颜色
* @property {String} customPrefix 自定义图标
* @event {Function} click 点击 Icon 触发事件
*/
export default {
name: 'UniIcons',
emits:['click'],
props: {
type: {
type: String,
default: ''
},
color: {
type: String,
default: '#333333'
},
size: {
type: [Number, String],
default: 16
},
customPrefix:{
type: String,
default: ''
}
},
data() {
return {
icons: icons.glyphs
}
},
computed:{
unicode(){
let code = this.icons.find(v=>v.font_class === this.type)
if(code){
return unescape(`%u${code.unicode}`)
}
return ''
},
iconSize(){
return getVal(this.size)
}
},
methods: {
_onClick() {
this.$emit('click')
}
}
}
</script>
<style lang="scss">
/* #ifndef APP-NVUE */
@import './uniicons.css';
@font-face {
font-family: uniicons;
src: url('./uniicons.ttf') format('truetype');
}
/* #endif */
.uni-icons {
font-family: uniicons;
text-decoration: none;
text-align: center;
}
</style>

View File

@@ -0,0 +1,663 @@
.uniui-color:before {
content: "\e6cf";
}
.uniui-wallet:before {
content: "\e6b1";
}
.uniui-settings-filled:before {
content: "\e6ce";
}
.uniui-auth-filled:before {
content: "\e6cc";
}
.uniui-shop-filled:before {
content: "\e6cd";
}
.uniui-staff-filled:before {
content: "\e6cb";
}
.uniui-vip-filled:before {
content: "\e6c6";
}
.uniui-plus-filled:before {
content: "\e6c7";
}
.uniui-folder-add-filled:before {
content: "\e6c8";
}
.uniui-color-filled:before {
content: "\e6c9";
}
.uniui-tune-filled:before {
content: "\e6ca";
}
.uniui-calendar-filled:before {
content: "\e6c0";
}
.uniui-notification-filled:before {
content: "\e6c1";
}
.uniui-wallet-filled:before {
content: "\e6c2";
}
.uniui-medal-filled:before {
content: "\e6c3";
}
.uniui-gift-filled:before {
content: "\e6c4";
}
.uniui-fire-filled:before {
content: "\e6c5";
}
.uniui-refreshempty:before {
content: "\e6bf";
}
.uniui-location-filled:before {
content: "\e6af";
}
.uniui-person-filled:before {
content: "\e69d";
}
.uniui-personadd-filled:before {
content: "\e698";
}
.uniui-back:before {
content: "\e6b9";
}
.uniui-forward:before {
content: "\e6ba";
}
.uniui-arrow-right:before {
content: "\e6bb";
}
.uniui-arrowthinright:before {
content: "\e6bb";
}
.uniui-arrow-left:before {
content: "\e6bc";
}
.uniui-arrowthinleft:before {
content: "\e6bc";
}
.uniui-arrow-up:before {
content: "\e6bd";
}
.uniui-arrowthinup:before {
content: "\e6bd";
}
.uniui-arrow-down:before {
content: "\e6be";
}
.uniui-arrowthindown:before {
content: "\e6be";
}
.uniui-bottom:before {
content: "\e6b8";
}
.uniui-arrowdown:before {
content: "\e6b8";
}
.uniui-right:before {
content: "\e6b5";
}
.uniui-arrowright:before {
content: "\e6b5";
}
.uniui-top:before {
content: "\e6b6";
}
.uniui-arrowup:before {
content: "\e6b6";
}
.uniui-left:before {
content: "\e6b7";
}
.uniui-arrowleft:before {
content: "\e6b7";
}
.uniui-eye:before {
content: "\e651";
}
.uniui-eye-filled:before {
content: "\e66a";
}
.uniui-eye-slash:before {
content: "\e6b3";
}
.uniui-eye-slash-filled:before {
content: "\e6b4";
}
.uniui-info-filled:before {
content: "\e649";
}
.uniui-reload:before {
content: "\e6b2";
}
.uniui-micoff-filled:before {
content: "\e6b0";
}
.uniui-map-pin-ellipse:before {
content: "\e6ac";
}
.uniui-map-pin:before {
content: "\e6ad";
}
.uniui-location:before {
content: "\e6ae";
}
.uniui-starhalf:before {
content: "\e683";
}
.uniui-star:before {
content: "\e688";
}
.uniui-star-filled:before {
content: "\e68f";
}
.uniui-calendar:before {
content: "\e6a0";
}
.uniui-fire:before {
content: "\e6a1";
}
.uniui-medal:before {
content: "\e6a2";
}
.uniui-font:before {
content: "\e6a3";
}
.uniui-gift:before {
content: "\e6a4";
}
.uniui-link:before {
content: "\e6a5";
}
.uniui-notification:before {
content: "\e6a6";
}
.uniui-staff:before {
content: "\e6a7";
}
.uniui-vip:before {
content: "\e6a8";
}
.uniui-folder-add:before {
content: "\e6a9";
}
.uniui-tune:before {
content: "\e6aa";
}
.uniui-auth:before {
content: "\e6ab";
}
.uniui-person:before {
content: "\e699";
}
.uniui-email-filled:before {
content: "\e69a";
}
.uniui-phone-filled:before {
content: "\e69b";
}
.uniui-phone:before {
content: "\e69c";
}
.uniui-email:before {
content: "\e69e";
}
.uniui-personadd:before {
content: "\e69f";
}
.uniui-chatboxes-filled:before {
content: "\e692";
}
.uniui-contact:before {
content: "\e693";
}
.uniui-chatbubble-filled:before {
content: "\e694";
}
.uniui-contact-filled:before {
content: "\e695";
}
.uniui-chatboxes:before {
content: "\e696";
}
.uniui-chatbubble:before {
content: "\e697";
}
.uniui-upload-filled:before {
content: "\e68e";
}
.uniui-upload:before {
content: "\e690";
}
.uniui-weixin:before {
content: "\e691";
}
.uniui-compose:before {
content: "\e67f";
}
.uniui-qq:before {
content: "\e680";
}
.uniui-download-filled:before {
content: "\e681";
}
.uniui-pyq:before {
content: "\e682";
}
.uniui-sound:before {
content: "\e684";
}
.uniui-trash-filled:before {
content: "\e685";
}
.uniui-sound-filled:before {
content: "\e686";
}
.uniui-trash:before {
content: "\e687";
}
.uniui-videocam-filled:before {
content: "\e689";
}
.uniui-spinner-cycle:before {
content: "\e68a";
}
.uniui-weibo:before {
content: "\e68b";
}
.uniui-videocam:before {
content: "\e68c";
}
.uniui-download:before {
content: "\e68d";
}
.uniui-help:before {
content: "\e679";
}
.uniui-navigate-filled:before {
content: "\e67a";
}
.uniui-plusempty:before {
content: "\e67b";
}
.uniui-smallcircle:before {
content: "\e67c";
}
.uniui-minus-filled:before {
content: "\e67d";
}
.uniui-micoff:before {
content: "\e67e";
}
.uniui-closeempty:before {
content: "\e66c";
}
.uniui-clear:before {
content: "\e66d";
}
.uniui-navigate:before {
content: "\e66e";
}
.uniui-minus:before {
content: "\e66f";
}
.uniui-image:before {
content: "\e670";
}
.uniui-mic:before {
content: "\e671";
}
.uniui-paperplane:before {
content: "\e672";
}
.uniui-close:before {
content: "\e673";
}
.uniui-help-filled:before {
content: "\e674";
}
.uniui-paperplane-filled:before {
content: "\e675";
}
.uniui-plus:before {
content: "\e676";
}
.uniui-mic-filled:before {
content: "\e677";
}
.uniui-image-filled:before {
content: "\e678";
}
.uniui-locked-filled:before {
content: "\e668";
}
.uniui-info:before {
content: "\e669";
}
.uniui-locked:before {
content: "\e66b";
}
.uniui-camera-filled:before {
content: "\e658";
}
.uniui-chat-filled:before {
content: "\e659";
}
.uniui-camera:before {
content: "\e65a";
}
.uniui-circle:before {
content: "\e65b";
}
.uniui-checkmarkempty:before {
content: "\e65c";
}
.uniui-chat:before {
content: "\e65d";
}
.uniui-circle-filled:before {
content: "\e65e";
}
.uniui-flag:before {
content: "\e65f";
}
.uniui-flag-filled:before {
content: "\e660";
}
.uniui-gear-filled:before {
content: "\e661";
}
.uniui-home:before {
content: "\e662";
}
.uniui-home-filled:before {
content: "\e663";
}
.uniui-gear:before {
content: "\e664";
}
.uniui-smallcircle-filled:before {
content: "\e665";
}
.uniui-map-filled:before {
content: "\e666";
}
.uniui-map:before {
content: "\e667";
}
.uniui-refresh-filled:before {
content: "\e656";
}
.uniui-refresh:before {
content: "\e657";
}
.uniui-cloud-upload:before {
content: "\e645";
}
.uniui-cloud-download-filled:before {
content: "\e646";
}
.uniui-cloud-download:before {
content: "\e647";
}
.uniui-cloud-upload-filled:before {
content: "\e648";
}
.uniui-redo:before {
content: "\e64a";
}
.uniui-images-filled:before {
content: "\e64b";
}
.uniui-undo-filled:before {
content: "\e64c";
}
.uniui-more:before {
content: "\e64d";
}
.uniui-more-filled:before {
content: "\e64e";
}
.uniui-undo:before {
content: "\e64f";
}
.uniui-images:before {
content: "\e650";
}
.uniui-paperclip:before {
content: "\e652";
}
.uniui-settings:before {
content: "\e653";
}
.uniui-search:before {
content: "\e654";
}
.uniui-redo-filled:before {
content: "\e655";
}
.uniui-list:before {
content: "\e644";
}
.uniui-mail-open-filled:before {
content: "\e63a";
}
.uniui-hand-down-filled:before {
content: "\e63c";
}
.uniui-hand-down:before {
content: "\e63d";
}
.uniui-hand-up-filled:before {
content: "\e63e";
}
.uniui-hand-up:before {
content: "\e63f";
}
.uniui-heart-filled:before {
content: "\e641";
}
.uniui-mail-open:before {
content: "\e643";
}
.uniui-heart:before {
content: "\e639";
}
.uniui-loop:before {
content: "\e633";
}
.uniui-pulldown:before {
content: "\e632";
}
.uniui-scan:before {
content: "\e62a";
}
.uniui-bars:before {
content: "\e627";
}
.uniui-cart-filled:before {
content: "\e629";
}
.uniui-checkbox:before {
content: "\e62b";
}
.uniui-checkbox-filled:before {
content: "\e62c";
}
.uniui-shop:before {
content: "\e62f";
}
.uniui-headphones:before {
content: "\e630";
}
.uniui-cart:before {
content: "\e631";
}

View File

@@ -0,0 +1,86 @@
{
"id": "uni-icons",
"displayName": "uni-icons 图标",
"version": "1.3.5",
"description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。",
"keywords": [
"uni-ui",
"uniui",
"icon",
"图标"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": "^3.2.14"
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": ["uni-scss"],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@@ -0,0 +1,8 @@
## Icons 图标
> **组件名uni-icons**
> 代码块: `uIcons`
用于展示 icons 图标 。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-icons)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

View File

@@ -0,0 +1,47 @@
## 1.3.92022-10-13
- 修复 条件编译错误的bug
## 1.3.82022-10-12
- 修复 nvue 环境 fixed 为 true 的情况下,无法置顶的 bug
## 1.3.72022-08-11
- 修复 nvue 环境下 fixed 为 true 的情况下,无法置顶的 bug
## 1.3.62022-06-30
- 修复 组件示例中插槽用法无法显示内容的bug
## 1.3.52022-05-24
- 新增 stat 属性 可开启统计title 上报 仅使用了title 属性且项目开启了uni统计生效
## 1.3.42022-01-24
- 更新 组件示例
## 1.3.32022-01-24
- 新增 left-width/right-width属性 ,可修改左右两侧的宽度
## 1.3.22022-01-18
- 修复 在vue下标题不垂直居中的bug
## 1.3.12022-01-18
- 修复 height 属性类型错误
## 1.3.02022-01-18
- 新增 height 属性,可修改组件高度
- 新增 dark 属性可可开启暗黑模式
- 优化 标题字数过多显示省略号
- 优化 插槽,插入内容可完全覆盖
## 1.2.12022-01-10
- 修复 color 属性不生效的bug
## 1.2.02021-11-19
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-nav-bar](https://uniapp.dcloud.io/component/uniui/uni-nav-bar)
## 1.1.02021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.0.112021-05-12
- 新增 组件示例地址
## 1.0.102021-04-30
- 修复 在nvue下fixed为true宽度不能撑满的Bug
## 1.0.92021-04-21
- 优化 添加依赖 uni-icons, 导入后自动下载依赖
## 1.0.82021-04-14
- uni-ui 修复 uni-nav-bar 当 fixed 属性为 true 时铺不满屏幕的 bug
## 1.0.72021-02-25
- 修复 easycom 下,找不到 uni-status-bar 的bug
## 1.0.62021-02-05
- 优化 组件引用关系通过uni_modules引用组件
## 1.0.52021-02-05
- 调整为uni_modules目录规范

View File

@@ -0,0 +1,357 @@
<template>
<view class="uni-navbar" :class="{'uni-dark':dark, 'uni-nvue-fixed': fixed}">
<view class="uni-navbar__content" :class="{ 'uni-navbar--fixed': fixed, 'uni-navbar--shadow': shadow, 'uni-navbar--border': border }"
:style="{ 'background-color': themeBgColor }" >
<status-bar v-if="statusBar" />
<view :style="{ color: themeColor,backgroundColor: themeBgColor ,height:navbarHeight}"
class="uni-navbar__header">
<view @tap="onClickLeft" class="uni-navbar__header-btns uni-navbar__header-btns-left"
:style="{width:leftIconWidth}">
<slot name="left">
<view class="uni-navbar__content_view" v-if="leftIcon.length > 0">
<uni-icons :color="themeColor" :type="leftIcon" size="20" />
</view>
<view :class="{ 'uni-navbar-btn-icon-left': !leftIcon.length > 0 }" class="uni-navbar-btn-text"
v-if="leftText.length">
<text :style="{ color: themeColor, fontSize: '12px' }">{{ leftText }}</text>
</view>
</slot>
</view>
<view class="uni-navbar__header-container " @tap="onClickTitle">
<slot>
<view class="uni-navbar__header-container-inner" v-if="title.length>0">
<text class="uni-nav-bar-text uni-ellipsis-1"
:style="{color: themeColor }">{{ title }}</text>
</view>
</slot>
</view>
<view @click="onClickRight" class="uni-navbar__header-btns uni-navbar__header-btns-right"
:style="{width:rightIconWidth}">
<slot name="right">
<view v-if="rightIcon.length">
<uni-icons :color="themeColor" :type="rightIcon" size="22" />
</view>
<view class="uni-navbar-btn-text" v-if="rightText.length && !rightIcon.length">
<text class="uni-nav-bar-right-text" :style="{ color: themeColor}">{{ rightText }}</text>
</view>
</slot>
</view>
</view>
</view>
<!-- #ifndef APP-NVUE -->
<view class="uni-navbar__placeholder" v-if="fixed">
<status-bar v-if="statusBar" />
<view class="uni-navbar__placeholder-view" :style="{ height:navbarHeight}" />
</view>
<!-- #endif -->
</view>
</template>
<script>
import statusBar from "./uni-status-bar.vue";
const getVal = (val) => typeof val === 'number' ? val + 'px' : val;
/**
*
*
* NavBar 自定义导航栏
* @description 导航栏组件,主要用于头部导航
* @tutorial https://ext.dcloud.net.cn/plugin?id=52
* @property {Boolean} dark 开启黑暗模式
* @property {String} title 标题文字
* @property {String} leftText 左侧按钮文本
* @property {String} rightText 右侧按钮文本
* @property {String} leftIcon 左侧按钮图标(图标类型参考 [Icon 图标](http://ext.dcloud.net.cn/plugin?id=28) type 属性)
* @property {String} rightIcon 右侧按钮图标(图标类型参考 [Icon 图标](http://ext.dcloud.net.cn/plugin?id=28) type 属性)
* @property {String} color 图标和文字颜色
* @property {String} backgroundColor 导航栏背景颜色
* @property {Boolean} fixed = [true|false] 是否固定顶部
* @property {Boolean} statusBar = [true|false] 是否包含状态栏
* @property {Boolean} shadow = [true|false] 导航栏下是否有阴影
* @property {Boolean} stat 是否开启统计标题上报
* @event {Function} clickLeft 左侧按钮点击时触发
* @event {Function} clickRight 右侧按钮点击时触发
* @event {Function} clickTitle 中间标题点击时触发
*/
export default {
name: "UniNavBar",
components: {
statusBar
},
emits: ['clickLeft', 'clickRight', 'clickTitle'],
props: {
dark: {
type: Boolean,
default: false
},
title: {
type: String,
default: ""
},
leftText: {
type: String,
default: ""
},
rightText: {
type: String,
default: ""
},
leftIcon: {
type: String,
default: ""
},
rightIcon: {
type: String,
default: ""
},
fixed: {
type: [Boolean, String],
default: false
},
color: {
type: String,
default: ""
},
backgroundColor: {
type: String,
default: ""
},
statusBar: {
type: [Boolean, String],
default: false
},
shadow: {
type: [Boolean, String],
default: false
},
border: {
type: [Boolean, String],
default: true
},
height: {
type: [Number, String],
default: 44
},
leftWidth: {
type: [Number, String],
default: 60
},
rightWidth: {
type: [Number, String],
default: 60
},
stat: {
type: [Boolean, String],
default: ''
}
},
computed: {
themeBgColor() {
if (this.dark) {
// 默认值
if (this.backgroundColor) {
return this.backgroundColor
} else {
return this.dark ? '#333' : '#FFF'
}
}
return this.backgroundColor || '#FFF'
},
themeColor() {
if (this.dark) {
// 默认值
if (this.color) {
return this.color
} else {
return this.dark ? '#fff' : '#333'
}
}
return this.color || '#333'
},
navbarHeight() {
return getVal(this.height)
},
leftIconWidth() {
return getVal(this.leftWidth)
},
rightIconWidth() {
return getVal(this.rightWidth)
}
},
mounted() {
if (uni.report && this.stat && this.title !== '') {
uni.report('title', this.title)
}
},
methods: {
onClickLeft() {
this.$emit("clickLeft");
},
onClickRight() {
this.$emit("clickRight");
},
onClickTitle() {
this.$emit("clickTitle");
}
}
};
</script>
<style lang="scss" scoped>
$nav-height: 44px;
.uni-nvue-fixed {
/* #ifdef APP-NVUE */
position: sticky;
/* #endif */
}
.uni-navbar {
// box-sizing: border-box;
}
.uni-nav-bar-text {
/* #ifdef APP-PLUS */
font-size: 34rpx;
/* #endif */
/* #ifndef APP-PLUS */
font-size: 14px;
/* #endif */
}
.uni-nav-bar-right-text {
font-size: 12px;
}
.uni-navbar__content {
position: relative;
// background-color: #fff;
// box-sizing: border-box;
background-color: transparent;
}
.uni-navbar__content_view {
// box-sizing: border-box;
}
.uni-navbar-btn-text {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: flex-start;
align-items: center;
line-height: 12px;
}
.uni-navbar__header {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
padding: 0 10px;
flex-direction: row;
height: $nav-height;
font-size: 12px;
}
.uni-navbar__header-btns {
/* #ifndef APP-NVUE */
overflow: hidden;
display: flex;
/* #endif */
flex-wrap: nowrap;
flex-direction: row;
width: 120rpx;
// padding: 0 6px;
justify-content: center;
align-items: center;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
.uni-navbar__header-btns-left {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
width: 120rpx;
justify-content: flex-start;
align-items: center;
}
.uni-navbar__header-btns-right {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
// width: 150rpx;
// padding-right: 30rpx;
justify-content: flex-end;
align-items: center;
}
.uni-navbar__header-container {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
padding: 0 10px;
overflow: hidden;
}
.uni-navbar__header-container-inner {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
justify-content: center;
font-size: 12px;
overflow: hidden;
// box-sizing: border-box;
}
.uni-navbar__placeholder-view {
height: $nav-height;
}
.uni-navbar--fixed {
position: fixed;
z-index: 998;
/* #ifdef H5 */
left: var(--window-left);
right: var(--window-right);
/* #endif */
/* #ifndef H5 */
left: 0;
right: 0;
/* #endif */
}
.uni-navbar--shadow {
box-shadow: 0 1px 6px #ccc;
}
.uni-navbar--border {
border-bottom-width: 1rpx;
border-bottom-style: solid;
border-bottom-color: #eee;
}
.uni-ellipsis-1 {
overflow: hidden;
/* #ifndef APP-NVUE */
white-space: nowrap;
text-overflow: ellipsis;
/* #endif */
/* #ifdef APP-NVUE */
lines: 1;
text-overflow: ellipsis;
/* #endif */
}
// 暗主题配置
.uni-dark {}
</style>

View File

@@ -0,0 +1,27 @@
<template>
<view :style="{ height: statusBarHeight }" class="uni-status-bar">
<slot />
</view>
</template>
<script>
export default {
name: 'UniStatusBar',
data() {
return {
statusBarHeight: 20
}
},
mounted() {
this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight + 'px'
}
}
</script>
<style lang="scss" >
.uni-status-bar {
// width: 750rpx;
height: 20px;
// height: var(--status-bar-height);
}
</style>

View File

@@ -0,0 +1,86 @@
{
"id": "uni-nav-bar",
"displayName": "uni-nav-bar 自定义导航栏",
"version": "1.3.9",
"description": "自定义导航栏组件,主要用于头部导航。",
"keywords": [
"uni-ui",
"导航",
"导航栏",
"自定义导航栏"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": [
"uni-scss",
"uni-icons"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@@ -0,0 +1,15 @@
## NavBar 导航栏
> **组件名uni-nav-bar**
> 代码块: `uNavBar`
导航栏组件,主要用于头部导航。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-nav-bar)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

Some files were not shown because too many files have changed in this diff Show More