mirror of
https://github.com/fantastic-admin/basic.git
synced 2026-10-07 11:34:10 +08:00
用 defineModel 重构部分组件
This commit is contained in:
@@ -12,7 +12,6 @@ const props = withDefaults(
|
||||
headers?: UploadProps['headers']
|
||||
data?: UploadProps['data']
|
||||
name?: UploadProps['name']
|
||||
url?: string
|
||||
size?: number
|
||||
width?: number
|
||||
height?: number
|
||||
@@ -22,7 +21,6 @@ const props = withDefaults(
|
||||
}>(),
|
||||
{
|
||||
name: 'file',
|
||||
url: '',
|
||||
size: 2,
|
||||
width: 150,
|
||||
height: 150,
|
||||
@@ -33,14 +31,15 @@ const props = withDefaults(
|
||||
)
|
||||
|
||||
const emits = defineEmits<{
|
||||
'update:url': [
|
||||
url: string,
|
||||
]
|
||||
'onSuccess': [
|
||||
res: any,
|
||||
]
|
||||
}>()
|
||||
|
||||
const url = defineModel<string>({
|
||||
default: '',
|
||||
})
|
||||
|
||||
const uploadData = ref({
|
||||
imageViewerVisible: false,
|
||||
progress: {
|
||||
@@ -59,7 +58,7 @@ function previewClose() {
|
||||
}
|
||||
// 移除
|
||||
function remove() {
|
||||
emits('update:url', '')
|
||||
url.value = ''
|
||||
}
|
||||
const beforeUpload: UploadProps['beforeUpload'] = (file) => {
|
||||
const fileName = file.name.split('.')
|
||||
|
||||
@@ -12,7 +12,6 @@ const props = withDefaults(
|
||||
headers?: UploadProps['headers']
|
||||
data?: UploadProps['data']
|
||||
name?: UploadProps['name']
|
||||
url?: string[]
|
||||
size?: number
|
||||
max?: number
|
||||
width?: number
|
||||
@@ -23,7 +22,6 @@ const props = withDefaults(
|
||||
}>(),
|
||||
{
|
||||
name: 'file',
|
||||
url: () => [],
|
||||
size: 2,
|
||||
max: 3,
|
||||
width: 150,
|
||||
@@ -35,14 +33,15 @@ const props = withDefaults(
|
||||
)
|
||||
|
||||
const emits = defineEmits<{
|
||||
'update:url': [
|
||||
url: string[],
|
||||
]
|
||||
'onSuccess': [
|
||||
res: any,
|
||||
]
|
||||
}>()
|
||||
|
||||
const url = defineModel<string[]>({
|
||||
default: [],
|
||||
})
|
||||
|
||||
const uploadData = ref({
|
||||
dialogImageIndex: 0,
|
||||
imageViewerVisible: false,
|
||||
@@ -63,20 +62,16 @@ function previewClose() {
|
||||
}
|
||||
// 移除
|
||||
function remove(index: number) {
|
||||
const url = props.url
|
||||
url.splice(index, 1)
|
||||
emits('update:url', url)
|
||||
url.value.splice(index, 1)
|
||||
}
|
||||
// 移动
|
||||
function move(index: number, type: 'left' | 'right') {
|
||||
const url = props.url
|
||||
if (type === 'left' && index !== 0) {
|
||||
url[index] = url.splice(index - 1, 1, url[index])[0]
|
||||
url.value[index] = url.value.splice(index - 1, 1, url.value[index])[0]
|
||||
}
|
||||
if (type === 'right' && index !== url.length - 1) {
|
||||
url[index] = url.splice(index + 1, 1, url[index])[0]
|
||||
if (type === 'right' && index !== url.value.length - 1) {
|
||||
url.value[index] = url.value.splice(index + 1, 1, url.value[index])[0]
|
||||
}
|
||||
emits('update:url', url)
|
||||
}
|
||||
|
||||
const beforeUpload: UploadProps['beforeUpload'] = (file) => {
|
||||
|
||||
@@ -8,10 +8,6 @@ defineOptions({
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
modelValue: string[] | {
|
||||
code: string
|
||||
name: string
|
||||
}[]
|
||||
disabled?: boolean
|
||||
type?: 'pc' | 'pca' | 'pcas'
|
||||
format?: 'code' | 'name' | 'both'
|
||||
@@ -23,14 +19,12 @@ const props = withDefaults(
|
||||
},
|
||||
)
|
||||
|
||||
const emits = defineEmits<{
|
||||
'update:modelValue': [
|
||||
value: string[] | {
|
||||
code: string
|
||||
name: string
|
||||
}[],
|
||||
]
|
||||
}>()
|
||||
const value = defineModel<string[] | {
|
||||
code: string
|
||||
name: string
|
||||
}[]>({
|
||||
default: [],
|
||||
})
|
||||
|
||||
interface pcasItem {
|
||||
code: string
|
||||
@@ -88,11 +82,11 @@ const pcasData = computed(() => {
|
||||
const myValue = computed({
|
||||
// 将入参数据转成 code 码
|
||||
get: () => {
|
||||
return anyToCode(props.modelValue)
|
||||
return anyToCode(value.value)
|
||||
},
|
||||
// 将 code 码转成出参数据
|
||||
set: (value) => {
|
||||
emits('update:modelValue', value ? codeToAny(value) : [])
|
||||
set: (val) => {
|
||||
value.value = val ? codeToAny(val) : []
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -3,38 +3,30 @@ defineOptions({
|
||||
name: 'SearchBar',
|
||||
})
|
||||
|
||||
const props = withDefaults(
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
fold?: boolean
|
||||
showToggle?: boolean
|
||||
background?: boolean
|
||||
}>(),
|
||||
{
|
||||
fold: true,
|
||||
showToggle: true,
|
||||
background: false,
|
||||
},
|
||||
)
|
||||
|
||||
const emits = defineEmits<{
|
||||
'update:fold': [
|
||||
value: boolean,
|
||||
]
|
||||
'toggle': [
|
||||
value: boolean,
|
||||
]
|
||||
}>()
|
||||
|
||||
const isFold = ref(props.fold)
|
||||
|
||||
watch(() => props.fold, (value) => {
|
||||
isFold.value = value
|
||||
emits('update:fold', value)
|
||||
const fold = defineModel<boolean>('fold', {
|
||||
default: true,
|
||||
})
|
||||
|
||||
function toggle() {
|
||||
isFold.value = !isFold.value
|
||||
emits('toggle', isFold.value)
|
||||
fold.value = !fold.value
|
||||
emits('toggle', fold.value)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -45,10 +37,10 @@ function toggle() {
|
||||
'px-4 bg-[var(--g-bg)] transition': background,
|
||||
}"
|
||||
>
|
||||
<slot :fold="isFold" />
|
||||
<slot :fold="fold" :toggle="toggle" />
|
||||
<div v-if="showToggle" class="absolute bottom-0 left-0 w-full translate-y-1/2 text-center">
|
||||
<button class="h-5 inline-flex cursor-pointer select-none items-center border-size-0 rounded bg-[var(--g-bg)] px-2 text-xs font-medium outline-none" @click="toggle">
|
||||
<SvgIcon :name="isFold ? 'ep:caret-bottom' : 'ep:caret-top' " />
|
||||
<SvgIcon :name="fold ? 'ep:caret-bottom' : 'ep:caret-top' " />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
const props = withDefaults(
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
modelValue: string | number | undefined
|
||||
options: {
|
||||
label?: string | number
|
||||
icon?: string
|
||||
@@ -16,18 +15,19 @@ const props = withDefaults(
|
||||
)
|
||||
|
||||
const emits = defineEmits<{
|
||||
'update:modelValue': [string | number]
|
||||
'change': [string | number | undefined]
|
||||
}>()
|
||||
|
||||
watch(() => props.modelValue, (val) => {
|
||||
const value = defineModel<string | number>()
|
||||
|
||||
watch(value, (val) => {
|
||||
emits('change', val)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="inline-flex select-none items-center justify-center of-hidden rounded-md bg-stone-3 dark:bg-stone-7">
|
||||
<button v-for="option in options" :key="option.value" :disabled="disabled || option.disabled" class="flex cursor-pointer items-center truncate border-size-0 bg-inherit px-2 py-1.5 text-sm disabled:cursor-not-allowed disabled:opacity-50 hover:not-disabled:(bg-ui-primary text-ui-text)" :class="{ 'text-ui-text bg-ui-primary': modelValue === option.value }" @click="emits('update:modelValue', option.value)">
|
||||
<button v-for="option in options" :key="option.value" :disabled="disabled || option.disabled" class="flex cursor-pointer items-center truncate border-size-0 bg-inherit px-2 py-1.5 text-sm disabled:cursor-not-allowed disabled:opacity-50 hover:not-disabled:(bg-ui-primary text-ui-text)" :class="{ 'text-ui-text bg-ui-primary': value === option.value }" @click="value = option.value">
|
||||
<SvgIcon v-if="option.icon" :name="option.icon" />
|
||||
<template v-else>
|
||||
{{ option.label }}
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import { Dialog, DialogDescription, DialogPanel, DialogTitle, TransitionChild, TransitionRoot } from '@headlessui/vue'
|
||||
|
||||
const props = withDefaults(
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
modelValue: boolean
|
||||
appear?: boolean
|
||||
title?: string
|
||||
preventClose?: boolean
|
||||
overlay?: boolean
|
||||
}>(),
|
||||
{
|
||||
modelValue: false,
|
||||
appear: false,
|
||||
preventClose: false,
|
||||
overlay: false,
|
||||
@@ -18,10 +16,13 @@ const props = withDefaults(
|
||||
)
|
||||
|
||||
const emits = defineEmits<{
|
||||
'update:modelValue': [boolean]
|
||||
'close': []
|
||||
}>()
|
||||
|
||||
const isOpen = defineModel<boolean>({
|
||||
default: false,
|
||||
})
|
||||
|
||||
const slots = useSlots()
|
||||
|
||||
const overlayTransitionClass = ref({
|
||||
@@ -44,15 +45,6 @@ const transitionClass = computed(() => {
|
||||
}
|
||||
})
|
||||
|
||||
const isOpen = computed({
|
||||
get() {
|
||||
return props.modelValue
|
||||
},
|
||||
set(value) {
|
||||
emits('update:modelValue', value)
|
||||
},
|
||||
})
|
||||
|
||||
function close() {
|
||||
isOpen.value = false
|
||||
emits('close')
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
<script setup lang="ts" generic="T extends string | number">
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
modelValue: string
|
||||
placeholder?: string
|
||||
disabled?: boolean
|
||||
}>(),
|
||||
@@ -10,16 +9,10 @@ withDefaults(
|
||||
},
|
||||
)
|
||||
|
||||
const emits = defineEmits<{
|
||||
'update:modelValue': [string]
|
||||
}>()
|
||||
const value = defineModel<T>()
|
||||
|
||||
const inputRef = ref()
|
||||
|
||||
function handleInput(event: Event) {
|
||||
emits('update:modelValue', (event.target as HTMLInputElement).value)
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
ref: inputRef,
|
||||
})
|
||||
@@ -27,6 +20,6 @@ defineExpose({
|
||||
|
||||
<template>
|
||||
<div class="relative w-full lg:w-48">
|
||||
<input ref="inputRef" type="text" :value="modelValue" :placeholder="placeholder" :disabled="disabled" class="relative block w-full border-0 rounded-md bg-white px-2.5 py-1.5 text-sm shadow-sm ring-1 ring-stone-2 ring-inset disabled:cursor-not-allowed dark:bg-dark disabled:opacity-50 focus:outline-none focus:ring-2 dark:ring-stone-8 focus:ring-ui-primary placeholder-stone-4 dark:placeholder-stone-5" @input="handleInput">
|
||||
<input v-model="value" type="text" :placeholder="placeholder" :disabled="disabled" class="relative block w-full border-0 rounded-md bg-white px-2.5 py-1.5 text-sm shadow-sm ring-1 ring-stone-2 ring-inset disabled:cursor-not-allowed dark:bg-dark disabled:opacity-50 focus:outline-none focus:ring-2 dark:ring-stone-8 focus:ring-ui-primary placeholder-stone-4 dark:placeholder-stone-5">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
modelValue: string | number | undefined
|
||||
options: {
|
||||
label: string | number
|
||||
value: string | number
|
||||
@@ -14,16 +13,14 @@ const props = withDefaults(
|
||||
},
|
||||
)
|
||||
|
||||
const emits = defineEmits<{
|
||||
'update:modelValue': [string | number]
|
||||
}>()
|
||||
const value = defineModel<string | number>()
|
||||
|
||||
const selected = computed({
|
||||
get() {
|
||||
return props.options.find(option => option.value === props.modelValue) ?? props.options[0]
|
||||
return props.options.find(option => option.value === value.value) ?? props.options[0]
|
||||
},
|
||||
set(val) {
|
||||
emits('update:modelValue', val.value)
|
||||
value.value = val.value
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -4,7 +4,6 @@ import { OverlayScrollbarsComponent } from 'overlayscrollbars-vue'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
modelValue: boolean
|
||||
appear?: boolean
|
||||
side?: 'left' | 'right'
|
||||
title?: string
|
||||
@@ -12,7 +11,6 @@ const props = withDefaults(
|
||||
overlay?: boolean
|
||||
}>(),
|
||||
{
|
||||
modelValue: false,
|
||||
appear: false,
|
||||
side: 'right',
|
||||
preventClose: false,
|
||||
@@ -21,10 +19,13 @@ const props = withDefaults(
|
||||
)
|
||||
|
||||
const emits = defineEmits<{
|
||||
'update:modelValue': [boolean]
|
||||
'close': []
|
||||
}>()
|
||||
|
||||
const isOpen = defineModel<boolean>({
|
||||
default: false,
|
||||
})
|
||||
|
||||
const slots = useSlots()
|
||||
|
||||
const overlayTransitionClass = ref({
|
||||
@@ -47,15 +48,6 @@ const transitionClass = computed(() => {
|
||||
}
|
||||
})
|
||||
|
||||
const isOpen = computed({
|
||||
get() {
|
||||
return props.modelValue
|
||||
},
|
||||
set(value) {
|
||||
emits('update:modelValue', value)
|
||||
},
|
||||
})
|
||||
|
||||
function close() {
|
||||
isOpen.value = false
|
||||
emits('close')
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import { Tab, TabGroup, TabList } from '@headlessui/vue'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: T
|
||||
options: {
|
||||
label: any
|
||||
value: T
|
||||
@@ -10,25 +9,26 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const emits = defineEmits<{
|
||||
'update:modelValue': [T]
|
||||
'change': [T]
|
||||
}>()
|
||||
|
||||
const value = defineModel<T>()
|
||||
|
||||
const selectedIndex = computed({
|
||||
get() {
|
||||
return props.options.findIndex(option => option.value === props.modelValue)
|
||||
return props.options.findIndex(option => option.value === value.value)
|
||||
},
|
||||
set(val) {
|
||||
emits('update:modelValue', props.options[val].value)
|
||||
value.value = props.options[val].value
|
||||
},
|
||||
})
|
||||
|
||||
watch(() => props.modelValue, (val) => {
|
||||
emits('change', val)
|
||||
watch(value, (val) => {
|
||||
val && emits('change', val)
|
||||
})
|
||||
|
||||
function handleChange(index: number) {
|
||||
emits('update:modelValue', props.options[index].value)
|
||||
value.value = props.options[index].value
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { Switch } from '@headlessui/vue'
|
||||
|
||||
const props = withDefaults(
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
modelValue?: boolean
|
||||
disabled?: boolean
|
||||
onIcon?: string
|
||||
offIcon?: string
|
||||
@@ -13,18 +12,7 @@ const props = withDefaults(
|
||||
},
|
||||
)
|
||||
|
||||
const emits = defineEmits<{
|
||||
'update:modelValue': [boolean]
|
||||
}>()
|
||||
|
||||
const enabled = computed({
|
||||
get() {
|
||||
return props.modelValue
|
||||
},
|
||||
set(value) {
|
||||
emits('update:modelValue', value)
|
||||
},
|
||||
})
|
||||
const enabled = defineModel<boolean>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -19,11 +19,7 @@ const search = ref({
|
||||
check2: false,
|
||||
})
|
||||
|
||||
const isFold = ref(false)
|
||||
const isFold2 = ref(true)
|
||||
const isFold3 = ref(true)
|
||||
|
||||
function toggle(fold: boolean) {
|
||||
function onToggle(fold: boolean) {
|
||||
ElMessage({
|
||||
message: fold ? '收起' : '展开',
|
||||
})
|
||||
@@ -101,7 +97,7 @@ function toggle(fold: boolean) {
|
||||
</SearchBar>
|
||||
</PageMain>
|
||||
<PageMain title="默认展开">
|
||||
<SearchBar :fold="isFold">
|
||||
<SearchBar :fold="false">
|
||||
<template #default="{ fold }">
|
||||
<ElForm :model="search" size="default" label-width="120px">
|
||||
<ElRow>
|
||||
@@ -235,7 +231,7 @@ function toggle(fold: boolean) {
|
||||
</SearchBar>
|
||||
</PageMain>
|
||||
<PageMain title="切换事件">
|
||||
<SearchBar @toggle="toggle">
|
||||
<SearchBar @toggle="onToggle">
|
||||
<template #default="{ fold }">
|
||||
<ElForm :model="search" size="default" label-width="120px">
|
||||
<ElRow>
|
||||
@@ -302,8 +298,8 @@ function toggle(fold: boolean) {
|
||||
</SearchBar>
|
||||
</PageMain>
|
||||
<PageMain title="自定义切换按钮(搭配自定义 grid 布局)">
|
||||
<SearchBar :fold="isFold2" :show-toggle="false">
|
||||
<template #default="{ fold }">
|
||||
<SearchBar :show-toggle="false">
|
||||
<template #default="{ fold, toggle }">
|
||||
<ElForm :model="search" size="default" label-width="120px" inline class="search-form">
|
||||
<ElFormItem label="姓名 / 手机号" class="search-form-item-name">
|
||||
<ElInput v-model="search.name" placeholder="请输入姓名或者手机号,支持模糊查询" clearable />
|
||||
@@ -343,7 +339,7 @@ function toggle(fold: boolean) {
|
||||
</template>
|
||||
筛选
|
||||
</ElButton>
|
||||
<ElButton link @click="isFold2 = !fold">
|
||||
<ElButton link @click="toggle">
|
||||
<template #icon>
|
||||
<SvgIcon :name="fold ? 'ep:caret-bottom' : 'ep:caret-top' " />
|
||||
</template>
|
||||
@@ -355,8 +351,8 @@ function toggle(fold: boolean) {
|
||||
</SearchBar>
|
||||
</PageMain>
|
||||
<PageMain title="自定义切换按钮(搭配 el-row 组件)">
|
||||
<SearchBar :fold="isFold3" :show-toggle="false">
|
||||
<template #default="{ fold }">
|
||||
<SearchBar :show-toggle="false">
|
||||
<template #default="{ fold, toggle }">
|
||||
<ElForm :model="search" size="default" label-width="120px">
|
||||
<ElRow>
|
||||
<ElCol :span="12">
|
||||
@@ -408,7 +404,7 @@ function toggle(fold: boolean) {
|
||||
</template>
|
||||
筛选
|
||||
</ElButton>
|
||||
<ElButton link @click="isFold3 = !fold">
|
||||
<ElButton link @click="toggle">
|
||||
<template #icon>
|
||||
<SvgIcon :name="fold ? 'ep:caret-bottom' : 'ep:caret-top' " />
|
||||
</template>
|
||||
|
||||
@@ -99,10 +99,10 @@ const tableData = [
|
||||
</template>
|
||||
</PageHeader>
|
||||
<PageMain title="单图上传">
|
||||
<ImageUpload v-model:url="image" action="https://console-mock.apipost.cn/app/mock/project/1f50f1da-5189-4282-d3c7-c133a514c5a8/upload/image" name="image" :width="250" :height="150" @on-success="handleSuccess1" />
|
||||
<ImageUpload v-model="image" action="https://console-mock.apipost.cn/app/mock/project/1f50f1da-5189-4282-d3c7-c133a514c5a8/upload/image" name="image" :width="250" :height="150" @on-success="handleSuccess1" />
|
||||
</PageMain>
|
||||
<PageMain title="多图上传(默认最多3张)">
|
||||
<ImagesUpload v-model:url="images" action="https://console-mock.apipost.cn/app/mock/project/1f50f1da-5189-4282-d3c7-c133a514c5a8/upload/image" name="image" @on-success="handleSuccess2" />
|
||||
<ImagesUpload v-model="images" action="https://console-mock.apipost.cn/app/mock/project/1f50f1da-5189-4282-d3c7-c133a514c5a8/upload/image" name="image" @on-success="handleSuccess2" />
|
||||
</PageMain>
|
||||
<PageMain title="文件上传(默认最多3个)">
|
||||
<FileUpload :files="files" action="https://console-mock.apipost.cn/app/mock/project/1f50f1da-5189-4282-d3c7-c133a514c5a8/upload/file" @on-success="handleSuccess3" />
|
||||
|
||||
Reference in New Issue
Block a user