feat: 实现发行申请提交
This commit is contained in:
2
src/components/ui/collapse/exports.ts
Normal file
2
src/components/ui/collapse/exports.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export { default as Collapse } from './index.vue';
|
||||
export type * from './types';
|
||||
138
src/components/ui/collapse/index.vue
Normal file
138
src/components/ui/collapse/index.vue
Normal file
@@ -0,0 +1,138 @@
|
||||
<script lang='ts' setup>
|
||||
import type { CollapseEmits, CollapseProps } from "./types";
|
||||
import { IonIcon } from "@ionic/vue";
|
||||
import { chevronDownOutline } from "ionicons/icons";
|
||||
import { nextTick, ref } from "vue";
|
||||
|
||||
const props = withDefaults(defineProps<CollapseProps>(), {
|
||||
disabled: false,
|
||||
bordered: true,
|
||||
size: "medium",
|
||||
});
|
||||
|
||||
defineEmits<CollapseEmits>();
|
||||
|
||||
const active = defineModel<boolean>("active", { type: Boolean, default: true });
|
||||
|
||||
const contentRef = ref<HTMLElement>();
|
||||
|
||||
async function toggle() {
|
||||
if (props.disabled)
|
||||
return;
|
||||
|
||||
if (!active.value) {
|
||||
// 展开
|
||||
active.value = true;
|
||||
await nextTick();
|
||||
|
||||
if (contentRef.value) {
|
||||
const height = contentRef.value.scrollHeight;
|
||||
contentRef.value.style.height = "0px";
|
||||
requestAnimationFrame(() => {
|
||||
contentRef.value!.style.height = `${height}px`;
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 收起
|
||||
if (contentRef.value) {
|
||||
const height = contentRef.value.scrollHeight;
|
||||
contentRef.value.style.height = `${height}px`;
|
||||
requestAnimationFrame(() => {
|
||||
contentRef.value!.style.height = "0px";
|
||||
});
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
active.value = false;
|
||||
}, 300);
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (contentRef.value && active.value) {
|
||||
contentRef.value.style.height = "auto";
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
function onTransitionEnd() {
|
||||
if (contentRef.value && !active.value) {
|
||||
contentRef.value.style.height = "0px";
|
||||
}
|
||||
}
|
||||
|
||||
// 暴露给父组件的方法和属性
|
||||
defineExpose({
|
||||
toggle,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="w-full overflow-hidden"
|
||||
:class="{
|
||||
'border border-gray-200 dark:border-gray-600 rounded-lg': bordered,
|
||||
'opacity-60': disabled,
|
||||
}"
|
||||
>
|
||||
<!-- 头部触发区域 -->
|
||||
<div
|
||||
class="flex items-center justify-between cursor-pointer transition-colors duration-200 select-none"
|
||||
:class="[
|
||||
{
|
||||
'border-b border-gray-200 dark:border-gray-600': bordered,
|
||||
},
|
||||
{
|
||||
'p-3 text-sm': size === 'small',
|
||||
'p-4 text-base': size === 'medium',
|
||||
'p-5 text-lg': size === 'large',
|
||||
},
|
||||
{
|
||||
'cursor-not-allowed': disabled,
|
||||
},
|
||||
]"
|
||||
@click="toggle"
|
||||
>
|
||||
<div class="font-medium text-gray-900 dark:text-white flex-1">
|
||||
<slot name="title">
|
||||
{{ title }}
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
<IonIcon
|
||||
:icon="chevronDownOutline"
|
||||
class="text-gray-500 dark:text-gray-400 transition-transform duration-300"
|
||||
:class="[
|
||||
{
|
||||
'w-4 h-4': size === 'small',
|
||||
'w-5 h-5': size === 'medium',
|
||||
'w-6 h-6': size === 'large',
|
||||
},
|
||||
{
|
||||
'rotate-180': active,
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<div
|
||||
ref="contentRef"
|
||||
class="overflow-hidden transition-all duration-300 ease-in-out"
|
||||
:style="{ height: active ? 'auto' : '0' }"
|
||||
@transitionend="onTransitionEnd"
|
||||
>
|
||||
<div
|
||||
class="p-4 text-gray-600 dark:text-gray-300 space-y-5"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang='css' scoped>
|
||||
.select-none {
|
||||
user-select: none;
|
||||
}
|
||||
</style>
|
||||
29
src/components/ui/collapse/types.ts
Normal file
29
src/components/ui/collapse/types.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
export interface CollapseProps {
|
||||
/** 面板标题 */
|
||||
title?: string;
|
||||
/** 是否禁用 */
|
||||
disabled?: boolean;
|
||||
/** 是否显示边框 */
|
||||
bordered?: boolean;
|
||||
/** 尺寸大小 */
|
||||
size?: "small" | "medium" | "large";
|
||||
/** 是否展开 (v-model:active) */
|
||||
active?: boolean;
|
||||
}
|
||||
|
||||
export interface CollapseEmits {
|
||||
/** 展开状态变化时触发 */
|
||||
"update:active": [value: boolean];
|
||||
}
|
||||
|
||||
export interface CollapseSlots {
|
||||
/** 默认插槽 - 面板内容 */
|
||||
default: () => any;
|
||||
/** 标题插槽 - 自定义标题内容 */
|
||||
title: () => any;
|
||||
}
|
||||
|
||||
export interface CollapseInstance {
|
||||
/** 切换展开/收起状态 */
|
||||
toggle: () => void;
|
||||
}
|
||||
39
src/components/ui/datetime/index.vue
Normal file
39
src/components/ui/datetime/index.vue
Normal file
@@ -0,0 +1,39 @@
|
||||
<script lang='ts' setup>
|
||||
import type { FieldBindingObject } from "vee-validate";
|
||||
|
||||
interface Props extends FieldBindingObject {
|
||||
label?: string;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
function handleChange(value: string) {
|
||||
const formattedValue = useDateFormat(value, "YYYY/MM/DD").value;
|
||||
props.onChange(formattedValue);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col items-start">
|
||||
<ion-label class="text-sm font-bold color-(--ion-text-color-secondary) mb-3.5">
|
||||
{{ props.label }}
|
||||
</ion-label>
|
||||
<ion-datetime-button datetime="datetime" color="primary">
|
||||
<div slot="date-target">
|
||||
{{ props.value }}
|
||||
</div>
|
||||
</ion-datetime-button>
|
||||
<ion-modal :keep-contents-mounted="true">
|
||||
<ion-datetime
|
||||
id="datetime"
|
||||
class="ui-datetime"
|
||||
done-text="Done"
|
||||
presentation="date"
|
||||
:show-default-buttons="true"
|
||||
@ion-change="handleChange($event.detail.value as string)"
|
||||
/>
|
||||
</ion-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang='css' scoped></style>
|
||||
@@ -1,9 +0,0 @@
|
||||
<script lang='ts' setup>
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
hello world
|
||||
</template>
|
||||
|
||||
<style lang='css' scoped></style>
|
||||
22
src/components/ui/result/index.vue
Normal file
22
src/components/ui/result/index.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<script lang='ts' setup>
|
||||
defineProps<{
|
||||
icon?: string;
|
||||
title?: string;
|
||||
description?: string;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex-col-center space-y-3">
|
||||
<ion-icon :icon="icon" class="text-5xl text-lime-500" />
|
||||
<div class="text-xl font-semibold">
|
||||
{{ title }}
|
||||
</div>
|
||||
<p class="text-center text-text-400 max-w-xs">
|
||||
{{ description }}
|
||||
</p>
|
||||
<slot name="extra" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang='css' scoped></style>
|
||||
Reference in New Issue
Block a user