同步代码到仓库

This commit is contained in:
GaoHao
2024-10-12 18:22:56 +08:00
commit 5586573ff1
37 changed files with 5248 additions and 0 deletions

14
commons/readme.txt Normal file
View File

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

378
commons/style/common.scss Normal file
View File

@@ -0,0 +1,378 @@
.u-relative,
.u-rela {
position: relative;
}
.u-absolute,
.u-abso {
position: absolute;
}
.u-fixed,.u-fix{
position: fixed;
}
.left-top{
left: 0;
top: 0;
}
.u-overflow-hide{
overflow: hidden;
}
// nvue不能用标签命名样式不能放在微信组件中否则微信开发工具会报警告无法使用标签名当做选择器
/* #ifndef APP-NVUE */
image {
display: inline-block;
}
// 在weex也即nvue中所有元素默认为border-box
view,
text {
box-sizing: border-box;
}
/* #endif */
.u-font-xs {
font-size: 22rpx;
}
.u-font-sm {
font-size: 26rpx;
}
.u-font-md {
font-size: 28rpx;
}
.u-font-lg {
font-size: 30rpx;
}
.u-font-xl {
font-size: 34rpx;
}
.u-flex {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
}
.u-flex-wrap {
flex-wrap: wrap;
}
.u-flex-nowrap {
flex-wrap: nowrap;
}
.u-col-center {
align-items: center;
}
.u-col-top {
align-items: flex-start;
}
.u-col-bottom {
align-items: flex-end;
}
.u-row-center {
justify-content: center;
}
.u-row-left {
justify-content: flex-start;
}
.u-row-right {
justify-content: flex-end;
}
.u-row-between {
justify-content: space-between;
}
.u-row-around {
justify-content: space-around;
}
.u-text-left {
text-align: left;
}
.u-text-center {
text-align: center;
}
.u-text-right {
text-align: right;
}
.u-flex-col {
/* #ifndef APP-NVUE */
display: flex!important;
/* #endif */
flex-direction: column!important;
}
// 定义flex等分
@for $i from 0 through 12 {
.u-flex-#{$i} {
flex: $i;
}
}
// 定义字体(px)单位小于20都为px单位字体
@for $i from 9 to 20 {
.u-font-#{$i} {
font-size: $i + px;
}
}
// 定义字体(rpx)单位大于或等于20的都为rpx单位字体
@for $i from 20 through 40 {
.u-font-#{$i} {
font-size: $i + rpx;
}
}
// 定义内外边距历遍1-80
@for $i from 0 through 80 {
// 只要双数和能被5除尽的数
@if $i % 2 == 0 or $i % 5 == 0 {
// 得出u-margin-30或者u-m-30
.u-margin-#{$i}, .u-m-#{$i} {
margin: $i + rpx!important;
}
// 得出u-padding-30或者u-p-30
.u-padding-#{$i}, .u-p-#{$i} {
padding: $i + rpx!important;
}
@each $short, $long in l left, t top, r right, b bottom {
// 缩写版,结果如: u-m-l-30
// 定义外边距
.u-m-#{$short}-#{$i} {
margin-#{$long}: $i + rpx!important;
}
// 定义内边距
.u-p-#{$short}-#{$i} {
padding-#{$long}: $i + rpx!important;
}
// 完整版结果如u-margin-left-30
// 定义外边距
.u-margin-#{$long}-#{$i} {
margin-#{$long}: $i + rpx!important;
}
// 定义内边距
.u-padding-#{$long}-#{$i} {
padding-#{$long}: $i + rpx!important;
}
}
}
}
// 重置nvue的默认关于flex的样式
.u-reset-nvue {
flex-direction: row;
align-items: center;
}
/* start--文本行数限制--start */
.u-line-1 {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.u-line-2 {
-webkit-line-clamp: 2;
}
.u-line-3 {
-webkit-line-clamp: 3;
}
.u-line-4 {
-webkit-line-clamp: 4;
}
.u-line-5 {
-webkit-line-clamp: 5;
}
.u-line-2, .u-line-3, .u-line-4, .u-line-5 {
overflow: hidden;
word-break: break-all;
text-overflow: ellipsis;
display: -webkit-box; // 弹性伸缩盒
-webkit-box-orient: vertical; // 设置伸缩盒子元素排列方式
}
/* end--文本行数限制--end */
/* start--不同颜色文字--start */
.color-333{
color: #333;
}
.color-666{
color: #666;
}
.color-999{
color: #999;
}
.color-red{
color: $my-red-color;
}
.color-main{
color:$my-main-color
}
/* end--不同颜色文字--end */
.tranistion{
transition: all .3s ease-in-out;
}
.tranistion-1{
transition: all .1s ease-in-out;
}
.tranistion-2{
transition: all .2s ease-in-out;
}
.font-bold{
font-weight: 700;
}
/* start--不同颜色背景--start */
.my-bg-main{
background-color:$my-main-color
}
/* end--不同颜色背景--end */
.safe-page{
padding-bottom: 60rpx!important;
}
::v-deep .uni-switch-input.uni-switch-input-checked{
border-color: $my-main-color;
background-color: $my-main-color;
}
.min-page{
/* #ifdef H5 */
min-height: calc(100vh - 44px);
/* #endif */
/* #ifndef H5 */
min-height: 100vh;
/* #endif */
}
.w-full{
width: 100%;
}
.gap-20{
gap: 20rpx;
}
.color-000{
color: #000;
}
.color-fff{
color: #fff;
}
.bg-fff{
background-color: #fff;
}
.bg-gray{
background-color: #F9F9F9;
}
.overflow-hide{
/* #ifdef H5 */
height: calc(100vh - 44px);
/* #endif */
/* #ifndef H5 */
height: 100vh;
/* #endif */
overflow: hidden;
}
.no-wrap{
white-space: nowrap;
}
.border-r-12{
border-radius: 12rpx;
}
.border-r-18{
border-radius: 18rpx;
}
.border-top{
border-top: 1px solid #E5E5E5;
}
.border-bottom{
border-bottom: 1px solid #E5E5E5;
}
.scale7{
transform: scale(0.7);
}
.page-gray {
min-height: calc(100vh);
/* #ifdef H5 */
min-height: calc(100vh - var(--window-top));
/* #endif */
display: flex;
flex-direction: column;
background: #F9F9F9;
}
.safe-bottom{
padding-bottom: env(safe-area-inset-bottom);
/* #ifdef H5 */
padding-bottom: 28rpx;
/* #endif */
}
.position-all{
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.fixed-top{
position: fixed;
/* #ifdef H5 */
top: 44px;
/* #endif */
/* #ifndef H5 */
top: 0;
/* #endif */
left: 0;
right: 0;
}
.lh30 {
line-height: 30px;
}
.default-box-padding{
padding: 32rpx 28rpx;
}
.icon-arrow-down-fill {
width: 16rpx;
height: 10rpx;
}
.zIndex-999{
z-index: 999;
}
.icon-default-size{
width: 28rpx;
height: 28rpx;
}
::v-deep.uni-easyinput__placeholder-class{
font-size: 28rpx!important;
}
.filter-gray{
filter: grayscale(1);
}

230
commons/style/global.scss Normal file
View File

@@ -0,0 +1,230 @@
/**
* 系统级别: 全局样式
*
* @site https://www.jeequan.com
* @date 2022/11/22 07:29
*/
/** 已整理 **/
// 通用 列表页样式
.page-wrapper {
min-height: calc(100vh - 70rpx); /** 最小高度 **/
padding-bottom: 70rpx; /** 安全距离防止home条遮挡文字 **/
background-color: $v-color-bgrey; /** 全局背景灰 **/
}
// 底部 固定的按钮, 比如: 创建门店, 创建员工等按钮。
.list-footer{
height: 100rpx;
background: transparent;
.button-wrapper {
border-top: 1rpx solid rgba(0,0,0, 0.07);
background-color: rgba(252, 252, 252, 0.85);
backdrop-filter: blur(20rpx);
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: 30rpx;
}
}
/** 详情页 覆写list-item */
.list-item-by-detail {
padding: 60rpx 60rpx 10rpx 60rpx !important;
background-color: transparent !important; /** 背景透明 **/
.list-title{
color: #fff !important;
}
.list-subtitle{
color: rgba(251,252,253,0.7) !important;
}
.list-info {
image {
margin-right: 0 !important;
}
}
}
/**列表条目渲染, 比如: 头像、 主标题, **/
.list-item {
display: flex;
align-items: center;
padding: 0 40rpx;
height: 170rpx;
background-color: #FFF; /** 背景 白色 **/
image {
flex-shrink: 0;
flex-grow: 0;
width: 100rpx;
height: 100rpx;
margin-right: 30rpx;
}
.list-info {
flex: 1;
.list-title {
display: flex;
justify-content: space-between;
align-items: center;
height: 40rpx;
color: rgba(77,77,77,1);
.list-name {
width: auto;
flex: 1;
display: flex;
align-items: center;
font-size: 30rpx;
font-weight: 400;
}
}
.list-subtitle {
color: rgba(153, 153, 153, 1);
margin-top: 25rpx;
font-size: 26rpx;
font-weight: 400;
width: 430rpx;
}
}
}
/** 状态小圆点 **/
.state-dot {
display: flex;
align-items: center;
font-size: 30rpx;
font-weight: 400;
&::after {
content: '';
display: block;
margin-left: 20rpx;
width: 20rpx;
height: 20rpx;
border-radius: 50%;
}
}
/** 状态小圆点 **/
.state-dot-enable {
&::after {
background-color: #168FFF;
}
}
/** 状态小圆点 **/
.state-dot-disable {
&::after {
background-color: #D9D9D9;
}
}
/** 状态小圆点 **/
.state-dot-error {
&::after {
background-color: red;
}
}
/**
* 描述预览图, 参考: app详情
* 第一个最后一个距离上下 40rpx, 中间间距20rpx
*/
.desc-view {
.desc-view-item {
display: flex;
justify-content: space-between;
padding: 20rpx 40rpx;
font-size: 30rpx;
font-weight: 400;
.title {
color: #808080;
}
.desc {
color: #000;
}
&:first-child {
margin-top: 20rpx;
}
&:last-child {
margin-bottom: 20rpx;
}
}
}
/** 已整理 **/
//容器内部元素上下左右居中
.flex-center {
display: flex;
justify-content: center;
align-items: center;
}
// 触摸反馈样式
.touch-hover {
background-color: #f7f8fa !important ;
}
.touch-button {
opacity: 0.5;
}
/* 单行文本超出省略号 */
.single-text-beyond {
overflow: hidden; /*超出部分隐藏*/
white-space: nowrap; /*禁止换行*/
text-overflow: ellipsis; /*省略号*/
}
// 按钮背景样式
.footer-button-style {
border-top: 1rpx solid #fcfcfc;
background-color: rgba(252, 252, 252, 0.85);
backdrop-filter: blur(20rpx);
}
// 搜素框 提示语样式
.input-placeholder {
font-size: 32rpx;
color: rgba(0, 0, 0, 0.35);
}
// 表单分割线
.line {
height: 20rpx;
background-color: $v-color-bgrey;
}
/**
* jeepay-btn 通用btn样式。
* 用法: <button class='jeepay-btn' hover-class="hover-button" @tap="loginFunc">登录</button>
*/
.jeepay-btn {
display: flex;
justify-content: center;
align-items: center;
height: 110rpx;
font-size: 33rpx;
font-weight: 500;
color: $J-color-tff;
border-radius: 20rpx;
background: linear-gradient(270deg, rgba(35,143,252,1) 0%, rgba(26,102,255,1) 100%);
box-shadow: 0 20rpx 60rpx -20rpx rgba(0,84,210,0.5);
&.hover-button {
opacity: 0.5;
}
}
/** 输入框icon **/
.input-icon{
width: 36rpx;
height: 36rpx;
}

View File

@@ -0,0 +1,181 @@
/**
* 系统级别:覆写 uni样式
*
* @site https://www.jeequan.com
* @date 2022/11/22 07:29
*/
/* 去除开关右侧边距 */
.uni-switch-input {
margin-right: 0 !important;
}
/* .uni-navbar {
position: relative;
z-index: 10;
} */
.uni-popup{
z-index: 998 !important;
}
// 表单组件样式 覆写
.uni-forms-item {
display: flex;
align-items: center;
min-height: 120rpx;
background-color: $J-bg-ff;
font-size: 32rpx;
font-weight: 400;
}
.uni-forms-item ::v-deep .uni-forms-item__label {
font-size: 32rpx !important;
font-weight: 400;
text-indent: 40rpx;
color: #4d4d4d;
height: auto !important;
}
// uni-form-item 表单校验, 如果校验不通过, 显示的文字占位, 并且添加下边距。
.uni-forms-item__error.msg--active{
position: relative !important;
margin-bottom: 30rpx;
}
.is-input-error-border .uni-easyinput__placeholder-class{
color: #f56c6c !important
}
// 去掉按钮边框
button:after {
border: none !important;
}
// 去点导航栏组件center&right
::v-deep.uni-navbar__header {
.uni-navbar__header-container,
.uni-navbar__header-btns-right {
display: none !important;
}
}
// 修改 uuni-easyinput
// form 外层必须包裹一个 view class="jeepay-form"
.jeepay-form {
.uni-easyinput {
.uni-easyinput__content {
border: 2px solid transparent !important;
height: 110rpx;
padding: 0 30rpx;
margin-bottom: 50rpx;
box-sizing: border-box !important;
border-radius: 20rpx !important;
background-color: rgba(247, 247, 247, 1) !important;
}
.uni-easyinput__content-input {
color: rgba(0, 0, 0, 1);
font-size: 32rpx !important;
font-weight: 400;
}
.is-foucs {
border: 2px solid #1d79fd !important;
background-color: white !important;
}
.uni-input-placeholder
/* #ifdef MP-WEIXIN */
,.uni-easyinput__placeholder-class
/* #endif */ {
font-size: 32rpx !important;
color: #B3B3B3 !important;
}
}
}
.jeepay-edit-form .uni-easyinput__content-input {
padding-left: 0 !important;
.uni-input-placeholder {
font-size: 32rpx !important;
}
}
// 设置新密码覆盖form默认样式
.new-password {
.uni-forms-item.is-direction-left {
padding: 0 40rpx;
.uni-forms-item__label {
width: 190rpx !important;
font-size: 32rpx !important;
font-weight: 400;
white-space: nowrap;
color: rgba(102, 102, 102, 1);
text-indent: 0 !important;
}
.uni-easyinput__placeholder-class {
font-size: 32rpx !important;
font-weight: 400 !important;
}
}
}
// 搜索栏覆盖默认样式
/* #ifdef MP-WEIXIN */
.input-main {
button {
font-size: 32rpx;
color: rgba(29,121,253,1);
background: rgba(255,255,255,1);
}
.uni-easyinput {
.uni-easyinput__content {
background-color: $J-bg-f5 !important;
border-radius: $J-b-r12;
.uni-easyinput__content-input {
padding-left: 0 !important;
.uni-input-input {
border-radius: $J-b-r12 !important;
overflow: hidden !important;
}
}
.uni-input-placeholder {
font-size: 27rpx;
}
.uni-icons {
color: rgba(230,230,230,1) !important;
}
}
}
}
/* #endif */
// 搜索栏覆盖默认样式
/* #ifdef MP-WEIXIN */
button[is="components/Button/Button"] {
padding: 0;
background-color: transparent !important;
}
/* #endif */
// 修改时间选择器按钮颜色
.xp-button--confirm {
background: $jeepay-bg-primary;
}
.xp-button--cancel {
color: rgba(0, 0, 0, 0.5) !important;
}
// label 样式
.f-label{
width: 280rpx;
align-self: start;
padding-top: 40rpx;
font-size: 32rpx ;
font-weight: 400;
text-indent: 40rpx;
color: #4d4d4d;
}

77
commons/style/vars.scss Normal file
View File

@@ -0,0 +1,77 @@
/**
* 系统级别: 自定义变量
*
* @site https://www.jeequan.com
* @date 2022/11/22 07:29
*/
// $v : 表示: variables简写。 uni的默认都有特殊开头 一般不会重复。
$v-color-t21: #217dfe;
// 全局通用: 背景灰 background grey
$v-color-bgrey: #F7F7F7;
// 背景色
$J-bg-f7: #f7f7f7; //页面背景色
$J-bg-ff: #fff;
$J-bg-f5: #f5f5f5; //输入框背景色
// 文字颜色
$J-color-t80: #808080; //常用于 未选中文字颜色
$J-color-t21: #217dfe; //卡片文字选中 统计报表
$J-color-tff: #fff;
$J-color-tSff: rgba(255, 255, 255, 0.7);
$J-color-t29: #2980fd; //选中 文字颜色 搜索
$J-color-ta6: #a6a6a6;
$J-color-t4d: #4d4d4d; //标题颜色
$J-color-t99: #999;
$J-color-t8c: #8c8c8c; // 卡片列表 标题文字颜色
//圆角相关变量
$J-b-r32: 32rpx;
$J-b-r12: 12rpx;
$J-b-r10: 10rpx;
$v-b-r20: 20rpx;
// 文字大小
$J-f-size30: 30rpx;
// 常用边框颜色
$v-b-color-ed: #ededed;
//common.scss 分包页面以及组件里所用的颜色
$my-main-color:#318AFE;
$my-red-color:#F02C45;
//my-components
$u-main-color: #303133;
$u-content-color: #606266;
$u-tips-color: #909193;
$u-light-color: #c0c4cc;
$u-border-color: #dadbde;
$u-bg-color: #f3f4f6;
$u-disabled-color: #c8c9cc;
$u-primary: #3c9cff;
$u-primary-dark: #398ade;
$u-primary-disabled: #9acafc;
$u-primary-light: #ecf5ff;
$u-warning: #f9ae3d;
$u-warning-dark: #f1a532;
$u-warning-disabled: #f9d39b;
$u-warning-light: #fdf6ec;
$u-success: #5ac725;
$u-success-dark: #53c21d;
$u-success-disabled: #a9e08f;
$u-success-light: #f5fff0;
$u-error: #f56c6c;
$u-error-dark: #e45656;
$u-error-disabled: #f7b2b2;
$u-error-light: #fef0f0;
$u-info: #909399;
$u-info-dark: #767a82;
$u-info-disabled: #c4c6c9;
$u-info-light: #f4f4f5;

37
commons/utils/cal.js Normal file
View File

@@ -0,0 +1,37 @@
/**
* 数字, 计算相关函数
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2022/11/22 10:38
*/
/**
* 保留小数n位不进行四舍五入
* num你传递过来的数字,
* decimal你保留的几位,默认保留小数后两位
*/
const formatDecimal = function(num, decimal = 2) {
num = num.toString()
const index = num.indexOf('.')
if (index !== -1) {
num = num.substring(0, decimal + index + 1)
} else {
num = num.substring(0)
}
//截取后保留两位小数
return parseFloat(num).toFixed(decimal)
}
const model = {
// 分转元
// amount - 金额 parseFloat - 是否转换为数字格式, 默认String
cert2Dollar(amount, needParseFloat = false) {
if (needParseFloat) { // parseFlot
return formatDecimal(amount / 100)
}
return formatDecimal(amount / 100)
}
}
export default model

38
commons/utils/dataKit.js Normal file
View File

@@ -0,0 +1,38 @@
/**
* 数据 工具类
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2022/11/30 14:18
*/
const model = {
// 递归遍历树状结构数据 matchFunc 匹配结果, true表示匹配成功 否则继续匹配。
// pnode 可不传入
// 返回结构: [当前数据, 上级数据 ]
recursionTreeData: (treeData, matchFunc, childrenName = 'children', pnode = null ) => {
for (let i = 0; i < treeData.length; i++) {
const item = treeData[i]
// 匹配成功
if(matchFunc(item)){
return [item, pnode]
}
if (item[childrenName] && item[childrenName].length > 0) {
let res = model.recursionTreeData(item[childrenName], matchFunc, childrenName, item)
if(res){
return res
}
}
}
}
}
export default model

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}
}

101
commons/utils/formUtil.js Normal file
View File

@@ -0,0 +1,101 @@
/**
* form 验证 工具类
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2022/11/25 10:58
*/
import infoBox from '@/commons/utils/infoBox.js'
const model = {
// 正则表达式
regexp: {
// 手机号验证规则
mobile: /^1\d{10}$/,
// 登录用户名: 字母开头 6 -18位。
loginUsername: /^[a-zA-Z][a-zA-Z0-9]{5,17}$/,
},
// 验证规则:
rules: {
// showText 为空, 说明是 input的placeHoloder 直接飘红,
// showText 有值: 在文本框下方提示。
// 只有input 才有这种特殊判断。
requiredInput: (showText, type = 'string') => {
return {format: type, required: true, errorMessage: showText ? ('请输入' + showText) : ' ' }
},
requiredSelect: (showText, type = 'string') => {
return {format: type, required: true, errorMessage: '请选择' + showText }
},
requiredUpload: (showText, type = 'string') => {
return {format: type, required: true, errorMessage: '请上传' + showText }
},
// 正则验证 请注意: 该规则需要在required后面 此处不可包含required
patternRule: (showText, p) => {
return {pattern: p, errorMessage: '请输入正确的' + showText }
},
requiredInputShowToast: (showText, type = 'string') => {
return {format: type, required: true, errorMessage:' ', toastErrorMessage: '请输入' + showText }
},
requiredSelectShowToast: (showText, type = 'string') => {
return {format: type, required: true, errorMessage:' ', toastErrorMessage: '请选择' + showText }
},
requiredUploadShowToast: (showText, type = 'string') => {
return {format: type, required: true, errorMessage:' ', toastErrorMessage: '请上传' + showText }
},
patternRuleShowToast: (showText, p) => {
return {pattern: p, errorMessage:' ', toastErrorMessage: '请输入正确的' + showText }
},
},
// 支持 提示信息
// 类型如下:
// {
// required: true,
// toastErrorMessage: "请输入去去去去群",
// errorMessage: ' ', // 不会显示在下部, 需要空格占位
// }
validate: (form) => {
return form.validate().catch(e => {
if(!e || e.length <= 0){
return Promise.reject()
}
for(let i = 0; i < e.length; i++){
let k = e[i].key
let rules = form.rules[k].rules
for(let j = 0; j < rules.length; j++){
if(rules[j].toastErrorMessage && rules[j].required){
infoBox.showToast(rules[j].toastErrorMessage) // 仅提示一次即可
return Promise.reject(e)
}
}
}
return Promise.reject(e)
})
},
}
export default model

54
commons/utils/format.js Normal file
View File

@@ -0,0 +1,54 @@
/**
* 格式化价格函数,将价格限定在指定的最小值和最大值范围内,并保留两位小数。
*
* @param {number} price - 需要格式化的价格。
* @param {number} min - 价格的最小值。
* @param {number} max - 价格的最大值默认为100000000。
* @param {Boolean} returnIsArea - 是否返回值符合范围区间默认为false。
* @returns {number} - 返回格式化后的价格,如果超出范围则返回最小值或最大值。
*/
export const formatPrice = (price,min=-Infinity, max = 100000000,returnIsArea=false ) => {
if(price === undefined || price === null||price===''){
return 0
}
// 将价格转换为浮点数并保留两位小数
const newval = parseFloat((Math.floor(price * 100) / 100).toFixed(2))
// 如果价格大于最大值,返回最大值
if (newval > max) {
return returnIsArea?{value:max,error:true}:max
}
// 如果价格小于最小值,返回最小值
if (newval < min) {
return returnIsArea?{value:min,error:true}:min
}
// 如果价格小于最小值,返回最小值
if (newval < min) {
return min
}
// 返回格式化后的价格
return newval
}
export function returnReverseVal(val, isReturnString = true) {
const isBol = typeof val === "boolean";
const isString = typeof val === "string";
let reverseNewval = "";
if (isBol) {
reverseNewval = !val;
}
if (isString) {
reverseNewval = val === "true" ? "false" : "true";
}
return reverseNewval;
}
export function returnBoolean(val) {
const isBol = typeof val === "boolean";
const isString = typeof val === "string";
let newval = "";
if (isBol) {
newval = val;
}
if (isString) {
newval = val === "true" ? true : false;
}
return newval;
}

View File

@@ -0,0 +1,32 @@
function getDayArea(date = new Date(), type) {
const now = date
if (type === 'start') {
const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate());
return startOfDay
}
if (type === 'end') {
const endOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999);
return endOfDay;
}
return `${startOfDay}-${endOfDay}`
}
function getMonthArea(date = new Date(), type) {
let now = date
let currentMonthStart = new Date(now.getFullYear(), now.getMonth(), 1);
let currentMonthEnd = new Date(now.getFullYear(), now.getMonth() + 1, 0 , 23, 59, 59, 999);
if (type === 'start') {
return currentMonthStart
}
if (type === 'end') {
return currentMonthEnd;
}
return {
start: currentMonthStart,
end: currentMonthEnd
};
}
export default {
getDayArea, getMonthArea
}

View File

@@ -0,0 +1,13 @@
/**
* 获取url链接参数
* @param {Object} url
* @param {Object} name
*/
export function getQueryString(url, name) {
var reg = new RegExp('(^|&|/?)' + name + '=([^&|/?]*)(&|/?|$)', 'i')
var r = url.substr(1).match(reg)
if (r != null) {
return r[2]
}
return null;
}

62
commons/utils/infoBox.js Normal file
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

View File

@@ -0,0 +1,143 @@
import { $getBaiduToken } from '@/http/apiManager.js';
const audioTeam = [];
let audioStartSwitch = false;
const getAudioUrl = 'https://tsn.baidu.com/text2audio';
export default function openVoice(objs) { // 传入需转为语音的文本内容
let lineUp = false;
let returnAudio = false;
if (typeof(objs) !== 'string') {
if (objs && objs.lineUp === true) {
lineUp = true;
}
if (objs && objs.returnAudio === true) {
returnAudio = true;
}
}
if(returnAudio) {
return new Promise((resolve, reject)=>{
openVoiceFc(objs, returnAudio).then(res=>{
resolve(res);
}).catch(err=>{
reject(err)
});
})
}
if (!audioStartSwitch || lineUp) {
audioStartSwitch = true;
openVoiceFc(objs);
} else {
audioTeam.push(objs);
}
}
function openVoiceFc(objs, returnAudio) {
if(returnAudio) {
return new Promise((resolve, reject)=>{
$getBaiduToken().then(({bizData}) => {
if (bizData) {
resolve(tts(objs, bizData, returnAudio));
} else {
reject('获取语音tok接口为空');
}
})
})
}else{
$getBaiduToken().then(({bizData}) => {
if (bizData) {
tts(objs, bizData);
} else {
}
})
}
}
function tts(objs, tok, returnAudio) {
if(typeof(objs)=='string')
objs = {voiceSet: {tex: objs}};
const data = {
tok,
cuid: tok,
ctp: 1,
lan: 'zh',
...objs.voiceSet
}
if(returnAudio)
return btts( data, objs.audioSet, objs.audioCallback, objs.lineUp, returnAudio);
btts( data, objs.audioSet, objs.audioCallback, objs.lineUp, returnAudio);
}
function setAudioSet(options, audio) {
if (options) {
audio.volume = options.volume || 1;
audio.startTime = options.startTime || 0;
audio.loop = options.loop || false;
audio.obeyMuteSwitch = options.obeyMuteSwitch && typeof(options.obeyMuteSwitch) == 'boolean' ? options.obeyMuteSwitch :
true; //支持微信小程序、百度小程序、头条小程序
}
}
function btts(param, options, audioCallback, lineUp, returnAudio) {
let audio = uni.createInnerAudioContext();
setAudioSet(options, audio);
// 序列化参数列表
let fd = [];
for (let k in param) {
fd.push(k + '=' + encodeURIComponent(encodeURIComponent(param[k])));
}
audio.src = `${getAudioUrl}?${fd.join('&')}`;
if(returnAudio) {
audio.onEnded(() => {
audio.destroy(); //销毁音频实例
audio = null;
})
audio.onError((e)=>{
if (audioCallback && audioCallback.onError && typeof(audioCallback.onError) == 'function') audioCallback.onError(e);
audio.destroy(); //销毁音频实例
audio = null;
})
return audio;
}
audio.onPlay(() => {
if (audioCallback && audioCallback.onPlay && typeof(audioCallback.onPlay) == 'function') audioCallback.onPlay();
})
audio.onPause(()=>{
if (audioCallback && audioCallback.onPause && typeof(audioCallback.onPause) == 'function') audioCallback.onPause();
})
audio.onWaiting(()=>{
if (audioCallback && audioCallback.onWaiting && typeof(audioCallback.onWaiting) == 'function') audioCallback.onWaiting();
})
audio.onStop(()=>{
if (audioCallback && audioCallback.onStop && typeof(audioCallback.onStop) == 'function') audioCallback.onStop();
})
audio.onTimeUpdate(()=>{
if (audioCallback && audioCallback.onTimeUpdate && typeof(audioCallback.onTimeUpdate) == 'function') audioCallback.onTimeUpdate();
})
audio.onSeeking(()=>{
if (audioCallback && audioCallback.onSeeking && typeof(audioCallback.onSeeking) == 'function') audioCallback.onSeeking();
})
audio.onSeeked(()=>{
if (audioCallback && audioCallback.onSeeked && typeof(audioCallback.onSeeked) == 'function') audioCallback.onSeeked();
})
audio.onEnded(() => {
audio.destroy(); //销毁音频实例
audio = null;
if (audioCallback && audioCallback.onEnded && typeof(audioCallback.onEnded) == 'function') audioCallback.onEnded();
if (lineUp !== false) {
if (audioTeam.length > 0) {
openVoiceFc(audioTeam[0]);
audioTeam.splice(0, 1);
} else {
audioStartSwitch = false;
}
}
})
audio.onError((e)=>{
if (audioCallback && audioCallback.onError && typeof(audioCallback.onError) == 'function') audioCallback.onError(e);
audio.destroy(); //销毁音频实例
audio = null;
})
audio.play();
}

View File

@@ -0,0 +1,71 @@
import storageManage from '@/commons/utils/storageManage.js'
import dayjs from 'dayjs'
import baiduyy from './QS-baiduyy.js'; // 百度语音合成
// #ifdef MP-WEIXIN
import wxTextToSpeach from './wxTextToSpeach.js'; // 微信小程序插件语音合成
// #endif
const model = {
// 监听推送通知
addPushMsgEventListener: function(){
console.log("监听推送")
// #ifdef APP-PLUS
// unipush1.0监听消息
if(plus && plus.push) {
plus.push.addEventListener('receive', model.handlePush)
}
// #endif
// unipush2.0监听消息
model.uniPushListener2()
},
// uniPush2.0 接收推送消息
uniPushListener2: function() {
uni.onPushMessage((res) => {
console.log("uniPush2.0 收到推送消息:", res.data) //监听推送消息
model.handlePush(res.data)
})
},
// 语音播报
handlePush: function(message) {
// 没有token信息
if(!storageManage.token()){
return false;
}
// 信息不存在
if(!message || !message.content) {
return false;
}
const content = JSON.parse(message.content)
console.log("消息内容:", content)
// 支付成功
if (content && content.type == 'paySuccess') {
// 在过期时间之内, 则调起语音播报。
if( dayjs(content.expiredTime).isAfter(dayjs()) ){
console.log('执行消息播报');
// #ifdef MP-WEIXIN
wxTextToSpeach(content.msg)
// #endif
// #ifndef MP-WEIXIN
baiduyy(content.msg)
// #endif
uni.vibrateLong({});
}
}
}
}
export default model

View File

@@ -0,0 +1,50 @@
import {
$pushInfoRegister
} from '@/http/apiManager.js'
import storageManage from '@/commons/utils/storageManage.js'
// 默认导出 方法 注册 push连接
export default async function() {
let cid1 = undefined // unipush1.0 客户端CID
let cid2 = undefined // unipush2.0 客户端CID
let orgCid = undefined // 原始cid如果获取的cid和新的cid不相同赋值原始cid后端会根据原始cid更新
let cidType = undefined //传递类型 是 app 还是 微信
// #ifdef APP-PLUS
cidType = 'app_plus'
// #endif
// #ifdef MP-WEIXIN
cidType = 'mp_weixin'
// #endif
// #ifdef APP-PLUS
if (!plus) {
cid1 = plus.push.getClientInfo().clientid
}
// #endif
const data = await uni.getPushClientId()
console.log('客户端推送标识:', data.cid)
cid2 = data.cid
// 如果不存 cid 本地存储 写入 cid
if (!storageManage.uniPush2Cid()) {
storageManage.uniPush2Cid(data.cid)
} else if (cid2 !== storageManage.uniPush2Cid()) { // 否则进行 cid 对比 判断 是否相等 不相等 赋值 orgCid
orgCid = storageManage.uniPush2Cid() //赋值原始cid
storageManage.uniPush2Cid(data.cid) //重新写入 cid
}
if (cid1) {
pushInfoRegister(cid1)
} else {
pushInfoRegister(cid1, cid2, orgCid, cidType)
}
function pushInfoRegister(cid1 = '', cid2 = '', org = '', cidType = '') {
$pushInfoRegister({
cid1,
cid2,
orgCid: org,
cidType
}).then(res => {
orgCid = '' //重置 数据
})
}
}

View File

@@ -0,0 +1,87 @@
import { $mchConfig } from "@/http/apiManager"
import storageManage from '@/commons/utils/storageManage.js'
let num = 0 //计算错误此时 超过5次错误 不在出触发
const plugin = requirePlugin("WechatSI")
const pushMsgArr = [] //维护一个消息队列
let backgroundAudioManager = undefined //获取背景音频实例
let audioMp3 = ''
console.log('执行创建 语音播报逻辑');
// 获取配置项 判断是否 开启 小程序 语音推送
export function getPushStatus () {
if (!storageManage.token()) return //未登录 不播放
$mchConfig('orderConfig').then(({ bizData = [] }) => {
const weChat = bizData.find(v => v.configKey == "weChatVoice")
if (weChat && weChat?.configVal == 1) {
createBgMusice()
}
})
}
// getPushStatus()
// 创建 背景音乐
function createBgMusice (file) {
backgroundAudioManager = wx.getBackgroundAudioManager()
backgroundAudioManager.title = '订单通知'
if (!audioMp3) {
createFile()
} else {
backgroundAudioManager.src = audioMp3
}
// 监听 音频播放失败事件
backgroundAudioManager.onError(function (res) {
console.log('音频播放失败', res, num);
if (num >= 5) return
createFile()
num++
})
// 监听 音频播放结束事件
onBgMusiceEnd()
}
// 监听bei背景音乐播放状态
export function onBgMusiceEnd () {
backgroundAudioManager.onEnded(() => {
if (pushMsgArr.length > 0) return broadcast(pushMsgArr.pop()) //如果有消息 则继续播放
backgroundAudioManager.src = audioMp3 //否则播放默认背景音乐
})
}
export function startOrEndMusice (flag) {
if (!flag && !!backgroundAudioManager) return backgroundAudioManager.stop() //关闭背景音乐 地址指向空即可
if (!backgroundAudioManager) return createBgMusice() // 如果一开始是关闭状态 则创建背景音乐实例
backgroundAudioManager.src = audioMp3 // 否则重新赋值背景音地址即可
}
export default function (message) {
if (!backgroundAudioManager) return
pushMsgArr.unshift(message) //将消息添加到消息队列头部 背景音乐播放结束后 会对消息队列 进行校验 如果消息队列有消息 会进行播放 否则继续循环背景音乐
}
// 播放订单
function broadcast (msg) {
plugin.textToSpeech({
lang: "zh_CN",
tts: true,
content: msg,
success: function (res) {
backgroundAudioManager.src = res.filename;
onBgMusiceEnd()
},
fail: function (res) {
console.log("fail tts", res)
}
})
}
// 创建文件
export function createFile (file) {
const fs = wx.getFileSystemManager()
fs.copyFile({
srcPath: `static/noiseless.mp3`,
destPath: `${wx.env.USER_DATA_PATH}/noiseless.mp3`,
success (res) {
console.log(res, `${wx.env.USER_DATA_PATH}/noiseless.mp3`)
audioMp3 = `${wx.env.USER_DATA_PATH}/noiseless.mp3`
backgroundAudioManager.src = audioMp3
},
fail (res) {
console.error(res)
}
})
}

View File

@@ -0,0 +1,10 @@
创建 云空间 上传云函数 云函数 url化 运营平台 配置云函数地址
打包时 勾选云push 2.0 push1.0 仅支持 app 推送
注意配置 百度语音相关参数
使用push2.0 请将 static\noiseless.mp3 文件 配置到运营平台 系统 配置 通知配置 push2.0 uniPush语音播报音频文件(小程序播报必填) 下
注意扩展库依赖3张opendb表opendb-tempdata,opendb-device,uni-id-device。公测版uniCloud执行扩展库会自动创建。如果你使用的是uniCloud正式版需要自己创建这3张表。

View File

@@ -0,0 +1,202 @@
/**
* 存储管理对象
* 目标:将现有系统的所有需要存储的数据,统一管理
*
* @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 = {
setLogin(res){
uni.setStorageSync('logoutHandle',false)
uni.setStorageSync('shopId', res.shopId)
uni.setStorageSync('shopName',res.shopName)
uni.setStorageSync('logo',res.logo)
uni.setStorageSync('loginType',res.loginType)
},
// 退出清空所有的缓存数据。 (不包含 环境相关)
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
}
},
// 获取和放置shopId
shopId: (val, isDelete = false) => {
if (isDelete) {
appCache.shopId = ""
return uni.removeStorageSync('shopId')
}
if (val) {
// 有值,为放置
appCache.shopId = val
uni.setStorageSync('shopId', val)
} else {
// 否则为获取
if (!appCache.shopId) {
//缓存取不到,获取应用本地信息
appCache.shopId = uni.getStorageSync('shopId')
}
return appCache.shopId
}
},
// 已经登录的用户记录
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, // 用户类型
mchNo: currentUserInfo.userNo, // 商户No
mchShortName: currentUserInfo.shortName, // 商户简称
mchType: currentUserInfo.mchType, // 商户类型
mchLevel: currentUserInfo.mchLevel, // 商户级别
isHasMemberEnt:currentUserInfo.isHasMemberEnt,// 是否购买会员模块
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)
},
// push 状态是否开启
pushIsOpen: (pushFlag) => {
if (pushFlag) {
uni.setStorageSync('pushFlag', pushFlag) // 改变存储
}
return uni.getStorageSync('pushFlag')
},
// 网站信息
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")
},
uploadImgSize: (uploadImgSize) => {
if (uploadImgSize) {
uni.setStorageSync("uploadImgSize", uploadImgSize) // 存储 上传 图片大小限制
}
return uni.getStorageSync("uploadImgSize")
},
}
export default model