|
@@ -1,13 +1,13 @@
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
import type Curd from '@/api/curd'
|
|
import type Curd from '@/api/curd'
|
|
import type { Column } from '@/components/StdDesign/types'
|
|
import type { Column } from '@/components/StdDesign/types'
|
|
-import type { Ref } from 'vue'
|
|
|
|
import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
|
|
import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
|
|
|
|
+import { watchOnce } from '@vueuse/core'
|
|
import _ from 'lodash'
|
|
import _ from 'lodash'
|
|
|
|
|
|
const props = defineProps<{
|
|
const props = defineProps<{
|
|
|
|
+ placeholder?: string
|
|
label?: string
|
|
label?: string
|
|
- selectedKey: number | number[] | undefined | null
|
|
|
|
selectionType: 'radio' | 'checkbox'
|
|
selectionType: 'radio' | 'checkbox'
|
|
recordValueIndex: string // to index the value of the record
|
|
recordValueIndex: string // to index the value of the record
|
|
// eslint-disable-next-line ts/no-explicit-any
|
|
// eslint-disable-next-line ts/no-explicit-any
|
|
@@ -24,9 +24,19 @@ const props = defineProps<{
|
|
disabled?: boolean
|
|
disabled?: boolean
|
|
// eslint-disable-next-line ts/no-explicit-any
|
|
// eslint-disable-next-line ts/no-explicit-any
|
|
valueApi?: Curd<any>
|
|
valueApi?: Curd<any>
|
|
|
|
+ // eslint-disable-next-line ts/no-explicit-any
|
|
|
|
+ getCheckboxProps?: (record: any) => any
|
|
|
|
+ hideInputContainer?: boolean
|
|
}>()
|
|
}>()
|
|
|
|
|
|
-const emit = defineEmits(['update:selectedKey'])
|
|
|
|
|
|
+const selectedKey = defineModel<number | number[] | undefined | null | string | string[]>('selectedKey')
|
|
|
|
+
|
|
|
|
+onMounted(() => {
|
|
|
|
+ if (!selectedKey.value)
|
|
|
|
+ watchOnce(selectedKey, _init)
|
|
|
|
+ else
|
|
|
|
+ _init()
|
|
|
|
+})
|
|
|
|
|
|
const getParams = computed(() => {
|
|
const getParams = computed(() => {
|
|
return props.getParams
|
|
return props.getParams
|
|
@@ -34,19 +44,23 @@ const getParams = computed(() => {
|
|
|
|
|
|
const visible = ref(false)
|
|
const visible = ref(false)
|
|
// eslint-disable-next-line ts/no-explicit-any
|
|
// eslint-disable-next-line ts/no-explicit-any
|
|
-const M_values = ref([]) as any
|
|
|
|
|
|
+const M_values = ref([]) as Ref<any[]>
|
|
|
|
|
|
-const init = _.debounce(_init, 500, {
|
|
|
|
- leading: true,
|
|
|
|
- trailing: false,
|
|
|
|
|
|
+const ComputedMValue = computed(() => {
|
|
|
|
+ return M_values.value.filter(v => v && Object.keys(v).length > 0)
|
|
})
|
|
})
|
|
|
|
|
|
-onMounted(() => {
|
|
|
|
- init()
|
|
|
|
|
|
+// eslint-disable-next-line ts/no-explicit-any
|
|
|
|
+const records = defineModel<any[]>('selectedRecords', {
|
|
|
|
+ default: () => [],
|
|
})
|
|
})
|
|
|
|
|
|
-// eslint-disable-next-line ts/no-explicit-any
|
|
|
|
-const records = ref([]) as Ref<any[]>
|
|
|
|
|
|
+watch(() => props.value, () => {
|
|
|
|
+ if (props.selectionType === 'radio')
|
|
|
|
+ M_values.value = [props.value]
|
|
|
|
+ else if (typeof selectedKey.value === 'object')
|
|
|
|
+ M_values.value = props.value || []
|
|
|
|
+})
|
|
|
|
|
|
async function _init() {
|
|
async function _init() {
|
|
// valueApi is used to fetch items that are using itemKey as index value
|
|
// valueApi is used to fetch items that are using itemKey as index value
|
|
@@ -55,22 +69,22 @@ async function _init() {
|
|
M_values.value = []
|
|
M_values.value = []
|
|
|
|
|
|
if (props.selectionType === 'radio') {
|
|
if (props.selectionType === 'radio') {
|
|
- // M_values.value = [props.value] // not init value, we need to fetch them from api
|
|
|
|
- if (!props.value && props.selectedKey) {
|
|
|
|
- api.get(props.selectedKey, props.getParams).then(r => {
|
|
|
|
|
|
+ // M_values.value = [props.value]
|
|
|
|
+ // not init value, we need to fetch them from api
|
|
|
|
+ if (!props.value && selectedKey.value && selectedKey.value !== '0') {
|
|
|
|
+ api.get(selectedKey.value, props.getParams).then(r => {
|
|
M_values.value = [r]
|
|
M_values.value = [r]
|
|
records.value = [r]
|
|
records.value = [r]
|
|
})
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- else if (typeof props.selectedKey === 'object') {
|
|
|
|
- M_values.value = props.value || []
|
|
|
|
-
|
|
|
|
|
|
+ else if (typeof selectedKey.value === 'object') {
|
|
|
|
+ // M_values.value = props.value || []
|
|
// not init value, we need to fetch them from api
|
|
// not init value, we need to fetch them from api
|
|
- if (!props.value && (props.selectedKey?.length || 0) > 0) {
|
|
|
|
|
|
+ if (!props.value && (selectedKey.value?.length || 0) > 0) {
|
|
api.get_list({
|
|
api.get_list({
|
|
...props.getParams,
|
|
...props.getParams,
|
|
- id: props.selectedKey,
|
|
|
|
|
|
+ id: selectedKey.value,
|
|
}).then(r => {
|
|
}).then(r => {
|
|
M_values.value = r.data
|
|
M_values.value = r.data
|
|
records.value = r.data
|
|
records.value = r.data
|
|
@@ -85,11 +99,22 @@ function show() {
|
|
}
|
|
}
|
|
|
|
|
|
const selectedKeyBuffer = ref()
|
|
const selectedKeyBuffer = ref()
|
|
|
|
+// eslint-disable-next-line ts/no-explicit-any
|
|
|
|
+const selectedBuffer: Ref<any[]> = ref([])
|
|
|
|
|
|
-if (props.selectionType === 'radio')
|
|
|
|
- selectedKeyBuffer.value = [props.selectedKey]
|
|
|
|
-else
|
|
|
|
- selectedKeyBuffer.value = props.selectedKey
|
|
|
|
|
|
+watch(selectedKey, () => {
|
|
|
|
+ selectedKeyBuffer.value = _.clone(selectedKey.value)
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+watch(records, v => {
|
|
|
|
+ selectedBuffer.value = [...v]
|
|
|
|
+ M_values.value = [...v]
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+onMounted(() => {
|
|
|
|
+ selectedKeyBuffer.value = _.clone(selectedKey.value)
|
|
|
|
+ selectedBuffer.value = _.clone(records.value)
|
|
|
|
+})
|
|
|
|
|
|
const computedSelectedKeys = computed({
|
|
const computedSelectedKeys = computed({
|
|
get() {
|
|
get() {
|
|
@@ -103,76 +128,80 @@ const computedSelectedKeys = computed({
|
|
},
|
|
},
|
|
})
|
|
})
|
|
|
|
|
|
-onMounted(() => {
|
|
|
|
- if (props.selectedKey === undefined || props.selectedKey === null) {
|
|
|
|
- if (props.selectionType === 'radio')
|
|
|
|
- emit('update:selectedKey', '')
|
|
|
|
- else
|
|
|
|
- emit('update:selectedKey', [])
|
|
|
|
- }
|
|
|
|
-})
|
|
|
|
-
|
|
|
|
async function ok() {
|
|
async function ok() {
|
|
visible.value = false
|
|
visible.value = false
|
|
- emit('update:selectedKey', selectedKeyBuffer.value)
|
|
|
|
-
|
|
|
|
|
|
+ selectedKey.value = selectedKeyBuffer.value
|
|
|
|
+ records.value = selectedBuffer.value
|
|
|
|
+ await nextTick()
|
|
M_values.value = _.clone(records.value)
|
|
M_values.value = _.clone(records.value)
|
|
}
|
|
}
|
|
|
|
|
|
-watchEffect(() => {
|
|
|
|
- init()
|
|
|
|
-})
|
|
|
|
-
|
|
|
|
// function clear() {
|
|
// function clear() {
|
|
// M_values.value = []
|
|
// M_values.value = []
|
|
// emit('update:selectedKey', '')
|
|
// emit('update:selectedKey', '')
|
|
// }
|
|
// }
|
|
|
|
+
|
|
|
|
+defineExpose({ show })
|
|
</script>
|
|
</script>
|
|
|
|
|
|
<template>
|
|
<template>
|
|
- <div class="std-selector-container">
|
|
|
|
|
|
+ <div>
|
|
<div
|
|
<div
|
|
- class="std-selector"
|
|
|
|
- @click="show"
|
|
|
|
|
|
+ v-if="!hideInputContainer"
|
|
|
|
+ class="std-selector-container"
|
|
>
|
|
>
|
|
- <div class="chips-container">
|
|
|
|
- <ATag
|
|
|
|
- v-for="(chipText, index) in M_values"
|
|
|
|
- :key="index"
|
|
|
|
- class="mr-1"
|
|
|
|
- color="orange"
|
|
|
|
- :bordered="false"
|
|
|
|
- @click="show"
|
|
|
|
- >
|
|
|
|
- {{ chipText?.[recordValueIndex] }}
|
|
|
|
- </ATag>
|
|
|
|
- </div>
|
|
|
|
- <AModal
|
|
|
|
- :mask="false"
|
|
|
|
- :open="visible"
|
|
|
|
- :cancel-text="$gettext('Cancel')"
|
|
|
|
- :ok-text="$gettext('Ok')"
|
|
|
|
- :title="$gettext('Selector')"
|
|
|
|
- :width="800"
|
|
|
|
- destroy-on-close
|
|
|
|
- @cancel="visible = false"
|
|
|
|
- @ok="ok"
|
|
|
|
|
|
+ <div
|
|
|
|
+ class="std-selector"
|
|
|
|
+ @click="show"
|
|
>
|
|
>
|
|
- {{ description }}
|
|
|
|
- <StdTable
|
|
|
|
- v-model:selected-row-keys="computedSelectedKeys"
|
|
|
|
- v-model:selected-rows="records"
|
|
|
|
- :api="api"
|
|
|
|
- :columns="columns"
|
|
|
|
- :disable-search="disableSearch"
|
|
|
|
- pithy
|
|
|
|
- :row-key="itemKey"
|
|
|
|
- :get-params="getParams"
|
|
|
|
- :selection-type="selectionType"
|
|
|
|
- disable-query-params
|
|
|
|
- />
|
|
|
|
- </AModal>
|
|
|
|
|
|
+ <div class="chips-container">
|
|
|
|
+ <div v-if="props.recordValueIndex">
|
|
|
|
+ <ATag
|
|
|
|
+ v-for="(chipText, index) in ComputedMValue"
|
|
|
|
+ :key="index"
|
|
|
|
+ class="mr-1"
|
|
|
|
+ color="orange"
|
|
|
|
+ :bordered="false"
|
|
|
|
+ @click="show"
|
|
|
|
+ >
|
|
|
|
+ {{ chipText?.[recordValueIndex] }}
|
|
|
|
+ </ATag>
|
|
|
|
+ </div>
|
|
|
|
+ <div
|
|
|
|
+ v-else
|
|
|
|
+ class="text-gray-400"
|
|
|
|
+ >
|
|
|
|
+ {{ placeholder }}
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
|
|
+ <AModal
|
|
|
|
+ :mask="false"
|
|
|
|
+ :open="visible"
|
|
|
|
+ :cancel-text="$gettext('Cancel')"
|
|
|
|
+ :ok-text="$gettext('Ok')"
|
|
|
|
+ :title="$gettext('Selector')"
|
|
|
|
+ :width="800"
|
|
|
|
+ destroy-on-close
|
|
|
|
+ @cancel="visible = false"
|
|
|
|
+ @ok="ok"
|
|
|
|
+ >
|
|
|
|
+ {{ description }}
|
|
|
|
+ <StdTable
|
|
|
|
+ v-model:selected-row-keys="computedSelectedKeys"
|
|
|
|
+ v-model:selected-rows="selectedBuffer"
|
|
|
|
+ :api
|
|
|
|
+ :columns
|
|
|
|
+ :disable-search
|
|
|
|
+ :row-key="itemKey"
|
|
|
|
+ :get-params
|
|
|
|
+ :selection-type
|
|
|
|
+ :get-checkbox-props
|
|
|
|
+ pithy
|
|
|
|
+ disable-query-params
|
|
|
|
+ />
|
|
|
|
+ </AModal>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</template>
|
|
|
|
|
|
@@ -180,7 +209,7 @@ watchEffect(() => {
|
|
.std-selector-container {
|
|
.std-selector-container {
|
|
min-height: 39.9px;
|
|
min-height: 39.9px;
|
|
display: flex;
|
|
display: flex;
|
|
- align-items: flex-start;
|
|
|
|
|
|
+ align-items: self-start;
|
|
|
|
|
|
.std-selector {
|
|
.std-selector {
|
|
overflow-y: auto;
|
|
overflow-y: auto;
|
|
@@ -195,7 +224,7 @@ watchEffect(() => {
|
|
line-height: 1.5;
|
|
line-height: 1.5;
|
|
background-image: none;
|
|
background-image: none;
|
|
border: 1px solid #d9d9d9;
|
|
border: 1px solid #d9d9d9;
|
|
- border-radius: 4px;
|
|
|
|
|
|
+ border-radius: 6px;
|
|
transition: all 0.3s;
|
|
transition: all 0.3s;
|
|
//margin: 0 10px 0 0;
|
|
//margin: 0 10px 0 0;
|
|
cursor: pointer;
|
|
cursor: pointer;
|
|
@@ -203,9 +232,10 @@ watchEffect(() => {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-.chips-container {
|
|
|
|
- span {
|
|
|
|
- margin: 2px;
|
|
|
|
|
|
+.dark {
|
|
|
|
+ .std-selector {
|
|
|
|
+ border: 1px solid #424242;
|
|
|
|
+ background-color: #141414;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|
|
</style>
|