├── .browserslistrc
├── .dockerignore
├── .editorconfig
├── .eslintrc.js
├── .gitignore
├── .gitlab-ci.yml
├── .npmrc
├── Dockerfile
├── LICENSE
├── README.md
├── babel.config.js
├── build
└── tag.sh
├── commitlint.config.js
├── config
└── default.yaml
├── docs
├── README.md
├── 实时测试.md
└── 技术文档.md
├── env.js
├── index.html
├── jest.config.js
├── mock
└── index.js
├── package.json
├── public
├── favicon.png
└── index.html
├── src
├── App.vue
├── assets
│ ├── iconfont.js
│ └── logo.svg
├── bus.ts
├── components
│ ├── README.md
│ ├── ant-design
│ │ ├── icons.ts
│ │ └── index.ts
│ ├── baseInstall
│ │ └── m-image-preivew
│ │ │ ├── index.js
│ │ │ └── index.vue
│ ├── common
│ │ ├── index.ts
│ │ ├── m-drawer-footer
│ │ │ └── index.vue
│ │ ├── m-filter-select
│ │ │ ├── FilterSelect.tsx
│ │ │ ├── MultiSelect.tsx
│ │ │ ├── SingleSelect.tsx
│ │ │ ├── menu
│ │ │ │ ├── VirtualMenu.vue
│ │ │ │ ├── menu.less
│ │ │ │ └── type.ts
│ │ │ └── select.less
│ │ ├── m-icon-font
│ │ │ └── index.vue
│ │ ├── m-rowselect-table
│ │ │ └── index.vue
│ │ ├── m-skeleton
│ │ │ └── skeleton.js
│ │ ├── m-virtual-scroll
│ │ │ └── index.vue
│ │ ├── u-divider-dash.vue
│ │ ├── u-divider.vue
│ │ ├── u-filter-select.vue
│ │ ├── u-mutiple-select.vue
│ │ ├── u-single-select.vue
│ │ ├── u-spinner.vue
│ │ └── u-tag.vue
│ ├── layout
│ │ ├── index.ts
│ │ ├── topbar
│ │ │ ├── Topbar.vue
│ │ │ ├── assets
│ │ │ │ ├── logo.svg
│ │ │ │ └── toggle-bar.svg
│ │ │ ├── components
│ │ │ │ ├── IconFont.vue
│ │ │ │ ├── Link.vue
│ │ │ │ └── iconFont.js
│ │ │ ├── index.ts
│ │ │ ├── product-navigation
│ │ │ │ ├── Group.vue
│ │ │ │ ├── Panel.vue
│ │ │ │ └── index.vue
│ │ │ ├── product-select
│ │ │ │ ├── ProductSelectModal.vue
│ │ │ │ └── index.vue
│ │ │ ├── quick-navigation
│ │ │ │ ├── SortableContainer.vue
│ │ │ │ ├── SortableItem.vue
│ │ │ │ └── index.vue
│ │ │ ├── styles
│ │ │ │ ├── global.less
│ │ │ │ └── var.less
│ │ │ ├── type.ts
│ │ │ ├── user-operation
│ │ │ │ └── index.vue
│ │ │ └── utils
│ │ │ │ ├── loadJs.ts
│ │ │ │ └── util.ts
│ │ ├── u-collapse.vue
│ │ ├── u-info-item.vue
│ │ ├── u-info.vue
│ │ ├── u-layout.vue
│ │ ├── u-left-right.vue
│ │ ├── u-sidebar.vue
│ │ └── u-topbar.vue
│ ├── modal
│ │ └── ImagePreviewModal.vue
│ ├── register-test.ts
│ ├── register-vite.ts
│ ├── register.ts
│ └── specific
│ │ ├── index.ts
│ │ ├── s-editor.vue
│ │ ├── s-page-top.vue
│ │ ├── s-table-search.vue
│ │ ├── s-upload-image.vue
│ │ ├── s-user-select.vue
│ │ └── upload-request.js
├── main.ts
├── middler
│ ├── README.md
│ ├── babelPlugin
│ │ ├── FunctionInstrumentation
│ │ │ └── AuthoirtyFeat.js
│ │ └── installCommon.js
│ ├── vitePlugin
│ │ ├── antDesignVueImport.js
│ │ ├── authorityFeat.js
│ │ └── injectAntIcon.js
│ └── webpackLoader
│ │ └── authorityFeat.js
├── mixin.ts
├── ndsc-vue3
│ ├── basic-components
│ │ └── lib
│ │ │ ├── components
│ │ │ ├── s-sync-button
│ │ │ │ ├── index.ts
│ │ │ │ └── s-sync-button.vue
│ │ │ ├── u-copy
│ │ │ │ ├── index.ts
│ │ │ │ └── u-copy.vue
│ │ │ ├── u-drawer
│ │ │ │ ├── index.ts
│ │ │ │ └── u-drawer.vue
│ │ │ ├── u-hint-tooltip
│ │ │ │ ├── index.ts
│ │ │ │ └── u-hint-tooltip.vue
│ │ │ ├── u-icon-button
│ │ │ │ ├── index.ts
│ │ │ │ └── u-icon-button.vue
│ │ │ ├── u-icon-font
│ │ │ │ ├── iconfont.js
│ │ │ │ ├── index.ts
│ │ │ │ └── u-icon-font.vue
│ │ │ ├── u-modal
│ │ │ │ ├── index.ts
│ │ │ │ └── u-modal.vue
│ │ │ ├── u-status-icon
│ │ │ │ ├── index.ts
│ │ │ │ └── u-status-icon.vue
│ │ │ ├── u-text-button
│ │ │ │ ├── index.ts
│ │ │ │ └── u-text-button.vue
│ │ │ └── u-text-tooltip
│ │ │ │ ├── index.ts
│ │ │ │ └── u-text-tooltip.vue
│ │ │ ├── directives
│ │ │ ├── v-click-outside
│ │ │ │ ├── index.ts
│ │ │ │ └── v-click-outside.ts
│ │ │ ├── v-copy
│ │ │ │ ├── index.ts
│ │ │ │ └── v-copy.ts
│ │ │ ├── v-drag-size
│ │ │ │ ├── index.ts
│ │ │ │ ├── v-drag-size.less
│ │ │ │ └── v-drag-size.ts
│ │ │ ├── v-ellipsis-title
│ │ │ │ ├── index.ts
│ │ │ │ └── v-ellipsis-title.ts
│ │ │ └── v-input-number
│ │ │ │ ├── index.ts
│ │ │ │ └── v-input-number.ts
│ │ │ ├── index.ts
│ │ │ ├── shims-tsx.d.ts
│ │ │ ├── shims-vue.d.ts
│ │ │ ├── style
│ │ │ ├── antd.less
│ │ │ ├── index.less
│ │ │ ├── s-sync-button.less
│ │ │ ├── u-drawer.less
│ │ │ ├── u-icon-button.less
│ │ │ ├── u-icon-font.less
│ │ │ ├── u-modal.less
│ │ │ ├── u-status-icon.less
│ │ │ ├── u-text-button.less
│ │ │ └── u-text-tooltip.less
│ │ │ └── utils
│ │ │ └── clipboard.ts
│ ├── exception-page
│ │ ├── README.md
│ │ ├── assets
│ │ │ ├── 403.svg
│ │ │ ├── 404.svg
│ │ │ └── nobiz.svg
│ │ ├── lib
│ │ │ ├── index.ts
│ │ │ ├── shims-vue.d.ts
│ │ │ ├── u-page-nobiz.vue
│ │ │ ├── u-page403.vue
│ │ │ └── u-page404.vue
│ │ └── package.json
│ ├── sidebar
│ │ ├── README.md
│ │ ├── lib
│ │ │ ├── VNode.tsx
│ │ │ ├── components
│ │ │ │ ├── IconFont.vue
│ │ │ │ └── iconfont.js
│ │ │ ├── flexbox.css
│ │ │ ├── index.ts
│ │ │ ├── interface.ts
│ │ │ ├── shims-tsx.d.ts
│ │ │ ├── shims-vue.d.ts
│ │ │ ├── sidebar.less
│ │ │ └── sidebar.vue
│ │ └── types
│ │ │ └── index.d.ts
│ ├── style
│ │ ├── README.md
│ │ ├── lib
│ │ │ ├── ant-design
│ │ │ │ ├── button.less
│ │ │ │ ├── collapse.less
│ │ │ │ ├── form.less
│ │ │ │ ├── index.less
│ │ │ │ ├── index.ts
│ │ │ │ ├── modal.less
│ │ │ │ └── table.less
│ │ │ ├── common.less
│ │ │ ├── flex.less
│ │ │ ├── font.less
│ │ │ ├── index.less
│ │ │ ├── index.ts
│ │ │ ├── margin.less
│ │ │ ├── padding.less
│ │ │ ├── text.less
│ │ │ ├── var.js
│ │ │ └── var.less
│ │ └── package.json
│ ├── theme
│ │ ├── README.md
│ │ ├── index.html
│ │ ├── lib
│ │ │ ├── common
│ │ │ │ └── index.less
│ │ │ ├── dark
│ │ │ │ ├── common.less
│ │ │ │ ├── index.js
│ │ │ │ ├── index.less
│ │ │ │ └── var.less
│ │ │ ├── light
│ │ │ │ ├── common.less
│ │ │ │ ├── index.js
│ │ │ │ ├── index.less
│ │ │ │ └── var.less
│ │ │ ├── purple
│ │ │ │ ├── common.less
│ │ │ │ ├── index.js
│ │ │ │ ├── index.less
│ │ │ │ └── var.less
│ │ │ └── utils
│ │ │ │ ├── ThemeMixin.vue
│ │ │ │ └── index.js
│ │ ├── package.json
│ │ ├── scripts
│ │ │ ├── copyCSS.js
│ │ │ └── copyVue.js
│ │ └── webpack.config.js
│ └── utils
│ │ ├── README.md
│ │ └── lib
│ │ ├── TableMixin.vue
│ │ ├── common.ts
│ │ ├── index.ts
│ │ ├── instance.ts
│ │ ├── loadJs.ts
│ │ ├── request.ts
│ │ ├── shims-tsx.d.ts
│ │ ├── shims-vue.d.ts
│ │ ├── url.ts
│ │ ├── validator.ts
│ │ └── vueProto.ts
├── pv.ts
├── router.ts
├── services
│ ├── README.md
│ ├── app.service.ts
│ ├── auth.service.ts
│ ├── authority.service.ts
│ ├── common.service.ts
│ ├── event.service.ts
│ ├── login.service.ts
│ ├── object.service.ts
│ ├── parameter.service.ts
│ ├── record.service.ts
│ ├── requirement.design.service.ts
│ ├── requirement.service.ts
│ ├── socket.ts
│ ├── tag.service.ts
│ ├── template.service.ts
│ ├── terminal.service.ts
│ ├── terminalVersion.service.ts
│ ├── test
│ │ └── realTime
│ │ │ └── index.service.ts
│ └── version.service.ts
├── sevice.d.ts
├── shims-tsx.d.ts
├── shims-vue.d.ts
├── store
│ ├── index.tsx
│ └── modules
│ │ └── live-test.ts
├── style
│ ├── animation.less
│ ├── ant-design.less
│ ├── global.less
│ ├── index.less
│ ├── nprogress.less
│ └── scrollbar.less
├── track.ts
├── types
│ ├── README.md
│ ├── app.type.ts
│ ├── authority.type.ts
│ ├── common.type.ts
│ ├── event.type.ts
│ ├── object.type.ts
│ ├── parameter.type.ts
│ ├── realtime.type.ts
│ ├── requirement.design.type.ts
│ ├── requirement.type.ts
│ ├── spm.type.ts
│ ├── table.type.ts
│ ├── template.type.ts
│ ├── terminal.type.ts
│ ├── terminalVersion.type.ts
│ └── version.type.ts
├── utils
│ ├── common.ts
│ ├── cookie.ts
│ ├── hooks
│ │ ├── Object
│ │ │ └── useFindAndroidAndIPhone.ts
│ │ ├── useCopy.ts
│ │ └── useCopyParams.ts
│ ├── request.ts
│ ├── tests
│ │ └── index.ts
│ ├── validator.ts
│ └── vars.ts
├── views
│ ├── 403.vue
│ ├── 404.vue
│ ├── NoBiz.vue
│ └── home
│ │ ├── README.md
│ │ ├── authorityManagement
│ │ ├── domainManage
│ │ │ ├── detail
│ │ │ │ └── index.vue
│ │ │ ├── index.vue
│ │ │ ├── member
│ │ │ │ ├── OptionMember.vue
│ │ │ │ └── index.vue
│ │ │ ├── nav.tsx
│ │ │ └── product
│ │ │ │ ├── OptionPruduct.vue
│ │ │ │ └── index.vue
│ │ ├── index.vue
│ │ ├── platformManage
│ │ │ ├── components
│ │ │ │ └── domain-modal
│ │ │ │ │ └── index.vue
│ │ │ ├── domain
│ │ │ │ └── index.vue
│ │ │ ├── index.vue
│ │ │ └── nav.tsx
│ │ └── productionManage
│ │ │ ├── index.vue
│ │ │ ├── info
│ │ │ └── index.vue
│ │ │ ├── manage
│ │ │ ├── components
│ │ │ │ ├── auth-tab
│ │ │ │ │ ├── index.vue
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── member-modal
│ │ │ │ │ └── index.vue
│ │ │ │ ├── member-tab
│ │ │ │ │ └── index.vue
│ │ │ │ ├── role-modal
│ │ │ │ │ └── index.vue
│ │ │ │ └── role-panel
│ │ │ │ │ └── index.vue
│ │ │ └── index.vue
│ │ │ ├── member
│ │ │ ├── OptionMember.vue
│ │ │ └── index.vue
│ │ │ └── nav.tsx
│ │ ├── index.vue
│ │ ├── router.ts
│ │ ├── test
│ │ ├── components
│ │ │ ├── column-setting
│ │ │ │ └── index.vue
│ │ │ ├── device-detail
│ │ │ │ └── index.vue
│ │ │ ├── error-list
│ │ │ │ └── index.vue
│ │ │ ├── ignore-checkbox.vue
│ │ │ ├── log-list
│ │ │ │ └── index.vue
│ │ │ ├── point-list
│ │ │ │ ├── code-show.vue
│ │ │ │ ├── detection.vue
│ │ │ │ ├── index.vue
│ │ │ │ └── point-code.vue
│ │ │ ├── rule-drawer
│ │ │ │ └── index.vue
│ │ │ ├── tab-content
│ │ │ │ └── index.vue
│ │ │ ├── test-abstract
│ │ │ │ └── index.vue
│ │ │ ├── tree-table
│ │ │ │ └── index.vue
│ │ │ ├── types
│ │ │ │ └── index.ts
│ │ │ └── undefined-log-stats
│ │ │ │ └── index.vue
│ │ ├── index.vue
│ │ ├── nav.tsx
│ │ └── realtime
│ │ │ ├── audit
│ │ │ ├── components
│ │ │ │ └── content.vue
│ │ │ └── index.vue
│ │ │ ├── detail
│ │ │ └── index.vue
│ │ │ ├── lists
│ │ │ ├── content.vue
│ │ │ ├── index.vue
│ │ │ ├── lists.vue
│ │ │ └── types
│ │ │ │ └── content.ts
│ │ │ └── record
│ │ │ ├── components
│ │ │ └── content.vue
│ │ │ └── index.vue
│ │ └── tracker
│ │ ├── event
│ │ ├── EventDetail.vue
│ │ ├── Record.vue
│ │ ├── VersionHistory.vue
│ │ └── index.vue
│ │ ├── index.vue
│ │ ├── metadata
│ │ ├── components
│ │ │ ├── ParamBindModal.vue
│ │ │ ├── ParamConfig.vue
│ │ │ ├── ParamConfigDrawer.vue
│ │ │ ├── VersionAddModal.vue
│ │ │ └── VersionConfig.vue
│ │ ├── event
│ │ │ ├── EventAddModal.vue
│ │ │ ├── EventEditModal.vue
│ │ │ ├── List.vue
│ │ │ └── index.vue
│ │ ├── index.vue
│ │ ├── parameter
│ │ │ ├── BusinessParamAddOrEditModal.vue
│ │ │ ├── BusinessParamList.vue
│ │ │ ├── BusinessParamPool.vue
│ │ │ ├── BusinessParamTab.vue
│ │ │ ├── List.vue
│ │ │ ├── ParamAddDrawer.vue
│ │ │ ├── ParamDetailDrawer.vue
│ │ │ ├── ParamEditDrawer.vue
│ │ │ ├── ParamValueDrawer.vue
│ │ │ ├── ParameterTab.vue
│ │ │ ├── VariableParamSelect.vue
│ │ │ └── index.vue
│ │ ├── rule
│ │ │ ├── components
│ │ │ │ └── add-rule-modal
│ │ │ │ │ └── index.vue
│ │ │ └── index.vue
│ │ ├── template
│ │ │ ├── List.vue
│ │ │ ├── ParamConfigForm.vue
│ │ │ ├── index.vue
│ │ │ ├── templateAddDrawer.vue
│ │ │ ├── templateDetailDrawer.vue
│ │ │ └── templateEditDrawer.vue
│ │ └── terminal
│ │ │ ├── List.vue
│ │ │ ├── TerminalAddModal.vue
│ │ │ ├── TerminalEditModal.vue
│ │ │ └── index.vue
│ │ ├── nav.tsx
│ │ ├── object
│ │ ├── detail
│ │ │ ├── BackToList.vue
│ │ │ ├── ImagePreviewModal.vue
│ │ │ ├── LineageTab.vue
│ │ │ ├── ObjHistoryTab.vue
│ │ │ ├── ObjTrackerTable.vue
│ │ │ ├── ParamConfigFilter.vue
│ │ │ ├── ParamConfigTab.vue
│ │ │ ├── ParamTableList.vue
│ │ │ └── ParamTableModal.vue
│ │ ├── index.vue
│ │ └── list
│ │ │ ├── BaseInfoForm.vue
│ │ │ ├── BatchAddBaseInfoForm.vue
│ │ │ ├── BloodRelationDrawer.vue
│ │ │ ├── EventConfigForm.vue
│ │ │ ├── Filter.vue
│ │ │ ├── HistoryList.vue
│ │ │ ├── LineageForm.vue
│ │ │ ├── List.vue
│ │ │ ├── ListHeaderFilter.vue
│ │ │ ├── ObjTagSelect.vue
│ │ │ ├── ObjectAddDrawer.vue
│ │ │ ├── ObjectAddForm.vue
│ │ │ ├── ObjectEditDiffDrawer.vue
│ │ │ ├── ObjectEditDrawer.vue
│ │ │ ├── ObjectEditForm.vue
│ │ │ ├── ObjectViewDrawer.vue
│ │ │ ├── ObjectViewForm.vue
│ │ │ ├── ObjectViewLineage.vue
│ │ │ ├── ParamConfigForm.vue
│ │ │ ├── SampleData.vue
│ │ │ ├── TagSetting.vue
│ │ │ ├── TemplateImportModal.vue
│ │ │ ├── TerminalAddModal.vue
│ │ │ ├── TerminalConfigForm.vue
│ │ │ ├── TerminalConfigItem.vue
│ │ │ ├── TrackerConfigPane.vue
│ │ │ ├── blood-relation
│ │ │ ├── BindOrUnbindParentObjModal.vue
│ │ │ ├── Filter.vue
│ │ │ ├── ToolBar.vue
│ │ │ ├── graph
│ │ │ │ ├── ObjectDetail.vue
│ │ │ │ ├── ObjectParamsTable.vue
│ │ │ │ ├── ToolBar.vue
│ │ │ │ ├── behavior
│ │ │ │ │ ├── click-canvas.ts
│ │ │ │ │ ├── click-node.ts
│ │ │ │ │ ├── hover-node.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.vue
│ │ │ │ ├── item
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── obj-node.ts
│ │ │ │ ├── plugin
│ │ │ │ │ ├── contextMenu.ts
│ │ │ │ │ ├── index.less
│ │ │ │ │ └── index.ts
│ │ │ │ ├── share
│ │ │ │ │ ├── color.ts
│ │ │ │ │ └── util.ts
│ │ │ │ └── type.ts
│ │ │ └── index.vue
│ │ │ ├── const.ts
│ │ │ └── index.vue
│ │ └── requirement
│ │ ├── components
│ │ ├── OptionButton.vue
│ │ ├── StatusTag.vue
│ │ ├── object-diff
│ │ │ ├── BaseInfo.vue
│ │ │ ├── LineageInfo.vue
│ │ │ ├── ObjectDiffDetail.vue
│ │ │ ├── ParamInfo.vue
│ │ │ ├── TrackerInfo.vue
│ │ │ └── util.ts
│ │ └── sample-data
│ │ │ └── index.vue
│ │ ├── detail
│ │ ├── BackToList.vue
│ │ ├── BaseInfoTab.vue
│ │ ├── ObjectDetail.vue
│ │ ├── ObjectLineage.vue
│ │ ├── ObjectViewDrawer.vue
│ │ ├── RequireTaskDetail
│ │ │ ├── BaseLineSetting.vue
│ │ │ ├── EventPool.vue
│ │ │ ├── ObjectPool.vue
│ │ │ ├── RequirementEventPool.vue
│ │ │ ├── RequirementObject.vue
│ │ │ ├── RequirementTaskDetail.vue
│ │ │ ├── RequriementObjectPool.vue
│ │ │ ├── TaskPool.vue
│ │ │ └── components
│ │ │ │ ├── EventTracker.vue
│ │ │ │ └── ReassignTasks.vue
│ │ ├── TaskCollapse.vue
│ │ ├── TaskObject.vue
│ │ ├── TrackerTab.vue
│ │ └── index.vue
│ │ ├── index.vue
│ │ ├── list
│ │ ├── BatchOperateModal.vue
│ │ ├── ExpandObjTable.vue
│ │ ├── ObjectChangeDrawer.vue
│ │ ├── ObjectChangeSelect.vue
│ │ ├── ObjectOperateDrawer.vue
│ │ ├── RejectTaskModal.vue
│ │ ├── ReqAddDrawer.vue
│ │ ├── ReqFilterDropDown.vue
│ │ ├── ReqTask.vue
│ │ ├── Requirement.vue
│ │ ├── RequirementFilter.vue
│ │ ├── RequirementGroup.vue
│ │ ├── RequirementGroupList.vue
│ │ ├── SettingSprint.vue
│ │ ├── SettingVersion.vue
│ │ ├── Task.vue
│ │ ├── TaskFilter.vue
│ │ ├── TaskList.vue
│ │ ├── TerminalList.vue
│ │ ├── TestingModal.vue
│ │ └── index.vue
│ │ ├── record
│ │ └── index.vue
│ │ └── version
│ │ ├── DeployDetailModal.vue
│ │ ├── Publish.vue
│ │ ├── VersionList.vue
│ │ ├── VersionNumEditModal.vue
│ │ ├── VersionTree.vue
│ │ ├── components
│ │ ├── PublishList.vue
│ │ ├── TaskList.vue
│ │ └── VersionList.vue
│ │ ├── graph
│ │ ├── ToolBar.vue
│ │ ├── context-menu.ts
│ │ └── index.vue
│ │ ├── index.vue
│ │ └── version-publish
│ │ ├── BackToList.vue
│ │ ├── DeployContentTable.vue
│ │ ├── ExpandTaskTable.vue
│ │ ├── ObjectDiffDrawer.vue
│ │ ├── ReqConflictCheck.vue
│ │ ├── TrackerInfoForm.vue
│ │ ├── VersionConflictCheck.vue
│ │ └── index.vue
├── vue-router.d.ts
└── vuex.d.ts
├── tsconfig.json
├── vue.config.js
└── yarn.lock
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | **/node_modules
2 | **/.git
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{js,jsx,ts,tsx,vue}]
2 | indent_style = space
3 | indent_size = 2
4 | trim_trailing_whitespace = true
5 | insert_final_newline = true
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .cache
3 | /node_modules
4 | /dist
5 |
6 | # Log files
7 | npm-debug.log*
8 | yarn-error.log*
9 |
10 | # Editor directories and files
11 | .idea
12 | .vscode
13 |
--------------------------------------------------------------------------------
/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 | cache:
2 | untracked: true
3 | paths:
4 | - node_modules/
5 |
6 | stages:
7 | - install
8 | - lint
9 |
10 | install:
11 | stage: install
12 | script: yarn
13 |
14 | lint:
15 | stage: lint
16 | script: yarn lint
17 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | registry=https://registry.npm.taobao.org
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:16.9 AS origin_builder
2 | WORKDIR /app
3 | COPY package.json yarn.lock ./
4 | RUN yarn install --frozen-lockfile
5 | COPY . .
6 | RUN yarn run build
7 |
8 | FROM ruisin/spa-webserver:0.8.0-beta2-onbuild as runtime
9 | COPY --from=origin_builder /app/dist/ ./dist/public
10 | RUN mv ./dist/public/index.html ./dist
11 |
12 | FROM scratch
13 | COPY --from=runtime /app /
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | const installCommon = require('./src/middler/babelPlugin/installCommon.js')
2 |
3 | const isPro = process.env.DEPLOY_ENV === 'production' || process.env.DEPLOY_ENV === 'webpack'
4 | const config = {
5 | presets: [
6 | [
7 | '@vue/cli-plugin-babel/preset',
8 | {
9 | useBuiltIns: 'usage' // 按需引入polyfill
10 | }
11 | ]
12 | ],
13 | plugins: [
14 | '@babel/plugin-syntax-jsx',
15 | // babel-plugin-import 按需加载ant-design-vue
16 | [
17 | 'import',
18 | {
19 | libraryName: 'ant-design-vue',
20 | libraryDirectory: 'es',
21 | style: true // 加载less文件,再通过vue.config.js配置less-loader来定制主题
22 | }
23 | ],
24 | '@babel/plugin-proposal-optional-chaining' // ts可选链语法支持
25 | ]
26 | }
27 |
28 | if (isPro) {
29 | config.plugins.push(installCommon)
30 | }
31 |
32 | module.exports = config
33 |
--------------------------------------------------------------------------------
/build/tag.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | # 指定分支,默认为 develop 分支(yarn release develop)
4 | branch=$1
5 | if [ -z $branch ]
6 | then
7 | branch=develop
8 | fi
9 |
10 | read -p "确定将 $branch 分支合并到 master 分支并发布? (y/n)" -n 1 -r
11 | echo
12 |
13 | if [[ $REPLY =~ ^[Yy]$ ]]
14 | then
15 | # 合并代码到 master 分支
16 | git checkout master
17 | git merge $branch
18 |
19 | # 指定上线版本,如 1.0.0,最后会生成 tag v1.0.0
20 | echo "输入当前上线的版本号: "
21 | read VERSION
22 |
23 | read -p "当前版本 $VERSION - are you sure? (y/n)" -n 1 -r
24 | echo
25 |
26 | if [[ $REPLY =~ ^[Yy]$ ]]
27 | then
28 | # 修改版本号
29 | yarn version --new-version $VERSION --no-git-tag-version --allow-same-version
30 |
31 | # 生成变更日志, 打 tag
32 | yarn changelog
33 | git add .
34 | git commit -m "release: $VERSION" --no-verify
35 | git tag v$VERSION
36 |
37 | # 提交代码
38 | git push origin master
39 | git push origin refs/tags/v$VERSION
40 |
41 | # 合并代码到 develop 分支
42 | git checkout develop
43 | git rebase master
44 | git push origin develop
45 | else
46 | echo '取消发布'
47 | fi
48 |
49 | else
50 | echo '取消发布'
51 | fi
52 |
53 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ['@commitlint/config-conventional']
3 | }
4 |
--------------------------------------------------------------------------------
/config/default.yaml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eventtracing/easyinsight-front/1ccfe5b7a287b6f26b48c9dc6d7d40526d947fc2/config/default.yaml
--------------------------------------------------------------------------------
/docs/实时测试.md:
--------------------------------------------------------------------------------
1 | # 1.2.0
2 | > 1.2.0版本需求点有大功能需求点如下
1.增加埋点测试大模块,本期做的是大模块里的第一个模块实时测试
2. 对象管理里页面元素增加了一个路径的字段,用于绑定端路径
3 |
4 |
5 |
6 | ## 实时测试
7 | 该版需要主要是为了帮助客户端人员在埋点还未上线的时候就可以用手机扫码进行端版本需求埋点测试
8 |
9 | ### 列表页
10 |
11 | 1. 常规筛选项
12 | 2. 列表(前端分页)
13 | ```
14 | 1.规则校验
15 | 不同版本的需求下相同的对象不能选择
16 | 不同端版本的需求不能选择
17 | 不同基线版本的需求不能选择
18 | 2.实时日志
19 | ```
20 | 扫码进测试详情, 选择对比的需求后点击规则校验会触发后台校验机制, 若是通过的话则展示一个二维码, 所以建立起socket连接, 等待客户端连接成功的消息传回后再进入的测试详情页
21 |
22 | ### 详情页
23 |
24 | 1. 用户终端
25 | 2. 客户端连接状态
26 | 3. 用户连接时间
27 | 4. 该需求或者该对象下埋点的对象以及对应埋点对象的日志条数
28 | 5. 规则校验, 对比客户端传回的埋点对象和需求下定义的对象进行diff比较以此来获取对应的错误信息
29 | 6. 查看实时日志, 不对比
30 | 7. 规则校验和实时日志都是通过socket连接自动传回给web端的
31 |
32 | ## 对象管理
33 |
34 | ### 对象添加编辑查看
35 | 当对象类型是页面类型的时候需要添加一个路由字段, 添加规则如下:
36 |
37 | ```
38 | 1. 对象oid可以映射多个不同的路由
39 | 2. 同一个路由只能对应同一个oid
40 | 3. Andriod与Iphone的所有路由都放置在同一个输入框里书写,最后取并集即可
41 | 4. 编辑页面元素时可以修改路由信息
42 | ```
--------------------------------------------------------------------------------
/docs/技术文档.md:
--------------------------------------------------------------------------------
1 | # 技术文档
2 |
3 | - vue ^3.2.0
4 | - template/pug
5 | - script setup / optionAPI + TS
6 | - less
7 | - vuex ^4.0.0
8 | - vue-router ^4.0.0
9 | - ant-design-vue ^2.1.7
10 | - vite(dev)
11 | - webpack(pro)
12 |
13 | ## 注意事项
14 | - vite是作为开发环境开发,而为了保证线上稳定性则在生产环境使用webpack,当更改打包配置时需要同步两个配置(vite.config.js/vue.config.js)
15 | - 开发环境遇到页面不断循环刷新的时候,采取以下步骤
16 | - 点击浏览器的x,禁止页面刷新,因为该过程其实是当前浏览器缓存里的eis-token过期,所以在检测登录状态时一直在重定向到aac认证中心页面,aac有防暴力登录的政策,会在一定登录次数后禁止某段时间再次登录,所以需要先禁止页面继续刷新
17 | - 登录到代理环境下对应的线上环境获取到对应的cookie下的eis-token的最新值
18 | - 随后返回刚才的页面将token替换掉然后刷新页面
19 | - 完成
20 | - vue3.x依旧支持optionsAPI的写法
--------------------------------------------------------------------------------
/env.js:
--------------------------------------------------------------------------------
1 | const DOMAIN = {
2 | // 开发环境域名
3 | dev: "localhost",
4 | // 测试环境域名
5 | test: "localhost",
6 | // 线上环境域名
7 | online: "localhost",
8 | };
9 |
10 | module.exports = { DOMAIN };
11 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%- title %>
9 |
10 |
11 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | preset: "@vue/cli-plugin-unit-jest/presets/typescript-and-babel",
3 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "vue"],
4 | moduleNameMapper: {
5 | "^@/(.*)$": "/src/$1",
6 | },
7 | testMatch: ["**/views/**/__tests__/**/unit/EventTracker.spec.ts"],
8 | transformIgnorePatterns: [
9 | "/node_modules/(?!(ant-design-vue|@babel|@vue|@ant-design|lodash-es)/)",
10 | ],
11 | watchPathIgnorePatterns: ["/node_modules/"],
12 | setupFiles: ["/src/components/register-test.ts"],
13 | snapshotSerializers: ["/node_modules/jest-serializer-vue"],
14 | };
15 |
--------------------------------------------------------------------------------
/mock/index.js:
--------------------------------------------------------------------------------
1 | // usage: https://github.com/xuxihai123/vue-cli-plugin-mock
2 | module.exports = {
3 | 'GET /api/cjd': {
4 | // obj
5 | id: 1,
6 | username: 'kenny',
7 | sex: 6
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eventtracing/easyinsight-front/1ccfe5b7a287b6f26b48c9dc6d7d40526d947fc2/public/favicon.png
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= htmlWebpackPlugin.options.title %>
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
49 |
50 |
55 |
--------------------------------------------------------------------------------
/src/assets/iconfont.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
--------------------------------------------------------------------------------
/src/bus.ts:
--------------------------------------------------------------------------------
1 | import { EventEmitter } from 'eventemitter3'
2 |
3 | const emitter = new EventEmitter()
4 | export default {
5 | // @ts-ignore
6 | $on: (...args) => emitter.on(...args),
7 | // @ts-ignore
8 | $once: (...args) => emitter.once(...args),
9 | // @ts-ignore
10 | $off: (...args) => emitter.off(...args),
11 | // @ts-ignore
12 | $emit: (...args) => emitter.emit(...args)
13 | }
14 |
--------------------------------------------------------------------------------
/src/components/README.md:
--------------------------------------------------------------------------------
1 | # components
2 |
3 | > 项目通用组件
4 |
5 | ## 目录说明
6 |
7 | ```
8 | |-- ant-design
9 | |-- index.ts antd组件导入
10 | |-- common 通用组件
11 | |-- m-filter-select 支持虚拟滚动的下拉选择组件
12 | |-- u-divider.vue 分割线组件
13 | |-- u-filter-select.vue 筛选组件,常用于列表页筛选
14 | |-- u-single-select.vue 支持虚拟滚动的单选组件
15 | |-- u-tag.vue tag 组件
16 | |-- layout 布局组件
17 | |-- topbar topbar 组件
18 | |-- u-collapse.vue 折叠面板组件
19 | |-- u-info-item.vue 信息 item 组件
20 | |-- u-info.vue 信息组组件,子节点为 u-info-item
21 | |-- u-layout.vue 全局布局组件
22 | |-- u-left-right.vue 左右布局组件
23 | |-- u-sidebar.vue 侧边栏组件
24 | |-- u-topbar.vue 顶部栏组件
25 | |-- modal 弹窗组件
26 | |-- ImagePreviewModal.vue 图片预览弹窗
27 | |-- specific 业务组件
28 | |-- s-editor.vue 富文本组件
29 | |-- s-page-top.vue 页面顶部布局组件
30 | |-- s-table-search.vue 列表页搜索、刷新组件
31 | |-- s-upload-image.vue 图片上传组件(用于坑位创建、编辑)
32 | |-- s-user-select.vue 支持分页搜索的用户选择组件
33 | |-- upload-request.js 图片上传请求封装
34 | |-- register.ts 组件注册
35 | ```
36 |
--------------------------------------------------------------------------------
/src/components/ant-design/icons.ts:
--------------------------------------------------------------------------------
1 | import {
2 | SearchOutlined,
3 | UploadOutlined,
4 | QuestionCircleOutlined,
5 | DownOutlined,
6 | CheckOutlined,
7 | CloseOutlined,
8 | ReloadOutlined,
9 | PlusSquareOutlined,
10 | EditOutlined,
11 | DeleteOutlined,
12 | SyncOutlined,
13 | SaveOutlined,
14 | FileSearchOutlined,
15 | SettingOutlined,
16 | ExclamationCircleOutlined,
17 | PlusOutlined,
18 | LeftOutlined,
19 | RightOutlined
20 | } from '@ant-design/icons-vue'
21 |
22 | export default {
23 | install(Vue) {
24 | Vue.component(SearchOutlined.name, SearchOutlined)
25 | Vue.component(UploadOutlined.name, UploadOutlined)
26 | Vue.component(QuestionCircleOutlined.name, QuestionCircleOutlined)
27 | Vue.component(DownOutlined.name, DownOutlined)
28 | Vue.component(CheckOutlined.name, CheckOutlined)
29 | Vue.component(CloseOutlined.name, CloseOutlined)
30 | Vue.component(ReloadOutlined.name, ReloadOutlined)
31 | Vue.component(PlusSquareOutlined.name, PlusSquareOutlined)
32 | Vue.component(EditOutlined.name, EditOutlined)
33 | Vue.component(DeleteOutlined.name, DeleteOutlined)
34 | Vue.component(SyncOutlined.name, SyncOutlined)
35 | Vue.component(SaveOutlined.name, SaveOutlined)
36 | Vue.component(FileSearchOutlined.name, FileSearchOutlined)
37 | Vue.component(SettingOutlined.name, SettingOutlined)
38 | Vue.component(ExclamationCircleOutlined.name, ExclamationCircleOutlined)
39 | Vue.component(PlusOutlined.name, PlusOutlined)
40 | Vue.component(LeftOutlined.name, LeftOutlined)
41 | Vue.component(RightOutlined.name, RightOutlined)
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/components/baseInstall/m-image-preivew/index.js:
--------------------------------------------------------------------------------
1 | import { createApp } from "vue";
2 | import Preview from "./index.vue";
3 | import Iconfont from "../../common/m-icon-font/index.vue";
4 |
5 | function genSingleton() {
6 | const PreviewContructor = createApp(Preview);
7 | PreviewContructor.component(Iconfont.name, Iconfont);
8 | const el = document.createElement("div");
9 | document.body.appendChild(el);
10 | return PreviewContructor.mount(el);
11 | }
12 |
13 | export default {
14 | install(Vue) {
15 | function PreviewEntity(options) {
16 | let instance = genSingleton();
17 | Object.assign(instance._.props, options);
18 | instance.show(true);
19 | instance.$watch("visible", (n) => {
20 | if (!n) {
21 | document.body.removeChild(instance.$el.parentNode);
22 | instance = null;
23 | }
24 | });
25 | }
26 |
27 | Vue.config.globalProperties.$preview = PreviewEntity;
28 | },
29 | };
30 |
--------------------------------------------------------------------------------
/src/components/common/index.ts:
--------------------------------------------------------------------------------
1 | import UDividerDash from './u-divider-dash.vue'
2 | import UDivider from './u-divider.vue'
3 | import UFilterSelect from './u-filter-select.vue'
4 | import USingleSelect from './u-single-select.vue'
5 | import USpinner from './u-spinner.vue'
6 | import UTag from './u-tag.vue'
7 | import UDrawFooter from './m-drawer-footer/index.vue'
8 | import UIconFont from './m-icon-font/index.vue'
9 | import RowSelectionTable from './m-rowselect-table/index.vue'
10 |
11 | export default {
12 | install(Vue) {
13 | Vue.component(UDividerDash.name, UDividerDash)
14 | Vue.component(UDivider.name, UDivider)
15 | Vue.component(UFilterSelect.name, UFilterSelect)
16 | Vue.component(USingleSelect.name, USingleSelect)
17 | Vue.component(USpinner.name, USpinner)
18 | Vue.component(UTag.name, UTag)
19 | Vue.component(UDrawFooter.name, UDrawFooter)
20 | Vue.component(UIconFont.name, UIconFont)
21 | Vue.component(RowSelectionTable.name, RowSelectionTable)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/common/m-drawer-footer/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
35 |
36 |
50 |
--------------------------------------------------------------------------------
/src/components/common/m-filter-select/menu/menu.less:
--------------------------------------------------------------------------------
1 | @hover-color: #e6efff;
2 |
3 | .mm-menu {
4 | min-width: 140px;
5 | width: auto;
6 | max-width: 400px;
7 | max-height: 330px;
8 | padding: 4px 0;
9 | border-radius: 2px;
10 | background: #fff;
11 | box-shadow: 0 2px 8px rgba(0,0,0,.15);
12 | z-index: 1050;
13 | overflow-y: auto;
14 | .mm-menu-item {
15 | height: 32px;
16 | line-height: 32px;
17 | padding: 0 20px 0 10px;
18 | color: @text-color;
19 | white-space: nowrap;
20 | position: relative;
21 | overflow: hidden;
22 | word-wrap: normal;
23 | white-space: nowrap;
24 | text-overflow: ellipsis;
25 | cursor: pointer;
26 | text-align: left;
27 | &:not(.disabled):hover {
28 | background-color: @hover-color;
29 | }
30 | &.selected:not(.hover) {
31 | font-weight: 600;
32 | background-color: #fafafa;
33 | padding-right: 32px;
34 | }
35 | .anticon-check {
36 | position: absolute;
37 | right: 10px;
38 | top: 50%;
39 | transform: translateY(-50%);
40 | color: @primary-color;
41 | }
42 | }
43 | .ant-divider-horizontal,
44 | .ant-divider {
45 | margin: 0;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/components/common/m-filter-select/menu/type.ts:
--------------------------------------------------------------------------------
1 | export interface SelectDropdownMenuData {
2 | key: string | number
3 | value: string
4 | isAll?: boolean // 是否是顶部的全部筛选项,如果是全部,则和清空选择的效果一样
5 | divider?: boolean // 是否显示是divider, 如果是divider,则该项的key和value值不会写在里面
6 | current?: boolean // 是否是当前用户快捷选项,如果是则选中里面的当前用户
7 | customItem?: boolean // 是否不参与全选等快捷选项
8 | name?: string // 一般用于定义回填属性
9 | [key: string]: any
10 | }
11 |
--------------------------------------------------------------------------------
/src/components/common/m-icon-font/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
23 |
24 |
33 |
--------------------------------------------------------------------------------
/src/components/common/u-divider-dash.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
18 |
--------------------------------------------------------------------------------
/src/components/common/u-divider.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
16 |
17 |
25 |
--------------------------------------------------------------------------------
/src/components/common/u-mutiple-select.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
50 |
--------------------------------------------------------------------------------
/src/components/common/u-single-select.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
50 |
--------------------------------------------------------------------------------
/src/components/common/u-spinner.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
13 |
14 |
25 |
--------------------------------------------------------------------------------
/src/components/common/u-tag.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
24 |
25 |
36 |
--------------------------------------------------------------------------------
/src/components/layout/index.ts:
--------------------------------------------------------------------------------
1 | import ULeftRight from './u-left-right.vue'
2 |
3 | export default {
4 | install(Vue) {
5 | Vue.component(ULeftRight.name, ULeftRight)
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/layout/topbar/assets/toggle-bar.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/src/components/layout/topbar/components/IconFont.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
25 |
26 |
35 |
--------------------------------------------------------------------------------
/src/components/layout/topbar/components/Link.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ name }}
13 |
14 | {{ name }}
15 |
16 |
17 |
18 |
42 |
--------------------------------------------------------------------------------
/src/components/layout/topbar/index.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | // eslint-disable-next-line
3 | import { default as TopBar } from './Topbar.vue'
4 |
5 | // Declare install function executed by Vue.use()
6 | function install(Vue) {
7 | if (install.installed) return
8 | install.installed = true
9 | Vue.component('TopBar', TopBar)
10 | }
11 |
12 | // Create module definition for Vue.use()
13 | const plugin = {
14 | install
15 | }
16 |
17 | // Auto-install when vue is found (eg. in browser via
16 |
--------------------------------------------------------------------------------
/src/components/layout/topbar/quick-navigation/SortableItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
16 |
--------------------------------------------------------------------------------
/src/components/layout/topbar/styles/global.less:
--------------------------------------------------------------------------------
1 | @import './var.less';
2 |
3 | *,
4 | *::before,
5 | *::after {
6 | box-sizing: border-box;
7 | }
8 |
9 | input[type='checkbox'] {
10 | padding: 0;
11 | touch-action: manipulation;
12 | }
13 |
14 | input,
15 | button,
16 | select,
17 | optgroup,
18 | textarea {
19 | margin: 0;
20 | color: inherit;
21 | font-size: inherit;
22 | font-family: inherit;
23 | line-height: inherit;
24 | }
25 |
26 | .m-topbar,
27 | .m-topbar-dropdown {
28 | ul,
29 | li {
30 | margin: 0;
31 | padding: 0;
32 | list-style: none;
33 | }
34 | a, a:focus {
35 | text-decoration: none;
36 | }
37 | a.a-link, a.spa-link {
38 | display: block;
39 | padding: 0 10px;
40 | color: @topbar-text-color !important;
41 | &:not(.disabled):hover {
42 | color: @topbar-text-hover-color !important;
43 | }
44 |
45 | &.active, &.router-link-active {
46 | color: @topbar-text-hover-color !important;
47 | }
48 |
49 | &.disabled {
50 | pointer-events: none;
51 | }
52 | }
53 | }
54 |
55 | .topbar-tooltip .ant-tooltip-content {
56 | .ant-tooltip-arrow::before {
57 | background: #3a3e50 !important;
58 | }
59 | .ant-tooltip-inner {
60 | font-size: 12px !important;
61 | padding: 5px 8px !important;
62 | border-radius: 2px !important;
63 | line-height: 1.5 !important;
64 | min-height: auto !important;
65 | background: #3a3e50 !important;
66 | box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.16) !important;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/components/layout/topbar/styles/var.less:
--------------------------------------------------------------------------------
1 | @header-height: 48px;
2 | @primary-color: #103ffa; // 主色
3 | @topbar-text-color: rgba(255, 255, 255, 0.72); // topbar 文本色
4 | @topbar-text-hover-color: #fff; // topbar hover 文本色
5 | @topbar-background-color-secondary: #3a3e50; // 用户操作、项目集群等面板的背景色
6 | @topbar-text-color-base: #787890; // 导航 panel 文本色
7 | @topbar-icon-color: #d8d9e3; // 产品 logo 默认颜色
8 |
--------------------------------------------------------------------------------
/src/components/layout/topbar/type.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 项目信息
3 | */
4 | export interface ProductItem {
5 | name: string
6 | id: number | string
7 | }
8 |
9 | /**
10 | * 项目、集群切换信息
11 | */
12 | export type SwitchInfo = ProductItem
13 |
14 | export interface NavigationItem {
15 | key: string // 子产品唯一标识符
16 | category: string // 组类别
17 | order: number // 组排序
18 | name: string // 子产品名
19 | iconName: string | Function // 图标名或渲染函数
20 | url: string // 子产品地址
21 | prefixIcon?: string // 后缀图标,逗号分隔:'new'
22 | clickAction?: 0 | 1 // 鼠标点击后的行为,0: 当前页面跳转,1: 新开页面跳转
23 | }
24 |
25 | export interface NavigationGroup {
26 | category: string
27 | order: number
28 | navItems: NavigationItem[]
29 | }
30 |
31 | export interface OuterLinkItem {
32 | name: string // 模块名
33 | url: string // 地址
34 | prefixIcon: string // 后缀图标,逗号分隔:'new'
35 | }
36 |
37 | export type UserActionItem =
38 | | {
39 | type: 'link'
40 | name: string
41 | url: string
42 | clickAction?: 0 | 1 // 鼠标点击后的行为,0: 当前页面跳转,1: 新开页面跳转
43 | }
44 | | {
45 | type: 'button'
46 | name: string
47 | onClick: Function
48 | }
49 |
--------------------------------------------------------------------------------
/src/components/layout/topbar/utils/loadJs.ts:
--------------------------------------------------------------------------------
1 | const customCache = new Set()
2 |
3 | export default function loadJs(scriptUrl: string) {
4 | if (
5 | typeof document !== 'undefined' &&
6 | typeof window !== 'undefined' &&
7 | typeof document.createElement === 'function' &&
8 | typeof scriptUrl === 'string' &&
9 | scriptUrl.length &&
10 | !customCache.has(scriptUrl)
11 | ) {
12 | const script = document.createElement('script')
13 | script.setAttribute('src', scriptUrl)
14 | script.setAttribute('data-namespace', scriptUrl)
15 | customCache.add(scriptUrl)
16 | document.body.appendChild(script)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/components/layout/u-collapse.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
33 |
34 |
64 |
--------------------------------------------------------------------------------
/src/components/layout/u-info.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
36 |
--------------------------------------------------------------------------------
/src/components/layout/u-layout.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
31 |
32 |
50 |
--------------------------------------------------------------------------------
/src/components/layout/u-left-right.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
31 |
--------------------------------------------------------------------------------
/src/components/layout/u-sidebar.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
33 |
34 |
39 |
--------------------------------------------------------------------------------
/src/components/register-test.ts:
--------------------------------------------------------------------------------
1 | import { config } from '@vue/test-utils'
2 | import AntDesign from './ant-design/index'
3 | import BasicComponents from '@/ndsc-vue3/basic-components/lib'
4 | import '@/ndsc-vue3/basic-components/lib/style/index.less'
5 | import Preview from '@/components/baseInstall/m-image-preivew/index.js'
6 | import Icons from './ant-design/icons'
7 | import JsonViewer from 'vue3-json-viewer'
8 | import Register from './common'
9 | import Layout from './layout'
10 | import Specific from './specific'
11 | import { RouterLink } from 'vue-router'
12 | import { Menu, Form, Select, Radio } from 'ant-design-vue'
13 |
14 | const RadioGroup = Radio.Group
15 | const MenuItem = Menu.Item
16 | const FormItem = Form.Item
17 | const SelectOptions = Select.Option
18 | const Install = {
19 | use(component) {
20 | this.component(component.name, component)
21 | },
22 | component(name, component) {
23 | config.global.components[name] = component
24 | },
25 | directive(name, directive) {
26 | config.global.directives[name] = directive
27 | },
28 | config: {
29 | globalProperties: {}
30 | }
31 | }
32 |
33 | AntDesign(Install)
34 | Preview.install(Install)
35 | BasicComponents.install(Install)
36 | Icons.install(Install)
37 | JsonViewer.install(Install)
38 | Register.install(Install)
39 | Layout.install(Install)
40 | Specific.install(Install)
41 | Install.use(RouterLink)
42 | Install.use(MenuItem)
43 | Install.use(FormItem)
44 | Install.use(RadioGroup)
45 | Install.directive('auth', {
46 | mounted() {
47 | return true
48 | }
49 | })
50 |
51 | // @ts-ignore
52 | window.matchMedia = function () {
53 | return {
54 | addListener() {
55 | return undefined
56 | },
57 | removeListener() {
58 | return undefined
59 | }
60 | }
61 | }
62 | config.global.mocks.$get = function () {
63 | return 'get'
64 | }
65 | config.global.components[SelectOptions.displayName] = SelectOptions
66 |
--------------------------------------------------------------------------------
/src/components/register.ts:
--------------------------------------------------------------------------------
1 | import AntDesign from './ant-design/index'
2 | import BasicComponents from '@/ndsc-vue3/basic-components/lib'
3 | import '@/ndsc-vue3/basic-components/lib/style/index.less'
4 | import Preview from '@/components/baseInstall/m-image-preivew/index.js'
5 | import Icons from './ant-design/icons'
6 | import JsonViewer from 'vue3-json-viewer'
7 |
8 | export default function Register(Vue) {
9 | Vue.use(AntDesign)
10 | Vue.use(Preview)
11 | Vue.use(BasicComponents)
12 | Vue.use(Icons)
13 | Vue.use(JsonViewer)
14 | /**
15 | * 使用 require.context 批量注册组件注意点
16 | 1. 组件需指定 name 属性, 如:
17 |
23 | 2. 注册时使用 component.options.name,component.name 默认是class名称,打包后会被压缩,名称会变化
24 | */
25 | // UI组件
26 |
27 | const commonContext = require.context('./common', true, /\.vue$/)
28 |
29 | commonContext.keys().forEach((key) => {
30 | const component = commonContext(key).default
31 | Vue.component(component.name, component)
32 | }) // 布局组件
33 |
34 | const layoutContext = require.context('./layout', false, /\.vue$/)
35 |
36 | layoutContext.keys().forEach((key) => {
37 | const component = layoutContext(key).default
38 | Vue.component(component.name, component)
39 | }) // 业务组件
40 |
41 | const specificContext = require.context('./specific', false, /\.vue$/)
42 |
43 | specificContext.keys().forEach((key) => {
44 | const component = specificContext(key).default
45 | Vue.component(component.name, component)
46 | })
47 | }
48 |
--------------------------------------------------------------------------------
/src/components/specific/index.ts:
--------------------------------------------------------------------------------
1 | import SUserSelect from './s-user-select.vue'
2 |
3 | export default {
4 | install(Vue) {
5 | Vue.component(SUserSelect.name, SUserSelect)
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/specific/s-page-top.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
31 |
32 |
37 |
--------------------------------------------------------------------------------
/src/components/specific/s-table-search.vue:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 |
49 |
--------------------------------------------------------------------------------
/src/middler/README.md:
--------------------------------------------------------------------------------
1 | # middler文件夹需知
2 | > middler文件夹是给打包编译时做自动转换处理的文件包
3 |
4 | ## 前言
5 | 背景条件是目前项目开发打包工具迁移到了vite,但是生产环境考虑到线上稳定性还是依旧沿用了webpack打包编译方式
6 |
7 | ## babelPlugin
8 | 由于vite的全局注册API与webpack具有差异,故分别编写了一份注册文件,installCommon.js在打包编译的时候根据当前打包软件来区别使用哪个注册文件
9 |
10 | ## vitePlugin
11 | 由于vite已经放弃了es5的转译功能,支持的浏览器是es6及其以上的版本,所以vite舍弃掉了babel,然后这里写的自定义的vitePlugin,用来模拟babel的转译
12 |
13 | #### antDesignVueImport
14 | 作用: 将ant-design-vue按需加载
15 |
16 | #### injectAction
17 | 作用: 由于ant-design-vue1.x存在浏览器esm兼容问题,所以自定义插件来做处理,现在升级到2.x可以不再使用
18 |
19 |
20 | ## 结束
21 | 其余的文件暂时没有用到,可以忽略
--------------------------------------------------------------------------------
/src/middler/babelPlugin/FunctionInstrumentation/AuthoirtyFeat.js:
--------------------------------------------------------------------------------
1 | const { declare } = require("@babel/helper-plugin-utils");
2 |
3 | module.exports = declare(function (api) {
4 | api.assertVersion("^7.0.0");
5 |
6 | return {
7 | visitor: {
8 | Program() {
9 | // something
10 | },
11 | },
12 | };
13 | });
14 |
--------------------------------------------------------------------------------
/src/middler/babelPlugin/installCommon.js:
--------------------------------------------------------------------------------
1 | const { declare } = require('@babel/helper-plugin-utils')
2 |
3 | module.exports = declare(function (api) {
4 | api.assertVersion('^7.0.0')
5 | return {
6 | name: 'babel-plugin-replace-import-meta',
7 | visitor: {
8 | ImportDeclaration(path) {
9 | const { source } = path.node
10 | if (source.value === './components/register-vite') {
11 | source.value = './components/register'
12 | }
13 | }
14 | }
15 | }
16 | })
17 |
--------------------------------------------------------------------------------
/src/middler/vitePlugin/authorityFeat.js:
--------------------------------------------------------------------------------
1 | // const babelParser = require('@babel/parser')
2 | // const traverse = require('@babel/traverse').default
3 | // const generator = require('@babel/generator').default
4 |
5 | function authorityFeat() {
6 | return {
7 | name: 'antd-vite-authority-feat-plugin',
8 | transform(code) {
9 | return {
10 | code
11 | }
12 | }
13 | }
14 | }
15 | module.exports = authorityFeat
16 | authorityFeat.default = authorityFeat
17 |
--------------------------------------------------------------------------------
/src/middler/vitePlugin/injectAntIcon.js:
--------------------------------------------------------------------------------
1 | const babelParser = require('@babel/parser')
2 | const traverse = require('@babel/traverse').default
3 | const generator = require('@babel/generator').default
4 |
5 | function antdViteImportPlugin() {
6 | return {
7 | name: 'antd-vite-modeify-icon-plugin',
8 | transform(code) {
9 | if (code.includes('@ant-design')) {
10 | const ast = babelParser.parse(code, {
11 | sourceType: 'unambiguous'
12 | })
13 |
14 | traverse(ast, {
15 | FunctionDeclaration(path) {
16 | const declarationPath = path.get('declaration').parentPath
17 | if (declarationPath.node.id.name === 'withSuffix') {
18 | const casesPath = declarationPath.get('body.body.0.cases')
19 | const replaceAst = casesPath[0].node.consequent
20 | casesPath[3].node.consequent = replaceAst
21 | }
22 | }
23 | })
24 |
25 | return {
26 | code: generator(ast).code,
27 | map: null
28 | }
29 | }
30 | return {
31 | code,
32 | map: null
33 | }
34 | }
35 | }
36 | }
37 | module.exports = antdViteImportPlugin
38 | antdViteImportPlugin.default = antdViteImportPlugin
39 |
--------------------------------------------------------------------------------
/src/middler/webpackLoader/authorityFeat.js:
--------------------------------------------------------------------------------
1 | // const compiler = require('vue-template-compiler')
2 |
3 | module.exports = function (code) {
4 | return code;
5 | };
6 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/components/s-sync-button/index.ts:
--------------------------------------------------------------------------------
1 | import SSyncButton from './s-sync-button.vue'
2 |
3 | SSyncButton.install = function (Vue) {
4 | Vue.component(SSyncButton.options.name, SSyncButton)
5 | }
6 |
7 | export default SSyncButton
8 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/components/s-sync-button/s-sync-button.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
32 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/components/u-copy/index.ts:
--------------------------------------------------------------------------------
1 | import UCopy from './u-copy.vue'
2 |
3 | UCopy.install = function (Vue) {
4 | Vue.component(UCopy.options.name, UCopy)
5 | }
6 |
7 | export default UCopy
8 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/components/u-copy/u-copy.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 复制
5 |
6 |
7 |
8 |
9 |
42 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/components/u-drawer/index.ts:
--------------------------------------------------------------------------------
1 | import UDrawer from './u-drawer.vue'
2 |
3 | UDrawer.install = function (Vue) {
4 | Vue.component(UDrawer.options.name, UDrawer)
5 | }
6 |
7 | export default UDrawer
8 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/components/u-hint-tooltip/index.ts:
--------------------------------------------------------------------------------
1 | import UHintTooltip from './u-hint-tooltip.vue'
2 |
3 | UHintTooltip.install = function (Vue) {
4 | Vue.component(UHintTooltip.options.name, UHintTooltip)
5 | }
6 |
7 | export default UHintTooltip
8 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/components/u-icon-button/index.ts:
--------------------------------------------------------------------------------
1 | import UIconButton from './u-icon-button.vue'
2 |
3 | UIconButton.install = function (Vue) {
4 | Vue.component(UIconButton.options.name, UIconButton)
5 | }
6 |
7 | export default UIconButton
8 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/components/u-icon-font/index.ts:
--------------------------------------------------------------------------------
1 | import UIconFont from './u-icon-font.vue'
2 |
3 | UIconFont.install = function (Vue) {
4 | Vue.component(UIconFont.options.name, UIconFont)
5 | }
6 |
7 | export default UIconFont
8 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/components/u-icon-font/u-icon-font.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
10 |
33 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/components/u-modal/index.ts:
--------------------------------------------------------------------------------
1 | import UModal from './u-modal.vue'
2 |
3 | UModal.install = function (Vue) {
4 | Vue.component(UModal.options.name, UModal)
5 | }
6 |
7 | export default UModal
8 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/components/u-modal/u-modal.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
14 |
15 |
16 |
17 |
51 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/components/u-status-icon/index.ts:
--------------------------------------------------------------------------------
1 | import UStatusIcon from './u-status-icon.vue'
2 |
3 | UStatusIcon.install = function (Vue) {
4 | Vue.component(UStatusIcon.options.name, UStatusIcon)
5 | }
6 |
7 | export default UStatusIcon
8 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/components/u-status-icon/u-status-icon.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
40 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/components/u-text-button/index.ts:
--------------------------------------------------------------------------------
1 | import UTextButton from './u-text-button.vue'
2 |
3 | UTextButton.install = function (Vue) {
4 | Vue.component(UTextButton.options.name, UTextButton)
5 | }
6 |
7 | export default UTextButton
8 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/components/u-text-button/u-text-button.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 | {{ text }}
9 |
10 |
11 |
12 |
35 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/components/u-text-tooltip/index.ts:
--------------------------------------------------------------------------------
1 | import UTextTooltip from './u-text-tooltip.vue'
2 |
3 | UTextTooltip.install = function (Vue) {
4 | Vue.component(UTextTooltip.options.name, UTextTooltip)
5 | }
6 |
7 | export default UTextTooltip
8 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/directives/v-click-outside/index.ts:
--------------------------------------------------------------------------------
1 | import VClickOutside from './v-click-outside'
2 |
3 | export default {
4 | name: 'click-outside',
5 | install: function (Vue: any) {
6 | Vue.directive('click-outside', VClickOutside)
7 | },
8 | ...VClickOutside
9 | }
10 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/directives/v-click-outside/v-click-outside.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | const clear = (el) => {
3 | if (el._clickOutsideHandler) {
4 | document.removeEventListener("click", el._clickOutsideHandler);
5 | }
6 | delete el._clickOutsideHandler;
7 | };
8 |
9 | const bind = (el, value) => {
10 | el._clickOutsideHandler = function clickOutsideHandle(e) {
11 | if (el.contains(e.target)) return false;
12 |
13 | if (value && typeof value === "function") {
14 | value(e);
15 | }
16 | };
17 | setTimeout(() => {
18 | document.addEventListener("click", el._clickOutsideHandler);
19 | });
20 | };
21 |
22 | export default {
23 | mounted(el, { value } = {} as any) {
24 | clear(el);
25 | bind(el, value);
26 | },
27 | update(el, { value, oldValue } = {} as any) {
28 | if (value === oldValue) return;
29 |
30 | clear(el);
31 | bind(el, value);
32 | },
33 | unmounted(el) {
34 | clear(el);
35 | },
36 | };
37 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/directives/v-copy/index.ts:
--------------------------------------------------------------------------------
1 | import VCopy from './v-copy'
2 |
3 | export default {
4 | name: 'copy',
5 | install: function (Vue: any) {
6 | Vue.directive('copy', VCopy)
7 | },
8 | ...VCopy
9 | }
10 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/directives/v-copy/v-copy.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | import { copy } from "../../utils/clipboard";
3 | import { message } from "ant-design-vue";
4 |
5 | const clear = (el) => {
6 | if (el._clickHanlder) {
7 | el.removeEventListener("click", el._clickHanlder);
8 | }
9 | delete el._clickHanlder;
10 | };
11 |
12 | const bind = (el, value) => {
13 | el._clickHanlder = function clickHandler() {
14 | const disabled = el.getAttribute("disabled");
15 | if (disabled !== null) return;
16 |
17 | if (value) {
18 | const success = copy(value);
19 | if (success) {
20 | message.success("复制成功!");
21 | }
22 | }
23 | };
24 | el.addEventListener("click", el._clickHanlder);
25 | };
26 |
27 | export default {
28 | mounted(el, binding) {
29 | clear(el);
30 | bind(el, binding?.value);
31 | },
32 | updated(el, { value, oldValue } = {} as any) {
33 | if (value === oldValue) return;
34 |
35 | clear(el);
36 | bind(el, value);
37 | },
38 | unmounted(el) {
39 | clear(el);
40 | },
41 | };
42 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/directives/v-drag-size/index.ts:
--------------------------------------------------------------------------------
1 | import VDragSize from './v-drag-size'
2 | import './v-drag-size.less'
3 |
4 | export default {
5 | name: 'drag-size',
6 | install: function (Vue: any) {
7 | Vue.directive('drag-size', VDragSize)
8 | },
9 | ...VDragSize
10 | }
11 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/directives/v-drag-size/v-drag-size.less:
--------------------------------------------------------------------------------
1 | .v-drag-size-anchor {
2 | position: absolute;
3 | z-index: 999;
4 | width: 10px;
5 | height: 28px;
6 | background-color: #e0e2e6;
7 | border-radius: 2px;
8 | &::before {
9 | content: '';
10 | width: 2px;
11 | height: 2px;
12 | display: block;
13 | position: absolute;
14 | box-shadow: 4px 8px 0 #4e5973, 4px 13px 0 #4e5973, 4px 18px 0 #4e5973;
15 | border-radius: 50%;
16 | }
17 | &__left,
18 | &__right {
19 | top: 50%;
20 | transform: translateY(-50%);
21 | cursor: ew-resize;
22 | }
23 | &__top,
24 | &__bottom {
25 | left: 50%;
26 | transform: translateX(-50%);
27 | transform: rotate(90deg);
28 | cursor: ns-resize;
29 | }
30 | &__left {
31 | left: -5px;
32 | }
33 | &__right {
34 | right: -5px;
35 | }
36 | &__top {
37 | top: -14px;
38 | }
39 | &__bottom {
40 | bottom: -14px;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/directives/v-ellipsis-title/index.ts:
--------------------------------------------------------------------------------
1 | import VEllipsisTitle from './v-ellipsis-title'
2 |
3 | export default {
4 | name: 'ellipsis-title',
5 | install: function (Vue: any) {
6 | Vue.directive('ellipsis-title', VEllipsisTitle)
7 | },
8 | ...VEllipsisTitle
9 | }
10 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/directives/v-ellipsis-title/v-ellipsis-title.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | mounted(el: HTMLElement, binding: any) {
3 | const lineCount =
4 | !isNaN(Number(binding.arg)) && Number(binding.arg) > 1 ? binding.arg : 1;
5 | if (lineCount === 1) {
6 | el.style.overflow = "hidden";
7 | el.style.whiteSpace = "nowrap";
8 | el.style.textOverflow = "ellipsis";
9 | } else {
10 | el.style.overflow = "hidden";
11 | el.style.textOverflow = "ellipsis";
12 | el.style.display = `-webkit-box`;
13 | el.style["-webkit-line-clamp"] = lineCount;
14 | el.style["-webkit-box-orient"] = "vertical";
15 | }
16 | requestAnimationFrame(() => {
17 | if (
18 | el.scrollWidth > el.offsetWidth ||
19 | el.scrollHeight > el.offsetHeight
20 | ) {
21 | const title = binding?.value || el.innerText;
22 | el.setAttribute("title", title);
23 | } else {
24 | el.removeAttribute("title");
25 | }
26 | });
27 | },
28 | update(el: HTMLElement, binding: any) {
29 | requestAnimationFrame(() => {
30 | if (
31 | el.scrollWidth > el.offsetWidth ||
32 | el.scrollHeight > el.offsetHeight
33 | ) {
34 | el.setAttribute("title", binding?.value || el.innerText);
35 | } else {
36 | el.removeAttribute("title");
37 | }
38 | });
39 | },
40 | };
41 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/directives/v-input-number/index.ts:
--------------------------------------------------------------------------------
1 | import VInputNumber from './v-input-number'
2 |
3 | export default {
4 | name: 'input-number',
5 | install: function (Vue: any) {
6 | Vue.directive('input-number', VInputNumber)
7 | },
8 | ...VInputNumber
9 | }
10 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/shims-tsx.d.ts:
--------------------------------------------------------------------------------
1 | import Vue, { VNode } from 'vue'
2 |
3 | declare global {
4 | namespace JSX {
5 | // tslint:disable no-empty-interface
6 | interface Element extends VNode {}
7 | // tslint:disable no-empty-interface
8 | interface ElementClass extends Vue {}
9 | interface IntrinsicElements {
10 | [elem: string]: any
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import Vue from 'vue'
3 | export default Vue
4 | }
5 |
6 | declare module 'vue-clipboard2'
7 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/style/antd.less:
--------------------------------------------------------------------------------
1 | // antd
2 | @import '~ant-design-vue/lib/tooltip/style/index.less';
3 | @import '~ant-design-vue/lib/icon/style/index.less';
4 | @import '~ant-design-vue/lib/modal/style/index.less';
5 | @import '~ant-design-vue/lib/drawer/style/index.less';
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/style/index.less:
--------------------------------------------------------------------------------
1 | @import 's-sync-button.less';
2 | @import 'u-drawer.less';
3 | @import 'u-icon-button.less';
4 | @import 'u-icon-font.less';
5 | @import 'u-status-icon.less';
6 | @import 'u-text-button.less';
7 | @import 'u-text-tooltip.less';
8 | @import 'u-modal.less';
9 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/style/s-sync-button.less:
--------------------------------------------------------------------------------
1 | .s-sync-button {
2 | font-size: 16px;
3 | }
4 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/style/u-drawer.less:
--------------------------------------------------------------------------------
1 | .u-drawer-wrapper.ant-drawer {
2 | &.c-object__container {
3 | .ant-drawer-main {
4 | position: relative;
5 | padding: 0 !important;
6 | overflow: hidden !important;
7 | }
8 | }
9 |
10 | .ant-drawer-wrapper-body {
11 | display: flex;
12 | flex-direction: column;
13 |
14 | .ant-drawer-title {
15 | margin-right: 24px; // 避免压盖 close icon
16 | }
17 |
18 | .ant-drawer-body {
19 | display: flex;
20 | flex-direction: column;
21 | flex: 1;
22 | min-height: 0;
23 | padding: 0 !important;
24 |
25 | .ant-drawer-main {
26 | flex: 1;
27 | min-height: 0;
28 | padding: 24px;
29 | overflow-y: auto;
30 | }
31 |
32 | .ant-drawer-footer {
33 | border-top: 1px solid rgb(233, 233, 233);
34 | padding: 16px 24px;
35 | background: rgb(255, 255, 255);
36 | text-align: left;
37 | }
38 | }
39 | }
40 |
41 | &.ant-drawer-left {
42 | .ant-drawer-footer {
43 | text-align: right !important;
44 | }
45 | }
46 |
47 | &.ant-drawer-bottom {
48 | .ant-drawer-header {
49 | padding: 10px 24px !important;
50 |
51 | .ant-drawer-title {
52 | margin-right: 0 !important;
53 | }
54 |
55 | .ant-drawer-close {
56 | height: 44px !important;
57 | line-height: 44px !important;
58 | }
59 | }
60 | }
61 | }
62 |
63 | .u-drawer-wrapper.edit-diff-dialog .ant-drawer-wrapper-body .ant-drawer-body .ant-drawer-main {
64 | padding-bottom: 0;
65 | margin-bottom: 53px;
66 | overflow: auto;
67 | }
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/style/u-icon-button.less:
--------------------------------------------------------------------------------
1 | .u-icon-button {
2 | cursor: pointer;
3 | &:hover {
4 | color: #103ffa !important;
5 | }
6 | &__disabled {
7 | cursor: not-allowed !important;
8 | color: #a9a9b8 !important;
9 | }
10 | }
11 |
12 | .u-icon-button-tooltip.ant-tooltip {
13 | .ant-tooltip-inner {
14 | font-size: 12px;
15 | padding: 6px 10px;
16 | border-radius: 4px;
17 | line-height: 1.2;
18 | min-height: auto;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/style/u-icon-font.less:
--------------------------------------------------------------------------------
1 | .u-icon {
2 | width: 1em;
3 | height: 1em;
4 | fill: currentColor;
5 | overflow: hidden;
6 | }
7 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/style/u-modal.less:
--------------------------------------------------------------------------------
1 | .u-modal-wrapper .ant-modal {
2 | .ant-modal-footer {
3 | padding: 10px 24px;
4 | }
5 | .ant-modal-footer__left {
6 | position: absolute;
7 | left: 24px;
8 | bottom: 10px;
9 | height: 32px;
10 | line-height: 32px;
11 | }
12 | }
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/style/u-status-icon.less:
--------------------------------------------------------------------------------
1 | .u-status-icon {
2 | display: inline-flex;
3 | align-items: center;
4 |
5 | &-dot {
6 | position: relative;
7 | width: 8px;
8 | height: 8px;
9 | margin-right: 8px;
10 | border-radius: 50%;
11 | background-color: var(--color);
12 | z-index: 0;
13 | &.wave {
14 | &::before {
15 | content: '';
16 | .wave-circle();
17 | animation: circleAnimationIn 2s ease-out;
18 | animation-iteration-count: infinite;
19 | }
20 | &::after {
21 | content: '';
22 | .wave-circle();
23 | animation: circleAnimationOut 2s ease-out;
24 | animation-iteration-count: infinite;
25 | }
26 | }
27 | }
28 |
29 | .wave-circle {
30 | position: absolute;
31 | z-index: 1;
32 | width: 16px;
33 | height: 16px;
34 | top: -4px;
35 | left: -4px;
36 | border-radius: 50%;
37 | box-sizing: border-box;
38 | border: 1px solid var(--color);
39 | box-shadow: 1px 1px 10px var(--color);
40 | }
41 | }
42 |
43 | @keyframes circleAnimationIn {
44 | 0% {
45 | transform: scale(0.3);
46 | opacity: 0;
47 | }
48 | 25% {
49 | transform: scale(0.3);
50 | opacity: 0.1;
51 | }
52 | 50% {
53 | transform: scale(0.5);
54 | opacity: 0.3;
55 | }
56 | 75% {
57 | transform: scale(0.8);
58 | opacity: 0.5;
59 | }
60 | 100% {
61 | transform: scale(1);
62 | opacity: 0;
63 | }
64 | }
65 |
66 | @keyframes circleAnimationOut {
67 | 0% {
68 | transform: scale(0.3);
69 | opacity: 0;
70 | }
71 | 25% {
72 | transform: scale(0.3);
73 | opacity: 0.1;
74 | }
75 | 50% {
76 | transform: scale(0.3);
77 | opacity: 0.3;
78 | }
79 | 75% {
80 | transform: scale(0.5);
81 | opacity: 0.5;
82 | }
83 | 100% {
84 | transform: scale(0.8);
85 | opacity: 0;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/style/u-text-button.less:
--------------------------------------------------------------------------------
1 | .u-text-button {
2 | display: inline-block;
3 | cursor: pointer;
4 | user-select: none;
5 | color: #103ffa;
6 | &.disabled {
7 | cursor: not-allowed;
8 | color: #a9a9b8;
9 | }
10 | & + .u-text-button {
11 | margin-left: 8px;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/basic-components/lib/style/u-text-tooltip.less:
--------------------------------------------------------------------------------
1 | .u-text-tooltip.ant-tooltip {
2 | max-width: 500px;
3 | .ant-tooltip-arrow {
4 | display: none;
5 | }
6 | .ant-tooltip-content {
7 | .ant-tooltip-inner {
8 | min-height: unset;
9 | min-width: unset;
10 | padding: 2px 8px;
11 | font-size: 13px;
12 | background-color: #fff;
13 | color: #79809a;
14 | border: 1px solid #dedede;
15 | box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.08);
16 | }
17 | }
18 | }
19 |
20 | .u-text-ellipsis {
21 | overflow: hidden;
22 | text-overflow: ellipsis;
23 | white-space: nowrap;
24 | }
25 |
26 | .u-text-ellipsis-multiline {
27 | overflow: hidden;
28 | text-overflow: ellipsis;
29 | display: -webkit-box !important;
30 | -webkit-line-clamp: var(--count);
31 | -webkit-box-orient: vertical;
32 | }
33 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/exception-page/README.md:
--------------------------------------------------------------------------------
1 | # `exception-page`
2 |
3 | > 403、404、无项目异常页组件
4 |
5 | ## Usage
6 |
7 | ```
8 | import { UPage403, UPage404, UPageNoBiz } from '@/ndsc-vue3/exception-page'
9 |
10 |
11 | ```
12 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/exception-page/lib/index.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | import UPage403 from './u-page403.vue'
3 | import UPage404 from './u-page404.vue'
4 | import UPageNoBiz from './u-page-nobiz.vue'
5 |
6 | let Vue
7 |
8 | function install(_Vue) {
9 | if (Vue && _Vue === Vue) {
10 | return
11 | }
12 | Vue = _Vue
13 | Vue.component('u-page403', UPage403)
14 | Vue.component('u-page404', UPage404)
15 | Vue.component('u-page-nobiz', UPageNoBiz)
16 | }
17 |
18 | const plugin = {
19 | install
20 | }
21 |
22 | // Auto-install when vue is found (eg. in browser via
26 |
27 |
43 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/exception-page/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@/ndsc-vue3/exception-page",
3 | "version": "1.1.3",
4 | "description": "403、404、nobiz pages",
5 | "homepage": "",
6 | "license": "MIT",
7 | "main": "lib/index.ts",
8 | "module": "dist/lib/u-exception-page.esm.js",
9 | "types": "dist/types/index.d.ts",
10 | "directories": {
11 | "lib": "lib",
12 | "test": "__tests__"
13 | },
14 | "files": [
15 | "lib",
16 | "dist"
17 | ],
18 | "publishConfig": {
19 | "access": "public"
20 | },
21 | "repository": {
22 | "type": "git",
23 | "url": ""
24 | },
25 | "scripts": {
26 | "prepublish": "npm run build",
27 | "build": "rollup --config",
28 | "test": "echo \"Error: run tests from root\" && exit 1"
29 | },
30 | "peerDependencies": {
31 | "vue-property-decorator": "^8.4.1"
32 | },
33 | "devDependencies": {
34 | "rollup": "^2.30.0"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/sidebar/lib/VNode.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | export default {
3 | name: 'v-nodes',
4 | functional: true,
5 | props: {
6 | vnodes: {
7 | type: [Object, Array],
8 | }
9 | },
10 | render: (ctx: any) => {
11 | return ctx.vnodes
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/sidebar/lib/components/IconFont.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
32 |
33 |
41 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/sidebar/lib/flexbox.css:
--------------------------------------------------------------------------------
1 | .FBH,
2 | .FBV {
3 | display: flex;
4 | }
5 | .FBV {
6 | flex-direction: column;
7 | }
8 | .FBW {
9 | flex-wrap: wrap;
10 | }
11 | .FBAS {
12 | align-items: flex-start;
13 | }
14 | .FBAC {
15 | align-items: center;
16 | }
17 | .FBAE {
18 | align-items: flex-end;
19 | }
20 | .FBAST {
21 | align-items: stretch;
22 | }
23 | .FBAB {
24 | align-items: baseline;
25 | }
26 | .FBJS {
27 | justify-content: flex-start;
28 | }
29 | .FBJC {
30 | justify-content: center;
31 | }
32 | .FBJE {
33 | justify-content: flex-end;
34 | }
35 | .FBJ {
36 | justify-content: space-between;
37 | }
38 | .FBJB {
39 | justify-content: space-between;
40 | }
41 | .FBJA {
42 | justify-content: space-around;
43 | }
44 | .FBAS-M {
45 | align-content: flex-start;
46 | }
47 | .FBAC-M {
48 | align-content: center;
49 | }
50 | .FBAE-M {
51 | align-content: flex-end;
52 | }
53 | .FBAST-M {
54 | align-content: stretch;
55 | }
56 | .FBAB {
57 | align-content: space-between;
58 | }
59 | .FBAA {
60 | align-content: space-around;
61 | }
62 | .FBAS-S {
63 | align-self: flex-start;
64 | }
65 | .FBAC-S {
66 | align-self: center;
67 | }
68 | .FBAE-S {
69 | align-self: flex-end;
70 | }
71 | .FBAB-S {
72 | align-self: baseline;
73 | }
74 | .FBAST-S {
75 | align-self: stretch;
76 | }
77 | .FB1 {
78 | flex: 1;
79 | }
80 | .FB2 {
81 | flex: 2;
82 | }
83 | .FB3 {
84 | flex: 3;
85 | }
86 | .FB4 {
87 | flex: 4;
88 | }
89 | .FB5 {
90 | flex: 5;
91 | }
92 | .FB6 {
93 | flex: 6;
94 | }
95 | .FB7 {
96 | flex: 7;
97 | }
98 | .FB8 {
99 | flex: 8;
100 | }
101 | .FB9 {
102 | flex: 9;
103 | }
104 | .FB10 {
105 | flex: 10;
106 | }
107 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/sidebar/lib/index.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck
2 | import Sidebar from "./sidebar.vue";
3 | export * from "./interface";
4 |
5 | function install(Vue) {
6 | if (install.installed) return;
7 | install.installed = true;
8 | Vue.component("sidebar", Sidebar);
9 | }
10 |
11 | let GlobalVue = null;
12 |
13 | if (typeof window !== "undefined") {
14 | GlobalVue = window.Vue;
15 | } else if (typeof global !== "undefined") {
16 | GlobalVue = (global as any).Vue;
17 | }
18 |
19 | if (GlobalVue) {
20 | GlobalVue.use({ install });
21 | }
22 |
23 | Sidebar.install = install;
24 |
25 | export default Sidebar;
26 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/sidebar/lib/interface.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 菜单信息
3 | */
4 | export interface NavListDto {
5 | id: string
6 | name: string
7 | to: string // 路由
8 | hide?: boolean // 是否隐藏
9 | // 支持slot和函数
10 | icon?: any // ant-design icon 名称, 优先级:icon > iconFont
11 | // iconType?: 'antdIcon' | 'svgIcon' | 'iconFont' | 'slot' // icon 的类型,支持 antd 、svgicon、iconFont、自定义slot
12 | children?: NavListDto[]
13 | includeTab?: string[] // 需要菜单高亮的路由标识数组
14 | [propName: string]: any // 组件内部使用
15 | }
16 |
17 | /**
18 | * 菜单key的数组item
19 | */
20 | export interface MenuIncludeDto {
21 | id: string
22 | tab: string[] // id 下包含的 array
23 | }
24 |
25 | export interface ProjectDto {
26 | // 项目logo的名字
27 | iconName?: string
28 | icon?: any
29 | // 项目名
30 | name: string
31 | to?: string
32 | }
33 |
34 | export interface ConfigDto {
35 | hide: boolean
36 | to: string
37 | name: string
38 | }
39 |
40 | export interface NavConfigDto {
41 | // 项目信息
42 | project?: ProjectDto
43 | // 主菜单信息
44 | menu: NavListDto[]
45 | // 是否业务设置页
46 | isConfigPage?: boolean
47 | // 底部业务设置
48 | config?: ConfigDto
49 | }
50 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/sidebar/lib/shims-tsx.d.ts:
--------------------------------------------------------------------------------
1 | import Vue, { VNode } from 'vue'
2 |
3 | declare global {
4 | namespace JSX {
5 | // tslint:disable no-empty-interface
6 | interface Element extends VNode {}
7 | // tslint:disable no-empty-interface
8 | interface ElementClass extends Vue {}
9 | interface IntrinsicElements {
10 | [elem: string]: any
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/sidebar/lib/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import Vue from 'vue'
3 | export default Vue
4 | }
5 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/sidebar/types/index.d.ts:
--------------------------------------------------------------------------------
1 | declare module '@/ndsc-vue3/sidebar'
2 |
3 | export * from '../lib'
4 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/style/README.md:
--------------------------------------------------------------------------------
1 | # `@/ndsc-vue3/style`
2 |
3 | > 共享 style
4 |
5 | ## Usage
6 |
7 | ```ts
8 | import '@/ndsc-vue3/style'
9 | ```
10 |
11 | ```less
12 | @import '~@/ndsc-vue3/style/lib/var.less';
13 | ```
14 |
15 | `vue.config.js`
16 |
17 | ```js
18 | const { getModifyVars } = require('@/ndsc-vue3/style/lib/var')
19 |
20 | module.exports = {
21 | css: {
22 | loaderOptions: {
23 | less: {
24 | modifyVars: getModifyVars(),
25 | javascriptEnabled: true
26 | }
27 | }
28 | }
29 | //...其他配置
30 | }
31 | ```
32 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/style/lib/ant-design/button.less:
--------------------------------------------------------------------------------
1 | // .ant-btn {
2 | // color: #103ffa;
3 | // border-color: #103ffa;
4 | // }
5 |
6 | // .ant-btn-primary {
7 | // color: #ffffff;
8 | // }
9 |
10 | // .ant-btn-link {
11 | // border-color: transparent;
12 | // }
13 |
14 | // .ant-btn-danger {
15 | // background-color: #f24957;
16 | // color: #ffffff;
17 | // border-color: #f24957;
18 | // }
19 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/style/lib/ant-design/collapse.less:
--------------------------------------------------------------------------------
1 | .ant-collapse {
2 | &-content {
3 | padding-left: 24px;
4 | }
5 |
6 | &-header {
7 | font-weight: 600;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/style/lib/ant-design/form.less:
--------------------------------------------------------------------------------
1 | .ant-form-horizontal {
2 | .ant-form-item {
3 | margin-bottom: 20px;
4 | &-label {
5 | text-align: left !important;
6 | margin-left: -10px;
7 | & > label {
8 | margin-left: 10px;
9 | }
10 | }
11 |
12 | &-required {
13 | &::before {
14 | position: absolute;
15 | left: -10px;
16 | top: 1px;
17 | }
18 | }
19 |
20 | .ant-alert {
21 | font-size: 12px;
22 | padding-top: 5px;
23 | padding-bottom: 5px;
24 | border-color: transparent;
25 |
26 | .ant-alert-icon {
27 | top: 8px;
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/style/lib/ant-design/index.less:
--------------------------------------------------------------------------------
1 | @import './button.less';
2 | @import './collapse.less';
3 | @import './form.less';
4 | @import './table.less';
5 | @import './modal.less';
--------------------------------------------------------------------------------
/src/ndsc-vue3/style/lib/ant-design/index.ts:
--------------------------------------------------------------------------------
1 | // 引入全局样式
2 | import './index.less'
3 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/style/lib/ant-design/modal.less:
--------------------------------------------------------------------------------
1 | @import '../var.less';
2 |
3 | .ant-modal-root{
4 | .ant-modal-footer{
5 | .ant-btn{
6 | padding: 0 17px;
7 | &:not(.ant-btn-primary){
8 | border-color: @border-color-split;
9 | color: @text-color;
10 | }
11 | }
12 | }
13 | &.ant-modal-confirm{
14 | .ant-modal-body{
15 | padding: 24px 16px 16px 24px;
16 | }
17 | .ant-modal-confirm-btns{
18 | .ant-modal-footer()
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/style/lib/ant-design/table.less:
--------------------------------------------------------------------------------
1 | .ant-table-thead {
2 | & > tr {
3 | & > th {
4 | padding: 16px 12px;
5 | background: #f1f2f4;
6 | font-size: 14px;
7 | color: #102048;
8 | vertical-align: top;
9 | }
10 | }
11 | }
12 |
13 | .ant-table-tbody {
14 | & > tr {
15 | & > td {
16 | padding: 16px 12px;
17 | font-size: 14px;
18 | color: #79809a;
19 | vertical-align: top;
20 | .table-action {
21 | .ant-btn-link {
22 | height: 20px;
23 | line-height: 1;
24 | }
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/style/lib/common.less:
--------------------------------------------------------------------------------
1 | .fill {
2 | height: 100%;
3 | }
4 |
5 | .clearfix {
6 | zoom: 1;
7 | &::before,
8 | &::after {
9 | display: table;
10 | content: '';
11 | }
12 | &::after {
13 | clear: both;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/style/lib/flex.less:
--------------------------------------------------------------------------------
1 | /* flex 布局 */
2 | .flex {
3 | display: flex;
4 | }
5 |
6 | .flex-wrap {
7 | .flex();
8 | flex-wrap: wrap;
9 | }
10 |
11 | .flex-reverse {
12 | .flex();
13 | flex-direction: row-reverse
14 | }
15 |
16 | .flex-column {
17 | .flex();
18 | flex-direction: column;
19 | }
20 |
21 | .flex-ac {
22 | .flex();
23 | align-items: center;
24 | }
25 |
26 | .flex-as {
27 | .flex();
28 | align-items: flex-start;
29 | }
30 |
31 | .flex-c {
32 | .flex-ac();
33 | justify-content: center;
34 | }
35 |
36 | .inline-flex {
37 | display: inline-flex;
38 | }
39 |
40 | .inline-flex-ac {
41 | .inline-flex();
42 | align-items: center;
43 | }
44 |
45 | .inline-flex-as {
46 | .flex();
47 | align-items: flex-start;
48 | }
49 |
50 | .inline-flex-c {
51 | .inline-flex-ac();
52 | justify-content: center;
53 | }
54 |
55 | .flex-1 {
56 | flex: 1;
57 | min-width: 0;
58 | min-height: 0;
59 | }
60 |
61 | .flex-1-w {
62 | flex: 1;
63 | min-width: 0;
64 | }
65 |
66 | .flex-1-h {
67 | flex: 1;
68 | min-height: 0;
69 | }
--------------------------------------------------------------------------------
/src/ndsc-vue3/style/lib/font.less:
--------------------------------------------------------------------------------
1 | .font {
2 | &-lg {
3 | font-size: 16px;
4 | line-height: 24px;
5 | }
6 |
7 | &-md {
8 | font-size: 14px;
9 | line-height: 22px;
10 | }
11 |
12 | &-sm {
13 | font-size: 12px;
14 | line-height: 20px;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/style/lib/index.less:
--------------------------------------------------------------------------------
1 | @import './var.less';
2 | @import './flex.less';
3 | @import './text.less';
4 | @import './margin.less';
5 | @import './padding.less';
6 | @import './common.less';
7 | @import './font.less';
8 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/style/lib/index.ts:
--------------------------------------------------------------------------------
1 | // 引入全局样式
2 | import './index.less'
3 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/style/lib/margin.less:
--------------------------------------------------------------------------------
1 | .make-margin(@size) {
2 | &-m-@{size} {
3 | margin: ~'@{size}px';
4 | }
5 | &-m-lr {
6 | &-@{size} {
7 | margin-left: ~'@{size}px';
8 | margin-right: ~'@{size}px';
9 | }
10 | }
11 | &-m-tb {
12 | &-@{size} {
13 | margin-top: ~'@{size}px';
14 | margin-bottom: ~'@{size}px';
15 | }
16 | }
17 | &-ml-@{size} {
18 | margin-left: ~'@{size}px';
19 | }
20 | &-mt-@{size} {
21 | margin-top: ~'@{size}px';
22 | }
23 | &-mr-@{size} {
24 | margin-right: ~'@{size}px';
25 | }
26 | &-mb-@{size} {
27 | margin-bottom: ~'@{size}px';
28 | }
29 | }
30 |
31 | .g {
32 | .make-margin(4);
33 | .make-margin(8);
34 | .make-margin(12);
35 | .make-margin(16);
36 | .make-margin(24);
37 | }
38 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/style/lib/padding.less:
--------------------------------------------------------------------------------
1 | .make-padding(@size) {
2 | &-p-@{size} {
3 | padding: ~'@{size}px';
4 | }
5 | &-p-lr {
6 | &-@{size} {
7 | padding-left: ~'@{size}px';
8 | padding-right: ~'@{size}px';
9 | }
10 | }
11 | &-p-tb {
12 | &-@{size} {
13 | padding-top: ~'@{size}px';
14 | padding-bottom: ~'@{size}px';
15 | }
16 | }
17 | &-pl-@{size} {
18 | padding-left: ~'@{size}px';
19 | }
20 | &-pt-@{size} {
21 | padding-top: ~'@{size}px';
22 | }
23 | &-pr-@{size} {
24 | padding-right: ~'@{size}px';
25 | }
26 | &-pb-@{size} {
27 | padding-bottom: ~'@{size}px';
28 | }
29 | }
30 |
31 | .g {
32 | .make-padding(4);
33 | .make-padding(8);
34 | .make-padding(12);
35 | .make-padding(16);
36 | .make-padding(24);
37 | }
38 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/style/lib/text.less:
--------------------------------------------------------------------------------
1 | @import './var.less';
2 |
3 | .text-link {
4 | cursor: pointer;
5 | user-select: none;
6 | color: @primary-color;
7 | }
8 |
9 | .text-disabled {
10 | color: @disabled-color;
11 | }
12 |
13 | .text-error {
14 | font-size: 12px;
15 | color: @error-color;
16 | }
17 |
18 | .text-secondary {
19 | font-size: 12px;
20 | color: @text-color-secondary;
21 | }
22 |
23 | .text-ellipsis {
24 | white-space: nowrap;
25 | overflow: hidden;
26 | text-overflow: ellipsis;
27 | }
28 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/style/lib/var.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const path = require('path')
3 |
4 | /**
5 | * 用于 vue.config.js 获取 less modifyVars 配置
6 | */
7 | const getModifyVars = function () {
8 | const css = fs.readFileSync(path.join(__dirname, 'var.less'), 'utf-8')
9 | const arr = css.match(/(?<=@)[^;]+(?=;)/g)
10 | const modifyVars = {}
11 | arr.reduce((pre, cur) => {
12 | const vars = cur.split(':')
13 | pre[vars[0].trim()] = vars[1].trim()
14 | return pre
15 | }, modifyVars)
16 |
17 | Object.keys(modifyVars).forEach((key) => {
18 | const value = modifyVars[key]
19 | if (value.startsWith('@')) {
20 | const equalKey = value.slice(1)
21 | modifyVars[key] = modifyVars[equalKey]
22 | }
23 | })
24 | return modifyVars
25 | }
26 |
27 | module.exports = {
28 | getModifyVars
29 | }
30 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/style/lib/var.less:
--------------------------------------------------------------------------------
1 | @primary-color: #103ffa; // 全局主色
2 | @link-color: #103ffa; // 链接色
3 | @info-color: #1890ff; // 信息提示色
4 | @success-color: #26bd71; // 成功色
5 | @warning-color: #ffaf0f; // 警告色
6 | @error-color: #f24957; // 错误色
7 |
8 | @font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB',
9 | 'PingFang SC', 'Microsoft YaHei', tahoma, simsun, '宋体';
10 | @body-background: #f6f7fa; // 背景色
11 | @heading-color: #102048; // 标题色
12 | @text-color: #79809a; // 正文色
13 | @text-color-secondary: #c0c0ca; // 次文本色(提示文本色)
14 | @border-color-split: #e8e8f0; // 分割线
15 | @border-radius-base: 2px;
16 |
17 | @disabled-color: #a9a9b8; // 失效色
18 | @disabled-bg: #f2f2f5;
19 |
20 | // Table
21 | @table-header-bg: #f1f2f4; // 表头背景色
22 | @table-header-color: @heading-color; // 表头文本色
23 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/style/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@/ndsc-vue3/style",
3 | "version": "1.3.4",
4 | "description": "the package of shared style",
5 | "keywords": [
6 | "style",
7 | "less",
8 | "css"
9 | ],
10 | "license": "MIT",
11 | "main": "lib/index.ts",
12 | "directories": {
13 | "lib": "lib"
14 | },
15 | "files": [
16 | "lib"
17 | ],
18 | "publishConfig": {
19 | "access": "public"
20 | },
21 | "repository": {
22 | "type": "git"
23 | },
24 | "scripts": {
25 | "test": "echo \"Error: run tests from root\" && exit 1"
26 | },
27 | "devDependencies": {
28 | "rollup": "^2.10.2",
29 | "eslint": "^6.7.2"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/theme/README.md:
--------------------------------------------------------------------------------
1 | ## 生成多套主题 css
2 |
3 | 1. `lib/`下开发主题,新增主题文件,一般包括:
4 |
5 | - `index.js`入口文件
6 | - `index.less`引入 antd 样式包、自定义变量`var.less`、`common.less`公共样式包
7 | - `common.less`定义 css 变量提供复用
8 | - `var.less`自定义样式变量
9 |
10 | 2. `webpack.config.js`中`entry`增加主题类型入口。
11 |
12 | 3. `yarn build`生成多套 css,并拷贝到 docs 目录下,供文档站点使用
13 |
14 | 4. 设置版本
15 |
16 | 5. `nenpm publish`发布
17 |
18 | ## 引入
19 |
20 | 1. 安装
21 | `yarn add @/ndsc-vue3/theme`
22 |
23 | 2. `vue.config.js`中配置
24 |
25 | ```js
26 | const CopyWebpackPlugin = require('copy-webpack-plugin')
27 |
28 | module.exports = {
29 | ...,
30 | configureWebpack: config => {}
31 | }
32 | ```
33 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/theme/index.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eventtracing/easyinsight-front/1ccfe5b7a287b6f26b48c9dc6d7d40526d947fc2/src/ndsc-vue3/theme/index.html
--------------------------------------------------------------------------------
/src/ndsc-vue3/theme/lib/common/index.less:
--------------------------------------------------------------------------------
1 | .mm-theme-dark,
2 | .mm-theme-light,
3 | .mm-theme-purple {
4 | --primary-color: @primary-color;
5 | --link-color: @link-color;
6 | --info-color: @info-color;
7 | --error-color: @error-color;
8 | --disabled-color: @disabled-color;
9 | --text-color-secondary: @text-color-secondary;
10 | --border-color-base: @border-color-base;
11 | --shadow-color: @shadow-color;
12 | --item-hover-bg: @item-hover-bg;
13 |
14 | // 仅供demo使用,正常项目中会去掉按需加载等
15 |
16 | .ant-btn {
17 | color: @primary-color;
18 | border-color: @primary-color;
19 | }
20 | .ant-btn-primary {
21 | color: #ffffff;
22 | background-color: @primary-color;
23 | }
24 | .ant-btn-link {
25 | border-color: transparent;
26 | }
27 | .ant-btn-danger {
28 | background-color: @error-color;
29 | color: #ffffff;
30 | border-color: @error-color;
31 | }
32 | .ant-btn-primary:hover,
33 | .ant-btn-primary:focus {
34 | background-color: @primary-color;
35 | border-color: @primary-color;
36 | }
37 |
38 | .ant-input:hover {
39 | border-color: @primary-color;
40 | }
41 | .ant-radio-checked::after {
42 | border: 1px solid @primary-color;
43 | }
44 | .ant-radio-checked .ant-radio-inner {
45 | border-color: @primary-color;
46 | }
47 | .ant-radio-inner::after {
48 | background-color: @primary-color;
49 | }
50 | .ant-switch-checked {
51 | background-color: @primary-color;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/theme/lib/dark/common.less:
--------------------------------------------------------------------------------
1 | @import '../common/index.less';
2 |
3 | .mm-theme-dark {
4 | }
5 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/theme/lib/dark/index.js:
--------------------------------------------------------------------------------
1 | import './index.less'
2 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/theme/lib/dark/index.less:
--------------------------------------------------------------------------------
1 | @import '~ant-design-vue/dist/antd.less';
2 | @import './var.less';
3 | @import './common.less';
4 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/theme/lib/dark/var.less:
--------------------------------------------------------------------------------
1 | @primary-color: #141720; // 全局主色
2 | @link-color: #141720; // 链接色
3 | @info-color: #eb2f96; // 信息提示色
4 | @success-color: #26bd71; // 成功色
5 | @warning-color: #ffaf0f; // 警告色
6 | @error-color: #f24957; // 错误色
7 |
8 | @font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB',
9 | 'PingFang SC', 'Microsoft YaHei', tahoma, simsun, '宋体';
10 | @body-background: #722ed1; // 背景色
11 | @heading-color: #141720; // 标题色
12 | @text-color: #722ed1; // 正文色
13 | @text-color-secondary: #722ed1; // 次文本色(提示文本色)
14 | @border-color-split: #722ed1; // 分割线
15 | @border-radius-base: 2px;
16 |
17 | @disabled-color: #a9a9b8; // 失效色
18 | @disabled-bg: #f2f2f5;
19 |
20 | // Table
21 | @table-header-bg: #f9f0ff; // 表头背景色
22 | @table-header-color: @heading-color; // 表头文本色
23 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/theme/lib/light/common.less:
--------------------------------------------------------------------------------
1 | @import '../common/index.less';
2 |
3 | .mm-theme-light {
4 | }
5 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/theme/lib/light/index.js:
--------------------------------------------------------------------------------
1 | import './index.less'
2 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/theme/lib/light/index.less:
--------------------------------------------------------------------------------
1 | @import '~ant-design-vue/dist/antd.less';
2 | @import './var.less';
3 | @import './common.less';
4 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/theme/lib/light/var.less:
--------------------------------------------------------------------------------
1 | @primary-color: #103ffa; // 全局主色
2 | @link-color: #103ffa; // 链接色
3 | @info-color: #1890ff; // 信息提示色
4 | @success-color: #26bd71; // 成功色
5 | @warning-color: #ffaf0f; // 警告色
6 | @error-color: #f24957; // 错误色
7 |
8 | @font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB',
9 | 'PingFang SC', 'Microsoft YaHei', tahoma, simsun, '宋体';
10 | @body-background: #f6f7fa; // 背景色
11 | @heading-color: #102048; // 标题色
12 | @text-color: #79809a; // 正文色
13 | @text-color-secondary: #c0c0ca; // 次文本色(提示文本色)
14 | @border-color-split: #e8e8f0; // 分割线
15 | @border-radius-base: 2px;
16 |
17 | @disabled-color: #a9a9b8; // 失效色
18 | @disabled-bg: #f2f2f5;
19 |
20 | // Table
21 | @table-header-bg: #f1f2f4; // 表头背景色
22 | @table-header-color: @heading-color; // 表头文本色
23 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/theme/lib/purple/common.less:
--------------------------------------------------------------------------------
1 | @import '../common/index.less';
2 |
3 | .mm-theme-purple {
4 | }
5 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/theme/lib/purple/index.js:
--------------------------------------------------------------------------------
1 | import './index.less'
2 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/theme/lib/purple/index.less:
--------------------------------------------------------------------------------
1 | @import '~ant-design-vue/dist/antd.less';
2 | @import './var.less';
3 | @import './common.less';
4 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/theme/lib/purple/var.less:
--------------------------------------------------------------------------------
1 | @primary-color: #722ed1; // 全局主色
2 | @link-color: #722ed1; // 链接色
3 |
4 | @info-color: #1890ff; // 信息提示色
5 | @success-color: #26bd71; // 成功色
6 | @warning-color: #ffaf0f; // 警告色
7 | @error-color: #f24957; // 错误色
8 |
9 | @font-family: 'Helvetica Neue', Helvetica, Arial, 'Hiragino Sans GB',
10 | 'PingFang SC', 'Microsoft YaHei', tahoma, simsun, '宋体';
11 | @body-background: #f6f7fa; // 背景色
12 | @heading-color: #102048; // 标题色
13 | @text-color: #79809a; // 正文色
14 | @text-color-secondary: #c0c0ca; // 次文本色(提示文本色)
15 | @border-color-split: #e8e8f0; // 分割线
16 | @border-radius-base: 2px;
17 |
18 | @disabled-color: #a9a9b8; // 失效色
19 | @disabled-bg: #f2f2f5;
20 |
21 | // Table
22 | @table-header-bg: #f1f2f4; // 表头背景色
23 | @table-header-color: @heading-color; // 表头文本色
24 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/theme/lib/utils/ThemeMixin.vue:
--------------------------------------------------------------------------------
1 |
60 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/theme/lib/utils/index.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eventtracing/easyinsight-front/1ccfe5b7a287b6f26b48c9dc6d7d40526d947fc2/src/ndsc-vue3/theme/lib/utils/index.js
--------------------------------------------------------------------------------
/src/ndsc-vue3/theme/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@/ndsc-vue3/theme",
3 | "version": "1.0.0-1",
4 | "description": "主题",
5 | "main": "index.js",
6 | "files": [
7 | "dist"
8 | ],
9 | "scripts": {
10 | "test": "echo \"Error: no test specified\" && exit 1",
11 | "dev": "webpack-dev-server --open --mode development",
12 | "build-only": "webpack --mode production",
13 | "build": "yarn build-only && yarn copy-vue && yarn copy-css",
14 | "copy-vue": "node ./scripts/copyVue",
15 | "copy-css": "node ./scripts/copyCSS"
16 | },
17 | "publishConfig": {
18 | "access": "public"
19 | },
20 | "repository": {
21 | "type": "git"
22 | },
23 | "author": "",
24 | "license": "ISC",
25 | "devDependencies": {
26 | "chalk": "^4.1.0",
27 | "clean-webpack-plugin": "^3.0.0",
28 | "css-loader": "^5.1.3",
29 | "cssnano": "^4.1.10",
30 | "extract-text-webpack-plugin": "^3.0.2",
31 | "html-webpack-plugin": "^5.3.1",
32 | "less": "^3.9.0",
33 | "less-loader": "^6.0.0",
34 | "mini-css-extract-plugin": "^1.3.9",
35 | "optimize-css-assets-webpack-plugin": "^5.0.4",
36 | "progress-bar-webpack-plugin": "^2.1.0",
37 | "style-loader": "^2.0.0",
38 | "terser-webpack-plugin": "^5.1.1",
39 | "webpack": "^5.26.3",
40 | "webpack-cli": "^4.5.0",
41 | "webpack-dev-server": "^3.11.2"
42 | },
43 | "dependencies": {
44 | "ant-design-vue": "^1.7.4",
45 | "fs": "^0.0.1-security",
46 | "vue-property-decorator": "^9.1.2"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/theme/scripts/copyCSS.js:
--------------------------------------------------------------------------------
1 | const { copyFile } = require('../../../scripts/lerna/util.js')
2 | const path = require('path')
3 | const rootPath = path.resolve(__dirname, '../../../')
4 | const publicPath = path.resolve(rootPath, './docs/.vuepress/public')
5 | const fs = require('fs')
6 |
7 | const files = fs.readdirSync(path.resolve(__dirname, '../dist'))
8 | files.forEach((e) => {
9 | if (e.indexOf('.css') > -1) {
10 | copyFile(path.resolve(__dirname, '../dist/' + e), path.resolve(publicPath, e))
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/theme/scripts/copyVue.js:
--------------------------------------------------------------------------------
1 | const { copyFile } = require('../../../scripts/lerna/util.js')
2 | const path = require('path')
3 |
4 | copyFile(
5 | path.resolve(__dirname, '../lib/utils/ThemeMixin.vue'),
6 | path.resolve(__dirname, '../dist/ThemeMixin.vue')
7 | )
8 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/utils/lib/TableMixin.vue:
--------------------------------------------------------------------------------
1 |
37 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/utils/lib/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./common";
2 | export * from "./instance";
3 | export * from "./loadJs";
4 | export * from "./request";
5 | export * from "./url";
6 | export * from "./validator";
7 |
8 | export * from "./vueProto";
9 |
10 | export { default as TableMixin } from "./TableMixin.vue";
11 |
12 | export function usePagination() {
13 | const _total = 0;
14 | const _current = 1;
15 | const _pageSizeOptions = ["25", "50", "100"];
16 | const _pageSize = 25;
17 |
18 | return {
19 | total: _total,
20 | current: _current,
21 | pageSize: _pageSize,
22 | pageSizeOptions: _pageSizeOptions,
23 | showQuickJumper: true,
24 | showSizeChanger: true,
25 | hideOnSinglePage: _total <= Number(_pageSizeOptions[0]),
26 | showTotal: (total: number) => `共 ${total} 条记录`,
27 | };
28 | }
29 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/utils/lib/loadJs.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 动态加载 js 文件
3 | */
4 | const customCache = new Set()
5 |
6 | /**
7 | * 动态引入 js
8 | * @param scriptUrl 脚本 url
9 | */
10 | export function loadJs(scriptUrl: string) {
11 | if (
12 | typeof document !== 'undefined' &&
13 | typeof window !== 'undefined' &&
14 | typeof document.createElement === 'function' &&
15 | typeof scriptUrl === 'string' &&
16 | scriptUrl.length &&
17 | !customCache.has(scriptUrl)
18 | ) {
19 | const script = document.createElement('script')
20 | script.setAttribute('src', scriptUrl)
21 | script.setAttribute('data-namespace', scriptUrl)
22 | customCache.add(scriptUrl)
23 | document.body.appendChild(script)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/utils/lib/shims-tsx.d.ts:
--------------------------------------------------------------------------------
1 | import Vue, { VNode } from 'vue'
2 |
3 | declare global {
4 | namespace JSX {
5 | // tslint:disable no-empty-interface
6 | interface Element extends VNode {}
7 | // tslint:disable no-empty-interface
8 | interface ElementClass extends Vue {}
9 | interface IntrinsicElements {
10 | [elem: string]: any
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/utils/lib/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import Vue from 'vue'
3 | export default Vue
4 | }
5 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/utils/lib/url.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 判断 url 是否是绝对路径
3 | * @param url url 字符串
4 | */
5 | export function isAbsoluteURL(url: string) {
6 | // A URL is considered absolute if it begins with "://" or "//" (protocol-relative URL).
7 | // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed
8 | // by any combination of letters, digits, plus, period, or hyphen.
9 | return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url)
10 | }
11 |
12 | /**
13 | * 返回基础路径或拼接后的路径
14 | * @param baseURL 基础路径
15 | * @param relativeURL 相对路径
16 | */
17 | export function combineURLs(baseURL: string, relativeURL: string) {
18 | return relativeURL ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '') : baseURL
19 | }
20 |
21 | /**
22 | * 获取url的query参数
23 | * @param name 参数名
24 | * @param url url 字符串
25 | */
26 | export function getQueryString(name: string, url: string) {
27 | const arr = url.split('?')
28 | if (arr.length) {
29 | const search = arr[arr.length - 1]
30 | const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)')
31 | const r = search.match(reg)
32 | if (r != null) {
33 | return unescape(r[2])
34 | }
35 | }
36 | return null
37 | }
38 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/utils/lib/validator.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 校验规则
3 | */
4 |
5 | /**
6 | * 大于0的整数
7 | */
8 | export const greaterThan0Validator = {
9 | message: '大于0的整数',
10 | pattern: /^[1-9]\d*$/,
11 | validator: (_rule: any, value: any, callback: any) => {
12 | if (!/^[1-9]\d*$/.test(value)) {
13 | return callback(new Error('此字段为大于0的整数'))
14 | }
15 | callback()
16 | }
17 | }
18 |
19 | /**
20 | * 不小于0的整数
21 | */
22 | export const noLessThan0Validator = {
23 | message: '不小于0的整数',
24 | pattern: /^[1-9]\d*$|^0$/,
25 | validator: (_rule: any, value: any, callback: any) => {
26 | if (!/^[1-9]\d*$|^0$/.test(value)) {
27 | return callback(new Error('此字段为不小于0的整数'))
28 | }
29 | callback()
30 | }
31 | }
32 |
33 | /**
34 | * 以字母开头
35 | */
36 | export const beginWithLetterValidator = {
37 | message: '以字母开头',
38 | pattern: /^[a-zA-Z]/,
39 | validator: (_rule: any, value: any, callback: any) => {
40 | if (value && !/^[a-zA-Z]/.test(value)) {
41 | callback(new Error('此字段必须以字母开头'))
42 | }
43 | callback()
44 | }
45 | }
46 |
47 | /**
48 | * 字段包含字母、数字、_
49 | */
50 | export const letterValidator = {
51 | message: '字段包含字母、数字、_',
52 | pattern: /^[a-zA-Z0-9_]*$/,
53 | validator: (_rule: any, value: any, callback: any) => {
54 | if (!/^[a-zA-Z0-9_]*$/.test(value)) {
55 | return callback(new Error('此字段只能包含字母、数字、_'))
56 | }
57 | callback()
58 | }
59 | }
60 |
61 | /**
62 | * 字段包含中英文、数字、_ 和 -
63 | */
64 | export const nameValidator = {
65 | message: '字段包含中英文、数字、_ 和 - ',
66 | pattern: /^[\u4e00-\u9fa5a-zA-Z0-9_-]*$/,
67 | validator: (_rule: any, value: any, callback: any) => {
68 | if (!/^[\u4e00-\u9fa5a-zA-Z0-9_-]*$/.test(value)) {
69 | return callback(new Error('此字段只能包含中英文、数字、_ 和 - '))
70 | }
71 | callback()
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/ndsc-vue3/utils/lib/vueProto.ts:
--------------------------------------------------------------------------------
1 | declare module "@vue/runtime-core" {
2 | interface Vue {
3 | $hasData: (data: any) => boolean;
4 | $get: (
5 | obj: Record,
6 | arr: string[] | string,
7 | defaultValue: any
8 | ) => any;
9 | }
10 | }
11 |
12 | // 扩展vue
13 | export const vueProto = () => {};
14 |
--------------------------------------------------------------------------------
/src/pv.ts:
--------------------------------------------------------------------------------
1 | interface PVInfoRouteMap {
2 | [props: string]: {
3 | id: string;
4 | data?: Record;
5 | query?: Record;
6 | };
7 | }
8 |
9 | export const PVInfoMap: PVInfoRouteMap = {
10 | "/tracker/requirement/list": {
11 | id: "page_requirement",
12 | },
13 | "/tracker/requirement/version": {
14 | id: "page_version",
15 | },
16 | "/tracker/object/list": {
17 | id: "page_object",
18 | },
19 | "/tracker/metadata/parameter": {
20 | id: "page_parameter",
21 | },
22 | "/tracker/metadata/template": {
23 | id: "page_template",
24 | },
25 | "/tracker/metadata/event": {
26 | id: "page_event",
27 | },
28 | "/tracker/metadata/terminal": {
29 | id: "page_terminal",
30 | },
31 | "/test/realtime": {
32 | id: "page_realtime",
33 | },
34 | "/test/realtime/detail": {
35 | id: "page_realtime_detail",
36 | },
37 | "/authorityManage/production/info": {
38 | id: "page_product_info",
39 | },
40 | "/authorityManage/production/member": {
41 | id: "page_product_member",
42 | },
43 | "/authorityManage/production/manage": {
44 | id: "page_product_role",
45 | },
46 | "/authorityManage/production/notification": {
47 | id: "page_product_notification",
48 | },
49 | "/authorityManage/domain/detail": {
50 | id: "page_domain_info",
51 | },
52 | "/authorityManage/domain/member": {
53 | id: "page_domain_member",
54 | },
55 | "/authorityManage/domain/product": {
56 | id: "page_domain_product",
57 | },
58 | "/authorityManage/platform/domain": {
59 | id: "page_platform_domain",
60 | },
61 | "/tracker/requirement/detail": {
62 | id: "page_requirement_detail",
63 | },
64 | };
65 |
--------------------------------------------------------------------------------
/src/services/README.md:
--------------------------------------------------------------------------------
1 | # services
2 |
3 | > 项目 api 请求文件
4 |
5 | ## 目录说明
6 |
7 | ```
8 | |-- app.service.ts 项目集群等请求
9 | |-- event.service.ts 事件类型模块请求
10 | |-- login.service.ts 登录服务
11 | |-- object.service.ts 对象模块请求
12 | |-- parameter.service.ts 参数模块请求
13 | |-- requirement.service.ts 需求模块请求
14 | |-- template.service.ts 参数模板模块请求
15 | |-- terminal.service.ts 终端管理模块请求
16 | |-- version.service.ts 版本管理模块请求
17 | ```
18 |
--------------------------------------------------------------------------------
/src/services/app.service.ts:
--------------------------------------------------------------------------------
1 | import request from "@/utils/request";
2 | import { AppDto } from "@/types/app.type";
3 | import { User } from "@/types/common.type";
4 |
5 | // 获取用户权限菜单列表
6 | export function getAuthorMenu(userEmail): Promise {
7 | return request.get("/et/v1/auth/menu/authorized/list", {
8 | params: { userEmail },
9 | });
10 | }
11 |
12 | // 获取用户可选产品
13 | export async function getAppList(): Promise {
14 | return request.get("/eis/v1/domain/getByEmail", { useToken: true });
15 | }
16 |
17 | // 获取该产品下所有成员
18 | export async function getAllUsers(): Promise {
19 | return request.get("/eis/v1/user/getall");
20 | }
21 |
--------------------------------------------------------------------------------
/src/services/common.service.ts:
--------------------------------------------------------------------------------
1 | import request from "@/utils/request";
2 |
3 | // 获取用户权限菜单列表
4 | export function getAppManagers(appId): Promise {
5 | return request.get("/et/v1/auth/user/managers", { params: { appId } });
6 | }
7 |
--------------------------------------------------------------------------------
/src/services/login.service.ts:
--------------------------------------------------------------------------------
1 | import request from "@/utils/request";
2 | import { User, AppDto } from "@/types/app.type";
3 | import store from "../store/index";
4 |
5 | interface LoginStatus {
6 | logon: boolean; // 是否登录
7 | localToken: string;
8 | user: User;
9 | domainId: number;
10 | app: AppDto;
11 | }
12 |
13 | class LoginService {
14 | // 检测登录接口,登录成功后返回用户信息
15 | checkLoginIn() {
16 | return request
17 | .get("/check/login", {
18 | useToken: false,
19 | })
20 | .then((res: LoginStatus) => {
21 | const { logon, localToken, user, domainId, app } = res || {};
22 | if (logon) {
23 | localToken && store.commit("setLocalToken", localToken);
24 | user && store.commit("setUser", user);
25 | domainId && store.commit("setDomainId", domainId);
26 | app && store.commit("setApp", app);
27 | }
28 | return logon;
29 | });
30 | }
31 |
32 | login() {
33 | location.href = "/api/login";
34 | }
35 |
36 | logOut() {
37 | location.href = "/api/logout";
38 | }
39 | }
40 |
41 | const loginService = new LoginService();
42 |
43 | export default loginService;
44 |
--------------------------------------------------------------------------------
/src/services/record.service.ts:
--------------------------------------------------------------------------------
1 | import request from "@/utils/request";
2 |
3 | // 获取测试需求
4 | export function getAllRequire() {
5 | return request.get("/eis/reqPool/query/all");
6 | }
7 |
8 | export function getRecordList(data) {
9 | return request.post("/realtime/test/history/search", data);
10 | }
11 |
--------------------------------------------------------------------------------
/src/services/tag.service.ts:
--------------------------------------------------------------------------------
1 | import request from "@/utils/request";
2 | import {
3 | Pagination,
4 | Search,
5 | PaginationList,
6 | ItemDto,
7 | } from "@/types/common.type";
8 |
9 | // 获取标签列表
10 | export async function getTagList(
11 | params: Pagination & Search & { type: number }
12 | ): Promise> {
13 | return request.get("/et/v1/tag/list", { params: { type: 1, ...params } });
14 | }
15 |
16 | // 创建标签
17 | export async function createTag(name: string, type = 1): Promise {
18 | return request.post("/et/v1/tag/create", { type, name });
19 | }
20 |
--------------------------------------------------------------------------------
/src/services/template.service.ts:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 | import { PaginationList } from '@/types/common.type'
3 | import {
4 | TemplateSimpleDto,
5 | GetTemplateListReq,
6 | NewTemplateReq,
7 | TemplateDetailDto
8 | } from '@/types/template.type'
9 |
10 | export async function getTempalteList(
11 | params: GetTemplateListReq
12 | ): Promise> {
13 | return request.get('/et/v1/template/list', { params, supportCancel: true })
14 | }
15 |
16 | export async function deleteTemplate(id: number) {
17 | return request.delete(`/et/v1/template/delete?id=${id}`, {
18 | handleError: false
19 | })
20 | }
21 |
22 | export async function addNewTemplate(data: NewTemplateReq) {
23 | return request.post('/et/v1/template/create', data, { handleError: false })
24 | }
25 |
26 | export async function updateTemplate(data: NewTemplateReq & { id: number }) {
27 | return request.put('/et/v1/template/edit', data, { handleError: false })
28 | }
29 |
30 | export async function getTemplateDetail(id: number): Promise {
31 | return request.get(`/et/v1/template/get?id=${id}`)
32 | }
33 |
--------------------------------------------------------------------------------
/src/services/terminal.service.ts:
--------------------------------------------------------------------------------
1 | import request from "@/utils/request";
2 | import { PaginationList } from "@/types/common.type";
3 | import {
4 | GetTerminalListReq,
5 | TerminalSimpleDto,
6 | NewTerminalReq,
7 | } from "@/types/terminal.type";
8 |
9 | export async function getTerminalList(
10 | data: GetTerminalListReq
11 | ): Promise> {
12 | return request.post("/et/v1/terminal/list", data);
13 | }
14 |
15 | export async function deleteTerminal(id: number) {
16 | return request.delete(`/et/v1/terminal/delete?id=${id}`, {
17 | handleError: false,
18 | });
19 | }
20 |
21 | export async function addNewTerminal(data: NewTerminalReq) {
22 | return request.post("/et/v1/terminal/create", data, { handleError: false });
23 | }
24 |
25 | export async function updateTerminal(data: NewTerminalReq & { id: number }) {
26 | return request.put("/et/v1/terminal/edit", data, { handleError: false });
27 | }
28 |
29 | export async function getTerminalDetail(
30 | id: number
31 | ): Promise {
32 | return request.get(`/et/v1/terminal/get?id=${id}`);
33 | }
34 |
--------------------------------------------------------------------------------
/src/services/terminalVersion.service.ts:
--------------------------------------------------------------------------------
1 | import request from "@/utils/request";
2 |
3 | // 查看产品各端前置版本列表
4 | export async function getPreTerminalVersion(reqPoolId: number): Promise<
5 | {
6 | terminalId: number;
7 | terminalVersionId: number;
8 | terminalName: string;
9 | terminalVersionName: string;
10 | baseReleaseId: string;
11 | }[]
12 | > {
13 | return request.get("/eis/v2/obj/base/version/get", { params: { reqPoolId } });
14 | }
15 |
16 | // 有端版本
17 | export function getVersionList(params) {
18 | return request.get("/eis/v2/release/aggregate/tasks/get", { params });
19 | }
20 |
21 | // 无端版本
22 | export function getNoVersionList(params) {
23 | return request.get("/eis/v2/release/tasks/get", { params });
24 | }
25 |
26 | // 历史列表
27 | export function getHistoryList(params: {
28 | terminalId: number | string;
29 | ascend: boolean;
30 | }) {
31 | return request.get("/eis/v2/release/tasks/history/get", { params });
32 | }
33 |
34 | // 发布端版本上线
35 | export function publishVersion(data: {
36 | terminalId: string | number;
37 | terminalVersionId: number;
38 | taskIds: number[];
39 | }) {
40 | return request.post("/eis/v2/release/releaseByVersion", data);
41 | }
42 |
43 | // 发布任务上线
44 | export function publishTaskVersion(params: {
45 | taskId: number;
46 | terminalId: string | number;
47 | }) {
48 | return request.get("/eis/v2/release/releaseByTask", { params });
49 | }
50 |
--------------------------------------------------------------------------------
/src/services/version.service.ts:
--------------------------------------------------------------------------------
1 | import request from "@/utils/request";
2 | import {
3 | VersionDto,
4 | GetVersionListReq,
5 | NewVersionReq,
6 | DelVersionReq,
7 | UpdateVersionBindsReq,
8 | CopyVersionReq,
9 | } from "@/types/version.type";
10 | import { ParamBindItemDto } from "@/types/template.type";
11 |
12 | // 获取版本绑定的参数列表
13 | export async function getVersionParamDetail(
14 | params: DelVersionReq
15 | ): Promise[]> {
16 | return request.get("/et/v1/parambind/get", { params });
17 | }
18 |
19 | // 更新版本名称及绑定参数列表
20 | export async function updateVersionParam(data: UpdateVersionBindsReq) {
21 | return request.put("/et/v1/parambind/edit", data, { handleError: false });
22 | }
23 |
24 | // 创建、复制新的参数版本
25 | export async function copyVersion(data: CopyVersionReq) {
26 | return request.post("/et/v1/parambind/copy", data, { handleError: false });
27 | }
28 |
29 | export async function getVersionList(
30 | params: Partial
31 | ): Promise {
32 | return request.get("/et/v1/version/list", { params });
33 | }
34 |
35 | export async function addNewVersion(data: NewVersionReq): Promise {
36 | return request.post("/et/v1/version/create", data, { handleError: false });
37 | }
38 |
39 | export async function deleteVersion(params: DelVersionReq) {
40 | return request.delete("/et/v1/version/delete", {
41 | params,
42 | handleError: false,
43 | });
44 | }
45 |
46 | export async function setCurrentVersion(data: DelVersionReq) {
47 | return request.put("/et/v1/version/setusing", data, { handleError: false });
48 | }
49 |
--------------------------------------------------------------------------------
/src/sevice.d.ts:
--------------------------------------------------------------------------------
1 | declare interface ResponseDTO {
2 | result: any
3 | }
4 |
--------------------------------------------------------------------------------
/src/shims-tsx.d.ts:
--------------------------------------------------------------------------------
1 | import { VNode } from 'vue'
2 |
3 | declare module '*.svg' {
4 | const content: any
5 | export default content
6 | }
7 |
8 | declare global {
9 | namespace JSX {
10 | // tslint:disable no-empty-interface
11 | interface Element extends VNode {}
12 | // tslint:disable no-empty-interface
13 | interface ElementClass extends Vue {}
14 | interface IntrinsicElements {
15 | [elem: string]: any
16 | }
17 | }
18 |
19 | interface Window {
20 | DATracker: any
21 | Quill: any
22 | mozRequestAnimationFrame: any
23 | oRequestAnimationFrame: any
24 | msRequestAnimationFrame: any
25 | }
26 |
27 | interface Promise {
28 | allSettled: any
29 | }
30 | }
31 |
32 | declare module '@vue/runtime-core' {
33 | interface ComponentCustomProperties {
34 | // 统一错误处理
35 | $handleError(e: Error, type?: string): void
36 | // 弹窗、抽屉统一解决方案
37 | $createInstance(
38 | vueConstructor: any,
39 | props: Omit & Record
40 | ): { destroy: () => void }
41 | $confirm(options: any): unknown
42 | $message: {
43 | success(str: string): unknown
44 | error(str: string): unknown
45 | }
46 | $warning(options: any): unknown
47 | $getPopupContainer(node: HTMLElement): HTMLElement
48 | $navToNewTab(to: _RouteLocationBase): void
49 | $filterOption(input: any, option: any): void
50 | getQueryParams: any
51 | setQueryParams: any
52 | checkAuth(code: number | number[]): boolean
53 | menuLists: any
54 | $preview(options: unknown): unknown
55 | $get(object: Record, path: string, defaultValue: any): any
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | declare module '*.vue' {
3 | import type { DefineComponent } from 'vue';
4 |
5 | const component: DefineComponent<{}, {}, any>;
6 |
7 | export default component;
8 | };
9 |
10 | declare module 'vue3-json-view' {
11 | import JsonView from 'vue3-json-view'
12 |
13 | export default JsonView;
14 | };
15 |
16 | declare module 'hooks/*' {
17 | export default (...args) => any;
18 | };
--------------------------------------------------------------------------------
/src/style/animation.less:
--------------------------------------------------------------------------------
1 | @keyframes slide-top {
2 | from {
3 | opacity: 0;
4 | transform: translate3d(0, -100%, 0);
5 | }
6 | to {
7 | opacity: 1;
8 | transform: translate3d(0, 0, 0);
9 | }
10 | }
11 |
12 | @keyframes slide-in-bottom {
13 | from {
14 | opacity: 0;
15 | transform: translate3d(0, 50%, 0);
16 | }
17 | to {
18 | opacity: 1;
19 | transform: translate3d(0, 0, 0);
20 | }
21 | }
22 |
23 | @keyframes opacity {
24 | from {
25 | position: absolute;
26 | right: 0;
27 | top: 0;
28 | width: 100%;
29 | opacity: 0;
30 | }
31 | to {
32 | position: absolute;
33 | right: 0;
34 | top: 0;
35 | width: 100%;
36 | opacity: 1;
37 | }
38 | }
39 |
40 | .initAnimation(@option, @time: .5) {
41 | @key: ~'@{option}';
42 | .@{key}-enter-active {
43 | animation: @key ~'@{time}s' ease-in-out;
44 | }
45 | .@{key}-leave-active {
46 | animation: @key ~'@{time}s' ease-in-out reverse;
47 | }
48 | }
49 |
50 | .initAnimation(slide-top);
51 | .initAnimation(slide-in-bottom);
52 | .initAnimation(opacity, .15);
53 |
54 | .opacitys-enter-active {
55 | animation: opacitys .3s ease-in-out;
56 | }
57 | .opacitys-leave-active {
58 | animation: opacitys .3s ease-in-out reverse;
59 | }
60 |
61 | @keyframes opacitys {
62 | from {
63 | opacity: 0;
64 | }
65 | to {
66 | opacity: 1;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/style/index.less:
--------------------------------------------------------------------------------
1 | @import 'scrollbar.less';
2 | @import 'global.less';
3 | @import 'ant-design.less';
4 | @import 'animation.less';
5 | @import 'nprogress.less';
6 |
--------------------------------------------------------------------------------
/src/style/nprogress.less:
--------------------------------------------------------------------------------
1 | /* Make clicks pass-through */
2 | #nprogress {
3 | pointer-events: none;
4 | }
5 |
6 | #nprogress .bar {
7 | background: #103FFA;
8 | position: fixed;
9 | z-index: 1031;
10 | top: 0;
11 | left: 0;
12 | width: 100%;
13 | height: 2px;
14 | }
15 |
16 | /* Fancy blur effect */
17 | #nprogress .peg {
18 | display: block;
19 | position: absolute;
20 | right: 0px;
21 | width: 100px;
22 | height: 100%;
23 | box-shadow: 0 0 10px #103FFA, 0 0 5px #103FFA;
24 | opacity: 1.0;
25 | -webkit-transform: rotate(3deg) translate(0px, -4px);
26 | -ms-transform: rotate(3deg) translate(0px, -4px);
27 | transform: rotate(3deg) translate(0px, -4px);
28 | }
29 |
30 | /* Remove these to get rid of the spinner */
31 | .nprogress-custom-parent {
32 | overflow: hidden;
33 | position: relative;
34 | }
35 |
36 | .nprogress-custom-parent #nprogress .bar {
37 | position: absolute;
38 | }
39 |
--------------------------------------------------------------------------------
/src/style/scrollbar.less:
--------------------------------------------------------------------------------
1 | /* 设置滚动条的样式 */
2 | ::-webkit-scrollbar {
3 | width:8px;
4 | height: 10px;
5 | }
6 | /* 滚动槽 */
7 | ::-webkit-scrollbar-track {
8 | border-radius:10px;
9 | }
10 | /* 滚动条滑块 */
11 | ::-webkit-scrollbar-thumb {
12 | border-radius:10px;
13 | background:rgba(0,0,0,0.2);
14 | }
15 |
--------------------------------------------------------------------------------
/src/track.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * PV 埋点装饰器
3 | * @param id 页面id
4 | * @returns 日志上报代码注入函数
5 | */
6 | export const PV = (id) => {
7 | return (target) => {
8 | ;(target.options.mounted || (target.options.mounted = [])).push(() => {
9 | window.DATracker && window.DATracker.track && window.DATracker.track(id)
10 | })
11 | }
12 | }
13 |
14 | /**
15 | * PV 埋点
16 | * @param id 页面id
17 | * @param data 上报数据
18 | */
19 | export const trackPage = (id, data = {}) => {
20 | window.DATracker && window.DATracker.track && window.DATracker.track(id, data)
21 | }
22 |
23 | /**
24 | * 日志上报
25 | * @param id 事件id
26 | * @param data 上报数据
27 | */
28 | export const trackEvent = (id, data = {}) => {
29 | window.DATracker && window.DATracker.track && window.DATracker.track(id, data)
30 | }
31 |
--------------------------------------------------------------------------------
/src/types/README.md:
--------------------------------------------------------------------------------
1 | # type
2 |
3 | > 项目类型文件
4 |
5 | ## 目录说明
6 |
7 | ```
8 | |-- app.type.ts 产品、集群等类型
9 | |-- common.type.ts 通用类型:用户、分页、排序、搜索等
10 | |-- event.type.ts 事件模块类型
11 | |-- object.type.ts 对象模块类型
12 | |-- parameter.type.ts 参数模块类型
13 | |-- requirement.type.ts 需求模块类型
14 | |-- table.type.ts 表格相关类型
15 | |-- template.type.ts 参数模板类型
16 | |-- terminal.type.ts 终端管理类型
17 | |-- version.type.ts 终端、事件类型参数版本相关类型
18 | ```
19 |
--------------------------------------------------------------------------------
/src/types/app.type.ts:
--------------------------------------------------------------------------------
1 | export interface User {
2 | email: string;
3 | userName: string;
4 | }
5 |
6 | // 产品信息
7 | export interface AppDto {
8 | id: number;
9 | code: string;
10 | name: string;
11 | description: string;
12 | creator: User;
13 | createTime: number;
14 | updateTime: number;
15 | }
16 |
17 | // 项目配置信息
18 | // TODO: 去除猛犸依赖
19 | export interface BizConfigDto {
20 | bdmsUrl: string; // mammaut url,用于获取导航栏
21 | bdmsPermissionUrl: string; // mammut用户项目、权限申请页面url(用于403、nobiz页面)
22 | musicRoutingUrl: string; // 路由平台地址
23 | }
24 |
25 | export interface WsDataDto {
26 | ruleList: any[];
27 | logData: any;
28 | oldRuleList: any[];
29 | oldLOgData: any;
30 | exceptions: any[];
31 | expLogList: any[];
32 | undefinedStatistics: any;
33 | baseTree: any[];
34 | taskTree: any[];
35 | taskName: string;
36 | }
37 |
38 | export interface FilterDto {
39 | key: string | number;
40 | value: string;
41 | }
42 |
--------------------------------------------------------------------------------
/src/types/authority.type.ts:
--------------------------------------------------------------------------------
1 | export interface RoleDto {
2 | id: string | number
3 | roleName: string
4 | description: string
5 | createTime: string
6 | updateTime: string
7 | }
8 |
9 | export interface UserDto {
10 | userId: number
11 | email: string
12 | userName: string
13 | apps: string[]
14 | createTime: string
15 | roles: RoleDto
16 | }
17 |
18 | export interface OwnerVo {
19 | id?: string | number
20 | userName: string
21 | email: string
22 | }
23 |
24 | export interface DomainDetailVo extends Omit {
25 | name: string
26 | owner: OwnerVo
27 | creator: OwnerVo
28 | admins: OwnerVo[]
29 | code: string
30 | }
31 |
32 | export interface NoticeDto {
33 | channelType: number
34 | modeTypes: number[]
35 | dailyNotifyTime?: string
36 | }
37 |
--------------------------------------------------------------------------------
/src/types/common.type.ts:
--------------------------------------------------------------------------------
1 | export interface User {
2 | id?: string | number
3 | email: string
4 | userName: string
5 | }
6 |
7 | // 分页请求
8 | export type Pagination = {
9 | currentPage: number
10 | pageSize: number
11 | }
12 |
13 | // 排序请求
14 | export type Order = {
15 | orderBy: string
16 | orderRule: 'ascend' | 'descend'
17 | }
18 |
19 | // 搜索请求
20 | export type Search = {
21 | search: string
22 | }
23 |
24 | // 分页响应结果
25 | export type PaginationList = {
26 | totalNum: number
27 | pageNum: number
28 | list: T[]
29 | }
30 |
31 | export type BaseObjectDto = {
32 | id: number
33 | code: string
34 | name: string
35 | description: string
36 | creator: User
37 | createTime: number
38 | updateTime: number
39 | updater: User
40 | }
41 |
42 | export type TagAggreDto = {
43 | key: number | string // 传递值
44 | value: string // 展示值
45 | }
46 |
47 | export type ItemDto = {
48 | id: number
49 | name: string
50 | }
51 |
--------------------------------------------------------------------------------
/src/types/event.type.ts:
--------------------------------------------------------------------------------
1 | import { BaseObjectDto, Pagination, Order, Search } from './common.type'
2 | import { ObjTypeEnum } from './object.type'
3 |
4 | export type EventSimpleDto = BaseObjectDto & {
5 | selectedByDefault: boolean // 是否默认选中
6 | applicableObjTypes: ObjTypeEnum[]
7 | }
8 |
9 | /** ----------------------------- Requst Parameter Type -------------------------- */
10 |
11 | export type GetEventListReq = Pagination & Partial & Search
12 |
13 | export type NewEventReq = {
14 | code: string
15 | name: string
16 | description: string
17 | selectedByDefault: boolean // 是否默认选中
18 | applicableObjTypes: ObjTypeEnum[]
19 | }
20 |
--------------------------------------------------------------------------------
/src/types/requirement.design.type.ts:
--------------------------------------------------------------------------------
1 | export type StatDto = Record<
2 | | 'allSpms'
3 | | 'assignedSpms'
4 | | 'unAssignedSpms'
5 | | 'allEvents'
6 | | 'assignedEvents'
7 | | 'unAssignedEvents'
8 | | 'tasks',
9 | number
10 | >
11 |
--------------------------------------------------------------------------------
/src/types/spm.type.ts:
--------------------------------------------------------------------------------
1 | interface SPMIds {
2 | spmIds: number[]
3 | }
4 |
5 | export interface ConditionDTO {
6 | terminalId: string | number | null
7 | isMapped?: boolean
8 | mapStatus?: number[]
9 | spmStatus?: number
10 | tagId?: number
11 | }
12 |
13 | export interface SPMListsResponseDTO {
14 | id: number
15 | spm: string
16 | spmOldList: string[]
17 | name: string
18 | tags: string
19 | mapStatus: number
20 | spmStatus: number
21 | version: string
22 | note: string
23 | }
24 |
25 | export interface SPMListsRequestDTO extends ConditionDTO {
26 | spmOldOrMapVersion?: string
27 | spmOrName?: string
28 | }
29 |
30 | export interface OldSPMMapRequestDTO {
31 | spmId: number
32 | spmOldList: string[]
33 | terminalId: number
34 | }
35 |
36 | export interface BindSPMTagRequestDTO extends SPMIds {
37 | tagIds: number[]
38 | terminalId: number
39 | }
40 |
41 | export interface UpdateSPMStatusRequestDTO extends SPMIds {
42 | status: number
43 | terminalId: number
44 | }
45 |
46 | export interface UpdateSPMVersionRequestDTO extends SPMIds {
47 | version: string
48 | terminalId: number
49 | }
50 |
51 | export interface UpdateSPMRemarkRequestDTO {
52 | spmId: number
53 | note: string
54 | }
55 | export interface CreateSPMRequestDTO {
56 | spmId?: number
57 | spm: string
58 | name: string
59 | appId: number
60 | terminalId: number
61 | spmStatus?: number
62 | status?: number
63 | }
64 |
--------------------------------------------------------------------------------
/src/types/table.type.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-unresolved */
2 | export type TablePagination = Partial
3 | export type Column = any
4 |
5 | export type TableColumn = Partial> & {
6 | customCell?: (
7 | record: any,
8 | rowIndex: number
9 | ) => {
10 | props?: Record
11 | attrs?: Record
12 | on?: Record
13 | class?: string | Record
14 | style?: string | Record
15 | nativeOn?: Record
16 | }
17 | customHeaderCell?: (
18 | record?: any,
19 | rowIndex?: number
20 | ) => {
21 | props?: Record
22 | attrs?: Record
23 | on?: Record
24 | class?: string | Record
25 | style?: string | Record
26 | nativeOn?: Record
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/types/template.type.ts:
--------------------------------------------------------------------------------
1 | import { BaseObjectDto, Pagination, Order, Search } from './common.type'
2 | import { ParamValueTypeEnum, ParamValueDto, ParamTypeEnum, ParameterDto } from './parameter.type'
3 |
4 | export type TemplateSimpleDto = Omit
5 |
6 | export interface ParamBindItemDto {
7 | uuid: string // 展示所构造的唯一值
8 | id: number // param id
9 | code: string
10 | name: string
11 | paramType: ParamTypeEnum
12 | valueType: ParamValueTypeEnum
13 | notEmpty: boolean // 非空
14 | must?: boolean // 必传
15 | description: string // 取值描述
16 | selectedValues: number[] // 选中的值
17 | values: ParamValueDto[] // 可选择的值
18 | names: ParameterDto[] // 对象业务私参可选的参数集合
19 | needTest?: boolean // 用于测试
20 | }
21 |
22 | export interface ParamBindSimpleDto {
23 | paramId: number
24 | values: number[]
25 | description: string
26 | notEmpty: boolean
27 | must: boolean // 必传
28 | }
29 |
30 | export interface TemplateDetailDto extends TemplateSimpleDto {
31 | binds: Omit[]
32 | }
33 |
34 | /** ----------------------------- Requst Parameter Type -------------------------- */
35 |
36 | export type GetTemplateListReq = Pagination & Search & Partial
37 |
38 | export type NewTemplateReq = {
39 | name: string
40 | description: string
41 | binds: ParamBindSimpleDto[]
42 | }
43 |
--------------------------------------------------------------------------------
/src/types/terminal.type.ts:
--------------------------------------------------------------------------------
1 | import { BaseObjectDto, Pagination, Order, Search } from './common.type'
2 |
3 | export enum TerminalTypeEnum {
4 | PC = 1,
5 | WIRELESS = 2, // 无线
6 | SERVER = 3 // 服务端
7 | }
8 |
9 | export const terminalTypeNameMap = {
10 | [TerminalTypeEnum.PC]: 'PC',
11 | [TerminalTypeEnum.WIRELESS]: '客户端',
12 | [TerminalTypeEnum.SERVER]: '服务端'
13 | }
14 |
15 | export type TerminalSimpleDto = BaseObjectDto & {
16 | type: TerminalTypeEnum
17 | terminalType?: string
18 | preset: boolean // 是否是预置信息
19 | }
20 |
21 | /** ----------------------------- Requst Parameter Type -------------------------- */
22 |
23 | export type GetTerminalListReq = Pagination &
24 | Partial &
25 | Search & {
26 | terminalTypes?: TerminalTypeEnum[]
27 | }
28 |
29 | export interface NewTerminalReq {
30 | type: TerminalTypeEnum
31 | name: string
32 | }
33 |
--------------------------------------------------------------------------------
/src/types/version.type.ts:
--------------------------------------------------------------------------------
1 | import { ParamBindSimpleDto } from '@/types/template.type'
2 |
3 | export interface VersionDto {
4 | id: string
5 | name: string
6 | preset: boolean // 是否是预置版本
7 | currentUsing: boolean // 是否是当前使用版本
8 | used: boolean // 是否被使用过,被使用过不可删除
9 | }
10 |
11 | export enum EntityTypeEnum {
12 | TERMINAL = 1, // 终端
13 | EVENT = 2, // 事件类型
14 | OBJ = 3, // 对象
15 | TEMPLATE = 4 // 模板
16 | }
17 |
18 | /** ----------------------------- Requst Parameter Type -------------------------- */
19 |
20 | export type GetVersionListReq = {
21 | search: string
22 | entityId: number
23 | entityType: EntityTypeEnum
24 | }
25 |
26 | export interface NewVersionReq {
27 | entityId: number
28 | entityType: EntityTypeEnum
29 | name: string
30 | }
31 |
32 | export interface DelVersionReq {
33 | entityId: number
34 | entityType: EntityTypeEnum
35 | versionId: number
36 | }
37 |
38 | export interface UpdateVersionBindsReq {
39 | entityId: number
40 | entityType: EntityTypeEnum
41 | versionId: number
42 | version: string // 版本名称
43 | paramBinds: ParamBindSimpleDto[]
44 | }
45 |
46 | export interface CopyVersionReq {
47 | name: string
48 | entityId: number
49 | entityType: EntityTypeEnum
50 | versionId: number
51 | }
52 |
--------------------------------------------------------------------------------
/src/utils/common.ts:
--------------------------------------------------------------------------------
1 | export function isArrayShallowEqual(a: any[], b: any[]) {
2 | if (!Array.isArray(a) || !Array.isArray(b)) return false;
3 | if (a.length !== b.length) return false;
4 |
5 | return a.every((v) => b.includes(v)) && b.every((v) => a.includes(v));
6 | }
7 |
8 | export function removeObjectNullProperty(obj: T): T {
9 | Object.keys(obj).forEach((k) => {
10 | if (obj[k] == null) {
11 | delete obj[k];
12 | }
13 | });
14 |
15 | return obj;
16 | }
17 |
18 | export const genBackground = (level: number) => {
19 | if (level > 0) {
20 | let background = "linear-gradient(to right, #dee2e6 0%, #dee2e6 16px,";
21 | let color = "#fff";
22 | let stop: any = 16;
23 |
24 | for (let i = 0; i < level; i++) {
25 | background += ` ${color} ${stop}px,`;
26 |
27 | if (i === level - 1) {
28 | background += ` ${color} 100%`;
29 | } else {
30 | stop += 16;
31 | background += ` ${color} ${stop}px,`;
32 | }
33 |
34 | color = color === "#f6f7fa" ? "#fff" : "#f6f7fa";
35 | }
36 |
37 | background += ")";
38 | return background;
39 | }
40 |
41 | return "#fff;";
42 | };
43 |
44 | export function generateExpandKeys(spmList = []) {
45 | const result = [];
46 |
47 | if (spmList && spmList.length) {
48 | spmList.forEach((spm) => {
49 | const list = spm.split("|").reverse();
50 |
51 | list.reduce((prev, cur) => {
52 | prev.unshift(cur);
53 | result.push(prev.join("|"));
54 |
55 | return prev;
56 | }, []);
57 | });
58 | }
59 |
60 | return result;
61 | }
62 |
--------------------------------------------------------------------------------
/src/utils/cookie.ts:
--------------------------------------------------------------------------------
1 | function fomattCookie() {
2 | const cookie = document.cookie;
3 |
4 | return cookie.split(";").reduce((objectCookie, next) => {
5 | const [key, value] = next.split("=");
6 |
7 | objectCookie[key] = value;
8 |
9 | return objectCookie;
10 | }, {});
11 | }
12 |
13 | export function getCookie(param) {
14 | const objectCookie = fomattCookie();
15 |
16 | return objectCookie[param];
17 | }
18 |
--------------------------------------------------------------------------------
/src/utils/hooks/Object/useFindAndroidAndIPhone.ts:
--------------------------------------------------------------------------------
1 | export default function useFindAndroidAndIPhone(trackers) {
2 | const terminalMap: string[] = ["android", "iphone"];
3 |
4 | return trackers.filter((next) =>
5 | terminalMap.some((v) => next.terminalName.toLowerCase().includes(v))
6 | );
7 | }
8 |
--------------------------------------------------------------------------------
/src/utils/hooks/useCopy.ts:
--------------------------------------------------------------------------------
1 | import { message } from "ant-design-vue";
2 |
3 | export default function useCopy(param): void {
4 | const input = document.createElement("textarea");
5 |
6 | document.body.appendChild(input);
7 |
8 | input.value = param;
9 | input.select();
10 |
11 | const status = document.execCommand("copy");
12 | const text = status ? "成功" : "失败";
13 |
14 | message.success(`复制${text}~`);
15 |
16 | document.body.removeChild(input);
17 | }
18 |
--------------------------------------------------------------------------------
/src/utils/hooks/useCopyParams.ts:
--------------------------------------------------------------------------------
1 | import { ParamValueTypeEnum } from '@/types/parameter.type'
2 |
3 | export default function useCopyParams(paramBinds = [], hasBox = true) {
4 | return (
5 | (paramBinds || []).reduce(
6 | (params, v, index) => {
7 | const isLast = index === paramBinds.length - 1
8 | const value =
9 | (v.valueType === ParamValueTypeEnum.CONSTANT &&
10 | Array.isArray(v.selectedValues) &&
11 | v.selectedValues.length > 1 &&
12 | v.values.find((b) => v.selectedValues.includes(b.id))?.code) ||
13 | ''
14 |
15 | params += `${v.code}: ${value || JSON.stringify('')}${isLast ? '' : ','}`
16 | params += v.description || value ? ` // ${v.description} ${value} \n` : ' \n'
17 |
18 | return params
19 | },
20 | hasBox ? '{ \n' : ''
21 | ) + (hasBox ? ' }' : '')
22 | )
23 | }
24 |
--------------------------------------------------------------------------------
/src/utils/request.ts:
--------------------------------------------------------------------------------
1 | import { Request, CustomAxiosRequestConfig } from "@/ndsc-vue3/utils/lib";
2 | import loginService from "@/services/login.service";
3 | import store from "@/store/index";
4 |
5 | const instance = new Request({
6 | baseURL: "/api/",
7 | addTokenFunc: (config: CustomAxiosRequestConfig) => {
8 | // 将 domainId 和 appId 添加到请求的 url 上
9 | const domainId = store.state.domainId;
10 | const app = store.state.app;
11 | const searchList = [];
12 |
13 | domainId && searchList.push("domainId=" + domainId);
14 | app?.id && searchList.push("appId=" + app.id);
15 |
16 | if (searchList.length) {
17 | config.url +=
18 | (config.url.indexOf("?") === -1 ? "?" : "&") + searchList.join("&");
19 | }
20 | },
21 | loginFunc: () => loginService.login(), // code === -4 时跳转登录操作
22 | });
23 |
24 | export default instance;
25 |
--------------------------------------------------------------------------------
/src/utils/tests/index.ts:
--------------------------------------------------------------------------------
1 | export function getData(wrapper: any, type = 1): any {
2 | const vm: any = wrapper.vm
3 |
4 | return type === 1 ? vm._.setupState : vm
5 | }
6 |
--------------------------------------------------------------------------------
/src/utils/validator.ts:
--------------------------------------------------------------------------------
1 | export const codeValidator = (rule, value) => {
2 | if (value === "") return Promise.resolve(true);
3 |
4 | if (!/^[a-zA-Z0-9_-]*$/.test(value)) {
5 | return Promise.reject(new Error("支持英文、数字、'_'和'-'"));
6 | }
7 |
8 | return Promise.resolve(true);
9 | };
10 |
11 | export const nameValidator = (rule, value) => {
12 | if (value === "") return Promise.resolve(true);
13 |
14 | if (!/^[\u4e00-\u9fa5a-zA-Z0-9_-]*$/.test(value)) {
15 | return Promise.reject(new Error("支持中英文、数字、'_'和'-'"));
16 | }
17 |
18 | return Promise.resolve(true);
19 | };
20 |
--------------------------------------------------------------------------------
/src/utils/vars.ts:
--------------------------------------------------------------------------------
1 | export const diffColors = {
2 | new: '#ecfdf0',
3 | mod: '#fafad7',
4 | del: '#fbe9eb'
5 | }
6 |
--------------------------------------------------------------------------------
/src/views/403.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
14 |
--------------------------------------------------------------------------------
/src/views/404.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
16 |
--------------------------------------------------------------------------------
/src/views/NoBiz.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
26 |
--------------------------------------------------------------------------------
/src/views/home/README.md:
--------------------------------------------------------------------------------
1 | # home
2 |
3 | > 项目页面结构
4 |
5 | ## 目录说明
6 | ```
7 | |-- tracker 埋点管理模块
8 | |-- metadata 元数据管理模块
9 | |-- components 公用组件
10 | |-- event 事件类型模块
11 | |-- parameter 参数管理模块
12 | |-- template 参数模板模块
13 | |-- terminal 终端管理模块
14 | |-- obejct 对象管理模块
15 | |-- detail 对象详情页面
16 | |-- list 对象管理页面
17 | |-- blood-relation 对象血缘模块
18 | |-- requirement 需求管理模块
19 | |-- components 公用组件
20 | |-- detail 需求详情页面
21 | |-- list 需求管理页面
22 | |-- version 版本管理页面
23 | |-- conflict-result 版本冲突结果页
24 | |-- graph 版本链图
25 | ```
--------------------------------------------------------------------------------
/src/views/home/authorityManagement/domainManage/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
13 |
14 |
20 |
--------------------------------------------------------------------------------
/src/views/home/authorityManagement/domainManage/nav.tsx:
--------------------------------------------------------------------------------
1 | import { NavListDto, NavConfigDto } from '@/ndsc-vue3/sidebar/lib'
2 | const navList: NavListDto[] = [
3 | {
4 | id: 'domain',
5 | name: '域信息',
6 | to: '/authorityManage/domain/detail',
7 | iconType: 'custom',
8 | icon: (h) => {
9 | return
10 | }
11 | },
12 | {
13 | id: 'member',
14 | name: '成员管理',
15 | to: '/authorityManage/domain/member',
16 | iconType: 'custom',
17 | icon: (h) => {
18 | return
19 | }
20 | },
21 | {
22 | id: 'product',
23 | name: '产品配置',
24 | to: '/authorityManage/domain/product',
25 | iconType: 'custom',
26 | icon: (h) => {
27 | return
28 | }
29 | }
30 | ]
31 | export default defineComponent({})
32 |
--------------------------------------------------------------------------------
/src/views/home/authorityManagement/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
15 |
16 |
21 |
--------------------------------------------------------------------------------
/src/views/home/authorityManagement/platformManage/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
13 |
14 |
22 |
--------------------------------------------------------------------------------
/src/views/home/authorityManagement/platformManage/nav.tsx:
--------------------------------------------------------------------------------
1 | import { NavListDto, NavConfigDto } from '@/ndsc-vue3/sidebar/lib'
2 | const navList: NavListDto[] = [
3 | {
4 | id: 'domain',
5 | name: '域配置',
6 | to: '/authorityManage/platform/domain',
7 | iconType: 'custom',
8 | icon: (h) => {
9 | return
10 | }
11 | }
12 | ]
13 | export default defineComponent({})
14 |
--------------------------------------------------------------------------------
/src/views/home/authorityManagement/productionManage/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
13 |
14 |
19 |
--------------------------------------------------------------------------------
/src/views/home/authorityManagement/productionManage/manage/components/auth-tab/utils.ts:
--------------------------------------------------------------------------------
1 | export function transformTreeData(list) {
2 | list.forEach((item) => {
3 | item.title = item.menuName
4 | item.key = item.id
5 |
6 | if (item.children) {
7 | transformTreeData(item.children)
8 | }
9 | })
10 | }
11 |
12 | export function getTreeNodeList(list, result) {
13 | list.forEach((item) => {
14 | if (item.assigned) {
15 | result.push(item.id)
16 | }
17 |
18 | if (item.children) {
19 | getTreeNodeList(item.children, result)
20 | }
21 | })
22 | }
23 |
--------------------------------------------------------------------------------
/src/views/home/authorityManagement/productionManage/manage/components/role-panel/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ detail.roleName || '' }}
5 | {{ detail.description ? ` : ${detail.description}` : '' }}
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | {
19 | this.$emit('fetchRoleList')
20 | }
21 | "
22 | >
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
48 |
49 |
59 |
--------------------------------------------------------------------------------
/src/views/home/authorityManagement/productionManage/nav.tsx:
--------------------------------------------------------------------------------
1 | import { NavListDto, NavConfigDto } from '@/ndsc-vue3/sidebar/lib'
2 | const navList: NavListDto[] = [
3 | {
4 | id: 'info',
5 | name: '产品信息',
6 | to: '/authorityManage/production/info',
7 | iconType: 'custom',
8 | icon: (h) => {
9 | return
10 | }
11 | },
12 | {
13 | id: 'member',
14 | name: '成员管理',
15 | to: '/authorityManage/production/member',
16 | iconType: 'custom',
17 | icon: (h) => {
18 | return
19 | }
20 | },
21 | {
22 | id: 'manage',
23 | name: '角色管理',
24 | to: '/authorityManage/production/manage',
25 | iconType: 'custom',
26 | icon: (h) => {
27 | return
28 | }
29 | }
30 | ]
31 | export default defineComponent({})
32 |
--------------------------------------------------------------------------------
/src/views/home/test/components/device-detail/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 终端:
5 | {{ terminal || '' }}
6 |
7 |
8 | 当前用户:
9 | {{ deviceInfo.anonymous ? deviceInfo.userid : deviceInfo.username }}
10 |
11 |
12 | 当前设备:
13 | {{ deviceInfo.deviceName || '' }}
14 |
15 |
16 | 当前设备品牌:
17 | {{ deviceInfo.channel || '' }}
18 |
19 |
20 | 当前设备型号:
21 | {{ deviceInfo.deviceName || '' }}
22 |
23 |
24 | 测试人:
25 | {{ deviceInfo.tester || '' }}
26 |
27 |
28 | 测试基线版本:
29 | {{ deviceInfo.baseLineName || '' }}
30 |
31 |
32 |
33 |
34 |
55 |
56 |
64 |
--------------------------------------------------------------------------------
/src/views/home/test/components/point-list/detection.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ textMap[name] }}
5 | :
6 | 0
7 |
8 | {{ `${value.numerator} / ${value.denominator} = ` }}
9 |
10 | {{ `${value.ratio.toFixed(2)}%` }}
11 |
12 |
13 |
14 |
15 |
16 |
17 |
43 |
44 |
63 |
--------------------------------------------------------------------------------
/src/views/home/test/components/types/index.ts:
--------------------------------------------------------------------------------
1 | export type deviceInfoDto = {
2 | appName: string
3 | appVer: string
4 | deviceName: string
5 | platform: string
6 | sysVer: string
7 | }
8 |
9 | export type statisticsDto = {
10 | eventStatistics: any[]
11 | logNum: number
12 | objTrackerNum: number
13 | }
14 |
15 | export type detailDto = {
16 | ruleCheck: any
17 | statistics: statisticsDto
18 | }
19 |
--------------------------------------------------------------------------------
/src/views/home/test/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
56 |
57 |
66 |
--------------------------------------------------------------------------------
/src/views/home/test/nav.tsx:
--------------------------------------------------------------------------------
1 | import { NavListDto, NavConfigDto } from '@/ndsc-vue3/sidebar/lib'
2 | const navList: NavListDto[] = [
3 | {
4 | id: 'realtime',
5 | name: '实时测试',
6 | to: '/test/realtime',
7 | iconType: 'custom',
8 | icon: (h) => {
9 | return
10 | }
11 | },
12 | {
13 | id: 'recordList',
14 | name: '测试记录',
15 | to: '/test/record',
16 | iconType: 'custom',
17 | icon: (h) => {
18 | return
19 | }
20 | },
21 | {
22 | id: 'requirement',
23 | name: '需求测试',
24 | to: '/test/requirement',
25 | iconType: 'custom',
26 | icon: (h) => {
27 | return
28 | }
29 | }
30 | ]
31 | export const navConfig: NavConfigDto = {
32 | project: {
33 | name: '埋点测试',
34 | to: '/test/realtime',
35 | icon: (h) => {
36 | return
37 | }
38 | },
39 | menu: navList
40 | }
41 |
--------------------------------------------------------------------------------
/src/views/home/test/realtime/audit/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
31 |
32 |
39 |
--------------------------------------------------------------------------------
/src/views/home/test/realtime/lists/types/content.ts:
--------------------------------------------------------------------------------
1 | import { TagAggreDto } from '@/types/common.type'
2 |
3 | type configKeys = 'requirementName' | 'taskName' | 'status' | 'objType' | 'owner' | 'terminal'
4 |
5 | export type configDto = {
6 | [P in configKeys]: TagAggreDto[]
7 | }
8 |
--------------------------------------------------------------------------------
/src/views/home/test/realtime/record/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
17 |
18 |
25 |
--------------------------------------------------------------------------------
/src/views/home/tracker/event/EventDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
41 |
--------------------------------------------------------------------------------
/src/views/home/tracker/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
54 |
55 |
64 |
--------------------------------------------------------------------------------
/src/views/home/tracker/metadata/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
--------------------------------------------------------------------------------
/src/views/home/tracker/nav.tsx:
--------------------------------------------------------------------------------
1 | import { NavConfigDto } from '@/ndsc-vue3/sidebar/lib'
2 |
3 | export const navConfig: Omit = {
4 | project: {
5 | name: '埋点管理',
6 | icon: () =>
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/views/home/tracker/object/detail/BackToList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 | 对象管理
13 |
14 | 对象详情
15 |
16 |
17 |
18 | oid:{{ oid }}
19 | 名称:{{ name }}
20 |
21 |
22 |
23 |
24 |
43 |
44 |
50 |
--------------------------------------------------------------------------------
/src/views/home/tracker/object/detail/ParamConfigFilter.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
15 |
16 |
71 |
--------------------------------------------------------------------------------
/src/views/home/tracker/object/detail/ParamTableModal.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
31 |
--------------------------------------------------------------------------------
/src/views/home/tracker/object/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
15 |
--------------------------------------------------------------------------------
/src/views/home/tracker/object/list/BloodRelationDrawer.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
18 |
19 |
20 |
21 |
53 |
54 |
61 |
--------------------------------------------------------------------------------
/src/views/home/tracker/object/list/ObjectAddDrawer.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
15 |
16 |
17 |
18 |
19 |
73 |
--------------------------------------------------------------------------------
/src/views/home/tracker/object/list/blood-relation/graph/ObjectDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ item.key }}:
6 | {{ item.value }}
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
35 |
36 |
45 |
--------------------------------------------------------------------------------
/src/views/home/tracker/object/list/blood-relation/graph/ObjectParamsTable.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
40 |
41 |
46 |
--------------------------------------------------------------------------------
/src/views/home/tracker/object/list/blood-relation/graph/behavior/click-canvas.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | getEvents() {
3 | return {
4 | 'canvas:click': 'onClick'
5 | }
6 | },
7 | onClick() {
8 | const graph = this.graph
9 | // 将所有当前是 click 状态的节点置为非 click 状态
10 | const clickNodes = graph.findAllByState('node', 'click')
11 | clickNodes.forEach((cn) => {
12 | graph.setItemState(cn, 'click', false)
13 | })
14 | // 将所有当前是 click 状态的边置为非 click 状态
15 | const clickEdges = graph.findAllByState('edge', 'click')
16 | clickEdges.forEach((ce) => {
17 | graph.setItemState(ce, 'click', false)
18 | })
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/views/home/tracker/object/list/blood-relation/graph/behavior/click-node.ts:
--------------------------------------------------------------------------------
1 | import { INode } from "@antv/g6-core/lib/interface/item";
2 | import { CustomNodeConfig } from "../type";
3 |
4 | const startAnchors = ["start-anchor", "start-anchor-icon"];
5 | const endAnchors = ["end-anchor", "end-anchor-icon"];
6 |
7 | export default {
8 | getEvents() {
9 | return {
10 | "node:click": "onClick",
11 | };
12 | },
13 | onClick(e) {
14 | const graph = this.graph;
15 | const name = e.shape?.cfg?.name;
16 |
17 | if (!startAnchors.concat(endAnchors).includes(name)) return;
18 |
19 | const item: INode = e.item;
20 | const cfg = item.getModel() as CustomNodeConfig;
21 | const { id, edges } = cfg;
22 | const isSource = edges.findIndex((e) => e.source === id) > -1;
23 | const eventEmitter = graph.eventEmitter;
24 |
25 | if (startAnchors.includes(name)) {
26 | const args = isSource ? ["fold-node", id] : ["expand-node", id, "son"];
27 |
28 | eventEmitter.emit(...args);
29 | } else {
30 | cfg.expandParent && eventEmitter.emit("expand-node", id, "parent");
31 | }
32 | },
33 | };
34 |
--------------------------------------------------------------------------------
/src/views/home/tracker/object/list/blood-relation/graph/behavior/hover-node.ts:
--------------------------------------------------------------------------------
1 | import { INode } from "@antv/g6-core/lib/interface/item";
2 |
3 | export default {
4 | getEvents() {
5 | return {
6 | "node:mouseover": "onMouseOver",
7 | "node:mouseleave": "onMouseLeave",
8 | };
9 | },
10 | onMouseOver(e) {
11 | const graph = this.graph;
12 | const item: INode = e.item;
13 |
14 | graph.setItemState(item, "hover", true);
15 | },
16 | onMouseLeave(e) {
17 | const graph = this.graph;
18 | const item: INode = e.item;
19 |
20 | graph.setItemState(item, "hover", false);
21 | },
22 | };
23 |
--------------------------------------------------------------------------------
/src/views/home/tracker/object/list/blood-relation/graph/behavior/index.ts:
--------------------------------------------------------------------------------
1 | import G6 from '@antv/g6'
2 | import canvasClick from './click-canvas'
3 | import clickNode from './click-node'
4 | import hoverNode from './hover-node'
5 |
6 | const behavors = {
7 | 'click-node': clickNode,
8 | 'click-canvas': canvasClick,
9 | 'hover-node': hoverNode
10 | }
11 |
12 | export const initBehaviors = () => {
13 | for (const key in behavors) {
14 | G6.registerBehavior(key, behavors[key])
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/views/home/tracker/object/list/blood-relation/graph/item/index.ts:
--------------------------------------------------------------------------------
1 | import { registerNode } from './obj-node'
2 |
3 | export const registerItems = () => {
4 | registerNode()
5 | }
6 |
--------------------------------------------------------------------------------
/src/views/home/tracker/object/list/blood-relation/graph/plugin/contextMenu.ts:
--------------------------------------------------------------------------------
1 | import G6 from "@antv/g6";
2 | import { Item } from "@antv/g6-core/lib/types";
3 |
4 | export const getContextMenu = (eventEmitter, supportSwitchCurrent = true) => {
5 | const nodeContextMenu = new G6.Menu({
6 | getContent(e) {
7 | const model = e.item?.getModel();
8 |
9 | return `
10 |
11 | - 查看对象详情
12 | ${
13 | supportSwitchCurrent && model?.objType !== "cur"
14 | ? "- 切换为当前对象
"
15 | : ""
16 | }
17 |
18 | `;
19 | },
20 | handleMenuClick: (target: HTMLElement, item: Item) => {
21 | const title = target.getAttribute("data-title");
22 |
23 | title && eventEmitter.emit(title, item?.getModel());
24 | },
25 | offsetX: 8,
26 | offsetY: 8,
27 | // 在哪些类型的元素上响应
28 | itemTypes: ["node"],
29 | });
30 | return [nodeContextMenu];
31 | };
32 |
--------------------------------------------------------------------------------
/src/views/home/tracker/object/list/blood-relation/graph/plugin/index.less:
--------------------------------------------------------------------------------
1 | // 右键菜单
2 | .g6-component-contextmenu {
3 | padding: 4px 0px !important;
4 | border: none !important;
5 | border-radius: 0 !important;
6 | background: #ffffff !important;
7 | box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.25) !important;
8 | li {
9 | padding: 4px 10px !important;
10 | cursor: pointer !important;
11 | &:hover {
12 | background-color: #e6efff !important;
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/views/home/tracker/object/list/blood-relation/graph/plugin/index.ts:
--------------------------------------------------------------------------------
1 | import { getContextMenu } from './contextMenu'
2 |
3 | // 引入 css
4 | import './index.less'
5 |
6 | export { getContextMenu }
7 |
--------------------------------------------------------------------------------
/src/views/home/tracker/object/list/blood-relation/graph/share/color.ts:
--------------------------------------------------------------------------------
1 | export const nodeColorMap = {
2 | cur: {
3 | stroke: '#FB8D18',
4 | fill: '#FFF7E6',
5 | color: '#fb8d18'
6 | },
7 | page: {
8 | stroke: '#26BD71',
9 | fill: '#E9F8F1',
10 | color: 'rgba(38, 189, 113, 1)'
11 | },
12 | element: {
13 | stroke: '#1890FF',
14 | fill: '#E6F7FF',
15 | color: '#1890FF'
16 | }
17 | }
18 |
19 | export const nodeBgColorMap = {
20 | page: '#ebf7f1',
21 | element: '#e8f7fe',
22 | popover: '#fef7e8',
23 | bridge: '#f4dfe1'
24 | }
25 |
26 | export const nodeBdColorMap = {
27 | otherSpace: '#FFA500',
28 | currentSpace: '#181616'
29 | }
30 |
--------------------------------------------------------------------------------
/src/views/home/tracker/object/list/blood-relation/graph/type.ts:
--------------------------------------------------------------------------------
1 | import { NodeConfig, EdgeConfig } from '@antv/g6-core/lib/types'
2 |
3 | export type CustomNodeConfig = NodeConfig & {
4 | objType: 'page' | 'element' | 'popover' | 'bridge'
5 | spaceType: 'otherSpace' | 'currentSpace'
6 | showName: string
7 | expandParent: boolean
8 | expandSon: boolean
9 | edges: EdgeConfig[]
10 | terminalId: number
11 | versionId: number
12 | naturalWidth?: number
13 | naturalHeight?: number
14 | }
15 |
--------------------------------------------------------------------------------
/src/views/home/tracker/object/list/const.ts:
--------------------------------------------------------------------------------
1 | export const objectType = {
2 | 1: "页面",
3 | 2: "元素",
4 | 3: "浮层",
5 | };
6 |
7 | export const elementType = {
8 | page: "页面",
9 | panel: "浮层",
10 | mod: "模块",
11 | cell: "卡片",
12 | btn: "按钮",
13 | layer: "老浮层",
14 | unknown: "未设置",
15 | };
16 |
--------------------------------------------------------------------------------
/src/views/home/tracker/requirement/components/StatusTag.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ statusText }}
3 |
4 |
5 |
24 |
--------------------------------------------------------------------------------
/src/views/home/tracker/requirement/components/object-diff/LineageInfo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
血缘配置
4 |
5 |
6 |
11 | {{
12 | item.parentObjName
13 | }}
14 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
47 |
48 |
63 |
--------------------------------------------------------------------------------
/src/views/home/tracker/requirement/components/object-diff/ObjectDiffDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
45 |
--------------------------------------------------------------------------------
/src/views/home/tracker/requirement/components/object-diff/TrackerInfo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
埋点信息
4 |
5 | {{ terminalName }}
6 |
7 |
12 | {{
13 | item.code
14 | }}
15 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
50 |
51 |
66 |
--------------------------------------------------------------------------------
/src/views/home/tracker/requirement/components/object-diff/util.ts:
--------------------------------------------------------------------------------
1 | import { ChangeTypeEnum } from "@/types/object.type";
2 |
3 | export function genClasses(paramChangeType: ChangeTypeEnum) {
4 | return paramChangeType === ChangeTypeEnum.CREATE
5 | ? "new-item"
6 | : paramChangeType === ChangeTypeEnum.DELETE
7 | ? "delete-item"
8 | : "";
9 | }
10 |
11 | export function genTooltip(
12 | {
13 | paramChangeType,
14 | terminalVersionName,
15 | isNewestTerminalVersion,
16 | isCurrentTask,
17 | },
18 | type = "参数"
19 | ) {
20 | let res = "";
21 | const operate = paramChangeType === ChangeTypeEnum.CREATE ? "增加" : "删除";
22 |
23 | if (isNewestTerminalVersion) {
24 | res += `${terminalVersionName}${operate}了该${type}`;
25 | }
26 |
27 | if (isCurrentTask) {
28 | res += res ? "," : "";
29 | res += `当前需求${operate}了该${type}`;
30 | }
31 |
32 | return res;
33 | }
34 |
--------------------------------------------------------------------------------
/src/views/home/tracker/requirement/detail/BackToList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | 需求管理
18 |
19 | 需求详情
20 |
21 |
22 |
23 | 需求ID:{{ reqIssueKey }}
24 |
25 |
26 |
27 |
28 |
29 |
50 |
51 |
57 |
--------------------------------------------------------------------------------
/src/views/home/tracker/requirement/detail/TaskObject.vue:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
54 |
55 |
66 |
--------------------------------------------------------------------------------
/src/views/home/tracker/requirement/detail/TrackerTab.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 | 暂无埋点方案
13 |
14 |
15 |
16 |
17 |
44 |
--------------------------------------------------------------------------------
/src/views/home/tracker/requirement/detail/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
71 |
--------------------------------------------------------------------------------
/src/views/home/tracker/requirement/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
15 |
--------------------------------------------------------------------------------
/src/views/home/tracker/requirement/list/RequirementGroup.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
16 |
17 |
18 |
19 |
24 |
25 |
26 |
27 |
35 |
--------------------------------------------------------------------------------
/src/views/home/tracker/requirement/list/SettingSprint.vue:
--------------------------------------------------------------------------------
1 |
2 | a-modal(:visible="props.visible" title="设置迭代" @ok="setSprintConfirm" @cancel="$emit('update:visible', false)")
3 | a-form(:colon="false" :label-col="{ span: 3 }" :wrapper-col="{ span: 18 }" ref="formRef")
4 | a-form-item(label="迭代" required)
5 | a-input(placeholder="请输入迭代" v-model:value="sprint")
6 |
7 |
8 |
28 |
--------------------------------------------------------------------------------
/src/views/home/tracker/requirement/list/SettingVersion.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
79 |
--------------------------------------------------------------------------------
/src/views/home/tracker/requirement/list/TerminalList.vue:
--------------------------------------------------------------------------------
1 |
2 | a-form
3 | a-form-item(label="选择所属终端")
4 | a-checkbox-group
5 | a-checkbox(v-for="terminal in terminalList" :value="terminal.id" :key="terminal.id") {{terminal.name}}
6 |
7 |
8 |
24 |
--------------------------------------------------------------------------------
/src/views/home/tracker/requirement/list/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
43 |
44 |
53 |
--------------------------------------------------------------------------------
/src/views/home/tracker/requirement/version/Publish.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
39 |
--------------------------------------------------------------------------------
/src/views/home/tracker/requirement/version/VersionNumEditModal.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
16 |
17 |
18 |
19 |
20 |
21 |
56 |
--------------------------------------------------------------------------------
/src/views/home/tracker/requirement/version/VersionTree.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
59 |
--------------------------------------------------------------------------------
/src/views/home/tracker/requirement/version/graph/context-menu.ts:
--------------------------------------------------------------------------------
1 | import G6 from "@antv/g6";
2 | import { Item } from "@antv/g6-core/lib/types";
3 |
4 | export const getContextMenu = (eventEmitter) => {
5 | const nodeContextMenu = new G6.Menu({
6 | getContent() {
7 | return `
8 |
11 | `;
12 | },
13 | handleMenuClick: (target: HTMLElement, item: Item) => {
14 | const title = target.getAttribute("data-title");
15 |
16 | title === "set-main-version" &&
17 | eventEmitter.emit("set-main-version", item.getID());
18 | },
19 | shouldBegin: (e) => {
20 | const model: any = e.item?.getModel();
21 |
22 | return model?.canSetMainVersion;
23 | },
24 | offsetX: 8,
25 | offsetY: 8,
26 | itemTypes: ["node"],
27 | });
28 | return [nodeContextMenu];
29 | };
30 |
--------------------------------------------------------------------------------
/src/views/home/tracker/requirement/version/version-publish/BackToList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
12 |
13 | 版本列表
14 |
15 | 发布上线
16 |
17 |
18 |
19 | 端解决版本:{{ terminalVersion }}
20 |
21 |
22 |
23 |
24 |
25 |
41 |
42 |
48 |
--------------------------------------------------------------------------------
/src/vue-router.d.ts:
--------------------------------------------------------------------------------
1 | // typings.d.ts or router.ts
2 | import 'vue-router'
3 |
4 | declare module 'vue-router' {
5 | interface RouteMeta {
6 | type?: number // 权限控制
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/vuex.d.ts:
--------------------------------------------------------------------------------
1 | import { Store } from 'vuex'
2 |
3 | declare module '@vue/runtime-core' {
4 | // 声明自己的 store state
5 | interface State {
6 | count: number
7 | }
8 |
9 | interface ComponentCustomProperties {
10 | $store: Store
11 | defferMoule: number
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "esnext",
5 | "jsx": "preserve",
6 | "strict": false,
7 | "skipLibCheck": true,
8 | "importHelpers": true,
9 | "moduleResolution": "node",
10 | "experimentalDecorators": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strictNullChecks": false,
14 | "sourceMap": true,
15 | "baseUrl": ".",
16 | "types": [
17 | "webpack-env",
18 | "jest"
19 | ],
20 | "paths": {
21 | "@/*": [
22 | "src/*"
23 | ]
24 | },
25 | "lib": [
26 | "esnext",
27 | "dom",
28 | "dom.iterable",
29 | "scripthost"
30 | ]
31 | },
32 | "include": [
33 | "**/*.d.ts",
34 | "src/**/*.ts",
35 | "src/**/*.tsx",
36 | "src/**/*.vue",
37 | "tests/**/*.ts",
38 | "tests/**/*.tsx",
39 | "auto-imports.d.ts",
40 | "src/middler/webpackLoader/installCommon.js"
41 | ],
42 | "exclude": ["node_modules"]
43 | }
44 |
--------------------------------------------------------------------------------