| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- <template>
- <!--TODO: 在uniapp插槽问题修复后,此处可修改为插槽默认值-->
- <FlexCol :innerStyle="{
- ...themeStyles.dialog.value,
- width: themeContext.resolveThemeSize(width)
- }">
- <slot v-if="topSlots?.default" />
- <FlexCol v-else :padding="contentPadding" align="center">
- <!-- 图标 -->
- <FlexCol v-if="icon" :innerStyle="themeStyles.icon.value">
- <slot name="icon" :icon="icon" />
- <Icon :icon="icon" :color="iconColor" :size="iconSize || 40" />
- </FlexCol>
- <!-- 标题 -->
- <slot v-if="topSlots?.title" name="title" :title="title" />
- <text v-else-if="title" :style="themeStyles.title.value">{{ title }}</text>
- <!-- 内容 -->
- <scroll-view
- v-if="contentScroll"
- scroll-y
- scroll-x
- :style="{
- position: 'relative',
- maxHeight: contentScrollMaxHeight
- }"
- >
- <slot v-if="topSlots?.content" name="content" />
- <text :style="themeStyles.contentText.value">{{ content }}</text>
- </scroll-view>
- <template v-else>
- <slot v-if="topSlots?.content" name="content" />
- <text v-else :style="themeStyles.contentText.value">{{ content }}</text>
- </template>
- </FlexCol>
- <!-- 底部按钮 -->
- <slot
- v-if="topSlots?.bottomContent"
- name="bottomContent"
- :onConfirmClick="(name?: string) => onConfirmClick(name || 'confirm')"
- :onCancelClick="onCancelClick"
- />
- <FlexView v-else :direction="bottomVertical ? 'column' : 'row'" :innerStyle="themeStyles.bottomView.value">
- <DialogButton
- v-if="showCancel"
- key="cancel"
- :vertical="bottomVertical"
- :text="cancelText"
- :loading="buttomLoadingState.cancel"
- :buttonColor="cancelColor"
- @click="onCancelClick"
- />
- <DialogButton
- v-for="(button, key) in customButtons"
- :vertical="bottomVertical"
- :key="key"
- :text="button.text"
- :loading="buttomLoadingState[button.name]"
- :buttonColor="button.color || 'text.content'"
- @click="onConfirmClick(button.name)"
- />
- <DialogButton
- v-if="showConfirm"
- key="confirm"
- :vertical="bottomVertical"
- :text="confirmCountDownValue > 0 ? `${confirmText} (${confirmCountDownValue})` : confirmText"
- :loading="buttomLoadingState.confirm"
- :touchable="confirmCountDownValue <= 0"
- :buttonColor="confirmColor"
- @click="onConfirmClick('confirm')"
- />
- </FlexView>
- </FlexCol>
- </template>
- <script setup lang="ts">
- import { onMounted, ref } from 'vue';
- import { propGetThemeVar, useTheme } from '../theme/ThemeDefine';
- import { DynamicColor, DynamicSize, DynamicVar } from '../theme/ThemeTools';
- import FlexView from '../layout/FlexView.vue';
- import FlexCol from '../layout/FlexCol.vue';
- import Icon from '../basic/Icon.vue';
- import DialogButton from './DialogButton.vue';
- import type { DialogProps } from './Dialog.vue';
- const themeContext = useTheme();
- const themeStyles = themeContext.useThemeStyles({
- dialog: {
- minWidth: DynamicSize('DialogMinWidth', 400),
- maxWidth: DynamicSize('DialogMaxWidth', 700),
- },
- bottomView: {
- position: 'relative',
- },
- icon: {
- marginTop: DynamicSize('DialogIconMarginTop', 16),
- marginBottom: DynamicSize('DialogIconMarginBottom', 12),
- justifyContent: 'center',
- alignItems: 'center',
- },
- title: {
- fontSize: DynamicSize('DialogTitleFontSize', 36),
- color: DynamicColor('DialogTitleColor', 'text.content'),
- fontWeight: DynamicSize('DialogTitleFontWeight', 'bold'),
- textAlign: 'center',
- marginBottom: DynamicSize('DialogTitleMarginBottom', 20),
- },
- contentText: {
- width: '100%',
- display: 'block',
- fontSize: DynamicSize('DialogContentTextFontSize', 28),
- color: DynamicColor('DialogContentTextColor', 'text.second'),
- textAlign: DynamicVar('DialogContentTextAlign', 'center'),
- },
- });
- export interface DialogInnerProps extends Omit<DialogProps, 'show'> {
- topSlots?: Record<string, boolean>,
- confirmCountDownTime?: number,
- }
- const emit = defineEmits([ 'close' ]);
- const props = withDefaults(defineProps<DialogInnerProps>(), {
- showConfirm: true,
- cancelText: '取消',
- cancelColor: () => propGetThemeVar('DialogCancelColor', 'text.content'),
- confirmText: '确定',
- confirmColor: () => propGetThemeVar('DialogConfirmColor', 'primary'),
- iconSize: () => propGetThemeVar('DialogIconSize', 70),
- iconColor: () => propGetThemeVar('DialogIconColor', 'primary'),
- contentScroll: true,
- contentScrollMaxHeight: () => propGetThemeVar('DialogContentScrollMaxHeight', '1000rpx'),
- contentPadding: () => propGetThemeVar('DialogContentPadding', [ 30, 40 ]),
- });
- const buttomLoadingState = ref<Record<string, boolean>>({});
- const confirmCountDownValue = ref<number>(0);
- function setButtonLoadingStateByName(name: string, state: boolean) {
- buttomLoadingState.value[name] = state;
- }
- function checkAnyButtonLoading() {
- for (const key in buttomLoadingState.value) {
- if (buttomLoadingState.value[key] === true)
- return true;
- }
- return false;
- }
- function startConfirmCountDown() {
- if (!props.confirmCountDownTime)
- return;
- confirmCountDownValue.value = props.confirmCountDownTime;
- const interval = setInterval(() => {
- confirmCountDownValue.value--;
- if (confirmCountDownValue.value <= 0) {
- clearInterval(interval);
- }
- }, 1000);
- }
-
- function onPopupClose() {
- emit('close');
- }
- function onCancelClick() {
- if (checkAnyButtonLoading())
- return;
- if (!props.onCancel) {
- onPopupClose();
- return;
- }
- const ret = props.onCancel();
- if (typeof ret === 'object') {
- setButtonLoadingStateByName('cancel', true);
- ret.then(() => {
- setButtonLoadingStateByName('cancel', false);
- onPopupClose();
- }).catch(() => {
- setButtonLoadingStateByName('cancel', false);
- });
- } else onPopupClose();
- }
- function onConfirmClick(name: string) {
- if (checkAnyButtonLoading())
- return;
- if (!props.onConfirm) {
- onPopupClose();
- return;
- }
- const ret = props.onConfirm(name);
- if (typeof ret === 'object') {
- setButtonLoadingStateByName(name, true);
- ret.then(() => {
- setButtonLoadingStateByName(name, false);
- onPopupClose();
- }).catch(() => {
- setButtonLoadingStateByName(name, false);
- });
- } else onPopupClose();
- }
- onMounted(() => {
- setTimeout(() => {
- startConfirmCountDown();
- }, 200);
- });
- defineExpose({
- startConfirmCountDown,
- })
- </script>
|