Commit 8516388e by User

添加本地代码开发示例和table组件

parent c560ab0d
{
"Offset": 0,
"Total": 10,
"Results": [
{
"OwnerName": "222",
"Name": "333",
"SerialNumber": "1111",
"Type": "Pos",
"CreditLine": 0,
"Amount": 0,
"Currency": "CNY",
"Summary": "",
"Remark": "",
"CreatorKvid": "7F5918CC-E15F-4D7A-B636-1B40A905B744",
"CreatorName": "高源",
"OrganizationKvid": "CC7B3DF9-1B95-46DF-83C5-150587E29612",
"Metadata": {},
"Kvid": "EF1D786D-06F7-43F5-A685-8E13AE0F33BF",
"CreateTime": "2025-05-07T14:30:22.0000000+08:00",
"UpdateTime": "2025-05-13T16:59:38.0000000+08:00",
"Status": 0
},
{
"OwnerName": "xxx",
"Name": "xxx",
"SerialNumber": "xxxx",
"Type": "Cash",
"CreditLine": 0,
"Amount": 0,
"Currency": "USD",
"Summary": "",
"Remark": "",
"CreatorKvid": "7F5918CC-E15F-4D7A-B636-1B40A905B744",
"CreatorName": "高源",
"OrganizationKvid": "CC7B3DF9-1B95-46DF-83C5-150587E29612",
"Metadata": {},
"Kvid": "66B88D4E-A1B9-4E3C-922B-DD5211BA3FB5",
"CreateTime": "2025-05-07T14:26:34.0000000+08:00",
"UpdateTime": "2025-05-13T16:57:05.0000000+08:00",
"Status": 0
},
{
"OwnerName": "1111",
"Name": "222",
"SerialNumber": "333",
"Type": "Pos",
"CreditLine": 0,
"Amount": 0,
"Currency": "CNY",
"Summary": "",
"Remark": "",
"CreatorKvid": "7F5918CC-E15F-4D7A-B636-1B40A905B744",
"CreatorName": "高源",
"OrganizationKvid": "CC7B3DF9-1B95-46DF-83C5-150587E29612",
"Metadata": {},
"Kvid": "97F8DA3B-06AC-4C50-ABEB-430F58B3DD64",
"CreateTime": "2025-05-07T14:30:08.0000000+08:00",
"UpdateTime": "2025-05-07T14:30:08.0000000+08:00",
"Status": 0
},
{
"OwnerName": "11",
"Name": "222",
"SerialNumber": "3",
"Type": "Cash",
"CreditLine": 0,
"Amount": 0,
"Currency": "USD",
"Summary": "",
"Remark": "",
"CreatorKvid": "7F5918CC-E15F-4D7A-B636-1B40A905B744",
"CreatorName": "高源",
"OrganizationKvid": "CC7B3DF9-1B95-46DF-83C5-150587E29612",
"Metadata": {},
"Kvid": "CC255F3E-9F80-4002-B68C-53C5FF86AE52",
"CreateTime": "2025-05-07T14:29:49.0000000+08:00",
"UpdateTime": "2025-05-07T14:29:49.0000000+08:00",
"Status": 0
},
{
"OwnerName": "22",
"Name": "222",
"SerialNumber": "33",
"Type": "AliPay",
"CreditLine": 0,
"Amount": 0,
"Currency": "CNY",
"Summary": "",
"Remark": "",
"CreatorKvid": "7F5918CC-E15F-4D7A-B636-1B40A905B744",
"CreatorName": "高源",
"OrganizationKvid": "CC7B3DF9-1B95-46DF-83C5-150587E29612",
"Metadata": {},
"Kvid": "99C366A3-5867-43D5-B22D-B71E970D9A3C",
"CreateTime": "2025-05-07T14:29:33.0000000+08:00",
"UpdateTime": "2025-05-07T14:29:33.0000000+08:00",
"Status": 0
},
{
"OwnerName": "xxx",
"Name": "111",
"SerialNumber": "2222",
"Type": "Bank",
"CreditLine": 0,
"Amount": 0,
"Currency": "CNY",
"Summary": "",
"Remark": "",
"CreatorKvid": "7F5918CC-E15F-4D7A-B636-1B40A905B744",
"CreatorName": "高源",
"OrganizationKvid": "CC7B3DF9-1B95-46DF-83C5-150587E29612",
"Metadata": {},
"Kvid": "F2475ECC-55BD-49FE-BC00-8822DC846739",
"CreateTime": "2025-05-07T14:29:00.0000000+08:00",
"UpdateTime": "2025-05-07T14:29:00.0000000+08:00",
"Status": 0
},
{
"OwnerName": "7275275",
"Name": "4274272",
"SerialNumber": "41042277",
"Type": "Cash",
"CreditLine": 0,
"Amount": 0,
"Currency": "CNY",
"Summary": "",
"Remark": "",
"CreatorKvid": "7F5918CC-E15F-4D7A-B636-1B40A905B744",
"CreatorName": "高源",
"OrganizationKvid": "CC7B3DF9-1B95-46DF-83C5-150587E29612",
"Metadata": {},
"Kvid": "0C38277C-7BA6-4E9D-BEF5-D43DB49B5EA1",
"CreateTime": "2025-03-27T14:47:54.0000000+08:00",
"UpdateTime": "2025-03-27T14:47:54.0000000+08:00",
"Status": 0
},
{
"OwnerName": "12312322",
"Name": "32131",
"SerialNumber": "2231123",
"Type": "Pos",
"CreditLine": 0,
"Amount": 0,
"Currency": "CNY",
"Summary": "",
"Remark": "",
"CreatorKvid": "7F5918CC-E15F-4D7A-B636-1B40A905B744",
"CreatorName": "高源",
"OrganizationKvid": "CC7B3DF9-1B95-46DF-83C5-150587E29612",
"Metadata": {},
"Kvid": "2A42BDFE-CDED-4300-ADF3-020D1B3E0138",
"CreateTime": "2025-03-27T14:33:13.0000000+08:00",
"UpdateTime": "2025-03-27T14:33:13.0000000+08:00",
"Status": 0
},
{
"OwnerName": "123123",
"Name": "321321",
"SerialNumber": "123132312312",
"Type": "Cash",
"CreditLine": 0,
"Amount": 0,
"Currency": "CNY",
"Summary": "",
"Remark": "",
"CreatorKvid": "7F5918CC-E15F-4D7A-B636-1B40A905B744",
"CreatorName": "高源",
"OrganizationKvid": "CC7B3DF9-1B95-46DF-83C5-150587E29612",
"Metadata": {},
"Kvid": "095872A0-513C-4834-A0C5-BA173F5189A4",
"CreateTime": "2025-03-27T14:29:36.0000000+08:00",
"UpdateTime": "2025-03-27T14:29:36.0000000+08:00",
"Status": 0
},
{
"OwnerName": "12",
"Name": "1212",
"SerialNumber": "12121211",
"Type": "Cash",
"CreditLine": 0,
"Amount": 0,
"Currency": "CNY",
"Summary": "",
"Remark": "",
"CreatorKvid": "7F5918CC-E15F-4D7A-B636-1B40A905B744",
"CreatorName": "高源",
"OrganizationKvid": "CC7B3DF9-1B95-46DF-83C5-150587E29612",
"Metadata": {},
"Kvid": "40D1968B-70A1-49D5-89FD-39943A080D0A",
"CreateTime": "2025-03-27T14:17:12.0000000+08:00",
"UpdateTime": "2025-03-27T14:17:12.0000000+08:00",
"Status": 0
}
]
}
\ No newline at end of file
...@@ -156,6 +156,7 @@ const local: App.I18n.Schema = { ...@@ -156,6 +156,7 @@ const local: App.I18n.Schema = {
'iframe-page': '外链页面', 'iframe-page': '外链页面',
home: '首页', home: '首页',
chat: 'AI助手', chat: 'AI助手',
tablecomponent: '表格组件',
exception: '异常页', exception: '异常页',
exception_403: '403', exception_403: '403',
exception_404: '404', exception_404: '404',
......
...@@ -4,6 +4,9 @@ import '@wangeditor/editor/dist/css/style.css'; ...@@ -4,6 +4,9 @@ import '@wangeditor/editor/dist/css/style.css';
import VueGridLayout from 'vue-grid-layout'; import VueGridLayout from 'vue-grid-layout';
import MateChat from '@matechat/core'; import MateChat from '@matechat/core';
import '@devui-design/icons/icomoon/devui-icon.css'; import '@devui-design/icons/icomoon/devui-icon.css';
import axios from 'axios';
import * as echarts from 'echarts/core';
import WangEditor from 'wangeditor';
import './plugins/assets'; import './plugins/assets';
import { localStg } from '@/utils/storage'; import { localStg } from '@/utils/storage';
// main.js or main.ts // main.js or main.ts
...@@ -62,6 +65,11 @@ async function setupApp() { ...@@ -62,6 +65,11 @@ async function setupApp() {
setupIconifyOffline(); setupIconifyOffline();
setupDayjs(); setupDayjs();
// 全局注册工具库到 window 对象,供外部组件使用
(window as any).$axios = axios;
(window as any).$echarts = echarts;
(window as any).$WangEditor = WangEditor;
const app = createApp(App); const app = createApp(App);
setupStore(app); setupStore(app);
await setupRouter(app); await setupRouter(app);
......
...@@ -22,4 +22,5 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro ...@@ -22,4 +22,5 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
login: () => import("@/views/_builtin/login/index.vue"), login: () => import("@/views/_builtin/login/index.vue"),
chat: () => import("@/views/chat/index.vue"), chat: () => import("@/views/chat/index.vue"),
home: () => import("@/views/home/index.vue"), home: () => import("@/views/home/index.vue"),
tablecomponent: () => import("@/views/tableComponent/index.vue"),
}; };
...@@ -84,5 +84,14 @@ export const generatedRoutes: GeneratedRoute[] = [ ...@@ -84,5 +84,14 @@ export const generatedRoutes: GeneratedRoute[] = [
constant: true, constant: true,
hideInMenu: true hideInMenu: true
} }
},
{
name: 'tablecomponent',
path: '/tablecomponent',
component: 'layout.base$view.tablecomponent',
meta: {
title: 'tablecomponent',
i18nKey: 'route.tablecomponent'
}
} }
]; ];
...@@ -182,7 +182,8 @@ const routeMap: RouteMap = { ...@@ -182,7 +182,8 @@ const routeMap: RouteMap = {
"chat": "/chat", "chat": "/chat",
"home": "/home", "home": "/home",
"iframe-page": "/iframe-page/:url", "iframe-page": "/iframe-page/:url",
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?" "login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?",
"tablecomponent": "/tablecomponent"
}; };
/** /**
......
...@@ -7,11 +7,17 @@ export {} ...@@ -7,11 +7,17 @@ export {}
/* prettier-ignore */ /* prettier-ignore */
declare module 'vue' { declare module 'vue' {
export interface GlobalComponents { export interface GlobalComponents {
AddFieldDrawer: typeof import('./../components/AddFieldDrawer.vue')['default']
AppProvider: typeof import('./../components/common/app-provider.vue')['default'] AppProvider: typeof import('./../components/common/app-provider.vue')['default']
BetterScroll: typeof import('./../components/custom/better-scroll.vue')['default'] BetterScroll: typeof import('./../components/custom/better-scroll.vue')['default']
ButtonIcon: typeof import('./../components/custom/button-icon.vue')['default'] ButtonIcon: typeof import('./../components/custom/button-icon.vue')['default']
ColumnEditDrawer: typeof import('../views/table/codet/components/ColumnEditDrawer.vue')['default']
ColumnSettings: typeof import('../views/table/codet/components/ColumnSettings.vue')['default']
CountTo: typeof import('./../components/custom/count-to.vue')['default'] CountTo: typeof import('./../components/custom/count-to.vue')['default']
CreateDialog: typeof import('../views/table/codet/components/CreateDialog.vue')['default']
DarkModeContainer: typeof import('./../components/common/dark-mode-container.vue')['default'] DarkModeContainer: typeof import('./../components/common/dark-mode-container.vue')['default']
DataTable: typeof import('../views/table/codet/components/DataTable.vue')['default']
DataTransform: typeof import('../views/table/codet/components/DataTransform.vue')['default']
ExceptionBase: typeof import('./../components/common/exception-base.vue')['default'] ExceptionBase: typeof import('./../components/common/exception-base.vue')['default']
FullScreen: typeof import('./../components/common/full-screen.vue')['default'] FullScreen: typeof import('./../components/common/full-screen.vue')['default']
IconAntDesignEnterOutlined: typeof import('~icons/ant-design/enter-outlined')['default'] IconAntDesignEnterOutlined: typeof import('~icons/ant-design/enter-outlined')['default']
...@@ -27,12 +33,16 @@ declare module 'vue' { ...@@ -27,12 +33,16 @@ declare module 'vue' {
LangSwitch: typeof import('./../components/common/lang-switch.vue')['default'] LangSwitch: typeof import('./../components/common/lang-switch.vue')['default']
LookForward: typeof import('./../components/custom/look-forward.vue')['default'] LookForward: typeof import('./../components/custom/look-forward.vue')['default']
MenuToggler: typeof import('./../components/common/menu-toggler.vue')['default'] MenuToggler: typeof import('./../components/common/menu-toggler.vue')['default']
NAlert: typeof import('naive-ui')['NAlert']
NBreadcrumb: typeof import('naive-ui')['NBreadcrumb'] NBreadcrumb: typeof import('naive-ui')['NBreadcrumb']
NBreadcrumbItem: typeof import('naive-ui')['NBreadcrumbItem'] NBreadcrumbItem: typeof import('naive-ui')['NBreadcrumbItem']
NButton: typeof import('naive-ui')['NButton'] NButton: typeof import('naive-ui')['NButton']
NCard: typeof import('naive-ui')['NCard'] NCard: typeof import('naive-ui')['NCard']
NCheckbox: typeof import('naive-ui')['NCheckbox'] NCheckbox: typeof import('naive-ui')['NCheckbox']
NCheckboxGroup: typeof import('naive-ui')['NCheckboxGroup']
NColorPicker: typeof import('naive-ui')['NColorPicker'] NColorPicker: typeof import('naive-ui')['NColorPicker']
NDataTable: typeof import('naive-ui')['NDataTable']
NDatePicker: typeof import('naive-ui')['NDatePicker']
NDialogProvider: typeof import('naive-ui')['NDialogProvider'] NDialogProvider: typeof import('naive-ui')['NDialogProvider']
NDivider: typeof import('naive-ui')['NDivider'] NDivider: typeof import('naive-ui')['NDivider']
NDrawer: typeof import('naive-ui')['NDrawer'] NDrawer: typeof import('naive-ui')['NDrawer']
...@@ -43,6 +53,8 @@ declare module 'vue' { ...@@ -43,6 +53,8 @@ declare module 'vue' {
NFormItem: typeof import('naive-ui')['NFormItem'] NFormItem: typeof import('naive-ui')['NFormItem']
NGi: typeof import('naive-ui')['NGi'] NGi: typeof import('naive-ui')['NGi']
NGrid: typeof import('naive-ui')['NGrid'] NGrid: typeof import('naive-ui')['NGrid']
NGridItem: typeof import('naive-ui')['NGridItem']
NIcon: typeof import('naive-ui')['NIcon']
NInput: typeof import('naive-ui')['NInput'] NInput: typeof import('naive-ui')['NInput']
NInputGroup: typeof import('naive-ui')['NInputGroup'] NInputGroup: typeof import('naive-ui')['NInputGroup']
NInputNumber: typeof import('naive-ui')['NInputNumber'] NInputNumber: typeof import('naive-ui')['NInputNumber']
...@@ -51,24 +63,34 @@ declare module 'vue' { ...@@ -51,24 +63,34 @@ declare module 'vue' {
NMessageProvider: typeof import('naive-ui')['NMessageProvider'] NMessageProvider: typeof import('naive-ui')['NMessageProvider']
NModal: typeof import('naive-ui')['NModal'] NModal: typeof import('naive-ui')['NModal']
NNotificationProvider: typeof import('naive-ui')['NNotificationProvider'] NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
NRadioButton: typeof import('naive-ui')['NRadioButton']
NRadioGroup: typeof import('naive-ui')['NRadioGroup']
NScrollbar: typeof import('naive-ui')['NScrollbar'] NScrollbar: typeof import('naive-ui')['NScrollbar']
NSelect: typeof import('naive-ui')['NSelect'] NSelect: typeof import('naive-ui')['NSelect']
NSpace: typeof import('naive-ui')['NSpace'] NSpace: typeof import('naive-ui')['NSpace']
NSpin: typeof import('naive-ui')['NSpin']
NStatistic: typeof import('naive-ui')['NStatistic'] NStatistic: typeof import('naive-ui')['NStatistic']
NSwitch: typeof import('naive-ui')['NSwitch'] NSwitch: typeof import('naive-ui')['NSwitch']
NTab: typeof import('naive-ui')['NTab'] NTab: typeof import('naive-ui')['NTab']
NTabPane: typeof import('naive-ui')['NTabPane']
NTabs: typeof import('naive-ui')['NTabs'] NTabs: typeof import('naive-ui')['NTabs']
NText: typeof import('naive-ui')['NText']
NTooltip: typeof import('naive-ui')['NTooltip'] NTooltip: typeof import('naive-ui')['NTooltip']
NWatermark: typeof import('naive-ui')['NWatermark'] NWatermark: typeof import('naive-ui')['NWatermark']
PinToggler: typeof import('./../components/common/pin-toggler.vue')['default'] PinToggler: typeof import('./../components/common/pin-toggler.vue')['default']
ReloadButton: typeof import('./../components/common/reload-button.vue')['default'] ReloadButton: typeof import('./../components/common/reload-button.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
SearchFieldEditDrawer: typeof import('../views/table/codet/components/SearchFieldEditDrawer.vue')['default']
SearchFieldSettings: typeof import('../views/table/codet/components/SearchFieldSettings.vue')['default']
SearchForm: typeof import('../views/table/codet/components/SearchForm.vue')['default']
SoybeanAvatar: typeof import('./../components/custom/soybean-avatar.vue')['default'] SoybeanAvatar: typeof import('./../components/custom/soybean-avatar.vue')['default']
SvgIcon: typeof import('./../components/custom/svg-icon.vue')['default'] SvgIcon: typeof import('./../components/custom/svg-icon.vue')['default']
SystemLogo: typeof import('./../components/common/system-logo.vue')['default'] SystemLogo: typeof import('./../components/common/system-logo.vue')['default']
TableBasicSettings: typeof import('../views/table/codet/components/TableBasicSettings.vue')['default']
TableColumnSetting: typeof import('./../components/advanced/table-column-setting.vue')['default'] TableColumnSetting: typeof import('./../components/advanced/table-column-setting.vue')['default']
TableHeaderOperation: typeof import('./../components/advanced/table-header-operation.vue')['default'] TableHeaderOperation: typeof import('./../components/advanced/table-header-operation.vue')['default']
TableSettingsDrawer: typeof import('../views/table/codet/components/TableSettingsDrawer.vue')['default']
ThemeSchemaSwitch: typeof import('./../components/common/theme-schema-switch.vue')['default'] ThemeSchemaSwitch: typeof import('./../components/common/theme-schema-switch.vue')['default']
WaveBg: typeof import('./../components/custom/wave-bg.vue')['default'] WaveBg: typeof import('./../components/custom/wave-bg.vue')['default']
} }
......
...@@ -37,6 +37,7 @@ declare module "@elegant-router/types" { ...@@ -37,6 +37,7 @@ declare module "@elegant-router/types" {
"home": "/home"; "home": "/home";
"iframe-page": "/iframe-page/:url"; "iframe-page": "/iframe-page/:url";
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?"; "login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?";
"tablecomponent": "/tablecomponent";
}; };
/** /**
...@@ -88,6 +89,7 @@ declare module "@elegant-router/types" { ...@@ -88,6 +89,7 @@ declare module "@elegant-router/types" {
| "home" | "home"
| "iframe-page" | "iframe-page"
| "login" | "login"
| "tablecomponent"
>; >;
/** /**
...@@ -113,6 +115,7 @@ declare module "@elegant-router/types" { ...@@ -113,6 +115,7 @@ declare module "@elegant-router/types" {
| "login" | "login"
| "chat" | "chat"
| "home" | "home"
| "tablecomponent"
>; >;
/** /**
......
...@@ -11,9 +11,7 @@ import { ...@@ -11,9 +11,7 @@ import {
} from 'vue'; } from 'vue';
import { NConfigProvider, darkTheme } from 'naive-ui'; import { NConfigProvider, darkTheme } from 'naive-ui';
import * as naive from 'naive-ui'; import * as naive from 'naive-ui';
import axios from 'axios'; // 这些库已在 main.ts 中全局注册,这里不需要重复导入
import * as echarts from 'echarts/core';
import WangEditor from 'wangeditor';
import { useThemeStore } from '@/store/modules/theme'; import { useThemeStore } from '@/store/modules/theme';
// 引入echarts相关 // 引入echarts相关
import { useEcharts } from '@/hooks/common/echarts'; import { useEcharts } from '@/hooks/common/echarts';
...@@ -44,23 +42,18 @@ Object.keys(naive).forEach(key => { ...@@ -44,23 +42,18 @@ Object.keys(naive).forEach(key => {
// 添加类型声明 // 添加类型声明
declare global { declare global {
interface Window { interface Window {
$axios: typeof axios; $axios: any;
$echarts: typeof echarts; $echarts: any;
$useEcharts: typeof useEcharts; $useEcharts: typeof useEcharts;
$themeStore: typeof themeStore; $themeStore: typeof themeStore;
$WangEditor: typeof WangEditor; $WangEditor: any;
} }
} }
// 全局注入axios // axios, echarts, WangEditor 已在 main.ts 中全局注册
(window as any).$axios = axios; // 这里只需要注册组件特有的工具
// 全局注入echarts和useEcharts
(window as any).$echarts = echarts;
(window as any).$useEcharts = useEcharts; (window as any).$useEcharts = useEcharts;
// 全局注入主题存储
(window as any).$themeStore = themeStore; (window as any).$themeStore = themeStore;
// 全局注入WangEditor
(window as any).$WangEditor = WangEditor;
// 清理函数 - 完全销毁Vue组件 // 清理函数 - 完全销毁Vue组件
function cleanup() { function cleanup() {
...@@ -75,8 +68,8 @@ function cleanup() { ...@@ -75,8 +68,8 @@ function cleanup() {
} }
// 清理编辑器实例 // 清理编辑器实例
const editor = (window as any).$WangEditor?.getInstance(); const editor = (window as any).$WangEditor?.getInstance?.();
if (editor) { if (editor && typeof editor.destroy === 'function') {
editor.destroy(); editor.destroy();
} }
} catch (e) { } catch (e) {
......
<script setup lang="ts">
import { inject } from 'vue';
// 从主组件注入状态和方法
const tableState: any = inject('tableState');
const tableMethods: any = inject('tableMethods');
const { showAddFieldDrawer, selectedColumns, availableColumns } = tableState;
const { confirmAddFields } = tableMethods;
defineOptions({
name: 'AddFieldDrawer'
});
</script>
<template>
<NDrawer v-model:show="showAddFieldDrawer" :width="400" placement="right">
<NDrawerContent title="添加搜索字段">
<div class="add-field-content">
<NAlert type="info" :show-icon="true" class="mb-4">请选择要添加为搜索条件的字段</NAlert>
<div class="field-select-list">
<NScrollbar style="max-height: calc(100vh - 250px)">
<NCheckboxGroup v-model:value="selectedColumns">
<div v-for="column in availableColumns" :key="column.key" class="field-select-item">
<NCheckbox :value="column.key">
<span class="field-select-label">{{ column.title }}</span>
<span class="field-select-key">({{ column.key }})</span>
</NCheckbox>
</div>
</NCheckboxGroup>
</NScrollbar>
</div>
</div>
<template #footer>
<NSpace justify="end">
<NButton @click="showAddFieldDrawer = false">取消</NButton>
<NButton type="primary" :disabled="selectedColumns.length === 0" @click="confirmAddFields">确定</NButton>
</NSpace>
</template>
</NDrawerContent>
</NDrawer>
</template>
<style scoped>
.add-field-content {
padding: 16px;
}
.field-select-list {
margin-top: 16px;
}
.field-select-item {
padding: 8px 0;
border-bottom: 1px solid var(--n-border-color);
}
.field-select-item:last-child {
border-bottom: none;
}
.field-select-label {
font-size: 14px;
color: var(--n-text-color);
}
.field-select-key {
font-size: 12px;
color: var(--n-text-color-3);
margin-left: 8px;
}
.mb-4 {
margin-bottom: 16px;
}
</style>
<script setup lang="ts">
import { inject } from 'vue';
// 从主组件注入状态和方法
const tableState: any = inject('tableState');
const tableMethods: any = inject('tableMethods');
const { showEditDrawer, currentEditColumn, isIndexColumn, newFilterLabel, newFilterValue } = tableState;
const { saveColumnEdit, addFilterOption, removeFilterOption, generateFilterOptions } = tableMethods;
defineOptions({
name: 'ColumnEditDrawer'
});
</script>
<template>
<NDrawer v-model:show="showEditDrawer" :width="400" placement="right">
<NDrawerContent title="编辑列">
<NForm label-placement="left" label-width="100" label-align="left">
<NFormItem label="显示名称">
<NInput
:value="currentEditColumn?.title"
:disabled="!currentEditColumn"
@update:value="val => currentEditColumn && (currentEditColumn.title = val)"
></NInput>
</NFormItem>
<NFormItem label="字段名">
<NInput :value="currentEditColumn?.key" disabled></NInput>
</NFormItem>
<NFormItem label="表头对齐">
<NRadioGroup
:value="currentEditColumn?.titleAlign"
@update:value="val => currentEditColumn && (currentEditColumn.titleAlign = val)"
>
<NRadioButton value="left">左对齐</NRadioButton>
<NRadioButton value="center">居中</NRadioButton>
<NRadioButton value="right">右对齐</NRadioButton>
</NRadioGroup>
</NFormItem>
<NFormItem label="内容对齐">
<NRadioGroup
:value="currentEditColumn?.align"
@update:value="val => currentEditColumn && (currentEditColumn.align = val)"
>
<NRadioButton value="left">左对齐</NRadioButton>
<NRadioButton value="center">居中</NRadioButton>
<NRadioButton value="right">右对齐</NRadioButton>
</NRadioGroup>
</NFormItem>
<!-- 只在非 index 字段时显示排序开关 -->
<NFormItem v-if="!isIndexColumn" label="开启排序">
<NSwitch
:value="currentEditColumn?.sortable"
@update:value="val => currentEditColumn && (currentEditColumn.sortable = val)"
></NSwitch>
</NFormItem>
<!-- 添加筛选功能相关配置 -->
<NFormItem v-if="!isIndexColumn" label="开启筛选">
<NSwitch
:value="!!currentEditColumn?.filter"
@update:value="
val => {
if (currentEditColumn) {
if (val) {
// 启用筛选时,初始化筛选相关属性
currentEditColumn.filter = true;
currentEditColumn.filterOptions = currentEditColumn.filterOptions || [];
} else {
// 禁用筛选时,清除筛选相关属性
delete currentEditColumn.filter;
delete currentEditColumn.filterOptions;
}
}
}
"
></NSwitch>
</NFormItem>
<!-- 筛选选项管理,仅在开启筛选时显示 -->
<template v-if="currentEditColumn?.filter">
<NDivider>筛选选项管理</NDivider>
<NFormItem label="自动获取选项">
<NButton size="small" @click="generateFilterOptions(currentEditColumn)">从当前数据生成选项</NButton>
</NFormItem>
<!-- 添加新筛选选项 -->
<NSpace vertical>
<NInputGroup>
<NInput v-model:value="newFilterLabel" placeholder="显示文本"></NInput>
<NInput v-model:value="newFilterValue" placeholder="筛选值"></NInput>
<NButton type="primary" :disabled="!newFilterLabel || !newFilterValue" @click="addFilterOption">
添加
</NButton>
</NInputGroup>
</NSpace>
<!-- 筛选选项列表 -->
<NSpace vertical style="margin-top: 12px; max-height: 200px; overflow-y: auto">
<div
v-for="(option, index) in currentEditColumn.filterOptions"
:key="index"
style="display: flex; justify-content: space-between; align-items: center; padding: 4px 0"
>
<span>{{ option.label }}</span>
<NButton text type="error" @click="removeFilterOption(index)">
<template #icon>
<NIcon>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"
fill="currentColor"
/>
</svg>
</NIcon>
</template>
</NButton>
</div>
</NSpace>
</template>
<!-- 添加 ellipsis 开关 -->
<NFormItem v-if="!isIndexColumn" label="文本省略">
<NSwitch
:value="!!currentEditColumn?.ellipsis"
@update:value="
val => {
if (currentEditColumn) {
if (val) {
currentEditColumn.ellipsis = { tooltip: true };
} else {
delete currentEditColumn.ellipsis;
}
}
}
"
></NSwitch>
</NFormItem>
<!-- 只在启用 ellipsis 时显示 tooltip 开关 -->
<NFormItem v-if="currentEditColumn?.ellipsis" label="显示tooltip">
<NSwitch
:value="currentEditColumn?.ellipsis?.tooltip"
@update:value="
val => {
if (currentEditColumn?.ellipsis) {
currentEditColumn.ellipsis.tooltip = val;
}
}
"
></NSwitch>
</NFormItem>
</NForm>
<template #footer>
<NSpace justify="end">
<NButton @click="showEditDrawer = false">取消</NButton>
<NButton type="primary" :disabled="!currentEditColumn" @click="saveColumnEdit">保存</NButton>
</NSpace>
</template>
</NDrawerContent>
</NDrawer>
</template>
<style scoped>
:deep(.n-drawer .n-form-item) {
margin-bottom: 16px;
}
:deep(.n-drawer .n-radio-group) {
width: 100%;
display: flex;
gap: 8px;
}
:deep(.n-drawer .n-radio-button) {
flex: 1;
text-align: center;
}
.n-input-group {
display: flex;
gap: 8px;
}
.n-input-group .n-input {
flex: 1;
}
.n-divider {
margin: 16px 0;
}
</style>
<script setup lang="ts">
import { inject } from 'vue';
// 从主组件注入状态和方法
const tableState: any = inject('tableState');
const tableMethods: any = inject('tableMethods');
const { filteredColumns, visibleColumns, columnSearchText } = tableState;
const {
handleColumnVisibleChange,
clearColumnSearch,
handleEditColumn,
handleDragStart,
handleDragOver,
handleDrop,
handleSetSettings
} = tableMethods;
// 添加拖拽完成后的保存处理
const handleDragEnd = () => {
// 触发配置保存
if (handleSetSettings) {
handleSetSettings();
}
};
defineOptions({
name: 'ColumnSettings'
});
</script>
<template>
<div>
<div class="columns-header">
<span>显示字段</span>
<span>显示 {{ visibleColumns.length }}</span>
</div>
<div class="columns-search">
<NInput v-model:value="columnSearchText" placeholder="搜索列" clearable @clear="clearColumnSearch">
<template #prefix>
<NIcon>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
<path
d="M15.5 14h-.79l-.28-.27a6.5 6.5 0 1 0-.7.7l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0A4.5 4.5 0 1 1 14 9.5A4.5 4.5 0 0 1 9.5 14z"
fill="currentColor"
/>
</svg>
</NIcon>
</template>
</NInput>
</div>
<div class="columns-list">
<NScrollbar style="max-height: calc(100vh - 200px)">
<div class="columns-container">
<div
v-for="(column, index) in filteredColumns"
:key="column.key"
class="column-item"
draggable="true"
@dragstart="handleDragStart($event, index)"
@dragover="handleDragOver"
@drop="handleDrop($event, index)"
@dragend="handleDragEnd"
>
<div class="column-item-left">
<NIcon class="column-drag-handle">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
<path d="M8 18h8v-2H8v2zm0-4h8v-2H8v2zm0-4h8V8H8v2zm0-4h8V4H8v2z" fill="currentColor" />
</svg>
</NIcon>
<NSwitch
:value="visibleColumns.includes(column.key)"
size="small"
@update:value="checked => handleColumnVisibleChange(checked, column)"
></NSwitch>
</div>
<div class="column-item-content">
<span class="column-title">{{ column.title }}</span>
<span class="column-key">({{ column.key }})</span>
</div>
<div class="column-item-right">
<NButton text @click="handleEditColumn(column)">
<template #icon>
<NIcon>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 24 24"
>
<g fill="none">
<path
d="M3 17.75A3.25 3.25 0 0 0 6.25 21h4.915l.356-1.423l.02-.077H6.25a1.75 1.75 0 0 1-1.75-1.75V11h3.25l.184-.005A3.25 3.25 0 0 0 11 7.75V4.5h6.75c.966 0 1.75.784 1.75 1.75v4.982c.479-.19.994-.263 1.5-.22V6.25A3.25 3.25 0 0 0 17.75 3h-6.879a2.25 2.25 0 0 0-1.59.659L3.658 9.28A2.25 2.25 0 0 0 3 10.871v6.879zM7.75 9.5H5.561L9.5 5.561V7.75l-.006.144A1.75 1.75 0 0 1 7.75 9.5zm11.35 3.17l-5.903 5.902a2.686 2.686 0 0 0-.706 1.247l-.458 1.831a1.087 1.087 0 0 0 1.319 1.318l1.83-.457a2.685 2.685 0 0 0 1.248-.707l5.902-5.902A2.286 2.286 0 0 0 19.1 12.67z"
fill="currentColor"
></path>
</g>
</svg>
</NIcon>
</template>
</NButton>
</div>
</div>
</div>
</NScrollbar>
</div>
</div>
</template>
<style scoped>
.columns-header {
padding: 0 16px 12px;
margin: 0;
flex-shrink: 0;
display: flex;
justify-content: space-between;
}
.columns-search {
padding: 0 16px 12px;
flex-shrink: 0;
}
.columns-list {
flex: 1;
overflow: hidden;
}
.columns-container {
display: flex;
flex-direction: column;
}
.column-item {
padding: 8px 16px;
min-height: 40px;
box-sizing: border-box;
display: flex;
border-bottom: 1px solid var(--n-border-color);
align-items: center;
}
.column-item-left {
display: flex;
align-items: center;
gap: 12px;
}
.column-drag-handle {
cursor: move;
color: var(--n-text-color-3);
}
.column-item-content {
display: flex;
align-items: center;
gap: 8px;
flex: 1;
margin-left: 12px;
}
.column-title {
font-size: 12px;
color: var(--n-text-color);
}
.column-key {
font-size: 12px;
color: var(--n-text-color-3);
}
.column-item-right {
opacity: 0;
transition: opacity 0.3s;
margin-left: auto;
}
.column-item:hover .column-item-right {
opacity: 1;
}
.columns-search :deep(.n-input) {
--n-height: 32px;
}
.columns-search :deep(.n-input-wrapper) {
background-color: var(--n-card-color);
}
.columns-search :deep(.n-input__prefix) {
margin-right: 8px;
}
.columns-search :deep(.n-icon) {
font-size: 16px;
color: var(--n-text-color-3);
}
</style>
<script setup lang="ts">
import { defineAsyncComponent, inject, ref } from 'vue';
// 从主组件注入状态
const tableState: any = inject('tableState');
const tableMethods: any = inject('tableMethods');
const { uiConfig } = tableState;
const showDialog = ref(false);
// 添加当前编辑的行数据
const currentRow = ref<any>(null);
const isEditMode = ref(false);
// 动态加载组件
const DynamicComponent = defineAsyncComponent(() => import(uiConfig.CreateVueUrl));
// 处理子组件关闭事件
const handleClose = () => {
// console.log('关闭弹窗');
showDialog.value = false;
// 重置状态
currentRow.value = null;
isEditMode.value = false;
// 刷新表格数据
tableMethods.fetchData();
};
// 处理子组件提交事件
const handleSubmit = () => {
// console.log('提交表单');
showDialog.value = false;
// 重置状态
currentRow.value = null;
isEditMode.value = false;
// 刷新表格数据
tableMethods.fetchData();
};
// 打开弹窗的方法
const open = (row?: any) => {
// 如果传入了row参数,则表示是编辑模式
if (row) {
currentRow.value = row;
isEditMode.value = true;
// console.log('打开编辑模式', row);
} else {
currentRow.value = null;
isEditMode.value = false;
// console.log('打开新建模式');
}
showDialog.value = true;
};
// 暴露方法给父组件
defineExpose({
open
});
defineOptions({
name: 'CreateDialog'
});
</script>
<template>
<NModal
:show="showDialog"
preset="card"
style="width: 90%; max-width: 1200px"
:mask-closable="false"
@update:show="showDialog = $event"
>
<template #header>
<div class="dialog-header">
<span>{{ isEditMode ? '编辑' : '新建' }}</span>
</div>
</template>
<div class="dialog-content">
<DynamicComponent
v-if="showDialog"
:edit-data="currentRow"
:is-edit="isEditMode"
@close="handleClose"
@submit="handleSubmit"
/>
</div>
</NModal>
</template>
<style scoped>
.dialog-header {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}
.dialog-content {
width: 100%;
height: 100%;
}
</style>
<script setup lang="ts">
import { inject } from 'vue';
// 从主组件注入状态和方法
const tableState: any = inject('tableState');
const tableMethods: any = inject('tableMethods');
// 获取表格数据和列
const { tagMappings, transformRules, selectedField, availableFields } = tableState;
// 颜色选项
const colorOptions = [
{ label: '默认', value: 'default' },
{ label: '主要', value: 'primary' },
{ label: '信息', value: 'info' },
{ label: '成功', value: 'success' },
{ label: '警告', value: 'warning' },
{ label: '错误', value: 'error' }
];
// 添加/删除映射规则
const addTagMapping = () => {
tableMethods.addTagMapping();
};
const removeTagMapping = (index: number) => {
tableMethods.removeTagMapping(index);
};
// 添加转换规则
const addTransformRule = () => {
if (!selectedField.value) return;
// 过滤掉空值映射
const validMappings = tagMappings.value.filter((mapping: any) => mapping.value !== '' && mapping.label !== '');
if (validMappings.length === 0) {
window.$message?.error('请添加至少一个有效的标记映射');
return;
}
tableMethods.addTransformRule({
field: selectedField.value,
fieldLabel: availableFields.value.find((f: any) => f.value === selectedField.value)?.label || selectedField.value,
type: 'tag',
typeLabel: '转换标记',
params: { mappings: validMappings }
});
// 重置输入
selectedField.value = '';
tagMappings.value = [{ value: '', label: '', color: '' }];
};
// 移除转换规则
const removeTransformRule = (index: number) => {
tableMethods.removeTransformRule(index);
};
// 应用转换规则
const applyTransforms = () => {
tableMethods.applyTransformations();
};
// 重置数据转换
const resetData = () => {
// 清除所有转换规则
transformRules.value = [];
// 重新获取数据
tableMethods.fetchData();
window.$message?.success('数据已重置');
};
// 暴露方法给父组件
defineExpose({
transformRules,
applyTransforms,
resetData
});
defineOptions({
name: 'DataTransform'
});
</script>
<template>
<div class="data-transform-container">
<h3>数据转换设置</h3>
<div class="transform-form">
<div class="form-row">
<div class="form-item">
<label>字段名</label>
<NSelect v-model:value="selectedField" :options="availableFields" placeholder="请选择字段" />
</div>
</div>
<!-- 标记转换参数 -->
<div class="param-section">
<h4>转换内容</h4>
<div v-for="(mapping, index) in tagMappings" :key="index" class="mapping-item">
<div class="mapping-row">
<div class="mapping-field">
<label>Name</label>
<NInput v-model:value="mapping.value" placeholder="表格值" />
</div>
<div class="mapping-field">
<label>Value</label>
<NInput v-model:value="mapping.label" placeholder="显示文本" />
</div>
<div class="mapping-field">
<label>颜色</label>
<NSelect v-model:value="mapping.color" :options="colorOptions" placeholder="选择颜色" />
</div>
<NButton
circle
type="error"
size="small"
class="remove-btn"
:disabled="tagMappings.length === 1"
@click="removeTagMapping(index)"
>
<span>-</span>
</NButton>
</div>
</div>
<div class="add-mapping">
<NButton circle type="primary" size="small" class="add-btn" @click="addTagMapping">
<span>+</span>
</NButton>
</div>
</div>
<div class="button-row">
<NButton type="primary" :disabled="!selectedField" @click="addTransformRule">添加规则</NButton>
</div>
<div v-if="transformRules.length > 0" class="rules-list">
<h4>转换规则列表</h4>
<div v-for="(rule, index) in transformRules" :key="index" class="rule-item">
<div class="rule-content">
<span class="field-name">{{ rule.fieldLabel }}</span>
<span class="transform-arrow"></span>
<span class="transform-type">{{ rule.typeLabel }}</span>
</div>
<NButton size="small" type="error" @click="removeTransformRule(index)">删除</NButton>
</div>
<div class="action-buttons">
<NButton type="primary" :disabled="transformRules.length === 0" @click="applyTransforms">应用转换</NButton>
<NButton @click="resetData">重置数据</NButton>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.data-transform-container {
padding: 16px;
height: 100%;
overflow-y: auto;
}
.transform-form {
margin-top: 16px;
display: flex;
flex-direction: column;
gap: 16px;
}
.form-row {
display: flex;
gap: 12px;
}
.form-item {
flex: 1;
display: flex;
flex-direction: column;
gap: 4px;
}
.param-section {
border: 1px solid #eee;
border-radius: 4px;
padding: 12px;
}
.param-section h4 {
margin-top: 0;
margin-bottom: 12px;
color: #666;
}
.button-row {
display: flex;
justify-content: flex-end;
margin-top: 16px;
}
.rules-list {
margin-top: 24px;
border-top: 1px solid #eee;
padding-top: 16px;
}
.rule-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 12px;
background-color: #f8f8f8;
border-radius: 4px;
margin-bottom: 8px;
}
.rule-content {
display: flex;
align-items: center;
gap: 8px;
}
.field-name {
font-weight: 500;
}
.transform-arrow {
color: #666;
}
.transform-type {
color: #2080f0;
}
.action-buttons {
display: flex;
gap: 12px;
margin-top: 16px;
}
.mapping-item {
margin-bottom: 12px;
padding-bottom: 12px;
border-bottom: 1px dashed #eee;
}
.mapping-row {
display: flex;
gap: 8px;
align-items: flex-end;
}
.mapping-field {
flex: 1;
display: flex;
flex-direction: column;
gap: 4px;
}
.remove-btn {
margin-bottom: 4px;
}
.add-mapping {
display: flex;
justify-content: center;
margin-top: 8px;
}
</style>
<script setup lang="ts">
import { inject } from 'vue';
// 从主组件注入状态和方法
const tableState: any = inject('tableState');
const tableMethods: any = inject('tableMethods');
const { showSearchFieldDrawer, currentSearchField, newOptionKey, newOptionValue } = tableState;
const { saveSearchField, addOption, removeOption } = tableMethods;
defineOptions({
name: 'SearchFieldEditDrawer'
});
</script>
<template>
<NDrawer v-model:show="showSearchFieldDrawer" :width="400" placement="right">
<NDrawerContent title="编辑搜索字段">
<NForm ref="searchFieldForm" :model="currentSearchField" label-placement="left" label-width="100">
<NFormItem label="显示名称" path="label">
<NInput v-model:value="currentSearchField.label" placeholder="请输入显示名称"></NInput>
</NFormItem>
<NFormItem label="字段名" path="key">
<NInput v-model:value="currentSearchField.key" disabled></NInput>
</NFormItem>
<NFormItem label="控件类型" path="type">
<NSelect
v-model:value="currentSearchField.type"
:options="[
{ label: '输入框', value: 'input' },
{ label: '下拉选择', value: 'select' },
{ label: '日期选择', value: 'date' },
{ label: '数字范围', value: 'number-range' }
]"
></NSelect>
</NFormItem>
<NFormItem label="占位提示" path="placeholder">
<NInput v-model:value="currentSearchField.placeholder" placeholder="请输入占位提示"></NInput>
</NFormItem>
<NFormItem label="默认值" path="defaultValue">
<NInput v-model:value="currentSearchField.defaultValue" placeholder="请输入默认值"></NInput>
</NFormItem>
<!-- 当类型为 select 时显示选项配置 -->
<template v-if="currentSearchField.type === 'select'">
<NDivider>选项配置</NDivider>
<!-- 添加新选项的输入框 -->
<NSpace vertical>
<NInputGroup>
<NInput v-model:value="newOptionKey" placeholder="选项名称"></NInput>
<NInput v-model:value="newOptionValue" placeholder="选项值"></NInput>
<NButton type="primary" :disabled="!newOptionKey || !newOptionValue" @click="addOption">添加</NButton>
</NInputGroup>
</NSpace>
<!-- 已添加选项列表 -->
<NSpace vertical style="margin-top: 12px">
<div
v-for="(option, index) in currentSearchField.options"
:key="index"
style="display: flex; justify-content: space-between; align-items: center"
>
<span>{{ option.label }} - {{ option.value }}</span>
<NButton text type="error" @click="removeOption(index)">
<template #icon>
<NIcon>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"
fill="currentColor"
/>
</svg>
</NIcon>
</template>
</NButton>
</div>
</NSpace>
</template>
</NForm>
<template #footer>
<NSpace justify="end">
<NButton @click="showSearchFieldDrawer = false">取消</NButton>
<NButton type="primary" @click="saveSearchField">保存</NButton>
</NSpace>
</template>
</NDrawerContent>
</NDrawer>
</template>
<style scoped>
.n-input-group {
display: flex;
gap: 8px;
}
.n-input-group .n-input {
flex: 1;
}
.n-divider {
margin: 16px 0;
}
</style>
<script setup lang="ts">
import { inject } from 'vue';
// 从主组件注入状态和方法
const tableState: any = inject('tableState');
const tableMethods: any = inject('tableMethods');
const { searchFields } = tableState;
defineOptions({
name: 'SearchFieldSettings'
});
const {
addSearchField,
editSearchField,
removeSearchField,
updateFieldVisibility,
handleSearchFieldDragStart,
handleSearchFieldDragOver,
handleSearchFieldDrop
} = tableMethods;
</script>
<template>
<div>
<div class="search-config-header">
<span>搜索字段配置</span>
<NButton size="small" type="primary" @click="addSearchField">添加字段</NButton>
</div>
<div class="search-fields-list">
<NScrollbar style="max-height: calc(100vh - 200px)">
<div class="search-fields-container">
<div
v-for="field in searchFields"
:key="field.key"
class="search-field-item"
draggable="true"
@dragstart="handleSearchFieldDragStart($event, field)"
@dragover="handleSearchFieldDragOver"
@drop="handleSearchFieldDrop($event, field)"
>
<div class="field-item-left">
<NIcon class="field-drag-handle">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M8 18h8v-2H8v2zm0-4h8v-2H8v2zm0-4h8V8H8v2zm0-4h8V4H8v2z" fill="currentColor" />
</svg>
</NIcon>
<NSwitch
:value="field.visible"
size="small"
@update:value="val => updateFieldVisibility(field, val)"
></NSwitch>
</div>
<div class="field-item-content">
<span class="field-label">{{ field.label }}</span>
<span class="field-key">({{ field.key }})</span>
</div>
<div class="field-item-right">
<NButton text @click="editSearchField(field)">
<template #icon>
<NIcon>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04a.996.996 0 0 0 0-1.41l-2.34-2.34a.996.996 0 0 0-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"
fill="currentColor"
/>
</svg>
</NIcon>
</template>
</NButton>
<NButton text @click="removeSearchField(field)">
<template #icon>
<NIcon>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"
fill="currentColor"
/>
</svg>
</NIcon>
</template>
</NButton>
</div>
</div>
</div>
</NScrollbar>
</div>
</div>
</template>
<style scoped>
.search-config-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 16px 12px;
border-bottom: 1px solid var(--n-border-color);
}
.search-fields-container {
padding: 8px 0;
}
.search-field-item {
display: flex;
align-items: center;
padding: 8px 16px;
border-bottom: 1px solid var(--n-border-color);
cursor: move;
}
.field-item-left {
display: flex;
align-items: center;
gap: 12px;
}
.field-drag-handle {
cursor: move;
color: var(--n-text-color-3);
}
.field-item-content {
flex: 1;
margin: 0 12px;
}
.field-label {
font-size: 14px;
color: var(--n-text-color);
}
.field-key {
font-size: 12px;
color: var(--n-text-color-3);
margin-left: 8px;
}
.field-item-right {
display: flex;
gap: 4px;
opacity: 0;
transition: opacity 0.3s;
}
.search-field-item:hover .field-item-right {
opacity: 1;
}
</style>
<script setup lang="ts">
import { inject } from 'vue';
// 从主组件注入状态和方法
const tableState: any = inject('tableState');
const { tableSize, showBorder, showStripe, enableSingleSelect, pagination, tableScrollWidth, tableHeight } = tableState;
</script>
<template>
<div>
<!-- 表格大小设置 -->
<div class="setting-item">
<div class="setting-label">表格的大小</div>
<div class="setting-control">
<NRadioGroup v-model:value="tableSize" name="tableSize" class="size-group" size="small">
<NRadioButton value="small">紧凑</NRadioButton>
<NRadioButton value="medium">默认</NRadioButton>
<NRadioButton value="large">宽松</NRadioButton>
</NRadioGroup>
</div>
</div>
<!-- 表格纵向边框 -->
<div class="setting-item">
<div class="setting-label">表格纵向边框</div>
<div class="setting-control">
<NSwitch v-model:value="showBorder"></NSwitch>
</div>
</div>
<!-- 表格隔行换色 -->
<div class="setting-item">
<div class="setting-label">表格条纹</div>
<div class="setting-control">
<NSpace align="center">
<NSwitch v-model:value="showStripe"></NSwitch>
</NSpace>
</div>
</div>
<!-- 是否开启单选 -->
<div class="setting-item">
<div class="setting-label">是否开启序号</div>
<div class="setting-control">
<NSwitch v-model:value="enableSingleSelect"></NSwitch>
</div>
</div>
<!-- 每页显示条数 -->
<div class="setting-item">
<div class="setting-label">每页显示条数</div>
<div class="setting-control">
<NInputNumber v-model:value="pagination.pageSize"></NInputNumber>
</div>
</div>
<!-- 表格宽度 -->
<div class="setting-item">
<div class="setting-label">表格宽度</div>
<div class="setting-control">
<NInputNumber v-model:value="tableScrollWidth"></NInputNumber>
</div>
</div>
<!-- 表格高度 -->
<div class="setting-item">
<div class="setting-label">表格高度</div>
<div class="setting-control">
<NInputNumber v-model:value="tableHeight"></NInputNumber>
</div>
</div>
</div>
</template>
<style scoped>
.setting-item {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 13px;
padding: 10px 0;
border-bottom: 1px solid var(--n-border-color);
}
.setting-item:last-child {
border-bottom: none;
}
.setting-label {
flex: 0 0 120px;
color: var(--n-text-color-2);
font-size: 14px;
}
.setting-control {
flex: 1;
display: flex;
align-items: center;
justify-content: flex-end;
}
.size-group {
width: 100%;
}
:deep(.n-radio-group) {
display: flex;
gap: 8px;
}
:deep(.n-radio-button) {
flex: 1;
text-align: center;
}
:deep(.n-select),
:deep(.n-input),
:deep(.n-input-number) {
width: 100%;
}
</style>
{
"Offset": 0,
"Total": 10,
"Results": [
{
"OwnerName": "222",
"Name": "333",
"SerialNumber": "1111",
"Type": "Pos",
"CreditLine": 0,
"Amount": 0,
"Currency": "CNY",
"Summary": "",
"Remark": "",
"CreatorKvid": "7F5918CC-E15F-4D7A-B636-1B40A905B744",
"CreatorName": "高源",
"OrganizationKvid": "CC7B3DF9-1B95-46DF-83C5-150587E29612",
"Metadata": {},
"Kvid": "EF1D786D-06F7-43F5-A685-8E13AE0F33BF",
"CreateTime": "2025-05-07T14:30:22.0000000+08:00",
"UpdateTime": "2025-05-13T16:59:38.0000000+08:00",
"Status": 0
},
{
"OwnerName": "xxx",
"Name": "xxx",
"SerialNumber": "xxxx",
"Type": "Cash",
"CreditLine": 0,
"Amount": 0,
"Currency": "USD",
"Summary": "",
"Remark": "",
"CreatorKvid": "7F5918CC-E15F-4D7A-B636-1B40A905B744",
"CreatorName": "高源",
"OrganizationKvid": "CC7B3DF9-1B95-46DF-83C5-150587E29612",
"Metadata": {},
"Kvid": "66B88D4E-A1B9-4E3C-922B-DD5211BA3FB5",
"CreateTime": "2025-05-07T14:26:34.0000000+08:00",
"UpdateTime": "2025-05-13T16:57:05.0000000+08:00",
"Status": 0
},
{
"OwnerName": "1111",
"Name": "222",
"SerialNumber": "333",
"Type": "Pos",
"CreditLine": 0,
"Amount": 0,
"Currency": "CNY",
"Summary": "",
"Remark": "",
"CreatorKvid": "7F5918CC-E15F-4D7A-B636-1B40A905B744",
"CreatorName": "高源",
"OrganizationKvid": "CC7B3DF9-1B95-46DF-83C5-150587E29612",
"Metadata": {},
"Kvid": "97F8DA3B-06AC-4C50-ABEB-430F58B3DD64",
"CreateTime": "2025-05-07T14:30:08.0000000+08:00",
"UpdateTime": "2025-05-07T14:30:08.0000000+08:00",
"Status": 0
},
{
"OwnerName": "11",
"Name": "222",
"SerialNumber": "3",
"Type": "Cash",
"CreditLine": 0,
"Amount": 0,
"Currency": "USD",
"Summary": "",
"Remark": "",
"CreatorKvid": "7F5918CC-E15F-4D7A-B636-1B40A905B744",
"CreatorName": "高源",
"OrganizationKvid": "CC7B3DF9-1B95-46DF-83C5-150587E29612",
"Metadata": {},
"Kvid": "CC255F3E-9F80-4002-B68C-53C5FF86AE52",
"CreateTime": "2025-05-07T14:29:49.0000000+08:00",
"UpdateTime": "2025-05-07T14:29:49.0000000+08:00",
"Status": 0
},
{
"OwnerName": "22",
"Name": "222",
"SerialNumber": "33",
"Type": "AliPay",
"CreditLine": 0,
"Amount": 0,
"Currency": "CNY",
"Summary": "",
"Remark": "",
"CreatorKvid": "7F5918CC-E15F-4D7A-B636-1B40A905B744",
"CreatorName": "高源",
"OrganizationKvid": "CC7B3DF9-1B95-46DF-83C5-150587E29612",
"Metadata": {},
"Kvid": "99C366A3-5867-43D5-B22D-B71E970D9A3C",
"CreateTime": "2025-05-07T14:29:33.0000000+08:00",
"UpdateTime": "2025-05-07T14:29:33.0000000+08:00",
"Status": 0
},
{
"OwnerName": "xxx",
"Name": "111",
"SerialNumber": "2222",
"Type": "Bank",
"CreditLine": 0,
"Amount": 0,
"Currency": "CNY",
"Summary": "",
"Remark": "",
"CreatorKvid": "7F5918CC-E15F-4D7A-B636-1B40A905B744",
"CreatorName": "高源",
"OrganizationKvid": "CC7B3DF9-1B95-46DF-83C5-150587E29612",
"Metadata": {},
"Kvid": "F2475ECC-55BD-49FE-BC00-8822DC846739",
"CreateTime": "2025-05-07T14:29:00.0000000+08:00",
"UpdateTime": "2025-05-07T14:29:00.0000000+08:00",
"Status": 0
},
{
"OwnerName": "7275275",
"Name": "4274272",
"SerialNumber": "41042277",
"Type": "Cash",
"CreditLine": 0,
"Amount": 0,
"Currency": "CNY",
"Summary": "",
"Remark": "",
"CreatorKvid": "7F5918CC-E15F-4D7A-B636-1B40A905B744",
"CreatorName": "高源",
"OrganizationKvid": "CC7B3DF9-1B95-46DF-83C5-150587E29612",
"Metadata": {},
"Kvid": "0C38277C-7BA6-4E9D-BEF5-D43DB49B5EA1",
"CreateTime": "2025-03-27T14:47:54.0000000+08:00",
"UpdateTime": "2025-03-27T14:47:54.0000000+08:00",
"Status": 0
},
{
"OwnerName": "12312322",
"Name": "32131",
"SerialNumber": "2231123",
"Type": "Pos",
"CreditLine": 0,
"Amount": 0,
"Currency": "CNY",
"Summary": "",
"Remark": "",
"CreatorKvid": "7F5918CC-E15F-4D7A-B636-1B40A905B744",
"CreatorName": "高源",
"OrganizationKvid": "CC7B3DF9-1B95-46DF-83C5-150587E29612",
"Metadata": {},
"Kvid": "2A42BDFE-CDED-4300-ADF3-020D1B3E0138",
"CreateTime": "2025-03-27T14:33:13.0000000+08:00",
"UpdateTime": "2025-03-27T14:33:13.0000000+08:00",
"Status": 0
},
{
"OwnerName": "123123",
"Name": "321321",
"SerialNumber": "123132312312",
"Type": "Cash",
"CreditLine": 0,
"Amount": 0,
"Currency": "CNY",
"Summary": "",
"Remark": "",
"CreatorKvid": "7F5918CC-E15F-4D7A-B636-1B40A905B744",
"CreatorName": "高源",
"OrganizationKvid": "CC7B3DF9-1B95-46DF-83C5-150587E29612",
"Metadata": {},
"Kvid": "095872A0-513C-4834-A0C5-BA173F5189A4",
"CreateTime": "2025-03-27T14:29:36.0000000+08:00",
"UpdateTime": "2025-03-27T14:29:36.0000000+08:00",
"Status": 0
},
{
"OwnerName": "12",
"Name": "1212",
"SerialNumber": "12121211",
"Type": "Cash",
"CreditLine": 0,
"Amount": 0,
"Currency": "CNY",
"Summary": "",
"Remark": "",
"CreatorKvid": "7F5918CC-E15F-4D7A-B636-1B40A905B744",
"CreatorName": "高源",
"OrganizationKvid": "CC7B3DF9-1B95-46DF-83C5-150587E29612",
"Metadata": {},
"Kvid": "40D1968B-70A1-49D5-89FD-39943A080D0A",
"CreateTime": "2025-03-27T14:17:12.0000000+08:00",
"UpdateTime": "2025-03-27T14:17:12.0000000+08:00",
"Status": 0
}
]
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment