first commit

This commit is contained in:
whitechiina 2025-11-25 11:21:13 +08:00
commit db4a95e35d
45 changed files with 5716 additions and 0 deletions

17
App.vue Normal file
View File

@ -0,0 +1,17 @@
<script>
export default {
onLaunch: function() {
console.log('App Launch')
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style>
/*每个页面公共css */
</style>

90
api/index.js Normal file
View File

@ -0,0 +1,90 @@
import request from "@/utils/request.js";
// 推送播报
export function cancelPaymentSoundAPI(data) {
return request.get('MiniProgram/Order/cancelPaymentSound', data);
}
// 取消发声
export function cancelPay(data) {
return request.post('/api/gzh/cancelPay', data);
}
// 获取商户信息
export function getMerchantAPI(data) {
return request.get('MiniProgram/Api/getMerchant', data);
}
// 获取用户信息
export function userInfoAPI(data) {
return request.get('MiniProgram/Api/userInfo', data);
}
// 支付
export function createScanOrderAPI(data) {
return request.get('MiniProgram/Api/submitOrder', data);
}
// 发送验证码
export function sendSmsAPI(data) {
return request.get('MiniProgram/Api/sendSms', data);
}
// 绑定手机号
export function bindPhoneAPI(data) {
return request.get('MiniProgram/Api/bindPhone', data);
}
// 商户端支付
export function againPayAPI(data) {
return request.get('client/mall/againPay', data);
}
// 订单详情?
export function orderDetailAPI(data) {
return request.get('MiniProgram/Api/orderDetail', data);
}
// code查店铺
export function getMerchantInfoByCode(data) {
return request.post('/api/gzh/getMerchantInfoByCode', data);
}
// id查店铺
export function getMerchantInfo(data) {
return request.post('/api/gzh/getMerchantInfo', data);
}
// 下单 1
export function doOrder(data) {
return request.post('/api/merchant/doOrder', data);
}
// 下单 0
export function dogzhOrder(data) {
return request.post('/api/gzh/doOrder', data);
}
// 券 1
export function computedOrder(data) {
return request.post('/api/merchant/computedOrder', data);
}
// 券 0
export function gzhcomputedOrder(data) {
return request.post('/api/gzh/computedOrder', data);
}
// 支付宝订单号查询 1
export function getOfflineOrderDetail(data) {
return request.post('/api/merchant/getOfflineOrderDetail', data);
}
// 支付宝订单号查询 0
export function getgzhlineOrderDetail(data) {
return request.post('/api/gzh/getOfflineOrderDetail', data);
}

448
api/order.js Normal file
View File

@ -0,0 +1,448 @@
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
import request from "@/utils/request.js";
/**
* 获取购物车列表
* @param numType boolean true 购物车数量,false=购物车产品数量
*/
export function getCartCounts(numType) {
return request.get("cart/count", {
numType: numType === undefined ? 0 : numType
});
}
/**
* 获取购物车列表
*
*/
export function getCartList(data) {
return request.get("cart/list", data);
}
/**
* 修改购物车
*
*/
export function getResetCart(data) {
return request.post("v2/reset_cart", data);
}
/**
* 修改购物车数量
* @param int cartId 购物车id
* @param int number 修改数量
*/
export function changeCartNum(cartId, number) {
return request.post("cart/num", {
id: cartId,
number: number
});
}
/**
* 清除购物车
* @param object ids join(',') 切割成字符串
*/
export function cartDel(ids) {
if (typeof ids === 'object')
ids = ids.join(',');
return request.post('cart/del', {
ids: ids
});
}
/**
* 订单列表
* @param object data
*/
export function getOrderList(data) {
return request.get('order/list', data);
}
/**
* 订单产品信息
* @param string unique
*/
export function orderProduct(unique) {
return request.post('order/product', {
unique: unique
});
}
/**
* 订单评价
* @param object data
*
*/
export function orderComment(data) {
return request.post('order/comment', data);
}
/**
* 订单支付
* @param object data
*/
export function orderPay(data) {
return request.post('/api/order/pay', data);
}
/**
* 删除已退款和拒绝退款的订单
* @param string uni
*
*/
export function refundOrderDel(uni) {
return request.get('order/refund/del/' + uni, {});
}
/**
* 订单统计数据
*/
export function orderData() {
return request.get('order/data')
}
/**
* 订单取消
* @param string id
*
*/
export function orderCancel(id) {
return request.post('mall/api/cancel_order', {
order_id: id
});
}
/**
* 删除已完成订单
* @param string uni
*
*/
export function orderDel(uni) {
return request.post('order/del', {
uni: uni
});
}
/**
* 订单详情
* @param string uni
*/
export function getOrderDetail(uni, cart_id) {
return request.get('order/detail/' + uni + `${cart_id ? `/${cart_id}`:''}`);
}
/**
* 退款订单详情
* @param string uni
*/
export function getRefundOrderDetail(uni, cart_id) {
return request.get('order/refund_detail/' + uni + `${cart_id ? `/${cart_id}`:''}`);
}
/**
* 再次下单
* @param string uni
*
*/
export function orderAgain(uni) {
return request.post('order/again', {
uni: uni
});
}
/**
* 订单收货
* @param string uni
*
*/
export function orderTake(uni) {
return request.post('order/take', {
uni: uni
});
}
/**
* 订单查询物流信息
* @returns {*}
*/
export function express(uni, type) {
return request.get("order/express/" + uni + `${type?'/refund':''}`);
}
/**
* 订单查询物流信息
* @returns {*}
*/
export function adminExpress(uni, type) {
return request.get("admin/order/express/" + uni + `${type?'/refund':''}`);
}
/**
* 获取退款理由
*
*/
export function ordeRefundReason() {
return request.get('order/refund/reason');
}
/**
* 订单退款审核
* @param object data
*/
export function orderRefundVerify(data) {
return request.post('order/refund/verify', data);
}
/**
* 订单确认获取订单详细信息
* @param string cartId
*/
export function orderConfirm(cartId, news, addressId, shipping_type) {
return request.post('order/confirm', {
cartId,
'new': news,
addressId,
shipping_type
});
}
/**
* 获取确认订单页面是否展示快递配送和到店自提
* @param string cartId
*/
export function checkShipping(cartId, news) {
return request.post('order/check_shipping', {
cartId,
'new': news
});
}
/**
* 获取当前金额能使用的优惠卷
* @param string price
*
*/
export function getCouponsOrderPrice(price, data) {
return request.get('coupons/order/' + price, data)
}
/**
* 订单创建
* @param string key
* @param object data
*
*/
export function orderCreate(key, data) {
return request.post('order/create/' + key, data);
}
/**
* 计算订单金额
* @param key
* @param data
* @returns {*}
*/
export function postOrderComputed(key, data) {
return request.post("order/computed/" + key, data);
}
/**
* 订单优惠券
* @param key
* @param data
* @returns {*}
*/
export function orderCoupon(orderId) {
return request.post("v2/order/product_coupon/" + orderId);
}
/**
* 计算会员线下付款金额
* @param {Object} data
*/
export function offlineCheckPrice(data) {
return request.post("order/offline/check/price", data);
}
/**
* 线下扫码付款
* @param {Object} data
*/
export function offlineCreate(data) {
return request.post("order/offline/create", data);
}
/**
* 支付方式开关
*/
export function orderOfflinePayType() {
return request.get('order/offline/pay/type');
}
/**
* 开票记录
*/
export function orderInvoiceList(data) {
return request.get('v2/order/invoice_list', data);
}
/**
* 开票订单详情
* @param {Object} id
*/
export function orderInvoiceDetail(id) {
return request.get(`v2/order/invoice_detail/${id}`);
}
/**
* 支付宝支付
* @param {Object} key
* @param {Object} quitUrl
*/
export function aliPay(key, quitUrl) {
return request.get('ali_pay', {
key,
quitUrl
}, {
noAuth: true
});
}
/**
* 退货物流单号提交
* @param {Object} data
*/
export function refundExpress(data) {
return request.post("order/refund/express", data);
}
/**
* 分类购物车列表
*/
export function vcartList() {
return request.get("v2/cart_list");
}
/**
* 退款商品列表
*/
export function refundGoodsList(orderId) {
return request.get(`order/refund/cart_info/${orderId}`);
}
/**
* 申请退款商品列表
*/
export function postRefundGoods(data) {
return request.post(`order/refund/cart_info`, data);
}
/**
* 退款商品提交
*/
export function returnGoodsSubmit(id, data) {
return request.post(`order/refund/apply/${id}`, data);
}
/**
* 新订单列表 2.1版本
* @param object data
*/
export function getNewOrderList(data) {
return request.get('order/refund/list', data);
}
/**
* 退款订单详情
* @param string uni
*/
export function refundOrderDetail(uni) {
return request.get('order/refund/detail/' + uni);
}
/**
* 放弃申请退款
* @param string uni
*/
export function cancelRefundOrder(uni) {
return request.post('order/refund/cancel/' + uni);
}
/**
* 收银台订单信息
* @param object data
*/
export function getCashierOrder(orderId, type) {
return request.get(`/api/order/cashier/${orderId}/${type}`);
}
/**
* 发票地址获取
* @param object data
*/
export function getInvoiceLink(id) {
return request.get(`v2/order/down_invoice/${id}`);
}
/**
* 点餐取消订单
* @param string data
*/
export function cancelShopOrder(data) {
return request.post('merchant_order/order/cancelOrder', data);
}
// /**
// * 线上商品取消订单
// * @param string data
// */
// export function cancelonlineOrder(data) {
// return request.post('/mall/api/cancel_order', data);
// }
/**
* 点餐扫码订单详情
* @param string data
*/
export function getOrderShopDetail(id) {
return request.get(`merchant/getOrderDetail?id=${id}`);
}
/**
* 线上订单详情
* @param string data
*/
export function getonlineOrderDetail(id) {
return request.get(`order/detail/${id}`);
}
/**
* 充值订单详情
* @param string data
*/
export function RechargeOrderDetail(id) {
return request.get(`virtual/orderDetail?id=${id}`);
}
/**
* 充值订单取消
*/
export function RechargeorderCancel(data) {
return request.post('virtual/cancelOrder', data);
}
/**
* 获取订单顶部Tabs
*/
export function OrderTabs(data) {
return request.get('order_tab_config', data);
}

11
api/public.js Normal file
View File

@ -0,0 +1,11 @@
import request from "@/utils/request.js";
/**
* 配置信息
*
*/
export function basicConfig(name) {
return request.get(`/api/basic_config`, {}, {
noAuth: true
});
}

573
components/OnlineShop.vue Normal file
View File

@ -0,0 +1,573 @@
<!-- 统一收银台支付 -->
<template>
<view class="page">
<view class="pay-price">
<view class="price">
<text class="unit"></text>
<view v-if="fromType == 'order'">
<numberScroll :num='payPriceShow' color="#E93323" width='30' height='50' fontSize='50'></numberScroll>
</view>
<view v-else>
<numberScroll :num='orderData.price' color="#E93323" width='30' height='50' fontSize='50'></numberScroll>
</view>
</view>
<view class="count-down">
支付剩余时间
<countDown :is-day="false" :tip-text="' '" :day-text="' '" :hour-text="' : '" :minute-text="' : '" :second-text="' '" :datatime="invalidTime"></countDown>
</view>
</view>
<view class="payment">
<view class="title">
支付方式
</view>
<view class="item acea-row row-between-wrapper" v-for="(item,index) in cartArr" :key="index"
v-show='item.payStatus' @click="payType(item.number || 0, item.value, index)">
<view class="left acea-row row-between-wrapper">
<image class="iconfont" src="https://imgs.agrimedia.cn/shop/shop-icon.png"
style="width: 50rpx; height: 50rpx;"></image>
<view class="text">
<view class="name">{{item.name}}</view>
<view class="info" v-if="item.value == 'yue'">
{{item.title}} <span class="money">{{ item.number }}</span>
</view>
<view class="info" v-else>{{item.title}}</view>
</view>
</view>
<image style="width: 31rpx;height: 31rpx; margin-top: 10rpx"
src="https://imgs.agrimedia.cn/shop/select_icon-red.png"></image>
</view>
</view>
<view class="btn">
<view class="button acea-row row-center-wrapper" @click='goPay(number, paytype)'>确认支付</view>
<view class="wait-pay" @click="waitPay">暂不支付</view>
</view>
<view v-show="false" v-html="formContent"></view>
</view>
</view>
</template>
<script>
import countDown from '@/components/countDown';
import numberScroll from '@/components/numberScroll.vue';
import {
HTTP_REQUEST_URL
} from '@/config/app';
import {
getCashierOrder,
orderPay
} from '@/api/order.js';
import {
basicConfig
} from '@/api/public.js';
export default {
components: {
countDown,
numberScroll
},
props: {
orderId: {
type: String,
default: ''
},
fromType: {
type: String,
default: ''
},
//
dat: {
type: Object,
default: {}
},
//
orderData: {
type: Object,
default: {}
},
tabIndex: {
type: Number,
default: 0
}
},
data() {
return {
//
cartArr: [{
"name": '微信支付',
"icon": "icon-weixin2",
value: 'middle_pay',
title: '使用微信快捷支付',
payStatus: 1,
}],
active: 0,
payPrice: 0,
payPriceShow: 0,
payPostage: 0,
offlinePostage: false,
invalidTime: 0,
initIn: false,
jumpData: {
orderId: '',
msg: ''
},
formContent: '',
oid: 0,
number: ''
}
},
watch: {
cartArr: {
handler(newV, oldValue) {
let newPayList = [];
newV.forEach((item, index) => {
if (item.payStatus) {
item.index = index;
newPayList.push(item)
}
});
this.$nextTick(e => {
this.active = newPayList[0].index;
this.paytype = newPayList[0].value;
})
},
immediate: true,
deep: true
}
},
onLoad() {
if (typeof window.WeixinJSBridge === "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', this.onBridgeReady.bind(this), false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', onBridgeReady.bind(this));
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady.bind(this));
}
} else {
onBridgeReady.call(this);
}
},
methods: {
getBasicConfig() {
basicConfig().then(res => {
//
this.cartArr[0].payStatus = res.data.pay_weixin_open || 0
//
this.cartArr[1].payStatus = res.data.ali_pay_status || 0;
//#ifdef MP
this.cartArr[1].payStatus = 0;
//#endif
//
this.cartArr[2].payStatus = res.data.yue_pay_status
if (res.data.offline_pay_status) {
this.cartArr[3].payStatus = 1
} else {
this.cartArr[3].payStatus = 0
}
//
this.cartArr[4].payStatus = res.data.friend_pay_status || 0;
this.getCashierOrder()
}).catch(err => {
uni.hideLoading();
console.log(err)
})
},
getCashierOrder() {
uni.showLoading({
title: `创建订单中`
});
getCashierOrder(this.orderId, this.fromType).then(res => {
this.payPrice = this.payPriceShow = res.data.pay_price
this.payPostage = res.data.pay_postage
this.offlinePostage = res.data.offline_postage
this.invalidTime = res.data.invalid_time
this.cartArr[2].number = res.data.now_money;
this.number = Number(res.data.now_money) || 0;
this.oid = res.data.oid
uni.hideLoading();
}).catch(err => {
uni.hideLoading();
console.log(err)
})
},
payType(number, paytype, index) {
this.active = index;
this.paytype = paytype;
this.number = number;
if (this.offlinePostage) {
if (paytype == 'offline') {
this.payPriceShow = this.$util.$h.Sub(this.payPrice, this.payPostage);
} else {
this.payPriceShow = this.payPrice;
}
}
},
formpost(url, postData) {
let tempform = document.createElement("form");
tempform.action = url;
tempform.method = "post";
tempform.target = "_self";
tempform.style.display = "none";
for (let x in postData) {
let opt = document.createElement("input");
opt.name = x;
opt.value = postData[x];
tempform.appendChild(opt);
}
document.body.appendChild(tempform);
this.$nextTick(e => {
tempform.submit();
})
},
waitPay() {
window.location.href = `${HTTP_REQUEST_URL}/JXH5/pages/goods/order_list/index?activeInd=1`
},
goPay(number, paytype) {
let that = this;
uni.showLoading({
title: `支付中`
});
//
const ua = window.navigator.userAgent.toLowerCase();
const isWechat = ua.includes('micromessenger');
const isH5 = typeof window !== 'undefined';
if (!isH5 || !isWechat) {
uni.hideLoading();
uni.showToast({
title: '请在微信浏览器中使用微信支付功能',
icon: 'none',
duration: 3000
});
return;
}
//
if (this.dat.prePay?.appId || this.dat.appId) {
let jsConfig = that.dat.prePay || that.dat
const onBridgeReady = () => {
window.WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
'appId': jsConfig.appId,
'timeStamp': jsConfig.timeStamp || jsConfig.timestamp,
'nonceStr': jsConfig.nonceStr,
'package': jsConfig.package,
'signType': jsConfig.signType,
'paySign': jsConfig.paySign,
'redirect_url': 'www.baidu.com',
}, (res) => {
const isSuccess = res.err_msg === 'get_brand_wcpay_request:ok';
uni.hideLoading();
uni.showToast({
title: isSuccess ? "支付完成" : "取消支付",
icon: isSuccess ? 'success' : 'none',
duration: 2000,
});
setTimeout(() => {
window.location.href = `${HTTP_REQUEST_URL}/JXH5/pages/goods/order_list/index`
}, 2000);
}
);
};
if (typeof window.WeixinJSBridge === "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', onBridgeReady.bind(this), false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', onBridgeReady.bind(this));
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady.bind(this));
}
} else {
onBridgeReady.call(this);
}
return
};
//
orderPay({
uni: that.orderId,
paytype: paytype,
type: that.friendPay ? 1 : 0,
quitUrl: location.port ? location.protocol + '//' + location.hostname + ':' + location
.port +
'/pages/goods/order_details/index?order_id=' + this.orderId : location.protocol +
'//' + location.hostname +
'/pages/goods/order_details/index?order_id=' + this.orderId
}).then(res => {
let status = res.data.status,
orderId = res.data.result.order_id,
jsConfig = res.data.result.jsConfig
// 0,
if (Number(this.payPriceShow) == 0) {
window.location.href = `${HTTP_REQUEST_URL}/JXH5/pages/goods/order_list/index?activeInd=${this.tabIndex}`
return
};
switch (status) {
case 'MIDDLE_PAY':
case 'WECHAT_PAY':
//
if (!jsConfig) {
uni.showToast({
title: '支付参数错误',
icon: 'none'
});
uni.hideLoading();
return;
}
const onBridgeReady = () => {
window.WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
'appId': jsConfig.appId,
'timeStamp': jsConfig.timeStamp,
'nonceStr': jsConfig.nonceStr,
'package': jsConfig.package,
'signType': jsConfig.signType,
'paySign': jsConfig.paySign,
'redirect_url': 'www.baidu.com',
}, (res) => {
const isSuccess = res.err_msg === 'get_brand_wcpay_request:ok';
uni.hideLoading();
uni.showToast({
title: isSuccess ? "支付完成" : "取消支付",
icon: isSuccess ? 'success' : 'none',
duration: 2000,
});
setTimeout(() => {
window.location.href = `${HTTP_REQUEST_URL}/JXH5/pages/goods/order_list/index?activeInd=${this.tabIndex}`
}, 2000);
}
);
};
if (typeof window.WeixinJSBridge === "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', onBridgeReady.bind(this), false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', onBridgeReady.bind(this));
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady.bind(this));
}
} else {
onBridgeReady.call(this);
}
}
}).catch(err => {
//
uni.hideLoading();
setTimeout(() => {
window.location.href = `${HTTP_REQUEST_URL}/JXH5/pages/goods/order_list/index`
}, 2000);
})
},
//
getTime() {
this.invalidTime = this.getTimestampAfter(15);
},
getTimestampAfter(val) {
const now = Math.floor(Date.now() / 1000); //
return now + (val * 60);
}
}
}
</script>
<style lang="scss" scoped>
page {
background-color: #F5F5F5;
}
.page {
.pay-price {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
padding: 50rpx 0 40rpx 0;
.price {
color: #E93323;
margin-bottom: 20rpx;
display: flex;
align-items: flex-end;
.unit {
font-size: 34rpx;
font-weight: 500;
line-height: 41rpx;
}
.num {
font-size: 50rpx;
font-weight: 600;
}
}
.count-down {
display: flex;
align-items: center;
background-color: #fff;
padding: 8rpx 28rpx;
border-radius: 40rpx;
font-size: 24rpx;
color: #E93323;
.time {
margin-top: 0 !important;
}
.red {
margin: 0 !important;
}
}
}
.payment {
width: 690rpx;
border-radius: 14rpx 14rpx;
background-color: #fff;
z-index: 999;
margin: 0 30rpx;
.title {
color: #000;
font-weight: 800;
font-size: 30rpx;
padding: 30rpx 0 0 30rpx;
margin-bottom: 30rpx;
}
.payMoney {
font-size: 28rpx;
color: #333333;
text-align: center;
margin-top: 50rpx;
.font-color {
margin-left: 10rpx;
.money {
font-size: 40rpx;
}
}
}
}
.payment.on {
transform: translate3d(0, 0, 0);
}
.icon-xuanzhong11 {
color: #E93323 !important;
}
.payment .item {
border-bottom: 1rpx solid #eee;
height: 100rpx;
margin-left: 30rpx;
padding-right: 30rpx;
display: flex;
padding-bottom: 20rpx;
align-items: center;
}
.payment .item:last-child {
border-bottom: none;
}
.payment .item .left {
display: flex;
align-items: center;
flex: 1;
}
.payment .item .left .text {
flex: 1;
}
.payment .item .left .text .name {
font-size: 30rpx;
color: #333;
}
.payment .item .left .text .info {
font-size: 22rpx;
color: #999;
}
.payment .item .left .text .info .money {
color: #ff9900;
}
.payment .item .left .iconfont {
font-size: 50rpx;
color: #09bb07;
margin-right: 28rpx;
}
.payment .item .left .iconfont.icon-zhifubao {
color: #00aaea;
}
.payment .item .left .iconfont.icon-yuezhifu {
color: #ff9900;
}
.payment .item .left .iconfont.icon-yuezhifu1 {
color: #eb6623;
}
.payment .item .left .iconfont.icon-tonglianzhifu1 {
color: #305fd8;
}
.payment .item .iconfont {
font-size: 40rpx;
color: #ccc;
}
.icon-haoyoudaizhifu {
color: #F34C3E !important;
}
.btn {
position: fixed;
left: 30rpx;
display: flex;
flex-direction: column;
align-items: center;
bottom: 30rpx;
bottom: calc(30rpx + constant(safe-area-inset-bottom)); /// IOS<11.2/
bottom: calc(30rpx + env(safe-area-inset-bottom)); /// IOS>11.2/
}
.wait-pay {
color: #aaa;
font-size: 24rpx;
padding-top: 20rpx;
}
.button {
width: 690rpx;
height: 90rpx;
border-radius: 45rpx;
color: #FFFFFF;
background-color: #E93323;
line-height: 90rpx;
text-align: center;
}
}
</style>

View File

@ -0,0 +1,128 @@
<template>
<view class="time" :style="justifyLeft">
<text class="red" v-if="tipText">{{ tipText }}</text>
<text class="styleAll" :style="'background-color:'+ bgColor +';color:'+ colors +';'" v-if="isDay === true">{{ day }}</text>
<text class="timeTxt red" v-if="dayText">{{ dayText }}</text>
<text class="styleAll" :style="'background-color:'+ bgColor +';color:'+ colors +';'">{{ hour }}</text>
<text class="timeTxt red" v-if="hourText">{{ hourText }}</text>
<text class="styleAll" :style="'background-color:'+ bgColor +';color:'+ colors +';'">{{ minute }}</text>
<text class="timeTxt red" v-if="minuteText">{{ minuteText }}</text>
<text class="styleAll" :style="'background-color:'+ bgColor +';color:'+ colors +';'">{{ second }}</text>
<text class="timeTxt red" v-if="secondText">{{ secondText }}</text>
</view>
</template>
<script>
export default {
name: "countDown",
props: {
justifyLeft: {
type: String,
default: ""
},
//
tipText: {
type: String,
default: "倒计时"
},
dayText: {
type: String,
default: "天"
},
hourText: {
type: String,
default: "时"
},
minuteText: {
type: String,
default: "分"
},
secondText: {
type: String,
default: "秒"
},
datatime: {
type: Number,
default: 0
},
isDay: {
type: Boolean,
default: true
},
bgColor:{
type: String,
default: ""
},
colors:{
type: String,
default: ""
}
},
data: function() {
return {
day: "00",
hour: "00",
minute: "00",
second: "00"
};
},
created: function() {
this.show_time();
},
mounted: function() {},
methods: {
show_time: function() {
let that = this;
function runTime() {
//
let intDiff = that.datatime - Date.parse(new Date()) / 1000; //
let day = 0,
hour = 0,
minute = 0,
second = 0;
if (intDiff > 0) {
//
if (that.isDay === true) {
day = Math.floor(intDiff / (60 * 60 * 24));
} else {
day = 0;
}
hour = Math.floor(intDiff / (60 * 60)) - day * 24;
minute = Math.floor(intDiff / 60) - day * 24 * 60 - hour * 60;
second =
Math.floor(intDiff) -
day * 24 * 60 * 60 -
hour * 60 * 60 -
minute * 60;
if (hour <= 9) hour = "0" + hour;
if (minute <= 9) minute = "0" + minute;
if (second <= 9) second = "0" + second;
that.day = day;
that.hour = hour;
that.minute = minute;
that.second = second;
} else {
that.day = "00";
that.hour = "00";
that.minute = "00";
that.second = "00";
}
}
runTime();
setInterval(runTime, 1000);
}
}
};
</script>
<style>
.time{
display: flex;
justify-content: center;
}
.red{
color: var(--view-theme);
margin: 0 4rpx;
}
</style>

View File

@ -0,0 +1,223 @@
<template>
<view class="keyboard " :class="{'show':show,'dark':dark}">
<view class="keyboard-content">
<view class="keyboard-content-left">
<view class="keyboard-content-left-item" v-for="item in KeyboardNumber" :index="item" @click="_setValue(item)" >
<view class="keyboard-content-left-item-cell hover">
{{item}}
</view>
</view>
<view class="keyboard-content-left-item" v-if="isDecimal" @click="_setValue('.')">
<view class="keyboard-content-left-item-cell hover" >.</view>
</view>
</view>
<view class="keyboard-content-right">
<view class="keyboard-content-right-item" @click="_setValue('delete')">
<view class="keyboard-content-right-item-cell hover">
<image class="icon" v-if="!dark" src="../../static/mono-keyboard/backspace.png" mode="aspectFill"></image>
<image class="icon" v-else src="../../static/mono-keyboard/backspace_dark.png" mode="aspectFill"></image>
</view>
</view>
<view class="keyboard-content-right-item" @click="confirm" :style="isPay? 'opacity: 1' : 'opacity: 0.5'">
<view class="keyboard-content-right-item-confirm" :class="{'disable':!money,'hover':money}" :style="{'background-color':btnColor }">{{confirmText}}</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name:'monokeyboard',
props:{
show:{
default:false,
type:Boolean
},
dark:{
default:false,
type:Boolean
},
btnColor:{
default:'#07C160',
type:String
},
confirmText:{
default:'去支付',
type:String
},
isDecimal:{
default:true,
type:Boolean
},
isPay: {
default:true,
type:Boolean
},
value:{
default:'',
type:[Number,String]
}
},
data(){
return {
KeyboardNumber:[1,2,3,4,5,6,7,8,9,0],
money:''
}
},
created(){
this.money+=this.value
},
computed:{
},
onHide() {
this.money = ''
},
methods:{
_setValue:function(e){
switch(e){
case '.':
if(this.money.indexOf('.') > -1) break
if(this.money==''){
this.money = '0.'
}else{
this.money += e.toString()
}
break
case 'delete':
if(this.money.length > 0){
this.money = this.money.substr(0,this.money.length-1)
}
break
default:
this.money +=e.toString()
}
this.$emit("change",this.money)
},
confirm:function(){
if (this.isPay == 1) {
if(this.money.length>0){
this.$emit("confirm",this.money)
}
}
}
}
}
</script>
<style lang="less" scoped>
.dark{
background-color: #1E1E1E !important;
.keyboard-content-left-item-cell{
background-color: #2c2c2c !important;
color: rgba(255,255,255,0.6);
}
.keyboard-content-right-item-cell{
background-color: #2c2c2c !important;
}
.keyboard-content-left-item-cell:active{
background-color: rgba(255,255,255,0.2) !important;
}
.keyboard-content-right-item-cell:active{
background-color: rgba(255,255,255,0.2) !important;
}
}
.keyboard{
position:fixed;
left: 0;
transform: translateY(100%);
transition: all 0.3s ease;
bottom: 0;
background-color: #F7F7F7;
width: 100%;
padding: 20rpx 0 40rpx 0;
box-sizing: border-box;
.keyboard-content{
display: flex;
.keyboard-content-left{
width: 75%;
display: flex;
flex-wrap: wrap;
.keyboard-content-left-item{
flex-basis: 33%;
flex-grow: 1;
padding: 0 0 15rpx 15rpx;
box-sizing: border-box;
.keyboard-content-left-item-cell{
background-color: #ffffff;
border-radius: 8rpx;
text-align: center;
font-size: 46rpx;
line-height: 92rpx;
font-weight: 500;
}
.keyboard-content-left-item-cell:active{
background-color: rgba(0,0,0,0.1);
}
}
.keyboard-content-left-item:nth-child(10){
flex-basis: 66%;
flex-grow:1;
}
}
.keyboard-content-right{
width: 25%;
display: flex;
flex-direction: column;
box-sizing: border-box;
.keyboard-content-right-item{
width: 100%;
padding: 0 15rpx 15rpx 15rpx;
box-sizing: border-box;
.keyboard-content-right-item-cell{
border-radius: 8rpx;
background-color: #ffffff;
height: 92rpx;
line-height: 92rpx;
padding: 20rpx;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
image{
height: 60%;
width: 40%;
}
}
.keyboard-content-right-item-cell:active{
background-color: rgba(0,0,0,0.1);
}
}
.keyboard-content-right-item:nth-child(2){
flex:1;
.keyboard-content-right-item-confirm{
background-color: #07C160;
opacity: 1;
color: rgba(255,255,255,0.8);
height: 100%;
border-radius: 8rpx;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 36rpx;
font-weight: 800;
}
.disable{
opacity: 0.4;
}
.hover:active{
//background-color: rgba(8,165,82,1);
opacity: 0.8;
}
}
}
}
}
.show {
transition: all 0.3s ease;
transform: translateY(0%) !important;
}
</style>

160
components/numberScroll.vue Normal file
View File

@ -0,0 +1,160 @@
<template>
<view class="number-box">
<block v-for="(myIndex, index) in indexArr" :key="index">
<swiper class="swiper" vertical="true" :current="myIndex" circular="true"
v-bind:style="{color:color,width:myIndex == 10 ? '14rpx' : myIndex == 1 ? '22rpx' : width+'rpx',height:height+'rpx',lineHeight:fontSize+'rpx',fontSize:fontSize+'rpx',fontWeight: fontWeight}">
<swiper-item>
<view class="swiper-item">0</view>
</swiper-item>
<swiper-item>
<view class="swiper-item">1</view>
</swiper-item>
<swiper-item>
<view class="swiper-item">2</view>
</swiper-item>
<swiper-item>
<view class="swiper-item">3</view>
</swiper-item>
<swiper-item>
<view class="swiper-item">4</view>
</swiper-item>
<swiper-item>
<view class="swiper-item">5</view>
</swiper-item>
<swiper-item>
<view class="swiper-item">6</view>
</swiper-item>
<swiper-item>
<view class="swiper-item">7</view>
</swiper-item>
<swiper-item>
<view class="swiper-item">8</view>
</swiper-item>
<swiper-item>
<view class="swiper-item">9</view>
</swiper-item>
<swiper-item>
<view class="swiper-item">.</view>
</swiper-item>
</swiper>
</block>
</view>
</template>
<script>
export default {
props: {
num: [String, Number],
color: {
type: String,
default: '#000000'
},
width: {
type: String,
default: '30'
},
height: {
type: String,
default: '30'
},
fontSize: {
type: String,
default: '30'
},
fontWeight: {
type: [String, Number],
default: 500
}
},
data() {
return {
indexArr: []
};
},
created() {
let {
num
} = this;
let arr = new Array(num.toString().length);
arr.fill(0);
this.indexArr = arr;
},
watch: {
num: function(val, oldVal) {
//
let arr = Array.prototype.slice.apply(this.indexArr);
let newLen = val.toString().length;
let oldLen = oldVal.toString().length;
if (newLen > oldLen) {
for (let i = 0; i < newLen - oldLen; i++) {
arr.push(0);
}
this.indexArr = arr;
}
if (newLen < oldLen) {
for (let i = 0; i < oldLen - newLen; i++) {
arr.pop();
}
this.indexArr = arr;
}
this.numChange(val);
}
},
mounted() {
//app
this._time = setTimeout(() => {
this.numChange(this.num);
clearTimeout(this._time);
}, 50);
},
methods: {
/**
* 数字改变
* @value 数字
*/
numChange(num) {
this.$nextTick(() => {
let {
indexArr
} = this;
let copyIndexArr = Array.prototype.slice.apply(indexArr);
let _num = num.toString();
for (let i = 0; i < _num.length; i++) {
if (_num[i] === '.') {
copyIndexArr[i] = 10;
} else {
copyIndexArr[i] = Number(_num[i]);
}
}
this.indexArr = copyIndexArr;
})
}
}
};
</script>
<style lang="scss">
.number-box {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.swiper {
position: relative;
// line-height: 30upx;
// width: 30upx;
// height: 30upx;
// font-size: 30upx;
// background: red;
}
.swiper:after {
content: '';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
</style>

11
config/app.js Normal file
View File

@ -0,0 +1,11 @@
module.exports = {
HTTP_REQUEST_URL: 'https://point.agrimedia.cn',
HEADER: {},
TOKENNAME: 'Authori-zation',
// 缓存时间 0 永久
EXPIRE: 0,
//分页最多显示条数
LIMIT: 10,
// 请求超时限制 默认10秒
TIMEOUT: 10000
}

46
config/cache.js Normal file
View File

@ -0,0 +1,46 @@
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
module.exports = {
//token
LOGIN_STATUS: 'LOGIN_STATUS_TOKEN',
ISPAY: '',
//uid
UID:'UID',
//用户信息
USER_INFO: 'USER_INFO',
//token过期时间
EXPIRES_TIME: 'EXPIRES_TIME',
//微信登录
WX_AUTH: 'WX_AUTH',
//公众号登录code
STATE_KEY: 'wx_authorize_state',
//登录类型
LOGINTYPE: 'loginType',
//登录跳转地址
BACK_URL: 'login_back_url',
//小程序登录状态code
STATE_R_KEY: 'roution_authorize_state',
//logo 地址
LOGO_URL: 'LOGO_URL',
//模板缓存
SUBSCRIBE_MESSAGE: 'SUBSCRIBE_MESSAGE',
TIPS_KEY: 'TIPS_KEY',
SPREAD: 'spread',
//缓存经度
CACHE_LONGITUDE: 'LONGITUDE',
//缓存纬度
CACHE_LATITUDE: 'LATITUDE',
// 店铺信息
USER_ADDRESS: 'USER_ADDRESS'
}

35
config/payChat.js Normal file
View File

@ -0,0 +1,35 @@
import store from '@/store/index.js';
import { HTTP_REQUEST_URL } from '@/config/app';
import { getMerchantInfo } from '@/api/user.js';
/**
* 使用方式
* 进入半屏小程序所需的参数
* parameter: {
need_login: 1,
shop_id: 1
}
*/
const PayParams = function(parameter) {
return getMerchantInfo(parameter.shop_id).then(res => {
let shopData = res.data;
return {
name: shopData.name,
code: res.data.bar_code,
need_login: parameter.need_login,
shop_id: parameter.shop_id,
price: parameter.price,
isVip: parameter.isVip,
envVersion: parameter.envVersion,
status: parameter.status,
token: parameter.token,
BASE_URL: HTTP_REQUEST_URL,
REQUEST_URL: parameter.REQUEST_URL,
};
});
};
export default PayParams;

18
config/socket.js Normal file
View File

@ -0,0 +1,18 @@
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
module.exports = {
// Socket链接 暂不做配置
WSS_SERVER_URL:'',
// Socket调试模式
SERVER_DEBUG:true,
// 心跳间隔
PINGINTERVAL:3000
}

20
index.html Normal file
View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="zh-CN">
<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>

27
main.js Normal file
View File

@ -0,0 +1,27 @@
import App from './App'
import store from './store'
import util from 'utils/util'
// #ifndef VUE3
import Vue from 'vue'
import './uni.promisify.adaptor'
Vue.prototype.$util = util;
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
store,
...App
})
app.$mount()
// #endif
// #ifdef VUE3
import { createSSRApp } from 'vue'
export function createApp() {
const app = createSSRApp(App)
return {
app
}
}
// #endif

77
manifest.json Normal file
View File

@ -0,0 +1,77 @@
{
"name" : "收银台支付",
"appid" : "__UNI__B05F7DA",
"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" : "",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "2",
"h5" : {
"router" : {
"mode" : "history"
}
}
}

27
pages.json Normal file
View File

@ -0,0 +1,27 @@
{
"pages": [ //pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "向商家付款",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
},
{
"path": "pages/Paysuccessful/jxPaysuccessful",
"style": {
"navigationBarTitleText": "支付结果",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"uniIdRouter": {}
}

View File

@ -0,0 +1,189 @@
<template>
<view class="Content-Box">
<template v-if="Name && Status != -1">
<view class="Status">
<image class="img" v-if="Status == 1" src="../../static/success.png" mode="widthFix" />
<image class="img" v-if="Status == 2" src="../../static/fail.png" mode="widthFix" />
</view>
<view class="Shop-Name">
<text>{{ Name }}</text>
</view>
<view class="Pay-Infor">
<view class="Pay-Item">
<view class="Label"><text>订单状态</text></view>
<view class="Value"><text>{{ Status == 1 ? '支付成功' : '取消支付' }}</text></view>
</view>
<view class="Pay-Item">
<view class="Label"><text>支付时间</text></view>
<view class="Value"><text>{{ paytime }}</text></view>
</view>
<view class="Pay-Item" v-if="amountInfo.order_price">
<view class="Label"><text>支付总额</text></view>
<view class="Value"><text>{{ amountInfo.order_price }}</text></view>
</view>
<!-- <view class="Pay-Item" v-if="amountInfo.broker_ded">
<view class="Label"><text>余额抵扣</text></view>
<view class="Value"><text>{{ amountInfo.broker_ded }}</text></view>
</view> -->
<view v-if="Number(isAllApi) == 1">
<view class="Pay-Item">
<view class="Label"><text>抵用券抵扣</text></view>
<view class="Value">
<text>{{ (Number(amountInfo.coin_ded) + Number(amountInfo.broker_ded)).toFixed(2) }}</text>
</view>
</view>
</view>
<view class="Pay-Item" v-if="amountInfo.real_pay">
<view class="Label"><text>实际付款</text></view>
<view class="Value"><text>{{ amountInfo.real_pay }}</text></view>
</view>
<view class="Pay-Item">
<view class="Label"><text>获得积分</text></view>
<view class="Value" v-if="amountInfo.agent_id"><text>{{ amountInfo.user_integral }}</text></view>
<view class="Value" v-else><text>{{ amountInfo.integral }}</text></view>
</view>
</view>
</template>
<template v-else>
<image class="img" src="../../static/fail.png" mode="widthFix" />
<view class="Shop-Name">
<text>订单错误请联系管理员</text>
</view>
</template>
<button class="complete" @click="closePage">完成</button>
</view>
</template>
<script>
import {
getOfflineOrderDetail,
getgzhlineOrderDetail
} from '@/api/index.js';
export default {
name: 'JxPaysuccessful',
data() {
return {
//
paytime: '',
Status: 1,
Name: '',
order_sn: '',
//
amountInfo: {} //
}
},
onLoad(option) {
let date = new Date();
this.paytime =
`${date.getFullYear()}/${this.f0(date.getMonth() + 1)}/${this.f0(date.getDate())} ${this.f0(date.getHours())}:${this.f0(date.getMinutes())}:${this.f0(date.getSeconds())}`;
this.Status = option?.Status;
this.Name = option?.merchant_name;
this.order_sn = option?.order_sn;
this.isAllApi = option?.isAllApi;
this.fetchOrderDetail();
},
methods: {
// 0
f0(n) {
if (n <= 9) return `0${n}`;
return n;
},
async fetchOrderDetail() {
try {
const apiCall = Number(this.isAllApi) ? getOfflineOrderDetail : getgzhlineOrderDetail;
const res = await apiCall({
order_sn: this.order_sn
});
this.amountInfo = res.data;
} catch (error) {
console.error('获取订单详情失败:', error);
}
},
// H5
closePage() {
// H5
window.close();
if (typeof WeixinJSBridge == "object" && typeof WeixinJSBridge.invoke == "function") {
WeixinJSBridge.invoke('closeWindow', {}, function(res) {
if (res.err_msg == "close_window:ok") {
//
console.log('关闭成功的处理')
} else {
//
console.log('关闭失败的处理')
}
});
}
}
}
}
</script>
<style lang="scss">
.Content-Box {
align-items: center;
display: flex;
flex-direction: column;
justify-content: center;
height: 100vh;
margin: 0rpx 50rpx;
.Status {
margin: 0 auto;
width: 296.15rpx;
height: 167.31rpx;
.img {
width: 100%;
height: 100%;
}
}
.Shop-Name {
width: 100%;
text-align: center;
line-height: 50rpx;
font-weight: bold;
margin: 50rpx 0rpx;
}
.Pay-Infor {
// margin-top: 42.31rpx;
padding: 19.23rpx;
width: 100%;
background-color: #FFFFFF;
border-radius: 23.08rpx;
font-size: 26.92rpx;
color: rgba(51, 51, 51, 1);
overflow: hidden;
.Pay-Item {
display: flex;
justify-content: space-between;
line-height: 76.92rpx;
}
}
}
.complete {
width: 500rpx;
margin: 32rpx auto;
background: linear-gradient(90deg, #FF9999 0%, #E11616 100%);
color: #FFFFFF;
border-radius: 50rpx;
&::after {
border: none !important;
}
}
</style>

606
pages/index/index.vue Normal file
View File

@ -0,0 +1,606 @@
<template>
<view>
<!-- 店铺扫码支付页 -->
<view class="content">
<view class="main">
<view class="title">
<image class="shop-images" src="https://img.agrimedia.cn/APP-ZhiFuBusiness/shop.png"></image>
<view class="name">{{form.name? form.name : '--'}}</view>
</view>
<view class="money" @click="inputClick()">
<view class="input">
<text class="txt">消费金额</text>
<view class="flex wrap">
<input class="num" type="text" v-model="money" disabled="true" />
<text class="line" v-if="!money">|</text>
</view>
</view>
</view>
<view class="container">
<view class="list-item" @click="rateTypeClick(2)">
<text class="titles">抵用券抵扣</text>
<view class="right-section">
<text>{{(Number(broker) + Number(vouchers)).toFixed(2) == 0? '0.00' : (Number(broker) + Number(vouchers)).toFixed(2)}}</text>
<view class="wx_flex wx_flex-items-center">
<image style="width: 31rpx;height: 31rpx; margin-top: 10rpx"
:src="couponUsed==1?'https://imgs.agrimedia.cn/shop/select_icon.png':'https://imgs.agrimedia.cn/shop/unselect_icon.png'"
mode=""></image>
</view>
</view>
</view>
<!-- 实际支付 -->
<view class="payment-section">
<text class="titles">实际支付</text>
<text class="payment-amount">¥{{actualPayment}}</text>
</view>
</view>
</view>
<view class="pay-btn" @click="keyConfirm">
去支付
</view>
<!-- <monokeyboard
ref="mono"
:value="money"
:show="keyshow"
@confirm="keyConfirm"
@change="keyChange"
:isPay="a">
</monokeyboard> -->
<!-- <view class="shadow" v-if="loading"></view> -->
</view>
</view>
</template>
<script>
import {
HTTP_REQUEST_URL
} from '@/config/app';
import monokeyboard from '@/components/mono-keyboard/mono-keyboard.vue';
import OnlineShop from '@/components/OnlineShop.vue';
import UrlUtils from '@/utils/urlUtils.js';
import getUrlParam from '@/utils/utils.js';
import {
middleLogin,
computedOrder,
gzhcomputedOrder,
getMerchantInfo,
doOrder,
dogzhOrder,
cancelPay,
getMerchantInfoByCode
} from '@/api/index';
export default {
components: {
monokeyboard,
OnlineShop
},
data() {
return {
authKey: '',
bindPhone: '',
keyshow: true,
token: '',
qrcode: '',
merchant_id: '', //id
ID: '',
form: {},
money: '', //
couponUsed: false, // 使
commissionUsed: false, // 使
vouchers: '',
broker: '',
actualPayment: '', //
a: false,
hasAssigned: false, //
loading: true,
amountInfo: {},
dikou: 0,
order_id: '', //
dat: '', //
tabIndex: '', // tab
orderData: {} // { price: '100' }
}
},
watch: {
money: {
handler: function(newV, oldV) {
this.getTotal()
},
deep: true
}
},
onLoad() {
const url = window.location.href;
const cleanUrl = this.cleanUrl(url);
const token = getUrlParam('token') || this.$store.state.app.token;
if (token) {
this.$store.commit('UPDATE_LOGIN', token);
//
if (getUrlParam('merchant_id') && !getUrlParam('from_type')) {
this.getData(getUrlParam('merchant_id'));
} else if (getUrlParam('code')) {
this.getQrData(getUrlParam('code'));
} else {
uni.showToast({
title: '店铺码为空',
icon: 'none'
});
}
} else {
// tokenurl
console.log(encodeURIComponent(cleanUrl), '跳转');
window.location.replace(`${HTTP_REQUEST_URL}/api/v2/routine/gzhLogin?back_url=${encodeURIComponent(cleanUrl)}`);
}
},
methods: {
// URL ?&
cleanUrl(url) {
let cleanUrl = url.replace(/\?+/g, '?');
const firstQuestionMarkIndex = cleanUrl.indexOf('?');
if (firstQuestionMarkIndex !== -1) {
const beforeParams = cleanUrl.substring(0, firstQuestionMarkIndex + 1);
const afterParams = cleanUrl.substring(firstQuestionMarkIndex + 1).replace(/\?/g, '&');
cleanUrl = beforeParams + afterParams;
}
return cleanUrl;
},
// ID
getData(id) {
getMerchantInfo({
id: id
}).then(res => {
this.form = res.data;
this.merchant_id = res.data.merchant_id
this.a = true;
this.loading = false;
//
this.calculatePayment();
}).catch(error => {
uni.showToast({
title: error,
icon: 'none'
})
this.loading = false
})
},
// CODE
getQrData(qrcode) {
let that = this;
this.qrcode = qrcode;
getMerchantInfoByCode({
code: qrcode
}).then(res => {
this.form = res.data.merchantInfo;
this.merchant_id = res.data.merchantInfo.merchant_id;
this.a = true;
this.loading = false;
//
this.calculatePayment();
}).catch(error => {
//
this.loading = false
this.showModal = true;
this.form.merchantInfo = 0;
this.form.status = 1;
})
},
//
rateTypeClick(val) {
if (this.money > 0 || this.money !== '') {
if (val == 1) {
this.commissionUsed = !this.commissionUsed;
this.couponUsed = !this.couponUsed
} else {
this.couponUsed = !this.couponUsed
this.commissionUsed = !this.commissionUsed;
}
this.getTotal();
} else {
uni.showToast({
title: '请输入金额',
icon: 'none'
})
}
},
//
getTotal() {
if (Number(this.amountInfo.broker_balance) + Number(this.amountInfo.coin_balance) >= Number(this.money) &&
Number(this.money) && this.couponUsed) {
this.actualPayment = 0.01
this.dikou = (Number(this.money) - (Number(this.amountInfo.broker_balance) + Number(this.amountInfo
.coin_balance))).toFixed(2);
} else if (Number(this.money) && this.couponUsed) {
this.actualPayment = (Number(this.money) - (Number(this.amountInfo.broker_balance) + Number(this
.amountInfo.coin_balance))).toFixed(2);
this.dikou = (Number(this.amountInfo.broker_balance) + Number(this.amountInfo.coin_balance)).toFixed(
2);
} else {
this.actualPayment = this.money;
}
},
//
async calculatePayment() {
const params = {
pay_price: this.money || 0,
use_coin: this.couponUsed ? 1 : 0,
use_broker: this.commissionUsed ? 1 : 0
};
try {
const apiCall = Number(this.isAllApi) === 1 ? computedOrder : gzhcomputedOrder;
const res = await apiCall(params);
this.actualPayment = res.data.real_pay_price;
this.amountInfo = res.data;
if (!this.hasAssigned) {
this.hasAssigned = true;
this.vouchers = res.data.coin_balance;
this.broker = res.data.broker_balance;
}
} catch (error) {
// console.error(':', error.msg);
uni.showToast({
title: error.msg,
icon: 'none'
});
}
},
async keyConfirm(e) {
//
if (isNaN(this.money)) {
uni.showToast({
title: '请输入正常的数字',
icon: 'none'
});
return;
}
if (Number(this.money) >= 1000000) {
uni.showToast({
title: '支付金额不能大于一百万',
icon: 'none'
});
return;
}
if (Number(this.money) <= 0) {
uni.showToast({
title: '支付金额不能为0',
icon: 'none'
});
return;
}
uni.showLoading({
title: "正在跳转中",
mask: true
});
if (!this.merchant_id) return;
try {
//
const params = {
pay_price: Number(this.money),
use_coin: this.couponUsed ? 1 : 0,
use_broker: this.commissionUsed ? 1 : 0,
merchant_id: this.merchant_id,
code: this.qrcode,
is_middle_pay: 1
};
//
const apiCall = Number(this.isAllApi) ? doOrder : dogzhOrder;
const res = await apiCall(params);
const jsConfig = res.data;
const order_sn = jsConfig.order_sn;
//
const ua = window.navigator.userAgent.toLowerCase();
const isWechat = ua.includes('micromessenger');
const isH5 = typeof window !== 'undefined';
if (!isH5 || !isWechat) {
uni.hideLoading();
uni.showToast({
title: '请在微信浏览器中使用微信支付功能',
icon: 'none',
duration: 3000
});
this.cancelVideo();
return;
}
//
if (!jsConfig) {
uni.showToast({
title: '支付参数错误',
icon: 'none'
});
uni.hideLoading();
return;
}
const onBridgeReady = () => {
window.WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
'appId': jsConfig.appId,
'timeStamp': jsConfig.timeStamp,
'nonceStr': jsConfig.nonceStr,
'package': jsConfig.package,
'signType': jsConfig.signType,
'paySign': jsConfig.paySign
}, (res) => {
const isSuccess = res.err_msg === 'get_brand_wcpay_request:ok';
uni.hideLoading();
uni.showToast({
title: isSuccess ? "支付完成" : "取消支付",
icon: isSuccess ? 'success' : 'none',
duration: 2000,
});
this.clearPaymentData();
if (!isSuccess) this.cancelVideo();
setTimeout(() => {
const url =
`/pages/Paysuccessful/jxPaysuccessful?merchant_name=${this.form.name}&order_sn=${order_sn}&Status=${isSuccess ? 1 : 2}&isAllApi=${this.isAllApi}`;
uni.redirectTo({
url
});
}, 2000);
}
);
};
if (typeof window.WeixinJSBridge === "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', onBridgeReady.bind(this), false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', onBridgeReady.bind(this));
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady.bind(this));
}
} else {
onBridgeReady.call(this);
}
} catch (err) {
uni.hideLoading();
uni.showToast({
title: err.msg || err.message || err.data.message || '支付处理失败',
icon: 'none',
duration: 2000
});
}
},
keyChange(e) {
if (this.isTwoDecimalPlaces(e)) {
console.log(e, '123')
this.money = e
}
},
inputClick() {
uni.showToast({
title: '使用键盘输入',
icon: 'none'
})
},
isTwoDecimalPlaces(num) {
const numStr = num.toString();
const decimalIndex = numStr.indexOf('.');
// 2
if (decimalIndex === -1 || numStr.length - decimalIndex - 1 <= 2) {
return true; //
} else {
return false; //
}
},
//
clearPaymentData() {
this.money = '';
this.actualPayment = '';
this.couponUsed = false;
this.commissionUsed = false;
if (this.$refs.mono) {
this.$refs.mono.money = '';
}
},
//
cancelVideo() {
cancelPay({
merchant_id: this.merchant_id
}).then(res => {
console.log(res)
}).catch(error => {
console.error('取消支付播报失败:', error);
})
}
}
}
</script>
<style lang="scss" scoped>
.content {
margin: 0 auto;
margin-top: 20rpx;
height: 100vh;
overflow: hidden;
.main {
margin: 20rpx;
background-color: #fff;
border-radius: 30rpx;
padding: 30rpx;
.title {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
font-size: 36rpx;
font-weight: 600;
margin-top: 30rpx;
.shop-images {
width: 50rpx;
height: 50rpx;
margin-right: 20rpx;
}
.name {
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
}
}
.money {
text-align: left;
padding: 30rpx 40rpx;
font-size: 42rpx;
font-weight: 600;
margin-top: 40rpx;
background-color: #f8f8f8;
border-radius: 20rpx;
.input {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 38rpx;
.txt {
width: 300rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-weight: 600;
margin-right: 30rpx;
}
.num {
font-weight: 600;
text-align: right;
font-size: 38rpx;
}
// /deep/ .u-input--radius {
// background-color: transparent !important;
// border: none !important;
// }
.wrap {
position: relative;
.line {
position: absolute;
top: 10rpx;
right: 14rpx;
animation: blink 1s infinite;
color: #556dea;
}
}
}
}
}
}
/* 光标闪烁动画 */
@keyframes blink {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0;
}
}
.list-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx 20rpx;
border-bottom: 1rpx solid #eee;
.titles {
font-size: 32rpx;
}
}
.right-section {
display: flex;
align-items: center;
gap: 20rpx;
}
.payment-section {
display: flex;
justify-content: space-between;
padding: 40rpx 20rpx;
font-weight: bold;
font-size: 38rpx;
.titles {}
}
.payment-amount {
color: #ff2d55;
font-size: 38rpx;
}
.shadow {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #000;
opacity: .5;
width: 100%;
height: 100vh;
z-index: 999999;
}
.pay-btn {
background-color: #07c160;
width: 200rpx;
margin: 0 auto;
text-align: center;
padding: 20rpx 10rpx;
color: #fff;
border-radius: 20rpx;
font-size: 38rpx;
font-weight: 600;
margin-top: 80rpx;
}
</style>

16
static/css/pageElement.scss Executable file
View File

@ -0,0 +1,16 @@
#app {
max-width: 750rpx;
min-width: 750rpx;
height: auto;
margin: 0 auto;
min-height: 100%;
}
page {
/* // background-color: #1C1C1E;
// background-image: url('https://img.agrimedia.cn/sch5/bg.png');
// background-size: cover; */
padding: 30.77rpx;
height: 100%;
width: 100;
}

BIN
static/fail.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

539
static/icon/demo.css Executable file
View File

@ -0,0 +1,539 @@
/* Logo 字体 */
@font-face {
font-family: "iconfont logo";
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
}
.logo {
font-family: "iconfont logo";
font-size: 160px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* tabs */
.nav-tabs {
position: relative;
}
.nav-tabs .nav-more {
position: absolute;
right: 0;
bottom: 0;
height: 42px;
line-height: 42px;
color: #666;
}
#tabs {
border-bottom: 1px solid #eee;
}
#tabs li {
cursor: pointer;
width: 100px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 16px;
border-bottom: 2px solid transparent;
position: relative;
z-index: 1;
margin-bottom: -1px;
color: #666;
}
#tabs .active {
border-bottom-color: #f00;
color: #222;
}
.tab-container .content {
display: none;
}
/* 页面布局 */
.main {
padding: 30px 100px;
width: 960px;
margin: 0 auto;
}
.main .logo {
color: #333;
text-align: left;
margin-bottom: 30px;
line-height: 1;
height: 110px;
margin-top: -50px;
overflow: hidden;
*zoom: 1;
}
.main .logo a {
font-size: 160px;
color: #333;
}
.helps {
margin-top: 40px;
}
.helps pre {
padding: 20px;
margin: 10px 0;
border: solid 1px #e7e1cd;
background-color: #fffdef;
overflow: auto;
}
.icon_lists {
width: 100% !important;
overflow: hidden;
*zoom: 1;
}
.icon_lists li {
width: 100px;
margin-bottom: 10px;
margin-right: 20px;
text-align: center;
list-style: none !important;
cursor: default;
}
.icon_lists li .code-name {
line-height: 1.2;
}
.icon_lists .icon {
display: block;
height: 100px;
line-height: 100px;
font-size: 42px;
margin: 10px auto;
color: #333;
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
-moz-transition: font-size 0.25s linear, width 0.25s linear;
transition: font-size 0.25s linear, width 0.25s linear;
}
.icon_lists .icon:hover {
font-size: 100px;
}
.icon_lists .svg-icon {
/* 通过设置 font-size 来改变图标大小 */
width: 1em;
/* 图标和文字相邻时,垂直对齐 */
vertical-align: -0.15em;
/* 通过设置 color 来改变 SVG 的颜色/fill */
fill: currentColor;
/* path stroke 溢出 viewBox 部分在 IE 下会显示
normalize.css 中也包含这行 */
overflow: hidden;
}
.icon_lists li .name,
.icon_lists li .code-name {
color: #666;
}
/* markdown 样式 */
.markdown {
color: #666;
font-size: 14px;
line-height: 1.8;
}
.highlight {
line-height: 1.5;
}
.markdown img {
vertical-align: middle;
max-width: 100%;
}
.markdown h1 {
color: #404040;
font-weight: 500;
line-height: 40px;
margin-bottom: 24px;
}
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
color: #404040;
margin: 1.6em 0 0.6em 0;
font-weight: 500;
clear: both;
}
.markdown h1 {
font-size: 28px;
}
.markdown h2 {
font-size: 22px;
}
.markdown h3 {
font-size: 16px;
}
.markdown h4 {
font-size: 14px;
}
.markdown h5 {
font-size: 12px;
}
.markdown h6 {
font-size: 12px;
}
.markdown hr {
height: 1px;
border: 0;
background: #e9e9e9;
margin: 16px 0;
clear: both;
}
.markdown p {
margin: 1em 0;
}
.markdown>p,
.markdown>blockquote,
.markdown>.highlight,
.markdown>ol,
.markdown>ul {
width: 80%;
}
.markdown ul>li {
list-style: circle;
}
.markdown>ul li,
.markdown blockquote ul>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown>ul li p,
.markdown>ol li p {
margin: 0.6em 0;
}
.markdown ol>li {
list-style: decimal;
}
.markdown>ol li,
.markdown blockquote ol>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown code {
margin: 0 3px;
padding: 0 5px;
background: #eee;
border-radius: 3px;
}
.markdown strong,
.markdown b {
font-weight: 600;
}
.markdown>table {
border-collapse: collapse;
border-spacing: 0px;
empty-cells: show;
border: 1px solid #e9e9e9;
width: 95%;
margin-bottom: 24px;
}
.markdown>table th {
white-space: nowrap;
color: #333;
font-weight: 600;
}
.markdown>table th,
.markdown>table td {
border: 1px solid #e9e9e9;
padding: 8px 16px;
text-align: left;
}
.markdown>table th {
background: #F7F7F7;
}
.markdown blockquote {
font-size: 90%;
color: #999;
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
}
.markdown blockquote p {
margin: 0;
}
.markdown .anchor {
opacity: 0;
transition: opacity 0.3s ease;
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
.markdown h4:hover .anchor,
.markdown h5:hover .anchor,
.markdown h6:hover .anchor {
opacity: 1;
display: inline-block;
}
.markdown>br,
.markdown>p>br {
clear: both;
}
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}
/* 代码高亮 */
/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre)>code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}

257
static/icon/demo_index.html Executable file
View File

@ -0,0 +1,257 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>iconfont Demo</title>
<link rel="shortcut icon" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg" type="image/x-icon"/>
<link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg"/>
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
<link rel="stylesheet" href="demo.css">
<link rel="stylesheet" href="iconfont.css">
<script src="iconfont.js"></script>
<!-- jQuery -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
<!-- 代码高亮 -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
<style>
.main .logo {
margin-top: 0;
height: auto;
}
.main .logo a {
display: flex;
align-items: center;
}
.main .logo .sub-title {
margin-left: 0.5em;
font-size: 22px;
color: #fff;
background: linear-gradient(-45deg, #3967FF, #B500FE);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
</style>
</head>
<body>
<div class="main">
<h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
<img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
</a></h1>
<div class="nav-tabs">
<ul id="tabs" class="dib-box">
<li class="dib active"><span>Unicode</span></li>
<li class="dib"><span>Font class</span></li>
<li class="dib"><span>Symbol</span></li>
</ul>
<a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=3770712" target="_blank" class="nav-more">查看项目</a>
</div>
<div class="tab-container">
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xed1d;</span>
<div class="name">对勾_块</div>
<div class="code-name">&amp;#xed1d;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xeb65;</span>
<div class="name">警告</div>
<div class="code-name">&amp;#xeb65;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe600;</span>
<div class="name">购物车满</div>
<div class="code-name">&amp;#xe600;</div>
</li>
</ul>
<div class="article markdown">
<h2 id="unicode-">Unicode 引用</h2>
<hr>
<p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
<ul>
<li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
<li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
</ul>
<blockquote>
<p>注意:新版 iconfont 支持两种方式引用多色图标SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p>
</blockquote>
<p>Unicode 使用步骤如下:</p>
<h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.woff2?t=1669284444124') format('woff2'),
url('iconfont.woff?t=1669284444124') format('woff'),
url('iconfont.ttf?t=1669284444124') format('truetype');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
<pre><code class="language-css"
>.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
<pre>
<code class="language-html"
>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-duigou_kuai"></span>
<div class="name">
对勾_块
</div>
<div class="code-name">.icon-duigou_kuai
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-jinggao"></span>
<div class="name">
警告
</div>
<div class="code-name">.icon-jinggao
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-gouwucheman"></span>
<div class="name">
购物车满
</div>
<div class="code-name">.icon-gouwucheman
</div>
</li>
</ul>
<div class="article markdown">
<h2 id="font-class-">font-class 引用</h2>
<hr>
<p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
<p>与 Unicode 使用方式相比,具有如下特点:</p>
<ul>
<li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
<li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
</code></pre>
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;span class="iconfont icon-xxx"&gt;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"
iconfont" 是你项目下的 font-family。可以通过编辑项目查看默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-duigou_kuai"></use>
</svg>
<div class="name">对勾_块</div>
<div class="code-name">#icon-duigou_kuai</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-jinggao"></use>
</svg>
<div class="name">警告</div>
<div class="code-name">#icon-jinggao</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-gouwucheman"></use>
</svg>
<div class="name">购物车满</div>
<div class="code-name">#icon-gouwucheman</div>
</li>
</ul>
<div class="article markdown">
<h2 id="symbol-">Symbol 引用</h2>
<hr>
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
<ul>
<li>支持多色图标了,不再受单色限制。</li>
<li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
<li>兼容性较差,支持 IE9+,及现代浏览器。</li>
<li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
</code></pre>
<h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
<pre><code class="language-html">&lt;style&gt;
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
&lt;/style&gt;
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
&lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
&lt;/svg&gt;
</code></pre>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('.tab-container .content:first').show()
$('#tabs li').click(function (e) {
var tabContent = $('.tab-container .content')
var index = $(this).index()
if ($(this).hasClass('active')) {
return
} else {
$('#tabs li').removeClass('active')
$(this).addClass('active')
tabContent.hide().eq(index).fadeIn()
}
})
})
</script>
</body>
</html>

27
static/icon/iconfont.css Executable file
View File

@ -0,0 +1,27 @@
@font-face {
font-family: "iconfont"; /* Project id 3770712 */
src: url('iconfont.woff2?t=1669284444124') format('woff2'),
url('iconfont.woff?t=1669284444124') format('woff'),
url('iconfont.ttf?t=1669284444124') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-duigou_kuai:before {
content: "\ed1d";
}
.icon-jinggao:before {
content: "\eb65";
}
.icon-gouwucheman:before {
content: "\e600";
}

1
static/icon/iconfont.js Executable file
View File

@ -0,0 +1 @@
window._iconfont_svg_string_3770712='<svg><symbol id="icon-duigou_kuai" viewBox="0 0 1024 1024"><path d="M817.728 198.72l111.744 114.56-545.216 532.128-285.92-273.024 110.528-115.712 174.176 166.336z" ></path></symbol><symbol id="icon-jinggao" viewBox="0 0 1024 1024"><path d="M512 32C246.912 32 32 246.912 32 512c0 265.088 214.912 480 480 480 265.088 0 480-214.912 480-480 0-265.088-214.912-480-480-480z m0 896C282.24 928 96 741.76 96 512S282.24 96 512 96s416 186.24 416 416-186.24 416-416 416z" ></path><path d="M512 384a32 32 0 0 0-32 32v352a32 32 0 0 0 64 0V416a32 32 0 0 0-32-32z" ></path><path d="M512 272m-48 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0Z" ></path></symbol><symbol id="icon-gouwucheman" viewBox="0 0 1024 1024"><path d="M346.112 806.912q19.456 0 36.864 7.168t30.208 19.968 20.48 30.208 7.68 36.864-7.68 36.864-20.48 30.208-30.208 20.48-36.864 7.68q-20.48 0-37.888-7.68t-30.208-20.48-20.48-30.208-7.68-36.864 7.68-36.864 20.48-30.208 30.208-19.968 37.888-7.168zM772.096 808.96q19.456 0 37.376 7.168t30.72 19.968 20.48 30.208 7.68 36.864-7.68 36.864-20.48 30.208-30.72 20.48-37.376 7.68-36.864-7.68-30.208-20.48-20.48-30.208-7.68-36.864 7.68-36.864 20.48-30.208 30.208-19.968 36.864-7.168zM944.128 227.328q28.672 0 44.544 7.68t22.528 18.944 6.144 24.064-3.584 22.016-13.312 37.888-22.016 62.976-23.552 68.096-18.944 53.248q-13.312 40.96-33.28 56.832t-49.664 15.872l-35.84 0-65.536 0-86.016 0-96.256 0-253.952 0 14.336 92.16 517.12 0q49.152 0 49.152 41.984 0 20.48-9.728 35.328t-38.4 14.848l-49.152 0-94.208 0-118.784 0-119.808 0-99.328 0-55.296 0q-20.48 0-34.304-9.216t-23.04-24.064-14.848-32.256-8.704-32.768q-1.024-6.144-5.632-29.696t-11.264-58.88-14.848-78.848-16.384-87.552q-19.456-103.424-44.032-230.4l-76.8 0q-15.36 0-25.6-7.68t-16.896-18.432-9.216-23.04-2.56-22.528q0-20.48 13.824-33.792t37.376-13.312l21.504 0 21.504 0 25.6 0 34.816 0q20.48 0 32.768 6.144t19.456 15.36 10.24 19.456 5.12 17.408q2.048 8.192 4.096 23.04t4.096 30.208q3.072 18.432 6.144 38.912l700.416 0zM867.328 194.56l-374.784 0 135.168-135.168q23.552-23.552 51.712-24.064t51.712 23.04z" ></path></symbol></svg>',function(n){var t=(t=document.getElementsByTagName("script"))[t.length-1],e=t.getAttribute("data-injectcss"),t=t.getAttribute("data-disable-injectsvg");if(!t){var o,i,a,d,c,s=function(t,e){e.parentNode.insertBefore(t,e)};if(e&&!n.__iconfont__svg__cssinject__){n.__iconfont__svg__cssinject__=!0;try{document.write("<style>.svgfont {display: inline-block;width: 1em;height: 1em;fill: currentColor;vertical-align: -0.1em;font-size:16px;}</style>")}catch(t){console&&console.log(t)}}o=function(){var t,e=document.createElement("div");e.innerHTML=n._iconfont_svg_string_3770712,(e=e.getElementsByTagName("svg")[0])&&(e.setAttribute("aria-hidden","true"),e.style.position="absolute",e.style.width=0,e.style.height=0,e.style.overflow="hidden",e=e,(t=document.body).firstChild?s(e,t.firstChild):t.appendChild(e))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(o,0):(i=function(){document.removeEventListener("DOMContentLoaded",i,!1),o()},document.addEventListener("DOMContentLoaded",i,!1)):document.attachEvent&&(a=o,d=n.document,c=!1,r(),d.onreadystatechange=function(){"complete"==d.readyState&&(d.onreadystatechange=null,l())})}function l(){c||(c=!0,a())}function r(){try{d.documentElement.doScroll("left")}catch(t){return void setTimeout(r,50)}l()}}(window);

30
static/icon/iconfont.json Executable file
View File

@ -0,0 +1,30 @@
{
"id": "3770712",
"name": "no name",
"font_family": "iconfont",
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "7954334",
"name": "对勾_块",
"font_class": "duigou_kuai",
"unicode": "ed1d",
"unicode_decimal": 60701
},
{
"icon_id": "3868273",
"name": "警告",
"font_class": "jinggao",
"unicode": "eb65",
"unicode_decimal": 60261
},
{
"icon_id": "5030",
"name": "购物车满",
"font_class": "gouwucheman",
"unicode": "e600",
"unicode_decimal": 58880
}
]
}

BIN
static/icon/iconfont.ttf Executable file

Binary file not shown.

BIN
static/icon/iconfont.woff Executable file

Binary file not shown.

BIN
static/icon/iconfont.woff2 Executable file

Binary file not shown.

5
static/js/appconfig.js Executable file
View File

@ -0,0 +1,5 @@
import { createSSRApp } from "vue";
const app = createSSRApp(App);
const globals = app.config.globalProperties;
// console.log(app,'globals');
export {globals};

214
static/js/indt.ts Executable file
View File

@ -0,0 +1,214 @@
import Request_ from '../../api/request';
class _init {
// 登录完成回调(包含处理完成用户携带数据)
UserLoginInitCollback = undefined;
userInfor = {};
// 微信登录之后获取到 参数
openid : String = "";
session_key : string = "";
// Wechat = {};
// 支付宝登录之后获取到的参数
Apple = {
access_token: "0",
alipay_user_id: "0",
auth_start: "0",
expires_in: 0,
re_expires_in: 0,
refresh_token: "",
user_id: "",
};
code = '';
pay_type : number = 0;
provider : "weixin" | "qq" | "sinaweibo" | "xiaomi" | "apple" | "univerify" = 'weixin';
// 进入来源 Scan | Half
referrerInfo:'Scan' | 'Half';
// 初始参数
__programParameter__ = null;
/** 请求参数 */
APIoptions = {};
constructor(parameters) {
// #ifdef MP-ALIPAY
this['pay_type'] = 2;
// #endif
// #ifdef MP-WEIXIN
this['pay_type'] = 1;
// #endif
/**
*
*/
// parameters.referrerInfo = {
// path:"pages/index/index",
// quer:{},
// scene:1037,
// referrerInfo:{"appId":"wxc8e2e1d28d15d2e3"},
// extraData:{
// "thrust_code":"4871020984",
// code:"49750683"
// },
// mode:"embedded",
// apiCategory:"embedded"
// };
if(parameters?.referrerInfo && Object.keys(parameters['referrerInfo'])['length']){
this.referrerInfo = 'Half';
/**
*
*/
this.__programParameter__ = parameters['referrerInfo']['extraData'];
this.APIoptions = this['__programParameter__'];
}else{
this.referrerInfo = 'Scan';
/**
*
*/
this.__programParameter__ = parameters;
/**处理拿到的初始化参数 */
this.InitParam();
};
}
/** 获取来源 */
get source(){
return this['referrerInfo'];
}
// 推送播报
// Pushbroadcast(data){
// if(getApp()['globalData']['Pay_Status'] == 2) return;
// Request_.GET({ url:"/MiniProgram/Order/cancelPaymentSound", data });
// }
Login() {
let url : string = null;
// #ifdef MP-ALIPAY
url = '/MiniProgram/Api/alipayCodeLogin';
this['pay_type'] = 2;
// #endif
// #ifdef MP-WEIXIN
url = '/MiniProgram/Api/wechatCodeLogin';
this['pay_type'] = 1;
console.log(uni.login,this['provider'],'执行登录');
// #endif
uni.login({
provider: this['provider'],
success: loginRes => {
console.log(loginRes['code'], 'code---');
if (loginRes.code) {
let data = null;
// #ifdef MP-ALIPAY
console.log(loginRes['code'], 'applecode');
data = { code: loginRes['code'] };
// #endif
// #ifdef MP-WEIXIN
console.log(loginRes['code'], 'WeChatcode');
data = { code: loginRes['code'], type: 1 };
// #endif
data['thrust_code'] = this['options']['thrust_code'] || '';
data['invite_code'] = this['options']['invite_code'] || '';
// return
console.log(data,'data')
this.userInfor = data;
Request_.GET({ url, data }).then(res => {
this.userInfor = {...this['userInfor'],...res['data']}
uni.setStorageSync('token', res['data']['token']);
console.log(res, '登录信息');
// #ifdef MP-ALIPAY
// let { openid, session_key } = res['data'];
this['Apple'] = res['data'];
// #endif
// #ifdef MP-WEIXIN
let { scan_openid, session_key } = res['data'];
this['openid'] = scan_openid;
this['session_key'] = session_key;
// #endif
console.log(this['UserLoginInitCollback'], 'UserLoginInitCollback');
if (this['UserLoginInitCollback'] != null && typeof this['UserLoginInitCollback'] == 'function') {
this.UserLoginInitCollback();
}
})
} else {
uni.showToast({
title: '登录失败未获取到code',
icon: 'none',
duration: 2000
})
}
},
fail:error=>{
console.log(error,'error')
}
});
}
// 支付时获取指定平台字段
get Getopenid() {
// #ifdef MP-ALIPAY
return this['Apple']['user_id'];
// #endif
// #ifdef MP-WEIXIN
return this['openid'];
// #endif
}
get options(){
return this['APIoptions']
}
// 解析小程序初始参数
InitParam() {
console.log(this['__programParameter__'],this['source'],'__programParameter__');
// 扫码进入
if (this['__programParameter__']?.query?.q || this['__programParameter__']?.query?.scene || this['__programParameter__']?.query?.qrCode) {
let searchParamToObj = '';
searchParamToObj = this['__programParameter__']['query']?.q || this['__programParameter__']['query']?.scene || this['__programParameter__']['query']?.qrCode;
console.log(searchParamToObj, 'searchParamToObj');
const obj = {};
const Para = this.escape2Html(decodeURIComponent(searchParamToObj));
const _i = Para.indexOf('?');
console.log(Para, _i, 'Para');
if (~_i) {
const _U = Para.slice(_i + 1, Para['length']);
const _M = _U.split('&');
for (let i = 0; i < _M['length']; i++) {
const index = _M[i].indexOf("=");
console.log(index, 'index');
const KEY = _M[i].substring(0, index);
const VAL = _M[i].substring(index + 1, _M[i].length);
obj[KEY] = VAL;
};
this.APIoptions = obj;
} else {
this.APIoptions = {};
}
} else {
// 商户端扫码进入
try{
this.APIoptions = this['__programParameter__']['query'];
}catch(e){
this.APIoptions = {};
//TODO handle the exception
}
}
}
// 字符转义
escape2Html(str) {
var arrEntities = { 'lt': '<', 'gt': '>', 'nbsp': ' ', 'amp': '&', 'quot': '"' };
return str.replace(/&(lt|gt|nbsp|amp|quot);/ig, function (all, t) { return arrEntities[t]; });
};
}
export default _init;

BIN
static/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 959 B

BIN
static/success.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

28
store/getters.js Normal file
View File

@ -0,0 +1,28 @@
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
export default {
token: state => state.app.token,
isLogin: state => !!state.app.token,
backgroundColor: state => state.app.backgroundColor,
userInfo: state => state.app.userInfo || {},
uid: state => state.app.uid,
homeActive: state => state.app.homeActive,
home: state => state.app.home,
cartNum: state => state.indexData.cartNum,
activityTab: state => state.app.activityTab,
address: state => state.app.addressInfo
};
// export default {
// token: state => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJrYWlmYS5jcm1lYi5uZXQiLCJhdWQiOiJrYWlmYS5jcm1lYi5uZXQiLCJpYXQiOjE1NzcwODM1MzQsIm5iZiI6MTU3NzA4MzUzNCwiZXhwIjoxNTc3MDk0MzM0LCJqdGkiOnsiaWQiOjExMCwidHlwZSI6InVzZXIifX0.U-i1pbdRjyXI1gr79Uq2XBPZ89T8f5Ai9jwrR8woTwE',
// isLogin: state => true,
// backgroundColor: state => state.app.backgroundColor,
// userInfo: state => state.app.userInfo || {}
// };

23
store/index.js Normal file
View File

@ -0,0 +1,23 @@
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
import Vue from "vue";
import Vuex from "vuex";
import modules from "./modules";
import getters from "./getters";
Vue.use(Vuex);
const debug = process.env.NODE_ENV !== "production";
export default new Vuex.Store({
modules,
getters,
strict: debug
});

37
store/modules/app.js Normal file
View File

@ -0,0 +1,37 @@
import {
LOGIN_STATUS,
ISPAY,
UID,
USER_INFO,
USER_ADDRESS
} from '../../config/cache';
import Cache from '../../utils/cache';
const state = {
token: Cache.get(LOGIN_STATUS) || false,
ISPAY: Cache.get(ISPAY) || '',
};
const mutations = {
LOGIN(state, opt) {
state.token = opt.token;
},
UPDATE_LOGIN(state, token) {
state.token = token;
Cache.set(LOGIN_STATUS, token);
},
SETALL_PAT(state, data) {
state.ISPAY = data;
Cache.set(ISPAY, data);
}
};
const actions = {
};
export default {
state,
mutations,
actions
};

14
store/modules/index.js Normal file
View File

@ -0,0 +1,14 @@
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
import app from "./app";
export default {
app,
};

13
uni.promisify.adaptor.js Normal file
View File

@ -0,0 +1,13 @@
uni.addInterceptor({
returnValue (res) {
if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) {
return res;
}
return new Promise((resolve, reject) => {
res.then((res) => {
if (!res) return resolve(res)
return res[0] ? reject(res[0]) : resolve(res[1])
});
});
},
});

76
uni.scss Normal file
View File

@ -0,0 +1,76 @@
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场https://ext.dcloud.net.cn上很多三方插件均使用了这些样式变量
* 如果你是插件开发者建议你使用scss预处理并在插件代码中直接使用这些变量无需 import 这个文件方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者插件使用者你可以通过修改这些变量来定制自己的插件主题实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理你也可以直接在你的 scss 代码中使用如下变量同时无需 import 这个文件
*/
/* 颜色变量 */
/* 行为相关颜色 */
$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:16px;
/* 图片尺寸 */
$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;

230
utils/cache.js Normal file
View File

@ -0,0 +1,230 @@
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
import {
EXPIRE
} from '../config/app';
class Cache {
constructor(handler) {
this.cacheSetHandler = uni.setStorageSync;
this.cacheGetHandler = uni.getStorageSync;
this.cacheClearHandler = uni.removeStorageSync;
this.cacheExpire = 'UNI-APP-CRMEB:TAG';
this.clearOverdue();
}
/**
* 获取当前时间戳
*/
time() {
return Math.round(new Date() / 1000);
}
/**
* 字符串转时间戳
* @param {Object} expiresTime
*/
strTotime(expiresTime) {
let expires_time = expiresTime.substring(0, 19);
expires_time = expires_time.replace(/-/g, '/');
return Math.round(new Date(expires_time).getTime() / 1000);
}
/**
* 设置过期时间缓存
* @param {Object} key
* @param {Object} expire
*/
setExpireCaheTag(key, expire) {
expire = expire !== undefined ? expire : EXPIRE;
if (typeof expire === 'number') {
let tag = this.cacheGetHandler(this.cacheExpire),
newTag = [],
newKeys = [];
if (typeof tag === 'object' && tag.length) {
newTag = tag.map(item => {
newKeys.push(item.key);
if (item.key === key) {
item.expire = expire === 0 ? 0 : this.time() + expire;
}
return item;
});
}
if (!newKeys.length || newKeys.indexOf(key) === -1) {
newTag.push({
key: key,
expire: expire === 0 ? 0 : this.time() + expire
});
}
this.cacheSetHandler(this.cacheExpire, newTag);
}
}
/**
* 缓存是否过期,过期自动删除
* @param {Object} key
* @param {Object} $bool true = 删除,false = 不删除
*/
getExpireCahe(key, $bool) {
try {
let tag = this.cacheGetHandler(this.cacheExpire),
time = 0,
index = false;
if (typeof tag === 'object' && tag.length) {
tag.map((item, i) => {
if (item.key === key) {
time = item.expire
index = i
}
});
if (time) {
let newTime = parseInt(time);
if (time && time < this.time() && !Number.isNaN(newTime)) {
if ($bool === undefined || $bool === true) {
this.cacheClearHandler(key);
if (index !== false) {
tag.splice(index, 1)
this.cacheSetHandler(this.cacheExpire, tag);
}
}
return false;
} else
return true;
} else {
return !!this.cacheGetHandler(key);
}
}
return false;
} catch (e) {
return false;
}
}
/**
* 设置缓存
* @param {Object} key
* @param {Object} data
*/
set(key, data, expire) {
if (data === undefined) {
return true;
}
if (typeof data === 'object')
data = JSON.stringify(data);
try {
this.setExpireCaheTag(key, expire);
return this.cacheSetHandler(key, data);
} catch (e) {
return false;
}
}
/**
* 检测缓存是否存在
* @param {Object} key
*/
has(checkwhethethecacheexists, isDel) {
this.clearOverdue();
return this.getExpireCahe(checkwhethethecacheexists, isDel);
}
/**
* 获取缓存
* @param {Object} key
* @param {Object} $default
* @param {Object} expire
*/
get(key, $default, expire) {
this.clearOverdue();
try {
let isBe = this.getExpireCahe(key);
let data = this.cacheGetHandler(key);
if (data && isBe) {
if (typeof $default === 'boolean')
return JSON.parse(data);
else
return data;
} else {
if (typeof $default === 'function') {
let value = $default();
this.set(key, value, expire);
return value;
} else {
this.set(key, $default, expire);
return $default;
}
}
} catch (e) {
return null;
}
}
/**
* 删除缓存
* @param {Object} key
*/
clear(key) {
try {
let cahceValue = this.cacheGetHandler(this.cacheExpire),
index = false;
if (cahceValue && typeof cahceValue === 'object' && cahceValue.length) {
cahceValue.map((item, i) => {
if (item.key === key) {
index = i;
}
});
if (index !== false) {
cahceValue.splice(index, 1);
}
this.cacheSetHandler(this.cacheExpire, cahceValue);
}
return this.cacheClearHandler(key);
} catch (e) {
return false;
}
}
/**
* 清除过期缓存
*/
clearOverdue() {
let cahceValue = this.cacheGetHandler(this.cacheExpire),
time = this.time(),
newBeOverdueValue = [],
newTagValue = [];
if (cahceValue && typeof cahceValue === 'object' && cahceValue.length) {
cahceValue.map(item => {
if (item) {
if ((item.expire !== undefined && item.expire > time) || item.expire === 0) {
newTagValue.push(item);
} else {
newBeOverdueValue.push(item.key);
}
}
});
}
//保存没有过期的缓存标签
if (newTagValue.length !== cahceValue.length) {
this.cacheSetHandler(this.cacheExpire, newTagValue);
}
//删除过期缓存
newBeOverdueValue.forEach(k => {
this.cacheClearHandler(k);
})
}
}
export default new Cache;

87
utils/request.js Normal file
View File

@ -0,0 +1,87 @@
import {
HTTP_REQUEST_URL,
HEADER,
TOKENNAME,
TIMEOUT
} from '@/config/app';
import store from '../store';
import UrlUtils from './urlUtils.js';
/**
* 发送请求
*/
function baseRequest(url, method, data, {
noAuth = false,
noVerify = false
}) {
let Url = HTTP_REQUEST_URL;
let header = HEADER;
HEADER['form-type'] = 'gzh';
header = HEADER;
if (store.state.app.token) header[TOKENNAME] = 'Bearer ' + store.state.app.token;
return new Promise((reslove, reject) => {
if (uni.getStorageSync('locale')) {
header['Cb-lang'] = uni.getStorageSync('locale')
}
uni.request({
url: url,
method: method || 'GET',
header: header,
data: data || {},
timeout: TIMEOUT,
success: (res) => {
if (noVerify)
reslove(res.data, res);
else if (res.data.status == 200)
reslove(res.data, res);
else if ([110002, 110003, 110004].indexOf(res.data.status) !== -1) {
// #ifdef H5
window.location.replace(`${HTTP_REQUEST_URL}/api/v2/routine/gzhLogin?back_url=${encodeURIComponent(UrlUtils.keepParams(window.location.href))}`);
// #endif
reject(res.data);
} else if (res.data.status == 400 && res.data.msg !== '商户未绑定码牌') {
uni.showToast({
title: res.data.msg,
icon: 'error'
})
reject(res.data.msg || '系统错误');
} else if (res.data.status == 100103) {
uni.showModal({
title: '提示',
content: res.data.msg,
showCancel: false,
confirmText: 我知道了
});
} else
reject(res.data.msg || '系统错误');
},
fail: (msg) => {
console.log(msg)
let data = {
mag: '请求失败1',
status: 1 //1没网
}
// #ifdef APP-PLUS
reject(data);
// #endif
// #ifndef APP-PLUS
reject('请求失败');
// #endif
}
})
});
}
const request = {};
['options', 'get', 'post', 'put', 'head', 'delete', 'trace', 'connect'].forEach((method) => {
request[method] = (api, data, opt) => baseRequest(api, method, data, opt || {})
});
export default request;

77
utils/urlUtils.js Normal file
View File

@ -0,0 +1,77 @@
const UrlUtils = {
/**
* 清理URL合并多余的?规范参数分隔符
* @param {string} url - 原始URL
* @returns {string} 清理后的URL
*/
clean: function(url) {
let cleanUrl = url.replace(/\?+/g, '?');
const firstQuestionMarkIndex = cleanUrl.indexOf('?');
if (firstQuestionMarkIndex !== -1) {
const beforeParams = cleanUrl.substring(0, firstQuestionMarkIndex + 1);
const afterParams = cleanUrl.substring(firstQuestionMarkIndex + 1).replace(/\?/g, '&');
cleanUrl = beforeParams + afterParams;
}
return cleanUrl;
},
/**
* 保留URL中指定的参数默认只保留merchant_id
* @param {string} url - 原始URL
* @param {string[]} [paramsToKeep=['merchant_id']] - 需要保留的参数名数组
* @returns {string} 简化后的URL
*/
keepParams: function(url, paramsToKeep = ['merchant_id']) {
// 先清理URL
const cleanedUrl = this.clean(url);
try {
const urlObj = new URL(cleanedUrl);
const newSearchParams = new URLSearchParams();
// 遍历原始参数,只保留需要的
urlObj.searchParams.forEach((value, key) => {
if (paramsToKeep.includes(key)) {
newSearchParams.append(key, value);
}
});
// 重建URL
urlObj.search = newSearchParams.toString();
return urlObj.toString();
} catch (e) {
// 如果URL解析失败如缺少协议回退到字符串处理
const [basePart, queryPart] = cleanedUrl.split('?');
if (!queryPart) return basePart;
const keptParams = queryPart.split('&').filter(param => {
const [key] = param.split('=');
return paramsToKeep.includes(key);
});
return keptParams.length > 0
? `${basePart}?${keptParams.join('&')}`
: basePart;
}
}
};
export default UrlUtils
// // 使用示例
// const dirtyUrl = "http://10.210.254.149:8081/h5_pay/??merchant_id=1&token=xxx&expires_time=123??is_all_api=1";
// // 1. 只清理URL
// console.log(UrlUtils.clean(dirtyUrl));
// // 输出: "http://10.210.254.149:8081/h5_pay/?merchant_id=1&token=xxx&expires_time=123&is_all_api=1"
// // 2. 清理并只保留merchant_id
// console.log(UrlUtils.keepParams(dirtyUrl));
// // 输出: "http://10.210.254.149:8081/h5_pay/?merchant_id=1"
// // 3. 清理并保留多个参数
// console.log(UrlUtils.keepParams(dirtyUrl, ['merchant_id', 'expires_time']));
// // 输出: "http://10.210.254.149:8081/h5_pay/?merchant_id=1&expires_time=123"

1278
utils/util.js Normal file

File diff suppressed because it is too large Load Diff

58
utils/utils.js Normal file
View File

@ -0,0 +1,58 @@
/*
* @LastEditors: whitechiina 1293616053@qq.com
* @LastEditTime: 2025-07-31 13:42:48
*/
/**
* 获取URL参数工具函数
* @param {string|array} keys - 要获取的参数名可以是字符串或数组
* @param {any} defaultValue - 当参数不存在时的默认值
* @returns {any} 返回参数值或参数对象
*/
const getUrlParam = function(keys, defaultValue = undefined) {
// 获取原始查询字符串(包含开头的'?'
let queryString = window.location.search;
// 预处理:将第一个问号后的所有问号替换为'&'
if (queryString.includes('?')) {
// 移除开头的'?',然后处理多个问号
let queryWithoutQuestion = queryString.substring(1);
// 将多个问号替换为&
queryWithoutQuestion = queryWithoutQuestion.replace(/\?/g, '&');
queryString = '?' + queryWithoutQuestion;
}
// 解析处理后的查询字符串
const params = new URLSearchParams(queryString);
// 1. 未传入keys返回全部参数组成的对象
if (!keys) {
const result = {};
for (const [key, value] of params.entries()) {
result[key] = decodeURIComponent(value);
}
return result;
}
// 2. 传入数组:返回包含这些参数的对象
if (Array.isArray(keys)) {
return keys.reduce((result, key) => {
result[key] = params.has(key)
? decodeURIComponent(params.get(key))
: defaultValue;
return result;
}, {});
}
// 3. 传入字符串:返回单个参数值
if (typeof keys === 'string') {
return params.has(keys)
? decodeURIComponent(params.get(keys))
: defaultValue;
}
// 4. 无效keys类型返回默认值
return defaultValue;
}
export default getUrlParam;