mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2026-01-03 03:45:28 +08:00
前端和后端源码,合并到一个git仓库中,方便用户下载,避免前后端不匹配的问题
This commit is contained in:
6
jeecgboot-vue3/src/components/CountDown/index.ts
Normal file
6
jeecgboot-vue3/src/components/CountDown/index.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { withInstall } from '/@/utils';
|
||||
import countButton from './src/CountButton.vue';
|
||||
import countdownInput from './src/CountdownInput.vue';
|
||||
|
||||
export const CountdownInput = withInstall(countdownInput);
|
||||
export const CountButton = withInstall(countButton);
|
||||
73
jeecgboot-vue3/src/components/CountDown/src/CountButton.vue
Normal file
73
jeecgboot-vue3/src/components/CountDown/src/CountButton.vue
Normal file
@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<Button v-bind="$attrs" :disabled="isStart" @click="handleStart" :loading="loading">
|
||||
{{ getButtonText }}
|
||||
</Button>
|
||||
<!-- 图片验证码弹窗 -->
|
||||
<CaptchaModal @register="captchaRegisterModal" @ok="handleStart" />
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, watchEffect, computed, unref } from 'vue';
|
||||
import { Button } from 'ant-design-vue';
|
||||
import { useCountdown } from './useCountdown';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useModal } from "@/components/Modal";
|
||||
import { createAsyncComponent } from "@/utils/factory/createAsyncComponent";
|
||||
import { ExceptionEnum } from "@/enums/exceptionEnum";
|
||||
const CaptchaModal = createAsyncComponent(() => import('/@/components/jeecg/captcha/CaptchaModal.vue'));
|
||||
const [captchaRegisterModal, { openModal: openCaptchaModal }] = useModal();
|
||||
|
||||
const props = {
|
||||
value: { type: [Object, Number, String, Array] },
|
||||
count: { type: Number, default: 60 },
|
||||
beforeStartFunc: {
|
||||
type: Function as PropType<() => Promise<boolean>>,
|
||||
default: null,
|
||||
},
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CountButton',
|
||||
components: { Button, CaptchaModal },
|
||||
props,
|
||||
setup(props) {
|
||||
const loading = ref(false);
|
||||
|
||||
const { currentCount, isStart, start, reset } = useCountdown(props.count);
|
||||
const { t } = useI18n();
|
||||
|
||||
const getButtonText = computed(() => {
|
||||
return !unref(isStart) ? t('component.countdown.normalText') : t('component.countdown.sendText', [unref(currentCount)]);
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
props.value === undefined && reset();
|
||||
});
|
||||
|
||||
/**
|
||||
* @description: Judge whether there is an external function before execution, and decide whether to start after execution
|
||||
*/
|
||||
async function handleStart() {
|
||||
const { beforeStartFunc } = props;
|
||||
if (beforeStartFunc && isFunction(beforeStartFunc)) {
|
||||
loading.value = true;
|
||||
try {
|
||||
//update-begin---author:wangshuai---date:2024-04-18---for:【QQYUN-9005】同一个IP,1分钟超过5次短信,则提示需要验证码---
|
||||
const canStart = await beforeStartFunc().catch((res) =>{
|
||||
if(res.code === ExceptionEnum.PHONE_SMS_FAIL_CODE){
|
||||
openCaptchaModal(true, {});
|
||||
}
|
||||
});
|
||||
//update-end---author:wangshuai---date:2024-04-18---for:【QQYUN-9005】同一个IP,1分钟超过5次短信,则提示需要验证码---
|
||||
canStart && start();
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
} else {
|
||||
start();
|
||||
}
|
||||
}
|
||||
return { handleStart, currentCount, loading, getButtonText, isStart, captchaRegisterModal };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<a-input v-bind="$attrs" :class="prefixCls" :size="size" :value="state">
|
||||
<template #addonAfter>
|
||||
<CountButton :size="size" :count="count" :value="state" :beforeStartFunc="sendCodeApi" />
|
||||
</template>
|
||||
<template #[item]="data" v-for="item in Object.keys($slots).filter((k) => k !== 'addonAfter')">
|
||||
<slot :name="item" v-bind="data || {}"></slot>
|
||||
</template>
|
||||
</a-input>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import CountButton from './CountButton.vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useRuleFormItem } from '/@/hooks/component/useFormItemSingle';
|
||||
|
||||
const props = {
|
||||
value: { type: String },
|
||||
size: { type: String, validator: (v) => ['default', 'large', 'small'].includes(v) },
|
||||
count: { type: Number, default: 60 },
|
||||
sendCodeApi: {
|
||||
type: Function as PropType<() => Promise<boolean>>,
|
||||
default: null,
|
||||
},
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CountDownInput',
|
||||
components: { CountButton },
|
||||
inheritAttrs: false,
|
||||
props,
|
||||
setup(props) {
|
||||
const { prefixCls } = useDesign('countdown-input');
|
||||
const [state] = useRuleFormItem(props);
|
||||
|
||||
return { prefixCls, state };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-countdown-input';
|
||||
|
||||
.@{prefix-cls} {
|
||||
.ant-input-group-addon {
|
||||
padding-right: 0;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
|
||||
button {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
51
jeecgboot-vue3/src/components/CountDown/src/useCountdown.ts
Normal file
51
jeecgboot-vue3/src/components/CountDown/src/useCountdown.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { ref, unref } from 'vue';
|
||||
import { tryOnUnmounted } from '@vueuse/core';
|
||||
|
||||
export function useCountdown(count: number) {
|
||||
const currentCount = ref(count);
|
||||
|
||||
const isStart = ref(false);
|
||||
|
||||
let timerId: ReturnType<typeof setInterval> | null;
|
||||
|
||||
function clear() {
|
||||
timerId && window.clearInterval(timerId);
|
||||
}
|
||||
|
||||
function stop() {
|
||||
isStart.value = false;
|
||||
clear();
|
||||
timerId = null;
|
||||
}
|
||||
|
||||
function start() {
|
||||
if (unref(isStart) || !!timerId) {
|
||||
return;
|
||||
}
|
||||
isStart.value = true;
|
||||
timerId = setInterval(() => {
|
||||
if (unref(currentCount) === 1) {
|
||||
stop();
|
||||
currentCount.value = count;
|
||||
} else {
|
||||
currentCount.value -= 1;
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function reset() {
|
||||
currentCount.value = count;
|
||||
stop();
|
||||
}
|
||||
|
||||
function restart() {
|
||||
reset();
|
||||
start();
|
||||
}
|
||||
|
||||
tryOnUnmounted(() => {
|
||||
reset();
|
||||
});
|
||||
|
||||
return { start, reset, restart, clear, stop, currentCount, isStart };
|
||||
}
|
||||
Reference in New Issue
Block a user