feat(share): align social sharing runtime
This commit is contained in:
1 parent
26ac8167f3
commit
cf6c11852e
33 files changed
+802
-1919
No files matched your search
@@ -82,6 +82,12 @@
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
</div>
|
||||
<AksSorterField
|
||||
v-else-if="field.type === 'custom' && field.renderer === 'sorter'"
|
||||
:model-value="getFieldValue(field.key) || {}"
|
||||
:options="field.options || []"
|
||||
@update:model-value="setFieldValue(field.key, $event)"
|
||||
/>
|
||||
<slot
|
||||
v-else-if="field.type === 'custom'"
|
||||
:name="`field-${field.key}`"
|
||||
@@ -93,7 +99,7 @@
|
||||
:form-data="formData"
|
||||
:error-message="errors?.[field.key]"
|
||||
@update:model-value="setFieldValue(field.key, $event)"
|
||||
@action="emit('field-action', $event)"
|
||||
@action="emit('field-action', $event)"
|
||||
/>
|
||||
</slot>
|
||||
<AksField
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<div class="aksrt-sorter">
|
||||
<div class="aksrt-sorter__column">
|
||||
<div class="aksrt-sorter__title">
|
||||
<span>已启用</span>
|
||||
<n-tag size="small" type="success" :bordered="false">{{ columns.enabled.length }}</n-tag>
|
||||
</div>
|
||||
<draggable
|
||||
v-model="columns.enabled"
|
||||
item-key="value"
|
||||
group="aksrt-sorter"
|
||||
handle=".aksrt-sorter__handle"
|
||||
ghost-class="aksrt-sorter__ghost"
|
||||
animation="180"
|
||||
class="aksrt-sorter__list"
|
||||
@change="commit"
|
||||
>
|
||||
<template #item="{ element }">
|
||||
<div class="aksrt-sorter__item">
|
||||
<i class="fa fas fa-grip-vertical aksrt-sorter__handle" aria-hidden="true"></i>
|
||||
<i v-if="element.icon" :class="element.icon" aria-hidden="true"></i>
|
||||
<span>{{ element.label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</draggable>
|
||||
<n-empty v-if="columns.enabled.length === 0" size="small" description="暂无启用项" />
|
||||
</div>
|
||||
|
||||
<div class="aksrt-sorter__column aksrt-sorter__column--disabled">
|
||||
<div class="aksrt-sorter__title">
|
||||
<span>未启用</span>
|
||||
<n-tag size="small" :bordered="false">{{ columns.disabled.length }}</n-tag>
|
||||
</div>
|
||||
<draggable
|
||||
v-model="columns.disabled"
|
||||
item-key="value"
|
||||
group="aksrt-sorter"
|
||||
handle=".aksrt-sorter__handle"
|
||||
ghost-class="aksrt-sorter__ghost"
|
||||
animation="180"
|
||||
class="aksrt-sorter__list"
|
||||
@change="commit"
|
||||
>
|
||||
<template #item="{ element }">
|
||||
<div class="aksrt-sorter__item">
|
||||
<i class="fa fas fa-grip-vertical aksrt-sorter__handle" aria-hidden="true"></i>
|
||||
<i v-if="element.icon" :class="element.icon" aria-hidden="true"></i>
|
||||
<span>{{ element.label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</draggable>
|
||||
<n-empty v-if="columns.disabled.length === 0" size="small" description="暂无未启用项" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, watch } from 'vue'
|
||||
import draggable from 'vuedraggable'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: { type: Object, default: () => ({}) },
|
||||
options: { type: Array, default: () => [] },
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const columns = reactive({ enabled: [], disabled: [] })
|
||||
let syncing = false
|
||||
|
||||
function keysOf(value) {
|
||||
if (Array.isArray(value)) return value.map(String)
|
||||
return value && typeof value === 'object' ? Object.keys(value) : []
|
||||
}
|
||||
|
||||
function syncColumns() {
|
||||
syncing = true
|
||||
const byKey = new Map(props.options.map(option => [String(option.value), option]))
|
||||
const used = new Set()
|
||||
const normalize = keys => keys.filter(key => byKey.has(key) && !used.has(key)).map(key => {
|
||||
used.add(key)
|
||||
return byKey.get(key)
|
||||
})
|
||||
columns.enabled = normalize(keysOf(props.modelValue?.enabled))
|
||||
columns.disabled = normalize(keysOf(props.modelValue?.disabled))
|
||||
for (const option of props.options) {
|
||||
if (!used.has(String(option.value))) columns.disabled.push(option)
|
||||
}
|
||||
syncing = false
|
||||
}
|
||||
|
||||
function commit() {
|
||||
if (syncing) return
|
||||
const toMap = items => Object.fromEntries(items.map(item => [String(item.value), String(item.label)]))
|
||||
emit('update:modelValue', {
|
||||
enabled: toMap(columns.enabled),
|
||||
disabled: toMap(columns.disabled),
|
||||
})
|
||||
}
|
||||
|
||||
watch(() => [props.modelValue, props.options], syncColumns, { immediate: true, deep: true })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.aksrt-sorter { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:14px; }
|
||||
.aksrt-sorter__column { min-height:210px; padding:12px; border:1px solid var(--aksrt-color-border); border-radius:6px; background:var(--aksrt-color-surface); }
|
||||
.aksrt-sorter__column--disabled { background:var(--aksrt-color-canvas); }
|
||||
.aksrt-sorter__title { display:flex; align-items:center; justify-content:space-between; margin-bottom:10px; font-weight:600; }
|
||||
.aksrt-sorter__list { display:grid; gap:7px; min-height:44px; }
|
||||
.aksrt-sorter__item { display:flex; align-items:center; gap:9px; min-height:38px; padding:7px 10px; border:1px solid var(--aksrt-color-border); border-radius:4px; background:var(--aksrt-color-surface); }
|
||||
.aksrt-sorter__handle { color:var(--aksrt-color-text-tertiary); cursor:grab; }
|
||||
.aksrt-sorter__ghost { opacity:.45; border-color:var(--aksrt-color-primary); }
|
||||
@media (max-width:720px) { .aksrt-sorter { grid-template-columns:1fr; } }
|
||||
</style>
|
||||
Reference in new issue
Block a user