Skip to content
This repository has been archived by the owner on Feb 24, 2024. It is now read-only.

Commit

Permalink
feat: single array edit component
Browse files Browse the repository at this point in the history
  • Loading branch information
neko-para committed Aug 2, 2023
1 parent 2f57bc8 commit b132d9b
Show file tree
Hide file tree
Showing 14 changed files with 1,122 additions and 148 deletions.
66 changes: 34 additions & 32 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { computed, ref } from 'vue'
import { NButton, NTree, NCard, NInput, NModal } from 'naive-ui'
import { taskData, taskTree } from './data'
import TaskEdit from './TaskEdit.vue'
const showEdit = ref(false)
const cacheEdit = ref('')
Expand Down Expand Up @@ -79,38 +80,39 @@ const active = computed(() => {
</NCard>
</NModal>

<div>
<NButton @click="popupEdit">编辑</NButton>
{{ active }}
</div>
<div class="flex gap-2 flex-1 min-h-0">
<NCard class="max-w-xs min-h-0" content-style="max-height: 100%">
<div class="flex flex-col gap-2 max-h-full items-stretch">
<div class="flex items-center gap-2">
<span class="whitespace-nowrap">搜索</span>
<NInput v-model:value="searchText" placeholder="task"></NInput>
<div class="flex flex-col gap-2 flex-1 min-h-0">
<div>
<NButton @click="popupEdit">编辑</NButton>
{{ active }}
</div>
<div class="flex gap-2 flex-1 min-h-0">
<NCard class="max-w-xs min-h-0" content-style="max-height: 100%">
<div class="flex flex-col gap-2 max-h-full items-stretch">
<div class="flex items-center gap-2">
<span class="whitespace-nowrap">搜索</span>
<NInput v-model:value="searchText" placeholder="task"></NInput>
</div>
<!-- {{ taskTree }} -->
<NTree
class="overflow-y-auto"
:data="taskTree"
v-model:selected-keys="selectedKeysFilter"
block-line
selectable
expand-on-click
accordion
default-expand-all
:pattern="searchText"
:show-irrelevant-nodes="false"
:cancelable="false"
></NTree>
</div>
<!-- {{ taskTree }} -->
<NTree
class=""
:data="taskTree"
v-model:selected-keys="selectedKeysFilter"
block-line
selectable
expand-on-click
accordion
default-expand-all
:pattern="searchText"
:show-irrelevant-nodes="false"
:cancelable="false"
virtual-scroll
></NTree>
</div>
</NCard>
<NCard>
<div v-if="active">
{{ taskData.data[active] }}
</div>
</NCard>
</NCard>
<NCard>
<div v-if="active">
<TaskEdit v-model:value="taskData.data[active]"></TaskEdit>
</div>
</NCard>
</div>
</div>
</template>
88 changes: 88 additions & 0 deletions src/TaskEdit.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<script setup lang="ts">
import { NButton, NCard, NSelect, NCode, NInput, NDivider } from 'naive-ui'
import type { Task, Rect } from './types'
import { computed, type Ref } from 'vue'
import ClearButton from '@/components/ClearButton.vue'
import SingleArrayEdit from './components/SingleArrayEdit.vue'
import FloatInput from '@/components/FloatInput.vue'
import RectEdit from '@/components/RectEdit.vue'
import TemplateEdit from './components/TemplateEdit.vue'
const task = defineModel<Task>('value', {
required: true
})
type RemUndefined<T> = T extends undefined ? never : T
function wrapProp<T extends Record<string, unknown>, K extends string>(
obj: Ref<T>,
key: K
) {
return computed<RemUndefined<T[K]> | null>({
set(v: RemUndefined<T[K]> | null) {
if (v === null) {
if (key in obj.value) {
delete obj.value[key]
}
} else {
obj.value[key] = v
}
},
get(): RemUndefined<T[K]> | null {
return (obj.value[key] ?? null) as RemUndefined<T[K]> | null
}
})
}
const recoOptions = ['DirectHit', 'TemplateMatch', 'OCR', 'Custom'].map(x => ({
label: x,
value: x
}))
const taskReco = wrapProp(task, 'recognition')
const taskRecoValue = computed(() => taskReco.value ?? 'DirectHit')
const taskRoi = wrapProp(task, 'roi')
const taskTemplate = wrapProp(task, 'template')
const taskThreshold = wrapProp(task, 'threshold')
</script>

<template>
<NCard>
<div class="flex flex-col gap-2">
<div
class="grid gap-2 items-center"
style="grid-template-columns: max-content minmax(0, 1fr)"
>
<ClearButton v-model="taskReco"> 识别 </ClearButton>
<NSelect
v-model:value="taskReco"
:options="recoOptions"
:placeholder="recoOptions[0].label"
></NSelect>
<template v-if="taskRecoValue !== 'Custom'">
<ClearButton v-model="taskRoi"> 区域 </ClearButton>
<SingleArrayEdit
v-model:value="taskRoi"
:def="() => [0, 0, 0, 0] as Rect"
:is-t="
v =>
v instanceof Array && v.length === 4 && typeof v[0] === 'number'
"
>
<template #edit="{ value, update }">
<RectEdit :value="value" @update:value="update"></RectEdit>
</template>
</SingleArrayEdit>
</template>
<TemplateEdit
v-if="taskRecoValue === 'TemplateMatch'"
v-model:template="taskTemplate"
v-model:threshold="taskThreshold"
></TemplateEdit>
</div>
<NCode language="json" :code="JSON.stringify(task, null, 2)"></NCode>
</div>
</NCard>
</template>
9 changes: 8 additions & 1 deletion src/Wrapper.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
<script setup lang="ts">
import { NConfigProvider } from 'naive-ui'
import App from './App.vue'
import hljs from 'highlight.js/lib/core'
import hljs_json from 'highlight.js/lib/languages/json'
hljs.registerLanguage('json', hljs_json)
</script>

<template>
<Suspense>
<template #default>
<App></App>
<NConfigProvider :hljs="hljs" class="flex flex-col flex-1 min-h-0">
<App></App>
</NConfigProvider>
</template>
<template #fallback> loading... </template>
</Suspense>
Expand Down
26 changes: 26 additions & 0 deletions src/components/ClearButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<script setup lang="ts" generic="T">
import { NButton } from 'naive-ui'
withDefaults(
defineProps<{
invalid?: boolean
}>(),
{
invalid: false
}
)
const val = defineModel<T | null>({
required: true
})
</script>

<template>
<NButton
secondary
@click="invalid || (val = null)"
:type="val === null ? 'default' : 'primary'"
>
<slot></slot>
</NButton>
</template>
51 changes: 51 additions & 0 deletions src/components/FloatInput.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<script setup lang="ts">
import { NInput } from 'naive-ui'
import { computed, ref } from 'vue'
const props = defineProps<{
nullable: boolean
def: number
alter: (v: number) => number
}>()
const val = defineModel<number | null>('value', {
required: true
})
function nullVal() {
return props.nullable ? null : props.def
}
const cacheStr = ref<string | null>(val.value === null ? null : `${val.value}`)
const strVal = computed<string | null>({
set(v: string | null) {
cacheStr.value = v
if (!v || v === '') {
val.value = nullVal()
} else {
const nv = parseFloat(v)
if (isNaN(nv)) {
val.value = nullVal()
} else {
const anv = props.alter(nv)
val.value = anv
if (anv !== nv) {
cacheStr.value = `${anv}`
}
}
}
},
get() {
return val.value === null ? null : cacheStr.value
}
})
</script>

<template>
<NInput v-model:value="strVal" :placeholder="`${def}`">
<template #prefix>
<slot></slot>
</template>
</NInput>
</template>
30 changes: 30 additions & 0 deletions src/components/IntInput.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<script setup lang="ts">
import { NInput } from 'naive-ui'
import { computed } from 'vue'
const val = defineModel<number>('value', {
required: true
})
const strVal = computed({
set(v: string | null) {
v = v ?? '0'
if (v === '') {
v = '0'
}
if (/^(?:[0-9]+)$/.test(v)) {
val.value = parseInt(v)
}
},
get() {
return `${val.value}`
}
})
</script>

<template>
<NInput v-model:value="strVal">
<template #prefix>
<slot></slot>
</template>
</NInput>
</template>
24 changes: 24 additions & 0 deletions src/components/RectEdit.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script setup lang="ts">
import type { Rect } from '@/types'
import IntInput from './IntInput.vue'
const rect = defineModel<Rect>('value', {
required: true
})
const prefixs = ['X:', 'Y:', 'W:', 'H:']
</script>

<template>
<div class="flex gap-2">
<IntInput
v-for="i in 4"
:key="i"
:value="rect[i - 1]"
@update:value="(v: number) => {
rect[i - 1] = v
}"
>
{{ prefixs[i - 1] }}
</IntInput>
</div>
</template>
21 changes: 21 additions & 0 deletions src/components/SingleArrayButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<script setup lang="ts">
import { NButton } from 'naive-ui'
defineProps<{
disabled?: boolean
}>()
const single = defineModel<boolean>('value', {
required: true
})
</script>

<template>
<NButton
:type="single ? 'default' : 'primary'"
:disabled="disabled"
@click="single = !single"
>
{{ single ? '单个' : '多个' }}
</NButton>
</template>
Loading

0 comments on commit b132d9b

Please sign in to comment.