|
@@ -28,18 +28,209 @@
|
|
|
</div>
|
|
</div>
|
|
|
@endif
|
|
@endif
|
|
|
|
|
|
|
|
- <div class="mt-8">
|
|
|
|
|
- @if ($menuItems->isEmpty())
|
|
|
|
|
- <div class="rounded border border-dashed border-gray-300 p-10 text-center text-gray-500 dark:border-gray-700">
|
|
|
|
|
- @lang('frontmenu::app.admin.menu.add-btn') 后即可在此管理前端导航。
|
|
|
|
|
- </div>
|
|
|
|
|
- @else
|
|
|
|
|
- <div class="space-y-2">
|
|
|
|
|
- @foreach ($menuItems as $item)
|
|
|
|
|
- @include('frontmenu::admin.menu.partials.tree', ['item' => $item, 'level' => 0])
|
|
|
|
|
- @endforeach
|
|
|
|
|
- </div>
|
|
|
|
|
- @endif
|
|
|
|
|
|
|
+ <p class="mt-4 text-xs text-gray-500">
|
|
|
|
|
+ <i class="icon-move"></i>
|
|
|
|
|
+ @lang('frontmenu::app.admin.menu.drag-hint')
|
|
|
|
|
+ </p>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="mt-4">
|
|
|
|
|
+ <v-front-menu-tree :items='@json($menuItems)'></v-front-menu-tree>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+
|
|
|
|
|
+ @pushOnce('scripts')
|
|
|
|
|
+ <script type="text/x-template" id="v-front-menu-tree-template">
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <draggable
|
|
|
|
|
+ :list="items"
|
|
|
|
|
+ group="front-menu"
|
|
|
|
|
+ item-key="id"
|
|
|
|
|
+ ghost-class="draggable-ghost"
|
|
|
|
|
+ animation="200"
|
|
|
|
|
+ @end="saveOrder"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template #item="{ element }">
|
|
|
|
|
+ <div class="rounded-lg border border-gray-200 bg-white shadow-sm dark:border-gray-700 dark:bg-gray-900">
|
|
|
|
|
+ <div class="flex items-center justify-between gap-4 px-4 py-3">
|
|
|
|
|
+ <div class="flex items-center gap-3">
|
|
|
|
|
+ <span class="icon-move cursor-move text-gray-400"></span>
|
|
|
|
|
+
|
|
|
|
|
+ <template v-if="element.image">
|
|
|
|
|
+ <img :src="element.image" :alt="element.name" class="h-8 w-8 rounded object-cover">
|
|
|
|
|
+ </template>
|
|
|
|
|
+ <template v-else>
|
|
|
|
|
+ <span class="flex h-8 w-8 items-center justify-center rounded bg-gray-100 text-gray-400 dark:bg-gray-800">
|
|
|
|
|
+ <i class="icon-menu"></i>
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <div class="flex items-center gap-2">
|
|
|
|
|
+ <span class="font-semibold text-gray-800 dark:text-white">@{{ element.name }}</span>
|
|
|
|
|
+ <span class="text-xs text-gray-400">(@{{ element.slug }})</span>
|
|
|
|
|
+ <span v-if="! element.status" class="rounded bg-amber-100 px-1.5 py-0.5 text-xs text-amber-700 dark:bg-amber-900 dark:text-amber-300">
|
|
|
|
|
+ @lang('frontmenu::app.admin.menu.disabled')
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="text-xs text-gray-500">@{{ element.url }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="flex items-center gap-2">
|
|
|
|
|
+ <a :href="'{{ route('admin.frontmenu.index') }}/' + element.id + '/edit'" class="secondary-button !px-3 !py-1.5 text-sm">
|
|
|
|
|
+ @lang('frontmenu::app.admin.menu.edit')
|
|
|
|
|
+ </a>
|
|
|
|
|
+
|
|
|
|
|
+ <form :action="'{{ route('admin.frontmenu.index') }}/' + element.id" method="POST"
|
|
|
|
|
+ onsubmit="return confirm('@lang('frontmenu::app.admin.menu.delete-confirm')');">
|
|
|
|
|
+ @csrf
|
|
|
|
|
+ @method('DELETE')
|
|
|
|
|
+ <button type="submit" class="text-sm text-red-600 hover:text-red-700">
|
|
|
|
|
+ @lang('frontmenu::app.admin.menu.delete')
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </form>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <v-front-menu-tree-children
|
|
|
|
|
+ :items="element.children"
|
|
|
|
|
+ @change="$emit('reorder', $event)"
|
|
|
|
|
+ ></v-front-menu-tree-children>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </draggable>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </script>
|
|
|
|
|
+
|
|
|
|
|
+ <script type="text/x-template" id="v-front-menu-tree-children-template">
|
|
|
|
|
+ <div class="px-4 pb-3" v-if="items && items.length">
|
|
|
|
|
+ <draggable
|
|
|
|
|
+ :list="items"
|
|
|
|
|
+ group="front-menu"
|
|
|
|
|
+ item-key="id"
|
|
|
|
|
+ ghost-class="draggable-ghost"
|
|
|
|
|
+ animation="200"
|
|
|
|
|
+ @end="$emit('change')"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template #item="{ element }">
|
|
|
|
|
+ <div class="rounded-lg border border-gray-200 bg-white shadow-sm dark:border-gray-700 dark:bg-gray-900">
|
|
|
|
|
+ <div class="flex items-center justify-between gap-4 px-4 py-3">
|
|
|
|
|
+ <div class="flex items-center gap-3">
|
|
|
|
|
+ <span class="icon-move cursor-move text-gray-400"></span>
|
|
|
|
|
+
|
|
|
|
|
+ <template v-if="element.image">
|
|
|
|
|
+ <img :src="element.image" :alt="element.name" class="h-8 w-8 rounded object-cover">
|
|
|
|
|
+ </template>
|
|
|
|
|
+ <template v-else>
|
|
|
|
|
+ <span class="flex h-8 w-8 items-center justify-center rounded bg-gray-100 text-gray-400 dark:bg-gray-800">
|
|
|
|
|
+ <i class="icon-menu"></i>
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <div class="flex items-center gap-2">
|
|
|
|
|
+ <span class="font-semibold text-gray-800 dark:text-white">@{{ element.name }}</span>
|
|
|
|
|
+ <span class="text-xs text-gray-400">(@{{ element.slug }})</span>
|
|
|
|
|
+ <span v-if="! element.status" class="rounded bg-amber-100 px-1.5 py-0.5 text-xs text-amber-700 dark:bg-amber-900 dark:text-amber-300">
|
|
|
|
|
+ @lang('frontmenu::app.admin.menu.disabled')
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="text-xs text-gray-500">@{{ element.url }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="flex items-center gap-2">
|
|
|
|
|
+ <a :href="'{{ route('admin.frontmenu.index') }}/' + element.id + '/edit'" class="secondary-button !px-3 !py-1.5 text-sm">
|
|
|
|
|
+ @lang('frontmenu::app.admin.menu.edit')
|
|
|
|
|
+ </a>
|
|
|
|
|
+
|
|
|
|
|
+ <form :action="'{{ route('admin.frontmenu.index') }}/' + element.id" method="POST"
|
|
|
|
|
+ onsubmit="return confirm('@lang('frontmenu::app.admin.menu.delete-confirm')');">
|
|
|
|
|
+ @csrf
|
|
|
|
|
+ @method('DELETE')
|
|
|
|
|
+ <button type="submit" class="text-sm text-red-600 hover:text-red-700">
|
|
|
|
|
+ @lang('frontmenu::app.admin.menu.delete')
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </form>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <v-front-menu-tree-children
|
|
|
|
|
+ :items="element.children"
|
|
|
|
|
+ @change="$emit('change')"
|
|
|
|
|
+ ></v-front-menu-tree-children>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </draggable>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </script>
|
|
|
|
|
+
|
|
|
|
|
+ <script type="module">
|
|
|
|
|
+ const childComponent = {
|
|
|
|
|
+ template: '#v-front-menu-tree-children-template',
|
|
|
|
|
+
|
|
|
|
|
+ props: {
|
|
|
|
|
+ items: {
|
|
|
|
|
+ type: Array,
|
|
|
|
|
+ default: () => [],
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ emits: ['change'],
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ app.component('v-front-menu-tree-children', childComponent);
|
|
|
|
|
+
|
|
|
|
|
+ app.component('v-front-menu-tree', {
|
|
|
|
|
+ template: '#v-front-menu-tree-template',
|
|
|
|
|
+
|
|
|
|
|
+ props: {
|
|
|
|
|
+ items: {
|
|
|
|
|
+ type: Array,
|
|
|
|
|
+ default: () => [],
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ methods: {
|
|
|
|
|
+ saveOrder() {
|
|
|
|
|
+ const payload = this.flatten(this.items, null);
|
|
|
|
|
+
|
|
|
|
|
+ this.$axios
|
|
|
|
|
+ .post('{{ route('admin.frontmenu.reorder') }}', { items: payload })
|
|
|
|
|
+ .then((response) => {
|
|
|
|
|
+ this.$emitter.emit('add-flash', {
|
|
|
|
|
+ type: 'success',
|
|
|
|
|
+ message: response.data.message,
|
|
|
|
|
+ });
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch((error) => {
|
|
|
|
|
+ this.$emitter.emit('add-flash', {
|
|
|
|
|
+ type: 'error',
|
|
|
|
|
+ message: error.response?.data?.message || '{{ trans('frontmenu::app.admin.menu.reordered') }}',
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ window.location.reload();
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ flatten(nodes, parentId) {
|
|
|
|
|
+ let result = [];
|
|
|
|
|
+
|
|
|
|
|
+ nodes.forEach((node, index) => {
|
|
|
|
|
+ result.push({
|
|
|
|
|
+ id: node.id,
|
|
|
|
|
+ parent_id: parentId,
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ if (node.children && node.children.length) {
|
|
|
|
|
+ result = result.concat(this.flatten(node.children, node.id));
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ return result;
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+ </script>
|
|
|
|
|
+ @endPushOnce
|
|
|
</x-admin::layouts>
|
|
</x-admin::layouts>
|