20260724232121
This commit is contained in:
1 parent
b33c743236
commit
1b86e0043a
10 files changed
+996
-230
No files matched your search
@@ -0,0 +1,383 @@
|
||||
[ 256286ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" row-class-name=fn<rowClassName> ... >
|
||||
at <FmsTable columns= [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object] onUpdate:columns=fn data-source= [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object] ... >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > key="/dashboard:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< null > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
[ 400526ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" style= {--header-row-height: 40px, --row-height: 34px, --footer-row-height: 36px} ... >
|
||||
at <FmsTable ref="tableRef" columns= [Object, Object] data-source= [] ... >
|
||||
at <ModuleI18nPanel key=6 ref_for=true ref="i18nPanelRef" ... >
|
||||
at <RenderComponent render=fn<childrenRender> >
|
||||
at <RenderComponent render= [Object] >
|
||||
at <TabPane key=1 id="vc-tabs-0" prefix-cls="ant-tabs-content" ... >
|
||||
at <Index destroy-on-hidden=undefined id="vc-tabs-0" activeKey="i18n" ... >
|
||||
at <Tabs ref=Ref< Proxy(Object) > direction=undefined getPopupContainer=undefined ... >
|
||||
at <ATabs active-key="i18n" onUpdate:activeKey=fn class="mm-tabs" >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="/system/module-management:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
[ 400883ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" style= {--header-row-height: 40px, --row-height: 34px, --footer-row-height: 36px} ... >
|
||||
at <FmsTable ref="tableRef" columns= [Object, Object, Object, Object] data-source= [] ... >
|
||||
at <ModuleI18nPanel key=6 ref_for=true ref="i18nPanelRef" ... >
|
||||
at <RenderComponent render=fn<childrenRender> >
|
||||
at <RenderComponent render= [Object] >
|
||||
at <TabPane key=1 id="vc-tabs-0" prefix-cls="ant-tabs-content" ... >
|
||||
at <Index destroy-on-hidden=undefined id="vc-tabs-0" activeKey="i18n" ... >
|
||||
at <Tabs ref=Ref< Proxy(Object) > direction=undefined getPopupContainer=undefined ... >
|
||||
at <ATabs active-key="i18n" onUpdate:activeKey=fn class="mm-tabs" >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="/system/module-management:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
[ 400885ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" style= {--header-row-height: 40px, --row-height: 34px, --footer-row-height: 36px} ... >
|
||||
at <FmsTable ref="tableRef" columns= [Object, Object, Object, Object] data-source= [] ... >
|
||||
at <ModuleI18nPanel key=6 ref_for=true ref="i18nPanelRef" ... >
|
||||
at <RenderComponent render=fn<childrenRender> >
|
||||
at <RenderComponent render= [Object] >
|
||||
at <TabPane key=1 id="vc-tabs-0" prefix-cls="ant-tabs-content" ... >
|
||||
at <Index destroy-on-hidden=undefined id="vc-tabs-0" activeKey="i18n" ... >
|
||||
at <Tabs ref=Ref< Proxy(Object) > direction=undefined getPopupContainer=undefined ... >
|
||||
at <ATabs active-key="i18n" onUpdate:activeKey=fn class="mm-tabs" >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="/system/module-management:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
[ 412143ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" style= {--header-row-height: 40px, --row-height: 34px, --footer-row-height: 36px} ... >
|
||||
at <FmsTable ref="tableRef" columns= [Object, Object, Object, Object] data-source= [Object] ... >
|
||||
at <ModuleI18nPanel key=6 ref_for=true ref="i18nPanelRef" ... >
|
||||
at <RenderComponent render=fn<childrenRender> >
|
||||
at <RenderComponent render= [Object] >
|
||||
at <TabPane key=1 id="vc-tabs-0" prefix-cls="ant-tabs-content" ... >
|
||||
at <Index destroy-on-hidden=undefined id="vc-tabs-0" activeKey="i18n" ... >
|
||||
at <Tabs ref=Ref< Proxy(Object) > direction=undefined getPopupContainer=undefined ... >
|
||||
at <ATabs active-key="i18n" onUpdate:activeKey=fn class="mm-tabs" >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="/system/module-management:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
[ 508727ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" style= {--header-row-height: 40px, --row-height: 34px, --footer-row-height: 36px} ... >
|
||||
at <FmsTable ref="tableRef" columns= [Object, Object] data-source= [] ... >
|
||||
at <ModuleI18nPanel key=6 ref_for=true ref="i18nPanelRef" ... >
|
||||
at <RenderComponent render=fn<childrenRender> >
|
||||
at <RenderComponent render= [Object] >
|
||||
at <TabPane key=1 id="vc-tabs-0" prefix-cls="ant-tabs-content" ... >
|
||||
at <Index destroy-on-hidden=undefined id="vc-tabs-0" activeKey="i18n" ... >
|
||||
at <Tabs ref=Ref< Proxy(Object) > direction=undefined getPopupContainer=undefined ... >
|
||||
at <ATabs active-key="i18n" onUpdate:activeKey=fn class="mm-tabs" >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="/system/module-management:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
[ 509065ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" style= {--header-row-height: 40px, --row-height: 34px, --footer-row-height: 36px} ... >
|
||||
at <FmsTable ref="tableRef" columns= [Object, Object, Object, Object] data-source= [] ... >
|
||||
at <ModuleI18nPanel key=6 ref_for=true ref="i18nPanelRef" ... >
|
||||
at <RenderComponent render=fn<childrenRender> >
|
||||
at <RenderComponent render= [Object] >
|
||||
at <TabPane key=1 id="vc-tabs-0" prefix-cls="ant-tabs-content" ... >
|
||||
at <Index destroy-on-hidden=undefined id="vc-tabs-0" activeKey="i18n" ... >
|
||||
at <Tabs ref=Ref< Proxy(Object) > direction=undefined getPopupContainer=undefined ... >
|
||||
at <ATabs active-key="i18n" onUpdate:activeKey=fn class="mm-tabs" >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="/system/module-management:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
[ 509068ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" style= {--header-row-height: 40px, --row-height: 34px, --footer-row-height: 36px} ... >
|
||||
at <FmsTable ref="tableRef" columns= [Object, Object, Object, Object] data-source= [] ... >
|
||||
at <ModuleI18nPanel key=6 ref_for=true ref="i18nPanelRef" ... >
|
||||
at <RenderComponent render=fn<childrenRender> >
|
||||
at <RenderComponent render= [Object] >
|
||||
at <TabPane key=1 id="vc-tabs-0" prefix-cls="ant-tabs-content" ... >
|
||||
at <Index destroy-on-hidden=undefined id="vc-tabs-0" activeKey="i18n" ... >
|
||||
at <Tabs ref=Ref< Proxy(Object) > direction=undefined getPopupContainer=undefined ... >
|
||||
at <ATabs active-key="i18n" onUpdate:activeKey=fn class="mm-tabs" >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="/system/module-management:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
[ 510951ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" style= {--header-row-height: 40px, --row-height: 34px, --footer-row-height: 36px} ... >
|
||||
at <FmsTable ref="tableRef" columns= [Object, Object, Object, Object] data-source= [Object] ... >
|
||||
at <ModuleI18nPanel key=6 ref_for=true ref="i18nPanelRef" ... >
|
||||
at <RenderComponent render=fn<childrenRender> >
|
||||
at <RenderComponent render= [Object] >
|
||||
at <TabPane key=1 id="vc-tabs-0" prefix-cls="ant-tabs-content" ... >
|
||||
at <Index destroy-on-hidden=undefined id="vc-tabs-0" activeKey="i18n" ... >
|
||||
at <Tabs ref=Ref< Proxy(Object) > direction=undefined getPopupContainer=undefined ... >
|
||||
at <ATabs active-key="i18n" onUpdate:activeKey=fn class="mm-tabs" >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="/system/module-management:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
[ 665122ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" style= {--header-row-height: 40px, --row-height: 34px, --footer-row-height: 36px} ... >
|
||||
at <FmsTable ref="tableRef" columns= [Object, Object] data-source= [] ... >
|
||||
at <ModuleI18nPanel key=6 ref_for=true ref="i18nPanelRef" ... >
|
||||
at <RenderComponent render=fn<childrenRender> >
|
||||
at <RenderComponent render= [Object] >
|
||||
at <TabPane key=1 id="vc-tabs-0" prefix-cls="ant-tabs-content" ... >
|
||||
at <Index destroy-on-hidden=undefined id="vc-tabs-0" activeKey="i18n" ... >
|
||||
at <Tabs ref=Ref< Proxy(Object) > direction=undefined getPopupContainer=undefined ... >
|
||||
at <ATabs active-key="i18n" onUpdate:activeKey=fn class="mm-tabs" >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="/system/module-management:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
[ 665466ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" style= {--header-row-height: 40px, --row-height: 34px, --footer-row-height: 36px} ... >
|
||||
at <FmsTable ref="tableRef" columns= [Object, Object, Object, Object] data-source= [] ... >
|
||||
at <ModuleI18nPanel key=6 ref_for=true ref="i18nPanelRef" ... >
|
||||
at <RenderComponent render=fn<childrenRender> >
|
||||
at <RenderComponent render= [Object] >
|
||||
at <TabPane key=1 id="vc-tabs-0" prefix-cls="ant-tabs-content" ... >
|
||||
at <Index destroy-on-hidden=undefined id="vc-tabs-0" activeKey="i18n" ... >
|
||||
at <Tabs ref=Ref< Proxy(Object) > direction=undefined getPopupContainer=undefined ... >
|
||||
at <ATabs active-key="i18n" onUpdate:activeKey=fn class="mm-tabs" >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="/system/module-management:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
[ 665468ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" style= {--header-row-height: 40px, --row-height: 34px, --footer-row-height: 36px} ... >
|
||||
at <FmsTable ref="tableRef" columns= [Object, Object, Object, Object] data-source= [] ... >
|
||||
at <ModuleI18nPanel key=6 ref_for=true ref="i18nPanelRef" ... >
|
||||
at <RenderComponent render=fn<childrenRender> >
|
||||
at <RenderComponent render= [Object] >
|
||||
at <TabPane key=1 id="vc-tabs-0" prefix-cls="ant-tabs-content" ... >
|
||||
at <Index destroy-on-hidden=undefined id="vc-tabs-0" activeKey="i18n" ... >
|
||||
at <Tabs ref=Ref< Proxy(Object) > direction=undefined getPopupContainer=undefined ... >
|
||||
at <ATabs active-key="i18n" onUpdate:activeKey=fn class="mm-tabs" >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="/system/module-management:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
[ 784394ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" style= {--header-row-height: 40px, --row-height: 34px, --footer-row-height: 36px} ... >
|
||||
at <FmsTable ref="tableRef" columns= [Object, Object, Object, Object] data-source= [Object] ... >
|
||||
at <ModuleI18nPanel key=6 ref_for=true ref="i18nPanelRef" ... >
|
||||
at <RenderComponent render=fn<childrenRender> >
|
||||
at <RenderComponent render= [Object] >
|
||||
at <TabPane key=1 id="vc-tabs-0" prefix-cls="ant-tabs-content" ... >
|
||||
at <Index destroy-on-hidden=undefined id="vc-tabs-0" activeKey="i18n" ... >
|
||||
at <Tabs ref=Ref< Proxy(Object) > direction=undefined getPopupContainer=undefined ... >
|
||||
at <ATabs active-key="i18n" onUpdate:activeKey=fn class="mm-tabs" >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="/system/module-management:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
@@ -0,0 +1,263 @@
|
||||
[ 23608ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" row-class-name=fn<rowClassName> ... >
|
||||
at <FmsTable columns= [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object] onUpdate:columns=fn data-source= [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object] ... >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > key="/dashboard:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< null > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
[ 31848ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" style= {--header-row-height: 40px, --row-height: 34px, --footer-row-height: 36px} ... >
|
||||
at <FmsTable ref="tableRef" columns= [Object, Object] data-source= [] ... >
|
||||
at <ModuleI18nPanel key=6 ref_for=true ref="i18nPanelRef" ... >
|
||||
at <RenderComponent render=fn<childrenRender> >
|
||||
at <RenderComponent render= [Object] >
|
||||
at <TabPane key=1 id="vc-tabs-0" prefix-cls="ant-tabs-content" ... >
|
||||
at <Index destroy-on-hidden=undefined id="vc-tabs-0" activeKey="i18n" ... >
|
||||
at <Tabs ref=Ref< Proxy(Object) > direction=undefined getPopupContainer=undefined ... >
|
||||
at <ATabs active-key="i18n" onUpdate:activeKey=fn class="mm-tabs" >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="/system/module-management:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
[ 32185ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" style= {--header-row-height: 40px, --row-height: 34px, --footer-row-height: 36px} ... >
|
||||
at <FmsTable ref="tableRef" columns= [Object, Object, Object, Object] data-source= [] ... >
|
||||
at <ModuleI18nPanel key=6 ref_for=true ref="i18nPanelRef" ... >
|
||||
at <RenderComponent render=fn<childrenRender> >
|
||||
at <RenderComponent render= [Object] >
|
||||
at <TabPane key=1 id="vc-tabs-0" prefix-cls="ant-tabs-content" ... >
|
||||
at <Index destroy-on-hidden=undefined id="vc-tabs-0" activeKey="i18n" ... >
|
||||
at <Tabs ref=Ref< Proxy(Object) > direction=undefined getPopupContainer=undefined ... >
|
||||
at <ATabs active-key="i18n" onUpdate:activeKey=fn class="mm-tabs" >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="/system/module-management:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
[ 32188ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" style= {--header-row-height: 40px, --row-height: 34px, --footer-row-height: 36px} ... >
|
||||
at <FmsTable ref="tableRef" columns= [Object, Object, Object, Object] data-source= [] ... >
|
||||
at <ModuleI18nPanel key=6 ref_for=true ref="i18nPanelRef" ... >
|
||||
at <RenderComponent render=fn<childrenRender> >
|
||||
at <RenderComponent render= [Object] >
|
||||
at <TabPane key=1 id="vc-tabs-0" prefix-cls="ant-tabs-content" ... >
|
||||
at <Index destroy-on-hidden=undefined id="vc-tabs-0" activeKey="i18n" ... >
|
||||
at <Tabs ref=Ref< Proxy(Object) > direction=undefined getPopupContainer=undefined ... >
|
||||
at <ATabs active-key="i18n" onUpdate:activeKey=fn class="mm-tabs" >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="/system/module-management:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
[ 34366ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" style= {--header-row-height: 40px, --row-height: 34px, --footer-row-height: 36px} ... >
|
||||
at <FmsTable ref="tableRef" columns= [Object, Object, Object, Object] data-source= [Object] ... >
|
||||
at <ModuleI18nPanel key=6 ref_for=true ref="i18nPanelRef" ... >
|
||||
at <RenderComponent render=fn<childrenRender> >
|
||||
at <RenderComponent render= [Object] >
|
||||
at <TabPane key=1 id="vc-tabs-0" prefix-cls="ant-tabs-content" ... >
|
||||
at <Index destroy-on-hidden=undefined id="vc-tabs-0" activeKey="i18n" ... >
|
||||
at <Tabs ref=Ref< Proxy(Object) > direction=undefined getPopupContainer=undefined ... >
|
||||
at <ATabs active-key="i18n" onUpdate:activeKey=fn class="mm-tabs" >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="/system/module-management:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
[ 369884ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" style= {--header-row-height: 40px, --row-height: 34px, --footer-row-height: 36px} ... >
|
||||
at <FmsTable ref="tableRef" columns= [Object, Object] data-source= [] ... >
|
||||
at <ModuleI18nPanel key=6 ref_for=true ref="i18nPanelRef" ... >
|
||||
at <RenderComponent render=fn<childrenRender> >
|
||||
at <RenderComponent render= [Object] >
|
||||
at <TabPane key=1 id="vc-tabs-0" prefix-cls="ant-tabs-content" ... >
|
||||
at <Index destroy-on-hidden=undefined id="vc-tabs-0" activeKey="i18n" ... >
|
||||
at <Tabs ref=Ref< Proxy(Object) > direction=undefined getPopupContainer=undefined ... >
|
||||
at <ATabs active-key="i18n" onUpdate:activeKey=fn class="mm-tabs" >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="/system/module-management:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
[ 370225ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" style= {--header-row-height: 40px, --row-height: 34px, --footer-row-height: 36px} ... >
|
||||
at <FmsTable ref="tableRef" columns= [Object, Object, Object, Object] data-source= [] ... >
|
||||
at <ModuleI18nPanel key=6 ref_for=true ref="i18nPanelRef" ... >
|
||||
at <RenderComponent render=fn<childrenRender> >
|
||||
at <RenderComponent render= [Object] >
|
||||
at <TabPane key=1 id="vc-tabs-0" prefix-cls="ant-tabs-content" ... >
|
||||
at <Index destroy-on-hidden=undefined id="vc-tabs-0" activeKey="i18n" ... >
|
||||
at <Tabs ref=Ref< Proxy(Object) > direction=undefined getPopupContainer=undefined ... >
|
||||
at <ATabs active-key="i18n" onUpdate:activeKey=fn class="mm-tabs" >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="/system/module-management:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
[ 370227ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" style= {--header-row-height: 40px, --row-height: 34px, --footer-row-height: 36px} ... >
|
||||
at <FmsTable ref="tableRef" columns= [Object, Object, Object, Object] data-source= [] ... >
|
||||
at <ModuleI18nPanel key=6 ref_for=true ref="i18nPanelRef" ... >
|
||||
at <RenderComponent render=fn<childrenRender> >
|
||||
at <RenderComponent render= [Object] >
|
||||
at <TabPane key=1 id="vc-tabs-0" prefix-cls="ant-tabs-content" ... >
|
||||
at <Index destroy-on-hidden=undefined id="vc-tabs-0" activeKey="i18n" ... >
|
||||
at <Tabs ref=Ref< Proxy(Object) > direction=undefined getPopupContainer=undefined ... >
|
||||
at <ATabs active-key="i18n" onUpdate:activeKey=fn class="mm-tabs" >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="/system/module-management:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
[ 372408ms] [WARNING] [Vue warn]: Invalid prop: type check failed for prop "areaSelection". Expected Boolean, got Object
|
||||
at <StkTable ref="tableRef" class="fms-table" style= {--header-row-height: 40px, --row-height: 34px, --footer-row-height: 36px} ... >
|
||||
at <FmsTable ref="tableRef" columns= [Object, Object, Object, Object] data-source= [Object] ... >
|
||||
at <ModuleI18nPanel key=6 ref_for=true ref="i18nPanelRef" ... >
|
||||
at <RenderComponent render=fn<childrenRender> >
|
||||
at <RenderComponent render= [Object] >
|
||||
at <TabPane key=1 id="vc-tabs-0" prefix-cls="ant-tabs-content" ... >
|
||||
at <Index destroy-on-hidden=undefined id="vc-tabs-0" activeKey="i18n" ... >
|
||||
at <Tabs ref=Ref< Proxy(Object) > direction=undefined getPopupContainer=undefined ... >
|
||||
at <ATabs active-key="i18n" onUpdate:activeKey=fn class="mm-tabs" >
|
||||
at <Index onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > key="/system/module-management:0" >
|
||||
at <KeepAlive>
|
||||
at <BaseTransition mode="out-in" appear=false persisted=false ... >
|
||||
at <Transition name="slide" mode="out-in" >
|
||||
at <RouterView>
|
||||
at <Anonymous hasSider=undefined suffixCls="content" rootClass=undefined ... >
|
||||
at <ALayoutContent class="app-content" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-main" >
|
||||
at <Anonymous hasSider=undefined suffixCls=undefined rootClass=undefined ... >
|
||||
at <ALayout class="app-layout" >
|
||||
at <DefaultLayout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) > >
|
||||
at <RouterView>
|
||||
at <Anonymous message= {} notification= {} >
|
||||
at <AApp>
|
||||
at <Anonymous prefixCls="anticon" csp=undefined layer=undefined ... >
|
||||
at <Anonymous value= {override: Object, hashed: false, theme: Theme, token: Object, components: Object} >
|
||||
at <Anonymous parentContext= {getPrefixCls: , iconPrefixCls: anticon} theme= {} componentDisabled=undefined ... >
|
||||
at <AConfigProvider theme= {} >
|
||||
at <App> @ http://localhost:5180/node_modules/.vite/deps/vue.runtime.esm-bundler-Bqo3P_GY.js?v=b7166b48:1751
|
||||
Whitespace-only changes.
Whitespace-only changes.
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, ref, useSlots } from "vue";
|
||||
import { computed, nextTick, ref, useSlots } from "vue";
|
||||
import { useRafFn, useResizeObserver } from "@vueuse/core";
|
||||
import { StkTable } from "stk-table-vue";
|
||||
import { createActionsCellRenderer } from "./utils/createActionsCellRenderer";
|
||||
@@ -36,148 +36,48 @@ const activeColKey = ref(null);
|
||||
function onStkRowClick(ev, row, data) {
|
||||
const td = ev.target.closest?.("td");
|
||||
activeColKey.value = td?.dataset?.colKey || null;
|
||||
|
||||
// 更新键盘导航的起始位置
|
||||
const rowIndex = props.dataSource.findIndex(
|
||||
(r) => String(getRowKey(r)) === String(getRowKey(row)),
|
||||
);
|
||||
const colIndex = props.columns.findIndex((c) => c.dataIndex === activeColKey.value);
|
||||
if (rowIndex >= 0 && colIndex >= 0) {
|
||||
currentPos.value = { rowIndex, colIndex };
|
||||
}
|
||||
|
||||
emit("row-click", ev, row, data);
|
||||
}
|
||||
|
||||
// ==================== 自定义键盘导航 ====================
|
||||
// StkTable 的 areaSelection keyboard 模式在按键重复(~30Hz)时内部做选区矩形计算、
|
||||
// overlay DOM 操作和虚拟滚动重算——这些不经过我们的 RAF,是 FPS ~12 的根源。
|
||||
// 这里关闭 areaSelection 内置键盘处理,自己接管方向键,只做行/列定位 + RAF 批量化更新。
|
||||
// ==================== 区域选取驱动键盘导航 ====================
|
||||
// 移除自实现的 onTableKeydown 键盘导航,改用 StkTable area-selection 内置键盘导航。
|
||||
// 选区变化(鼠标拖拽 / 方向键 / Ctrl 多选 / Shift 扩选)统一由 area-selection-change
|
||||
// 事件处理:定位当前激活单元格,设置编辑列 activeColKey 并通知父组件切换编辑行。
|
||||
// 选区索引说明见 AreaSelectionRange:index.begin / index.end 为 { row, col } 索引(含两端)。
|
||||
|
||||
const currentPos = ref({ rowIndex: -1, colIndex: -1 });
|
||||
|
||||
let navRafPending = false;
|
||||
let navPendingState = null;
|
||||
|
||||
/** RAF 批量化提交一次导航(activeColKey + row-click emit),每帧至多一次。 */
|
||||
function flushNav() {
|
||||
navRafPending = false;
|
||||
const p = navPendingState;
|
||||
navPendingState = null;
|
||||
if (!p) return;
|
||||
if (activeColKey.value !== p.colKey) {
|
||||
activeColKey.value = p.colKey;
|
||||
function onAreaSelectionChange(ranges) {
|
||||
const range = ranges?.[0];
|
||||
if (!range) {
|
||||
// 选区被清空(如按 Esc)时取消编辑列高亮,但保留当前编辑行
|
||||
activeColKey.value = null;
|
||||
return;
|
||||
}
|
||||
const rowKey = String(getRowKey(p.row));
|
||||
const { begin } = range.index;
|
||||
const row = props.dataSource[begin.row];
|
||||
if (!row) return;
|
||||
// 列索引基于实际渲染列(含行多选列),需映射到业务列 dataIndex
|
||||
const cols = tableColumnsModel.value;
|
||||
const col = cols[begin.col];
|
||||
activeColKey.value = col && !col.__fmsSelection ? (col.dataIndex ?? null) : null;
|
||||
// 通知父组件切换编辑行(单行编辑模式);行未变则不重复 emit
|
||||
const rowKey = String(getRowKey(row));
|
||||
if (String(props.activeRowKey ?? "") !== rowKey) {
|
||||
emit("row-click", null, p.row, p.rows);
|
||||
emit("row-click", null, row, props.dataSource);
|
||||
}
|
||||
}
|
||||
// ==================== 区域选取驱动键盘导航 END ====================
|
||||
|
||||
function navigateTo(rowIndex, colIndex) {
|
||||
const rows = props.dataSource;
|
||||
const cols = props.columns;
|
||||
if (rowIndex < 0 || rowIndex >= rows.length || colIndex < 0 || colIndex >= cols.length) return;
|
||||
|
||||
const row = rows[rowIndex];
|
||||
const colKey = cols[colIndex].dataIndex;
|
||||
|
||||
currentPos.value = { rowIndex, colIndex };
|
||||
navPendingState = { row, colKey, rows };
|
||||
if (!navRafPending) {
|
||||
navRafPending = true;
|
||||
requestAnimationFrame(flushNav);
|
||||
}
|
||||
|
||||
// 虚拟滚动跟随:目标行超出可视区时滚动
|
||||
const table = tableRef.value;
|
||||
if (!table) return;
|
||||
const el = table.$el;
|
||||
const scrollTop = el?.scrollTop ?? 0;
|
||||
const containerHeight = el?.clientHeight ?? 600;
|
||||
const visibleTop = scrollTop + headerRowHeight;
|
||||
const visibleBottom = scrollTop + containerHeight;
|
||||
const targetTop = rowIndex * rowHeight;
|
||||
if (targetTop < visibleTop) {
|
||||
table.scrollTo(Math.max(0, targetTop - headerRowHeight), null);
|
||||
} else if (targetTop + rowHeight > visibleBottom) {
|
||||
table.scrollTo(targetTop + rowHeight - containerHeight + headerRowHeight, null);
|
||||
}
|
||||
}
|
||||
|
||||
function onTableKeydown(event) {
|
||||
const { key, shiftKey, ctrlKey } = event;
|
||||
if (ctrlKey || ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Tab"].indexOf(key) < 0)
|
||||
return;
|
||||
if (key === "Tab" && shiftKey) return;
|
||||
|
||||
// 输入框/文本框内按键留给浏览器处理光标移动,不拦截为表格导航
|
||||
const tag = event.target?.tagName;
|
||||
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT" || event.target?.isContentEditable)
|
||||
return;
|
||||
|
||||
const rows = props.dataSource;
|
||||
const cols = props.columns;
|
||||
if (rows.length === 0 || cols.length === 0) return;
|
||||
|
||||
let { rowIndex, colIndex } = currentPos.value;
|
||||
|
||||
// 首次按键或位置无效时,从 activeRowKey 推导起始位置
|
||||
if (rowIndex < 0 || colIndex < 0 || rowIndex >= rows.length) {
|
||||
const activeRowKeyStr = String(props.activeRowKey ?? "");
|
||||
rowIndex = rows.findIndex((r) => String(getRowKey(r)) === activeRowKeyStr);
|
||||
colIndex = 0;
|
||||
if (rowIndex < 0) rowIndex = 0;
|
||||
currentPos.value = { rowIndex, colIndex };
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case "ArrowUp":
|
||||
if (rowIndex > 0) rowIndex--;
|
||||
break;
|
||||
case "ArrowDown":
|
||||
if (rowIndex < rows.length - 1) rowIndex++;
|
||||
break;
|
||||
case "ArrowLeft":
|
||||
if (colIndex > 0) colIndex--;
|
||||
break;
|
||||
case "ArrowRight":
|
||||
case "Tab":
|
||||
if (colIndex < cols.length - 1) colIndex++;
|
||||
else if (rowIndex < rows.length - 1) {
|
||||
rowIndex++;
|
||||
colIndex = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
navigateTo(rowIndex, colIndex);
|
||||
}
|
||||
|
||||
function attachKeyboard() {
|
||||
nextTick(() => {
|
||||
const el = tableRef.value?.$el;
|
||||
if (el) el.addEventListener("keydown", onTableKeydown, true);
|
||||
});
|
||||
}
|
||||
|
||||
function detachKeyboard() {
|
||||
const el = tableRef.value?.$el;
|
||||
if (el) el.removeEventListener("keydown", onTableKeydown, true);
|
||||
}
|
||||
|
||||
onMounted(attachKeyboard);
|
||||
onBeforeUnmount(detachKeyboard);
|
||||
// ==================== 自定义键盘导航 END ====================
|
||||
// 首个可编辑业务列(dataIndex),用于新增行/未指定列时默认聚焦该列
|
||||
const firstEditableColKey = computed(() => {
|
||||
const col = props.columns.find((c) => c.editor && !c.customCell && !c.actions);
|
||||
return col ? getColumnKey(col) : null;
|
||||
});
|
||||
|
||||
const EditableCell = createEditableCellRenderer({
|
||||
getRowKey,
|
||||
getActiveRowKey: () => props.activeRowKey,
|
||||
getActiveColKey: () => activeColKey.value,
|
||||
getFirstEditableColKey: () => firstEditableColKey.value,
|
||||
});
|
||||
|
||||
const { SelectionCell, SelectionHeaderCell } = createSelectionCellRenderers({
|
||||
@@ -187,14 +87,13 @@ const { SelectionCell, SelectionHeaderCell } = createSelectionCellRenderers({
|
||||
onChange: (keys, rows) => props.rowSelection?.onChange?.(keys, rows),
|
||||
});
|
||||
|
||||
// areaSelection 仅保留 enabled 做占位(避免 StkTable prop 类型警告),
|
||||
// keyboard 已关闭:键盘导航改为本组件自实现的 onTableKeydown 接管,
|
||||
// 绕过 StkTable 内部每帧 30+ 次的选区计算 + overlay DOM 操作。
|
||||
// 区域选取:启用内置键盘导航(方向键 / Tab / Ctrl 多选 / Shift 扩选)与单元格高亮,
|
||||
// 键盘导航与鼠标拖拽产生的选区变化统一由 @area-selection-change 事件处理(见 onAreaSelectionChange)。
|
||||
const areaSelectionConfig = ref({
|
||||
enabled: true,
|
||||
keyboard: false,
|
||||
keyboard: true,
|
||||
highlight: {
|
||||
cell: false,
|
||||
cell: true,
|
||||
row: false,
|
||||
},
|
||||
});
|
||||
@@ -312,9 +211,6 @@ const forwardSlots = computed(() => {
|
||||
return result;
|
||||
});
|
||||
|
||||
// areaSelection 只做外观占位,键盘导航由自实现接管以避免 StkTable 内部选区计算开销。
|
||||
// 鼠标点击后 keyboard 会通过 onTableKeydown 从 activeRowKey 推导起始位置继续导航。
|
||||
|
||||
// 滚动到指定行;用于新增后自动聚焦
|
||||
async function scrollToRow(rowKey) {
|
||||
await nextTick();
|
||||
@@ -348,6 +244,7 @@ defineExpose({ scrollToRow });
|
||||
:no-data-full="noDataFull"
|
||||
:area-selection="areaSelectionConfig"
|
||||
@row-click="onStkRowClick"
|
||||
@area-selection-change="onAreaSelectionChange"
|
||||
>
|
||||
<template v-for="(slot, name) in forwardSlots" :key="name" #[name]="slotProps">
|
||||
<slot :name="name" v-bind="slotProps || {}" />
|
||||
@@ -376,18 +273,27 @@ defineExpose({ scrollToRow });
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* 编辑单元格 wrapper:始终同时渲染文本 span 和编辑组件,通过 display 切换。
|
||||
保证编辑/文本切换时 Vue patch 只更新 props,不触发组件 mount/unmount。 */
|
||||
::deep(.fms-editable-cell-wrap) {
|
||||
/* 编辑单元格 wrapper:仅编辑行渲染此 wrapper(内含编辑器组件),
|
||||
非编辑行只渲染 .fms-cell-text 文本 span,避免滚动时 churn 重型组件。
|
||||
|
||||
实测 DOM:customCell 根元素会经 StkTable fallthrough 合并 class="table-cell-wrapper",
|
||||
即 td > div.table-cell-wrapper.fms-editable-cell-wrap > 编辑器(同一个 div,非嵌套)。
|
||||
.table-cell-wrapper 高度默认 auto(虚拟模式仅 max-height),导致子编辑器 height:100%
|
||||
解析为 auto 而无法占满行高——这是之前几次失败的根因。
|
||||
方案:用 --row-height 定死 wrapper 高度打破循环;用负 margin + 宽度补偿突破 td 的
|
||||
--cell-padding-x(默认 8px,上下 0),使编辑器占满整个单元格(含 padding 区)。 */
|
||||
:deep(.fms-editable-cell-wrap) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
align-items: stretch;
|
||||
box-sizing: border-box;
|
||||
width: calc(100% + 2 * var(--cell-padding-x, 8px));
|
||||
height: var(--row-height, 34px);
|
||||
margin: calc(0px - var(--cell-padding-y, 0px)) calc(0px - var(--cell-padding-x, 8px));
|
||||
}
|
||||
::deep(.fms-editable-cell-wrap .fms-cell-text) {
|
||||
:deep(.fms-editable-cell-wrap .fms-cell-text) {
|
||||
flex: 1;
|
||||
}
|
||||
::deep(
|
||||
:deep(
|
||||
.fms-editable-cell-wrap .ant-input-number,
|
||||
.fms-editable-cell-wrap .ant-select,
|
||||
.fms-editable-cell-wrap .ant-input
|
||||
@@ -395,9 +301,32 @@ defineExpose({ scrollToRow });
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* 隐藏 areaSelection 视觉覆盖层:只借用它的键盘导航 + 虚拟滚动跟随,
|
||||
不需要蓝色的选区高亮遮罩。编辑态下由 EditableCell 的 input/select 展示焦点。 */
|
||||
::deep(.stk-table-area-selection) {
|
||||
display: none !important;
|
||||
/* 让 Input / InputNumber / Select 占满单元格的宽高(覆盖 antdv-next small 尺寸默认高度) */
|
||||
:deep(.fms-editable-cell-wrap .ant-input) {
|
||||
height: 100%;
|
||||
}
|
||||
:deep(.fms-editable-cell-wrap .ant-input-number) {
|
||||
height: 100%;
|
||||
}
|
||||
:deep(.fms-editable-cell-wrap .ant-input-number .ant-input-number-input) {
|
||||
height: 100%;
|
||||
}
|
||||
:deep(.fms-editable-cell-wrap .ant-select) {
|
||||
height: 100%;
|
||||
}
|
||||
:deep(.fms-editable-cell-wrap .ant-select .ant-select-selector) {
|
||||
height: 100%;
|
||||
}
|
||||
:deep(
|
||||
.fms-editable-cell-wrap .ant-select .ant-select-selection-item,
|
||||
.fms-editable-cell-wrap .ant-select .ant-select-selection-placeholder,
|
||||
.fms-editable-cell-wrap .ant-select .ant-select-selection-search
|
||||
) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* 移除:原 hide areaSelection 覆盖层;现已启用 StkTable 内置区域选取与单元格高亮,
|
||||
编辑态下由 EditableCell 的 input/select 展示焦点,选区边框由 .cell-range-selected 提供。 */
|
||||
</style>
|
||||
@@ -1,30 +1,42 @@
|
||||
import { h } from "vue";
|
||||
import { h, nextTick, watch } from "vue";
|
||||
import { Checkbox, Input, InputNumber, Select } from "antdv-next";
|
||||
|
||||
function resolveOption(option, row) {
|
||||
return typeof option === "function" ? option(row) : option;
|
||||
}
|
||||
|
||||
export function createEditableCellRenderer({ getRowKey, getActiveRowKey, getActiveColKey }) {
|
||||
export function createEditableCellRenderer({
|
||||
getRowKey,
|
||||
getActiveRowKey,
|
||||
getActiveColKey,
|
||||
getFirstEditableColKey,
|
||||
}) {
|
||||
// 每个单元格独立的 debounce timer,避免每次击键都触发
|
||||
// onChange → emitUpdate → emit → parent drafts → watch → localData 新引用
|
||||
// → FmsTable dataSource 新引用 → StkTable 全量虚拟滚动重算 → 卡顿。
|
||||
// 150ms debounce 让连续打字期间只触发一次同步。
|
||||
const changeTimers = new Map();
|
||||
|
||||
// 追踪已聚焦过的单元格 key,避免在同一个编辑会话内重复 focus+select
|
||||
//(例如父组件数据变化导致行重渲染时不应打断正在输入的用户)。
|
||||
// 与旧实现不同:不依赖 DOM dataset,因为优化后编辑组件始终驻留 DOM。
|
||||
// 追踪已聚焦过的单元格 key,避免在同一个编辑会话(同一编辑行、父数据变化导致
|
||||
// 行重渲染)内重复 focus+select 从而打断正在输入的用户。
|
||||
// 编辑行切换(activeRowKey 变化)时会在 EditableCell 内清空本 Map,
|
||||
// 允许用户重新进入任意编辑单元格时再次自动聚焦+选中(按需挂载模式下行会 unmount/mount)。
|
||||
const focusedCells = new Map();
|
||||
|
||||
// 缓存每个 cellKey 的 focusRef 闭包引用,避免每次渲染创建新引用导致
|
||||
// Vue ref 回调反复触发(ref 变化 → ref(null) → ref(instance) → focus+select)。
|
||||
const focusRefCache = new Map();
|
||||
|
||||
// 记录当前编辑单元格的 input 元素:area-selection 内置键盘导航在每次按键后会把
|
||||
// 焦点抢回表格容器(见 stk-table-vue 的 blurCellElement),此处用于 nextTick 兜底
|
||||
// 重新聚焦,确保编辑器 Input 稳定持有焦点、文本被选中,可直接覆盖输入。
|
||||
let lastFocusedEl = null;
|
||||
let lastActiveRowKey = null;
|
||||
|
||||
// 稳定引用:Vue VNode diff 按引用比较 props,每次 render 创建新函数/对象
|
||||
// 会触发事件监听器重绑定和样式对比。提到外面让引用恒定,消除击键时的无意义 diff。
|
||||
const stopPropagation = (e) => e.stopPropagation();
|
||||
const fullWidth = { width: "100%" };
|
||||
const fullWidth = { width: "100%", height: "100%" };
|
||||
|
||||
function getFocusRef(cellKey, enabled) {
|
||||
if (!enabled) return undefined;
|
||||
@@ -39,19 +51,48 @@ export function createEditableCellRenderer({ getRowKey, getActiveRowKey, getActi
|
||||
target?.focus?.({ preventScroll: true });
|
||||
const inputEl = el?.matches?.("input") ? el : el?.querySelector?.("input");
|
||||
inputEl?.select?.();
|
||||
// 记录当前 input 元素,供下方 watch 兜底重新聚焦(应对 area-selection 抢焦点)。
|
||||
lastFocusedEl = inputEl || el || null;
|
||||
};
|
||||
focusRefCache.set(cellKey, fn);
|
||||
}
|
||||
return fn;
|
||||
}
|
||||
|
||||
// 兜底重新聚焦:activeRowKey / activeColKey 变化(来自 area-selection 键盘导航
|
||||
// 或鼠标点击)后,StkTable 会在按键同步阶段把焦点抢回表格容器(blurCellElement),
|
||||
// 这里在 nextTick(晚于该抢占)把焦点交还当前编辑单元格的 Input 并选中文本,
|
||||
// 保证编辑态下光标稳定、可直接覆盖输入。
|
||||
watch(
|
||||
() => [getActiveRowKey(), getActiveColKey ? getActiveColKey() : null],
|
||||
() => {
|
||||
nextTick(() => {
|
||||
if (!lastFocusedEl || !lastFocusedEl.isConnected) return;
|
||||
if (document.activeElement !== lastFocusedEl) {
|
||||
lastFocusedEl.focus?.({ preventScroll: true });
|
||||
}
|
||||
lastFocusedEl.select?.();
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
return function EditableCell({ row, col, cellValue }) {
|
||||
const editor = typeof col.editor === "string" ? { type: col.editor } : col.editor || {};
|
||||
const rowKey = String(getRowKey(row));
|
||||
const activeRowKey = getActiveRowKey();
|
||||
// 编辑行切换时重置焦点追踪:允许新编辑行(含重新进入过的行)再次自动聚焦+选中;
|
||||
// 同一编辑行内父数据变化导致的重渲染不重置,避免打断正在输入的用户。
|
||||
const activeRowKeyStr = activeRowKey == null ? null : String(activeRowKey);
|
||||
if (lastActiveRowKey !== activeRowKeyStr) {
|
||||
lastActiveRowKey = activeRowKeyStr;
|
||||
focusedCells.clear();
|
||||
}
|
||||
const isEditing = activeRowKey != null && String(activeRowKey) === rowKey;
|
||||
const activeColKey = getActiveColKey?.();
|
||||
const shouldFocus = isEditing && (activeColKey == null || col.dataIndex === activeColKey);
|
||||
// 未指定具体编辑列(如点击「新增」后编程式进入编辑态)时,只聚焦首个可编辑列,
|
||||
// 避免出现“所有可编辑单元格都尝试聚焦、最右列胜出”导致聚焦到最后一列的问题。
|
||||
const targetColKey = activeColKey != null ? activeColKey : (getFirstEditableColKey?.() ?? null);
|
||||
const shouldFocus = isEditing && col.dataIndex === targetColKey;
|
||||
const cellKey = `${rowKey}_${col.dataIndex}`;
|
||||
|
||||
const update = (value) => {
|
||||
@@ -90,24 +131,19 @@ export function createEditableCellRenderer({ getRowKey, getActiveRowKey, getActi
|
||||
"")
|
||||
: (cellValue ?? "");
|
||||
|
||||
// 始终同时渲染文本 span 和编辑组件,仅通过 CSS display 切换可见性。
|
||||
// 这样 Vue diff 看到的是同一个 div 容器 + 同一对子 VNode 类型,
|
||||
// 跨行切换时只更新 props/style,不触发组件卸载/挂载。
|
||||
// (之前 if(!isEditing) return span else return Input → 不同类型 VNode
|
||||
// → 强制 mount/unmount Ant Design 组件,是键盘导航时 FPS 暴跌的另一主因。)
|
||||
|
||||
const textSpan = h(
|
||||
"span",
|
||||
{
|
||||
class: "fms-cell-text",
|
||||
style: { display: isEditing ? "none" : "inline-block" },
|
||||
},
|
||||
textContent,
|
||||
);
|
||||
// 仅“编辑行”才渲染 Ant Design 编辑器组件,其余行只渲染纯文本 span。
|
||||
// 此前为保持键盘导航时不重挂载而“常驻双渲染”(始终挂载 Input/Select,
|
||||
// 仅靠 CSS display 切换显隐),导致虚拟滚动时非编辑行每帧 churn 数十至上百个
|
||||
// 重型组件实例,是权限页 6 列 5000 行滚动仅 30FPS 的主因。
|
||||
// 改为按需挂载后:编辑行通常只有一行的可编辑列挂编辑器,滚动时非编辑行零开销,
|
||||
// 与工作台(编辑行按需渲染)表现一致。键盘导航只是单行内少量 mount,亦无卡顿。
|
||||
if (!isEditing) {
|
||||
return h("span", { class: "fms-cell-text" }, textContent);
|
||||
}
|
||||
|
||||
const common = {
|
||||
size: "small",
|
||||
style: { ...fullWidth, display: isEditing ? "inline-block" : "none" },
|
||||
style: fullWidth,
|
||||
onClick: stopPropagation,
|
||||
ref: getFocusRef(cellKey, shouldFocus),
|
||||
};
|
||||
@@ -144,6 +180,6 @@ export function createEditableCellRenderer({ getRowKey, getActiveRowKey, getActi
|
||||
});
|
||||
}
|
||||
|
||||
return h("div", { class: "fms-editable-cell-wrap" }, [textSpan, editComponent]);
|
||||
return h("div", { class: "fms-editable-cell-wrap" }, [editComponent]);
|
||||
};
|
||||
}
|
||||
@@ -36,6 +36,8 @@ export function createSelectionCellRenderers({
|
||||
checked: getSelectedRowKeySet().has(getRowKey(row)),
|
||||
"onUpdate:checked": (checked) => changeRow(row, checked),
|
||||
onClick: (event) => event.stopPropagation(),
|
||||
// 阻止 mousedown 冒泡到表格根,避免触发 area-selection 误将本行设入编辑态
|
||||
onMousedown: (event) => event.stopPropagation(),
|
||||
});
|
||||
|
||||
const SelectionHeaderCell = () => {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<script setup>
|
||||
import { computed, h, nextTick, ref, watch } from "vue";
|
||||
import { message, Select } from "antdv-next";
|
||||
import { message, Modal } from "antdv-next";
|
||||
import FmsTable from "@/components/fms-table/FmsTable.vue";
|
||||
import FpsMonitor from "@/components/FpsMonitor.vue";
|
||||
import { loadDataApi } from "@/services/api";
|
||||
import {
|
||||
cloneData,
|
||||
@@ -17,11 +18,15 @@ const props = defineProps({
|
||||
loading: { type: Boolean, default: false },
|
||||
});
|
||||
|
||||
const i18nData = ref([]);
|
||||
const originals = ref([]);
|
||||
// 启用的语言类型(b_i18n_type 中 b_canuse=1),每种语言作为表格的一列。
|
||||
const langOptions = ref([]);
|
||||
// 扁平原始数据(b_id, b_key, b_locale, b_value),仅用于保存时差量对比。
|
||||
const originalsFlat = ref([]);
|
||||
// 透视后的行数据:一行一个 key,每种语言的值挂在对应 locale 字段上。
|
||||
// 形如 { _id, b_key, "zh-CN": "…", "en-US": "…", _localeIds: { "zh-CN": b_id, … } }
|
||||
const pivotRows = ref([]);
|
||||
const isLoading = ref(false);
|
||||
const searchKey = ref("");
|
||||
const langOptions = ref([]);
|
||||
const activeKey = ref(null);
|
||||
const tableRef = ref(null);
|
||||
|
||||
@@ -37,6 +42,25 @@ async function loadLangTypes() {
|
||||
}
|
||||
}
|
||||
|
||||
// 将扁平记录按 key 聚合成一行(每种语言一列)。
|
||||
function buildPivot(flat) {
|
||||
const byKey = new Map();
|
||||
for (const r of flat) {
|
||||
if (!byKey.has(r.b_key)) byKey.set(r.b_key, []);
|
||||
byKey.get(r.b_key).push(r);
|
||||
}
|
||||
const rows = [];
|
||||
for (const [key, recs] of byKey) {
|
||||
const row = { _id: createTempId(), b_key: key, _localeIds: {} };
|
||||
for (const r of recs) {
|
||||
row[r.b_locale] = r.b_value;
|
||||
row._localeIds[r.b_locale] = r.b_id;
|
||||
}
|
||||
rows.push(row);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
async function loadI18n() {
|
||||
isLoading.value = true;
|
||||
try {
|
||||
@@ -44,8 +68,14 @@ async function loadI18n() {
|
||||
loadDataApi("b_i18n", null, "b_key ASC, b_locale ASC"),
|
||||
loadLangTypes(),
|
||||
]);
|
||||
originals.value = i18nRes.data || [];
|
||||
i18nData.value = cloneData(originals.value);
|
||||
const flat = (i18nRes.data || []).map((r) => ({
|
||||
b_id: r.b_id,
|
||||
b_key: r.b_key,
|
||||
b_locale: r.b_locale,
|
||||
b_value: r.b_value,
|
||||
}));
|
||||
originalsFlat.value = cloneData(flat);
|
||||
pivotRows.value = buildPivot(flat);
|
||||
} catch (e) {
|
||||
message.error("加载多语言失败:" + (e.message || e));
|
||||
} finally {
|
||||
@@ -56,18 +86,9 @@ async function loadI18n() {
|
||||
watch(() => props.moduleId, loadI18n, { immediate: true });
|
||||
|
||||
async function addRow() {
|
||||
const def = langOptions.value[0]?.value || "zh-CN";
|
||||
const newId = createTempId();
|
||||
// 用新引用替换(而非 push),否则 displayedData 这个 computed 因返回同一数组引用而不会触发重渲染
|
||||
i18nData.value = [
|
||||
...i18nData.value,
|
||||
{
|
||||
b_id: newId,
|
||||
b_key: "",
|
||||
b_locale: def,
|
||||
b_value: "",
|
||||
},
|
||||
];
|
||||
pivotRows.value = [...pivotRows.value, { _id: newId, b_key: "", _localeIds: {} }];
|
||||
|
||||
activeKey.value = String(newId);
|
||||
await nextTick();
|
||||
@@ -75,12 +96,66 @@ async function addRow() {
|
||||
}
|
||||
|
||||
function deleteRow(record) {
|
||||
i18nData.value = i18nData.value.filter((r) => r.b_id !== record.b_id);
|
||||
pivotRows.value = pivotRows.value.filter((r) => r._id !== record._id);
|
||||
// 同步清理选择状态,避免选中项被删后 keys 残留
|
||||
const k = String(record._id);
|
||||
if (selectedRowKeys.value.includes(k)) {
|
||||
selectedRowKeys.value = selectedRowKeys.value.filter((x) => x !== k);
|
||||
}
|
||||
}
|
||||
|
||||
// 行多选:selectedRowKeys 由 FmsTable 的选择列(createSelectionCellRenderers 提供)
|
||||
// 通过 onChange 回写;FmsTable 在传了 rowSelection 时自动在最前列插入复选框列。
|
||||
const selectedRowKeys = ref([]);
|
||||
const rowSelection = computed(() => ({
|
||||
selectedRowKeys: selectedRowKeys.value,
|
||||
onChange: (keys) => {
|
||||
selectedRowKeys.value = keys;
|
||||
},
|
||||
}));
|
||||
|
||||
// 批量删除选中行(整条 key,含其全部语言)
|
||||
function batchDelete() {
|
||||
const keys = selectedRowKeys.value;
|
||||
if (!keys.length) return;
|
||||
Modal.confirm({
|
||||
title: `确定删除选中的 ${keys.length} 条记录?`,
|
||||
okText: "删除",
|
||||
okType: "danger",
|
||||
cancelText: "取消",
|
||||
onOk: () => {
|
||||
const delSet = new Set(keys);
|
||||
pivotRows.value = pivotRows.value.filter((r) => !delSet.has(String(r._id)));
|
||||
selectedRowKeys.value = [];
|
||||
if (activeKey.value && delSet.has(activeKey.value)) activeKey.value = "";
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 将透视行平铺回 (key, locale) 扁平记录;空值不生成记录(原存在则视为删除)。
|
||||
function flatten(rows) {
|
||||
const flat = [];
|
||||
for (const row of rows) {
|
||||
for (const opt of langOptions.value) {
|
||||
const locale = opt.value;
|
||||
const val = row[locale];
|
||||
if (val == null || val === "") continue;
|
||||
let id = row._localeIds[locale];
|
||||
if (id == null) {
|
||||
// 新语言值:分配稳定的临时 ID,供保存时映射为雪花 ID
|
||||
id = createTempId();
|
||||
row._localeIds[locale] = id;
|
||||
}
|
||||
flat.push({ b_id: id, b_key: row.b_key, b_locale: locale, b_value: val });
|
||||
}
|
||||
}
|
||||
return flat;
|
||||
}
|
||||
|
||||
// 由父级统一保存调用:返回 b_i18n 的变更请求(无变更返回 null),保存成功后父级调用 markSaved 同步基线
|
||||
async function buildSaveRequest() {
|
||||
const changes = diffRows(i18nData.value, originals.value);
|
||||
const flat = flatten(pivotRows.value);
|
||||
const changes = diffRows(flat, originalsFlat.value);
|
||||
const req = tableChange("b_i18n", changes);
|
||||
if (!hasChanges(req)) return null;
|
||||
await allocateTemporaryIds([req.inserts || [], req.updates || [], req.deletes || []]);
|
||||
@@ -88,54 +163,68 @@ async function buildSaveRequest() {
|
||||
}
|
||||
|
||||
function markSaved() {
|
||||
originals.value = cloneData(i18nData.value);
|
||||
originalsFlat.value = cloneData(flatten(pivotRows.value));
|
||||
}
|
||||
|
||||
defineExpose({ buildSaveRequest, markSaved });
|
||||
|
||||
const displayedData = computed(() => {
|
||||
if (!searchKey.value) return i18nData.value;
|
||||
if (!searchKey.value) return pivotRows.value;
|
||||
const kw = searchKey.value.toLowerCase();
|
||||
return i18nData.value.filter(
|
||||
(r) =>
|
||||
(r.b_key || "").toLowerCase().includes(kw) || (r.b_value || "").toLowerCase().includes(kw),
|
||||
);
|
||||
return pivotRows.value.filter((r) => (r.b_key || "").toLowerCase().includes(kw));
|
||||
});
|
||||
|
||||
function createLocaleCell() {
|
||||
return (props) => {
|
||||
const row = props.row;
|
||||
return h(Select, {
|
||||
value: row.b_locale,
|
||||
size: "small",
|
||||
style: { width: "100%" },
|
||||
options: langOptions.value,
|
||||
onChange: (val) => {
|
||||
row.b_locale = val;
|
||||
// 操作列单元格:普通文字「删除」按钮(原生 button,避免每行一个组件实例开销)
|
||||
const ActionsCell = ({ row }) =>
|
||||
h(
|
||||
"button",
|
||||
{
|
||||
type: "button",
|
||||
title: "删除",
|
||||
onMousedown: (e) => e.stopPropagation(),
|
||||
style: {
|
||||
border: "none",
|
||||
background: "transparent",
|
||||
cursor: "pointer",
|
||||
padding: "2px 4px",
|
||||
color: "#ff4d4f",
|
||||
fontSize: "12px",
|
||||
lineHeight: "20px",
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
onClick: (e) => {
|
||||
e.stopPropagation();
|
||||
Modal.confirm({
|
||||
title: "确定删除该记录(含其全部语言)?",
|
||||
okText: "删除",
|
||||
okType: "danger",
|
||||
cancelText: "取消",
|
||||
onOk: () => deleteRow(row),
|
||||
});
|
||||
},
|
||||
},
|
||||
"删除",
|
||||
);
|
||||
|
||||
const columns = [
|
||||
{ dataIndex: "b_key", title: "键", width: 200 },
|
||||
{ dataIndex: "b_locale", title: "语言", width: 160, customCell: createLocaleCell() },
|
||||
{ dataIndex: "b_value", title: "翻译文本", width: 300 },
|
||||
{
|
||||
// 动态列:键 + 每种语言一列 + 操作列
|
||||
const columns = computed(() => {
|
||||
const cols = [{ dataIndex: "b_key", title: "键", width: 240, editor: { type: "input" } }];
|
||||
for (const opt of langOptions.value) {
|
||||
cols.push({
|
||||
dataIndex: opt.value,
|
||||
title: opt.label,
|
||||
width: 180,
|
||||
editor: { type: "input" },
|
||||
});
|
||||
}
|
||||
cols.push({
|
||||
dataIndex: "actions",
|
||||
title: "操作",
|
||||
width: 60,
|
||||
align: "center",
|
||||
actions: [
|
||||
{
|
||||
type: "danger",
|
||||
label: "删除",
|
||||
confirm: { title: "确定删除该记录?", okText: "删除" },
|
||||
onClick: (row) => deleteRow(row),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
customCell: ActionsCell,
|
||||
});
|
||||
return cols;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -144,21 +233,26 @@ const columns = [
|
||||
<a-space>
|
||||
<a-input-search
|
||||
v-model:value="searchKey"
|
||||
placeholder="搜索键或值"
|
||||
placeholder="搜索键"
|
||||
style="width: 200px"
|
||||
allow-clear
|
||||
/>
|
||||
<a-button type="primary" @click="addRow">新增翻译</a-button>
|
||||
<a-button danger :disabled="!selectedRowKeys.length" @click="batchDelete">
|
||||
批量删除{{ selectedRowKeys.length ? `(${selectedRowKeys.length})` : "" }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<FpsMonitor />
|
||||
<FmsTable
|
||||
ref="tableRef"
|
||||
:columns="columns"
|
||||
:data-source="displayedData"
|
||||
row-key="b_id"
|
||||
row-key="_id"
|
||||
:active-row-key="activeKey"
|
||||
@row-click="(_, row) => (activeKey = String(row.b_id))"
|
||||
:row-selection="rowSelection"
|
||||
@row-click="(_, row) => (activeKey = String(row._id))"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { h, nextTick, ref, watch } from "vue";
|
||||
import { computed, h, nextTick, ref, watch } from "vue";
|
||||
import { message, Modal } from "antdv-next";
|
||||
import { Languages } from "@lucide/vue";
|
||||
import FmsTable from "@/components/fms-table/FmsTable.vue";
|
||||
@@ -60,9 +60,43 @@ async function addRow() {
|
||||
|
||||
function deleteRow(record) {
|
||||
localPowers.value = localPowers.value.filter((r) => r.b_id !== record.b_id);
|
||||
// 同步清理选择状态,避免选中项被删后 keys 残留
|
||||
const k = String(record.b_id);
|
||||
if (selectedRowKeys.value.includes(k)) {
|
||||
selectedRowKeys.value = selectedRowKeys.value.filter((x) => x !== k);
|
||||
}
|
||||
emitUpdate();
|
||||
}
|
||||
|
||||
// 行多选:selectedRowKeys 由 FmsTable 的选择列(createSelectionCellRenderers 提供)
|
||||
// 通过 onChange 回写;FmsTable 在传了 rowSelection 时自动在最前列插入复选框列。
|
||||
const selectedRowKeys = ref([]);
|
||||
const rowSelection = computed(() => ({
|
||||
selectedRowKeys: selectedRowKeys.value,
|
||||
onChange: (keys) => {
|
||||
selectedRowKeys.value = keys;
|
||||
},
|
||||
}));
|
||||
|
||||
// 批量删除选中行
|
||||
function batchDelete() {
|
||||
const keys = selectedRowKeys.value;
|
||||
if (!keys.length) return;
|
||||
Modal.confirm({
|
||||
title: `确定删除选中的 ${keys.length} 条记录?`,
|
||||
okText: "删除",
|
||||
okType: "danger",
|
||||
cancelText: "取消",
|
||||
onOk: () => {
|
||||
const delSet = new Set(keys);
|
||||
localPowers.value = localPowers.value.filter((r) => !delSet.has(r.b_id));
|
||||
selectedRowKeys.value = [];
|
||||
if (activeKey.value && delSet.has(activeKey.value)) activeKey.value = "";
|
||||
emitUpdate();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// ── 快速设置多语言 ──
|
||||
const i18nModalRef = ref(null);
|
||||
|
||||
@@ -145,13 +179,14 @@ const CanUseCell = ({ row, cellValue }) => {
|
||||
);
|
||||
};
|
||||
|
||||
// 操作列单元格:原生 button + Modal.confirm,避免每行一个 Popconfirm 实例的开销
|
||||
// 操作列单元格:普通文字「删除」按钮(原生 button,避免每行一个组件实例开销)
|
||||
const ActionsCell = ({ row }) =>
|
||||
h(
|
||||
"button",
|
||||
{
|
||||
type: "button",
|
||||
title: "删除",
|
||||
onMousedown: (e) => e.stopPropagation(),
|
||||
style: {
|
||||
border: "none",
|
||||
background: "transparent",
|
||||
@@ -190,6 +225,9 @@ const columns = [
|
||||
<div class="panel-toolbar">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="addRow">新增权限</a-button>
|
||||
<a-button danger :disabled="!selectedRowKeys.length" @click="batchDelete">
|
||||
批量删除{{ selectedRowKeys.length ? `(${selectedRowKeys.length})` : "" }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
@@ -200,6 +238,7 @@ const columns = [
|
||||
:data-source="localPowers"
|
||||
row-key="b_id"
|
||||
:active-row-key="activeKey"
|
||||
:row-selection="rowSelection"
|
||||
@row-click="(_, row) => (activeKey = String(row.b_id))"
|
||||
/>
|
||||
</div>
|
||||
@@ -241,8 +280,10 @@ const columns = [
|
||||
基于 antdv-next Checkbox 源码(checkbox/style/index.js)精确模拟外观。 -->
|
||||
<style lang="scss">
|
||||
.pw-checkbox {
|
||||
display: inline-flex;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
margin: 0;
|
||||
|
||||
@@ -44,3 +44,21 @@
|
||||
2. **以最少的 CSS 完成任务**:优先复用 Antdv Next 组件能力、设计变量和已有工具类,能用组件属性或已有 token 解决的就不写样式,不重复实现已有的尺寸/状态/交互。
|
||||
3. **公用样式集中管理**:跨页面或同功能重复出现的样式抽到 `src/styles/main.scss`、共用组件或组合(composable)中,做到「改一处、处处变」;组件内只保留该组件独有、无法共享的样式,并保持 `scoped`。
|
||||
4. **不兼容移动端**:按桌面端实现,不写 `@media` 响应式断点;如确有需要,须先与需求方确认。
|
||||
|
||||
## 六、性能优先(重要、重要、重要)
|
||||
|
||||
- **性能是本项目的一等约束,贯穿全部层面**,优先于代码便利与组件/外观一致性。适用于前端、后端、数据库及一切场景,任何改动都不得引入可感知的性能退化(卡顿、慢查询、高延迟、资源浪费等)。
|
||||
- **前端**:表格单元格、列表项、滚动区域默认使用原生 DOM(`h("button")` / `<input>` / 原生元素)或轻量自绘元素,**避免每行/每项常驻重型组件实例**(如 antdv 的 `Dropdown`、`Select`、`Input`、`Modal` 等)。
|
||||
- 重型组件(如 `Dropdown` 菜单)必须「按需挂载」:列表态只渲染轻量触发器(原生按钮 + 图标),仅在用户真正交互(点击/悬停)时才为「当前那一行/项」临时挂载真正的组件,交互结束(菜单关闭/失焦)即卸载,保证**任意时刻最多只有 1 个该类组件实例存在**。
|
||||
- 虚拟滚动(如 `fms-table` / stk-table)场景下,组件实例的 mount/unmount 会随滚动反复发生;常驻重型组件会显著拖慢帧率(实测每行一个 `Dropdown` 可让滚动从约 55fps 跌到 40–50fps)。务必用轻量元素 + 按需挂载规避。
|
||||
- 含列表/表格滚动的页面,交付或评审前应关注 FPS,必要时用轻量替代或按需挂载优化。
|
||||
- **后端**:优先复用现有通用接口完成查询/分页/保存/取号,不随意新增业务接口或重复封装;查询与保存应合理批量(如用 `/data/saveobjt` 的单事务批量 upsert 而非逐条请求);避免 N+1 查询、在循环内做远程调用或重复 IO;大数据量必须分页,不一次拉全表。
|
||||
- **数据库(SQL Server)**:编写 SQL 时优先走索引(避免对索引列做函数包裹、隐式类型转换、`SELECT *`、不必要的 `ORDER BY`/`DISTINCT`);分页、聚合、联表需评估执行计划与数据量;大表慎用全表扫描与锁表操作;连接池(Druid 多组织路由)配置与慢查询需关注,避免连接泄漏与长事务。
|
||||
- 性能问题应在设计/编码阶段前置考量,而非事后优化;涉及慢查询、重接口、大列表等高风险改动,实施前应说明性能影响与规避方式。
|
||||
|
||||
## 七、表格「更多操作」按钮
|
||||
|
||||
- 表格/列表中若需要「更多操作」(⋯)按钮并弹出菜单,**必须采用按需挂载模式**(禁止为每一行常驻一个 `Dropdown` 组件实例,否则会导致滚动卡顿):
|
||||
- **列表态**:单元格只渲染一个轻量原生 `⋯` 图标按钮(无边框、透明背景、hover 显底色),点击后才为当前行挂载真正的 `Dropdown`(`menu` 属性驱动 `items`,`open` 受控,`onOpenChange` 关闭即卸载)。
|
||||
- **任意时刻最多 1 个 `Dropdown` 实例**;菜单项统一使用「图标 + 文字」形式(如 `h(icon, { size: 14 })` 加文本)。
|
||||
- **参考实现**:`src/views/module-management/components/ModulePowersPanel.vue` 中的 `MoreActions` 组件——原生 `⋯` 触发器 + 仅在 `open` 时挂载 `antdv-next` 的 `Dropdown`,菜单含「编辑 / 复制 / 设置多语言」三项,每项带图标与文字。新增类似按钮时直接参照此模式。
|
||||
Reference in new issue
Block a user