pagetype列表页工具栏拆分为独立的组件GenericListPageToolBar.vue
This commit is contained in:
parent
ec822037f8
commit
7aa2b10cdd
@ -29,50 +29,19 @@
|
||||
t
|
||||
}"
|
||||
/>
|
||||
<template v-else>
|
||||
<div class="filters">
|
||||
<n-input v-model:value="searchQuery" :placeholder="t('Search')" clearable style="width: 200px" />
|
||||
</div>
|
||||
<div class="view-toggle">
|
||||
<button
|
||||
class="toggle-btn"
|
||||
:class="{ active: viewMode === 'list' }"
|
||||
@click="viewMode = 'list'"
|
||||
:title="t('List View')"
|
||||
>
|
||||
<i class="fa fa-list"></i>
|
||||
</button>
|
||||
<button
|
||||
class="toggle-btn"
|
||||
:class="{ active: viewMode === 'card' }"
|
||||
@click="viewMode = 'card'"
|
||||
:title="t('Card View')"
|
||||
>
|
||||
<i class="fa fa-th-large"></i>
|
||||
</button>
|
||||
</div>
|
||||
<button class="refresh-btn" @click="reload" :disabled="loading">
|
||||
<i :class="loading ? 'fa fa-spinner fa-spin' : 'fa fa-refresh'"></i>
|
||||
</button>
|
||||
<button
|
||||
v-if="selectedKeys.length === 0"
|
||||
class="create-btn"
|
||||
@click="createRecordHandler"
|
||||
:disabled="loading"
|
||||
>
|
||||
<i class="fa fa-plus"></i>
|
||||
{{ t('Create') }}
|
||||
</button>
|
||||
<button
|
||||
<GenericListPageToolBar
|
||||
v-else
|
||||
class="delete-btn"
|
||||
@click="handleDeleteSelected"
|
||||
:disabled="loading"
|
||||
>
|
||||
<i class="fa fa-trash"></i>
|
||||
{{ t('Delete Selected') }} ({{ selectedKeys.length }})
|
||||
</button>
|
||||
</template>
|
||||
:entity="entity"
|
||||
:search-query="searchQuery"
|
||||
:view-mode="viewMode"
|
||||
:selected-keys="selectedKeys"
|
||||
:loading="loading"
|
||||
@update:search-query="searchQuery = $event"
|
||||
@update:view-mode="viewMode = $event"
|
||||
@reload="reload"
|
||||
@create="createRecordHandler"
|
||||
@delete-selected="handleDeleteSelected"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -303,7 +272,7 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, computed, watch, shallowRef, markRaw } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { NInput, NPagination, useMessage } from 'naive-ui'
|
||||
import { NPagination, useMessage } from 'naive-ui'
|
||||
import { Icon } from '@iconify/vue'
|
||||
import axios from 'axios'
|
||||
import { t } from '@/shared/i18n'
|
||||
@ -312,6 +281,7 @@ import { usePageTypeSlug } from '@/shared/utils/slug'
|
||||
import { isSinglePageType } from '@/shared/utils/pagetype'
|
||||
import SinglePageDetail from './SinglePageDetail.vue'
|
||||
import FilterBar from '@/core/components/FilterBar.vue'
|
||||
import GenericListPageToolBar from './GenericListPageToolBar.vue'
|
||||
import {
|
||||
resolvePagetypeListOverride,
|
||||
resolvePagetypeListToolbarOverride,
|
||||
@ -1229,14 +1199,6 @@ function formatDisplayValue(value: any, fieldName: string) {
|
||||
|
||||
.header-left h2 { font-size: 28px; font-weight: 700; color: #1f2937; margin: 0; }
|
||||
|
||||
.header-right { display: flex; align-items: center; gap: 12px; }
|
||||
.filters { display: flex; gap: 8px; align-items: center; }
|
||||
|
||||
.refresh-btn { width: 36px; height: 36px; border: none; border-radius: 8px; background: #f8fafc; color: #64748b; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 14px; transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); position: relative; overflow: hidden; }
|
||||
.refresh-btn:hover { background: #e2e8f0; color: #475569; transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); }
|
||||
.refresh-btn:active { transform: translateY(0); box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); }
|
||||
.refresh-btn:disabled { opacity: 0.6; cursor: not-allowed; transform: none; box-shadow: none; }
|
||||
.refresh-btn:disabled:hover { background: #f8fafc; color: #64748b; transform: none; box-shadow: none; }
|
||||
|
||||
.agent-list { background: white; border: 1px solid #e5e7eb; border-radius: 12px; overflow: hidden; }
|
||||
.list-pagination { padding: 16px 20px; border-top: 1px solid #e5e7eb; background: #f9fafb; display: flex; justify-content: center; }
|
||||
@ -1493,118 +1455,8 @@ function formatDisplayValue(value: any, fieldName: string) {
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 工具栏样式(对齐 AgentList) */
|
||||
/* 工具栏容器样式(保留用于布局) */
|
||||
.header-right { display: flex; align-items: center; gap: 12px; }
|
||||
.filters { display: flex; gap: 8px; align-items: center; }
|
||||
|
||||
/* 视图切换按钮 */
|
||||
.view-toggle {
|
||||
display: flex;
|
||||
background: #f8fafc;
|
||||
border-radius: 8px;
|
||||
padding: 2px;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
/* 切换按钮 - 使用灰色系 */
|
||||
.toggle-btn {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: #6b7280;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 6px;
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.toggle-btn:hover {
|
||||
background: #f1f5f9;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.toggle-btn.active {
|
||||
background: #e2e8f0;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
/* 刷新按钮 */
|
||||
.refresh-btn {
|
||||
width: 36px; height: 36px; border: none; border-radius: 8px; background: #f8fafc;
|
||||
color: #64748b; cursor: pointer; display: flex; align-items: center;
|
||||
justify-content: center; font-size: 14px; transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
position: relative; overflow: hidden;
|
||||
}
|
||||
.refresh-btn:hover { background: #e2e8f0; color: #475569; transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); }
|
||||
.refresh-btn:active { transform: translateY(0); box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); }
|
||||
.refresh-btn:disabled { opacity: 0.6; cursor: not-allowed; transform: none; box-shadow: none; }
|
||||
.refresh-btn:disabled:hover { background: #f8fafc; color: #64748b; transform: none; box-shadow: none; }
|
||||
|
||||
/* 新建按钮 - 使用柔和的品牌色系,与整体风格协调 */
|
||||
.create-btn {
|
||||
height: 36px;
|
||||
padding: 0 16px;
|
||||
border: 1px solid #1fc76f;
|
||||
border-radius: 8px;
|
||||
background: #e6f8f0;
|
||||
color: #0d684b;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.create-btn:hover {
|
||||
background: #dcfce7;
|
||||
border-color: #1fc76f;
|
||||
color: #166534;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 8px rgba(31, 199, 111, 0.15);
|
||||
}
|
||||
.create-btn:active {
|
||||
background: #1fc76f;
|
||||
border-color: #1fc76f;
|
||||
color: white;
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 1px 4px rgba(31, 199, 111, 0.2);
|
||||
}
|
||||
.create-btn:disabled {
|
||||
background: #f1f5f9;
|
||||
border-color: #e2e8f0;
|
||||
color: #94a3b8;
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.create-btn:disabled:hover {
|
||||
background: #f1f5f9;
|
||||
border-color: #e2e8f0;
|
||||
color: #94a3b8;
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.create-btn i {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* 删除选中按钮 */
|
||||
.delete-btn {
|
||||
background: #ef4444; color: white; border: none; padding: 8px 16px; border-radius: 6px;
|
||||
cursor: pointer; font-size: 14px; font-weight: 500; display: flex; align-items: center;
|
||||
gap: 6px; transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); position: relative; overflow: hidden;
|
||||
}
|
||||
.delete-btn:hover { background: #dc2626; transform: translateY(-1px); box-shadow: 0 4px 12px rgba(239, 68, 68, 0.3); }
|
||||
.delete-btn:active { transform: translateY(0); box-shadow: 0 2px 6px rgba(239, 68, 68, 0.3); }
|
||||
.delete-btn:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||
.delete-btn i { font-size: 12px; }
|
||||
|
||||
/* 表格操作列样式 - 与 AgentList 完全一致 */
|
||||
.col-actions {
|
||||
|
||||
@ -0,0 +1,286 @@
|
||||
<template>
|
||||
<div class="header-right">
|
||||
<div class="filters">
|
||||
<n-input
|
||||
v-model:value="searchQueryModel"
|
||||
:placeholder="t('Search')"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
/>
|
||||
</div>
|
||||
<div class="view-toggle">
|
||||
<button
|
||||
class="toggle-btn"
|
||||
:class="{ active: viewModeModel === 'list' }"
|
||||
@click="viewModeModel = 'list'"
|
||||
:title="t('List View')"
|
||||
>
|
||||
<i class="fa fa-list"></i>
|
||||
</button>
|
||||
<button
|
||||
class="toggle-btn"
|
||||
:class="{ active: viewModeModel === 'card' }"
|
||||
@click="viewModeModel = 'card'"
|
||||
:title="t('Card View')"
|
||||
>
|
||||
<i class="fa fa-th-large"></i>
|
||||
</button>
|
||||
</div>
|
||||
<button class="refresh-btn" @click="reload" :disabled="loading">
|
||||
<i :class="loading ? 'fa fa-spinner fa-spin' : 'fa fa-refresh'"></i>
|
||||
</button>
|
||||
<button
|
||||
v-if="selectedKeys.length === 0"
|
||||
class="create-btn"
|
||||
@click="createRecordHandler"
|
||||
:disabled="loading"
|
||||
>
|
||||
<i class="fa fa-plus"></i>
|
||||
{{ t('Create') }}
|
||||
</button>
|
||||
<button
|
||||
v-else
|
||||
class="delete-btn"
|
||||
@click="handleDeleteSelected"
|
||||
:disabled="loading"
|
||||
>
|
||||
<i class="fa fa-trash"></i>
|
||||
{{ t('Delete Selected') }} ({{ selectedKeys.length }})
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { NInput } from 'naive-ui'
|
||||
import { t } from '@/shared/i18n'
|
||||
|
||||
interface Props {
|
||||
entity: string
|
||||
searchQuery: string
|
||||
viewMode: 'card' | 'list'
|
||||
selectedKeys: string[]
|
||||
loading: boolean
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'update:searchQuery', value: string): void
|
||||
(e: 'update:viewMode', value: 'card' | 'list'): void
|
||||
(e: 'reload'): void
|
||||
(e: 'create'): void
|
||||
(e: 'delete-selected'): void
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
// 使用 computed 来处理双向绑定
|
||||
const searchQueryModel = computed({
|
||||
get: () => props.searchQuery,
|
||||
set: (value) => emit('update:searchQuery', value)
|
||||
})
|
||||
|
||||
const viewModeModel = computed({
|
||||
get: () => props.viewMode,
|
||||
set: (value) => emit('update:viewMode', value)
|
||||
})
|
||||
|
||||
function reload() {
|
||||
emit('reload')
|
||||
}
|
||||
|
||||
function createRecordHandler() {
|
||||
emit('create')
|
||||
}
|
||||
|
||||
function handleDeleteSelected() {
|
||||
emit('delete-selected')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.header-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.filters {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 视图切换按钮 */
|
||||
.view-toggle {
|
||||
display: flex;
|
||||
background: #f8fafc;
|
||||
border-radius: 8px;
|
||||
padding: 2px;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
/* 切换按钮 - 使用灰色系 */
|
||||
.toggle-btn {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: #6b7280;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 6px;
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.toggle-btn:hover {
|
||||
background: #f1f5f9;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.toggle-btn.active {
|
||||
background: #e2e8f0;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
/* 刷新按钮 */
|
||||
.refresh-btn {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
background: #f8fafc;
|
||||
color: #64748b;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.refresh-btn:hover {
|
||||
background: #e2e8f0;
|
||||
color: #475569;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.refresh-btn:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.refresh-btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.refresh-btn:disabled:hover {
|
||||
background: #f8fafc;
|
||||
color: #64748b;
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* 新建按钮 - 使用柔和的品牌色系,与整体风格协调 */
|
||||
.create-btn {
|
||||
height: 36px;
|
||||
padding: 0 16px;
|
||||
border: 1px solid #1fc76f;
|
||||
border-radius: 8px;
|
||||
background: #e6f8f0;
|
||||
color: #0d684b;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.create-btn:hover {
|
||||
background: #dcfce7;
|
||||
border-color: #1fc76f;
|
||||
color: #166534;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 8px rgba(31, 199, 111, 0.15);
|
||||
}
|
||||
|
||||
.create-btn:active {
|
||||
background: #1fc76f;
|
||||
border-color: #1fc76f;
|
||||
color: white;
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 1px 4px rgba(31, 199, 111, 0.2);
|
||||
}
|
||||
|
||||
.create-btn:disabled {
|
||||
background: #f1f5f9;
|
||||
border-color: #e2e8f0;
|
||||
color: #94a3b8;
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.create-btn:disabled:hover {
|
||||
background: #f1f5f9;
|
||||
border-color: #e2e8f0;
|
||||
color: #94a3b8;
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.create-btn i {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* 删除选中按钮 */
|
||||
.delete-btn {
|
||||
background: #ef4444;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 16px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.delete-btn:hover {
|
||||
background: #dc2626;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(239, 68, 68, 0.3);
|
||||
}
|
||||
|
||||
.delete-btn:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 2px 6px rgba(239, 68, 68, 0.3);
|
||||
}
|
||||
|
||||
.delete-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.delete-btn i {
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
Loading…
x
Reference in New Issue
Block a user