uview-plus组件库全面升级更新,订单结算判断支付方式是否可用代码调整,公众号关注二维码修改
This commit is contained in:
@@ -94,4 +94,7 @@ page,
|
||||
}
|
||||
.u-col-center{
|
||||
align-items: center;
|
||||
}
|
||||
.justify-between{
|
||||
justify-content: space-between;
|
||||
}
|
||||
@@ -159,7 +159,7 @@ async function getHandle() {
|
||||
const res = await receivePopUp({
|
||||
getMode: props.getMode
|
||||
});
|
||||
show.value = false;
|
||||
close()
|
||||
uni.showToast({
|
||||
title: '已领取,请在我的优惠券中查看',
|
||||
icon: 'none'
|
||||
|
||||
@@ -60,7 +60,7 @@ function close() {
|
||||
emit("close");
|
||||
}
|
||||
const drainageConfig = ref({});
|
||||
onMounted(async () => {
|
||||
async function getDrainageConfig() {
|
||||
const shopId = uni.cache.get("shopId");
|
||||
const drainageConfigRes = await drainageConfigApi.config({
|
||||
shopId: shopId,
|
||||
@@ -71,7 +71,18 @@ onMounted(async () => {
|
||||
} else {
|
||||
close();
|
||||
}
|
||||
});
|
||||
}
|
||||
// onMounted(() => {
|
||||
// getDrainageConfig();
|
||||
// });
|
||||
watch(
|
||||
() => showPreview.value,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
getDrainageConfig();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- 生成公众号二维码 -->
|
||||
<we-qrcode @generate="(e) => qrcodeResult(e)"></we-qrcode>
|
||||
<officialAccount
|
||||
followIndex="eat"
|
||||
:wechatAcQrcode="wechatAcQrcode"
|
||||
v-if="showOfficialAccount"
|
||||
@close="modelClose($event, 'officialAccount')"
|
||||
/>
|
||||
@@ -9,10 +13,15 @@
|
||||
getMode="eat"
|
||||
@close="modelClose($event, 'coupon')"
|
||||
/>
|
||||
<birthdayGift v-if="showBirthdayGift" @close="modelClose($event, 'birthdayGift')" />
|
||||
<birthdayGift
|
||||
v-if="showBirthdayGift"
|
||||
@close="modelClose($event, 'birthdayGift')"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import weQrcode from "@/components/wechat-ac-qrcode.vue";
|
||||
|
||||
import { ref, watch, computed, reactive, toRaw } from "vue";
|
||||
import couponModal from "@/components/coupon-modal.vue";
|
||||
import birthdayGift from "@/components/birthday-modal.vue";
|
||||
@@ -38,4 +47,12 @@ function modelClose(e, type) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
const wechatAcQrcode = ref("");
|
||||
const userinfo = uni.cache.get("userInfo") || {};
|
||||
const codeVal = ref(userinfo.wechatAcQrcode || "");
|
||||
function qrcodeResult(e) {
|
||||
console.log("qrcodeResult", e);
|
||||
wechatAcQrcode.value = e;
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,36 +1,39 @@
|
||||
<!-- 首页优惠券弹窗 -->
|
||||
<template>
|
||||
<up-popup :show="show" bgColor="transparent" mode="center" @close="close">
|
||||
<view class="container">
|
||||
<view class="content">
|
||||
<image class="bg" :src="bgUrl" mode="widthFix"></image>
|
||||
<view class="info">
|
||||
<view class="u-flex u-row-center">
|
||||
<image
|
||||
:show-menu-by-longpress="true"
|
||||
:src="code"
|
||||
style="height: 240rpx"
|
||||
mode="heightFix"
|
||||
></image>
|
||||
<view>
|
||||
|
||||
<up-popup :show="show" bgColor="transparent" mode="center" @close="close">
|
||||
<view class="container">
|
||||
<view class="content">
|
||||
<image class="bg" :src="bgUrl" mode="widthFix"></image>
|
||||
<view class="info">
|
||||
<view class="u-flex u-row-center">
|
||||
<image
|
||||
:show-menu-by-longpress="true"
|
||||
:src="wechatAcQrcode"
|
||||
style="height: 240rpx"
|
||||
mode="heightFix"
|
||||
></image>
|
||||
</view>
|
||||
<view
|
||||
class="color-999 font-12 text-center u-m-t-10"
|
||||
style="line-height: 36rpx"
|
||||
>长按识别关注,更多优惠不能错过</view
|
||||
>
|
||||
</view>
|
||||
<view class="close" @click="close">
|
||||
<up-icon name="close-circle" size="34" color="#fff"></up-icon>
|
||||
</view>
|
||||
<view
|
||||
class="color-999 font-12 text-center u-m-t-10"
|
||||
style="line-height: 36rpx"
|
||||
>长按识别关注,更多优惠不能错过</view
|
||||
>
|
||||
</view>
|
||||
<view class="close" @click="close">
|
||||
<up-icon name="close-circle" size="34" color="#fff"></up-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</up-popup>
|
||||
</up-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import _ from "lodash";
|
||||
import dayjs from "dayjs";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { string } from "../uni_modules/uview-plus/libs/function/test";
|
||||
|
||||
const bgUrl = ref(
|
||||
"https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/4/41239c8852874aa39d1f106e45456e10.png"
|
||||
@@ -40,16 +43,31 @@ const show = ref(false);
|
||||
const code = ref(
|
||||
"https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240408/4d6e818a01f145a898d8c2368f4b5ad1.jpg"
|
||||
);
|
||||
|
||||
|
||||
const emit=defineEmits(['close'])
|
||||
const props = defineProps({
|
||||
followIndex: {
|
||||
type: string,
|
||||
default: "", // 公众号关注位置 mine-我的 order-订单 eat-就餐
|
||||
},
|
||||
wechatAcQrcode: {
|
||||
type: string,
|
||||
default: "", // 微信公众号二维码
|
||||
},
|
||||
});
|
||||
const emit = defineEmits(["close"]);
|
||||
|
||||
function close() {
|
||||
show.value = false;
|
||||
emit('close');
|
||||
emit("close");
|
||||
}
|
||||
function init() {
|
||||
const followIndex = uni.cache.get("followIndex");
|
||||
if (props.wechatAcQrcode && props.followIndex == followIndex) {
|
||||
show.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
show.value = true;
|
||||
init();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,26 +1,50 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- 生成公众号二维码 -->
|
||||
<we-qrcode @generate="(e) => qrcodeResult(e)"></we-qrcode>
|
||||
|
||||
<officialAccount
|
||||
followIndex="order"
|
||||
:wechatAcQrcode="wechatAcQrcode"
|
||||
v-if="showOfficialAccount"
|
||||
@close="modelClose($event, 'officialAccount')"
|
||||
/>
|
||||
<Drainage v-model="showDrainage" @close="modelClose($event, 'drainage')" />
|
||||
<Drainage v-model="showDrainage" @close="modelClose($event, 'drainage')" />
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import weQrcode from "@/components/wechat-ac-qrcode.vue";
|
||||
|
||||
import { ref, watch, computed, reactive, toRaw } from "vue";
|
||||
import officialAccount from "@/components/official-account.vue";
|
||||
import Drainage from "@/components/drainage.vue";
|
||||
|
||||
const showDrainage = ref(true);
|
||||
const showDrainage = defineModel({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
});
|
||||
const showOfficialAccount = ref(false);
|
||||
|
||||
function modelClose(e, type) {
|
||||
console.log("modelClose", type);
|
||||
if(type=='drainage'){
|
||||
if (type == "drainage") {
|
||||
showOfficialAccount.value = true;
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
const wechatAcQrcode = ref("");
|
||||
const userinfo = uni.cache.get("userInfo") || {};
|
||||
const codeVal = ref(userinfo.wechatAcQrcode || "");
|
||||
console.log("codeVal", codeVal.value);
|
||||
function qrcodeResult(e) {
|
||||
console.log("qrcodeResult", e);
|
||||
wechatAcQrcode.value = e;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.qrcode {
|
||||
position: fixed;
|
||||
transform: translateX(200vw, 200vh);
|
||||
}
|
||||
</style>
|
||||
@@ -48,6 +48,7 @@
|
||||
password.value += num;
|
||||
}
|
||||
if (password.value.length === 6) {
|
||||
console.log('密码输入完成:', password.value);
|
||||
emits('inputComplete', password.value);
|
||||
password.value = ''
|
||||
}
|
||||
@@ -56,7 +57,7 @@
|
||||
// 关闭模态框
|
||||
const closeModal = () => {
|
||||
emits('close');
|
||||
password = '';
|
||||
password.value = '';
|
||||
};
|
||||
// 将方法暴露给父组件
|
||||
defineExpose({
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<view class="paymentMethod_content">
|
||||
<view class="paymentMethod_title">支付方式</view>
|
||||
<up-radio-group
|
||||
v-model="radiovalue"
|
||||
v-model="radiovalue.type"
|
||||
iconPlacement="right"
|
||||
@change="groupChanges"
|
||||
:size="28"
|
||||
@@ -146,11 +146,37 @@ const paymentMethodName = ref([
|
||||
},
|
||||
]);
|
||||
|
||||
const radiovalue = ref(2); // 支付方式
|
||||
// const radiovalue = ref(2); // 支付方式
|
||||
const radiovalue = defineModel({
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
name: "微信支付",
|
||||
type: 2,
|
||||
url: "https://czg-qr-order.oss-cn-beijing.aliyuncs.com/confirmOrder/weChat.png",
|
||||
payType: "wechatPay",
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const ispws = ref(false); // 输入支付密码
|
||||
watch(
|
||||
() => props.disablePayType,
|
||||
(newval) => {
|
||||
console.log('禁止支付方式', newval);
|
||||
|
||||
const storeInfo = ref({});
|
||||
const canUsePayType = paymentMethodList.value.filter((item) => {
|
||||
return !newval.includes(item.name);
|
||||
});
|
||||
console.log('可用支付方式', canUsePayType);
|
||||
if (canUsePayType.find((v) => v.type == radiovalue.value.type)) {
|
||||
return;
|
||||
}
|
||||
radiovalue.value = canUsePayType[0];
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
// * 监听支付方式切换
|
||||
const groupChanges = (type) => {
|
||||
@@ -158,8 +184,6 @@ const groupChanges = (type) => {
|
||||
return;
|
||||
}
|
||||
const item = paymentMethodList.value.find((v) => v.type == type);
|
||||
console.log("groupChanges", item);
|
||||
console.log("props.disablePayType", props.disablePayType);
|
||||
|
||||
if (item && returnDisabled(item)) {
|
||||
uni.showToast({
|
||||
@@ -171,9 +195,7 @@ const groupChanges = (type) => {
|
||||
// if (props.payAmount <= 0 && type != 1) {
|
||||
// return;
|
||||
// }
|
||||
radiovalue.value = type;
|
||||
let name = paymentMethodName.value[type - 1].name;
|
||||
console.log('emit:groupChange',paymentMethodName.value[type - 1]);
|
||||
radiovalue.value = item;
|
||||
emits("groupChange", paymentMethodName.value[type - 1]);
|
||||
};
|
||||
|
||||
@@ -182,15 +204,18 @@ const goRecharge = () => {
|
||||
if (props.disablePayType.includes("余额支付")) {
|
||||
return;
|
||||
}
|
||||
if (orderVIP.value.isVip) {
|
||||
uni.navigateTo({
|
||||
url: "/pages/user/member/czzx?shopId=" + orderVIP.value.shopId,
|
||||
});
|
||||
return;
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: "/user/vip/buy-vip?shopId=" + orderVIP.value.shopId,
|
||||
url: "/pages/user/member/czzx?shopId=" + orderVIP.value.shopId,
|
||||
});
|
||||
// if (orderVIP.value.isVip) {
|
||||
// uni.navigateTo({
|
||||
// url: "/pages/user/member/czzx?shopId=" + orderVIP.value.shopId,
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
// uni.navigateTo({
|
||||
// url: "/user/vip/buy-vip?shopId=" + orderVIP.value.shopId,
|
||||
// });
|
||||
|
||||
// uni.pro.navigateTo('user/member/index', {
|
||||
// shopId: orderVIP.value.shopId
|
||||
|
||||
41
components/wechat-ac-qrcode.vue
Normal file
41
components/wechat-ac-qrcode.vue
Normal file
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- 生成公众号二维码 -->
|
||||
|
||||
<view class="qrcode-box" v-if="codeOptions.code">
|
||||
<w-qrcode
|
||||
:options="codeOptions"
|
||||
ref="wQrcode"
|
||||
@generate="(e) => qrcodeResult(e)"
|
||||
></w-qrcode>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import wQrcode from "@/uni_modules/wmf-code/components/w-qrcode/w-qrcode.vue";
|
||||
import { onMounted ,ref} from "vue";
|
||||
const codeOptions = ref({
|
||||
size: 200,
|
||||
code: "",
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
// 页面加载完成后生成二维码
|
||||
const userInfo = uni.cache.get("userInfo") || {};
|
||||
const wechatAcQrcode = userInfo.wechatAcQrcode || "";
|
||||
codeOptions.value.code = wechatAcQrcode;
|
||||
});
|
||||
const emit = defineEmits(["generate"]);
|
||||
function qrcodeResult(e) {
|
||||
console.log(e);
|
||||
emit("generate", e.img.tempFilePath);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.qrcode-box {
|
||||
position: fixed;
|
||||
transform: translateX(200vw, 200vh);
|
||||
}
|
||||
</style>
|
||||
@@ -201,7 +201,7 @@
|
||||
></u-image>
|
||||
</view>
|
||||
<text class="name u-m-l-16 no-wrap"> {{ item.name }} </text>
|
||||
<template v-if="item.type == 'points' && !disabledPointsUse">
|
||||
<template v-if="item.type == 'points' && !pointObj.disabled">
|
||||
<text
|
||||
class="u-p-l-6"
|
||||
style="color: #666; max-width: 400rpx; font-size: 10px"
|
||||
@@ -227,8 +227,8 @@
|
||||
<template v-else>
|
||||
<text
|
||||
class="favorable_right_text red"
|
||||
v-if="disabledCouponUse"
|
||||
>{{ disabledCouponReason }}</text
|
||||
v-if="couponObj.disabled"
|
||||
>{{ couponObj.disabledReason }}</text
|
||||
>
|
||||
<text
|
||||
class="favorable_right_text red"
|
||||
@@ -239,7 +239,7 @@
|
||||
>暂无可用优惠券</text
|
||||
>
|
||||
</template>
|
||||
<template v-if="!disabledCouponUse">
|
||||
<template v-if="!couponObj.disabled">
|
||||
<up-icon
|
||||
name="arrow-right"
|
||||
color="#575B66"
|
||||
@@ -268,10 +268,10 @@
|
||||
v-if="item.type == 'points'"
|
||||
>
|
||||
<text
|
||||
v-if="disabledPointsUse"
|
||||
v-if="pointObj.disabled"
|
||||
class="u-p-l-6 red"
|
||||
style="max-width: 400rpx; font-size: 24rpx"
|
||||
>{{ disabledPointsUseReason }}</text
|
||||
style="max-width: 440rpx; font-size: 24rpx"
|
||||
>{{ pointObj.disabledReason }}</text
|
||||
>
|
||||
<template
|
||||
v-else-if="
|
||||
@@ -290,7 +290,7 @@
|
||||
|
||||
<template v-else>
|
||||
<view
|
||||
v-if="maxPointDiscount > 0 && !disabledPointsUse"
|
||||
v-if="maxPointDiscount > 0 && !pointObj.disabled"
|
||||
class="u-flex u-col-center"
|
||||
>
|
||||
<view class="round"></view>
|
||||
@@ -517,13 +517,67 @@ const discountActivityRes = ref(null);
|
||||
const discountActivity = ref(null);
|
||||
//备份当前使用的满减活动的门槛满减
|
||||
let back_discountActivity = null;
|
||||
//禁止使用优惠券
|
||||
const disabledCouponUse = ref(false);
|
||||
const disabledCouponReason = ref("");
|
||||
//禁止使用积分
|
||||
const disabledPointsUse = ref(false);
|
||||
//禁止使用积分原因
|
||||
const disabledPointsUseReason = ref("");
|
||||
|
||||
const couponObj = computed(() => {
|
||||
const obj = {
|
||||
disabled: false,
|
||||
disabledReason: "",
|
||||
};
|
||||
const freeDineConfig = props.orderVIP.freeDineConfig;
|
||||
if (props.isBwc && freeDineConfig.enable) {
|
||||
//使用了霸王餐
|
||||
if (!freeDineConfig.withCoupon) {
|
||||
obj.disabled = true;
|
||||
obj.disabledReason = "霸王餐与优惠券不可同时使用";
|
||||
}
|
||||
}
|
||||
//使用了满减活动
|
||||
const res = discountActivityRes.value;
|
||||
|
||||
if (discountActivity.value && res) {
|
||||
if (!res.couponShare) {
|
||||
obj.disabled = true;
|
||||
obj.disabledReason = "当前满减活动不可与其他优惠共享";
|
||||
}
|
||||
}
|
||||
if (obj.disabled) {
|
||||
cartStore.backendCoupons = [];
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
|
||||
const pointObj = computed(() => {
|
||||
const obj = {
|
||||
disabled: false,
|
||||
disabledReason: "",
|
||||
};
|
||||
const freeDineConfig = props.orderVIP.freeDineConfig;
|
||||
if (props.isBwc && freeDineConfig.enable) {
|
||||
//使用了霸王餐
|
||||
if (!freeDineConfig.withPoints) {
|
||||
obj.disabled = true;
|
||||
obj.disabledReason = "霸王餐与积分不可同时使用";
|
||||
}
|
||||
}
|
||||
//使用了满减活动
|
||||
const res = discountActivityRes.value;
|
||||
if (discountActivity.value && res) {
|
||||
if (!res.pointsShare) {
|
||||
obj.disabled = true;
|
||||
obj.disabledReason = "当前满减活动不可与积分同享";
|
||||
}
|
||||
}
|
||||
|
||||
//积分抵扣不足
|
||||
if (pointsRes && !pointsRes.usable) {
|
||||
obj.disabledReason = pointsRes.unusableReason || "积分抵扣不足或不可用";
|
||||
}
|
||||
if (obj.disabled) {
|
||||
cartStore.setUserPoints(0);
|
||||
}
|
||||
|
||||
return obj;
|
||||
});
|
||||
|
||||
// 监听送餐/打包切换
|
||||
const tabClick = (item, index) => {
|
||||
@@ -534,10 +588,7 @@ const tabClick = (item, index) => {
|
||||
};
|
||||
cartStore.setDinnerType(tebtypeList[is_type.value].val);
|
||||
|
||||
// 操作优惠卷
|
||||
const dataprocessing = (data) => {
|
||||
favorablelist.value[1].value = data;
|
||||
};
|
||||
|
||||
|
||||
// 清空
|
||||
const bwcclear = () => {
|
||||
@@ -556,20 +607,19 @@ const goUrl = (item) => {
|
||||
|
||||
switch (item.type) {
|
||||
case "coupon":
|
||||
if (disabledCouponUse.value) {
|
||||
if (couponObj.value.disabled) {
|
||||
return uni.showToast({
|
||||
title: disabledCouponReason.value,
|
||||
title: couponObj.value.disabledReason,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
emits("learcoupons", "coupon");
|
||||
uni.pro.navigateTo("/pages/order/coupon", {});
|
||||
break;
|
||||
|
||||
case "points":
|
||||
if (disabledPointsUse.value) {
|
||||
if (pointObj.value.disabled) {
|
||||
return uni.showToast({
|
||||
title: disabledPointsUseReason.value,
|
||||
title: pointObj.value.disabledReason,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
@@ -598,31 +648,36 @@ const maxPointDiscount = ref(0);
|
||||
//积分可抵扣最大金额
|
||||
const maxMoney = computed(() => {
|
||||
return (
|
||||
cartStore.orderCostSummary.finalPayAmount +
|
||||
cartStore.orderCostSummary.orderOriginFinalPayAmount +
|
||||
cartStore.orderCostSummary.pointDeductionAmount
|
||||
);
|
||||
});
|
||||
|
||||
async function getMaxPointsDiscount() {
|
||||
if (!props.orderVIP.id) {
|
||||
return;
|
||||
}
|
||||
let res = await APImemberPointscalcUsablePoints({
|
||||
shopUserId: props.orderVIP.id,
|
||||
orderAmount: maxMoney.value,
|
||||
});
|
||||
if(res){
|
||||
if (res) {
|
||||
cartStore.setPointDeductionRule(
|
||||
res.equivalentPoints,
|
||||
res.maxDeductionAmount
|
||||
res.equivalentPoints || 0,
|
||||
res.maxDeductionAmount || 0
|
||||
);
|
||||
}
|
||||
Object.assign(pointsRes, res);
|
||||
|
||||
maxPointDiscount.value = res.maxDeductionAmount;
|
||||
maxPointDiscount.value = res.maxDeductionAmount || 0;
|
||||
console.log("积分可抵扣最大金额", maxPointDiscount.value);
|
||||
console.log("是否可以用积分", usePoints.value);
|
||||
if (usePoints.value) {
|
||||
|
||||
if (usePoints.value && res.usable) {
|
||||
console.log("积分抵扣金额", res.maxDeductionAmount);
|
||||
cartStore.setUserPoints(res.maxUsablePoints || 0);
|
||||
}
|
||||
if (!res.usable) {
|
||||
cartStore.setUserPoints(0);
|
||||
}
|
||||
}
|
||||
watch(
|
||||
() => maxMoney.value,
|
||||
@@ -680,7 +735,6 @@ const copyHandle = (e) => {
|
||||
|
||||
// 将方法暴露给父组件
|
||||
defineExpose({
|
||||
dataprocessing,
|
||||
getCalcUsablePoints,
|
||||
bwcclear,
|
||||
IntegralInputclose,
|
||||
@@ -746,8 +800,7 @@ const originalPrice = computed(() => {
|
||||
-cartStore.orderCostSummary.newUserDiscount +
|
||||
cartStore.orderCostSummary.packFee +
|
||||
cartStore.orderCostSummary.seatFee;
|
||||
console.log("originalPrice", originalPrice);
|
||||
return originalPrice;
|
||||
return originalPrice <= 0 ? 0 : originalPrice;
|
||||
});
|
||||
|
||||
watch(
|
||||
@@ -766,28 +819,9 @@ watch(
|
||||
if (newval) {
|
||||
discountActivity.value = null;
|
||||
cartStore.fullReductionActivities = [];
|
||||
if (!freeDineConfig.withCoupon) {
|
||||
disabledCouponUse.value = true;
|
||||
disabledCouponReason.value = "霸王餐与优惠券不可同时使用";
|
||||
cartStore.setCoupons([]);
|
||||
} else {
|
||||
disabledCouponUse.value = false;
|
||||
disabledCouponReason.value = "";
|
||||
}
|
||||
if (!freeDineConfig.withPoints) {
|
||||
disabledPointsUse.value = true;
|
||||
disabledPointsUseReason.value = "霸王餐与积分不可同时使用";
|
||||
usePoints.value = false;
|
||||
cartStore.setUserPoints(0);
|
||||
} else {
|
||||
disabledPointsUse.value = false;
|
||||
disabledPointsUseReason.value = "";
|
||||
}
|
||||
usePoints.value = false;
|
||||
cartStore.setUserPoints(0);
|
||||
} else {
|
||||
disabledPointsUse.value = false;
|
||||
disabledPointsUseReason.value = "";
|
||||
disabledCouponUse.value = false;
|
||||
disabledCouponReason.value = "";
|
||||
if (back_discountActivity) {
|
||||
calcDiscountActivity();
|
||||
}
|
||||
@@ -824,17 +858,7 @@ function calcDiscountActivity() {
|
||||
return;
|
||||
}
|
||||
console.log("当前满减门槛", discountActivity.value);
|
||||
if (!res.couponShare) {
|
||||
disabledCouponUse.value = true;
|
||||
cartStore.backendCoupons = [];
|
||||
disabledCouponReason.value = "当前满减活动不可与其他优惠共享";
|
||||
}
|
||||
//不与积分同享
|
||||
if (!res.pointsShare && discountActivity.value) {
|
||||
disabledPointsUse.value = true;
|
||||
disabledPointsUseReason.value = "当前满减活动不与积分同享";
|
||||
cartStore.setUserPoints(0);
|
||||
}
|
||||
|
||||
if (discountActivity.value) {
|
||||
cartStore.fullReductionActivities = [discountActivityRes.value];
|
||||
}
|
||||
|
||||
@@ -77,7 +77,6 @@
|
||||
:ordershopUserInfo="ordershopUserInfo"
|
||||
@istype="istype"
|
||||
@clickPointsamount="clickPointsamount"
|
||||
@learcoupons="learcoupons"
|
||||
:isBwc="isBwc"
|
||||
>
|
||||
</orderInfo>
|
||||
@@ -106,9 +105,15 @@
|
||||
</rechargeFree>
|
||||
|
||||
<!-- 充值享优惠 -->
|
||||
<view v-if="!showFreeDine && (listinfo.status == 'unpaid' || !listinfo.id)">
|
||||
<view
|
||||
v-if="
|
||||
!showFreeDine &&
|
||||
(listinfo.status == 'unpaid' || !listinfo.id) &&
|
||||
cartStore.orderCostSummary.finalPayAmount > 0
|
||||
"
|
||||
>
|
||||
<ChargeVue
|
||||
@updateChargeSel="updateChargeSel"
|
||||
@updateChargeSel="(e) => updateChargeSel(e)"
|
||||
@updateRechargeId="updateRechargeId"
|
||||
v-if="listinfo.status == 'unpaid' || !listinfo.id"
|
||||
></ChargeVue>
|
||||
@@ -120,6 +125,7 @@
|
||||
@groupChange="groupChange"
|
||||
:disablePayType="disablePayType"
|
||||
:changeFreeenable="isBwc"
|
||||
v-model="paymentmethod"
|
||||
v-if="listinfo.status == 'unpaid' || !listinfo.id"
|
||||
>
|
||||
</paymentMethodes>
|
||||
@@ -160,7 +166,7 @@
|
||||
shape="circle"
|
||||
v-if="listinfo.id && listinfo.status == 'unpaid'"
|
||||
plain
|
||||
@tap="cancelOrder"
|
||||
@tap="cancelOrder()"
|
||||
:custom-style="customStyle"
|
||||
>
|
||||
<view class="u-flex u-flex-y-center">
|
||||
@@ -200,7 +206,7 @@
|
||||
</template>
|
||||
</view>
|
||||
<view class="fixedview_tow" @tap="$u.debounce(istoricalorders, 1000)">
|
||||
{{ paymentmethod.paymentBtnText }}
|
||||
{{ paymentmethod.name }}
|
||||
</view>
|
||||
<!-- <view class="fixedview_tows" @tap="$u.debounce(APIputuserorderclick,1000)">
|
||||
取消订单
|
||||
@@ -212,34 +218,19 @@
|
||||
<payPassword
|
||||
ref="payPasswordref"
|
||||
:isShow="ispws"
|
||||
@inputComplete="accountPayevent"
|
||||
@inputComplete="(e) => accountPayevent(e)"
|
||||
@close="ispws = false"
|
||||
/>
|
||||
<!-- 私域引流配置 -->
|
||||
<OrderFinshModal v-if="showDrainage"></OrderFinshModal>
|
||||
<OrderFinshModal v-model="showDrainage" ></OrderFinshModal>
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { back } from "@/utils/uniapp.js";
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import { BigNumber } from "bignumber.js";
|
||||
import ChargeVue from "./components/charge.vue";
|
||||
import { pay } from "@/utils/pay.js";
|
||||
import Drainage from "@/components/drainage.vue";
|
||||
import * as drainageConfigApi from "@/common/api/market/drainageConfig.js";
|
||||
import OrderFinshModal from "@/components/order-finish-modal.vue";
|
||||
|
||||
function onback() {
|
||||
closeSocket();
|
||||
back();
|
||||
}
|
||||
const customStyle = {
|
||||
width: "180rpx",
|
||||
height: "70rpx",
|
||||
background: "FFFFFF",
|
||||
"border-radius": "106rpx",
|
||||
border: "2rpx solid #E8AD7B",
|
||||
};
|
||||
import _ from "lodash";
|
||||
import {
|
||||
ref,
|
||||
@@ -247,12 +238,12 @@ import {
|
||||
computed,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
watchEffect,
|
||||
nextTick,
|
||||
watch,
|
||||
onBeforeMount,
|
||||
onBeforeUnmount,
|
||||
} from "vue";
|
||||
|
||||
import { getTableInfo } from "@/common/api/shop/index.js";
|
||||
import {
|
||||
APIgetOrderById,
|
||||
@@ -269,9 +260,21 @@ import {
|
||||
import { useCartsStore } from "@/stores/carts.js";
|
||||
import { useWebSocket } from "@/stores/carts-websocket.js";
|
||||
|
||||
function onback() {
|
||||
closeSocket();
|
||||
console.log("返回");
|
||||
back();
|
||||
}
|
||||
const customStyle = {
|
||||
width: "180rpx",
|
||||
height: "70rpx",
|
||||
background: "FFFFFF",
|
||||
"border-radius": "106rpx",
|
||||
border: "2rpx solid #E8AD7B",
|
||||
};
|
||||
|
||||
const cartStore = useCartsStore();
|
||||
|
||||
const disablePayType = ref([]);
|
||||
//充值相关
|
||||
const rechargeItem = ref({
|
||||
id: "",
|
||||
@@ -285,32 +288,6 @@ function updateRechargeId(e) {
|
||||
function updateChargeSel(newval) {
|
||||
rechargeItem.value = newval;
|
||||
console.log("updateChargeSel", newval);
|
||||
//充值并付款时只能微信支付
|
||||
if (newval && newval.id) {
|
||||
disablePayType.value = ["余额支付"];
|
||||
paymentMethodref.value.groupChanges(2);
|
||||
return;
|
||||
}
|
||||
console.log("orderVIP.value.amount", orderVIP.value.amount);
|
||||
if (!orderVIP.value.amount) {
|
||||
disablePayType.value = ["余额支付"];
|
||||
if (paymentMethodref.value) {
|
||||
paymentMethodref.value.groupChanges(2);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (orderVIP.value.amount < newval) {
|
||||
disablePayType.value = ["余额支付"];
|
||||
if (paymentMethodref.value) {
|
||||
paymentMethodref.value.groupChanges(2);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (cartStore.orderCostSummary.orderOriginFinalPayAmount <= 0) {
|
||||
disablePayType.value = ["微信支付"];
|
||||
} else {
|
||||
disablePayType.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
async function onMessage(Message) {
|
||||
@@ -386,7 +363,6 @@ function youhuiReset() {
|
||||
listinfo.pointsNum = 0;
|
||||
listinfo.pointsDiscountAmount = 0;
|
||||
listinfo.Productroll = 0;
|
||||
uniqueIds.value = [];
|
||||
try {
|
||||
orderInfoAfterRef.value?.IntegralInputclose();
|
||||
} catch {}
|
||||
@@ -437,7 +413,6 @@ const listinfo = reactive({
|
||||
packFeess: 0,
|
||||
totalPrices: 0,
|
||||
Seatcharge: 0,
|
||||
pointsNum: 0,
|
||||
id: null,
|
||||
});
|
||||
|
||||
@@ -544,82 +519,17 @@ function getOrderInfoAfterCalcInit(res) {
|
||||
// },1000)
|
||||
}
|
||||
|
||||
// 监听价格算法
|
||||
watchEffect(async () => {
|
||||
if (listinfo.combinedArray.length > 0 || cartStore.carts.length > 0) {
|
||||
// 打包费packFeess 计算购物车商品费用totalPrices 餐位费Seatcharge
|
||||
// try {
|
||||
let historyOrderPackFee = is_type.value != 0 ? listinfo.packFeess : 0;
|
||||
let nowCartPackFee = is_type.value != 0 ? cartStore.totalPackFee * 1 : 0;
|
||||
let seatFee = is_type.value == 0 ? listinfo.Seatcharge : 0;
|
||||
let sum =
|
||||
cartStore.totalPackFee * 1 +
|
||||
historyOrderPackFee +
|
||||
listinfo.totalPrices +
|
||||
seatFee;
|
||||
listinfo.originAmount = Math.round(sum * 100) / 100;
|
||||
|
||||
// 打包费packFeess 计算购物车商品费用totalPrices 餐位费Seatcharge 商品卷Productroll 优惠卷coupondiscountAmount 积分listinfo.pointsDiscountAmount
|
||||
let sums =
|
||||
nowCartPackFee +
|
||||
historyOrderPackFee +
|
||||
listinfo.totalPrices +
|
||||
seatFee -
|
||||
(listinfo.Productroll || 0) -
|
||||
(listinfo.coupondiscountAmount || 0) -
|
||||
(listinfo.pointsDiscountAmount || 0);
|
||||
listinfo.totalCost = Math.round(sums * 100) / 100;
|
||||
|
||||
// 总价格
|
||||
// console.log(listinfo.combinedArray, listinfo.packFeess, listinfo.totalPrices, listinfo
|
||||
// .Seatcharge, listinfo.Productroll, listinfo.coupondiscountAmount, sums) // 霸王餐
|
||||
// console.log(orderVIP.value.freeDineConfig.enable, changeFreeenable.value)
|
||||
if (orderVIP.value.freeDineConfig.enable && isBwc.value) {
|
||||
listinfo.totalCost = (
|
||||
parseFloat(listinfo.totalCost) *
|
||||
parseFloat(orderVIP.value.freeDineConfig.rechargeTimes)
|
||||
).toFixed(2);
|
||||
}
|
||||
// 积分
|
||||
if (
|
||||
listinfo.totalCost &&
|
||||
(listinfo.status == "unpaid" || !listinfo.id) &&
|
||||
orderVIP.value.id
|
||||
) {
|
||||
uni.$u.debounce(memberPointscalcUsablePoints, 500);
|
||||
}
|
||||
// } catch (error) {
|
||||
// //TODO handle the exception
|
||||
// }
|
||||
}
|
||||
});
|
||||
|
||||
const changeFree = (e) => {
|
||||
if (JSON.stringify(e) == "{}") {
|
||||
return;
|
||||
}
|
||||
isBwc.value = e;
|
||||
cartStore.isFreeDine = e;
|
||||
if (e) {
|
||||
disablePayType.value = ["余额支付"];
|
||||
} else {
|
||||
disablePayType.value = [];
|
||||
}
|
||||
orderInfoAfterRef.value.bwcclear();
|
||||
uniqueIds.value = []; // 筛选出商品卷的id
|
||||
listinfo.coupondiscountAmount = 0; // 优惠卷减去的金额
|
||||
listinfo.pointsNum = 0; // 商品卷总价价格
|
||||
// 商品价格
|
||||
// listinfo.totalPrices = cartStore.getTotalTotalPrices(
|
||||
// listinfo.combinedArray,
|
||||
// isBwc.value
|
||||
// );
|
||||
console.log("changeFree", e);
|
||||
|
||||
// 支付方式切换
|
||||
// #ifdef MP-WEIXIN
|
||||
paymentMethodref.value.groupChanges(2);
|
||||
// #endif
|
||||
// #ifdef MP-ALIPAY
|
||||
paymentMethodref.value.groupChanges(3);
|
||||
// #endif
|
||||
};
|
||||
|
||||
@@ -637,71 +547,35 @@ const saveImage = (url) => {
|
||||
|
||||
//
|
||||
const paymentMethodref = ref(null);
|
||||
|
||||
// 支付方式切换
|
||||
const paymentmethod = reactive({
|
||||
radiovalue: 2,
|
||||
paymentBtnText: "微信支付",
|
||||
const paymentmethod = ref({});
|
||||
// 支付方式
|
||||
// #ifdef MP-WEIXIN
|
||||
paymentmethod.value = {
|
||||
name: "微信支付",
|
||||
type: 2,
|
||||
url: "https://czg-qr-order.oss-cn-beijing.aliyuncs.com/confirmOrder/weChat.png",
|
||||
payType: "wechatPay",
|
||||
});
|
||||
};
|
||||
// #endif
|
||||
// #ifdef MP-ALIPAY
|
||||
paymentmethod.value = {
|
||||
name: "支付宝支付",
|
||||
type: 3,
|
||||
url: "https://czg-qr-order.oss-cn-beijing.aliyuncs.com/confirmOrder/alipay.png",
|
||||
payType: "aliPay",
|
||||
};
|
||||
// #endif
|
||||
|
||||
const groupChange = async (e) => {
|
||||
if (e == 5) {
|
||||
return;
|
||||
}
|
||||
console.log("groupChange", e);
|
||||
paymentmethod.radiovalue = e.type;
|
||||
paymentmethod.paymentBtnText = e.name;
|
||||
paymentmethod.payType = e.payType;
|
||||
paymentmethod.value = e;
|
||||
};
|
||||
|
||||
// 操作下单时候
|
||||
const orderInfoAfterRef = ref(null);
|
||||
|
||||
// 商品卷的id储存
|
||||
const uniqueIds = ref([]);
|
||||
|
||||
// 这是优惠卷传的值
|
||||
const handleReturnData = async (data) => {
|
||||
// 这是优惠卷
|
||||
if (data.typeOrder == 1) {
|
||||
if (data.item) {
|
||||
// 优惠卷减去的金额
|
||||
listinfo.coupondiscountAmount = data.item.discountAmount;
|
||||
uniqueIds.value.push(data.item.id);
|
||||
orderInfoAfterRef.value.dataprocessing(data);
|
||||
}
|
||||
} else {
|
||||
// 筛选出商品卷的id
|
||||
// 商品卷总价价格
|
||||
// uniqueIds.value = [...uniqueIds.value, ...new Set(data.map(item => item.id))]
|
||||
uniqueIds.value = [...uniqueIds.value, ...data.map((item) => item.id)];
|
||||
console.log(uniqueIds.value);
|
||||
listinfo.Productroll = cartStore.getTotalProductroll(data).value;
|
||||
// TODO handle the exception
|
||||
let res = {
|
||||
Productroll: listinfo.Productroll,
|
||||
uniqueIds: uniqueIds.value.length,
|
||||
};
|
||||
orderInfoAfterRef.value.dataprocessing(res);
|
||||
}
|
||||
};
|
||||
|
||||
const learcoupons = (data) => {
|
||||
if (data == "product") {
|
||||
uniqueIds.value = []; // 筛选出商品卷的id
|
||||
listinfo.coupondiscountAmount = 0; // 优惠卷减去的金额
|
||||
listinfo.Productroll = 0; // 商品卷总价价格
|
||||
listinfo.pointsNum = 0; // 积分总价格
|
||||
} else {
|
||||
// 每次点击优惠卷删除优惠卷里的id
|
||||
if (listinfo.coupondiscountAmount != 0) {
|
||||
uniqueIds.value.pop();
|
||||
}
|
||||
listinfo.coupondiscountAmount = 0; // 优惠卷减去的金额
|
||||
}
|
||||
};
|
||||
|
||||
//取消订单
|
||||
const cancelOrder = async () => {
|
||||
uni.showModal({
|
||||
@@ -821,7 +695,9 @@ function returnPayParams() {
|
||||
cartStore.orderCostSummary.productCouponDeduction, //商品优惠券抵扣金额
|
||||
otherCouponDiscountAmount: cartStore.orderCostSummary.fullCouponDeduction, //其他优惠券抵扣金额
|
||||
couponList: cartStore.backendCoupons.map((v) => v.id), //用户使用的卡券
|
||||
orderAmount:isBwc.value? cartStore.orderCostSummary.orderOriginFinalPayAmount: cartStore.orderCostSummary.finalPayAmount, // 最终订单金额
|
||||
orderAmount: isBwc.value
|
||||
? cartStore.orderCostSummary.orderOriginFinalPayAmount
|
||||
: cartStore.orderCostSummary.finalPayAmount, // 最终订单金额
|
||||
roundAmount: 0, //抹零金额 减免多少钱
|
||||
pointsDiscountAmount: cartStore.orderCostSummary.pointDeductionAmount, //积分抵扣金额(tb_points_basic_setting表)
|
||||
pointsNum: cartStore.orderCostSummary.pointUsed, //(扣除各类折扣 enable_deduction后使用)
|
||||
@@ -837,7 +713,7 @@ function returnPayParams() {
|
||||
return {
|
||||
isBwc: isBwc.value,
|
||||
checkOrderPay,
|
||||
payType: paymentmethod.payType,
|
||||
payType: paymentmethod.value.payType,
|
||||
buyerRemark: "",
|
||||
returnUrl: "",
|
||||
rechargeId: rechargeId.value,
|
||||
@@ -926,7 +802,7 @@ const istoricalorders = async () => {
|
||||
// * 去支付
|
||||
const goToPay = async (payParams) => {
|
||||
console.log("goToPay:payParams", payParams);
|
||||
|
||||
|
||||
// 余额支付
|
||||
if (payParams.payType == "accountPay") {
|
||||
if (orderVIP.value.payPwd == "") {
|
||||
@@ -1035,22 +911,7 @@ const goToPay = async (payParams) => {
|
||||
orderorderInfo();
|
||||
};
|
||||
|
||||
//002-获取订单可用积分及抵扣金额(支付页面使用)
|
||||
const memberPointscalcUsablePoints = async () => {
|
||||
let res = await APImemberPointscalcUsablePoints({
|
||||
shopUserId: orderVIP.value.id,
|
||||
orderAmount: listinfo.totalCost,
|
||||
});
|
||||
console.log('获取订单可用积分及抵扣金额(支付页面使用)')
|
||||
if(res){
|
||||
cartStore.setPointDeductionRule(
|
||||
res.equivalentPoints,
|
||||
res.maxDeductionAmount
|
||||
);
|
||||
}
|
||||
|
||||
orderInfoAfterRef.value?.getCalcUsablePoints(res);
|
||||
};
|
||||
//
|
||||
const clickPointsamount = (Pointsamount) => {
|
||||
listinfo.pointsDiscountAmount = Pointsamount.pointsDiscountAmount;
|
||||
@@ -1060,6 +921,10 @@ const clickPointsamount = (Pointsamount) => {
|
||||
const payPasswordref = ref(null);
|
||||
// 余额支付
|
||||
const accountPayevent = async (pwd) => {
|
||||
console.log("账户支付", pwd);
|
||||
if (JSON.stringify(pwd) === "{}") {
|
||||
return;
|
||||
}
|
||||
const payParams = returnPayParams();
|
||||
ispws.value = false;
|
||||
payParams.checkOrderPay.userId = uni.cache.get("userInfo").id;
|
||||
@@ -1079,46 +944,8 @@ const accountPayevent = async (pwd) => {
|
||||
}
|
||||
orderorderInfo();
|
||||
};
|
||||
watch(
|
||||
() => cartStore.orderCostSummary.orderOriginFinalPayAmount,
|
||||
(newval) => {
|
||||
console.log("orderOriginFinalPayAmount", newval);
|
||||
if (newval <= 0) {
|
||||
disablePayType.value = ["微信支付"];
|
||||
paymentMethodref.value.groupChanges(1);
|
||||
}
|
||||
if (
|
||||
newval <= 0 ||
|
||||
newval < orderVIP.value.freeDineConfig.rechargeThreshold
|
||||
) {
|
||||
isBwc.value = false;
|
||||
showFreeDine.value = false;
|
||||
return;
|
||||
}
|
||||
disablePayType.value = [];
|
||||
|
||||
if (
|
||||
(listinfo.status == "unpaid" || !listinfo.id) &&
|
||||
orderVIP.value.freeDineConfig.enable &&
|
||||
newval >= orderVIP.value.freeDineConfig.rechargeThreshold
|
||||
) {
|
||||
showFreeDine.value = true;
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => isBwc.value,
|
||||
(newval) => {
|
||||
cartStore.isFreeDine = newval;
|
||||
}
|
||||
);
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
uni.$off("returnData", handleReturnData);
|
||||
clearTimeout(backtimer);
|
||||
clearInterval(payStatusTimer);
|
||||
closeSocket();
|
||||
@@ -1153,7 +980,6 @@ onShow(() => {
|
||||
uni.$off("selCoupon");
|
||||
uni.$on("selCoupon", function (data) {
|
||||
console.log("selCoupon", data);
|
||||
orderInfoAfterRef.value.dataprocessing(_.cloneDeep(data));
|
||||
cartStore.setCoupons(_.cloneDeep(data));
|
||||
});
|
||||
});
|
||||
@@ -1161,6 +987,7 @@ let options = {};
|
||||
|
||||
// 跳转到加菜页面
|
||||
function toJiacai() {
|
||||
console.log("跳转到加菜页面");
|
||||
back();
|
||||
return;
|
||||
uni.navigateTo({
|
||||
@@ -1200,6 +1027,7 @@ const navTitle = computed(() => {
|
||||
|
||||
//支付成功后的处理
|
||||
function paySucessCallback() {
|
||||
console.log("paySucessCallback");
|
||||
showDrainage.value = true;
|
||||
}
|
||||
|
||||
@@ -1208,6 +1036,8 @@ const drainageConfig = ref({});
|
||||
//私域引流弹窗
|
||||
const showDrainage = ref(false);
|
||||
async function init(opt) {
|
||||
await storeuser.actionsproductqueryProduct();
|
||||
|
||||
console.log("init");
|
||||
cartStore.clearOrderConfig();
|
||||
Object.assign(options, opt);
|
||||
@@ -1216,7 +1046,6 @@ async function init(opt) {
|
||||
if (options.shopId) {
|
||||
// 每次进来全局更新shopId
|
||||
uni.cache.set("shopId", options.shopId, 30);
|
||||
uni.$on("returnData", handleReturnData);
|
||||
}
|
||||
//如果已经生成订单,根据历史订信息设置相关配置
|
||||
if (options.orderId) {
|
||||
@@ -1242,7 +1071,6 @@ async function init(opt) {
|
||||
}
|
||||
await cartStore.goodsInit();
|
||||
// * 获取会员信息
|
||||
await storeuser.actionsproductqueryProduct();
|
||||
await nextTick();
|
||||
|
||||
orderVIP.value = uni.cache.get("orderVIP");
|
||||
@@ -1257,6 +1085,78 @@ async function init(opt) {
|
||||
onLoad((opt) => {
|
||||
init(opt);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => cartStore.orderCostSummary.orderOriginFinalPayAmount,
|
||||
(newval) => {
|
||||
if (
|
||||
!orderVIP.value.freeDineConfig ||
|
||||
!orderVIP.value.freeDineConfig.enable
|
||||
) {
|
||||
//未开始霸王餐后面代码不执行
|
||||
isBwc.value = false;
|
||||
showFreeDine.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const bwc_fullaniunt_money =
|
||||
newval + cartStore.orderCostSummary.fullReduction.actualAmount;
|
||||
if (
|
||||
bwc_fullaniunt_money <= 0 ||
|
||||
bwc_fullaniunt_money < orderVIP.value.freeDineConfig.rechargeThreshold
|
||||
) {
|
||||
isBwc.value = false;
|
||||
showFreeDine.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
(listinfo.status == "unpaid" || !listinfo.id) &&
|
||||
orderVIP.value.freeDineConfig.enable &&
|
||||
bwc_fullaniunt_money >= orderVIP.value.freeDineConfig.rechargeThreshold
|
||||
) {
|
||||
showFreeDine.value = true;
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => isBwc.value,
|
||||
(newval) => {
|
||||
cartStore.isFreeDine = newval;
|
||||
}
|
||||
);
|
||||
|
||||
const disablePayType = computed(() => {
|
||||
const arr = new Set([]);
|
||||
if (isBwc.value) {
|
||||
if (cartStore.orderCostSummary.orderOriginFinalPayAmount <= 0) {
|
||||
arr.add("微信支付");
|
||||
} else {
|
||||
arr.add("余额支付");
|
||||
}
|
||||
}
|
||||
//充值并付款时只能微信支付
|
||||
if (rechargeItem.value.id) {
|
||||
arr.add("余额支付");
|
||||
}
|
||||
if (!orderVIP.value.amount) {
|
||||
arr.add("余额支付");
|
||||
}
|
||||
if (
|
||||
orderVIP.value.amount < cartStore.orderCostSummary.orderOriginFinalPayAmount
|
||||
) {
|
||||
arr.add("余额支付");
|
||||
}
|
||||
if (cartStore.orderCostSummary.orderOriginFinalPayAmount <= 0) {
|
||||
arr.add("微信支付");
|
||||
}
|
||||
|
||||
return Array.from(arr);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -225,7 +225,6 @@ export const useCartsStore = defineStore("cart", () => {
|
||||
}
|
||||
}
|
||||
allGoods.value = getAllGoodsList();
|
||||
console.log("allGoods.value ", allGoods.value);
|
||||
goodsIsloading.value = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ export const Storelogin = defineStore('login', {
|
||||
this.userInfo = res.userInfo
|
||||
uni.cache.set('token', res.token);
|
||||
uni.cache.set('userInfo', res.userInfo);
|
||||
uni.cache.set('followIndex', res.followIndex||'');
|
||||
}
|
||||
resolve(true);
|
||||
},
|
||||
|
||||
49
uni_modules/lime-qrcode/changelog.md
Normal file
49
uni_modules/lime-qrcode/changelog.md
Normal file
@@ -0,0 +1,49 @@
|
||||
## 0.2.4(2025-09-22)
|
||||
- fix: uniappx ios报错
|
||||
## 0.2.3(2025-06-13)
|
||||
- fix: 修复uniapp x 安卓问题
|
||||
## 0.2.2(2025-06-13)
|
||||
- fix: 修复uniapp x ios问题
|
||||
## 0.2.1(2025-05-24)
|
||||
- feat: 支持uniapp x 鸿蒙next
|
||||
## 0.2.0(2025-02-09)
|
||||
- chore: 更新文档
|
||||
## 0.1.9(2024-11-24)
|
||||
- feat: 支持uniapp x 微信小程序
|
||||
## 0.1.8(2024-08-05)
|
||||
- fix: 修复因shared升级导致微信小程序可能不生效的问题
|
||||
## 0.1.7(2024-05-15)
|
||||
- fix: 修复uvue因缺少依赖无法使用
|
||||
## 0.1.6(2024-05-09)
|
||||
- fix: 修复vue2因type问题导致无法使用
|
||||
## 0.1.5(2024-04-14)
|
||||
- fix: 修复缺少依赖
|
||||
## 0.1.4(2024-04-10)
|
||||
- chore: 更新文档
|
||||
## 0.1.3(2024-04-01)
|
||||
- chore: 兼容uniapp x ios(app-js)
|
||||
## 0.1.2(2023-12-14)
|
||||
- fix: uvue 引入 API 自定义包出错
|
||||
## 0.1.1(2023-12-11)
|
||||
- chore: uvue的二维码API独立,需要单独下载
|
||||
## 0.1.0(2023-12-07)
|
||||
- fix: 修复因utssdk目录导致无法运行
|
||||
## 0.0.9(2023-12-06)
|
||||
- feat: 支持uvue
|
||||
## 0.0.8(2023-12-06)
|
||||
- feat: 支持uvue
|
||||
## 0.0.7(2023-12-06)
|
||||
- feat: 支持uvue
|
||||
## 0.0.6(2023-12-06)
|
||||
- feat: 支持uvue
|
||||
## 0.0.5(2023-07-30)
|
||||
- fix: 修复再次生成前没有清空,导致图形叠加
|
||||
## 0.0.4(2023-07-27)
|
||||
- fix: 修复相同尺寸无法再次生成
|
||||
## 0.0.3(2023-06-09)
|
||||
- feat: 支持通过`@vue/composition-api`在`vue2`上使用
|
||||
- chore: 更新文档
|
||||
## 0.0.2(2023-06-08)
|
||||
- chore: 更新文档
|
||||
## 0.0.1(2023-06-08)
|
||||
- 首次
|
||||
180
uni_modules/lime-qrcode/components/l-qrcode/ios/index.uts
Normal file
180
uni_modules/lime-qrcode/components/l-qrcode/ios/index.uts
Normal file
@@ -0,0 +1,180 @@
|
||||
// export * from '../qrcode'
|
||||
import { qrcodegen } from './qrcodegen'
|
||||
|
||||
// export * from '@/uni_modules/lime-qrcodegen/utssdk/interface';
|
||||
// import { type QRCodePropsTypes , type ImageSettings, type QRCodeCallback } from '@/uni_modules/lime-qrcodegen/utssdk/interface'
|
||||
export type QRCodePropsTypes = {
|
||||
value?: string
|
||||
size?: number
|
||||
fgColor?: string
|
||||
level?: string
|
||||
marginSize: number
|
||||
includeMargin: boolean
|
||||
imageSettings?: ImageSettings
|
||||
}
|
||||
export type ImageSettings = {
|
||||
width: number
|
||||
height: number
|
||||
x?: number
|
||||
y?: number
|
||||
src?: string
|
||||
excavate: boolean
|
||||
}
|
||||
export type QRCodeCallback = (cells : boolean[][]) => void
|
||||
|
||||
|
||||
const Ecc = qrcodegen.QrCode.Ecc
|
||||
const QrCode = qrcodegen.QrCode
|
||||
type Modules = boolean[][];
|
||||
type Excavation = { x : number; y : number; w : number; h : number };
|
||||
type ImageSettingExcavation = {
|
||||
x: number
|
||||
y: number
|
||||
h: number
|
||||
w: number
|
||||
excavation: Excavation
|
||||
}
|
||||
const ERROR_LEVEL_MAP = {
|
||||
L: Ecc.LOW,
|
||||
M: Ecc.MEDIUM,
|
||||
Q: Ecc.QUARTILE,
|
||||
H: Ecc.HIGH,
|
||||
};
|
||||
|
||||
const DEFAULT_SIZE:number = 128;
|
||||
const DEFAULT_LEVEL:string = 'L';
|
||||
// const DEFAULT_BGCOLOR:string = '#FFFFFF';
|
||||
const DEFAULT_FGCOLOR:string = '#000000';
|
||||
const DEFAULT_INCLUDEMARGIN:boolean = false;
|
||||
|
||||
const SPEC_MARGIN_SIZE : number = 4;
|
||||
const DEFAULT_MARGIN_SIZE : number = 0;
|
||||
|
||||
// This is *very* rough estimate of max amount of QRCode allowed to be covered.
|
||||
// It is "wrong" in a lot of ways (area is a terrible way to estimate, it
|
||||
// really should be number of modules covered), but if for some reason we don't
|
||||
// get an explicit height or width, I'd rather default to something than throw.
|
||||
const DEFAULT_IMG_SCALE = 0.1;
|
||||
|
||||
// We could just do this in generatePath, except that we want to support
|
||||
// non-Path2D canvas, so we need to keep it an explicit step.
|
||||
function excavateModules(modules : Modules, excavation : Excavation) : Modules {
|
||||
const ox = excavation.x
|
||||
const oy = excavation.y
|
||||
const oh = excavation.h
|
||||
const ow = excavation.w
|
||||
return modules.slice().map((row, y):boolean[] => {
|
||||
if (y < oy || y >= oy + oh) {
|
||||
return row;
|
||||
}
|
||||
return row.map((cell, x):boolean => {
|
||||
if (x < ox || x >= ox + ow) {
|
||||
return cell;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getImageSettings(
|
||||
cells : Modules,
|
||||
size : number,
|
||||
margin : number,
|
||||
imageSettings: ImageSettings | null
|
||||
) : ImageSettingExcavation | null {
|
||||
if (imageSettings == null) {
|
||||
return null;
|
||||
}
|
||||
// const result : UTSJSONObject = {}
|
||||
const numCells = cells.length + margin * 2;
|
||||
const defaultSize = Math.floor(size * DEFAULT_IMG_SCALE);
|
||||
const scale = numCells / size;
|
||||
|
||||
const width = imageSettings.width
|
||||
const height = imageSettings.height
|
||||
const ox = imageSettings.x
|
||||
const oy = imageSettings.y
|
||||
const excavate = imageSettings.excavate
|
||||
|
||||
const w = (width > 0 ? width : defaultSize) * scale;
|
||||
const h = (height > 0 ? height: defaultSize) * scale;
|
||||
const x = ox == null ? cells.length / 2 - w / 2 : ox * scale;
|
||||
const y = oy == null ? cells.length / 2 - h / 2 : oy * scale;
|
||||
|
||||
let excavation: Excavation = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 0,
|
||||
h: 0,
|
||||
};
|
||||
if (excavate) {
|
||||
let floorX = Math.floor(x);
|
||||
let floorY = Math.floor(y);
|
||||
let ceilW = Math.ceil(w + x - floorX);
|
||||
let ceilH = Math.ceil(h + y - floorY);
|
||||
// excavation = { x: floorX, y: floorY, w: ceilW, h: ceilH };
|
||||
excavation.x = floorX
|
||||
excavation.y = floorY
|
||||
excavation.w = ceilW
|
||||
excavation.h = ceilH
|
||||
}
|
||||
|
||||
return { x, y, h, w, excavation } as ImageSettingExcavation;
|
||||
}
|
||||
function getMarginSize(includeMargin : boolean, marginSize: number|null) : number {
|
||||
if (marginSize != null) {
|
||||
return Math.floor(marginSize);
|
||||
}
|
||||
return includeMargin ? SPEC_MARGIN_SIZE : DEFAULT_MARGIN_SIZE;
|
||||
}
|
||||
export class QRCodeCanvas {
|
||||
ctx : DrawableContext
|
||||
constructor(ctx : DrawableContext) {
|
||||
this.ctx = ctx
|
||||
}
|
||||
render(props : QRCodePropsTypes, cb : QRCodeCallback | null=null) {
|
||||
const ctx = this.ctx
|
||||
const value = props.value
|
||||
const size = props.size ?? DEFAULT_SIZE
|
||||
const level = props.level ?? DEFAULT_LEVEL
|
||||
const fgColor = props.fgColor ?? DEFAULT_FGCOLOR
|
||||
const includeMargin = props.includeMargin || DEFAULT_INCLUDEMARGIN
|
||||
const marginSize = props.marginSize
|
||||
const imageSettings = props.imageSettings
|
||||
if (value == null || value == '') {
|
||||
return;
|
||||
}
|
||||
let cells = QrCode.encodeText(value, ERROR_LEVEL_MAP[level] as Ecc).getModules();
|
||||
const margin = getMarginSize(includeMargin, marginSize);
|
||||
const numCells = cells.length + margin * 2;
|
||||
const scale = (size / numCells);
|
||||
const calculatedImageSettings = getImageSettings(
|
||||
cells,
|
||||
size,
|
||||
margin,
|
||||
imageSettings
|
||||
)
|
||||
const haveImageToRender = calculatedImageSettings != null
|
||||
const excavation: Excavation | null = haveImageToRender ? calculatedImageSettings?.excavation : null
|
||||
|
||||
if(haveImageToRender && excavation != null) {
|
||||
cells = excavateModules(cells, excavation);
|
||||
}
|
||||
ctx.reset()
|
||||
// ctx.clearRect(0, 0, size, size)
|
||||
// ctx.fillStyle = bgColor;
|
||||
// ctx.fillRect(0, 0, numCells, numCells);
|
||||
ctx.fillStyle = fgColor;
|
||||
cells.forEach(function (row, rdx) {
|
||||
row.forEach(function (cell, cdx) {
|
||||
if (cell) {
|
||||
ctx.fillRect((cdx + margin) * scale, (rdx + margin) * scale, scale, scale);
|
||||
}
|
||||
});
|
||||
});
|
||||
ctx.update()
|
||||
if(cb != null){
|
||||
cb(cells)
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
300
uni_modules/lime-qrcode/components/l-qrcode/l-qrcode.uvue
Normal file
300
uni_modules/lime-qrcode/components/l-qrcode/l-qrcode.uvue
Normal file
@@ -0,0 +1,300 @@
|
||||
<template>
|
||||
<!-- #ifndef APP || WEB -->
|
||||
<canvas :style="styles" v-if="use2d" type="2d" :canvas-id="canvasId" :id="canvasId"></canvas>
|
||||
<canvas :style="styles" v-else :canvas-id="canvasId" :id="canvasId"></canvas>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP -->
|
||||
<view class="l-qrcode" ref="drawableRef" :style="[styles]">
|
||||
<image class="l-qrcode__icon" v-if="icon" :src="icon" :style="[iconStyle]"></image>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef WEB -->
|
||||
<view class="l-qrcode" ref="drawableRef" :style="[styles]"></view>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
<script lang="uts" setup>
|
||||
/**
|
||||
* QRCode 二维码组件
|
||||
* @description 用于生成二维码图形,支持自定义图标和样式配置
|
||||
* <br>插件类型:LQrcodeComponentPublicInstance
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?name=lime-qrcode
|
||||
*
|
||||
* @property {string} value 二维码内容(支持文本/URL等)
|
||||
* @property {string} icon 中心图标路径(支持本地/网络路径)
|
||||
* @property {number | string} size 二维码尺寸
|
||||
* @property {number | string} iconSize 中心图标尺寸
|
||||
* @property {number} marginSize 二维码外边距(默认:0)
|
||||
* @property {string} color 二维码颜色(默认:#000000)
|
||||
* @property {string} bgColor 背景颜色(默认:#ffffff)
|
||||
* @property {boolean} bordered 显示边框(默认:false)
|
||||
* @property {'L' | 'M' | 'Q' | 'H'} errorLevel 容错等级(默认:'H')
|
||||
* @value L 可恢复7%的数据
|
||||
* @value M 可恢复15%的数据
|
||||
* @value Q 可恢复25%的数据
|
||||
* @value H 可恢复30%的数据
|
||||
* @property {boolean} useCanvasToTempFilePath 使用canvas生成临时路径(H5端可能需要)
|
||||
* @property {boolean} use2d 启用2D上下文渲染(性能优化,默认:false)
|
||||
*/
|
||||
import { type PropType, nextTick } from 'vue'
|
||||
// #ifndef APP
|
||||
import { createImage } from '@/uni_modules/lime-shared/createImage'
|
||||
import { getCanvas, isCanvas2d } from './useCanvas'
|
||||
import { QRCodeCanvas } from './qrcode.js';
|
||||
import { QRCodePropsTypes , ImageSettings } from './type'
|
||||
// #endif
|
||||
// #ifdef APP-ANDROID || APP-HARMONY
|
||||
import { QRCodeCanvas, type QRCodePropsTypes , type ImageSettings } from '@/uni_modules/lime-qrcodegen'
|
||||
// #endif
|
||||
// #ifdef APP-IOS
|
||||
import { QRCodeCanvas, type QRCodePropsTypes , type ImageSettings } from './ios'
|
||||
// #endif
|
||||
// import { addUnit } from '@/uni_modules/lime-shared/addUnit'
|
||||
// import { unitConvert } from '@/uni_modules/lime-shared/unitConvert'
|
||||
// import { toBoolean } from '@/uni_modules/lime-shared/toBoolean'
|
||||
import { addUnit, unitConvert } from './utils'
|
||||
import { LQrcodeFailCallback, LQrcodeCompleteCallback, LQrcodeSuccessCallback} from './type'
|
||||
|
||||
const name = 'l-qrcode'
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: String
|
||||
},
|
||||
icon: {
|
||||
type: String
|
||||
},
|
||||
// #ifdef APP-ANDROID
|
||||
size: {
|
||||
type: Object,
|
||||
default: 160
|
||||
},
|
||||
iconSize: {
|
||||
type: Object,
|
||||
default: 40
|
||||
},
|
||||
// #endif
|
||||
// #ifndef APP-ANDROID
|
||||
size: {
|
||||
type: [Number, String],
|
||||
default: 160
|
||||
},
|
||||
iconSize: {
|
||||
type: [Number, String],
|
||||
default: 40
|
||||
},
|
||||
// #endif
|
||||
marginSize: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '#000'
|
||||
},
|
||||
bgColor: {
|
||||
type: String,
|
||||
default: 'transparent'
|
||||
},
|
||||
bordered: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
errorLevel: {
|
||||
type: String as PropType<'L' | 'M' | 'Q' | 'H'>,
|
||||
default: 'M' // 'L' | 'M' | 'Q' | 'H'
|
||||
},
|
||||
useCanvasToTempFilePath: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
use2d: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
// status: {
|
||||
// type: String as PropType<'active'|'expired'|'loading'>,
|
||||
// default: 'active' // active | expired | loading
|
||||
// }
|
||||
})
|
||||
const emits = defineEmits(['success'])
|
||||
const context = getCurrentInstance();
|
||||
const canvasId = `l-qrcode${context!.uid}`
|
||||
const styles = computed<Map<string, any>>(():Map<string, any>=>{
|
||||
const style = new Map<string, any>()
|
||||
const size = addUnit(props.size);
|
||||
if(size!=null){
|
||||
style.set('width', size)
|
||||
style.set('height', size)
|
||||
}
|
||||
style.set('background', props.bgColor)
|
||||
return style
|
||||
})
|
||||
// #ifdef APP
|
||||
const iconStyle = computed<Map<string, any>>(():Map<string, any>=>{
|
||||
const style = new Map<string, any>()
|
||||
const size = addUnit(props.iconSize);
|
||||
// if(size!=null){
|
||||
style.set('width', size)
|
||||
style.set('height', size)
|
||||
// }
|
||||
return style
|
||||
})
|
||||
// #endif
|
||||
const drawableRef = ref<UniElement|null>(null);
|
||||
// #ifndef APP
|
||||
let canvas:HTMLCanvasElement|null = null
|
||||
// #endif
|
||||
let qrcode:QRCodeCanvas|null = null
|
||||
|
||||
const canvasToTempFilePath = (options: UTSJSONObject)=>{
|
||||
const format = options.getString('format') ?? 'png';
|
||||
const fail = options.get('fail') as LQrcodeFailCallback | null;
|
||||
const complete = options.get('complete') as LQrcodeCompleteCallback | null;
|
||||
const success = options.get('success') as LQrcodeSuccessCallback | null;
|
||||
// #ifdef APP
|
||||
const newOptions = {
|
||||
format,
|
||||
fail,
|
||||
complete,
|
||||
success,
|
||||
} as TakeSnapshotOptions
|
||||
drawableRef.value!.takeSnapshot(newOptions)
|
||||
// #endif
|
||||
// #ifdef WEB
|
||||
success?.({
|
||||
tempFilePath: canvas?.toDataURL('image/'+format)
|
||||
})
|
||||
// #endif
|
||||
|
||||
}
|
||||
const render = ()=>{
|
||||
const param:QRCodePropsTypes = {
|
||||
value: props.value,
|
||||
size: unitConvert(props.size),
|
||||
fgColor: props.color,
|
||||
level: ['L', 'M', 'Q', 'H'].includes(props.errorLevel) ? props.errorLevel : 'M',
|
||||
marginSize: props.marginSize,
|
||||
includeMargin: props.bordered,
|
||||
imageSettings: null,
|
||||
} as QRCodePropsTypes
|
||||
// #ifdef APP-HARMONY
|
||||
param.value = props.value
|
||||
param.size = unitConvert(props.size)
|
||||
param.fgColor = props.color
|
||||
param.level = ['L', 'M', 'Q', 'H'].includes(props.errorLevel) ? props.errorLevel : 'M'
|
||||
param.marginSize = props.marginSize
|
||||
param.includeMargin = props.bordered
|
||||
param.imageSettings = null
|
||||
// #endif
|
||||
if(props.icon != null){
|
||||
// if(toBoolean(props.iconSize) && toBoolean(props.icon)){
|
||||
const size = unitConvert(props.iconSize)
|
||||
param.imageSettings = {
|
||||
src: props.icon,
|
||||
width: size,
|
||||
height: size,
|
||||
excavate: true
|
||||
} as ImageSettings
|
||||
|
||||
// #ifdef APP-HARMONY
|
||||
param.imageSettings.src = props.icon
|
||||
param.imageSettings.width = size
|
||||
param.imageSettings.height = size
|
||||
param.imageSettings.excavate = true
|
||||
// #endif
|
||||
}
|
||||
qrcode?.render(param)
|
||||
if(props.useCanvasToTempFilePath){
|
||||
setTimeout(()=>{
|
||||
canvasToTempFilePath({
|
||||
success: (res: TakeSnapshotSuccess)=>{
|
||||
emits('success', res.tempFilePath)
|
||||
}
|
||||
})
|
||||
},100)
|
||||
}
|
||||
}
|
||||
defineExpose({
|
||||
canvasToTempFilePath
|
||||
})
|
||||
onMounted(()=>{
|
||||
nextTick(()=>{
|
||||
// #ifdef APP
|
||||
requestAnimationFrame(()=> {
|
||||
drawableRef.value?.getBoundingClientRectAsync()?.then(res => {
|
||||
const ctx = drawableRef.value!.getDrawableContext();
|
||||
qrcode = new QRCodeCanvas(ctx!)
|
||||
watchEffect(()=>{
|
||||
render()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// #endif
|
||||
// #ifdef WEB
|
||||
canvas = document.createElement('canvas')
|
||||
canvas!.style.width = '100%'
|
||||
canvas!.style.height = '100%'
|
||||
drawableRef.value!.appendChild(canvas!)
|
||||
qrcode = new QRCodeCanvas(canvas, {
|
||||
pixelRatio: uni.getSystemInfoSync().pixelRatio,
|
||||
createImage: () => {
|
||||
const image = new Image();
|
||||
// @ts-ignore
|
||||
image.crossOrigin = 'anonymous';
|
||||
return image;
|
||||
}
|
||||
})
|
||||
watchEffect(()=>{
|
||||
render()
|
||||
})
|
||||
// #endif
|
||||
// #ifndef APP || WEB
|
||||
getCanvas(canvasId, { context }).then(res => {
|
||||
canvas = res;
|
||||
qrcode = new QRCodeCanvas(res, {
|
||||
path2D: false,
|
||||
pixelRatio: isCanvas2d && props.use2d ? uni.getSystemInfoSync().pixelRatio : 1,
|
||||
createImage
|
||||
})
|
||||
watchEffect(()=>{
|
||||
render()
|
||||
})
|
||||
})
|
||||
// #endif
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
onUnmounted(()=>{
|
||||
// #ifdef WEB
|
||||
canvas?.remove();
|
||||
// #endif
|
||||
qrcode = null;
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.l-qrcode {
|
||||
position: relative;
|
||||
background-color: aqua;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&-mask {
|
||||
position: absolute;
|
||||
// inset: 0;
|
||||
// inset-block-start: 0;
|
||||
// inset-inline-start: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
// width: 100%;
|
||||
// height: 100%;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
line-height: 1.5714285714285714;
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
249
uni_modules/lime-qrcode/components/l-qrcode/l-qrcode.vue
Normal file
249
uni_modules/lime-qrcode/components/l-qrcode/l-qrcode.vue
Normal file
@@ -0,0 +1,249 @@
|
||||
<template>
|
||||
<view class="l-qrcode" :style="[styles]">
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<canvas :style="styles" v-if="use2d" type="2d" :canvas-id="canvasId" :id="canvasId"></canvas>
|
||||
<canvas :style="styles" v-else :canvas-id="canvasId" :id="canvasId"></canvas>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<web-view
|
||||
ref="qrcodeRef"
|
||||
@pagefinish="onFinished"
|
||||
@error="onError"
|
||||
@onPostMessage="onMessage"
|
||||
:style="styles" src="/uni_modules/lime-qrcode/hybrid/html/index.html?v=1"></web-view>
|
||||
<!-- #endif -->
|
||||
<!-- <view class="l-qrcode-mask" v-if="['loading', 'expired'].includes(props.status)">
|
||||
<l-loading v-if="props.status == 'loading'"></l-loading>
|
||||
<view class="l-qrcode-expired" v-if="props.status == 'expired'">
|
||||
<slot></slot>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* QRCode 二维码组件
|
||||
* @description 用于生成二维码图形,支持自定义图标和样式配置
|
||||
* <br>插件类型:LQrcodeComponentPublicInstance
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?name=lime-qrcode
|
||||
*
|
||||
* @property {string} value 二维码内容(支持文本/URL等)
|
||||
* @property {string} icon 中心图标路径(支持本地/网络路径)
|
||||
* @property {number | string} size 二维码尺寸
|
||||
* @property {number | string} iconSize 中心图标尺寸
|
||||
* @property {number} marginSize 二维码外边距(默认:0)
|
||||
* @property {string} color 二维码颜色(默认:#000000)
|
||||
* @property {string} bgColor 背景颜色(默认:#ffffff)
|
||||
* @property {boolean} bordered 显示边框(默认:false)
|
||||
* @property {'L' | 'M' | 'Q' | 'H'} errorLevel 容错等级(默认:'H')
|
||||
* @value L 可恢复7%的数据
|
||||
* @value M 可恢复15%的数据
|
||||
* @value Q 可恢复25%的数据
|
||||
* @value H 可恢复30%的数据
|
||||
* @property {boolean} useCanvasToTempFilePath 使用canvas生成临时路径(H5端可能需要)
|
||||
* @property {boolean} use2d 启用2D上下文渲染(性能优化,默认:false)
|
||||
*/
|
||||
import { computed, defineComponent, getCurrentInstance, watch, onUnmounted, onMounted } from '@/uni_modules/lime-shared/vue';
|
||||
import QRCodeProps from './props'
|
||||
// #ifndef APP-NVUE
|
||||
import { getCanvas, isCanvas2d } from './useCanvas'
|
||||
import { QRCodeCanvas } from './qrcode.js';
|
||||
// #endif
|
||||
import { addUnit } from '@/uni_modules/lime-shared/addUnit'
|
||||
import { createImage } from '@/uni_modules/lime-shared/createImage'
|
||||
import { unitConvert } from '@/uni_modules/lime-shared/unitConvert'
|
||||
import { isBase64 } from '@/uni_modules/lime-shared/isBase64'
|
||||
import { pathToBase64 } from '@/uni_modules/lime-shared/pathToBase64'
|
||||
import { debounce } from '@/uni_modules/lime-shared/debounce'
|
||||
const name = 'l-qrcode'
|
||||
export default defineComponent({
|
||||
name,
|
||||
props: QRCodeProps,
|
||||
emits: ['success'],
|
||||
setup(props, {emit}) {
|
||||
const context = getCurrentInstance();
|
||||
const canvasId = `l-qrcode${context.uid}`
|
||||
const styles = computed(() => `width: ${addUnit(props.size)}; height: ${addUnit(props.size)};`)
|
||||
let qrcode = null
|
||||
let canvas = null
|
||||
const qrCodeProps = computed(() => {
|
||||
const { value, icon, size, color, bgColor, bordered, iconSize, errorLevel, marginSize } = props
|
||||
const imageSettings = {
|
||||
src: icon,
|
||||
x: undefined,
|
||||
y: undefined,
|
||||
height: unitConvert(iconSize),
|
||||
width: unitConvert(iconSize),
|
||||
excavate: true,
|
||||
}
|
||||
return {
|
||||
value,
|
||||
size: unitConvert(size),
|
||||
level: errorLevel,
|
||||
bgColor,
|
||||
fgColor: color,
|
||||
imageSettings: icon ? imageSettings : undefined,
|
||||
includeMargin: bordered,
|
||||
marginSize: marginSize ?? 0
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
// #ifdef APP-NVUE
|
||||
const stacks = new Map()
|
||||
// #endif
|
||||
const canvasToTempFilePath = debounce((args: UniNamespace.CanvasToTempFilePathRes) => {
|
||||
if(!canvas) return
|
||||
// #ifndef APP-NVUE
|
||||
const copyArgs = Object.assign({
|
||||
canvasId,
|
||||
canvas: null
|
||||
}, args)
|
||||
|
||||
if (isCanvas2d && props.use2d) {
|
||||
// copyArgs.canvas = canvas
|
||||
const tempFilePath = canvas.toDataURL();
|
||||
copyArgs.success({
|
||||
tempFilePath
|
||||
})
|
||||
return
|
||||
}
|
||||
if ('toTempFilePath' in canvas) {
|
||||
canvas.toTempFilePath(copyArgs)
|
||||
} else {
|
||||
uni.canvasToTempFilePath(copyArgs, context);
|
||||
}
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
if(!stacks.size) {
|
||||
const flie = 'file-' + Math.random();
|
||||
const stack = {args, time: +new Date()}
|
||||
stacks.set(`${flie}`, stack)
|
||||
canvas.toDataURL(flie)
|
||||
setTimeout(() => {
|
||||
const stack = stacks.get(flie)
|
||||
if(stack && 'fail' in stack.args) {
|
||||
stack.args.fail({
|
||||
error: '超时'
|
||||
})
|
||||
stacks.delete(flie)
|
||||
}
|
||||
},5000)
|
||||
}
|
||||
// #endif
|
||||
})
|
||||
const useCanvasToTempFilePath = () => {
|
||||
if(props.useCanvasToTempFilePath) {
|
||||
canvasToTempFilePath({
|
||||
success(res: UniNamespace.CanvasToTempFilePathRes) {
|
||||
emit('success', res.tempFilePath)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
// #ifdef APP-NVUE
|
||||
const onFinished = () => {
|
||||
const { pixelRatio } = uni.getSystemInfoSync()
|
||||
canvas = {
|
||||
toDataURL(flie: string) {
|
||||
const ref: any = context.refs['qrcodeRef'];
|
||||
if(ref) {
|
||||
ref?.evalJS(`toDataURL('${flie}')`)
|
||||
}
|
||||
}
|
||||
};
|
||||
qrcode = {
|
||||
async render(props: any) {
|
||||
const ref: any = context.refs['qrcodeRef'];
|
||||
const { src } = props.imageSettings || { };
|
||||
if(!ref) return
|
||||
if(src && !isBase64(src) && !/^http/.test(src) && /^\/static/.test(src)) {
|
||||
props.imageSettings.src = await pathToBase64(src)
|
||||
}
|
||||
const _props = JSON.stringify(Object.assign({}, props, {pixelRatio}));
|
||||
ref?.evalJS(`render(${_props})`);
|
||||
}
|
||||
}
|
||||
qrcode.render(qrCodeProps.value)
|
||||
useCanvasToTempFilePath()
|
||||
}
|
||||
const onError = () => {
|
||||
console.warn('lime-qrcode 加载失败')
|
||||
}
|
||||
const onMessage = (e: any) => {
|
||||
const {detail:{data: [res]}} = e
|
||||
if(res.event == 'toDataURL') {
|
||||
const {file, image, msg} = res.data;
|
||||
const stack = stacks.get(file)
|
||||
if(stack && image && 'success' in stack.args) {
|
||||
stack.args.success({tempFilePath: image})
|
||||
stacks.delete(file)
|
||||
} else if(stack && 'fails' in stack.args) {
|
||||
stack.args.fail({error: msg})
|
||||
stacks.delete(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
const propsWatch = watch(props, () => {
|
||||
if (qrcode) {
|
||||
qrcode.render(qrCodeProps.value)
|
||||
useCanvasToTempFilePath()
|
||||
}
|
||||
})
|
||||
onMounted(() => {
|
||||
// #ifndef APP-NVUE
|
||||
getCanvas(canvasId, { context }).then(res => {
|
||||
canvas = res;
|
||||
qrcode = new QRCodeCanvas(res, {
|
||||
path2D: false,
|
||||
pixelRatio: isCanvas2d && props.use2d ? uni.getSystemInfoSync().pixelRatio : 1,
|
||||
createImage
|
||||
})
|
||||
qrcode.render(qrCodeProps.value)
|
||||
useCanvasToTempFilePath()
|
||||
})
|
||||
// #endif
|
||||
})
|
||||
onUnmounted(() => {
|
||||
propsWatch && propsWatch()
|
||||
})
|
||||
return {
|
||||
canvasId,
|
||||
styles,
|
||||
props,
|
||||
canvasToTempFilePath,
|
||||
|
||||
// #ifdef APP-NVUE
|
||||
onFinished,
|
||||
onError,
|
||||
onMessage
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.l-qrcode {
|
||||
position: relative;
|
||||
|
||||
&-mask {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
// inset-block-start: 0;
|
||||
// inset-inline-start: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
// width: 100%;
|
||||
// height: 100%;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
line-height: 1.5714285714285714;
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
40
uni_modules/lime-qrcode/components/l-qrcode/props.ts
Normal file
40
uni_modules/lime-qrcode/components/l-qrcode/props.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
// @ts-nocheck
|
||||
// import type { PropType } from './vue'
|
||||
export default {
|
||||
value: String,
|
||||
icon: String,
|
||||
size: {
|
||||
type: [Number, String],
|
||||
default: 160
|
||||
},
|
||||
iconSize: {
|
||||
type: [Number, String],
|
||||
default: 40
|
||||
},
|
||||
marginSize: Number,
|
||||
color: {
|
||||
type: String,
|
||||
default: '#000'
|
||||
},
|
||||
bgColor: {
|
||||
type: String,
|
||||
default: 'transparent'
|
||||
},
|
||||
bordered: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
errorLevel: {
|
||||
type: String as PropType<'L'|'M'|'Q'|'H'>,
|
||||
default: 'M' // 'L' | 'M' | 'Q' | 'H'
|
||||
},
|
||||
useCanvasToTempFilePath: Boolean,
|
||||
use2d: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
// status: {
|
||||
// type: String as PropType<'active'|'expired'|'loading'>,
|
||||
// default: 'active' // active | expired | loading
|
||||
// }
|
||||
}
|
||||
6
uni_modules/lime-qrcode/components/l-qrcode/qrcode.js
Normal file
6
uni_modules/lime-qrcode/components/l-qrcode/qrcode.js
Normal file
File diff suppressed because one or more lines are too long
48
uni_modules/lime-qrcode/components/l-qrcode/type.ts
Normal file
48
uni_modules/lime-qrcode/components/l-qrcode/type.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
// @ts-nocheck
|
||||
export type ImageSettings = {
|
||||
width: number
|
||||
height: number
|
||||
x?: number
|
||||
y?: number
|
||||
excavate: boolean
|
||||
}
|
||||
export type QRCodePropsTypes = {
|
||||
value?: string
|
||||
size?: number
|
||||
fgColor?: string
|
||||
level?: string
|
||||
marginSize: number
|
||||
includeMargin: boolean
|
||||
imageSettings?: ImageSettings
|
||||
}
|
||||
|
||||
export type QRCodeCallback = (cells : boolean[][]) => void
|
||||
|
||||
export type Excavation = {
|
||||
x: number
|
||||
y: number
|
||||
h: number
|
||||
w: number
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 成功回调函数定义
|
||||
*/
|
||||
export type TakeSnapshotSuccessCallback = (res: TakeSnapshotSuccess) => void
|
||||
/**
|
||||
* 失败回调函数定义
|
||||
*/
|
||||
export type TakeSnapshotFailCallback = (res: TakeSnapshotFail) => void
|
||||
/**
|
||||
* 完成回调函数定义
|
||||
*/
|
||||
export type TakeSnapshotCompleteCallback = (res: any) => void
|
||||
|
||||
|
||||
export type LQrcodeFailCallback = TakeSnapshotFailCallback
|
||||
export type LQrcodeCompleteCallback = TakeSnapshotCompleteCallback
|
||||
export type LQrcodeSuccessCallback = TakeSnapshotSuccessCallback
|
||||
78
uni_modules/lime-qrcode/components/l-qrcode/useCanvas.ts
Normal file
78
uni_modules/lime-qrcode/components/l-qrcode/useCanvas.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
|
||||
// @ts-nocheck
|
||||
import type { ComponentInternalInstance } from '@/uni_modules/lime-shared/vue'
|
||||
import { getRect } from '@/uni_modules/lime-shared/getRect'
|
||||
import { canIUseCanvas2d } from '@/uni_modules/lime-shared/canIUseCanvas2d'
|
||||
export const isCanvas2d = canIUseCanvas2d()
|
||||
|
||||
export async function getCanvas(canvasId: string, options: {context: ComponentInternalInstance}) {
|
||||
let { context } = options
|
||||
// #ifdef MP || VUE2
|
||||
if (context.proxy) context = context.proxy
|
||||
// #endif
|
||||
return getRect('#' + canvasId, context, isCanvas2d).then(res => {
|
||||
if(res.node){
|
||||
return res.node
|
||||
} else {
|
||||
const ctx = uni.createCanvasContext(canvasId, context)
|
||||
return {
|
||||
getContext(type: string) {
|
||||
if(type == '2d') {
|
||||
return ctx
|
||||
}
|
||||
},
|
||||
width: res.width,
|
||||
height: res.height,
|
||||
}
|
||||
// #ifdef H5
|
||||
// canvas.value = context.proxy.$el.querySelector('#'+ canvasId)
|
||||
// #endif
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// #ifndef H5 || APP-NVUE
|
||||
class Image {
|
||||
currentSrc: string | null = null
|
||||
naturalHeight: number = 0
|
||||
naturalWidth: number = 0
|
||||
width: number = 0
|
||||
height: number = 0
|
||||
tagName: string = 'IMG'
|
||||
path: any = ''
|
||||
crossOrigin: any = ''
|
||||
referrerPolicy: any = ''
|
||||
onload: () => void
|
||||
onerror: () => void
|
||||
constructor() {}
|
||||
set src(src) {
|
||||
this.currentSrc = src
|
||||
uni.getImageInfo({
|
||||
src,
|
||||
success: (res) => {
|
||||
this.path = res.path
|
||||
this.naturalWidth = this.width = res.width
|
||||
this.naturalHeight = this.height = res.height
|
||||
this.onload()
|
||||
},
|
||||
fail: () => {
|
||||
this.onerror()
|
||||
}
|
||||
})
|
||||
}
|
||||
get src() {
|
||||
return this.currentSrc
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
|
||||
export function createImage(canvas: WechatMiniprogram.Canvas) {
|
||||
if(canvas && canvas.createImage) {
|
||||
return canvas.createImage()
|
||||
} else if(typeof window != 'undefined' && window.Image) {
|
||||
return new window.Image()
|
||||
}
|
||||
// #ifndef H5 || APP-NVUE
|
||||
return new Image()
|
||||
// #endif
|
||||
}
|
||||
35
uni_modules/lime-qrcode/components/l-qrcode/utils.uts
Normal file
35
uni_modules/lime-qrcode/components/l-qrcode/utils.uts
Normal file
@@ -0,0 +1,35 @@
|
||||
export function addUnit(value: any|null):string{
|
||||
if(value == null){
|
||||
return ''
|
||||
}
|
||||
value = `${value}`
|
||||
return /^(-)?\d+(\\.\d+)?$/.test(value) ? `${value}px` : value
|
||||
}
|
||||
|
||||
export function unitConvert(value: any|null): number{
|
||||
if(typeof value == 'number'){
|
||||
return value as number
|
||||
}
|
||||
if(typeof value == 'string'){
|
||||
value = `${value}`
|
||||
if(/^(-)?\d+(\\.\d+)?$/.test(value)){
|
||||
return parseFloat(value);
|
||||
}
|
||||
|
||||
const reg = /^-?([0-9]+)?([.]{1}[0-9]+){0,1}(em|rpx|px|%)$/g;
|
||||
const results = reg.exec(value);
|
||||
if (results == null) {
|
||||
return 0;
|
||||
}
|
||||
const unit = results[3];
|
||||
const v = parseFloat(value);
|
||||
if (unit == 'rpx') {
|
||||
const { windowWidth } = uni.getWindowInfo()
|
||||
return windowWidth / 750 * v;
|
||||
}
|
||||
if (unit == 'px') {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
146
uni_modules/lime-qrcode/components/lime-qrcode/lime-qrcode.uvue
Normal file
146
uni_modules/lime-qrcode/components/lime-qrcode/lime-qrcode.uvue
Normal file
@@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<view class="demo-block">
|
||||
<text class="demo-block__title-text ultra">QRCode</text>
|
||||
<text class="demo-block__desc-text">能够将文本转换生成二维码的组件,支持自定义配色和 Logo 配置</text>
|
||||
<view class="demo-block__body">
|
||||
<view class="demo-block card">
|
||||
<text class="demo-block__title-text large">基础</text>
|
||||
<view class="demo-block__body">
|
||||
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" :use2d="false"></l-qrcode>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="demo-block card">
|
||||
<text class="demo-block__title-text large">icon</text>
|
||||
<view class="demo-block__body">
|
||||
<image v-if="image !=''" :src="image" style="width: 300rpx;" mode="widthFix"></image>
|
||||
<view style="flex-direction: row; justify-content: space-between">
|
||||
<l-qrcode ref="qrcodeRef" value="https://limeui.qcoon.cn" size="300rpx" icon="https://img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" iconSize="70rpx"></l-qrcode>
|
||||
<l-qrcode :useCanvasToTempFilePath="true" @success="success" value="https://limeui.qcoon.cn" size="300rpx" icon="https://img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" iconSize="70rpx"></l-qrcode>
|
||||
</view>
|
||||
<button type="primary" style="margin-top: 20rpx;" @click="onClick">生成图片</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="demo-block card">
|
||||
<text class="demo-block__title-text large">颜色</text>
|
||||
<view class="demo-block__body">
|
||||
<view style="flex-direction: row; justify-content: space-between">
|
||||
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" color="rgba(82,196,26,1)"></l-qrcode>
|
||||
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" color="rgba(22,119,255,1)" bgColor="rgb(245,245,245)"></l-qrcode>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="demo-block card">
|
||||
<text class="demo-block__title-text large">纠错比例</text>
|
||||
<view class="demo-block__body">
|
||||
<l-qrcode value="img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" size="300rpx" :errorLevel="levels[index]"></l-qrcode>
|
||||
<button type="primary" style="margin-top: 20rpx;" @click="onToggle">切换纠错等级:{{levels[index]}}</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="demo-block card">
|
||||
<text class="demo-block__title-text large">动态</text>
|
||||
<view class="demo-block__body">
|
||||
<l-qrcode :value="text" size="300rpx" :marginSize="1" bgColor="white"></l-qrcode>
|
||||
<button type="primary" style="margin-top: 20rpx;" @click="update">更新</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</template>
|
||||
<script>
|
||||
// import {ComponentPublicInstance} from 'vue'
|
||||
export default {
|
||||
name: 'lime-qrcode',
|
||||
data() {
|
||||
return {
|
||||
text: 'qcoon.com.cn',
|
||||
image: '',
|
||||
index: 0,
|
||||
levels: ['L', 'M', 'Q', 'H']
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
success(src: string) {
|
||||
console.log(`src`, src)
|
||||
},
|
||||
update() {
|
||||
this.text = `qcoon.cn?v=${Math.random()}`
|
||||
},
|
||||
onToggle() {
|
||||
this.index++
|
||||
this.index = this.index % this.levels.length
|
||||
},
|
||||
onClick() {
|
||||
const el:LQrcodeComponentPublicInstance = this.$refs['qrcodeRef'] as LQrcodeComponentPublicInstance
|
||||
el.canvasToTempFilePath({
|
||||
success:(res: TakeSnapshotSuccess)=>{
|
||||
this.image = res.tempFilePath
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
$card-bg-color: var(--doc-card-bg-color, white);
|
||||
// $page-bg-color: var(--doc-page-bg-color, #f5f5f5);
|
||||
$title-color: var(--doc-title-color, #000000E6);
|
||||
$summary-color: var(--doc-summary-color, #00000099);
|
||||
|
||||
.demo-block {
|
||||
margin: 32px 10px 0;
|
||||
overflow: visible;
|
||||
&.card{
|
||||
background-color: $card-bg-color;
|
||||
transition-property: background-color;
|
||||
// transition-duration: 300ms;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
&__title {
|
||||
margin: 0;
|
||||
margin-top: 8px;
|
||||
&-text {
|
||||
color: $summary-color;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 16px;
|
||||
|
||||
&.large {
|
||||
color: $title-color;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
line-height: 26px;
|
||||
}
|
||||
&.ultra {
|
||||
color: $title-color;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
&__desc-text {
|
||||
color: $summary-color;
|
||||
margin: 8px 16px 0 0;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
}
|
||||
&__body {
|
||||
margin: 16px 0;
|
||||
overflow: visible;
|
||||
.demo-block {
|
||||
// margin-top: 0px;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
141
uni_modules/lime-qrcode/components/lime-qrcode/lime-qrcode.vue
Normal file
141
uni_modules/lime-qrcode/components/lime-qrcode/lime-qrcode.vue
Normal file
@@ -0,0 +1,141 @@
|
||||
<template>
|
||||
<view class="demo-block">
|
||||
<text class="demo-block__title-text ultra">QRCode 二维码</text>
|
||||
<text class="demo-block__desc-text">生成二维码</text>
|
||||
<view class="demo-block__body">
|
||||
|
||||
<view class="demo-block">
|
||||
<text class="demo-block__title-text">基础</text>
|
||||
<view class="demo-block__body">
|
||||
<view style="display: flex; gap: 10px">
|
||||
<image v-if="image" :src="image" style="width: 300rpx;" mode="widthFix"></image>
|
||||
<l-qrcode :use2d="false" ref="qrcodeRef" value="https://limeui.qcoon.cn" size="300rpx" icon="https://img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" iconSize="70rpx"></l-qrcode>
|
||||
<!-- <l-qrcode useCanvasToTempFilePath @success="success" value="https://limeui.qcoon.cn" size="300rpx" icon="https://img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" iconSize="70rpx"></l-qrcode> -->
|
||||
</view>
|
||||
<button @click="onClick">生成图片</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="demo-block">
|
||||
<text class="demo-block__title-text">颜色</text>
|
||||
<view class="demo-block__body">
|
||||
<view style="display: flex; gap: 10px">
|
||||
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" color="rgb(82,196,26)"></l-qrcode>
|
||||
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" color="rgb(22,119,255)" bgColor="rgb(245,245,245)"></l-qrcode>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="demo-block">
|
||||
<text class="demo-block__title-text">纠错比例</text>
|
||||
<view class="demo-block__body">
|
||||
<l-qrcode value="img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" size="300rpx" :errorLevel="levels[index]"></l-qrcode>
|
||||
<button @click="onToggle">切换纠错等级:{{levels[index]}}</button>
|
||||
</view>
|
||||
</view>
|
||||
<view class="demo-block">
|
||||
<text class="demo-block__title-text">动态</text>
|
||||
<view class="demo-block__body">
|
||||
<l-qrcode :value="text" size="300rpx" :marginSize="1" bgColor="white"></l-qrcode>
|
||||
<button @click="update">更新</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import {ref, defineComponent} from '@/uni_modules/lime-shared/vue'
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const qrcodeRef = ref(null)
|
||||
const image = ref(null)
|
||||
const text = ref('qcoon.com.cn')
|
||||
const levels = ['L', 'M', 'Q', 'H']
|
||||
let index = ref(0)
|
||||
const onToggle = () => {
|
||||
index.value++
|
||||
index.value = index.value % levels.length
|
||||
}
|
||||
const onClick = () => {
|
||||
if(qrcodeRef.value) {
|
||||
qrcodeRef.value.canvasToTempFilePath({
|
||||
success(res) {
|
||||
image.value = res.tempFilePath
|
||||
console.log('success:::', res)
|
||||
},
|
||||
fail(err) {
|
||||
console.log('err:::', err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
const success = (res) => {
|
||||
console.log('res', res)
|
||||
}
|
||||
|
||||
const update = () =>{
|
||||
text.value = `qcoon.cn?v=${Math.random()}`
|
||||
}
|
||||
|
||||
return {
|
||||
levels,
|
||||
index,
|
||||
image,
|
||||
text,
|
||||
qrcodeRef,
|
||||
onClick,
|
||||
update,
|
||||
success,
|
||||
onToggle,
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
|
||||
.demo-block {
|
||||
margin: 32px 10px 0;
|
||||
overflow: visible;
|
||||
&.card{
|
||||
background-color: white;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
&__title {
|
||||
margin: 0;
|
||||
margin-top: 8px;
|
||||
&-text {
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 16px;
|
||||
display: flex;
|
||||
&.large {
|
||||
color: rgba(0, 0, 0, 0.9);
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
line-height: 26px;
|
||||
}
|
||||
&.ultra {
|
||||
color: rgba(0, 0, 0, 0.9);
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
&__desc-text {
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
margin: 8px 16px 0 0;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
}
|
||||
&__body {
|
||||
margin: 16px 0;
|
||||
overflow: visible;
|
||||
.demo-block {
|
||||
// margin-top: 0px;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
77
uni_modules/lime-qrcode/hybrid/html/index.html
Normal file
77
uni_modules/lime-qrcode/hybrid/html/index.html
Normal file
@@ -0,0 +1,77 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>lime-qrcode</title>
|
||||
<style>
|
||||
html,body,canvas {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
/* background-color: rgba(255,0,0,0.1) */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="lime-qrcode"></canvas>
|
||||
<script type="text/javascript" src="./uni.webview.1.5.3.js"></script>
|
||||
<script type="text/javascript" src="./qrcode.min.js"></script>
|
||||
<script>
|
||||
var canvas = document.querySelector('#lime-qrcode')
|
||||
var pixelRatio = window.devicePixelRatio || 1
|
||||
function appendWatermark(image) {
|
||||
emit('append', mark.toDataURL())
|
||||
}
|
||||
|
||||
var qrcode = new lime.QRCodeCanvas(canvas, {
|
||||
pixelRatio,
|
||||
})
|
||||
function render(props) {
|
||||
if(props.pixelRatio) {
|
||||
pixelRatio = props.pixelRatio
|
||||
}
|
||||
if(qrcode) {
|
||||
qrcode.render(props)
|
||||
}
|
||||
}
|
||||
function toDataURL(file) {
|
||||
if(qrcode && canvas) {
|
||||
try{
|
||||
const image = canvas.toDataURL()
|
||||
emit('toDataURL', {
|
||||
file,
|
||||
image
|
||||
})
|
||||
}catch(e){
|
||||
emit('toDataURL', {
|
||||
file,
|
||||
msg: e
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
function emit(event, data) {
|
||||
postMessage({
|
||||
event,
|
||||
data
|
||||
});
|
||||
};
|
||||
function postMessage(data) {
|
||||
uni.postMessage({
|
||||
data
|
||||
});
|
||||
};
|
||||
// render({
|
||||
// content: ['Lime UI'],
|
||||
// // rotate: -22,
|
||||
// // baseSize: 2,
|
||||
// // fontGap: 3
|
||||
// })
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
6
uni_modules/lime-qrcode/hybrid/html/qrcode.min.js
vendored
Normal file
6
uni_modules/lime-qrcode/hybrid/html/qrcode.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
uni_modules/lime-qrcode/hybrid/html/uni.webview.1.5.3.js
Normal file
1
uni_modules/lime-qrcode/hybrid/html/uni.webview.1.5.3.js
Normal file
File diff suppressed because one or more lines are too long
108
uni_modules/lime-qrcode/package.json
Normal file
108
uni_modules/lime-qrcode/package.json
Normal file
@@ -0,0 +1,108 @@
|
||||
{
|
||||
"id": "lime-qrcode",
|
||||
"displayName": "qrcode 二维码生成",
|
||||
"version": "0.2.4",
|
||||
"description": "一款全平台通用的二维码生成插件,支持uniapp/uniappx",
|
||||
"keywords": [
|
||||
"qrcode",
|
||||
"qr",
|
||||
"uvue",
|
||||
"生成图片",
|
||||
"二维码"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"uni-app": "^4.41",
|
||||
"uni-app-x": "^4.61"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "component-vue",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": "305716444"
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "",
|
||||
"darkmode": "x",
|
||||
"i18n": "x",
|
||||
"widescreen": "x"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [
|
||||
"lime-shared"
|
||||
],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "√",
|
||||
"aliyun": "√",
|
||||
"alipay": "√"
|
||||
},
|
||||
"client": {
|
||||
"uni-app": {
|
||||
"vue": {
|
||||
"vue2": "√",
|
||||
"vue3": "√"
|
||||
},
|
||||
"web": {
|
||||
"safari": "√",
|
||||
"chrome": "√"
|
||||
},
|
||||
"app": {
|
||||
"vue": "√",
|
||||
"nvue": "√",
|
||||
"android": {
|
||||
"extVersion": "",
|
||||
"minVersion": "21"
|
||||
},
|
||||
"ios": "√",
|
||||
"harmony": "√"
|
||||
},
|
||||
"mp": {
|
||||
"weixin": "√",
|
||||
"alipay": "√",
|
||||
"toutiao": "√",
|
||||
"baidu": "√",
|
||||
"kuaishou": "√",
|
||||
"jd": "√",
|
||||
"harmony": "-",
|
||||
"qq": "√",
|
||||
"lark": "√"
|
||||
},
|
||||
"quickapp": {
|
||||
"huawei": "-",
|
||||
"union": "-"
|
||||
}
|
||||
},
|
||||
"uni-app-x": {
|
||||
"web": {
|
||||
"safari": "√",
|
||||
"chrome": "√"
|
||||
},
|
||||
"app": {
|
||||
"android": {
|
||||
"extVersion": "",
|
||||
"minVersion": "21"
|
||||
},
|
||||
"ios": "√",
|
||||
"harmony": "√"
|
||||
},
|
||||
"mp": {
|
||||
"weixin": "√"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
166
uni_modules/lime-qrcode/readme - 副本.md
Normal file
166
uni_modules/lime-qrcode/readme - 副本.md
Normal file
@@ -0,0 +1,166 @@
|
||||
# lime-qrcode 二维码
|
||||
- 一款全平台通用的二维码生成插件,支持uniapp/uniappx
|
||||
- uniappx app 需要导入[lime-qrcodegen](https://ext.dcloud.net.cn/plugin?id=15838)
|
||||
|
||||
|
||||
## 文档
|
||||
[qrcode【站点1】](https://limex.qcoon.cn/components/qrcode.html)
|
||||
[qrcode【站点2】](https://limeui.netlify.app/components/qrcode.html)
|
||||
[qrcode【站点3】](https://limeui.familyzone.top/components/qrcode.html)
|
||||
|
||||
|
||||
|
||||
## 安装
|
||||
在插件市场导入即可。
|
||||
|
||||
**注意**
|
||||
- uniappx app 需要导入**[lime-qrcodegen](https://ext.dcloud.net.cn/plugin?id=15838)**,
|
||||
- 非uniappx app可直接使用
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 基础使用
|
||||
|
||||
```html
|
||||
<l-qrcode value="http://lime.qcoon.cn" />
|
||||
```
|
||||
|
||||
|
||||
### ICON
|
||||
- 带 Icon 的二维码
|
||||
|
||||
```html
|
||||
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" icon="/static/logo.png" iconSize="70rpx"></l-qrcode>
|
||||
```
|
||||
|
||||
### 颜色
|
||||
- 通过设置 `color` 自定义二维码颜色,通过设置 `bgColor` 自定义背景颜色。
|
||||
|
||||
```html
|
||||
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" color="rgb(82,196,26)"></l-qrcode>
|
||||
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" color="rgb(22,119,255)" bgColor="rgb(245,245,245)"></l-qrcode>
|
||||
```
|
||||
|
||||
### 纠错比例
|
||||
- 通过设置 `errorLevel` 调整不同的容错等级。
|
||||
|
||||
```html
|
||||
<l-qrcode value="img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" size="300rpx" errorLevel="H"></l-qrcode>
|
||||
```
|
||||
|
||||
### 生成图片
|
||||
如果是canvas 2d的环境生成的是base64
|
||||
- 1、通过调用插件的`canvasToTempFilePath`方法生成图片。
|
||||
|
||||
```html
|
||||
<image v-if="image" :src="image" style="width: 300rpx;" mode="widthFix"></image>
|
||||
<l-qrcode ref="qrcodeRef" value="https://limeui.qcoon.cn" size="300rpx" icon="https://img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" iconSize="70rpx"></l-qrcode>
|
||||
<button @click="onClick">生成图片</button>
|
||||
```
|
||||
```js
|
||||
// vue3
|
||||
const qrcodeRef = ref(null)
|
||||
const onClick = () => {
|
||||
if(!qrcodeRef.value) return
|
||||
qrcodeRef.value.canvasToTempFilePath({
|
||||
success(res) {
|
||||
image.value = res.tempFilePath
|
||||
console.log('success:::', res)
|
||||
},
|
||||
fail(err) {
|
||||
console.log('err:::', err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// vue2
|
||||
const el = this.$refs['qrcodeRef']
|
||||
el.canvasToTempFilePath({
|
||||
success:(res)=>{
|
||||
this.image = res.tempFilePath
|
||||
},
|
||||
fail(err) {
|
||||
console.log('err:::', err)
|
||||
}
|
||||
})
|
||||
|
||||
// uvue
|
||||
const el:LQrcodeComponentPublicInstance = this.$refs['qrcodeRef'] as LQrcodeComponentPublicInstance
|
||||
el.canvasToTempFilePath({
|
||||
success:(res: TakeSnapshotSuccess)=>{
|
||||
this.image = res.tempFilePath
|
||||
},
|
||||
fail(err: TakeSnapshotFail) {
|
||||
console.log('err:::', err)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
- 2、通过设置`useCanvasToTempFilePath`在`success`事件里接收图片地址
|
||||
|
||||
```html
|
||||
<image v-if="image" :src="image" style="width: 300rpx;" mode="widthFix"></image>
|
||||
<l-qrcode useCanvasToTempFilePath @success="success" value="https://limeui.qcoon.cn"></l-qrcode>
|
||||
```
|
||||
```js
|
||||
const image = ref(null)
|
||||
const success = (img) => {
|
||||
image.value = img
|
||||
}
|
||||
```
|
||||
|
||||
### Vue2使用
|
||||
- 插件使用了`composition-api`, 如果你希望在vue2中使用请按官方的教程[vue-composition-api](https://uniapp.dcloud.net.cn/tutorial/vue-composition-api.html)配置
|
||||
- 关键代码是: 在main.js中 在vue2部分加上这一段即可
|
||||
|
||||
```js
|
||||
// main.js vue2
|
||||
import Vue from 'vue'
|
||||
import VueCompositionAPI from '@vue/composition-api'
|
||||
Vue.use(VueCompositionAPI)
|
||||
```
|
||||
另外插件也用到了TS,vue2可能会遇过官方的TS版本过低的问题,找到HX目录下的`compile-typescript`目录
|
||||
```cmd
|
||||
// \HBuilderX\plugins\compile-typescript
|
||||
yarn add typescript -D
|
||||
- or -
|
||||
npm install typescript -D
|
||||
```
|
||||
|
||||
### 查看示例
|
||||
- 导入后直接使用这个标签查看演示效果
|
||||
|
||||
```html
|
||||
// 代码位于 uni_modules/lime-qrcode/compoents/lime-qrcode
|
||||
<lime-qrcode />
|
||||
```
|
||||
|
||||
### 插件标签
|
||||
- 默认 l-qrcode 为 component
|
||||
- 默认 lime-qrcode 为 demo
|
||||
|
||||
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --------------------------| ------------------------------------------------------------ | ---------------- | ------------ |
|
||||
| value | 扫描后的文本 | <em>string</em> | `-` |
|
||||
| icon | 二维码中图片的地址 | <em>string</em> | `-` |
|
||||
| size | 二维码大小 | <em>number,string</em> | `160` |
|
||||
| iconSize | 二维码中图片的大小 | <em>number,string</em> | `40` |
|
||||
| color | 二维码颜色 | <em>string</em> | `-` |
|
||||
| bgColor | 二维码背景颜色 | <em>string</em> | `-` |
|
||||
| errorLevel | 二维码纠错等级 | `'L' | 'M' | 'Q' | 'H' ` | `M` |
|
||||
| marginSize | 边距码大小,默认为0码点 | <em>number</em> | `0` |
|
||||
|
||||
### 常见问题
|
||||
- icon 是网络地址时,H5和Nvue需要解决跨域问题,小程序需要配置download
|
||||
|
||||
## 打赏
|
||||
|
||||
如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。
|
||||

|
||||

|
||||
172
uni_modules/lime-qrcode/readme.md
Normal file
172
uni_modules/lime-qrcode/readme.md
Normal file
@@ -0,0 +1,172 @@
|
||||
# lime-qrcode 二维码组件
|
||||
一个功能丰富的二维码生成组件,用于生成自定义二维码。支持自定义大小、颜色、图标、边框等多种配置,可用于分享链接、支付码、名片等多种场景。组件提供了丰富的自定义选项,可以满足各种二维码生成需求。
|
||||
|
||||
> 插件依赖:`lime-shared`
|
||||
|
||||
## 文档链接
|
||||
📚 组件详细文档请访问以下站点:
|
||||
- [二维码组件文档 - 站点1](https://limex.qcoon.cn/components/qrcode.html)
|
||||
- [二维码组件文档 - 站点2](https://limeui.netlify.app/components/qrcode.html)
|
||||
- [二维码组件文档 - 站点3](https://limeui.familyzone.top/components/qrcode.html)
|
||||
|
||||
## 安装方法
|
||||
1. 在uni-app插件市场中搜索并导入`lime-qrcode`
|
||||
2. 导入后可能需要重新编译项目
|
||||
3. 在页面中使用`l-qrcode`组件
|
||||
|
||||
::: tip 注意🔔
|
||||
uniappx app 需要导入[【lime-qrcodegen】](https://ext.dcloud.net.cn/plugin?id=1583)这个依赖插件,它是收费的插件,普通授权则需要自定义基座,才能使用,如果您是UI组件库VIP则忽略。
|
||||
:::
|
||||
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 基础使用
|
||||
|
||||
```html
|
||||
<l-qrcode value="http://lime.qcoon.cn" />
|
||||
```
|
||||
|
||||
|
||||
### ICON
|
||||
- 带 Icon 的二维码
|
||||
|
||||
```html
|
||||
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" icon="/static/logo.png" iconSize="70rpx"></l-qrcode>
|
||||
```
|
||||
|
||||
### 颜色
|
||||
- 通过设置 `color` 自定义二维码颜色,通过设置 `bgColor` 自定义背景颜色。
|
||||
|
||||
```html
|
||||
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" color="rgb(82,196,26)"></l-qrcode>
|
||||
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" color="rgb(22,119,255)" bgColor="rgb(245,245,245)"></l-qrcode>
|
||||
```
|
||||
|
||||
### 纠错比例
|
||||
- 通过设置 `errorLevel` 调整不同的容错等级。
|
||||
|
||||
```html
|
||||
<l-qrcode value="img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" size="300rpx" errorLevel="H"></l-qrcode>
|
||||
```
|
||||
|
||||
### 生成图片
|
||||
如果是canvas 2d的环境生成的是base64
|
||||
- 1、通过调用插件的`canvasToTempFilePath`方法生成图片。
|
||||
|
||||
```html
|
||||
<image v-if="image" :src="image" style="width: 300rpx;" mode="widthFix"></image>
|
||||
<l-qrcode ref="qrcodeRef" value="https://limeui.qcoon.cn" size="300rpx" icon="https://img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" iconSize="70rpx"></l-qrcode>
|
||||
<button @click="onClick">生成图片</button>
|
||||
```
|
||||
```js
|
||||
// vue3
|
||||
const qrcodeRef = ref(null)
|
||||
const onClick = () => {
|
||||
if(!qrcodeRef.value) return
|
||||
qrcodeRef.value.canvasToTempFilePath({
|
||||
success(res) {
|
||||
image.value = res.tempFilePath
|
||||
console.log('success:::', res)
|
||||
},
|
||||
fail(err) {
|
||||
console.log('err:::', err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// vue2
|
||||
const el = this.$refs['qrcodeRef']
|
||||
el.canvasToTempFilePath({
|
||||
success:(res)=>{
|
||||
this.image = res.tempFilePath
|
||||
},
|
||||
fail(err) {
|
||||
console.log('err:::', err)
|
||||
}
|
||||
})
|
||||
|
||||
// uvue
|
||||
const el:LQrcodeComponentPublicInstance = this.$refs['qrcodeRef'] as LQrcodeComponentPublicInstance
|
||||
el.canvasToTempFilePath({
|
||||
success:(res: TakeSnapshotSuccess)=>{
|
||||
this.image = res.tempFilePath
|
||||
},
|
||||
fail(err: TakeSnapshotFail) {
|
||||
console.log('err:::', err)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
- 2、通过设置`useCanvasToTempFilePath`在`success`事件里接收图片地址
|
||||
|
||||
```html
|
||||
<image v-if="image" :src="image" style="width: 300rpx;" mode="widthFix"></image>
|
||||
<l-qrcode useCanvasToTempFilePath @success="success" value="https://limeui.qcoon.cn"></l-qrcode>
|
||||
```
|
||||
```js
|
||||
const image = ref(null)
|
||||
const success = (img) => {
|
||||
image.value = img
|
||||
}
|
||||
```
|
||||
|
||||
## 快速预览
|
||||
导入插件后,可以直接使用以下标签查看演示效果:
|
||||
|
||||
```html
|
||||
<!-- 代码位于 uni_modules/lime-qrcode/components/lime-qrcode -->
|
||||
<lime-qrcode />
|
||||
```
|
||||
|
||||
## 插件标签说明
|
||||
|
||||
| 标签名 | 说明 |
|
||||
| --- | --- |
|
||||
| `l-qrcode` | 组件标签 |
|
||||
| `lime-qrcode` | 演示标签 |
|
||||
|
||||
## Vue2使用说明
|
||||
main.js中添加以下代码:
|
||||
```js
|
||||
// vue2项目中使用
|
||||
import Vue from 'vue'
|
||||
import VueCompositionAPI from '@vue/composition-api'
|
||||
Vue.use(VueCompositionAPI)
|
||||
```
|
||||
|
||||
详细配置请参考官方文档:[Vue Composition API](https://uniapp.dcloud.net.cn/tutorial/vue-composition-api.html)
|
||||
|
||||
|
||||
## API文档
|
||||
|
||||
### Props 属性说明
|
||||
|
||||
| 属性名 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| value | 二维码内容 | _string_ | - |
|
||||
| size | 二维码大小 | _number \| string_ | `160` |
|
||||
| color | 二维码颜色 | _string_ | `#000` |
|
||||
| bgColor | 二维码背景色 | _string_ | `transparent` |
|
||||
| icon | 二维码中心图标 | _string_ | - |
|
||||
| iconSize | 图标大小 | _number \| string_ | `40` |
|
||||
| marginSize | 二维码外边距 | _number_ | - |
|
||||
| bordered | 是否显示边框 | _boolean_ | `true` |
|
||||
| errorLevel | 纠错级别,可选值为 `L`、`M`、`Q`、`H` | _string_ | `M` |
|
||||
| useCanvasToTempFilePath | 是否使用Canvas导出为临时文件 | _boolean_ | `false` |
|
||||
| use2d | 是否使用2D Canvas | _boolean_ | `true` |
|
||||
|
||||
### Events 事件
|
||||
|
||||
| 事件名 | 说明 | 回调参数 |
|
||||
| --- | --- | --- |
|
||||
| complete | 二维码生成完成时触发 | _path: string_ 临时文件路径(仅当 useCanvasToTempFilePath 为 true 时有效) |
|
||||
| error | 二维码生成失败时触发 | _error: Error_ 错误信息 |
|
||||
|
||||
## 支持与赞赏
|
||||
|
||||
如果你觉得本插件解决了你的问题,可以考虑支持作者:
|
||||
|
||||
| 支付宝赞助 | 微信赞助 |
|
||||
|------------|------------|
|
||||
|  |  |
|
||||
42
uni_modules/lime-shared/addUnit/index.ts
Normal file
42
uni_modules/lime-shared/addUnit/index.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
// @ts-nocheck
|
||||
import {isNumeric} from '../isNumeric'
|
||||
import {isDef} from '../isDef'
|
||||
/**
|
||||
* 给一个值添加单位(像素 px)
|
||||
* @param value 要添加单位的值,可以是字符串或数字
|
||||
* @returns 添加了单位的值,如果值为 null 则返回 null
|
||||
*/
|
||||
|
||||
// #ifndef UNI-APP-X && APP
|
||||
export function addUnit(value?: string | number): string | null {
|
||||
if (!isDef(value)) {
|
||||
return null;
|
||||
}
|
||||
value = String(value); // 将值转换为字符串
|
||||
// 如果值是数字,则在后面添加单位 "px",否则保持原始值
|
||||
return isNumeric(value) ? `${value}px` : value;
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef UNI-APP-X && APP
|
||||
function addUnit(value: string): string|null
|
||||
function addUnit(value: number): string|null
|
||||
function addUnit(value: string|number|null): string|null {
|
||||
if (!isDef(value)) {
|
||||
return null;
|
||||
}
|
||||
value = `${value}` //value.toString(); // 将值转换为字符串
|
||||
|
||||
// 如果值是数字,则在后面添加单位 "px",否则保持原始值
|
||||
return isNumeric(value) ? `${value}px` : value;
|
||||
}
|
||||
export {addUnit}
|
||||
// #endif
|
||||
|
||||
|
||||
// console.log(addUnit(100)); // 输出: "100px"
|
||||
// console.log(addUnit("200")); // 输出: "200px"
|
||||
// console.log(addUnit("300px")); // 输出: "300px"(已经包含单位)
|
||||
// console.log(addUnit()); // 输出: undefined(值为 undefined)
|
||||
// console.log(addUnit(null)); // 输出: undefined(值为 null)
|
||||
82
uni_modules/lime-shared/animation/bezier.ts
Normal file
82
uni_modules/lime-shared/animation/bezier.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
export function cubicBezier(p1x : number, p1y : number, p2x : number, p2y : number):(x: number)=> number {
|
||||
const ZERO_LIMIT = 1e-6;
|
||||
// Calculate the polynomial coefficients,
|
||||
// implicit first and last control points are (0,0) and (1,1).
|
||||
const ax = 3 * p1x - 3 * p2x + 1;
|
||||
const bx = 3 * p2x - 6 * p1x;
|
||||
const cx = 3 * p1x;
|
||||
|
||||
const ay = 3 * p1y - 3 * p2y + 1;
|
||||
const by = 3 * p2y - 6 * p1y;
|
||||
const cy = 3 * p1y;
|
||||
|
||||
function sampleCurveDerivativeX(t : number) : number {
|
||||
// `ax t^3 + bx t^2 + cx t` expanded using Horner's rule
|
||||
return (3 * ax * t + 2 * bx) * t + cx;
|
||||
}
|
||||
|
||||
function sampleCurveX(t : number) : number {
|
||||
return ((ax * t + bx) * t + cx) * t;
|
||||
}
|
||||
|
||||
function sampleCurveY(t : number) : number {
|
||||
return ((ay * t + by) * t + cy) * t;
|
||||
}
|
||||
|
||||
// Given an x value, find a parametric value it came from.
|
||||
function solveCurveX(x : number) : number {
|
||||
let t2 = x;
|
||||
let derivative : number;
|
||||
let x2 : number;
|
||||
|
||||
// https://trac.webkit.org/browser/trunk/Source/WebCore/platform/animation
|
||||
// first try a few iterations of Newton's method -- normally very fast.
|
||||
// http://en.wikipedia.org/wikiNewton's_method
|
||||
for (let i = 0; i < 8; i++) {
|
||||
// f(t) - x = 0
|
||||
x2 = sampleCurveX(t2) - x;
|
||||
if (Math.abs(x2) < ZERO_LIMIT) {
|
||||
return t2;
|
||||
}
|
||||
derivative = sampleCurveDerivativeX(t2);
|
||||
// == 0, failure
|
||||
/* istanbul ignore if */
|
||||
if (Math.abs(derivative) < ZERO_LIMIT) {
|
||||
break;
|
||||
}
|
||||
t2 -= x2 / derivative;
|
||||
}
|
||||
|
||||
// Fall back to the bisection method for reliability.
|
||||
// bisection
|
||||
// http://en.wikipedia.org/wiki/Bisection_method
|
||||
let t1 = 1;
|
||||
/* istanbul ignore next */
|
||||
let t0 = 0;
|
||||
|
||||
/* istanbul ignore next */
|
||||
t2 = x;
|
||||
/* istanbul ignore next */
|
||||
while (t1 > t0) {
|
||||
x2 = sampleCurveX(t2) - x;
|
||||
if (Math.abs(x2) < ZERO_LIMIT) {
|
||||
return t2;
|
||||
}
|
||||
if (x2 > 0) {
|
||||
t1 = t2;
|
||||
} else {
|
||||
t0 = t2;
|
||||
}
|
||||
t2 = (t1 + t0) / 2;
|
||||
}
|
||||
|
||||
// Failure
|
||||
return t2;
|
||||
}
|
||||
|
||||
return function (x : number) : number {
|
||||
return sampleCurveY(solveCurveX(x));
|
||||
}
|
||||
|
||||
// return solve;
|
||||
}
|
||||
3
uni_modules/lime-shared/animation/ease.ts
Normal file
3
uni_modules/lime-shared/animation/ease.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import {cubicBezier} from './bezier';
|
||||
export let ease = cubicBezier(0.25, 0.1, 0.25, 1);
|
||||
export let linear = cubicBezier(0,0,1,1);
|
||||
12
uni_modules/lime-shared/animation/index.ts
Normal file
12
uni_modules/lime-shared/animation/index.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
// @ts-nocheck
|
||||
// #ifdef UNI-APP-X && APP
|
||||
// export * from './uvue.uts'
|
||||
export { Timeline, Animation } from './uvue.uts'
|
||||
// #endif
|
||||
|
||||
|
||||
|
||||
// #ifndef UNI-APP-X && APP
|
||||
// export * from './vue.ts'
|
||||
export { Timeline, Animation } from './vue.ts'
|
||||
// #endif
|
||||
108
uni_modules/lime-shared/animation/useTransition.ts
Normal file
108
uni_modules/lime-shared/animation/useTransition.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
// @ts-nocheck
|
||||
import type { ComponentPublicInstance, Ref } from 'vue'
|
||||
import { ease, linear } from './ease';
|
||||
import { Timeline, Animation } from './';
|
||||
export type UseTransitionOptions = {
|
||||
duration ?: number
|
||||
immediate ?: boolean
|
||||
context ?: ComponentPublicInstance
|
||||
}
|
||||
// #ifndef UNI-APP-X && APP
|
||||
import { ref, watch } from '@/uni_modules/lime-shared/vue'
|
||||
|
||||
export function useTransition(percent : Ref<number>|(() => number), options : UseTransitionOptions) : Ref<number> {
|
||||
const current = ref(0)
|
||||
const { immediate, duration = 300 } = options
|
||||
let tl:Timeline|null = null;
|
||||
let timer = -1
|
||||
const isFunction = typeof percent === 'function'
|
||||
watch(isFunction ? percent : () => percent.value, (v) => {
|
||||
if(tl == null){
|
||||
tl = new Timeline()
|
||||
}
|
||||
tl.start();
|
||||
tl.add(
|
||||
new Animation(
|
||||
current.value,
|
||||
v,
|
||||
duration,
|
||||
0,
|
||||
ease,
|
||||
nowValue => {
|
||||
current.value = nowValue
|
||||
clearTimeout(timer)
|
||||
if(current.value == v){
|
||||
timer = setTimeout(()=>{
|
||||
tl?.pause();
|
||||
tl = null
|
||||
}, duration)
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
}, { immediate })
|
||||
|
||||
return current
|
||||
}
|
||||
|
||||
// #endif
|
||||
|
||||
// #ifdef UNI-APP-X && APP
|
||||
type UseTransitionReturnType = Ref<number>
|
||||
export function useTransition(source : any, options : UseTransitionOptions) : UseTransitionReturnType {
|
||||
const outputRef : Ref<number> = ref(0)
|
||||
const immediate = options.immediate ?? false
|
||||
const duration = options.duration ?? 300
|
||||
const context = options.context //as ComponentPublicInstance | null
|
||||
let tl:Timeline|null = null;
|
||||
let timer = -1
|
||||
const watchFunc = (v : number) => {
|
||||
if(tl == null){
|
||||
tl = new Timeline()
|
||||
}
|
||||
tl!.start();
|
||||
tl!.add(
|
||||
new Animation(
|
||||
outputRef.value,
|
||||
v,
|
||||
duration,
|
||||
0,
|
||||
ease,
|
||||
nowValue => {
|
||||
outputRef.value = nowValue
|
||||
clearTimeout(timer)
|
||||
if(outputRef.value == v){
|
||||
timer = setTimeout(()=>{
|
||||
tl?.pause();
|
||||
tl = null
|
||||
}, duration)
|
||||
}
|
||||
}
|
||||
),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
if (context != null && typeof source == 'string') {
|
||||
context.$watch(source, watchFunc, { immediate } as WatchOptions)
|
||||
} else if(typeof source == 'function'){
|
||||
watch(source, watchFunc, { immediate })
|
||||
}
|
||||
// #ifdef APP-ANDROID
|
||||
else if(isRef(source) && source instanceof Ref<number>) {
|
||||
watch(source as Ref<number>, watchFunc, { immediate })
|
||||
}
|
||||
// #endif
|
||||
// #ifndef APP-ANDROID
|
||||
else if(isRef(source) && typeof source.value == 'number') {
|
||||
watch(source, watchFunc, { immediate })
|
||||
}
|
||||
// #endif
|
||||
|
||||
const stop = ()=>{
|
||||
|
||||
}
|
||||
return outputRef //as UseTransitionReturnType
|
||||
}
|
||||
|
||||
// #endif
|
||||
119
uni_modules/lime-shared/animation/uvue.uts
Normal file
119
uni_modules/lime-shared/animation/uvue.uts
Normal file
@@ -0,0 +1,119 @@
|
||||
// @ts-nocheck
|
||||
import { raf, cancelRaf} from '../raf'
|
||||
export class Timeline {
|
||||
state : string
|
||||
animations : Set<Animation> = new Set<Animation>()
|
||||
delAnimations : Animation[] = []
|
||||
startTimes : Map<Animation, number> = new Map<Animation, number>()
|
||||
pauseTime : number = 0
|
||||
pauseStart : number = Date.now()
|
||||
tickHandler : number = 0
|
||||
tickHandlers : number[] = []
|
||||
tick : (() => void) | null = null
|
||||
constructor() {
|
||||
this.state = 'Initiated';
|
||||
}
|
||||
start() {
|
||||
if (!(this.state == 'Initiated')) return;
|
||||
this.state = 'Started';
|
||||
|
||||
let startTime = Date.now();
|
||||
this.pauseTime = 0;
|
||||
this.tick = () => {
|
||||
let now = Date.now();
|
||||
this.animations.forEach((animation : Animation) => {
|
||||
let t:number;
|
||||
const ani = this.startTimes.get(animation)
|
||||
if (ani == null) return
|
||||
if (ani < startTime) {
|
||||
t = now - startTime - animation.delay - this.pauseTime;
|
||||
} else {
|
||||
t = now - ani - animation.delay - this.pauseTime;
|
||||
}
|
||||
if (t > animation.duration) {
|
||||
this.delAnimations.push(animation)
|
||||
// 不能在 foreach 里面 对 集合进行删除操作
|
||||
// this.animations.delete(animation);
|
||||
t = animation.duration;
|
||||
}
|
||||
if (t > 0) animation.run(t);
|
||||
})
|
||||
// 不能在 foreach 里面 对 集合进行删除操作
|
||||
while (this.delAnimations.length > 0) {
|
||||
const animation = this.delAnimations.pop();
|
||||
if (animation == null) return
|
||||
this.animations.delete(animation);
|
||||
}
|
||||
// cancelAnimationFrame(this.tickHandler);
|
||||
if (this.state != 'Started') return
|
||||
|
||||
this.tickHandler = raf(()=>{
|
||||
this.tick!()
|
||||
})
|
||||
|
||||
this.tickHandlers.push(this.tickHandler)
|
||||
}
|
||||
if(this.tick != null) {
|
||||
this.tick!()
|
||||
}
|
||||
|
||||
}
|
||||
pause() {
|
||||
if (!(this.state === 'Started')) return;
|
||||
this.state = 'Paused';
|
||||
this.pauseStart = Date.now();
|
||||
cancelRaf(this.tickHandler);
|
||||
// cancelRaf(this.tickHandler);
|
||||
}
|
||||
resume() {
|
||||
if (!(this.state === 'Paused')) return;
|
||||
this.state = 'Started';
|
||||
this.pauseTime += Date.now() - this.pauseStart;
|
||||
this.tick!();
|
||||
}
|
||||
reset() {
|
||||
this.pause();
|
||||
this.state = 'Initiated';
|
||||
this.pauseTime = 0;
|
||||
this.pauseStart = 0;
|
||||
this.animations.clear()
|
||||
this.delAnimations.clear()
|
||||
this.startTimes.clear()
|
||||
this.tickHandler = 0;
|
||||
}
|
||||
add(animation : Animation, startTime ?: number | null) {
|
||||
if (startTime == null) startTime = Date.now();
|
||||
this.animations.add(animation);
|
||||
this.startTimes.set(animation, startTime);
|
||||
}
|
||||
}
|
||||
|
||||
export class Animation {
|
||||
startValue : number
|
||||
endValue : number
|
||||
duration : number
|
||||
timingFunction : (t : number) => number
|
||||
delay : number
|
||||
template : (t : number) => void
|
||||
constructor(
|
||||
startValue : number,
|
||||
endValue : number,
|
||||
duration : number,
|
||||
delay : number,
|
||||
timingFunction : (t : number) => number,
|
||||
template : (v : number) => void) {
|
||||
this.startValue = startValue;
|
||||
this.endValue = endValue;
|
||||
this.duration = duration;
|
||||
this.timingFunction = timingFunction;
|
||||
this.delay = delay;
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
run(time : number) {
|
||||
let range = this.endValue - this.startValue;
|
||||
let progress = time / this.duration
|
||||
if(progress != 1) progress = this.timingFunction(progress)
|
||||
this.template(this.startValue + range * progress)
|
||||
}
|
||||
}
|
||||
123
uni_modules/lime-shared/animation/vue.ts
Normal file
123
uni_modules/lime-shared/animation/vue.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
// @ts-nocheck
|
||||
const TICK = Symbol('tick');
|
||||
const TICK_HANDLER = Symbol('tick-handler');
|
||||
const ANIMATIONS = Symbol('animations');
|
||||
const START_TIMES = Symbol('start-times');
|
||||
const PAUSE_START = Symbol('pause-start');
|
||||
const PAUSE_TIME = Symbol('pause-time');
|
||||
const _raf = typeof requestAnimationFrame !== 'undefined' ? requestAnimationFrame : function(cb: Function) {return setTimeout(cb, 1000/60)}
|
||||
const _caf = typeof cancelAnimationFrame !== 'undefined' ? cancelAnimationFrame: function(id: any) {clearTimeout(id)}
|
||||
|
||||
// const TICK = 'tick';
|
||||
// const TICK_HANDLER = 'tick-handler';
|
||||
// const ANIMATIONS = 'animations';
|
||||
// const START_TIMES = 'start-times';
|
||||
// const PAUSE_START = 'pause-start';
|
||||
// const PAUSE_TIME = 'pause-time';
|
||||
// const _raf = function(callback):number|null {return setTimeout(callback, 1000/60)}
|
||||
// const _caf = function(id: number):void {clearTimeout(id)}
|
||||
|
||||
export class Timeline {
|
||||
state: string
|
||||
constructor() {
|
||||
this.state = 'Initiated';
|
||||
this[ANIMATIONS] = new Set();
|
||||
this[START_TIMES] = new Map();
|
||||
}
|
||||
start() {
|
||||
if (!(this.state === 'Initiated')) return;
|
||||
this.state = 'Started';
|
||||
|
||||
let startTime = Date.now();
|
||||
this[PAUSE_TIME] = 0;
|
||||
this[TICK] = () => {
|
||||
let now = Date.now();
|
||||
this[ANIMATIONS].forEach((animation) => {
|
||||
let t: number;
|
||||
if (this[START_TIMES].get(animation) < startTime) {
|
||||
t = now - startTime - animation.delay - this[PAUSE_TIME];
|
||||
} else {
|
||||
t = now - this[START_TIMES].get(animation) - animation.delay - this[PAUSE_TIME];
|
||||
}
|
||||
|
||||
if (t > animation.duration) {
|
||||
this[ANIMATIONS].delete(animation);
|
||||
t = animation.duration;
|
||||
}
|
||||
if (t > 0) animation.run(t);
|
||||
})
|
||||
// for (let animation of this[ANIMATIONS]) {
|
||||
// let t: number;
|
||||
// console.log('animation', animation)
|
||||
// if (this[START_TIMES].get(animation) < startTime) {
|
||||
// t = now - startTime - animation.delay - this[PAUSE_TIME];
|
||||
// } else {
|
||||
// t = now - this[START_TIMES].get(animation) - animation.delay - this[PAUSE_TIME];
|
||||
// }
|
||||
|
||||
// if (t > animation.duration) {
|
||||
// this[ANIMATIONS].delete(animation);
|
||||
// t = animation.duration;
|
||||
// }
|
||||
// if (t > 0) animation.run(t);
|
||||
// }
|
||||
this[TICK_HANDLER] = _raf(this[TICK]);
|
||||
};
|
||||
this[TICK]();
|
||||
}
|
||||
pause() {
|
||||
if (!(this.state === 'Started')) return;
|
||||
this.state = 'Paused';
|
||||
|
||||
this[PAUSE_START] = Date.now();
|
||||
_caf(this[TICK_HANDLER]);
|
||||
}
|
||||
resume() {
|
||||
if (!(this.state === 'Paused')) return;
|
||||
this.state = 'Started';
|
||||
|
||||
this[PAUSE_TIME] += Date.now() - this[PAUSE_START];
|
||||
this[TICK]();
|
||||
}
|
||||
reset() {
|
||||
this.pause();
|
||||
this.state = 'Initiated';
|
||||
this[PAUSE_TIME] = 0;
|
||||
this[PAUSE_START] = 0;
|
||||
this[ANIMATIONS] = new Set();
|
||||
this[START_TIMES] = new Map();
|
||||
this[TICK_HANDLER] = null;
|
||||
}
|
||||
add(animation: any, startTime?: number) {
|
||||
if (arguments.length < 2) startTime = Date.now();
|
||||
this[ANIMATIONS].add(animation);
|
||||
this[START_TIMES].set(animation, startTime);
|
||||
}
|
||||
}
|
||||
|
||||
export class Animation {
|
||||
startValue: number
|
||||
endValue: number
|
||||
duration: number
|
||||
timingFunction: (t: number) => number
|
||||
delay: number
|
||||
template: (t: number) => void
|
||||
constructor(startValue: number, endValue: number, duration: number, delay: number, timingFunction: (t: number) => number, template: (v: number) => void) {
|
||||
timingFunction = timingFunction || (v => v);
|
||||
template = template || (v => v);
|
||||
|
||||
this.startValue = startValue;
|
||||
this.endValue = endValue;
|
||||
this.duration = duration;
|
||||
this.timingFunction = timingFunction;
|
||||
this.delay = delay;
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
run(time: number) {
|
||||
let range = this.endValue - this.startValue;
|
||||
let progress = time / this.duration
|
||||
if(progress != 1) progress = this.timingFunction(progress)
|
||||
this.template(this.startValue + range * progress)
|
||||
}
|
||||
}
|
||||
3888
uni_modules/lime-shared/areaData/city-china.json
Normal file
3888
uni_modules/lime-shared/areaData/city-china.json
Normal file
File diff suppressed because it is too large
Load Diff
71
uni_modules/lime-shared/areaData/index.ts
Normal file
71
uni_modules/lime-shared/areaData/index.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
// @ts-nocheck
|
||||
import _areaList from './city-china.json';
|
||||
export const areaList = _areaList
|
||||
// #ifndef UNI-APP-X
|
||||
type UTSJSONObject = Record<string, string>
|
||||
// #endif
|
||||
// #ifdef UNI-APP-X
|
||||
type Object = UTSJSONObject
|
||||
// #endif
|
||||
type AreaList = {
|
||||
province_list : Map<string, string>;
|
||||
city_list : Map<string, string>;
|
||||
county_list : Map<string, string>;
|
||||
}
|
||||
// type CascaderOption = {
|
||||
// text : string;
|
||||
// value : string;
|
||||
// children ?: CascaderOption[];
|
||||
// };
|
||||
|
||||
const makeOption = (
|
||||
label : string,
|
||||
value : string,
|
||||
children ?: UTSJSONObject[],
|
||||
) : UTSJSONObject => ({
|
||||
label,
|
||||
value,
|
||||
children,
|
||||
});
|
||||
|
||||
|
||||
|
||||
export function useCascaderAreaData() : UTSJSONObject[] {
|
||||
const city = areaList['city_list'] as UTSJSONObject
|
||||
const county = areaList['county_list'] as UTSJSONObject
|
||||
const province = areaList['province_list'] as UTSJSONObject
|
||||
const provinceMap = new Map<string, UTSJSONObject>();
|
||||
Object.keys(province).forEach((code) => {
|
||||
provinceMap.set(code.slice(0, 2), makeOption(`${province[code]}`, code, []));
|
||||
});
|
||||
|
||||
const cityMap = new Map<string, UTSJSONObject>();
|
||||
|
||||
Object.keys(city).forEach((code) => {
|
||||
const option = makeOption(`${city[code]}`, code, []);
|
||||
cityMap.set(code.slice(0, 4), option);
|
||||
|
||||
const _province = provinceMap.get(code.slice(0, 2));
|
||||
if (_province != null) {
|
||||
(_province['children'] as UTSJSONObject[]).push(option)
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(county).forEach((code) => {
|
||||
const _city = cityMap.get(code.slice(0, 4));
|
||||
if (_city != null) {
|
||||
(_city['children'] as UTSJSONObject[]).push(makeOption(`${county[code]}`, code, null));
|
||||
}
|
||||
});
|
||||
|
||||
// #ifndef APP-ANDROID || APP-IOS
|
||||
return Array.from(provinceMap.values());
|
||||
// #endif
|
||||
// #ifdef APP-ANDROID || APP-IOS
|
||||
const obj : UTSJSONObject[] = []
|
||||
provinceMap.forEach((value, code) => {
|
||||
obj.push(value)
|
||||
})
|
||||
return obj
|
||||
// #endif
|
||||
}
|
||||
10
uni_modules/lime-shared/arrayBufferToFile/index.ts
Normal file
10
uni_modules/lime-shared/arrayBufferToFile/index.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef UNI-APP-X && APP
|
||||
// export * from './vue.ts'
|
||||
export { arrayBufferToFile } from './vue.ts'
|
||||
// #endif
|
||||
|
||||
// #ifdef UNI-APP-X && APP
|
||||
// export * from './uvue.uts'
|
||||
export { arrayBufferToFile } from './uvue.uts'
|
||||
// #endif
|
||||
10
uni_modules/lime-shared/arrayBufferToFile/uvue.uts
Normal file
10
uni_modules/lime-shared/arrayBufferToFile/uvue.uts
Normal file
@@ -0,0 +1,10 @@
|
||||
// @ts-nocheck
|
||||
// import {platform} from '../platform'
|
||||
/**
|
||||
* buffer转路径
|
||||
* @param {Object} buffer
|
||||
*/
|
||||
// @ts-nocheck
|
||||
export function arrayBufferToFile(buffer: ArrayBuffer, name?: string, format?:string):Promise<(File|string)> {
|
||||
console.error('[arrayBufferToFile] 当前环境不支持')
|
||||
}
|
||||
63
uni_modules/lime-shared/arrayBufferToFile/vue.ts
Normal file
63
uni_modules/lime-shared/arrayBufferToFile/vue.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
// @ts-nocheck
|
||||
import {platform} from '../platform'
|
||||
/**
|
||||
* buffer转路径
|
||||
* @param {Object} buffer
|
||||
*/
|
||||
// @ts-nocheck
|
||||
export function arrayBufferToFile(buffer: ArrayBuffer | Blob, name?: string, format?:string):Promise<(File|string)> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// #ifdef MP
|
||||
const fs = uni.getFileSystemManager()
|
||||
//自定义文件名
|
||||
if (!name && !format) {
|
||||
reject(new Error('ERROR_NAME_PARSE'))
|
||||
}
|
||||
const fileName = `${name || new Date().getTime()}.${format.replace(/(.+)?\//,'')}`;
|
||||
let pre = platform()
|
||||
const filePath = `${pre.env.USER_DATA_PATH}/${fileName}`
|
||||
fs.writeFile({
|
||||
filePath,
|
||||
data: buffer,
|
||||
success() {
|
||||
resolve(filePath)
|
||||
},
|
||||
fail(err) {
|
||||
console.error(err)
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
const file = new File([buffer], name, {
|
||||
type: format,
|
||||
});
|
||||
resolve(file)
|
||||
// #endif
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
|
||||
const base64 = uni.arrayBufferToBase64(buffer)
|
||||
bitmap.loadBase64Data(base64, () => {
|
||||
if (!name && !format) {
|
||||
reject(new Error('ERROR_NAME_PARSE'))
|
||||
}
|
||||
const fileNmae = `${name || new Date().getTime()}.${format.replace(/(.+)?\//,'')}`;
|
||||
const filePath = `_doc/uniapp_temp/${fileNmae}`
|
||||
bitmap.save(filePath, {},
|
||||
() => {
|
||||
bitmap.clear()
|
||||
resolve(filePath)
|
||||
},
|
||||
(error) => {
|
||||
bitmap.clear()
|
||||
reject(error)
|
||||
})
|
||||
}, (error) => {
|
||||
bitmap.clear()
|
||||
reject(error)
|
||||
})
|
||||
// #endif
|
||||
})
|
||||
}
|
||||
13
uni_modules/lime-shared/base64ToArrayBuffer/index.ts
Normal file
13
uni_modules/lime-shared/base64ToArrayBuffer/index.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
// @ts-nocheck
|
||||
// 未完成
|
||||
export function base64ToArrayBuffer(base64 : string) {
|
||||
const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
|
||||
if (!format) {
|
||||
new Error('ERROR_BASE64SRC_PARSE')
|
||||
}
|
||||
if(uni.base64ToArrayBuffer) {
|
||||
return uni.base64ToArrayBuffer(bodyData)
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
11
uni_modules/lime-shared/base64ToPath/index.ts
Normal file
11
uni_modules/lime-shared/base64ToPath/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef UNI-APP-X && APP
|
||||
// export * from './vue.ts'
|
||||
export { base64ToPath } from './vue.ts'
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef UNI-APP-X && APP
|
||||
// export * from './uvue.uts'
|
||||
export { base64ToPath } from './uvue.uts'
|
||||
// #endif
|
||||
22
uni_modules/lime-shared/base64ToPath/uvue.uts
Normal file
22
uni_modules/lime-shared/base64ToPath/uvue.uts
Normal file
@@ -0,0 +1,22 @@
|
||||
// @ts-nocheck
|
||||
import { processFile, type ProcessFileOptions } from '@/uni_modules/lime-file-utils'
|
||||
|
||||
/**
|
||||
* base64转路径
|
||||
* @param {Object} base64
|
||||
*/
|
||||
export function base64ToPath(base64: string, filename: string | null = null):Promise<string> {
|
||||
return new Promise((resolve,reject) => {
|
||||
processFile({
|
||||
type: 'toDataURL',
|
||||
path: base64,
|
||||
filename,
|
||||
success(res: string){
|
||||
resolve(res)
|
||||
},
|
||||
fail(err){
|
||||
reject(err)
|
||||
}
|
||||
} as ProcessFileOptions)
|
||||
})
|
||||
}
|
||||
75
uni_modules/lime-shared/base64ToPath/vue.ts
Normal file
75
uni_modules/lime-shared/base64ToPath/vue.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
// @ts-nocheck
|
||||
import {platform} from '../platform'
|
||||
/**
|
||||
* base64转路径
|
||||
* @param {Object} base64
|
||||
*/
|
||||
export function base64ToPath(base64: string, filename?: string):Promise<string> {
|
||||
const [, format] = /^data:image\/(\w+);base64,/.exec(base64) || [];
|
||||
return new Promise((resolve, reject) => {
|
||||
// #ifdef MP
|
||||
const fs = uni.getFileSystemManager()
|
||||
//自定义文件名
|
||||
if (!filename && !format) {
|
||||
reject(new Error('ERROR_BASE64SRC_PARSE'))
|
||||
}
|
||||
// const time = new Date().getTime();
|
||||
const name = filename || `${new Date().getTime()}.${format}`;
|
||||
let pre = platform()
|
||||
const filePath = `${pre.env.USER_DATA_PATH}/${name}`
|
||||
fs.writeFile({
|
||||
filePath,
|
||||
data: base64.split(',')[1],
|
||||
encoding: 'base64',
|
||||
success() {
|
||||
resolve(filePath)
|
||||
},
|
||||
fail(err) {
|
||||
console.error(err)
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
// mime类型
|
||||
let mimeString = base64.split(',')[0].split(':')[1].split(';')[0];
|
||||
//base64 解码
|
||||
let byteString = atob(base64.split(',')[1]);
|
||||
//创建缓冲数组
|
||||
let arrayBuffer = new ArrayBuffer(byteString.length);
|
||||
//创建视图
|
||||
let intArray = new Uint8Array(arrayBuffer);
|
||||
for (let i = 0; i < byteString.length; i++) {
|
||||
intArray[i] = byteString.charCodeAt(i);
|
||||
}
|
||||
resolve(URL.createObjectURL(new Blob([intArray], {
|
||||
type: mimeString
|
||||
})))
|
||||
// #endif
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
|
||||
bitmap.loadBase64Data(base64, () => {
|
||||
if (!filename && !format) {
|
||||
reject(new Error('ERROR_BASE64SRC_PARSE'))
|
||||
}
|
||||
// const time = new Date().getTime();
|
||||
const name = filename || `${new Date().getTime()}.${format}`;
|
||||
const filePath = `_doc/uniapp_temp/${name}`
|
||||
bitmap.save(filePath, {},
|
||||
() => {
|
||||
bitmap.clear()
|
||||
resolve(filePath)
|
||||
},
|
||||
(error) => {
|
||||
bitmap.clear()
|
||||
reject(error)
|
||||
})
|
||||
}, (error) => {
|
||||
bitmap.clear()
|
||||
reject(error)
|
||||
})
|
||||
// #endif
|
||||
})
|
||||
}
|
||||
21
uni_modules/lime-shared/camelCase/index.ts
Normal file
21
uni_modules/lime-shared/camelCase/index.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* 将字符串转换为 camelCase 或 PascalCase 风格的命名约定
|
||||
* @param str 要转换的字符串
|
||||
* @param isPascalCase 指示是否转换为 PascalCase 的布尔值,默认为 false
|
||||
* @returns 转换后的字符串
|
||||
*/
|
||||
export function camelCase(str: string, isPascalCase: boolean = false): string {
|
||||
// 将字符串分割成单词数组
|
||||
let words: string[] = str.split(/[\s_-]+/);
|
||||
|
||||
// 将数组中的每个单词首字母大写(除了第一个单词)
|
||||
let camelCased: string[] = words.map((word, index):string => {
|
||||
if (index == 0 && !isPascalCase) {
|
||||
return word.toLowerCase(); // 第一个单词全小写
|
||||
}
|
||||
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
||||
});
|
||||
|
||||
// 将数组中的单词拼接成一个字符串
|
||||
return camelCased.join('');
|
||||
};
|
||||
67
uni_modules/lime-shared/canIUseCanvas2d/index.ts
Normal file
67
uni_modules/lime-shared/canIUseCanvas2d/index.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
// @ts-nocheck
|
||||
|
||||
// #ifndef UNI-APP-X && APP
|
||||
|
||||
// #ifdef MP-ALIPAY
|
||||
interface My {
|
||||
SDKVersion: string
|
||||
}
|
||||
declare var my: My
|
||||
// #endif
|
||||
|
||||
function compareVersion(v1:string, v2:string) {
|
||||
let a1 = v1.split('.');
|
||||
let a2 = v2.split('.');
|
||||
const len = Math.max(a1.length, a2.length);
|
||||
|
||||
while (a1.length < len) {
|
||||
a1.push('0');
|
||||
}
|
||||
while (a2.length < len) {
|
||||
a2.push('0');
|
||||
}
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
const num1 = parseInt(a1[i], 10);
|
||||
const num2 = parseInt(a2[i], 10);
|
||||
|
||||
if (num1 > num2) {
|
||||
return 1;
|
||||
}
|
||||
if (num1 < num2) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function gte(version: string) {
|
||||
let {SDKVersion} = uni.getSystemInfoSync();
|
||||
// #ifdef MP-ALIPAY
|
||||
SDKVersion = my.SDKVersion
|
||||
// #endif
|
||||
return compareVersion(SDKVersion, version) >= 0;
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
/** 环境是否支持canvas 2d */
|
||||
export function canIUseCanvas2d(): boolean {
|
||||
// #ifdef MP-WEIXIN
|
||||
return gte('2.9.0');
|
||||
// #endif
|
||||
// #ifdef MP-ALIPAY
|
||||
return gte('2.7.0');
|
||||
// #endif
|
||||
// #ifdef MP-TOUTIAO
|
||||
return gte('1.78.0');
|
||||
// #endif
|
||||
// #ifdef UNI-APP-X && WEB || UNI-APP-X && APP
|
||||
return true;
|
||||
// #endif
|
||||
// #ifndef MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO
|
||||
return false
|
||||
// #endif
|
||||
|
||||
}
|
||||
111
uni_modules/lime-shared/capitalizedAmount/index.ts
Normal file
111
uni_modules/lime-shared/capitalizedAmount/index.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
// @ts-nocheck
|
||||
import { isString } from "../isString";
|
||||
import { isNumber } from "../isNumber";
|
||||
/**
|
||||
* 将金额转换为中文大写形式
|
||||
* @param {number | string} amount - 需要转换的金额,可以是数字或字符串
|
||||
* @returns {string} 转换后的中文大写金额
|
||||
*/
|
||||
export function capitalizedAmount(amount : number) : string
|
||||
export function capitalizedAmount(amount : string) : string
|
||||
export function capitalizedAmount(amount : any | null) : string {
|
||||
try {
|
||||
let _amountStr :string;
|
||||
let _amountNum :number = 0;
|
||||
// 如果输入是字符串,先将其转换为数字,并去除逗号
|
||||
if (typeof amount == 'string') {
|
||||
_amountNum = parseFloat((amount as string).replace(/,/g, ''));
|
||||
}
|
||||
if(isNumber(amount)) {
|
||||
_amountNum = amount as number
|
||||
}
|
||||
// 判断输入是否为有效的金额 || isNaN(amount)
|
||||
if (amount == null) throw new Error('不是有效的金额!');
|
||||
|
||||
let result = '';
|
||||
|
||||
// 处理负数情况
|
||||
if (_amountNum < 0) {
|
||||
result = '欠';
|
||||
_amountNum = Math.abs(_amountNum);
|
||||
}
|
||||
|
||||
// 金额不能超过千亿以上
|
||||
if (_amountNum >= 10e11) throw new Error('计算金额过大!');
|
||||
|
||||
// 保留两位小数并转换为字符串
|
||||
_amountStr = _amountNum.toFixed(2);
|
||||
|
||||
// 定义数字、单位和小数单位的映射
|
||||
const digits = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
|
||||
const units = ['', '拾', '佰', '仟'];
|
||||
const bigUnits = ['', '万', '亿'];
|
||||
const decimalUnits = ['角', '分'];
|
||||
|
||||
// 分离整数部分和小数部分
|
||||
const amountArray = _amountStr.split('.');
|
||||
let integerPart = amountArray[0]; // string| number[]
|
||||
const decimalPart = amountArray[1];
|
||||
|
||||
// 处理整数部分
|
||||
if (integerPart != '0') {
|
||||
let _integerPart = integerPart.split('').map((item):number => parseInt(item));
|
||||
|
||||
// 将整数部分按四位一级进行分组
|
||||
const levels = _integerPart.reverse().reduce((prev:string[][], item, index):string[][] => {
|
||||
// const level = prev?.[0]?.length < 4 ? prev[0] : [];
|
||||
const level = prev.length > 0 && prev[0].length < 4 ? prev[0]: []
|
||||
|
||||
const value = item == 0 ? digits[item] : digits[item] + units[index % 4];
|
||||
|
||||
level.unshift(value);
|
||||
|
||||
if (level.length == 1) {
|
||||
prev.unshift(level);
|
||||
} else {
|
||||
prev[0] = level;
|
||||
}
|
||||
|
||||
return prev;
|
||||
}, [] as string[][]);
|
||||
// 将分组后的整数部分转换为中文大写形式
|
||||
result += levels.reduce((prev, item, index):string => {
|
||||
let _level = bigUnits[levels.length - index - 1];
|
||||
let _item = item.join('').replace(/(零)\1+/g, '$1');
|
||||
|
||||
if (_item == '零') {
|
||||
_level = '';
|
||||
_item = '';
|
||||
} else if (_item.endsWith('零')) {
|
||||
_item = _item.slice(0, _item.length - 1);
|
||||
}
|
||||
|
||||
return prev + _item + _level;
|
||||
}, '');
|
||||
} else {
|
||||
result += '零';
|
||||
}
|
||||
|
||||
// 添加元
|
||||
result += '元';
|
||||
|
||||
// 处理小数部分
|
||||
if (decimalPart != '00') {
|
||||
if (result == '零元') result = '';
|
||||
|
||||
for (let i = 0; i < decimalPart.length; i++) {
|
||||
const digit = parseInt(decimalPart.charAt(i));
|
||||
|
||||
if (digit != 0) {
|
||||
result += digits[digit] + decimalUnits[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result += '整';
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error : Error) {
|
||||
return error.message;
|
||||
}
|
||||
};
|
||||
91
uni_modules/lime-shared/changelog.md
Normal file
91
uni_modules/lime-shared/changelog.md
Normal file
@@ -0,0 +1,91 @@
|
||||
## 0.4.2(2025-09-26)
|
||||
- feat: 增加`cssToObj`
|
||||
## 0.4.1(2025-06-13)
|
||||
- fix:测试hbx4.71更新
|
||||
## 0.4.0(2025-06-04)
|
||||
- fix:测试hbx4.71更新
|
||||
## 0.3.9(2025-06-04)
|
||||
- fix: 因hbx4.71更新导致mac用户下载的文件被重命名,故退回4.66
|
||||
## 0.3.8(2025-06-03)
|
||||
- fix: 修复`while`在vue2报错的问题
|
||||
## 0.3.7(2025-05-21)
|
||||
- fix: 修复`merge`在vue2报错的问题
|
||||
## 0.3.6(2025-05-17)
|
||||
- fix: 修复`raf`导错目录的问题
|
||||
## 0.3.5(2025-05-16)
|
||||
- feat: 增加`isIP`
|
||||
- feat: 增加`merge`
|
||||
- feat: 增加`isByteLength`
|
||||
- feat: 增加`isRegExp`
|
||||
## 0.3.4(2025-04-27)
|
||||
- fix: 修复exif缺少isBase64的问题
|
||||
## 0.3.3(2025-04-14)
|
||||
- fix: 修复4.61上的类型问题
|
||||
## 0.3.2(2025-04-14)
|
||||
- fix: 修复4.61上的类型问题
|
||||
## 0.3.1(2025-03-28)
|
||||
- fix: 修复getRect在nvue上的问题
|
||||
## 0.3.0(2025-02-27)
|
||||
- fix: 修复部分函数无法在uniappx上运行的问题
|
||||
## 0.2.9(2025-02-19)
|
||||
- chore: 更新文档
|
||||
## 0.2.8(2025-02-11)
|
||||
- chore: 更新文档
|
||||
## 0.2.7(2025-01-17)
|
||||
- fix: 针对canvas 平台判断优化
|
||||
## 0.2.6(2025-01-09)
|
||||
- feat: 增加`areaData`中国省市区数据
|
||||
## 0.2.5(2025-01-07)
|
||||
- fix: animation在app上类型问题
|
||||
## 0.2.4(2025-01-04)
|
||||
- feat: getRect类型问题
|
||||
## 0.2.3(2025-01-01)
|
||||
- chore: unitConvert使用uni.rpx2px
|
||||
## 0.2.2(2024-12-11)
|
||||
- chore: 动画使用`requestAnimationFrame`
|
||||
## 0.2.1(2024-11-20)
|
||||
- feat: 增加`characterLimit`
|
||||
## 0.2.0(2024-11-14)
|
||||
- fix: vue2的类型问题
|
||||
## 0.1.9(2024-11-14)
|
||||
- feat: 增加`shuffle`
|
||||
## 0.1.8(2024-10-08)
|
||||
- fix: vue2 条件编译 // #ifdef APP-IOS || APP-ANDROID 会生效
|
||||
## 0.1.7(2024-09-23)
|
||||
- fix: raf 类型跟随版本变更
|
||||
## 0.1.6(2024-07-24)
|
||||
- fix: vue2 app ts需要明确的后缀,所有补全
|
||||
- chore: 减少依赖
|
||||
## 0.1.5(2024-07-21)
|
||||
- feat: 删除 Hooks
|
||||
- feat: 兼容uniappx
|
||||
## 0.1.4(2023-09-05)
|
||||
- feat: 增加 Hooks `useIntersectionObserver`
|
||||
- feat: 增加 `floatAdd`
|
||||
- feat: 因为本人插件兼容 vue2 需要使用 `composition-api`,故增加vue文件代码插件的条件编译
|
||||
## 0.1.3(2023-08-13)
|
||||
- feat: 增加 `camelCase`
|
||||
## 0.1.2(2023-07-17)
|
||||
- feat: 增加 `getClassStr`
|
||||
## 0.1.1(2023-07-06)
|
||||
- feat: 增加 `isNumeric`, 区别于 `isNumber`
|
||||
## 0.1.0(2023-06-30)
|
||||
- fix: `clamp`忘记导出了
|
||||
## 0.0.9(2023-06-27)
|
||||
- feat: 增加`arrayBufferToFile`
|
||||
## 0.0.8(2023-06-19)
|
||||
- feat: 增加`createAnimation`、`clamp`
|
||||
## 0.0.7(2023-06-08)
|
||||
- chore: 更新注释
|
||||
## 0.0.6(2023-06-08)
|
||||
- chore: 增加`createImage`为`lime-watermark`和`lime-qrcode`提供依赖
|
||||
## 0.0.5(2023-06-03)
|
||||
- chore: 更新注释
|
||||
## 0.0.4(2023-05-22)
|
||||
- feat: 增加`range`,`exif`,`selectComponent`
|
||||
## 0.0.3(2023-05-08)
|
||||
- feat: 增加`fillZero`,`debounce`,`throttle`,`random`
|
||||
## 0.0.2(2023-05-05)
|
||||
- chore: 更新文档
|
||||
## 0.0.1(2023-05-05)
|
||||
- 无
|
||||
63
uni_modules/lime-shared/characterLimit/index.ts
Normal file
63
uni_modules/lime-shared/characterLimit/index.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 计算字符串字符的长度并可以截取字符串。
|
||||
* @param char 传入字符串(maxcharacter条件下,一个汉字表示两个字符)
|
||||
* @param max 规定最大字符串长度
|
||||
* @returns 当没有传入maxCharacter/maxLength 时返回字符串字符长度,当传入maxCharacter/maxLength时返回截取之后的字符串和长度。
|
||||
*/
|
||||
export type CharacterLengthResult = {
|
||||
length : number;
|
||||
characters : string;
|
||||
}
|
||||
// #ifdef APP-ANDROID
|
||||
type ChartType = any
|
||||
// #endif
|
||||
// #ifndef APP-ANDROID
|
||||
type ChartType = string | number
|
||||
// #endif
|
||||
|
||||
export function characterLimit(type : string, char : ChartType, max : number) : CharacterLengthResult {
|
||||
const str = `${char}`;
|
||||
|
||||
if (str.length == 0) {
|
||||
return {
|
||||
length: 0,
|
||||
characters: '',
|
||||
} as CharacterLengthResult
|
||||
}
|
||||
|
||||
if (type == 'maxcharacter') {
|
||||
let len = 0;
|
||||
for (let i = 0; i < str.length; i += 1) {
|
||||
let currentStringLength : number// = 0;
|
||||
const code = str.charCodeAt(i)!
|
||||
if (code > 127 || code == 94) {
|
||||
currentStringLength = 2;
|
||||
} else {
|
||||
currentStringLength = 1;
|
||||
}
|
||||
if (len + currentStringLength > max) {
|
||||
return {
|
||||
length: len,
|
||||
characters: str.slice(0, i),
|
||||
} as CharacterLengthResult
|
||||
}
|
||||
len += currentStringLength;
|
||||
}
|
||||
return {
|
||||
length: len,
|
||||
characters: str,
|
||||
} as CharacterLengthResult
|
||||
} else if (type == 'maxlength') {
|
||||
const length = str.length > max ? max : str.length;
|
||||
return {
|
||||
length: length,
|
||||
characters: str.slice(0, length),
|
||||
} as CharacterLengthResult
|
||||
}
|
||||
|
||||
return {
|
||||
length: str.length,
|
||||
characters: str,
|
||||
} as CharacterLengthResult
|
||||
};
|
||||
16
uni_modules/lime-shared/clamp/index.ts
Normal file
16
uni_modules/lime-shared/clamp/index.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 将一个值限制在指定的范围内
|
||||
* @param val 要限制的值
|
||||
* @param min 最小值
|
||||
* @param max 最大值
|
||||
* @returns 限制后的值
|
||||
*/
|
||||
export function clamp(val: number, min: number, max: number): number {
|
||||
return Math.max(min, Math.min(max, val));
|
||||
}
|
||||
|
||||
|
||||
// console.log(clamp(5 ,0, 10)); // 输出: 5(在范围内,不做更改)
|
||||
// console.log(clamp(-5 ,0, 10)); // 输出: 0(小于最小值,被限制为最小值)
|
||||
// console.log(clamp(15 ,0, 10)); // 输出: 10(大于最大值,被限制为最大值)
|
||||
53
uni_modules/lime-shared/classNames/index.ts
Normal file
53
uni_modules/lime-shared/classNames/index.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
// @ts-nocheck
|
||||
|
||||
// #ifdef UNI-APP-X && APP
|
||||
import { isNumber } from '../isNumber'
|
||||
import { isString } from '../isString'
|
||||
import { isDef } from '../isDef'
|
||||
// #endif
|
||||
|
||||
/**
|
||||
* 获取对象的类名字符串
|
||||
* @param obj - 需要处理的对象
|
||||
* @returns 由对象属性作为类名组成的字符串
|
||||
*/
|
||||
export function classNames<T>(obj : T) : string {
|
||||
let classNames : string[] = [];
|
||||
// #ifdef APP-ANDROID || APP-HARMONY
|
||||
if (obj instanceof UTSJSONObject) {
|
||||
(obj as UTSJSONObject).toMap().forEach((value, key) => {
|
||||
if (isDef(value)) {
|
||||
if (isNumber(value)) {
|
||||
classNames.push(key);
|
||||
}
|
||||
if (isString(value) && value !== '') {
|
||||
classNames.push(key);
|
||||
}
|
||||
if (typeof value == 'boolean' && (value as boolean)) {
|
||||
classNames.push(key);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
// #ifndef APP-ANDROID || APP-HARMONY
|
||||
// 遍历对象的属性
|
||||
for (let key in obj) {
|
||||
// 检查属性确实属于对象自身且其值为true
|
||||
if ((obj as any).hasOwnProperty(key) && obj[key]) {
|
||||
// 将属性名添加到类名数组中
|
||||
classNames.push(key);
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
// 将类名数组用空格连接成字符串并返回
|
||||
return classNames.join(' ');
|
||||
}
|
||||
|
||||
|
||||
// 示例
|
||||
// const obj = { foo: true, bar: false, baz: true };
|
||||
// const classNameStr = stringify(obj);
|
||||
// console.log(classNameStr); // 输出: "foo baz"
|
||||
12
uni_modules/lime-shared/cloneDeep/index.ts
Normal file
12
uni_modules/lime-shared/cloneDeep/index.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
// @ts-nocheck
|
||||
|
||||
// #ifdef APP-ANDROID
|
||||
// export * from './uvue.uts'
|
||||
export { cloneDeep } from './uvue.uts'
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifndef APP-ANDROID
|
||||
// export * from './vue.ts'
|
||||
export { cloneDeep } from './vue.ts'
|
||||
// #endif
|
||||
39
uni_modules/lime-shared/cloneDeep/uvue.uts
Normal file
39
uni_modules/lime-shared/cloneDeep/uvue.uts
Normal file
@@ -0,0 +1,39 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 深度克隆一个对象或数组
|
||||
* @param obj 要克隆的对象或数组
|
||||
* @returns 克隆后的对象或数组
|
||||
*/
|
||||
export function cloneDeep<T>(obj : any) : T {
|
||||
if (obj instanceof Set) {
|
||||
const set = new Set<any>();
|
||||
obj.forEach((item : any) => {
|
||||
set.add(item)
|
||||
})
|
||||
return set as T;
|
||||
}
|
||||
if (obj instanceof Map) {
|
||||
const map = new Map<any, any>();
|
||||
obj.forEach((value : any, key : any) => {
|
||||
map.set(key, value)
|
||||
})
|
||||
return map as T;
|
||||
}
|
||||
|
||||
if (obj instanceof RegExp) {
|
||||
return new RegExp(obj) as T;
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return (obj as any[]).map((item : any):any => item) as T;
|
||||
}
|
||||
|
||||
if (obj instanceof Date) {
|
||||
return new Date(obj.getTime()) as T;
|
||||
}
|
||||
|
||||
if (typeof obj == 'object') {
|
||||
return UTSJSONObject.assign<T>({}, toRaw(obj))!
|
||||
}
|
||||
return obj as T
|
||||
}
|
||||
103
uni_modules/lime-shared/cloneDeep/vue.ts
Normal file
103
uni_modules/lime-shared/cloneDeep/vue.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 深度克隆一个对象或数组
|
||||
* @param obj 要克隆的对象或数组
|
||||
* @returns 克隆后的对象或数组
|
||||
*/
|
||||
export function cloneDeep<T>(obj: any): T {
|
||||
// 如果传入的对象为空,返回空
|
||||
if (obj === null) {
|
||||
return null as unknown as T;
|
||||
}
|
||||
|
||||
// 如果传入的对象是 Set 类型,则将其转换为数组,并通过新的 Set 构造函数创建一个新的 Set 对象
|
||||
if (obj instanceof Set) {
|
||||
return new Set([...obj]) as unknown as T;
|
||||
}
|
||||
|
||||
// 如果传入的对象是 Map 类型,则将其转换为数组,并通过新的 Map 构造函数创建一个新的 Map 对象
|
||||
if (obj instanceof Map) {
|
||||
return new Map([...obj]) as unknown as T;
|
||||
}
|
||||
|
||||
// 如果传入的对象是 WeakMap 类型,则直接用传入的 WeakMap 对象进行赋值
|
||||
if (obj instanceof WeakMap) {
|
||||
let weakMap = new WeakMap();
|
||||
weakMap = obj;
|
||||
return weakMap as unknown as T;
|
||||
}
|
||||
|
||||
// 如果传入的对象是 WeakSet 类型,则直接用传入的 WeakSet 对象进行赋值
|
||||
if (obj instanceof WeakSet) {
|
||||
let weakSet = new WeakSet();
|
||||
weakSet = obj;
|
||||
return weakSet as unknown as T;
|
||||
}
|
||||
|
||||
// 如果传入的对象是 RegExp 类型,则通过新的 RegExp 构造函数创建一个新的 RegExp 对象
|
||||
if (obj instanceof RegExp) {
|
||||
return new RegExp(obj) as unknown as T;
|
||||
}
|
||||
|
||||
// 如果传入的对象是 undefined 类型,则返回 undefined
|
||||
if (typeof obj === 'undefined') {
|
||||
return undefined as unknown as T;
|
||||
}
|
||||
|
||||
// 如果传入的对象是数组,则递归调用 cloneDeep 函数对数组中的每个元素进行克隆
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map(cloneDeep) as unknown as T;
|
||||
}
|
||||
|
||||
// 如果传入的对象是 Date 类型,则通过新的 Date 构造函数创建一个新的 Date 对象
|
||||
if (obj instanceof Date) {
|
||||
return new Date(obj.getTime()) as unknown as T;
|
||||
}
|
||||
|
||||
// 如果传入的对象是普通对象,则使用递归调用 cloneDeep 函数对对象的每个属性进行克隆
|
||||
if (typeof obj === 'object') {
|
||||
const newObj: any = {};
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
newObj[key] = cloneDeep(value);
|
||||
}
|
||||
const symbolKeys = Object.getOwnPropertySymbols(obj);
|
||||
for (const key of symbolKeys) {
|
||||
newObj[key] = cloneDeep(obj[key]);
|
||||
}
|
||||
return newObj;
|
||||
}
|
||||
|
||||
// 如果传入的对象是基本数据类型(如字符串、数字等),则直接返回
|
||||
return obj;
|
||||
}
|
||||
|
||||
// 示例使用
|
||||
|
||||
// // 克隆一个对象
|
||||
// const obj = { name: 'John', age: 30 };
|
||||
// const clonedObj = cloneDeep(obj);
|
||||
|
||||
// console.log(clonedObj); // 输出: { name: 'John', age: 30 }
|
||||
// console.log(clonedObj === obj); // 输出: false (副本与原对象是独立的)
|
||||
|
||||
// // 克隆一个数组
|
||||
// const arr = [1, 2, 3];
|
||||
// const clonedArr = cloneDeep(arr);
|
||||
|
||||
// console.log(clonedArr); // 输出: [1, 2, 3]
|
||||
// console.log(clonedArr === arr); // 输出: false (副本与原数组是独立的)
|
||||
|
||||
// // 克隆一个包含嵌套对象的对象
|
||||
// const person = {
|
||||
// name: 'Alice',
|
||||
// age: 25,
|
||||
// address: {
|
||||
// city: 'New York',
|
||||
// country: 'USA',
|
||||
// },
|
||||
// };
|
||||
// const clonedPerson = cloneDeep(person);
|
||||
|
||||
// console.log(clonedPerson); // 输出: { name: 'Alice', age: 25, address: { city: 'New York', country: 'USA' } }
|
||||
// console.log(clonedPerson === person); // 输出: false (副本与原对象是独立的)
|
||||
// console.log(clonedPerson.address === person.address); // 输出: false (嵌套对象的副本也是独立的)
|
||||
22
uni_modules/lime-shared/closest/index.ts
Normal file
22
uni_modules/lime-shared/closest/index.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
// @ts-nocheck
|
||||
|
||||
/**
|
||||
* 在给定数组中找到最接近目标数字的元素。
|
||||
* @param arr 要搜索的数字数组。
|
||||
* @param target 目标数字。
|
||||
* @returns 最接近目标数字的数组元素。
|
||||
*/
|
||||
export function closest(arr: number[], target: number):number {
|
||||
return arr.reduce((pre: number, cur: number):number =>
|
||||
Math.abs(pre - target) < Math.abs(cur - target) ? pre : cur
|
||||
);
|
||||
}
|
||||
|
||||
// 示例
|
||||
// // 定义一个数字数组
|
||||
// const numbers = [1, 3, 5, 7, 9];
|
||||
|
||||
// // 在数组中找到最接近目标数字 6 的元素
|
||||
// const closestNumber = closest(numbers, 6);
|
||||
|
||||
// console.log(closestNumber); // 输出结果: 5
|
||||
407
uni_modules/lime-shared/components/lime-shared/lime-shared.vue
Normal file
407
uni_modules/lime-shared/components/lime-shared/lime-shared.vue
Normal file
@@ -0,0 +1,407 @@
|
||||
<template>
|
||||
<view id="shared" style="height: 500px; width: 300px; background-color: aqua;">
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
// #ifdef WEB
|
||||
import validator from 'validator'
|
||||
// #endif
|
||||
import { getRect, getAllRect } from '@/uni_modules/lime-shared/getRect'
|
||||
|
||||
import { camelCase } from '@/uni_modules/lime-shared/camelCase'
|
||||
import { canIUseCanvas2d } from '@/uni_modules/lime-shared/canIUseCanvas2d'
|
||||
import { clamp } from '@/uni_modules/lime-shared/clamp'
|
||||
import { cloneDeep } from '@/uni_modules/lime-shared/cloneDeep'
|
||||
import { closest } from '@/uni_modules/lime-shared/closest'
|
||||
import { debounce } from '@/uni_modules/lime-shared/debounce'
|
||||
import { fillZero } from '@/uni_modules/lime-shared/fillZero'
|
||||
import { floatAdd } from '@/uni_modules/lime-shared/floatAdd'
|
||||
import { floatMul } from '@/uni_modules/lime-shared/floatMul'
|
||||
import { floatDiv } from '@/uni_modules/lime-shared/floatDiv'
|
||||
import { floatSub } from '@/uni_modules/lime-shared/floatSub'
|
||||
import { getClassStr } from '@/uni_modules/lime-shared/getClassStr'
|
||||
import { getCurrentPage } from '@/uni_modules/lime-shared/getCurrentPage'
|
||||
import { getStyleStr } from '@/uni_modules/lime-shared/getStyleStr'
|
||||
import { hasOwn } from '@/uni_modules/lime-shared/hasOwn'
|
||||
import { isBase64 } from '@/uni_modules/lime-shared/isBase64'
|
||||
import { isBrowser } from '@/uni_modules/lime-shared/isBrowser'
|
||||
import { isDef } from '@/uni_modules/lime-shared/isDef'
|
||||
import { isEmpty } from '@/uni_modules/lime-shared/isEmpty'
|
||||
import { isFunction } from '@/uni_modules/lime-shared/isFunction'
|
||||
import { isNumber } from '@/uni_modules/lime-shared/isNumber'
|
||||
import { isNumeric } from '@/uni_modules/lime-shared/isNumeric'
|
||||
import { isObject } from '@/uni_modules/lime-shared/isObject'
|
||||
import { isPromise } from '@/uni_modules/lime-shared/isPromise'
|
||||
import { isString } from '@/uni_modules/lime-shared/isString'
|
||||
import { kebabCase } from '@/uni_modules/lime-shared/kebabCase'
|
||||
import { raf, doubleRaf } from '@/uni_modules/lime-shared/raf'
|
||||
import { random } from '@/uni_modules/lime-shared/random'
|
||||
import { range } from '@/uni_modules/lime-shared/range'
|
||||
import { sleep } from '@/uni_modules/lime-shared/sleep'
|
||||
import { throttle } from '@/uni_modules/lime-shared/throttle'
|
||||
import { toArray } from '@/uni_modules/lime-shared/toArray'
|
||||
import { toBoolean } from '@/uni_modules/lime-shared/toBoolean'
|
||||
import { toNumber } from '@/uni_modules/lime-shared/toNumber'
|
||||
import { unitConvert } from '@/uni_modules/lime-shared/unitConvert'
|
||||
import { getCurrentInstance } from '@/uni_modules/lime-shared/vue'
|
||||
import { capitalizedAmount } from '@/uni_modules/lime-shared/capitalizedAmount'
|
||||
|
||||
import { obj2url } from '@/uni_modules/lime-shared/obj2url'
|
||||
import { isURL, type IsURLOptions } from '@/uni_modules/lime-shared/isURL'
|
||||
import { isIP } from '@/uni_modules/lime-shared/isIP'
|
||||
import { isDate, type IsDateOptions } from '@/uni_modules/lime-shared/isDate'
|
||||
import { isEmail } from '@/uni_modules/lime-shared/isEmail'
|
||||
import { isRegExp } from '@/uni_modules/lime-shared/isRegExp'
|
||||
import { isValidDomain, type IsValidDomainOptions } from '@/uni_modules/lime-shared/isValidDomain'
|
||||
import { merge } from '@/uni_modules/lime-shared/merge'
|
||||
import { isByteLength, type IsByteLengthOptions } from '@/uni_modules/lime-shared/isByteLength'
|
||||
|
||||
// #ifdef VUE2
|
||||
type UTSJSONObject = any
|
||||
// #endif
|
||||
|
||||
const context = getCurrentInstance()
|
||||
// getRect('#shared', context!).then(res =>{
|
||||
// console.log('res', res.bottom)
|
||||
// })
|
||||
// getAllRect('#shared', context).then(res =>{
|
||||
// console.log('res', res)
|
||||
// })
|
||||
|
||||
|
||||
// console.log('camelCase::', camelCase("hello world"));
|
||||
// console.log('camelCase::', camelCase("my_name_is_john", true));
|
||||
// console.log('canIUseCanvas2d::', canIUseCanvas2d());
|
||||
// console.log('clamp::', clamp(5 ,0, 10));
|
||||
// console.log('cloneDeep::', cloneDeep<UTSJSONObject>({a:5}));
|
||||
// console.log('closest::', closest([1, 3, 5, 7, 9], 6));
|
||||
|
||||
|
||||
|
||||
|
||||
// const saveData = (data: any) => {
|
||||
// // 模拟保存数据的操作
|
||||
// console.log(`Saving data: ${data}`);
|
||||
// }
|
||||
|
||||
// const debouncedSaveData = debounce(saveData, 500);
|
||||
// debouncedSaveData('Data 1');
|
||||
// debouncedSaveData('Data 2');
|
||||
|
||||
// console.log('fillZero', fillZero(1))
|
||||
// console.log('floatAdd', floatAdd(0.1, 0.2), floatAdd(1.05, 0.05), floatAdd(0.1, 0.7), floatAdd(0.0001, 0.0002), floatAdd(123.456 , 789.012))
|
||||
// console.log('floatMul', floatMul(0.1, 0.02), floatMul(1.0255, 100))
|
||||
// console.log('floatDiv', floatDiv(10.44, 100), floatDiv(1.0255, 100), floatDiv(5.419909340994699, 0.2))
|
||||
// console.log('floatSub', floatSub(0.4, 0.1), floatSub(1.0255, 100))
|
||||
// const now = () : number => System.nanoTime() / 1_000_000.0
|
||||
// console.log('capitalizedAmount', capitalizedAmount(0.4))
|
||||
// console.log('capitalizedAmount', capitalizedAmount(100))
|
||||
// console.log('capitalizedAmount', capitalizedAmount(100000000))
|
||||
// console.log('capitalizedAmount', capitalizedAmount('2023.04'))
|
||||
// console.log('capitalizedAmount', capitalizedAmount(-1024))
|
||||
// console.log('now', now(), Date.now())
|
||||
// console.log('getClassStr', getClassStr({hover: true}))
|
||||
// console.log('getStyleStr', getStyleStr({ color: 'red', fontSize: '16px', backgroundColor: '', border: null }))
|
||||
// console.log('hasOwn', hasOwn({a: true}, 'key'))
|
||||
// console.log('isBase64::', isBase64("SGVsbG8sIFdvcmxkIQ=="));
|
||||
// console.log('isBrowser::', isBrowser);
|
||||
// console.log('isDef::', isDef('6'));
|
||||
// console.log('isEmpty::', isEmpty({a: true}));
|
||||
|
||||
// const b = () =>{}
|
||||
// console.log('isFunction::', isFunction(b));
|
||||
// console.log('isNumber::', isNumber('6'));
|
||||
// console.log('isNumeric::', isNumeric('6'));
|
||||
// console.log('isObject::', isObject({}));
|
||||
|
||||
// const promise = ():Promise<boolean> => {
|
||||
// return new Promise((resolve) => {
|
||||
// resolve(true)
|
||||
// })
|
||||
// }
|
||||
// const a = promise()
|
||||
// console.log('isPromise::', isPromise(a));
|
||||
// console.log('isString::', isString('null'));
|
||||
// console.log('kebabCase::', kebabCase('my love'));
|
||||
// console.log('raf::', raf(()=>{
|
||||
// console.log('raf:::1')
|
||||
// }));
|
||||
// console.log('doubleRaf::', doubleRaf(()=>{
|
||||
// console.log('doubleRaf:::1')
|
||||
// }));
|
||||
// console.log('random', random(0, 10))
|
||||
// console.log('random', random(0, 1, 2))
|
||||
// console.log('range', range(0, 10, 2))
|
||||
// console.log('sleep', sleep(300).then(res => {
|
||||
// console.log('log')
|
||||
// }))
|
||||
|
||||
// const handleScroll = (a: string) => {
|
||||
// console.log("Scroll event handled!", a);
|
||||
// }
|
||||
|
||||
// // // 使用节流函数对 handleScroll 进行节流,间隔时间为 500 毫秒
|
||||
// const throttledScroll = throttle(handleScroll, 500);
|
||||
// throttledScroll('5');
|
||||
// const page = getCurrentPage()
|
||||
// console.log('getCurrentPage::', page)
|
||||
|
||||
// console.log('toArray', toArray<number>(5))
|
||||
// console.log('toBoolean', toBoolean(5))
|
||||
// console.log('toNumber', toNumber('5'))
|
||||
// console.log('unitConvert', unitConvert('5'))
|
||||
|
||||
// uni.getImageInfo({
|
||||
// src: '/static/logo.png',
|
||||
// success(res) {
|
||||
// console.log('res', res)
|
||||
// }
|
||||
// })
|
||||
|
||||
// --------------------------
|
||||
// IPv4 验证示例
|
||||
// --------------------------
|
||||
|
||||
// 标准IPv4格式
|
||||
// console.log(isIP('192.168.1.1', 4)); // true
|
||||
// console.log(isIP('255.255.255.255', { version: 4 })); // true
|
||||
|
||||
// // 边界值验证
|
||||
// console.log(isIP('0.0.0.0', 4)); // true
|
||||
// console.log(isIP('223.255.255.255', '4')); // true
|
||||
|
||||
// // 非法IPv4案例
|
||||
// console.log(isIP('256.400.999.1', 4)); // false(数值超限)
|
||||
// console.log(isIP('192.168.01', 4)); // false(段数不足)
|
||||
|
||||
// // --------------------------
|
||||
// // IPv6 验证示例
|
||||
// // --------------------------
|
||||
|
||||
// // 标准IPv6格式
|
||||
// console.log(isIP('2001:0db8:85a3:0000:0000:8a2e:0370:7334', 6)); // true
|
||||
// console.log(isIP('fe80::1%eth0', { version: 6 })); // true(带区域标识)
|
||||
|
||||
// // 压缩格式验证
|
||||
// console.log(isIP('2001:db8::1', '6')); // true(双冒号压缩)
|
||||
// console.log(isIP('::1', 6)); // true(本地环回简写)
|
||||
|
||||
// // IPv4混合格式
|
||||
// console.log(isIP('::ffff:192.168.1.1', 6)); // true(IPv4映射地址)
|
||||
|
||||
// // 非法IPv6案例
|
||||
// console.log(isIP('2001::gggg::1', 6)); // false(非法字符)
|
||||
// console.log(isIP('fe80::1%', 6)); // false(空区域标识)
|
||||
|
||||
// // --------------------------
|
||||
// // 自动版本检测
|
||||
// // --------------------------
|
||||
|
||||
// // 有效地址检测
|
||||
// console.log(isIP('172.16.254.1')); // true(自动识别IPv4)
|
||||
// console.log(isIP('2001:db8:3333:4444:5555:6666:7777:8888')); // true(自动识别IPv6)
|
||||
|
||||
// // 无效地址检测
|
||||
// console.log(isIP('192.168.1.256')); // false(无效IPv4)
|
||||
// console.log(isIP('2001::gggg::1')); // false(无效IPv6)
|
||||
|
||||
// // --------------------------
|
||||
// // 特殊场景
|
||||
// // --------------------------
|
||||
|
||||
// // 带前后空格处理
|
||||
// console.log(isIP(' 203.0.113.50 ', 4)); // true(自动trim)
|
||||
// console.log(isIP(' fe80::1%1 ', 6)); // true(自动trim)
|
||||
|
||||
// // 非法版本指定
|
||||
// console.log(isIP('192.168.1.1', 5)); // false(不存在IPv5)
|
||||
// console.log(isIP('2001:db8::1', 'ipv6')); // false(版本参数格式错误)
|
||||
|
||||
// // --------------------------
|
||||
// // 边界案例
|
||||
// // --------------------------
|
||||
|
||||
// // 最小/最大有效值
|
||||
// console.log(isIP('0.0.0.0', 4)); // true
|
||||
// console.log(isIP('255.255.255.255', 4)); // true
|
||||
// console.log(isIP('0000:0000:0000:0000:0000:0000:0000:0000', 6)); // true
|
||||
|
||||
// // 超长地址验证
|
||||
// console.log(isIP('192.168.1.1.1', 4)); // false(IPv4段数过多)
|
||||
// console.log(isIP('2001:db8:1:2:3:4:5:6:7', 6)); // false(IPv6段数过多)
|
||||
|
||||
// const original = { color: 'red' };
|
||||
// const merged = merge({ ...original }, { color: 'blue', size: 'M' });
|
||||
|
||||
// console.log('original', original); // 输出: { color: 'red' } (保持不变)
|
||||
// console.log('merged', merged); // 输出: { color: 'red', size: 'M' }
|
||||
|
||||
|
||||
type ColorType = {
|
||||
color?: string,
|
||||
size?: string,
|
||||
}
|
||||
|
||||
const merged2 = merge({ color: 'red' }, { size: 'M' } as ColorType);
|
||||
console.log('merged2:::', merged2)
|
||||
|
||||
// // 使用配置对象参数
|
||||
// console.log(isByteLength('hello', { min: 3, max: 7 } as ByteLengthOptions)); // true (5字节)
|
||||
// console.log(isByteLength('hello', { min: 6 } as ByteLengthOptions)); // false (5 < 6)
|
||||
// console.log(isByteLength('hello', { max: 4 } as ByteLengthOptions)); // false (5 > 4)
|
||||
|
||||
// // 使用独立参数(旧式调用)
|
||||
// console.log(isByteLength('hello', 3, 7)); // true
|
||||
// console.log(isByteLength('hello', 6)); // false
|
||||
// console.log(isByteLength('hello', null, 4)); // false
|
||||
|
||||
// =====================
|
||||
// 多字节字符处理示例
|
||||
// =====================
|
||||
|
||||
// 中文字符(UTF-8 每个汉字3字节)
|
||||
// console.log(isByteLength('中国', { min: 6 })); // true (2字 × 3字节 = 6)
|
||||
// console.log(isByteLength('中国', { max: 5 })); // false (6 > 5)
|
||||
|
||||
// // 表情符号(多数占用4字节)
|
||||
// console.log(isByteLength('🌟', { min: 4, max: 4 })); // true
|
||||
// console.log(isByteLength('👨👩👧👦', { max: 15 })); // false (家庭表情占25字节)
|
||||
|
||||
// // 混合字符集
|
||||
// console.log(isByteLength('aé🌟', { min: 7 })); // true
|
||||
|
||||
// // URL编码字符
|
||||
// console.log(isByteLength('%20', { min: 3 })); // true(实际字节长度3)
|
||||
// console.log(isByteLength('%E2%82%AC', { max: 3 })); // false(欧元符号编码为3字节)
|
||||
|
||||
// // 构造函数创建的正则表达式
|
||||
// console.log(isRegExp(new RegExp('hello'))); // true
|
||||
// console.log(isRegExp(new RegExp('\\d+', 'gi'))); // true
|
||||
|
||||
// // 字面量正则表达式
|
||||
// console.log(isRegExp(/abc/)); // true
|
||||
// console.log(isRegExp(/^[0-9]+$/gi)); // true
|
||||
|
||||
// // 字符串(含正则格式字符串)
|
||||
// console.log(isRegExp('/abc/')); // false
|
||||
// console.log(isRegExp('new RegExp("abc")')); // false
|
||||
|
||||
// console.log(isEmail('"John"@example.com')) // false(实际有效)
|
||||
// console.log(isEmail('中国@例子.中国')) // false(实际有效)
|
||||
|
||||
// // 简单键值对
|
||||
// console.log(obj2url({ name: '张三', age: 25 }));
|
||||
// // "name=%E5%BC%A0%E4%B8%89&age=25"
|
||||
// // 包含布尔值
|
||||
// console.log(obj2url({ active: true, admin: false }));
|
||||
// // "active=true&admin=false"
|
||||
|
||||
// // 数字处理
|
||||
// console.log(obj2url({ page: 1, limit: 10 }));
|
||||
// // "page=1&limit=10"
|
||||
|
||||
// 基础验证
|
||||
// console.log("example.com =>", isValidDomain("example.com")); // true
|
||||
// console.log("sub.example.co.uk =>", isValidDomain("sub.example.co.uk")); // true
|
||||
|
||||
// // 缺少TLD的情况
|
||||
// console.log("localhost =>", isValidDomain("localhost")); // false
|
||||
// console.log("localhost (不要求TLD) =>", isValidDomain("localhost", { requireTld: false } as DomainOptions)); // true
|
||||
|
||||
// // 带结尾点号的情况
|
||||
// console.log("example.com. =>", isValidDomain("example.com.")); // false
|
||||
// console.log("example.com. (允许结尾点号) =>", isValidDomain("example.com.", { allowTrailingDot: true } as DomainOptions)); // true
|
||||
|
||||
// // 带下划线的情况
|
||||
// console.log("my_site.com =>", isValidDomain("my_site.com")); // false
|
||||
// console.log("my_site.com (允许下划线) =>", isValidDomain("my_site.com", { allowUnderscore: true } as DomainOptions)); // true
|
||||
|
||||
// // 非法字符测试
|
||||
// console.log("含有空格的域名 =>", isValidDomain("exa mple.com")); // false
|
||||
// console.log("含有!的域名 =>", isValidDomain("exa!mple.com")); // false
|
||||
|
||||
// // 长度测试
|
||||
// const longPart = "a".repeat(64);
|
||||
// console.log(`超长部分 (${longPart.length}字符) =>`, isValidDomain(`${longPart}.com`)); // false
|
||||
|
||||
// // 连字符测试
|
||||
// console.log("以连字符开头 =>", isValidDomain("-example.com")); // false
|
||||
// console.log("以连字符结尾 =>", isValidDomain("example-.com")); // false
|
||||
|
||||
// // 国际化域名测试
|
||||
// console.log("中文域名 =>", isValidDomain("中国.中国")); // true
|
||||
// console.log("日文域名 =>", isValidDomain("ドメイン.テスト")); // true
|
||||
|
||||
// // 基础格式验证
|
||||
// console.log("1. 标准日期格式验证:");
|
||||
// console.log("2023/12/31 =>", isDate("2023/12/31")); // true
|
||||
// console.log("1999-01-01 =>", isDate("1999-01-01")); // true
|
||||
// console.log("02.28.2023 =>", isDate("02.28.2023", { delimiters: ['.'], format: 'MM.DD.YYYY' } as DateOptions)); // true (自定义分隔符)
|
||||
|
||||
// // 严格模式验证
|
||||
// console.log("2. 严格模式验证:");
|
||||
// console.log("严格匹配格式:", isDate("2023/02/28", { strictMode: true, format: "YYYY/MM/DD" }as DateOptions)); // true
|
||||
// console.log("长度不符:", isDate("2023/2/28", { strictMode: true, format: "YYYY/MM/DD" }as DateOptions)); // false
|
||||
// console.log("错误分隔符:", isDate("2023-02-28", { strictMode: true, format: "YYYY/MM/DD" }as DateOptions)); // false
|
||||
|
||||
// // 两位年份处理
|
||||
// console.log("3. 两位年份验证:");
|
||||
// console.log("23 -> 2023:", isDate("23/12/31", { format: "YY/MM/DD" } as DateOptions)); // true → 2023-12-31
|
||||
// console.log("87 -> 1987:", isDate("87-01-01", { format: "YY-MM-DD" } as DateOptions)); // true → 1987-01-01
|
||||
// console.log("负数年份:", isDate("-100/12/31", { format: "YYYY/MM/DD" } as DateOptions)); // false
|
||||
|
||||
// // 日期有效性验证
|
||||
// console.log("4. 无效日期检测:");
|
||||
// console.log("闰年2020-02-29:", isDate("2020/02/29")); // true
|
||||
// console.log("非闰年2023-02-29:", isDate("2023/02/29")); // false
|
||||
// console.log("月份溢出:", isDate("2023/13/01")); // false
|
||||
// console.log("日期溢出:", isDate("2023/12/32")); // false
|
||||
|
||||
// // Date对象验证
|
||||
// console.log("5. Date对象验证:");
|
||||
// console.log("有效Date对象:", isDate(new Date())); // true
|
||||
// console.log("无效Date对象:", isDate(new Date("invalid")), new Date("invalid")); // false
|
||||
// console.log("严格模式Date对象:", isDate(new Date(), { strictMode: true } as DateOptions)); // false
|
||||
|
||||
// // 自定义格式验证
|
||||
// console.log("6. 自定义格式测试:");
|
||||
// console.log("MM-DD-YYYY:", isDate("12-31-2023", { format: "MM-DD-YYYY" } as DateOptions)); // true
|
||||
// console.log("DD.MM.YY:", isDate("31.12.23", { format: "DD.MM.YY", delimiters: ['.'] } as DateOptions)); // true
|
||||
// console.log("中文分隔符:", isDate("2023年12月31日", {
|
||||
// format: "YYYY年MM月DD日",
|
||||
// strictMode: true,
|
||||
// delimiters: ['年', '月', '日']
|
||||
// } as DateOptions )); // true
|
||||
|
||||
|
||||
// 示例测试
|
||||
// console.log("示例1 标准HTTP URL:", isURL("http://example.com")); // true
|
||||
// console.log("示例2 需要端口时缺少端口:", isURL("https://example.com", { requirePort: true } as URLOptions)); // false
|
||||
// console.log("示例3 协议相对URL:", isURL("//example.com", { allowProtocolRelativeUrls: true })); // true
|
||||
console.log("示例4 IPv6地址:", isURL("http://[2001:db8::1]:8080", {})); // true
|
||||
// console.log("示例5 带认证信息被禁用:", isURL("user:pass@example.com", { disallowAuth: true })); // false
|
||||
console.log("示例6 查询参数被禁用:", isURL("http://example.com?q=test", { allowQueryComponents: true })); // false
|
||||
console.log("示例7 非字符串输入:", isURL(null, {})); // false
|
||||
console.log("示例8 邮件协议被排除:", isURL("mailto:test@example.com", {})); // false
|
||||
console.log("示例9 自定义协议:", isURL("ftp://files.example.com", { protocols: ["ftp"] })); // true
|
||||
console.log("示例10 白名单检查:", isURL("http://trusted.com", { hostWhitelist: ["trusted.com"] })); // true
|
||||
|
||||
|
||||
// #ifdef WEB
|
||||
// console.log('validator', validator.isURL())
|
||||
console.log("示例4 IPv6地址:", validator.isURL("http://[2001:db8::1]:8080", {})); // true
|
||||
console.log("示例6 查询参数被禁用:", validator.isURL("http://example.com?q=test", { allow_query_components: true })); // false
|
||||
console.log("示例8 邮件协议被排除:", validator.isURL("mailto:test@example.com", {})); // false
|
||||
console.log("示例9 自定义协议:", isURL("ftp://files.example.com", { protocols: ["ftp"] })); // true
|
||||
// #endif
|
||||
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
11
uni_modules/lime-shared/createAnimation/index.ts
Normal file
11
uni_modules/lime-shared/createAnimation/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef UNI-APP-X
|
||||
export * from './type.ts'
|
||||
// export * from './vue.ts'
|
||||
export { createAnimation } from './vue.ts'
|
||||
// #endif
|
||||
|
||||
// #ifdef UNI-APP-X
|
||||
// export * from './uvue.ts'
|
||||
export { createAnimation } from './uvue.uts'
|
||||
// #endif
|
||||
25
uni_modules/lime-shared/createAnimation/type.ts
Normal file
25
uni_modules/lime-shared/createAnimation/type.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
export type CreateAnimationOptions = {
|
||||
/**
|
||||
* 动画持续时间,单位ms
|
||||
*/
|
||||
duration ?: number;
|
||||
/**
|
||||
* 定义动画的效果
|
||||
* - linear: 动画从头到尾的速度是相同的
|
||||
* - ease: 动画以低速开始,然后加快,在结束前变慢
|
||||
* - ease-in: 动画以低速开始
|
||||
* - ease-in-out: 动画以低速开始和结束
|
||||
* - ease-out: 动画以低速结束
|
||||
* - step-start: 动画第一帧就跳至结束状态直到结束
|
||||
* - step-end: 动画一直保持开始状态,最后一帧跳到结束状态
|
||||
*/
|
||||
timingFunction ?: string //'linear' | 'ease' | 'ease-in' | 'ease-in-out' | 'ease-out' | 'step-start' | 'step-end';
|
||||
/**
|
||||
* 动画延迟时间,单位 ms
|
||||
*/
|
||||
delay ?: number;
|
||||
/**
|
||||
* 设置transform-origin
|
||||
*/
|
||||
transformOrigin ?: string;
|
||||
}
|
||||
5
uni_modules/lime-shared/createAnimation/uvue.uts
Normal file
5
uni_modules/lime-shared/createAnimation/uvue.uts
Normal file
@@ -0,0 +1,5 @@
|
||||
// @ts-nocheck
|
||||
// export * from '@/uni_modules/lime-animateIt'
|
||||
export function createAnimation() {
|
||||
console.error('当前环境不支持,请使用:lime-animateIt')
|
||||
}
|
||||
148
uni_modules/lime-shared/createAnimation/vue.ts
Normal file
148
uni_modules/lime-shared/createAnimation/vue.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
// @ts-nocheck
|
||||
// nvue 需要在节点上设置ref或在export里传入
|
||||
// const animation = createAnimation({
|
||||
// ref: this.$refs['xxx'],
|
||||
// duration: 0,
|
||||
// timingFunction: 'linear'
|
||||
// })
|
||||
// animation.opacity(1).translate(x, y).step({duration})
|
||||
// animation.export(ref)
|
||||
|
||||
// 抹平nvue 与 uni.createAnimation的使用差距
|
||||
// 但是nvue动画太慢
|
||||
|
||||
|
||||
|
||||
import { type CreateAnimationOptions } from './type'
|
||||
// #ifdef APP-NVUE
|
||||
const nvueAnimation = uni.requireNativePlugin('animation')
|
||||
|
||||
type AnimationTypes = 'matrix' | 'matrix3d' | 'rotate' | 'rotate3d' | 'rotateX' | 'rotateY' | 'rotateZ' | 'scale' | 'scale3d' | 'scaleX' | 'scaleY' | 'scaleZ' | 'skew' | 'skewX' | 'skewY' | 'translate' | 'translate3d' | 'translateX' | 'translateY' | 'translateZ'
|
||||
| 'opacity' | 'backgroundColor' | 'width' | 'height' | 'left' | 'right' | 'top' | 'bottom'
|
||||
|
||||
interface Styles {
|
||||
[key : string] : any
|
||||
}
|
||||
|
||||
interface StepConfig {
|
||||
duration?: number
|
||||
timingFunction?: string
|
||||
delay?: number
|
||||
needLayout?: boolean
|
||||
transformOrigin?: string
|
||||
}
|
||||
interface StepAnimate {
|
||||
styles?: Styles
|
||||
config?: StepConfig
|
||||
}
|
||||
interface StepAnimates {
|
||||
[key: number]: StepAnimate
|
||||
}
|
||||
// export interface CreateAnimationOptions extends UniApp.CreateAnimationOptions {
|
||||
// ref?: string
|
||||
// }
|
||||
|
||||
type Callback = (time: number) => void
|
||||
const animateTypes1 : AnimationTypes[] = ['matrix', 'matrix3d', 'rotate', 'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'scale', 'scale3d',
|
||||
'scaleX', 'scaleY', 'scaleZ', 'skew', 'skewX', 'skewY', 'translate', 'translate3d', 'translateX', 'translateY',
|
||||
'translateZ'
|
||||
]
|
||||
const animateTypes2 : AnimationTypes[] = ['opacity', 'backgroundColor']
|
||||
const animateTypes3 : AnimationTypes[] = ['width', 'height', 'left', 'right', 'top', 'bottom']
|
||||
|
||||
class LimeAnimation {
|
||||
ref : any
|
||||
context : any
|
||||
options : UniApp.CreateAnimationOptions
|
||||
// stack : any[] = []
|
||||
next : number = 0
|
||||
currentStepAnimates : StepAnimates = {}
|
||||
duration : number = 0
|
||||
constructor(options : CreateAnimationOptions) {
|
||||
const {ref} = options
|
||||
this.ref = ref
|
||||
this.options = options
|
||||
}
|
||||
addAnimate(type : AnimationTypes, args: (string | number)[]) {
|
||||
let aniObj = this.currentStepAnimates[this.next]
|
||||
let stepAnimate:StepAnimate = {}
|
||||
if (!aniObj) {
|
||||
stepAnimate = {styles: {}, config: {}}
|
||||
} else {
|
||||
stepAnimate = aniObj
|
||||
}
|
||||
|
||||
if (animateTypes1.includes(type)) {
|
||||
if (!stepAnimate.styles.transform) {
|
||||
stepAnimate.styles.transform = ''
|
||||
}
|
||||
let unit = ''
|
||||
if (type === 'rotate') {
|
||||
unit = 'deg'
|
||||
}
|
||||
stepAnimate.styles.transform += `${type}(${args.map((v: number) => v + unit).join(',')}) `
|
||||
} else {
|
||||
stepAnimate.styles[type] = `${args.join(',')}`
|
||||
}
|
||||
this.currentStepAnimates[this.next] = stepAnimate
|
||||
}
|
||||
animateRun(styles: Styles = {}, config:StepConfig = {}, ref: any) {
|
||||
const el = ref || this.ref
|
||||
if (!el) return
|
||||
return new Promise((resolve) => {
|
||||
const time = +new Date()
|
||||
nvueAnimation.transition(el, {
|
||||
styles,
|
||||
...config
|
||||
}, () => {
|
||||
resolve(+new Date() - time)
|
||||
})
|
||||
})
|
||||
}
|
||||
nextAnimate(animates: StepAnimates, step: number = 0, ref: any, cb: Callback) {
|
||||
let obj = animates[step]
|
||||
if (obj) {
|
||||
let { styles, config } = obj
|
||||
// this.duration += config.duration
|
||||
this.animateRun(styles, config, ref).then((time: number) => {
|
||||
step += 1
|
||||
this.duration += time
|
||||
this.nextAnimate(animates, step, ref, cb)
|
||||
})
|
||||
} else {
|
||||
this.currentStepAnimates = {}
|
||||
cb && cb(this.duration)
|
||||
}
|
||||
}
|
||||
step(config:StepConfig = {}) {
|
||||
this.currentStepAnimates[this.next].config = Object.assign({}, this.options, config)
|
||||
this.currentStepAnimates[this.next].styles.transformOrigin = this.currentStepAnimates[this.next].config.transformOrigin
|
||||
this.next++
|
||||
return this
|
||||
}
|
||||
export(ref: any, cb?: Callback) {
|
||||
ref = ref || this.ref
|
||||
if(!ref) return
|
||||
this.duration = 0
|
||||
this.next = 0
|
||||
this.nextAnimate(this.currentStepAnimates, 0, ref, cb)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
animateTypes1.concat(animateTypes2, animateTypes3).forEach(type => {
|
||||
LimeAnimation.prototype[type] = function(...args: (string | number)[]) {
|
||||
this.addAnimate(type, args)
|
||||
return this
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
export function createAnimation(options : CreateAnimationOptions) {
|
||||
// #ifndef APP-NVUE
|
||||
return uni.createAnimation({ ...options })
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
return new LimeAnimation(options)
|
||||
// #endif
|
||||
}
|
||||
73
uni_modules/lime-shared/createCanvas/index.ts
Normal file
73
uni_modules/lime-shared/createCanvas/index.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
|
||||
// @ts-nocheck
|
||||
// #ifndef UNI-APP-X && APP
|
||||
import type { ComponentInternalInstance } from '@/uni_modules/lime-shared/vue'
|
||||
import { getRect } from '@/uni_modules/lime-shared/getRect'
|
||||
import { canIUseCanvas2d } from '@/uni_modules/lime-shared/canIUseCanvas2d'
|
||||
export const isCanvas2d = canIUseCanvas2d()
|
||||
// #endif
|
||||
|
||||
|
||||
export function createCanvas(canvasId : string, component : ComponentInternalInstance) {
|
||||
// #ifdef UNI-APP-X
|
||||
uni.createCanvasContextAsync({
|
||||
canvasId,
|
||||
component,
|
||||
success(context : CanvasContext) {
|
||||
|
||||
},
|
||||
fail(error : UniError) {
|
||||
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
// #ifndef UNI-APP-X
|
||||
const isCanvas2d = canIUseCanvas2d()
|
||||
getRect('#' + canvasId, context, isCanvas2d).then(res => {
|
||||
if (res.node) {
|
||||
res.node.width = res.width
|
||||
res.node.height = res.height
|
||||
return res.node
|
||||
} else {
|
||||
const ctx = uni.createCanvasContext(canvasId, context)
|
||||
if (!ctx._drawImage) {
|
||||
ctx._drawImage = ctx.drawImage
|
||||
ctx.drawImage = function (...args) {
|
||||
const { path } = args.shift()
|
||||
ctx._drawImage(path, ...args)
|
||||
}
|
||||
}
|
||||
if (!ctx.getImageData) {
|
||||
ctx.getImageData = function () {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.canvasGetImageData({
|
||||
canvasId,
|
||||
x: parseInt(arguments[0]),
|
||||
y: parseInt(arguments[1]),
|
||||
width: parseInt(arguments[2]),
|
||||
height: parseInt(arguments[3]),
|
||||
success(res) {
|
||||
resolve(res)
|
||||
},
|
||||
fail(err) {
|
||||
reject(err)
|
||||
}
|
||||
}, context)
|
||||
})
|
||||
|
||||
}
|
||||
return {
|
||||
getContext(type: string) {
|
||||
if(type == '2d') {
|
||||
return ctx
|
||||
}
|
||||
},
|
||||
width: res.width,
|
||||
height: res.height,
|
||||
createImage
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
}
|
||||
71
uni_modules/lime-shared/createImage/index.ts
Normal file
71
uni_modules/lime-shared/createImage/index.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef UNI-APP-X && APP
|
||||
import {isBrowser} from '../isBrowser'
|
||||
class Image {
|
||||
currentSrc: string | null = null
|
||||
naturalHeight: number = 0
|
||||
naturalWidth: number = 0
|
||||
width: number = 0
|
||||
height: number = 0
|
||||
tagName: string = 'IMG'
|
||||
path: string = ''
|
||||
crossOrigin: string = ''
|
||||
referrerPolicy: string = ''
|
||||
onload: () => void = () => {}
|
||||
onerror: () => void = () => {}
|
||||
complete: boolean = false
|
||||
constructor() {}
|
||||
set src(src: string) {
|
||||
console.log('src', src)
|
||||
if(!src) {
|
||||
return this.onerror()
|
||||
}
|
||||
src = src.replace(/^@\//,'/')
|
||||
this.currentSrc = src
|
||||
uni.getImageInfo({
|
||||
src,
|
||||
success: (res) => {
|
||||
const localReg = /^\.|^\/(?=[^\/])/;
|
||||
// #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-TOUTIAO
|
||||
res.path = localReg.test(src) ? `/${res.path}` : res.path;
|
||||
// #endif
|
||||
this.complete = true
|
||||
this.path = res.path
|
||||
this.naturalWidth = this.width = res.width
|
||||
this.naturalHeight = this.height = res.height
|
||||
this.onload()
|
||||
},
|
||||
fail: () => {
|
||||
this.onerror()
|
||||
}
|
||||
})
|
||||
}
|
||||
get src() {
|
||||
return this.currentSrc
|
||||
}
|
||||
}
|
||||
interface UniImage extends WechatMiniprogram.Image {
|
||||
complete?: boolean
|
||||
naturalHeight?: number
|
||||
naturalWidth?: number
|
||||
}
|
||||
/** 创建用于 canvas 的 img */
|
||||
export function createImage(canvas?: any): HTMLImageElement | UniImage {
|
||||
if(canvas && canvas.createImage) {
|
||||
return (canvas as WechatMiniprogram.Canvas).createImage()
|
||||
} else if(this && this['tagName'] == 'canvas' && !('toBlob' in this) || canvas && !('toBlob' in canvas)){
|
||||
return new Image()
|
||||
} else if(isBrowser) {
|
||||
return new window.Image()
|
||||
}
|
||||
return new Image()
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef UNI-APP-X && APP
|
||||
export function createImage():Image{
|
||||
// console.error('当前环境不支持')
|
||||
return new Image()
|
||||
}
|
||||
// #endif
|
||||
45
uni_modules/lime-shared/cssToObj/index.ts
Normal file
45
uni_modules/lime-shared/cssToObj/index.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef UNI-APP-X
|
||||
type UTSJSONObject = Record<string, any>
|
||||
// #endif
|
||||
|
||||
|
||||
/**
|
||||
* 将 CSS 字符串转换为样式对象
|
||||
* @param css CSS 字符串,例如 "color: red; font-size: 16px;"
|
||||
* @returns CSSProperties 对象
|
||||
*/
|
||||
export function cssToObj(css : string | UTSJSONObject | null) : UTSJSONObject {
|
||||
// #ifdef APP-ANDROID
|
||||
if(css == null) return {}
|
||||
// #endif
|
||||
// #ifndef APP-ANDROID
|
||||
if(!css) return {}
|
||||
// #endif
|
||||
if(typeof css == 'object') return css as UTSJSONObject
|
||||
|
||||
|
||||
const style : UTSJSONObject = {};
|
||||
|
||||
(css as string).split(';').forEach(decl => {
|
||||
// #ifdef APP-ANDROID
|
||||
const res = decl.split(':').map(s => s.trim());
|
||||
if(res.length > 1) {
|
||||
const [prop, val] = res;
|
||||
if (prop != '' && val != '') {
|
||||
const camelProp = prop!.replace(/-([a-z])/g, (_: string, _offset: number,c: string):string => c.toUpperCase());
|
||||
style[camelProp] = val!;
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
// #ifndef APP-ANDROID
|
||||
const [prop, val] = decl.split(':').map(s => s.trim());
|
||||
if (prop && val) {
|
||||
const camelProp = prop.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
||||
style[camelProp] = val;
|
||||
}
|
||||
// #endif
|
||||
});
|
||||
|
||||
return style;
|
||||
}
|
||||
11
uni_modules/lime-shared/debounce/index.ts
Normal file
11
uni_modules/lime-shared/debounce/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
// @ts-nocheck
|
||||
|
||||
// #ifdef UNI-APP-X && APP
|
||||
// export * from './uvue.uts'
|
||||
export { debounce } from './uvue.uts'
|
||||
// #endif
|
||||
|
||||
// #ifndef UNI-APP-X && APP
|
||||
// export * from './vue.ts'
|
||||
export { debounce } from './vue.ts'
|
||||
// #endif
|
||||
36
uni_modules/lime-shared/debounce/uvue.uts
Normal file
36
uni_modules/lime-shared/debounce/uvue.uts
Normal file
@@ -0,0 +1,36 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 防抖函数,通过延迟一定时间来限制函数的执行频率。
|
||||
* @param fn 要防抖的函数。
|
||||
* @param wait 触发防抖的等待时间,单位为毫秒。
|
||||
* @returns 防抖函数。
|
||||
*/
|
||||
export function debounce<A extends any>(fn : (args: A)=> void, wait = 300): (args: A)=> void {
|
||||
let timer = -1
|
||||
|
||||
return (args: A) => {
|
||||
if (timer >-1) {clearTimeout(timer)};
|
||||
|
||||
timer = setTimeout(()=>{
|
||||
fn(args)
|
||||
}, wait)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// 示例
|
||||
// 定义一个函数
|
||||
// function saveData(data: string) {
|
||||
// // 模拟保存数据的操作
|
||||
// console.log(`Saving data: ${data}`);
|
||||
// }
|
||||
|
||||
// // 创建一个防抖函数,延迟 500 毫秒后调用 saveData 函数
|
||||
// const debouncedSaveData = debounce(saveData, 500);
|
||||
|
||||
// // 连续调用防抖函数
|
||||
// debouncedSaveData('Data 1'); // 不会立即调用 saveData 函数
|
||||
// debouncedSaveData('Data 2'); // 不会立即调用 saveData 函数
|
||||
|
||||
// 在 500 毫秒后,只会调用一次 saveData 函数,输出结果为 "Saving data: Data 2"
|
||||
40
uni_modules/lime-shared/debounce/vue.ts
Normal file
40
uni_modules/lime-shared/debounce/vue.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
// @ts-nocheck
|
||||
type Timeout = ReturnType<typeof setTimeout> | null;
|
||||
/**
|
||||
* 防抖函数,通过延迟一定时间来限制函数的执行频率。
|
||||
* @param fn 要防抖的函数。
|
||||
* @param wait 触发防抖的等待时间,单位为毫秒。
|
||||
* @returns 防抖函数。
|
||||
*/
|
||||
export function debounce<A extends any, R>(
|
||||
fn : (...args : A) => R,
|
||||
wait : number = 300) : (...args : A) => void {
|
||||
let timer : Timeout = null;
|
||||
|
||||
return function (...args : A) {
|
||||
if (timer) clearTimeout(timer); // 如果上一个 setTimeout 存在,则清除它
|
||||
|
||||
// 设置一个新的 setTimeout,在指定的等待时间后调用防抖函数
|
||||
timer = setTimeout(() => {
|
||||
fn.apply(this, args); // 使用提供的参数调用原始函数
|
||||
}, wait);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
// 示例
|
||||
// 定义一个函数
|
||||
// function saveData(data: string) {
|
||||
// // 模拟保存数据的操作
|
||||
// console.log(`Saving data: ${data}`);
|
||||
// }
|
||||
|
||||
// // 创建一个防抖函数,延迟 500 毫秒后调用 saveData 函数
|
||||
// const debouncedSaveData = debounce(saveData, 500);
|
||||
|
||||
// // 连续调用防抖函数
|
||||
// debouncedSaveData('Data 1'); // 不会立即调用 saveData 函数
|
||||
// debouncedSaveData('Data 2'); // 不会立即调用 saveData 函数
|
||||
|
||||
// 在 500 毫秒后,只会调用一次 saveData 函数,输出结果为 "Saving data: Data 2"
|
||||
18
uni_modules/lime-shared/dom/index.ts
Normal file
18
uni_modules/lime-shared/dom/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
// @ts-nocheck
|
||||
export function findClosestElementWithStyle(startEl: UniElement | null, styleProperty: string): UniElement | null {
|
||||
let currentEl: UniElement | null = startEl;
|
||||
|
||||
while (currentEl != null) {
|
||||
// Check if the current element has the style property with a non-empty value
|
||||
const styleValue = currentEl?.style.getPropertyValue(styleProperty) ?? '';
|
||||
if (styleValue.trim() != '') {
|
||||
return currentEl;
|
||||
}
|
||||
|
||||
// Move to parent element
|
||||
currentEl = currentEl.parentElement;
|
||||
}
|
||||
|
||||
// Return null if no element with the specified style was found
|
||||
return null;
|
||||
};
|
||||
11
uni_modules/lime-shared/exif/index.ts
Normal file
11
uni_modules/lime-shared/exif/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef UNI-APP-X && APP
|
||||
// export * from './vue.ts'
|
||||
export { exif } from './vue.ts'
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef UNI-APP-X && APP
|
||||
// export * from './uvue.uts'
|
||||
export { exif } from './uvue.uts'
|
||||
// #endif
|
||||
7
uni_modules/lime-shared/exif/uvue.uts
Normal file
7
uni_modules/lime-shared/exif/uvue.uts
Normal file
@@ -0,0 +1,7 @@
|
||||
class EXIF {
|
||||
constructor(){
|
||||
console.error('当前环境不支持')
|
||||
}
|
||||
}
|
||||
|
||||
export const exif = new EXIF()
|
||||
1057
uni_modules/lime-shared/exif/vue.ts
Normal file
1057
uni_modules/lime-shared/exif/vue.ts
Normal file
File diff suppressed because it is too large
Load Diff
11
uni_modules/lime-shared/fillZero/index.ts
Normal file
11
uni_modules/lime-shared/fillZero/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 在数字前填充零,返回字符串形式的结果
|
||||
* @param number 要填充零的数字
|
||||
* @param length 填充零后的字符串长度,默认为2
|
||||
* @returns 填充零后的字符串
|
||||
*/
|
||||
export function fillZero(number: number, length: number = 2): string {
|
||||
// 将数字转换为字符串,然后使用 padStart 方法填充零到指定长度
|
||||
return `${number}`.padStart(length, '0');
|
||||
}
|
||||
36
uni_modules/lime-shared/floatAdd/index.ts
Normal file
36
uni_modules/lime-shared/floatAdd/index.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { isNumber } from '../isNumber'
|
||||
/**
|
||||
* 返回两个浮点数相加的结果
|
||||
* @param num1 第一个浮点数
|
||||
* @param num2 第二个浮点数
|
||||
* @returns 两个浮点数的相加结果
|
||||
*/
|
||||
export function floatAdd(num1 : number, num2 : number) : number {
|
||||
// 检查 num1 和 num2 是否为数字类型
|
||||
if (!(isNumber(num1) || isNumber(num2))) {
|
||||
console.warn('Please pass in the number type');
|
||||
return NaN;
|
||||
}
|
||||
|
||||
let r1 : number, r2 : number, m : number;
|
||||
|
||||
try {
|
||||
// 获取 num1 小数点后的位数
|
||||
r1 = num1.toString().split('.')[1].length;
|
||||
} catch (error) {
|
||||
r1 = 0;
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取 num2 小数点后的位数
|
||||
r2 = num2.toString().split('.')[1].length;
|
||||
} catch (error) {
|
||||
r2 = 0;
|
||||
}
|
||||
|
||||
// 计算需要扩大的倍数
|
||||
m = Math.pow(10, Math.max(r1, r2));
|
||||
|
||||
// 返回相加结果
|
||||
return (num1 * m + num2 * m) / m;
|
||||
}
|
||||
45
uni_modules/lime-shared/floatDiv/index.ts
Normal file
45
uni_modules/lime-shared/floatDiv/index.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { floatMul } from '../floatMul';
|
||||
import { isNumber } from '../isNumber';
|
||||
|
||||
/**
|
||||
* 除法函数,用于处理浮点数除法并保持精度。
|
||||
* @param {number} num1 - 被除数。
|
||||
* @param {number} num2 - 除数。
|
||||
* @returns {number} 除法运算的结果,保留正确的精度。
|
||||
*/
|
||||
export function floatDiv(num1:number, num2:number):number {
|
||||
// 如果传入的不是数字类型,则打印警告并返回NaN
|
||||
if (!isNumber(num1) || !isNumber(num2)) {
|
||||
console.warn('请传入数字类型');
|
||||
return NaN;
|
||||
}
|
||||
|
||||
let m1 = 0, // 被除数小数点后的位数
|
||||
m2 = 0, // 除数小数点后的位数
|
||||
s1 = num1.toString(), // 将被除数转换为字符串
|
||||
s2 = num2.toString(); // 将除数转换为字符串
|
||||
|
||||
// 计算被除数小数点后的位数
|
||||
try {
|
||||
m1 += s1.split('.')[1].length;
|
||||
} catch (error) {}
|
||||
|
||||
// 计算除数小数点后的位数
|
||||
try {
|
||||
m2 += s2.split('.')[1].length;
|
||||
} catch (error) {}
|
||||
|
||||
// 进行除法运算并处理小数点后的位数,使用之前定义的乘法函数保持精度
|
||||
// #ifdef APP-ANDROID
|
||||
return floatMul(
|
||||
parseFloat(s1.replace('.', '')) / parseFloat(s2.replace('.', '')),
|
||||
Math.pow(10, m2 - m1),
|
||||
);
|
||||
// #endif
|
||||
// #ifndef APP-ANDROID
|
||||
return floatMul(
|
||||
Number(s1.replace('.', '')) / Number(s2.replace('.', '')),
|
||||
Math.pow(10, m2 - m1),
|
||||
);
|
||||
// #endif
|
||||
}
|
||||
44
uni_modules/lime-shared/floatMul/index.ts
Normal file
44
uni_modules/lime-shared/floatMul/index.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
// @ts-nocheck
|
||||
import {isNumber} from '../isNumber';
|
||||
// #ifdef APP-ANDROID
|
||||
import BigDecimal from 'java.math.BigDecimal'
|
||||
// import BigDecimal from 'java.math.BigDecimal'
|
||||
// import StringBuilder from 'java.lang.StringBuilder'
|
||||
// import java.math.BigDecimal;
|
||||
// #endif
|
||||
|
||||
/**
|
||||
* 乘法函数,用于处理浮点数乘法并保持精度。
|
||||
* @param {number} num1 - 第一个乘数。
|
||||
* @param {number} num2 - 第二个乘数。
|
||||
* @returns {number} 乘法运算的结果,保留正确的精度。
|
||||
*/
|
||||
export function floatMul(num1 : number, num2 : number) : number {
|
||||
if (!(isNumber(num1) || isNumber(num2))) {
|
||||
console.warn('Please pass in the number type');
|
||||
return NaN;
|
||||
}
|
||||
let m = 0;
|
||||
// #ifdef APP-ANDROID
|
||||
let s1 = BigDecimal.valueOf(num1.toDouble()).toPlainString(); //new UTSNumber(num1).toString() // //`${num1.toFloat()}`// num1.toString(),
|
||||
let s2 = BigDecimal.valueOf(num2.toDouble()).toPlainString(); //new UTSNumber(num2).toString() //`${num2.toFloat()}`//.toString();
|
||||
// #endif
|
||||
// #ifndef APP-ANDROID
|
||||
let s1:string = `${num1}`// num1.toString(),
|
||||
let s2:string = `${num2}`//.toString();
|
||||
// #endif
|
||||
|
||||
try {
|
||||
m += s1.split('.')[1].length;
|
||||
} catch (error) { }
|
||||
try {
|
||||
m += s2.split('.')[1].length;
|
||||
} catch (error) { }
|
||||
|
||||
// #ifdef APP-ANDROID
|
||||
return parseFloat(s1.replace('.', '')) * parseFloat(s2.replace('.', '')) / Math.pow(10, m);
|
||||
// #endif
|
||||
// #ifndef APP-ANDROID
|
||||
return Number(s1.replace('.', '')) * Number(s2.replace('.', '')) / Math.pow(10, m);
|
||||
// #endif
|
||||
}
|
||||
32
uni_modules/lime-shared/floatSub/index.ts
Normal file
32
uni_modules/lime-shared/floatSub/index.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { isNumber } from '../isNumber';
|
||||
/**
|
||||
* 减法函数,用于处理浮点数减法并保持精度。
|
||||
* @param {number} num1 - 被减数。
|
||||
* @param {number} num2 - 减数。
|
||||
* @returns {number} 减法运算的结果,保留正确的精度。
|
||||
*/
|
||||
export function floatSub(num1 : number, num2 : number) : number {
|
||||
if (!(isNumber(num1) || isNumber(num2))) {
|
||||
console.warn('Please pass in the number type');
|
||||
return NaN;
|
||||
}
|
||||
let r1:number, r2:number, m:number, n:number;
|
||||
try {
|
||||
r1 = num1.toString().split('.')[1].length;
|
||||
} catch (error) {
|
||||
r1 = 0;
|
||||
}
|
||||
try {
|
||||
r2 = num2.toString().split('.')[1].length;
|
||||
} catch (error) {
|
||||
r2 = 0;
|
||||
}
|
||||
m = Math.pow(10, Math.max(r1, r2));
|
||||
n = r1 >= r2 ? r1 : r2;
|
||||
// #ifndef APP-ANDROID
|
||||
return Number(((num1 * m - num2 * m) / m).toFixed(n));
|
||||
// #endif
|
||||
// #ifdef APP-ANDROID
|
||||
return parseFloat(((num1 * m - num2 * m) / m).toFixed(n));
|
||||
// #endif
|
||||
}
|
||||
53
uni_modules/lime-shared/getClassStr/index.ts
Normal file
53
uni_modules/lime-shared/getClassStr/index.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
// @ts-nocheck
|
||||
|
||||
// #ifdef UNI-APP-X && APP
|
||||
import { isNumber } from '../isNumber'
|
||||
import { isString } from '../isString'
|
||||
import { isDef } from '../isDef'
|
||||
// #endif
|
||||
|
||||
/**
|
||||
* 获取对象的类名字符串
|
||||
* @param obj - 需要处理的对象
|
||||
* @returns 由对象属性作为类名组成的字符串
|
||||
*/
|
||||
export function getClassStr<T>(obj : T) : string {
|
||||
let classNames : string[] = [];
|
||||
// #ifdef APP-ANDROID
|
||||
if (obj instanceof UTSJSONObject) {
|
||||
(obj as UTSJSONObject).toMap().forEach((value, key) => {
|
||||
if (isDef(value)) {
|
||||
if (isNumber(value)) {
|
||||
classNames.push(key);
|
||||
}
|
||||
if (isString(value) && value !== '') {
|
||||
classNames.push(key);
|
||||
}
|
||||
if (typeof value == 'boolean' && (value as boolean)) {
|
||||
classNames.push(key);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
// #ifndef APP-ANDROID
|
||||
// 遍历对象的属性
|
||||
for (let key in obj) {
|
||||
// 检查属性确实属于对象自身且其值为true
|
||||
if ((obj as any).hasOwnProperty(key) && obj[key]) {
|
||||
// 将属性名添加到类名数组中
|
||||
classNames.push(key);
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
// 将类名数组用空格连接成字符串并返回
|
||||
return classNames.join(' ');
|
||||
}
|
||||
|
||||
|
||||
// 示例
|
||||
// const obj = { foo: true, bar: false, baz: true };
|
||||
// const classNameStr = getClassStr(obj);
|
||||
// console.log(classNameStr); // 输出: "foo baz"
|
||||
11
uni_modules/lime-shared/getCurrentPage/index.ts
Normal file
11
uni_modules/lime-shared/getCurrentPage/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef UNI-APP-X && APP
|
||||
// export * from './vue.ts'
|
||||
export { getCurrentPage } from './vue.ts'
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef UNI-APP-X && APP
|
||||
// export * from './uvue.uts'
|
||||
export { getCurrentPage } from './uvue.uts'
|
||||
// #endif
|
||||
5
uni_modules/lime-shared/getCurrentPage/uvue.uts
Normal file
5
uni_modules/lime-shared/getCurrentPage/uvue.uts
Normal file
@@ -0,0 +1,5 @@
|
||||
// @ts-nocheck
|
||||
export const getCurrentPage = ():Page => {
|
||||
const pages = getCurrentPages();
|
||||
return pages[pages.length - 1]
|
||||
};
|
||||
6
uni_modules/lime-shared/getCurrentPage/vue.ts
Normal file
6
uni_modules/lime-shared/getCurrentPage/vue.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
// @ts-nocheck
|
||||
/** 获取当前页 */
|
||||
export const getCurrentPage = () => {
|
||||
const pages = getCurrentPages();
|
||||
return pages[pages.length - 1] //as T & WechatMiniprogram.Page.TrivialInstance;
|
||||
};
|
||||
62
uni_modules/lime-shared/getLocalFilePath/index.ts
Normal file
62
uni_modules/lime-shared/getLocalFilePath/index.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
// @ts-nocheck
|
||||
// #ifdef APP-NVUE || APP-VUE
|
||||
export const getLocalFilePath = (path : string) => {
|
||||
if (typeof plus == 'undefined') return path
|
||||
if (/^(_www|_doc|_documents|_downloads|file:\/\/|\/storage\/emulated\/0\/)/.test(path)) return path
|
||||
if (/^\//.test(path)) {
|
||||
const localFilePath = plus.io.convertAbsoluteFileSystem(path)
|
||||
if (localFilePath !== path) {
|
||||
return localFilePath
|
||||
} else {
|
||||
path = path.slice(1)
|
||||
}
|
||||
}
|
||||
return '_www/' + path
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef UNI-APP-X && APP
|
||||
export { getResourcePath as getLocalFilePath } from '@/uni_modules/lime-file-utils'
|
||||
// export const getLocalFilePath = (path : string) : string => {
|
||||
// let uri = path
|
||||
// if (uri.startsWith("http") || uri.startsWith("<svg") || uri.startsWith("data:image/svg+xml")) {
|
||||
// return uri
|
||||
// }
|
||||
// if (uri.startsWith("file://")) {
|
||||
// uri = uri.substring("file://".length)
|
||||
// } else if (uri.startsWith("unifile://")) {
|
||||
// uri = UTSAndroid.convert2AbsFullPath(uri)
|
||||
// } else {
|
||||
// uri = UTSAndroid.convert2AbsFullPath(uri)
|
||||
// if (uri.startsWith("/android_asset/")) {
|
||||
// uri = uri.replace("/android_asset/", "")
|
||||
// }
|
||||
// }
|
||||
// if (new File(uri).exists()) {
|
||||
// return uri
|
||||
// } else {
|
||||
// return null
|
||||
// }
|
||||
// // return UTSAndroid.convert2AbsFullPath(path)
|
||||
// }
|
||||
// #endif
|
||||
// #ifdef APP-IOS
|
||||
// export const getLocalFilePath = (path : string) : string => {
|
||||
// try {
|
||||
// let uri = path
|
||||
// if (uri.startsWith("http") || uri.startsWith("<svg") || uri.startsWith("data:image/svg+xml")) {
|
||||
// return uri
|
||||
// }
|
||||
// if (uri.startsWith("file://")) {
|
||||
// return uri.substring("file://".length)
|
||||
// } else if (path.startsWith("/var/")) {
|
||||
// return path
|
||||
// }
|
||||
// return UTSiOS.getResourcePath(path)
|
||||
// } catch (e) {
|
||||
// return null
|
||||
// }
|
||||
// // return UTSiOS.getResourcePath(path)
|
||||
// }
|
||||
// #endif
|
||||
138
uni_modules/lime-shared/getRect/index.ts
Normal file
138
uni_modules/lime-shared/getRect/index.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
// @ts-nocheck
|
||||
// #ifdef UNI-APP-X && APP
|
||||
// export * from './uvue.uts'
|
||||
export { getRect, getAllRect } from './uvue.uts'
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifndef UNI-APP-X && APP
|
||||
// export * from './vue.ts'
|
||||
export { getRect, getAllRect } from './vue.ts'
|
||||
// #endif
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取视口滚动条位置信息
|
||||
*/
|
||||
export function getViewportScrollInfo() : Promise<any> {
|
||||
return new Promise(resolve => {
|
||||
uni.createSelectorQuery()
|
||||
.selectViewport()
|
||||
.scrollOffset((res) => {
|
||||
resolve(res);
|
||||
}).exec();
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
```
|
||||
page
|
||||
╱
|
||||
╭───────────────╮ viewport
|
||||
╭─│─ ─ ─ ─ ─ ─ ─ ─│─╮ ╱
|
||||
│ │ ╭───────────╮ │ │
|
||||
│ │ │ element │ │ │
|
||||
│ │ ╰───────────╯ │ │
|
||||
╰─│─ ─ ─ ─ ─ ─ ─ ─│─╯
|
||||
│ │
|
||||
│ │
|
||||
╰───────────────╯
|
||||
```
|
||||
|
||||
# 参数
|
||||
- viewportHeight: viewport 高度
|
||||
- viewportScrollTop: viewport 垂直滚动值
|
||||
- elementHeight: element 高度
|
||||
- elementOffsetTop: element 距离页面顶部距离
|
||||
|
||||
# 选项
|
||||
- position: element 在视窗中的位置(start, center, end, nearest)
|
||||
- startOffset: element 距离视窗顶部的偏移量
|
||||
- endOffset: element 距离视窗底部的偏移量
|
||||
|
||||
# 结果值
|
||||
- viewportScrollTop: viewport 新的垂直滚动值
|
||||
|
||||
*/
|
||||
|
||||
export type ScrollIntoViewOptions = {
|
||||
/** 元素顶部需要保留的缓冲距离(默认 0) */
|
||||
startOffset ?: number;
|
||||
/** 元素底部需要保留的缓冲距离(默认 0) */
|
||||
endOffset ?: number;
|
||||
/** 滚动对齐方式:start/center/end/nearest(默认 nearest) */
|
||||
position ?: 'start' | 'center' | 'end' | 'nearest';
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算元素需要滚动到可视区域的目标滚动位置
|
||||
* @param viewportHeight 视口高度(像素)
|
||||
* @param viewportScrollTop 当前滚动位置(像素)
|
||||
* @param elementHeight 元素高度(像素)
|
||||
* @param elementOffsetTop 元素相对于父容器顶部的偏移量(像素)
|
||||
* @param options 配置选项
|
||||
* @returns 计算后的目标滚动位置(像素)
|
||||
*
|
||||
* @example
|
||||
* // 示例:将元素滚动到视口顶部对齐
|
||||
* const scrollTop = getScrollIntoViewValue(
|
||||
* 500, // 视口高度
|
||||
* 200, // 当前滚动位置
|
||||
* 100, // 元素高度
|
||||
* 300, // 元素偏移量
|
||||
* { position: 'start' }
|
||||
* );
|
||||
*/
|
||||
export function getScrollIntoViewValue(
|
||||
viewportHeight : number,
|
||||
viewportScrollTop : number,
|
||||
elementHeight : number,
|
||||
elementOffsetTop : number,
|
||||
options : ScrollIntoViewOptions = {}
|
||||
) : number {
|
||||
let { startOffset = 0, endOffset = 0, position = 'nearest'} = options;
|
||||
|
||||
// 计算元素相对于视口的上下偏移量
|
||||
const elementToViewportTopOffset = elementOffsetTop - viewportScrollTop - startOffset;
|
||||
const elementToViewportBottomOffset =
|
||||
elementOffsetTop +
|
||||
elementHeight -
|
||||
viewportScrollTop -
|
||||
viewportHeight +
|
||||
endOffset;
|
||||
|
||||
// 处理 nearest 模式,自动选择最近边缘
|
||||
if (position == 'nearest') {
|
||||
if (elementToViewportTopOffset >= 0 && elementToViewportBottomOffset <= 0) {
|
||||
return viewportScrollTop;
|
||||
}
|
||||
position =
|
||||
Math.abs(elementToViewportTopOffset) > Math.abs(elementToViewportBottomOffset)
|
||||
? 'end'
|
||||
: 'start';
|
||||
}
|
||||
|
||||
// 根据不同的对齐位置计算目标滚动位置
|
||||
let nextScrollTop = 0;
|
||||
switch (position) {
|
||||
case 'start':
|
||||
// 顶部对齐:元素顶部对齐视口顶部(考虑顶部缓冲)
|
||||
nextScrollTop = elementOffsetTop - startOffset;
|
||||
break;
|
||||
case 'center':
|
||||
// 居中对齐:元素中心对齐视口中心(考虑上下缓冲)
|
||||
nextScrollTop =
|
||||
elementOffsetTop -
|
||||
(viewportHeight - elementHeight - endOffset - startOffset) / 2 +
|
||||
startOffset;
|
||||
break;
|
||||
case 'end':
|
||||
// 底部对齐:元素底部对齐视口底部(考虑底部缓冲)
|
||||
nextScrollTop =
|
||||
elementOffsetTop + elementHeight - viewportHeight + endOffset;
|
||||
break;
|
||||
}
|
||||
|
||||
return nextScrollTop;
|
||||
}
|
||||
17
uni_modules/lime-shared/getRect/uvue.uts
Normal file
17
uni_modules/lime-shared/getRect/uvue.uts
Normal file
@@ -0,0 +1,17 @@
|
||||
// @ts-nocheck
|
||||
export function getRect(selector : string, context: ComponentPublicInstance):Promise<NodeInfo> {
|
||||
return new Promise((resolve)=>{
|
||||
uni.createSelectorQuery().in(context).select(selector).boundingClientRect(res =>{
|
||||
resolve(res as NodeInfo)
|
||||
}).exec();
|
||||
})
|
||||
}
|
||||
|
||||
export function getAllRect(selector : string, context: ComponentPublicInstance):Promise<NodeInfo[]> {
|
||||
return new Promise((resolve)=>{
|
||||
uni.createSelectorQuery().in(context).selectAll(selector).boundingClientRect(res =>{
|
||||
resolve(res as NodeInfo[])
|
||||
}).exec();
|
||||
})
|
||||
}
|
||||
|
||||
117
uni_modules/lime-shared/getRect/vue.ts
Normal file
117
uni_modules/lime-shared/getRect/vue.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
// @ts-nocheck
|
||||
|
||||
// #ifdef APP-NVUE
|
||||
// 当编译环境是 APP-NVUE 时,引入 uni.requireNativePlugin('dom'),具体插件用途未知
|
||||
const dom = uni.requireNativePlugin('dom')
|
||||
// #endif
|
||||
|
||||
/**
|
||||
* 获取节点信息
|
||||
* @param selector 选择器字符串
|
||||
* @param context ComponentInternalInstance 对象
|
||||
* @param node 是否获取node
|
||||
* @returns 包含节点信息的 Promise 对象
|
||||
*/
|
||||
export function getRect(selector : string, context : ComponentInternalInstance|ComponentPublicInstance, node: boolean = false) {
|
||||
// 之前是个对象,现在改成实例,防止旧版会报错
|
||||
if(context== null) {
|
||||
return Promise.reject('context is null')
|
||||
}
|
||||
if(context.context){
|
||||
context = context.context
|
||||
}
|
||||
// #ifdef MP || VUE2
|
||||
if (context.proxy) context = context.proxy
|
||||
// #endif
|
||||
return new Promise<UniNamespace.NodeInfo>((resolve, reject) => {
|
||||
// #ifndef APP-NVUE
|
||||
const dom = uni.createSelectorQuery().in(context).select(selector);
|
||||
const result = (rect: UniNamespace.NodeInfo) => {
|
||||
if (rect) {
|
||||
resolve(rect)
|
||||
} else {
|
||||
reject('no rect')
|
||||
}
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
dom.boundingClientRect(result).exec()
|
||||
} else {
|
||||
dom.fields({
|
||||
node: true,
|
||||
size: true,
|
||||
rect: true
|
||||
}, result).exec()
|
||||
}
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
const refs = context.refs || context.$refs
|
||||
if (/#|\./.test(selector) && refs) {
|
||||
selector = selector.replace(/#|\./, '')
|
||||
if (refs[selector]) {
|
||||
selector = refs[selector]
|
||||
if(Array.isArray(selector)) {
|
||||
selector = selector[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
dom.getComponentRect(selector, (res) => {
|
||||
if (res.size) {
|
||||
resolve(res.size)
|
||||
} else {
|
||||
reject('no rect')
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
export function getAllRect(selector : string, context: ComponentInternalInstance|ComponentPublicInstance, node:boolean = false) {
|
||||
if(context== null) {
|
||||
return Promise.reject('context is null')
|
||||
}
|
||||
// #ifdef MP || VUE2
|
||||
if (context.proxy) context = context.proxy
|
||||
// #endif
|
||||
return new Promise<UniNamespace.NodeInfo>((resolve, reject) => {
|
||||
// #ifndef APP-NVUE
|
||||
const dom = uni.createSelectorQuery().in(context).selectAll(selector);
|
||||
const result = (rect: UniNamespace.NodeInfo[]) => {
|
||||
if (rect) {
|
||||
resolve(rect)
|
||||
} else {
|
||||
reject('no rect')
|
||||
}
|
||||
}
|
||||
if (!node) {
|
||||
dom.boundingClientRect(result).exec()
|
||||
} else {
|
||||
dom.fields({
|
||||
node: true,
|
||||
size: true,
|
||||
rect: true
|
||||
}, result).exec()
|
||||
}
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
let { context } = options
|
||||
if (/#|\./.test(selector) && context.refs) {
|
||||
selector = selector.replace(/#|\./, '')
|
||||
if (context.refs[selector]) {
|
||||
selector = context.refs[selector]
|
||||
if(Array.isArray(selector)) {
|
||||
selector = selector[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
dom.getComponentRect(selector, (res) => {
|
||||
if (res.size) {
|
||||
resolve([res.size])
|
||||
} else {
|
||||
reject('no rect')
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
});
|
||||
};
|
||||
54
uni_modules/lime-shared/getStyleStr/index.ts
Normal file
54
uni_modules/lime-shared/getStyleStr/index.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef UNI-APP-X && APP
|
||||
interface CSSProperties {
|
||||
[key : string] : string | number | null
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef VUE3
|
||||
// #ifdef UNI-APP-X && APP
|
||||
type CSSProperties = UTSJSONObject
|
||||
// #endif
|
||||
// #endif
|
||||
/**
|
||||
* 将字符串转换为带有连字符分隔的小写形式
|
||||
* @param key - 要转换的字符串
|
||||
* @returns 转换后的字符串
|
||||
*/
|
||||
export function toLowercaseSeparator(key : string):string {
|
||||
return key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取样式对象对应的样式字符串
|
||||
* @param style - CSS样式对象
|
||||
* @returns 由非空有效样式属性键值对组成的字符串
|
||||
*/
|
||||
export function getStyleStr(style : CSSProperties) : string {
|
||||
|
||||
// #ifdef UNI-APP-X && APP
|
||||
let styleStr = '';
|
||||
style.toMap().forEach((value, key) => {
|
||||
if(value !== null && value != '') {
|
||||
styleStr += `${toLowercaseSeparator(key as string)}: ${value};`
|
||||
}
|
||||
})
|
||||
return styleStr
|
||||
// #endif
|
||||
// #ifndef UNI-APP-X && APP
|
||||
return Object.keys(style)
|
||||
.filter(
|
||||
(key) =>
|
||||
style[key] !== undefined &&
|
||||
style[key] !== null &&
|
||||
style[key] !== '')
|
||||
.map((key : string) => `${toLowercaseSeparator(key)}: ${style[key]};`)
|
||||
.join(' ');
|
||||
// #endif
|
||||
}
|
||||
|
||||
// 示例
|
||||
// const style = { color: 'red', fontSize: '16px', backgroundColor: '', border: null };
|
||||
// const styleStr = getStyleStr(style);
|
||||
// console.log(styleStr);
|
||||
// 输出: "color: red; font-size: 16px;"
|
||||
28
uni_modules/lime-shared/guid/index.ts
Normal file
28
uni_modules/lime-shared/guid/index.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 生成指定长度的伪随机字符串,通常用作唯一标识符(非标准GUID)
|
||||
*
|
||||
* 此函数使用Math.random()生成基于36进制(数字+小写字母)的随机字符串。当长度超过11位时,
|
||||
* 会通过递归拼接多个随机段实现。注意:该方法生成的并非标准GUID/UUID,不适合高安全性场景。
|
||||
*
|
||||
* @param {number} [len=32] - 要生成的字符串长度,默认32位
|
||||
* @returns {string} 生成的伪随机字符串,包含0-9和a-z字符
|
||||
*
|
||||
* @example
|
||||
* guid(); // 返回32位字符串,例如"3zyf6a5f3kb4ayy9jq9v1a70z0qdm0bk"
|
||||
* guid(5); // 返回5位字符串,例如"kf3a9"
|
||||
* guid(20); // 返回20位字符串,由两段随机字符串拼接而成
|
||||
*
|
||||
* @note
|
||||
* 1. 由于使用Math.random(),随机性存在安全缺陷,不适用于密码学用途
|
||||
* 2. 当长度>11时采用递归拼接,可能略微影响性能(在极端大长度情况下)
|
||||
* 3. 字符串补全时使用'0'填充,可能略微降低末尾字符的随机性
|
||||
*/
|
||||
export function guid(len:number = 32):string {
|
||||
// crypto.randomUUID();
|
||||
return len <= 11
|
||||
? Math.random()
|
||||
.toString(36)
|
||||
.substring(2, 2 + len)
|
||||
.padEnd(len, '0')
|
||||
: guid(11) + guid(len - 11);
|
||||
}
|
||||
11
uni_modules/lime-shared/hasOwn/index.ts
Normal file
11
uni_modules/lime-shared/hasOwn/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
// @ts-nocheck
|
||||
// #ifdef UNI-APP-X && APP
|
||||
// export * from './uvue.uts'
|
||||
export { hasOwn } from './uvue.uts'
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifndef UNI-APP-X && APP
|
||||
// export * from './vue.ts'
|
||||
export { hasOwn } from './vue.ts'
|
||||
// #endif
|
||||
43
uni_modules/lime-shared/hasOwn/uvue.uts
Normal file
43
uni_modules/lime-shared/hasOwn/uvue.uts
Normal file
@@ -0,0 +1,43 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 检查对象或数组是否具有指定的属性或键
|
||||
* @param obj 要检查的对象或数组
|
||||
* @param key 指定的属性或键
|
||||
* @returns 如果对象或数组具有指定的属性或键,则返回true;否则返回false
|
||||
*/
|
||||
function hasOwn(obj: UTSJSONObject, key: string): boolean
|
||||
function hasOwn(obj: Map<string, unknown>, key: string): boolean
|
||||
function hasOwn(obj: any, key: string): boolean {
|
||||
if(obj instanceof UTSJSONObject){
|
||||
return obj[key] != null
|
||||
}
|
||||
if(obj instanceof Map<string, unknown>){
|
||||
return (obj as Map<string, unknown>).has(key)
|
||||
}
|
||||
if(typeof obj == 'object') {
|
||||
const obj2 = {...toRaw(obj)}
|
||||
return obj2[key] != null
|
||||
}
|
||||
return false
|
||||
}
|
||||
export {
|
||||
hasOwn
|
||||
}
|
||||
// 示例
|
||||
// const obj = { name: 'John', age: 30 };
|
||||
|
||||
// if (hasOwn(obj, 'name')) {
|
||||
// console.log("对象具有 'name' 属性");
|
||||
// } else {
|
||||
// console.log("对象不具有 'name' 属性");
|
||||
// }
|
||||
// // 输出: 对象具有 'name' 属性
|
||||
|
||||
// const arr = [1, 2, 3];
|
||||
|
||||
// if (hasOwn(arr, 'length')) {
|
||||
// console.log("数组具有 'length' 属性");
|
||||
// } else {
|
||||
// console.log("数组不具有 'length' 属性");
|
||||
// }
|
||||
// 输出: 数组具有 'length' 属性
|
||||
30
uni_modules/lime-shared/hasOwn/vue.ts
Normal file
30
uni_modules/lime-shared/hasOwn/vue.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
// @ts-nocheck
|
||||
const hasOwnProperty = Object.prototype.hasOwnProperty
|
||||
/**
|
||||
* 检查对象或数组是否具有指定的属性或键
|
||||
* @param obj 要检查的对象或数组
|
||||
* @param key 指定的属性或键
|
||||
* @returns 如果对象或数组具有指定的属性或键,则返回true;否则返回false
|
||||
*/
|
||||
export function hasOwn(obj: Object | Array<any>, key: string): boolean {
|
||||
return hasOwnProperty.call(obj, key);
|
||||
}
|
||||
|
||||
// 示例
|
||||
// const obj = { name: 'John', age: 30 };
|
||||
|
||||
// if (hasOwn(obj, 'name')) {
|
||||
// console.log("对象具有 'name' 属性");
|
||||
// } else {
|
||||
// console.log("对象不具有 'name' 属性");
|
||||
// }
|
||||
// // 输出: 对象具有 'name' 属性
|
||||
|
||||
// const arr = [1, 2, 3];
|
||||
|
||||
// if (hasOwn(arr, 'length')) {
|
||||
// console.log("数组具有 'length' 属性");
|
||||
// } else {
|
||||
// console.log("数组不具有 'length' 属性");
|
||||
// }
|
||||
// 输出: 数组具有 'length' 属性
|
||||
43
uni_modules/lime-shared/index.ts
Normal file
43
uni_modules/lime-shared/index.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
// @ts-nocheck
|
||||
// validator
|
||||
// export * from './isString'
|
||||
// export * from './isNumber'
|
||||
// export * from './isNumeric'
|
||||
// export * from './isDef'
|
||||
// export * from './isFunction'
|
||||
// export * from './isObject'
|
||||
// export * from './isPromise'
|
||||
// export * from './isBase64'
|
||||
|
||||
// export * from './hasOwn'
|
||||
|
||||
// // 单位转换
|
||||
// export * from './addUnit'
|
||||
// export * from './unitConvert'
|
||||
// export * from './toNumber'
|
||||
|
||||
// export * from './random'
|
||||
// export * from './range'
|
||||
// export * from './fillZero'
|
||||
|
||||
// // image
|
||||
// export * from './base64ToPath'
|
||||
// export * from './pathToBase64'
|
||||
// export * from './exif'
|
||||
|
||||
// // canvas
|
||||
// export * from './canIUseCanvas2d'
|
||||
|
||||
// // page
|
||||
// export * from './getCurrentPage'
|
||||
|
||||
// // dom
|
||||
// export * from './getRect'
|
||||
// export * from './selectComponent'
|
||||
// export * from './createAnimation'
|
||||
|
||||
// // delay
|
||||
// export * from './sleep'
|
||||
// export * from './debounce'
|
||||
// export * from './throttle'
|
||||
|
||||
23
uni_modules/lime-shared/isBase64/index.ts
Normal file
23
uni_modules/lime-shared/isBase64/index.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
// @ts-nocheck
|
||||
|
||||
/**
|
||||
* 判断一个字符串是否为Base64编码。
|
||||
* Base64编码的字符串只包含A-Z、a-z、0-9、+、/ 和 = 这些字符。
|
||||
* @param {string} str - 要检查的字符串。
|
||||
* @returns {boolean} 如果字符串是Base64编码,返回true,否则返回false。
|
||||
*/
|
||||
export function isBase64(str: string): boolean {
|
||||
const base64Regex = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
|
||||
return base64Regex.test(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断一个字符串是否为Base64编码的data URI。
|
||||
* Base64编码的data URI通常以"data:"开头,后面跟着MIME类型和编码信息,然后是Base64编码的数据。
|
||||
* @param {string} str - 要检查的字符串。
|
||||
* @returns {boolean} 如果字符串是Base64编码的data URI,返回true,否则返回false。
|
||||
*/
|
||||
export function isDataURI(str: string): boolean {
|
||||
const dataUriRegex = /^data:([a-zA-Z]+\/[a-zA-Z0-9-+.]+)(;base64)?,([a-zA-Z0-9+/]+={0,2})$/;
|
||||
return dataUriRegex.test(str);
|
||||
}
|
||||
24
uni_modules/lime-shared/isBoolean/index.ts
Normal file
24
uni_modules/lime-shared/isBoolean/index.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 检查一个值是否为严格的布尔值(仅限 `true` 或 `false`)
|
||||
*
|
||||
* @example
|
||||
* isBoolean(true); // true
|
||||
* isBoolean(false); // true
|
||||
* isBoolean(0); // false
|
||||
* isBoolean(null); // false
|
||||
*
|
||||
* @param {unknown} value - 要检查的值
|
||||
* @returns {value is boolean} 如果值是 `true` 或 `false` 则返回 `true`,否则返回 `false`
|
||||
*
|
||||
* @description
|
||||
* 此函数使用严格相等(`===`)检查,避免隐式类型转换。
|
||||
* 注意:不适用于 `Boolean` 包装对象(如 `new Boolean(true)`)。
|
||||
*/
|
||||
export function isBoolean(value: any|null): boolean {
|
||||
// #ifdef APP-ANDROID
|
||||
return value == true || value == false
|
||||
// #endif
|
||||
// #ifndef APP-ANDROID
|
||||
return value === true || value === false
|
||||
// #endif
|
||||
}
|
||||
8
uni_modules/lime-shared/isBrowser/index.ts
Normal file
8
uni_modules/lime-shared/isBrowser/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
// @ts-nocheck
|
||||
// #ifdef WEB
|
||||
export const isBrowser = typeof window !== 'undefined';
|
||||
// #endif
|
||||
|
||||
// #ifndef WEB
|
||||
export const isBrowser = false;
|
||||
// #endif
|
||||
86
uni_modules/lime-shared/isByteLength/index.ts
Normal file
86
uni_modules/lime-shared/isByteLength/index.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
// @ts-nocheck
|
||||
// import assertString from './util/assertString';
|
||||
|
||||
/**
|
||||
* 字节长度验证配置选项
|
||||
*/
|
||||
export type IsByteLengthOptions = {
|
||||
/** 允许的最小字节长度 */
|
||||
min ?: number;
|
||||
/** 允许的最大字节长度 */
|
||||
max ?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查字符串字节长度是否在指定范围内
|
||||
* @function
|
||||
* @overload 使用配置对象
|
||||
* @param str - 要检查的字符串
|
||||
* @param options - 配置选项对象
|
||||
* @returns 是否满足字节长度要求
|
||||
*
|
||||
* @overload 使用独立参数
|
||||
* @param str - 要检查的字符串
|
||||
* @param min - 最小字节长度
|
||||
* @param max - 最大字节长度(可选)
|
||||
* @returns 是否满足字节长度要求
|
||||
*
|
||||
* @example
|
||||
* // 使用配置对象
|
||||
* isByteLength('🇨🇳', { min: 4, max: 8 }); // true(unicode 国旗符号占 8 字节)
|
||||
*
|
||||
* @example
|
||||
* // 旧式参数调用
|
||||
* isByteLength('hello', 3, 7); // true(实际字节长度 5)
|
||||
*
|
||||
* @description
|
||||
* 1. 使用 URL 编码计算字节长度(更准确处理多字节字符)
|
||||
* 2. 同时支持两种参数格式:
|
||||
* - 配置对象格式 { min, max }
|
||||
* - 独立参数格式 (min, max)
|
||||
* 3. 不传 max 参数时只验证最小长度
|
||||
* 4. 严格空值处理,允许设置 0 值
|
||||
*/
|
||||
export function isByteLength(str : string, optionsOrMin ?: IsByteLengthOptions) : boolean;
|
||||
export function isByteLength(str : string, optionsOrMin ?: number) : boolean;
|
||||
export function isByteLength(str : string, optionsOrMin : number, maxParam : number | null) : boolean;
|
||||
export function isByteLength(
|
||||
str : string,
|
||||
optionsOrMin ?: IsByteLengthOptions | number,
|
||||
maxParam : number | null = null
|
||||
) : boolean {
|
||||
// assertString(str);
|
||||
|
||||
/** 最终计算的最小长度 */
|
||||
let min: number;
|
||||
|
||||
/** 最终计算的最大长度 */
|
||||
let max : number | null;
|
||||
|
||||
// 参数逻辑处理
|
||||
if (optionsOrMin != null && typeof optionsOrMin == 'object') {
|
||||
// 使用对象配置的情况
|
||||
const options = optionsOrMin as IsByteLengthOptions;
|
||||
min = Math.max(options.min ?? 0, 0); // 确保最小值为正整数
|
||||
max = options.max;
|
||||
} else {
|
||||
// 使用独立参数的情况
|
||||
min = Math.max(
|
||||
typeof optionsOrMin == 'number' ? optionsOrMin : 0,
|
||||
0
|
||||
);
|
||||
max = maxParam;
|
||||
}
|
||||
|
||||
// URL 编码后的字节长度计算
|
||||
const encoded = encodeURI(str);
|
||||
const len = (encoded?.split(/%..|./).length ?? 0) - 1;
|
||||
|
||||
// 执行验证逻辑
|
||||
// #ifndef APP-ANDROID
|
||||
return len >= min && (typeof max == 'undefined' || len <= (max ?? 0));
|
||||
// #endif
|
||||
// #ifdef APP-ANDROID
|
||||
return len >= min && (max == null || len <= max);
|
||||
// #endif
|
||||
}
|
||||
189
uni_modules/lime-shared/isDate/index.ts
Normal file
189
uni_modules/lime-shared/isDate/index.ts
Normal file
@@ -0,0 +1,189 @@
|
||||
// @ts-nocheck
|
||||
|
||||
/**
|
||||
* 日期验证配置选项
|
||||
*/
|
||||
export type IsDateOptions = {
|
||||
/** 日期格式字符串,默认 'YYYY/MM/DD' */
|
||||
format ?: string;
|
||||
/** 允许的分隔符数组,默认 ['/', '-'] */
|
||||
delimiters ?: string[];
|
||||
/** 是否严格匹配格式,默认 false */
|
||||
strictMode ?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证日期格式字符串是否合法
|
||||
* @param format - 需要验证的格式字符串
|
||||
* @returns 是否合法格式
|
||||
*/
|
||||
function isValidFormat(format : string) : boolean {
|
||||
return /(^(y{4}|y{2})[年./-](m{1,2})[月./-](d{1,2}(日)?)$)|(^(m{1,2})[./-](d{1,2})[./-]((y{4}|y{2})$))|(^(d{1,2})[./-](m{1,2})[./-]((y{4}|y{2})$))/i.test(format);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将日期部分和格式部分组合成键值对数组
|
||||
* @param date - 分割后的日期部分数组
|
||||
* @param format - 分割后的格式部分数组
|
||||
* @returns 组合后的二维数组
|
||||
*/
|
||||
function zip(date : string[], format : string[]) : string[][] {
|
||||
const zippedArr : string[][] = [];
|
||||
const len = Math.max(date.length, format.length);
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
const key = i < date.length ? date[i] : ''
|
||||
const value = i < format.length ? format[i] : ''
|
||||
|
||||
zippedArr.push([key, value])
|
||||
}
|
||||
|
||||
return zippedArr;
|
||||
}
|
||||
|
||||
|
||||
/** 验证日期对象 */
|
||||
function validateDateObject(date : Date, strictMode : boolean) : boolean {
|
||||
// #ifndef APP-ANDROID
|
||||
return !strictMode && Object.prototype.toString.call(date) === '[object Date]' && !isNaN(date.getTime());
|
||||
// #endif
|
||||
// #ifdef APP-ANDROID
|
||||
return !strictMode && !isNaN(date.getTime())
|
||||
// #endif
|
||||
}
|
||||
|
||||
|
||||
function escapeRegExp(str: string): string {
|
||||
return str//.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
|
||||
function enhancedSplit(
|
||||
str: string,
|
||||
delimiters: string[]
|
||||
): string[] {
|
||||
// 构建动态分隔符正则表达式
|
||||
const escapedDelimiters = delimiters.map(d => escapeRegExp(d));
|
||||
const pattern = new RegExp(
|
||||
`[${escapedDelimiters.join('')}]+`, // 匹配任意允许的分隔符
|
||||
'g'
|
||||
);
|
||||
|
||||
return str.split(pattern).filter(p => p != '');
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证输入是否为有效日期
|
||||
* @param input - 输入值,可以是字符串或 Date 对象
|
||||
* @param options - 配置选项,可以是字符串(简写格式)或配置对象
|
||||
* @returns 是否为有效日期
|
||||
*
|
||||
* @example
|
||||
* isDate('2023/12/31'); // true
|
||||
* isDate(new Date()); // true
|
||||
* isDate('02-29-2023', { strictMode: true }); // false(2023年不是闰年)
|
||||
*/
|
||||
export function isDate(input : Date, options ?: IsDateOptions) : boolean;
|
||||
export function isDate(input : string, options ?: string | IsDateOptions) : boolean;
|
||||
export function isDate(input : string | Date, options : string | IsDateOptions | null = null) : boolean {
|
||||
// 处理参数重载:允许第二个参数直接传格式字符串
|
||||
// Date对象验证
|
||||
|
||||
|
||||
let format = 'YYYY/MM/DD'
|
||||
let delimiters = ['/', '-']
|
||||
let strictMode = false
|
||||
|
||||
|
||||
if (options != null) {
|
||||
if (typeof options == 'string') {
|
||||
format = options as string
|
||||
} else {
|
||||
format = (options as IsDateOptions).format ?? format
|
||||
delimiters = (options as IsDateOptions).delimiters ?? delimiters
|
||||
strictMode = (options as IsDateOptions).strictMode ?? strictMode
|
||||
}
|
||||
}
|
||||
if (input instanceof Date) {
|
||||
return validateDateObject(input, strictMode);
|
||||
}
|
||||
|
||||
|
||||
// 字符串类型验证
|
||||
if (!isValidFormat(format)) return false;
|
||||
// 严格模式长度检查
|
||||
if (strictMode && input.length != format.length) {
|
||||
return false;
|
||||
}
|
||||
// 获取格式中的分隔符
|
||||
const formatDelimiter = delimiters.find((d) : boolean => format.indexOf(d) != -1);
|
||||
// 获取实际使用的分隔符
|
||||
const dateDelimiter = strictMode
|
||||
? formatDelimiter
|
||||
: delimiters.find((d) : boolean => input.indexOf(d) != -1);
|
||||
// 分割日期和格式
|
||||
const dateParts = strictMode ? enhancedSplit(input, delimiters) : input.split(dateDelimiter ?? '');
|
||||
const formatParts = strictMode ? enhancedSplit(format.toLowerCase(), delimiters) : format.toLowerCase().split(formatDelimiter ?? '');
|
||||
// 组合成键值对
|
||||
const dateAndFormat = zip(dateParts, formatParts);
|
||||
const dateObj = new Map<string, string>();
|
||||
|
||||
|
||||
// 解析日期组成部分
|
||||
for (const [dateWord, formatWord] of dateAndFormat) {
|
||||
if (dateWord == '' || formatWord == '' || dateWord.length != formatWord.length) {
|
||||
return false;
|
||||
}
|
||||
dateObj.set(formatWord.charAt(0), dateWord)
|
||||
}
|
||||
|
||||
// 年份处理
|
||||
let fullYear = dateObj.get('y');
|
||||
|
||||
if (fullYear == null) return false;
|
||||
|
||||
// 检查年份前导负号
|
||||
if (fullYear.startsWith('-')) return false;
|
||||
|
||||
// 两位年份转四位
|
||||
if (fullYear.length == 2) {
|
||||
const parsedYear = parseInt(fullYear, 10);
|
||||
|
||||
if (isNaN(parsedYear)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const currentYear = new Date().getFullYear();
|
||||
const century = currentYear - (currentYear % 100);
|
||||
fullYear = (parseInt(fullYear, 10) < (currentYear % 100))
|
||||
? `${century + 100 + parseInt(fullYear, 10)}`
|
||||
: `${century + parseInt(fullYear, 10)}`;
|
||||
}
|
||||
|
||||
// 月份补零
|
||||
const month = dateObj.get('m')?.padStart(2, '0') ?? '';
|
||||
// 日期补零
|
||||
const day = dateObj.get('d')?.padStart(2, '0') ?? '';
|
||||
|
||||
const isoDate = `${fullYear}-${month}-${day}T00:00:00.000Z`;
|
||||
|
||||
// return new Date(time).getDate() == parseInt(day);
|
||||
|
||||
// 构造 ISO 日期字符串验证
|
||||
try {
|
||||
// #ifndef APP-ANDROID
|
||||
const date = new Date(isoDate);
|
||||
return date.getUTCDate() === parseInt(day, 10) &&
|
||||
(date.getUTCMonth() + 1) === parseInt(month, 10) &&
|
||||
date.getUTCFullYear() === parseInt(fullYear, 10);
|
||||
// #endif
|
||||
// #ifdef APP-ANDROID
|
||||
const date = new Date(isoDate);
|
||||
return date.getDate() == parseInt(day, 10) &&
|
||||
(date.getMonth() + 1) == parseInt(month, 10) &&
|
||||
date.getFullYear() == parseInt(fullYear, 10);
|
||||
// #endif
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
23
uni_modules/lime-shared/isDef/index.ts
Normal file
23
uni_modules/lime-shared/isDef/index.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 检查一个值是否已定义(不为 undefined)且不为 null
|
||||
* @param value 要检查的值
|
||||
* @returns 如果值已定义且不为 null,则返回 true;否则返回 false
|
||||
*/
|
||||
// #ifndef UNI-APP-X
|
||||
export function isDef(value: unknown): boolean {
|
||||
return value !== undefined && value !== null;
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef UNI-APP-X
|
||||
export function isDef(value : any|null) : boolean {
|
||||
// #ifdef UNI-APP-X && APP
|
||||
return value != null;
|
||||
// #endif
|
||||
// #ifndef UNI-APP-X && APP
|
||||
return value != null && value != undefined;
|
||||
// #endif
|
||||
}
|
||||
// #endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user